Text-zu-Sprache-Konvertierung durch Express.js-App mit Cognitive Services Speech

In diesem Tutorial fügen Sie Cognitive Services Speech einer vorhandenen Express.js-App hinzu, um die Text-zu-Sprache-Konvertierung mit dem Cognitive Services Speech-Dienst zu ermöglichen. Bei der Text-zu-Sprache-Konvertierung erhalten Sie Audiodaten, ohne dass Sie diese manuell generieren müssen.

In diesem Tutorial werden drei verschiedene Vorgehensweisen der Text-zu-Sprache-Konvertierung mit Azure Cognitive Services Speech veranschaulicht:

  • Direktes Abrufen der Audiodaten durch den JavaScript-Code des Clients
  • Abrufen der Audiodaten durch den JavaScript-Code des Servers aus einer Datei (*.MP3)
  • Abrufen der Audiodaten aus In-Memory-arrayBuffer durch den JavaScript-Code des Servers

Anwendungsarchitektur

Im Tutorial wird eine minimal ausgestattete Express.js-App verwendet, und die Funktionen werden über eine Kombination der folgenden Elemente hinzugefügt:

  • Neue Route für die Server-API für die Text-zu-Sprache-Konvertierung, bei der ein MP3-Stream zurückgegeben wird
  • Neue Route für ein HTML-Formular, damit Sie Ihre Informationen eingeben können
  • Neues HTML-Formular mit JavaScript zum Durchführen eines clientseitigen Aufrufs des Speech-Diensts

Diese Anwendung verfügt über drei verschiedene Aufrufe für die Sprache-in-Text-Konvertierung:

  • Mit dem ersten Serveraufruf wird eine Datei auf dem Server erstellt, die dann an den Client zurückgegeben wird. Dieser Aufruf wird normalerweise für längere oder mehr als einmal bereitzustellende Texte genutzt.
  • Der zweite Serveraufruf ist für kürzeren Begriffstext vorgesehen und wird im Arbeitsspeicher gehalten, bevor er an den Client zurückgegeben wird.
  • Der Clientaufruf veranschaulicht einen direkten Aufruf des Speech-Diensts per SDK. Sie können diesen Aufruf auch nutzen, wenn Sie eine reine Clientanwendung ohne Server verwenden.

Voraussetzungen

  • Node.js LTS - auf Ihrem lokalen Computer installiert.
  • Visual Studio Code (installiert auf Ihrem lokalen Computer)
  • Azure App Service-Erweiterung für VS Code (installiert aus VS Code)
  • Git zum Pushen an GitHub, wodurch wiederum die GitHub-Aktion aktiviert wird
  • Verwenden von Azure Cloud Shell mithilfe der Bash Embed launch
  • Wenn Sie möchten, können Sie auch die Azure CLI installieren, um CLI-Verweisbefehle auszuführen.
    • Wenn Sie eine lokale Installation verwenden, melden Sie sich mithilfe des Befehls az login bei der Azure CLI an. Führen Sie die in Ihrem Terminal angezeigten Schritte aus, um den Authentifizierungsprozess abzuschließen. Weitere Anmeldeoptionen finden Sie unter Anmelden mit der Azure CLI.
    • Installieren Sie die Azure CLI-Erweiterungen bei der ersten Verwendung, wenn Sie dazu aufgefordert werden. Weitere Informationen zu Erweiterungen finden Sie unter Verwenden von Erweiterungen mit der Azure CLI.
    • Führen Sie az version aus, um die installierte Version und die abhängigen Bibliotheken zu ermitteln. Führen Sie az upgrade aus, um das Upgrade auf die aktuelle Version durchzuführen.

Herunterladen des Express.js-Beispielrepositorys

  1. Verwenden Sie Git, um das Express.js-Beispielrepository auf Ihrem lokalen Computer zu klonen.

    git clone https://github.com/Azure-Samples/js-e2e-express-server
    
  2. Wechseln Sie in das neue Verzeichnis mit dem Beispiel.

    cd js-e2e-express-server
    
  3. Öffnen Sie das Projekt in Visual Studio Code.

    code .
    
  4. Öffnen Sie in Visual Studio Code ein neues Terminal, und installieren Sie die Projektabhängigkeiten.

    npm install
    

Installieren des Cognitive Services Speech SDK für JavaScript

Installieren Sie über das Visual Studio Code-Terminal das Azure Cognitive Services Speech SDK.

npm install microsoft-cognitiveservices-speech-sdk

Erstellen eines Speech-Moduls für die Express.js-App

  1. Erstellen Sie im Ordner src eine Datei mit dem Namen azure-cognitiveservices-speech.js, um das Speech SDK in die Express.js-Anwendung zu integrieren.

  2. Fügen Sie den folgenden Code hinzu, um Abhängigkeiten zu pullen und eine Funktion für die Text-zu-Sprache-Konvertierung zu erstellen.

    // 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
    };
    
    • Parameter: Mit der Datei werden die Abhängigkeiten für die Nutzung des SDK, der Streams, der Puffer und des Dateisystems (fs) gepullt. Für die Funktion textToSpeech werden vier Argumente verwendet. Wenn ein Dateiname mit einem lokalen Pfad gesendet wird, wird der Text in eine Audiodatei konvertiert. Wenn kein Dateiname gesendet wird, wird ein In-Memory-Audiostream erstellt.
    • Speech SDK-Methode: Mit der Speech SDK-Methode synthesizer.speakTextAsync werden basierend auf der empfangenen Konfiguration unterschiedliche Typen zurückgegeben. Die Methode gibt das Ergebnis zurück, das sich je nach dem, was die Methode zu tun hat, unterscheidet:
      • Datei erstellen
      • Erstellen eines In-Memory-Datenstroms als Array mit Puffern
    • Audioformat: Das ausgewählte Audioformat ist MP3. Es gibt aber auch andere Formate und andere Methoden für die Audiokonfiguration.

    Mit der lokalen Methode textToSpeech wird die SDK-Rückruffunktion umschlossen und in eine Zusage konvertiert.

Erstellen einer neuen Route für die Express.js-App

  1. Öffnen Sie die Datei src/server.js.

  2. Fügen Sie das Modul azure-cognitiveservices-speech.js oben in der Datei als Abhängigkeit hinzu:

    const { textToSpeech } = require('./azure-cognitiveservices-speech');
    
  3. Fügen Sie eine neue API-Route für den Aufruf der textToSpeech-Methode hinzu, die im vorherigen Abschnitt des Tutorials erstellt wurde. Fügen Sie diesen Code nach der /api/hello Route hinzu.

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

    Bei dieser Methode werden die erforderlichen und optionalen Parameter für die textToSpeech-Methode aus der Abfragezeichenfolge verwendet. Wenn eine Datei erstellt werden muss, wird ein eindeutiger Dateiname entwickelt. Die textToSpeech-Methode wird asynchron aufgerufen, und das Ergebnis wird per Pipe-Zeichen mit dem Antwortobjekt (res) verbunden.

Aktualisieren der Clientwebseite mit einem Formular

Aktualisieren Sie die HTML-Webseite des Clients mit einem Formular, mit dem die erforderlichen Parameter erfasst werden. Der optionale Parameter wird basierend darauf übergeben, welches Audiosteuerelement der Benutzer auswählt. Da dieses Tutorial ein Verfahren zum Aufrufen des Azure Speech-Diensts über den Client umfasst, ist auch der entsprechende JavaScript-Code angegeben.

Öffnen Sie die Datei /public/client.html, und ersetzen Sie ihren Inhalt durch Folgendes:

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

Hervorgehobene Zeilen in der Datei:

  • Zeile 74: Das Azure Speech SDK wird mithilfe der cdn.jsdelivr.net Website in die Clientbibliothek abgerufen, um das NPM-Paket bereitzustellen.
  • Zeile 102: Die updateSrc Methode aktualisiert die URL der Audiosteuerelemente src mit der Abfragezeichenfolge, einschließlich Schlüssel, Region und Text.
  • Zeile 137: Wenn ein Benutzer die Get directly from Azure Schaltfläche auswählt, ruft die Webseite direkt von der Clientseite an Azure auf und verarbeitet das Ergebnis.

Erstellen einer Cognitive Services Speech-Ressource

Erstellen Sie die Speech-Ressource mit Azure CLI-Befehlen in einer Azure Cloud Shell-Instanz.

  1. Melden Sie sich bei Azure Cloud Shell an. Hierfür müssen Sie sich in einem Browser mit einem Konto authentifizieren, das über die Berechtigung zur Verwendung eines gültigen Azure-Abonnements verfügt.

  2. Erstellen Sie eine Ressourcengruppe für Ihre Speech-Ressource.

    az group create \
        --location eastus \
        --name tutorial-resource-group-eastus
    
  3. Erstellen Sie in der Ressourcengruppe eine Speech-Ressource.

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

    Für diesen Befehl tritt ein Fehler auf, falls Ihre kostenlose Speech-Ressource bereits erstellt wurde.

  4. Verwenden Sie den Befehl, um die Schlüsselwerte für die neue Speech-Ressource abzurufen.

    az cognitiveservices account keys list \
        --name tutorial-speech \
        --resource-group tutorial-resource-group-eastus \
        --output table
    
  5. Kopieren Sie einen der Schlüssel.

    Sie verwenden den Schlüssel, indem Sie ihn in das Webformular der Express-App einfügen, um sich beim Azure Speech-Dienst zu authentifizieren.

Ausführen der Express.js-App für die Text-zu-Sprache-Konvertierung

  1. Starten Sie die App mit dem folgenden Bash-Befehl.

    npm start
    
  2. Öffnen Sie die Web-App in einem Browser.

    http://localhost:3000    
    
  3. Fügen Sie Ihren Speech-Schlüssel in das hervorgehobene Textfeld ein.

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

  4. Wenn Sie möchten, können Sie den Text ändern.

  5. Wählen Sie eine der drei Schaltflächen aus, um die Konvertierung in das Audioformat zu starten:

    • Direktes Abrufen aus Azure: Clientseitiger Aufruf von Azure
    • Audiosteuerelement für Audiodaten aus Datei
    • Audiosteuerelement für Audiodaten aus Puffer

    Unter Umständen kommt es zwischen der Auswahl des Steuerelements und der Wiedergabe der Audiodaten zu einer kurzen Verzögerung.

Erstellen einer neuen Azure App Service-Instanz in Visual Studio Code

  1. Geben Sie in der Befehlspalette (STRG+UMSCHALT+P) "Web erstellen" ein, und wählen Sie Azure-App Dienst aus: Neue Web App erstellen... Erweitert. Sie verwenden den erweiterten Befehl anstelle der Linux-Standardeinstellungen, um die vollständige Kontrolle über die Bereitstellung zu haben, einschließlich Ressourcengruppe, App Service-Plan und Betriebssystem.

  2. Gehen Sie bei den Aufforderungen wie folgt vor:

    • Wählen Sie Ihr Abonnementkonto aus.
    • Geben Sie unter Geben Sie einen global eindeutigen Namen ein einen Namen wie my-text-to-speech-app ein.
      • Der eingegebene Name muss innerhalb von Azure eindeutig sein. Verwenden Sie nur alphanumerische Zeichen („A - Z“, „a - z“ und „0 - 9“) und Bindestriche („-“).
    • Wählen Sie tutorial-resource-group-eastus als Ressourcengruppe aus.
    • Wählen Sie einen Runtimestapel einer Version aus, die Node und LTS beinhaltet.
    • Wählen Sie das Linux-Betriebssystem aus.
    • Wählen Sie Einen neuen App Services-Plan erstellen aus, und geben Sie einen Namen (etwa my-text-to-speech-app-plan) an.
    • Wählen Sie den kostenlosen TarifF1 aus. Wenn Ihr Abonnement bereits über eine kostenlose Web-App verfügt, wählen Sie den Tarif Basic aus.
    • Wählen Sie für die Application Insights-Ressource die Option Vorerst überspringen aus.
    • Wählen Sie den Standort eastus aus.
  3. Nach kurzer Zeit erhalten Sie von Visual Studio Code die Benachrichtigung, dass die Erstellung abgeschlossen ist. Schließen Sie die Benachrichtigung mit der Schaltfläche X.

Bereitstellen einer lokalen Express.js-App für eine App Service-Remoteinstanz in Visual Studio Code

  1. Da die Web-App nun vorhanden ist, können Sie Ihren Code über den lokalen Computer bereitstellen. Wählen Sie das Azure-Symbol aus, um den Azure App Service-Explorer zu öffnen. Erweitern Sie anschließend Ihren Abonnementknoten, klicken Sie mit der rechten Maustaste auf den Namen der gerade erstellten Web-App, und wählen Sie In Web-App bereitstellen aus.

  2. Wählen Sie bei Bereitstellungsaufforderungen den Stammordner der Express.js-App, erneut Ihr Abonnementkonto und dann den Namen der zuvor erstellten Web-App my-text-to-speech-app aus.

  3. Wenn Sie bei der Bereitstellung unter Linux zur Ausführung von npm install aufgefordert werden, wählen Sie Ja aus, wenn Sie aufgefordert werden, Ihre Konfiguration für die Ausführung von npm install auf dem Zielserver zu aktualisieren.

    Prompt to update configuration on the target Linux server

  4. Wählen Sie nach Abschluss der Bereitstellung in der Aufforderung die Option Website durchsuchen aus, um Ihre neu bereitgestellte Web-App anzuzeigen.

  5. (Optional): Sie können Änderungen an Ihren Codedateien vornehmen und dann die Bereitstellung in Web App in der Azure-App Diensterweiterung verwenden, um die Web-App zu aktualisieren.

Streamen von Remotedienstprotokollen in Visual Studio Code

Zeigen Sie mithilfe von Aufrufen von console.log eine beliebige Ausgabe an, die die ausgeführte App generiert. Diese Ausgabe wird im Fenster Ausgabe in Visual Studio Code angezeigt.

  1. Klicken Sie im Azure App Service-Explorer mit der rechten Maustaste auf Ihren neuen App-Knoten, und wählen Sie Start Streaming Logs (Streamen der Protokolle starten) aus.

     Starting Live Log Stream ---
     
  2. Aktualisieren Sie die Webseite im Browser einige Male, um die zusätzliche Protokollausgabe anzuzeigen.

Bereinigen der Ressourcen durch das Entfernen der Ressourcengruppe

Nach Abschluss dieses Tutorials müssen Sie die Ressourcengruppe entfernen, in der die Ressource enthalten ist, um sicherzustellen, dass Ihnen hierfür keine weiteren Nutzungskosten in Rechnung gestellt werden.

Verwenden Sie in Azure Cloud Shell den Azure CLI-Befehl, um die Ressourcengruppe zu löschen:

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

Die Ausführung dieses Befehls kann mehrere Minuten dauern.

Nächste Schritte