Escrito por

Software Architect at Visum
Artigo Yuri Marx · Fev. 21, 2022 6m read

Serviço REST para converter texto em áudio usando IRIS e Python gTTS

Olá Comunidade,

Imagine habilitar seu aplicativo para ler texto para seu cliente? Isso agora é possível com o novo recurso IRIS, Embedded Python. Com essa nova funcionalidade, o IRIS pode executar nativamente qualquer biblioteca Python comercial ou de código aberto. gTTS (https://pypi.org/project/gTTS/) é uma biblioteca gratuita que transforma texto em áudio usando o serviço Google Translate.

Como funciona

Basta passar o texto por parâmetro e o gTTS retorna um arquivo mp3 com o texto transformado em áudio. Ou seja, seu aplicativo pode reproduzir o áudio de qualquer texto! Veja como fazer:

1. Vá em https://openexchange.intersystems.com/package/IRIS-Text2Audio e clique Download.

2. Clone/git pull o repositório em qualquer diretório local

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

3. Abra um terminal docker no diretório criado e execute:

$ docker-compose build

4. Execute o IRIS container:

$ docker-compose up -d 

5. Vá no Postman (ou similar) e configure a requisição como na figura:

Request TTS input

6. Clique em enviar e obtenha uma resposta com um player para reproduzir o arquivo mp3, como na imagem acima.

Explicando o Código Fonte

1. O Dockerfile instala o IRIS com Python e gTTS

 

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. Uma ClassMethod foi criada com linguagem Python e usa gTTS para transformar texto em audio e gravar em um arquivo mp3:

 

Método Python para gerar audio a partir do texto

/// 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. Uma API REST API em ObjectScript foi criada para expor a funcionalidade Python como um microserviço TTS (muito chique!)

 

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)
}

 

}