O aplicativo Express.js converte texto em fala com a Fala dos Serviços Cognitivos

Neste tutorial, adicione a Fala dos Serviços Cognitivos a um aplicativo Express.js existente a fim de adicionar a conversão de texto em fala usando o serviço de Fala dos Serviços Cognitivos. A conversão de texto em fala permite que você forneça áudio sem o custo da geração manual de áudio.

Este tutorial mostra três maneiras diferentes de converter texto em fala por meio da Fala dos Serviços Cognitivos do Azure:

  • O JavaScript do cliente obtém áudio diretamente
  • O JavaScript do servidor obtém áudio de um arquivo (*.MP3)
  • O JavaScript do servidor obtém áudio de um arrayBuffer na memória

Arquitetura do aplicativo

O tutorial usa um aplicativo Express.js mínimo e adiciona funcionalidade usando uma combinação de:

  • nova rota para a API do servidor a fim de fornecer conversão de texto em fala, retornando um fluxo de MP3
  • nova rota para um formulário HTML a fim de permitir que você insira as informações
  • novo formulário HTML, com JavaScript, fornece uma chamada do lado do cliente para o serviço de Fala

Esse aplicativo fornece três chamadas diferentes para conversão de fala em texto:

  • A primeira chamada ao servidor cria um arquivo no servidor e o retorna ao cliente. Normalmente, você usa isso para textos mais longos ou textos que você sabe que poderão ser usados mais de uma vez.
  • A segunda chamada do servidor é para texto de curto prazo e é mantida na memória antes de retornar ao cliente.
  • A chamada ao cliente demonstra uma chamada direta ao serviço de Fala usando o SDK. Você poderá optar por fazer essa chamada se tiver um aplicativo somente de cliente sem um servidor.

Pré-requisitos

  • Nó.js LTS - instalado em sua máquina local.
  • Visual Studio Code – instalado no computador local.
  • A extensão do Serviço de Aplicativo do Azure para VS Code (instalada de dentro do VS Code).
  • Git – usado para enviar por push para o GitHub, o que ativa a ação do GitHub.
  • Usar o Azure Cloud Shell usando o bash Embed launch
  • Se preferir, instale a CLI do Azure para executar comandos de referência da CLI.
    • Se estiver usando uma instalação local, entre com a CLI do Azure usando o comando az login. Para concluir o processo de autenticação, siga as etapas exibidas no terminal. Confira Entrar com a CLI do Azure para ver mais opções de entrada.
    • Quando solicitado, instale as extensões da CLI do Azure no primeiro uso. Para obter mais informações sobre extensões, confira Usar extensões com a CLI do Azure.
    • Execute az version para localizar a versão e as bibliotecas dependentes que estão instaladas. Para fazer a atualização para a versão mais recente, execute az upgrade.

Baixar o repositório de exemplo Express.js

  1. Usando o Git, clone o repositório de exemplo Express.js no computador local.

    git clone https://github.com/Azure-Samples/js-e2e-express-server
    
  2. Altere para o novo diretório para o exemplo.

    cd js-e2e-express-server
    
  3. Abra o projeto no Visual Studio Code.

    code .
    
  4. Abra um novo terminal no Visual Studio Code e instale as dependências do projeto.

    npm install
    

Instale o SDK de Fala dos Serviços Cognitivos para JavaScript

Por meio do terminal do Visual Studio Code, instale o SDK de Fala dos Serviços Cognitivos do Azure.

npm install microsoft-cognitiveservices-speech-sdk

Criar um módulo de Fala para o aplicativo Express.js

  1. Para integrar o SDK de Fala ao aplicativo Express.js, crie um arquivo na pasta do src chamada azure-cognitiveservices-speech.js.

  2. Adicione o código a seguir para efetuar pull de dependências e criar uma função para conversão de texto em fala.

    // azure-cognitiveservices-speech.js
    
    const sdk = require('microsoft-cognitiveservices-speech-sdk');
    const { Buffer } = require('buffer');
    const { PassThrough } = require('stream');
    const fs = require('fs');
    
    /**
     * Node.js server code to convert text to speech
     * @returns stream
     * @param {*} key your resource key
     * @param {*} region your resource region
     * @param {*} text text to convert to audio/speech
     * @param {*} filename optional - best for long text - temp file for converted speech/audio
     */
    const textToSpeech = async (key, region, text, filename)=> {
        
        // convert callback function to promise
        return new Promise((resolve, reject) => {
            
            const speechConfig = sdk.SpeechConfig.fromSubscription(key, region);
            speechConfig.speechSynthesisOutputFormat = 5; // mp3
            
            let audioConfig = null;
            
            if (filename) {
                audioConfig = sdk.AudioConfig.fromAudioFileOutput(filename);
            }
            
            const synthesizer = new sdk.SpeechSynthesizer(speechConfig, audioConfig);
    
            synthesizer.speakTextAsync(
                text,
                result => {
                    
                    const { audioData } = result;
    
                    synthesizer.close();
                    
                    if (filename) {
                        
                        // return stream from file
                        const audioFile = fs.createReadStream(filename);
                        resolve(audioFile);
                        
                    } else {
                        
                        // return stream from memory
                        const bufferStream = new PassThrough();
                        bufferStream.end(Buffer.from(audioData));
                        resolve(bufferStream);
                    }
                },
                error => {
                    synthesizer.close();
                    reject(error);
                }); 
        });
    };
    
    module.exports = {
        textToSpeech
    };
    
    • Parâmetros – O arquivo efetua pull das dependências para usar o SDK, os fluxos, os buffers e o FS (sistema de arquivos). A função textToSpeech usa quatro argumentos. Se um nome de arquivo com caminho local for enviado, o texto será convertido em um arquivo de áudio. Se um nome de arquivo não for enviado, um fluxo de áudio na memória será criado.
    • Método SDK de Fala – O método SDK de Fala synthesizer.speakTextAsync retorna tipos diferentes, com base na configuração que recebe. O método retorna o resultado, que difere com base no que o método foi solicitado a fazer:
      • Criar arquivo
      • Criar um fluxo na memória como matriz de buffers
    • Formato de áudio – O formato de áudio selecionado é MP3, mas existem outros formatos, juntamente com outros Métodos de configuração de áudio.

    O método local, textToSpeech, encapsula e converte a função de retorno de chamada do SDK em uma promessa.

Criar uma rota para o aplicativo Express.js

  1. Abra o arquivo src/server.js .

  2. Adicione o módulo azure-cognitiveservices-speech.js como uma dependência na parte superior do arquivo:

    const { textToSpeech } = require('./azure-cognitiveservices-speech');
    
  3. Adicione uma nova rota de API para chamar o método textToSpeech criado na seção anterior do tutorial. Adicione este código após a /api/hello rota.

    // creates a temp file on server, the streams to client
    /* eslint-disable no-unused-vars */
    app.get('/text-to-speech', async (req, res, next) => {
        
        const { key, region, phrase, file } = req.query;
        
        if (!key || !region || !phrase) res.status(404).send('Invalid query string');
        
        let fileName = null;
        
        // stream from file or memory
        if (file && file === true) {
            fileName = `./temp/stream-from-file-${timeStamp()}.mp3`;
        }
        
        const audioStream = await textToSpeech(key, region, phrase, fileName);
        res.set({
            'Content-Type': 'audio/mpeg',
            'Transfer-Encoding': 'chunked'
        });
        audioStream.pipe(res);
    });
    

    Esse método usa os parâmetros obrigatórios e opcionais para o método textToSpeech da QueryString. Se for necessário criar um arquivo, um nome de arquivo exclusivo será desenvolvido. O método textToSpeech é chamado de maneira assíncrona e canaliza o resultado para o objeto de resposta (res).

Atualizar a página da Web do cliente com um formulário

Atualize a página da Web HTML do cliente com um formulário que coleta os parâmetros necessários. O parâmetro opcional é passado com base em qual controle de áudio o usuário seleciona. Como este tutorial fornece um mecanismo para chamar o serviço de Fala do Azure do cliente, esse JavaScript também é fornecido.

Abra o arquivo /public/client.html e substitua o conteúdo pelo seguinte código:

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Microsoft Cognitive Services Demo</title>
  <meta charset="utf-8" />
</head>

<body>

  <div id="content" style="display:none">
    <h1 style="font-weight:500;">Microsoft Cognitive Services Speech </h1>
    <h2>npm: microsoft-cognitiveservices-speech-sdk</h2>
    <table width="100%">
      <tr>
        <td></td>
        <td>
          <a href="https://docs.microsoft.com/azure/cognitive-services/speech-service/get-started" target="_blank">Azure
            Cognitive Services Speech Documentation</a>
        </td>
      </tr>
      <tr>
        <td align="right">Your Speech Resource Key</td>
        <td>

          <input id="resourceKey" type="text" size="40" placeholder="Your resource key (32 characters)" value=""
            onblur="updateSrc()">

      </tr>
      <tr>
        <td align="right">Your Speech Resource region</td>
        <td>
          <input id="resourceRegion" type="text" size="40" placeholder="Your resource region" value="eastus"
            onblur="updateSrc()">

        </td>
      </tr>
      <tr>
        <td align="right" valign="top">Input Text (max 255 char)</td>
        <td><textarea id="phraseDiv" style="display: inline-block;width:500px;height:50px" maxlength="255"
            onblur="updateSrc()">all good men must come to the aid</textarea></td>
      </tr>
      <tr>
        <td align="right">
          Stream directly from Azure Cognitive Services
        </td>
        <td>
          <div>
            <button id="clientAudioAzure" onclick="getSpeechFromAzure()">Get directly from Azure</button>
          </div>
        </td>
      </tr>

      <tr>
        <td align="right">
          Stream audio from file on server</td>
        <td>
          <audio id="serverAudioFile" controls preload="none" onerror="DisplayError()">
          </audio>
        </td>
      </tr>

      <tr>
        <td align="right">Stream audio from buffer on server</td>
        <td>
          <audio id="serverAudioStream" controls preload="none" onerror="DisplayError()">
          </audio>
        </td>
      </tr>
    </table>
  </div>

  <!-- Speech SDK reference sdk. -->
  <script
    src="https://cdn.jsdelivr.net/npm/microsoft-cognitiveservices-speech-sdk@latest/distrib/browser/microsoft.cognitiveservices.speech.sdk.bundle-min.js">
    </script>

  <!-- Speech SDK USAGE -->
  <script>
    // status fields and start button in UI
    var phraseDiv;
    var resultDiv;

    // subscription key and region for speech services.
    var resourceKey = null;
    var resourceRegion = "eastus";
    var authorizationToken;
    var SpeechSDK;
    var synthesizer;

    var phrase = "all good men must come to the aid"
    var queryString = null;

    var audioType = "audio/mpeg";
    var serverSrc = "/text-to-speech";

    document.getElementById('serverAudioStream').disabled = true;
    document.getElementById('serverAudioFile').disabled = true;
    document.getElementById('clientAudioAzure').disabled = true;

    // update src URL query string for Express.js server
    function updateSrc() {

      // input values
      resourceKey = document.getElementById('resourceKey').value.trim();
      resourceRegion = document.getElementById('resourceRegion').value.trim();
      phrase = document.getElementById('phraseDiv').value.trim();

      // server control - by file
      var serverAudioFileControl = document.getElementById('serverAudioFile');
      queryString += `%file=true`;
      const fileQueryString = `file=true&region=${resourceRegion}&key=${resourceKey}&phrase=${phrase}`;
      serverAudioFileControl.src = `${serverSrc}?${fileQueryString}`;
      console.log(serverAudioFileControl.src)
      serverAudioFileControl.type = "audio/mpeg";
      serverAudioFileControl.disabled = false;

      // server control - by stream
      var serverAudioStreamControl = document.getElementById('serverAudioStream');
      const streamQueryString = `region=${resourceRegion}&key=${resourceKey}&phrase=${phrase}`;
      serverAudioStreamControl.src = `${serverSrc}?${streamQueryString}`;
      console.log(serverAudioStreamControl.src)
      serverAudioStreamControl.type = "audio/mpeg";
      serverAudioStreamControl.disabled = false;

      // client control
      var clientAudioAzureControl = document.getElementById('clientAudioAzure');
      clientAudioAzureControl.disabled = false;

    }

    function DisplayError(error) {
      window.alert(JSON.stringify(error));
    }

    // Client-side request directly to Azure Cognitive Services
    function getSpeechFromAzure() {

      // authorization for Speech service
      var speechConfig = SpeechSDK.SpeechConfig.fromSubscription(resourceKey, resourceRegion);

      // new Speech object
      synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig);

      synthesizer.speakTextAsync(
        phrase,
        function (result) {

          // Success function

          // display status
          if (result.reason === SpeechSDK.ResultReason.SynthesizingAudioCompleted) {

            // load client-side audio control from Azure response
            audioElement = document.getElementById("clientAudioAzure");
            const blob = new Blob([result.audioData], { type: "audio/mpeg" });
            const url = window.URL.createObjectURL(blob);

          } else if (result.reason === SpeechSDK.ResultReason.Canceled) {
            // display Error
            throw (result.errorDetails);
          }

          // clean up
          synthesizer.close();
          synthesizer = undefined;
        },
        function (err) {

          // Error function
          throw (err);
          audioElement = document.getElementById("audioControl");
          audioElement.disabled = true;

          // clean up
          synthesizer.close();
          synthesizer = undefined;
        });

    }

    // Initialization
    document.addEventListener("DOMContentLoaded", function () {

      var clientAudioAzureControl = document.getElementById("clientAudioAzure");
      var resultDiv = document.getElementById("resultDiv");

      resourceKey = document.getElementById('resourceKey').value;
      resourceRegion = document.getElementById('resourceRegion').value;
      phrase = document.getElementById('phraseDiv').value;
      if (!!window.SpeechSDK) {
        SpeechSDK = window.SpeechSDK;
        clientAudioAzure.disabled = false;

        document.getElementById('content').style.display = 'block';
      }
    });

  </script>
</body>

</html>

Linhas realçadas no arquivo:

  • Linha 74: O SDK de Fala do Azure é puxado para a biblioteca do cliente, usando o site para entregar o cdn.jsdelivr.net pacote NPM.
  • Linha 102: O updateSrc método atualiza a URL dos src controles de áudio com a cadeia de caracteres de consulta, incluindo a chave, a região e o texto.
  • Linha 137: se um usuário selecionar o botão, a página da Web chamará diretamente para o Azure a partir da página do cliente e processará o Get directly from Azure resultado.

Criar recurso de Fala dos Serviços Cognitivo

Cria o recurso de Fala com comandos da CLI do Azure em um Azure Cloud Shell.

  1. Entrar no Azure Cloud Shell. Isso exige que você se autentique em um navegador com sua conta, que tem permissão em uma assinatura válida do Azure.

  2. Crie um grupo de recursos para o recurso de Fala.

    az group create \
        --location eastus \
        --name tutorial-resource-group-eastus
    
  3. Crie um recurso de Fala no grupo de recursos.

    az cognitiveservices account create \
        --kind SpeechServices \
        --location eastus \
        --name tutorial-speech \
        --resource-group tutorial-resource-group-eastus \
        --sku F0
    

    Esse comando falhará se o único recurso de Fala gratuito já tiver sido criado.

  4. Use o comando para obter os valores de chave para o novo recurso de Fala.

    az cognitiveservices account keys list \
        --name tutorial-speech \
        --resource-group tutorial-resource-group-eastus \
        --output table
    
  5. Copie uma das chaves.

    Use a chave colando-a no formulário da Web do aplicativo Express para se autenticar no serviço de Fala do Azure.

Executar o aplicativo Express.js para converter texto em fala

  1. Inicie o aplicativo com o comando bash a seguir.

    npm start
    
  2. Abra o aplicativo Web em um navegador.

    http://localhost:3000    
    
  3. Cole a chave de Fala na caixa de texto realçada.

    Browser screenshot of web form with Speech key input field highlighted.

  4. Opcionalmente, altere o texto para algo novo.

  5. Selecione um dos três botões para iniciar a conversão ao formato de áudio:

    • Obtenha diretamente do Azure – Chamada do lado do cliente ao Azure
    • Controle de áudio para áudio do arquivo
    • Controle de áudio para áudio do buffer

    Você pode notar um pequeno atraso entre a seleção do controle e a reprodução do áudio.

Criar Serviço de Aplicativo do Azure no Visual Studio Code

  1. Na paleta de comandos (Ctrl+Shift+P), digite "create web" e selecione Serviço de Aplicativo do Azure: Criar novo aplicativo Web... Avançado. Use o comando avançado para ter controle completo sobre a implantação, incluindo o grupo de recursos, o Plano do Serviço de Aplicativo e o sistema operacional, em vez de usar padrões do Linux.

  2. Responda aos prompts da seguinte maneira:

    • Selecionar sua conta de Assinatura.
    • Para Inserir um nome globalmente exclusivo como my-text-to-speech-app.
      • Insira um nome que seja exclusivo em todo o Azure. Use apenas caracteres alfanuméricos ("A-Z", "a-z" e "0-9") e hifens ("-")
    • Selecione tutorial-resource-group-eastus para o grupo de recursos.
    • Selecione uma pilha de runtime de uma versão que inclui Node e LTS.
    • Selecione o sistema operacional Linux.
    • Selecione Criar um Plano do Serviço de Aplicativo e forneça um nome como my-text-to-speech-app-plan.
    • Selecione o tipo de preço gratuito F1. Se sua assinatura já tem um aplicativo Web gratuito, selecione a camada Basic.
    • Selecione Ignorar por enquanto para o recurso do Application Insights.
    • Selecione a localização eastus.
  3. Após um breve período, o Visual Studio Code notificará você de que a criação foi concluída. Feche a notificação por meio do botão X.

Implantar o aplicativo local Express.js no serviço de aplicativo remoto no Visual Studio Code

  1. Com o aplicativo Web em vigor, implante o código por meio do computador local. Selecione o ícone do Azure para abrir o gerenciador do Serviço de Aplicativo do Azure, expanda o nó de assinatura, clique com o botão direito do mouse no nome do aplicativo Web que acabou de criar e selecione Implantar no aplicativo Web.

  2. Se houver prompts de implantação, selecione a pasta raiz do aplicativo Express.js, escolha a conta de assinatura novamente e selecione o nome do aplicativo Web, my-text-to-speech-app, criado anteriormente.

  3. Se receber um prompt para executar npm install ao implantar no Linux, selecione Sim se solicitado a atualizar a configuração para executar npm install no servidor de destino.

    Prompt to update configuration on the target Linux server

  4. Quando a implantação for concluída, selecione Procurar no Site no prompt para exibir seu aplicativo Web implantado recentemente.

  5. (Opcional): você pode fazer alterações em seus arquivos de código e usar o Implantar no Aplicativo Web, na extensão de serviço do Aplicativo do Azure, para atualizar o aplicativo Web.

Transmitir logs de serviço remoto no Visual Studio Code

Exibir (acompanhar) qualquer saída que o aplicativo em execução gerar por meio de chamadas a console.log. Essa saída aparece na janela Saída no Visual Studio Code.

  1. No gerenciador do Serviço de Aplicativo do Azure, clique com o botão direito do mouse no novo nó do aplicativo e escolha Iniciar Fluxo de Logs.

     Starting Live Log Stream ---
     
  2. Atualize a página da Web algumas vezes no navegador para ver saída de log adicional.

Limpar os recursos por meio da remoção do grupo de recursos

Depois de concluir este tutorial, você precisará remover o grupo de recursos, que inclui todos os recursos, a fim de garantir que você não será cobrado por mais nenhum uso.

No Azure Cloud Shell, use o comando da CLI do Azure para excluir o grupo de recursos:

az group delete --name tutorial-resource-group-eastus  -y

Esse comando pode levar alguns minutos.

Próximas etapas