Written by

Software Architect at Visum
Article Yuri Marx · Feb 21, 2022 6m read

REST Service for Convert text to audio using IRIS and Python gTTS

Hi Community,

Imagine enabling your application to read text to your customer? This is now possible with the new IRIS feature, Embedded Python. With this new functionality IRIS can natively run any open source or commercial Python libraries natively. gTTS (https://pypi.org/project/gTTS/) is a free library that transforms text into audio using the Google Translate service.

How to

Just pass the text by parameter and gTTS returns an mp3 file with the text transformed into audio. That is, your application can play the audio of any text! See how to do it:

1. Go to https://openexchange.intersystems.com/package/IRIS-Text2Audio and Click Download button.

2. Clone/git pull the repo into any local directory

$ git clone https://github.com/yurimarx/iris-tts.git

3. Open a Docker terminal in this directory and run:

$ docker-compose build

4. Run the IRIS container:

$ docker-compose up -d 

5. Go to your Postman (or other similar REST client) and config the request like this image:

Request TTS input

6. Click send and get a response with a player to play the mp3 file, like picture above.

Behind the scenes

1. The Dockerfile install IRIS with Python and gTTS library

 

Dockerfile

FROM intersystemsdc/iris-community

 

USER root

 

ENV DEBIAN_FRONTEND noninteractive

 

# install libraries required to gTTS to process TTS
RUN apt-get -y update \
    && apt-get -y install apt-utils \
    && apt-get install -y build-essential unzip pkg-config wget \
    && apt-get install -y python3-pip  

 

# use pip3 (the python zpm) to install gTTS dependencies
RUN pip3 install --upgrade pip setuptools wheel
RUN pip3 install --target /usr/irissys/mgr/python gTTS

 

USER root  
WORKDIR /opt/irisbuild
RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisbuild
USER ${ISC_PACKAGE_MGRUSER}

 

WORKDIR /opt/irisbuild
COPY  src src
COPY Installer.cls Installer.cls
COPY module.xml module.xml
COPY iris.script iris.script

 

USER ${ISC_PACKAGE_MGRUSER}

 

RUN iris start IRIS \
    && iris session IRIS < iris.script \
    && iris stop IRIS quietly

2. A ClassMethod was created with Python language configured that uses gTTS to transform text into audio and record it in an mp3 file:

 

Python method to generate audio from text

/// TTS engine
Class dc.tts.TTSEngine
{

 

/// Text to audio file
ClassMethod GenerateAudioFileFromText(sentence, language, domain) [ Language = python ]
{
        from gtts import gTTS
        import uuid

 

        tts = gTTS(sentence, lang=str(language), tld=str(domain))
        output = str(uuid.uuid1()) + '.mp3'
        tts.save('/opt/irisbuild/' + output)
        return output
}

 

}

3. A REST API in ObjectScript was created to expose Python functionality as a TTS microservice (very fancy!)

 

TTS REST Service

Class dc.tts.TTSRESTApp Extends %CSP.REST
{

 

Parameter CHARSET = "utf-8";

 

Parameter CONVERTINPUTSTREAM = 1;

 

Parameter CONTENTTYPE = "application/json";

 

Parameter Version = "1.0.0";

 

Parameter HandleCorsRequest = 1;

 

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<!-- Server Info -->
<Route Url="/" Method="GET" Call="GetInfo" Cors="true"/>
<!-- Swagger specs -->
<Route Url="/_spec" Method="GET" Call="SwaggerSpec" />

 

<!-- generate text from audio file -->
<Route Url="/texttoaudio" Method="POST" Call="GenerateAudioFromText" />

 

</Routes>
}

 

// Generate audio file from text

 

ClassMethod GenerateAudioFromText() As %Status
{
    Set tSC = $$$OK
   
    try {
      // get the sentence to be processed
      Set sentence = $ZCONVERT(%request.Content.Read(),"I","UTF8")

 

      Set Language = %request.Get("lang")
      Set Domain = %request.Get("domain")

 

      Set Language = $GET(Language,0)
      If Language = "" {
        Set Language = "en"
      }

 

      Set Domain = $GET(Domain,0)
      If Domain = "" {
        Set Domain = "com"
      }

 

      //call embedded python classmethod to get mp3 audio file from text
      Set output = ##class(dc.tts.TTSEngine).GenerateAudioFileFromText(sentence, Language, Domain)

 

      Set %response.ContentType = "audio/mp3"
     
      Do %response.SetHeader("Content-Disposition","attachment;filename="""_output_"""")
      Set %response.NoCharSetConvert=1
      Set %response.Headers("Access-Control-Allow-Origin")="*"

 

      Set stream=##class(%Stream.FileBinary).%New()
      Set sc=stream.LinkToFile("/opt/irisbuild/"_output)
      Do stream.OutputToDevice()
       
      Set tSC=$$$OK
 
    //returns error message to the user
    } catch e {
        Set tSC=e.AsStatus()
        Set pOutput = tSC
    }

 

    Quit tSC
}

 

/// General information
ClassMethod GetInfo() As %Status
{
  SET version = ..#Version
  SET fmt=##class(%SYS.NLS.Format).%New("ptbw")
 
  SET info = {
    "Service": "TTS Service API",
    "version": (version),
    "Developer": "Yuri Gomes",
    "Status": "Ok",
    "Date": ($ZDATETIME($HOROLOG))
  }
  Set %response.ContentType = ..#CONTENTTYPEJSON
  Set %response.Headers("Access-Control-Allow-Origin")="*"

 

  Write info.%ToJSON()
  Quit $$$OK
}

 

ClassMethod %ProcessResult(pStatus As %Status = {$$$OK}, pResult As %DynamicObject = "") As %Status [ Internal ]
{
  #dim %response As %CSP.Response
  SET tSC = $$$OK
  IF $$$ISERR(pStatus) {
    SET %response.Status = 500
    SET tSC = ..StatusToJSON(pStatus, .tJSON)
    IF $isobject(tJSON) {
      SET pResult = tJSON
    } ELSE {
      SET pResult = { "errors": [ { "error": "Unknown error parsing status code" } ] }
    }
  }
  ELSEIF pStatus=1 {
    IF '$isobject(pResult){
      SET pResult = {
      }
    }
  }
  ELSE {
    SET %response.Status = pStatus
    SET error = $PIECE(pStatus, " ", 2, *)
    SET pResult = {
      "error": (error)
    }
  }
 
  IF pResult.%Extends("%Library.DynamicAbstractObject") {
    WRITE pResult.%ToJSON()
  }
  ELSEIF pResult.%Extends("%JSON.Adaptor") {
    DO pResult.%JSONExport()
  }
  ELSEIF pResult.%Extends("%Stream.Object") {
    DO pResult.OutputToDevice()
  }
 
  QUIT tSC
}

 

ClassMethod SwaggerSpec() As %Status
{
  Set tSC = ##class(%REST.API).GetWebRESTApplication($NAMESPACE, %request.Application, .swagger)
  Do swagger.info.%Remove("x-ISC_Namespace")
  Set swagger.basePath = "/iris-tts"
  Set swagger.info.title = "TTS Service API"
  Set swagger.info.version = "1.0"
  Set swagger.host = "localhost:52773"
  Return ..%ProcessResult($$$OK, swagger)
}

 

}

Comments

Ben Spead · May 3, 2022

love it!!  I have previously said that I believe the most useful benefit of python for IRIS would be opening the gateway to python based libraries which do cool things.   this is an awesome example of that concept!!

0
Yuri Marx · May 3, 2022

Thanks! You right, I have other apps published on OEX to detect objects, encrypt, do geocoding, all using Python and IRIS.

0