Share via


Aplicación de Express.js que convierte texto en voz con los servicios de Voz de Cognitive Services

En este tutorial, agregue los servicios de Voz de Cognitive Services a una aplicación de Express.js existente para agregar la conversión de texto a voz mediante el servicio de Voz de Cognitive Services. La conversión de texto a voz le permite proporcionar audio sin el costo de generar manualmente el audio.

En este tutorial se muestran tres maneras diferentes de convertir texto a voz desde los servicios de Voz de Azure Cognitive Services:

  • El código JavaScript del cliente recibe el audio directamente
  • El código JavaScript del servidor obtiene el audio de un archivo (*.MP3)
  • El código JavaScript del servidor obtiene el audio de un elemento arrayBuffer en memoria

Arquitectura de la aplicación

El tutorial toma una aplicación de Express.js mínima y agrega funcionalidad mediante una combinación de:

  • nueva ruta para la API de servidor para proporcionar conversión de texto a voz y devolver un flujo MP3
  • nueva ruta para un formulario HTML que le permite escribir la información
  • nuevo formulario HTML, con JavaScript, que proporciona una llamada del lado cliente al servicio de Voz

Esta aplicación proporciona tres llamadas diferentes para convertir voz en texto:

  • La primera llamada de servidor crea un archivo en el servidor y, a continuación, lo devuelve al cliente. Normalmente se usaría para texto más largo o para texto que se sabe que se debe atender más de una vez.
  • La segunda llamada al servidor es para texto a corto plazo y se mantiene en memoria antes de volver al cliente.
  • La llamada de cliente muestra una llamada directa al servicio de Voz mediante el SDK. Puede optar por realizar esta llamada si tiene una aplicación solo de cliente sin servidor.

Requisitos previos

  • Node.js LTS : instalado en el equipo local.
  • Visual Studio Code: instalado en la máquina local.
  • La extensión de Azure App Service para VS Code (se instala desde VS Code).
  • Git: se usa para insertar en GitHub, lo que activa la acción de GitHub.
  • Uso de Azure Cloud Shell mediante Bash Embed launch
  • Si lo prefiere, instale la CLI de Azure para ejecutar sus comandos de referencia.
    • Si usa una instalación local, inicie sesión con la CLI de Azure mediante el comando az login. Siga los pasos que se muestran en el terminal para completar el proceso de autenticación. Para más opciones de inicio de sesión, consulte Inicio de sesión con la CLI de Azure.
    • Cuando se le solicite, instale las extensiones de la CLI de Azure la primera vez que la use. Para más información, consulte Uso de extensiones con la CLI de Azure.
    • Ejecute az version para buscar cuál es la versión y las bibliotecas dependientes que están instaladas. Para realizar la actualización a la versión más reciente, ejecute az upgrade.

Descarga del repositorio de ejemplo de Express.js

  1. Con git, clone el repositorio de ejemplo de Express.js en el equipo local.

    git clone https://github.com/Azure-Samples/js-e2e-express-server
    
  2. Cambie al nuevo directorio del ejemplo.

    cd js-e2e-express-server
    
  3. Abra el proyecto en Visual Studio Code.

    code .
    
  4. Abra un nuevo terminal en Visual Studio Code e instale las dependencias del proyecto.

    npm install
    

Instalación del SDK de Voz de Cognitive Services para JavaScript

En el terminal de Visual Studio Code, instale el SDK de Voz de Azure Cognitive Services.

npm install microsoft-cognitiveservices-speech-sdk

Creación de un módulo de Voz para la aplicación de Express.js

  1. Para integrar el SDK de Voz en la aplicación de Express.js, cree un archivo en la carpeta src llamado azure-cognitiveservices-speech.js.

  2. Agregue el código siguiente para extraer las dependencias y crear una función para convertir texto a voz.

    // 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: el archivo extrae las dependencias para usar el SDK, las secuencias, los búferes y el sistema de archivos (fs). La función textToSpeech toma cuatro argumentos. Si se envía un nombre de archivo con una ruta de acceso local, el texto se convierte en un archivo de audio. Si no se envía un nombre de archivo, se crea una secuencia de audio en memoria.
    • Método del SDK de Voz: el método synthesizer.speakTextAsync del SDK de Voz devuelve tipos diferentes, en función de la configuración que recibe. El método devuelve el resultado, que difiere en función de lo que se le pidió que hiciera el método:
      • Crear archivo
      • Crear una secuencia en memoria como una matriz de búferes
    • Formato de audio: el formato de audio seleccionado es MP3, pero hay otros formatos, junto con otros métodos de configuración de audio.

    El método local, textToSpeech, encapsula y convierte la función de devolución de llamada del SDK en una promesa.

Creación de una nueva ruta para la aplicación de Express.js

  1. Abra el archivo src/server.js.

  2. Agregue el módulo azure-cognitiveservices-speech.js como una dependencia en la parte superior del archivo:

    const { textToSpeech } = require('./azure-cognitiveservices-speech');
    
  3. Agregue una nueva ruta de API para llamar al método textToSpeech creado en la sección anterior del tutorial. Agregue este código después de la /api/hello ruta.

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

    Este método toma los parámetros obligatorios y opcionales para el método textToSpeech de la cadena de consulta. Si es necesario crear un archivo, se desarrolla un nombre de archivo único. Se llama al método textToSpeech de forma asincrónica y este canaliza el resultado al objeto de respuesta (res).

Actualización de la página web del cliente con un formulario

Actualice la página web HTML del cliente con un formulario que recopile los parámetros necesarios. El parámetro opcional se pasa en función del control de audio que seleccione el usuario. Dado que este tutorial proporciona un mecanismo para llamar al servicio de Voz de Azure desde el cliente, también se proporciona ese código JavaScript.

Abra el archivo /public/client.html y reemplace su contenido por lo siguiente:

<!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>

Líneas resaltadas en el archivo:

  • Línea 74: El SDK de Voz de Azure se extrae en la biblioteca cliente mediante el cdn.jsdelivr.net sitio para entregar el paquete NPM.
  • Línea 102: el updateSrc método actualiza la dirección URL de los controles src de audio con la cadena de consulta, incluida la clave, la región y el texto.
  • Línea 137: Si un usuario selecciona el Get directly from Azure botón, la página web llama directamente a Azure desde la página del cliente y procesa el resultado.

Creación de un recurso de Voz de Cognitive Services

Cree el recurso de Voz con comandos de la CLI de Azure en una instancia de Azure Cloud Shell.

  1. Inicie sesión en Azure Cloud Shell. Esto requiere que se autentique en un explorador con su cuenta, que tiene permisos en una suscripción válida de Azure.

  2. Cree un grupo de recursos para el recurso de Voz.

    az group create \
        --location eastus \
        --name tutorial-resource-group-eastus
    
  3. Cree un recurso de Voz en el grupo de recursos.

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

    Este comando producirá un error si ya se ha creado el recurso de Voz gratis.

  4. Use el comando para obtener los valores de clave del nuevo recurso de Voz.

    az cognitiveservices account keys list \
        --name tutorial-speech \
        --resource-group tutorial-resource-group-eastus \
        --output table
    
  5. Copie una de las claves.

    Para usarla, péguela en el formulario web de la aplicación Express para autenticarse en el servicio de voz de Azure.

Ejecución de la aplicación de Express.js para convertir texto a voz

  1. Inicie la aplicación con el siguiente comando bash.

    npm start
    
  2. Abra la aplicación web en un explorador.

    http://localhost:3000    
    
  3. Pegue la clave del servicio de Voz en el cuadro de texto resaltado.

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

  4. Opcionalmente, cambie el texto a algo nuevo.

  5. Seleccione uno de los tres botones para iniciar la conversión al formato de audio:

    • Obtener directamente de Azure: llamada del lado cliente a Azure
    • Control de audio para audio desde archivo
    • Control de audio para audio desde búfer

    Es posible que observe un pequeño retraso entre la selección del control y la reproducción del audio.

Creación de una nueva instancia de Azure App Service en Visual Studio Code

  1. En la paleta de comandos (Ctrl+Mayús+P), escriba "crear web" y seleccione App de Azure Servicio: Crear nueva aplicación web... Avanzado. En lugar de usar los valores predeterminados de Linux, use el comando avanzado para tener control total sobre la implementación, incluido el grupo de recursos, el plan de App Service y el sistema operativo.

  2. Responda a los mensajes como se indica a continuación:

    • Seleccione la cuenta de Suscripción.
    • Para Escriba un nombre único global, escriba algo como my-text-to-speech-app.
      • Escriba un nombre que sea único en todo Azure. Use solo caracteres alfanuméricos (A-Z, a-z y 0-9) y guiones ("-").
    • Seleccione tutorial-resource-group-eastus para el grupo de recursos.
    • Seleccione una pila de tiempo de ejecución de una versión que incluya Node y LTS.
    • Seleccione el sistema operativo Linux.
    • Seleccione Crear un nuevo plan de App Service y proporcione un nombre, como my-text-to-speech-app-plan.
    • Seleccione el plan de tarifa gratis F1. Si la suscripción ya tiene una aplicación web gratuita, seleccione el nivel Basic.
    • Seleccione Omitir por ahora para el recurso de Application Insights.
    • Seleccione la ubicación eastus.
  3. Tras unos momentos, Visual Studio Code notifica que se ha completado la creación. Cierre la notificación con el botón X.

Implementación de una aplicación local de Express.js en el servicio de aplicaciones remoto en Visual Studio Code

  1. Una vez implementada la aplicación web, implemente el código desde el equipo local. Seleccione el icono de Azure para abrir el explorador de Azure App Service, expanda el nodo de la suscripción, haga clic con el botón derecho en el nombre de la aplicación web que acaba de crear y seleccione Deploy to Web App (Implementar en aplicación web).

  2. Si hay avisos de implementación, seleccione la carpeta raíz de la aplicación de Express.js, vuelva a seleccionar la cuenta de la suscripción y, luego, elija el nombre de la aplicación web creada anteriormente, my-text-to-speech-app.

  3. Si, al realizar la implementación en Linux, se le pide que ejecute npm install y se le pregunta si quiere actualizar la configuración para ejecutar npm install en el servidor de destino, seleccione .

    Prompt to update configuration on the target Linux server

  4. Una vez finalizada la implementación, seleccione Browse Website (Examinar sitio web) en el mensaje para ver la aplicación web recién implementada.

  5. (Opcional): puede realizar cambios en los archivos de código y, a continuación, usar La implementación en la aplicación web, en la extensión de servicio App de Azure, para actualizar la aplicación web.

Transmisión de registros de servicio remoto en Visual Studio Code

Vea o consulte el final de los archivos de salida que la aplicación en ejecución genere mediante llamadas a console.log. Esta salida aparece en la ventana Salida de Visual Studio Code.

  1. En el explorador de Azure App Service, haga clic con el botón derecho en el nodo de la aplicación y elija Start Streaming Logs (Iniciar transmisión de registros).

     Starting Live Log Stream ---
     
  2. Actualice la página web varias veces en el explorador para ver otras salidas de registros.

Limpieza de recursos mediante la eliminación del grupo de recursos

Una vez que haya completado este tutorial, deberá eliminar el grupo de recursos que incluye el recurso para asegurarse de que no se le facturará por ningún uso adicional.

En Azure Cloud Shell, use el comando de la CLI de Azure para eliminar el grupo de recursos:

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

Este comando puede tardar unos minutos.

Pasos siguientes