IBM Watson III: Adicionando fala e reconhecimento de voz
Nesta série de artigos sobre o IBM Watson já vimos como funciona o serviço Watson Assistant, suas diversas ferramentas e criamos um chatbot que entende nossas mensagens e responde com ações ou informações que estamos esperando.
Neste artigo será demonstrado como adicionar uma interface com suporte a voz no chatbot, habilitando nele o reconhecimento de fala e a sintetização de voz. Para isso, utilizaremos os serviços de Texto Para Fala (Text To Speech — TTS) e Fala Para Texto (Speech To Text — STT) do IBM Watson.
O código do chatbot não precisa ser alterado, pois o que faremos é incluir a possibilidade do usuário enviar um stream de áudio, o qual será convertido em texto pela STT, sendo este texto enviado ao bot para processamento. Quando uma resposta for recebida do chatbot, é feita uma requisição à TTS com o texto desta resposta, gerando o respectivo áudio que será ouvido pelo usuário.
Fala para Texto — STT
O objetivo da STT é reconhecer a fala em formato de áudio e transcrevê-la para texto. Algumas API’s de STT atualmente disponíveis:
Abaixo segue um exemplo de como implementar reconhecimento de fala em Node.js utilizando o serviço IBM Watson Speech to Text. Vamos fazer uma requisição ao serviço Watson STT, enviando um arquivo de áudio, mostrando no console o texto retornado:
Para utilizar o Watson STT precisamos informar as nossas credenciais do serviço ou gerar um token para esta aplicação específica. Os únicos parâmetros obrigatórios ao chamar o serviço Watson STT são o stream do áudio e o seu formato. No exemplo acima, os parâmetros obrigatórios são definidos na variável “params”: o arquivo “artigo-stt.mp3” como stream de áudio e o respectivo formato (“audio/mp3”). O retorno da função recognize
será um JSON com o texto interpretado ou um erro.
Áudio original:
JSON retornado informando o texto entendido pelo Watson com 93,7% de confiança:
"results":
[{
"alternatives":
[{
"confidence":0.937,
"transcript":"I didn't invent the time machine to win at gambling I invented a time machine to travel through time "
}],
"final":true
}],
"result_index":0
HTTP ou WebSocket
No exemplo anterior utilizamos uma requisição HTTP para transcrever nosso áudio, porém estamos limitados à sequência de: gravar um áudio, enviar à API, mostrar texto resposta. Com Websocket podemos ir além e construir aplicações que se comunicam de forma mais orgânica com o usuário, exibindo feedback conforme o áudio é entendido pela API.
Utilizando o Websocket é possível, enquanto está ocorrendo a gravação da fala do usuário, enviar streams representando pequenos trechos do áudio captado. A API de STT vai retornando o que entendeu, porém conforme ela recebe mais trechos, seu entendimento da frase vai melhorando conforme o usuário fala. Pode-se visualizar um exemplo de implementação de STT via Websocket nesta demo do Google STT.
Interface gráfica
É interessante dar um feedback ao usuário enquanto ele fala. Para isso, podemos utilizar a API de Web Audio (confira a compatibilidade dos navegadores). A Web Audio permite manipular alguns parâmetros de áudio dos navegadores, tais como frequência, volume, ganho e outros. Para criarmos uma animação de feedback que se transforma de acordo com o áudio que está sendo gravado pelo microfone, devemos extrair valores de frequência do stream com a Transformada de Fourier. Esta transformada nos permite decompor um sinal em função do tempo para vários intervalos de frequência extraindo sua amplitude. Se atribuirmos algumas vezes por segundo cada uma destas amplitudes à altura de barras, por exemplo, teremos uma espécie de gráfico de equalização. No exemplo abaixo é mostrado como criar a animação em forma de círculos utilizada no ChatterBot Crescer, semelhante à Cortana da Microsoft:
Para implementarmos a animação acima, utilizaremos o analyser
para obter em tempo real os valores de frequência que precisamos, conectando-o ao stream de áudio vindo do microfone:
Precisamos definir em quantos pontos nosso sinal será decomposto, este valor deve ser entre 32 e 32768. Lembrando que cada ponto corresponde a um intervalo de frequência e seu valor é a amplitude média deste intervalo. É criado um array para estes valores:
Para inserir os valores neste array é usada a função getByteTimeDomainData
e a partir deste passo podemos criar qualquer visualização desejada para o stream de áudio:
No chatbot do Crescer foi criado um componente chamado voice-listener
com uma div contendo 16 box-shadows variando conforme a fala do usuário:
Estas box-shadows tem seu diâmetro alterado pela função abaixo várias vezes por segundo. Os valores do array variam de 0 a 255, sendo silêncio o valor 127. Como a variação é muito grande para nossa aplicação, distorcendo demais a animação, limitamos os valores ao intervalo de 110 a 145, ampliando-os em 150%:
Texto para Fala — TTS
O serviço de TTS tem como objetivo reproduzir artificialmente a voz humana. Listamos abaixo alguns fornecedores que disponibilizam APIs para este serviço:
Cada API tem características próprias, mas todas as citadas acima disponibilizam ao menos uma voz para o português falado no Brasil, além de aceitarem a escolha de qual formato de áudio será retornado. Vamos fazer um exemplo de requisição em Node.js utilizando o IBM Watson Text to Speech:
Assim como no exemplo do SST, também precisamos informar as credenciais ou o token de autenticação. Os parâmetros devem incluir no mínimo o texto a ser sintetizado e a voz utilizada para sintetizá-lo, podendo incluir também o formato de áudio a ser retornado. Neste caso foi escolhida a voz Isabela por ser a única disponível (até o momento dessa publicação) em português do Brasil da lista de vozes do IBM Watson TTS. O retorno será um stream que pode ser salvo em um arquivo ou executado no navegador, por exemplo. Este foi o áudio gerado.
Customização com SSML
SSML — Speech Synthesis Markup Language é uma linguagem de marcação baseada em XML para aplicações com síntese de fala. São tags que informam à API de TTS como aquele determinado elemento (frase, palavra, número, letra, etc) deve ser pronunciado. Embora seja um padrão suportado pela grande maioria das APIs de TTS, a implementação do SSML termina tendo alguma variação. Por isso vamos analizar seu uso no Watson TTS. Abaixo temos um exemplo de como um texto pode ser elaborado com SSML:
Analisando o SSML do exemplo acima, vemos que tudo é encapsulado pela tag <speak>
, a API irá sintetizar somente o que estiver dentro desta. As tags <paragraph>
e <sentence>
organizam o texto e diminuem a quantidade de outras marcações que teríamos de usar para atingir o mesmo efeito; também podemos escrevê-las como: <p>
e <s>
. Para inserir pausas utilizamos o <break>
, o qual requer ou o atributo 'time', informando de quanto tempo será a pausa, ou ‘strength’ que indica quão forte ela será. Quando queremos alterar parâmetros físicos do audio a ser gerado utilizamos a tag <prosody>.
Podemos definir o tom de voz com o parâmetro ‘pitch’ indo de ‘low’ à ’high’, a velocidade com o ‘rate’ indo de ‘slow’ a ‘fast’ e o volume com o ‘volume’ indo de ‘soft’ a ‘loud’.
Este foi o áudio gerado pelo texto acima:
Nesse próximo exemplo é demostrado o uso da tag <say-as>
:
A tag <say-as>
permite definirmos pelo atributo ‘interpret-as’ o tipo de texto que está sendo lido, por exemplo ao colocarmos esta tag no texto '17/12/2005' com seu atributo ‘interpret-as="date"’ teremos um áudio de uma data, ao invés de uma leitura como ‘17 barra 12 barra 2005’. Uma nota importante sobre esta tag: ela á apenas parcialmente suportada em português, suas funções completas, incluindo sintetização de números de telefone e valores monetários, estão disponíveis apenas em inglês.
Audio gerado:
Há também a tag <express-as>
, no momento suportada apenas por uma voz em inglês: 'en-US_AllisonVoice', seu uso é muito útil pois permite especificar como a frase deve ser dita sem grandes alterações manuais, por exemplo:
Com o uso do atributo ‘GoodNews’ podemos enfatizar a frase para que ela seja dita de forma empolgante, com o ‘Apology’ de forma mais triste e desapontada, e com o ‘Uncertainty’ de forma duvidosa, ideal para perguntas.
Audio gerado: