https://d226lax1qjow5r.cloudfront.net/blog/blogposts/building-a-real-time-net-transcription-service-dr/Blog_Real-Time_NET-Transcription_1200x600-1.png

Aufbau eines .NET-Transkriptionsdienstes in Echtzeit

Zuletzt aktualisiert am May 18, 2021

Lesedauer: 4 Minuten

Der Aufbau von Sprache-zu-Text-Transkriptionsdiensten war noch nie so einfach. In dieser Demo werden Sie einen extrem einfachen, aber leistungsstarken Echtzeit-Transkriptionsdienst in ASP.NET erstellen, der das Vonage .NET SDK und Microsoft Azure's Sprach-SDK.

Voraussetzungen

  • Visual Studio 2019 Version 16.3 oder höher

  • Ein Azure Account

  • Fakultativ: Ngrok für den Testeinsatz

Vonage API-Konto

Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.

In diesem Lernprogramm wird auch eine virtuelle Telefonnummer verwendet. Um eine zu erwerben, gehen Sie zu Rufnummern > Rufnummern kaufen und suchen Sie nach einer Nummer, die Ihren Anforderungen entspricht.

Azure Cognitive Services Ressource erstellen

  • Gehen Sie zu Ihrem Azure Dashboard

  • Öffnen Sie das Hamburger-Menü und wählen Sie "Ressource erstellen".

  • Suchen Sie nach Sprache und erstellen Sie eine Sprachressource:

Speech Resource page

  • Füllen Sie das Erstellungsformular aus. Zu Demonstrationszwecken können Sie die folgenden Eingaben verwenden

    • Name: TranscriptionTest

    • Abonnement: umlagefinanziert

    • Standort: Osten der USA

    • Preisstufe: F0

    • Ressourcengruppe: Transkription

Das Hochfahren wird einige Zeit in Anspruch nehmen. Sobald die Anwendung gestartet ist, navigieren Sie zum Abschnitt Schnellstart, um Ihre Zugangsschlüssel zu sammeln. Sie suchen nach dem Key1 Wert, also suchen Sie nach dem hervorgehobenen Abschnitt:

Quick Start Section

Speichern Sie diesen Schlüsselwert vorerst offline irgendwo.

Aufbau des Transkriptionsdienstes in Echtzeit

Projekt einrichten

Öffnen Sie Visual Studio und erstellen Sie ein neues Projekt ASP.NET Core WebApplication. Zum Beispiel: "TranscriptionBlogPostDemo".

Für diese Demonstration werden Sie nun eine MVC-Webanwendung in ASP.NET Core 3.0 erstellen.

Web Application Type Selection

Fügen Sie nun die folgenden Nuget-Pakete zum Projekt hinzu:

  • Nexmo.Csharp.Client

  • Newtonsoft.Json

  • Microsoft.CognitiveServices.Speech

Transkriptionsmaschine

Erstellen Sie mit diesen importierten Projekten eine neue Klasse namens TranscriptionEngine.

Definieren Sie zunächst einige Konstanten, die sowohl für das Sprach-SDK als auch für die Verwaltung des WebSocket-Puffers nützlich sind.

const int SAMPLES_PER_SECOND = 8000;
const int BITS_PER_SAMPLE = 16;
const int NUMBER_OF_CHANNELS = 1;
const int BUFFER_SIZE = 160 * 2;

Fügen Sie dann der Klasse das folgende Feld hinzu:

  • _config - hier werden die Abonnement-/Regionalinformationen des Sprachanalysators gespeichert. Die Region in der Demo ist eastus - abgeleitet von der Region, für die Sie Ihren Sprachdienst konfiguriert haben. Für eine Zuordnung von Region zu Eingabe-String siehe die Microsoft Azure Speech Service Supported Regions Dokumentation

  • _inputStream - dies wird ein Push-Stream sein, der als Puffer dient, der zum Azure Speech-to-Text-Dienst gestreamt wird

  • _audioInput - dies wird die Eingabe für den Spracherkenner sein

  • _recognizer - dies ist der Erkenner, der die Spracherkennungsaufgabe durchführen wird

Diese können wie folgt definiert werden:

SpeechConfig _config = SpeechConfig.FromSubscription("your_subscription_key", "your_azure_region"); // e.g. eastus
PushAudioInputStream _inputStream = AudioInputStream.CreatePushStream(AudioStreamFormat.GetWaveFormatPCM(SAMPLES_PER_SECOND, BITS_PER_SAMPLE, NUMBER_OF_CHANNELS));
AudioConfig _audioInput;
SpeechRecognizer _recognizer;

Da einige der Felder IDisposable sind, sollte diese Klasse IDisposable implementieren und alle Einwegfelder auf ihrem Weg nach unten einfach entsorgen

public void Dispose()
{
    _inputStream.Dispose();
    _audioInput.Dispose();
    _recognizer.Dispose();
}

Fügen Sie dann einen Konstruktor hinzu, der _audioInput mit dem oben definierten Push-Input-Stream initialisiert:

public TranscriptionEngine()
{
    _audioInput = AudioConfig.FromStreamInput(_inputStream);
}

Fügen Sie als Nächstes die Methode hinzu, die auf Spracherkennungsereignisse des Erkenners wartet

private void RecognizerRecognized(object sender, SpeechRecognitionEventArgs e)
{
    Trace.WriteLine("Recognized: " + e.Result.Text);
}

Von hier aus können Sie eine Funktion zum Anhalten und Starten des Spracherkenners hinzufügen.

Die Methode start Methode akzeptiert eine Sprachzeichenkette, setzt die Sprache der SpeechConfig, initialisiert den Recognizer mit der Konfiguration und der Audioeingabequelle, registriert das zuvor erstellte Ereignis RecognizerRecognized und startet eine kontinuierliche Erkennung.

Ihre stop Methode hebt die Registrierung des Ereignisses RecognizerRecognized auf und stoppt den Erkenner.

HINWEIS: Der StopContinuousRecognitionAsync kann bis zu 20 Sekunden dauern, da es derzeit keinen Mechanismus zum Abbrechen des laufenden Eingabestroms gibt. In dieser Demo wird dieses Problem explizit entschärft, indem der Recognizer zwischen den Aufrufen nicht wiederverwendet wird und das Herunterfahren des Sockets nicht blockiert wird, um den Vorgang abzuschließen.

public async Task StartSpeechTranscriptionEngine(string language)
{
    _config.SpeechRecognitionLanguage = language;
    _recognizer = new SpeechRecognizer(_config, _audioInput);
    _recognizer.Recognized += RecognizerRecognized;
    await _recognizer.StartContinuousRecognitionAsync();
}

private async Task StopTranscriptionEngine()
{
    if(_recognizer != null)
    {
        _recognizer.Recognized -= RecognizerRecognized;
        await _recognizer.StopContinuousRecognitionAsync();
    }
}

Die letzte Aufgabe, die diese Klasse übernehmen wird, ist der Empfang von Audiodaten über den Websocket, den Sie einrichten werden, und deren Weiterleitung an den zuvor erstellten PushAudioStream. Dies wird erwartet, nachdem der Websocket eingerichtet wurde, und zwar so lange, bis der Websocket geschlossen wird.

public async Task ReceiveAudioOnWebSocket(HttpContext context, WebSocket webSocket)
{
    var buffer = new byte[BUFFER_SIZE];

    try
    {
        var language = "en-US";
        await StartSpeechTranscriptionEngine(language);
        WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        while (!result.CloseStatus.HasValue)
        {
            await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

            result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

            _inputStream.Write(buffer);
        }
        await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
    }
    catch (Exception e)
    {
        Trace.WriteLine(e.ToString());
    }
    finally
    {
        await StopTranscriptionEngine();
    }
}

HINWEIS: Der anfängliche Puffer, den Sie vom Websocket zurückerhalten, enthält Metadaten für den Aufruf. Wenn Sie möchten, können Sie diese Daten aus dem ersten ReceiveAsync extrahieren - für die Zwecke der Demo wird dies jedoch nicht getan, da der Puffer und der Recognizer robust genug sind, um damit umzugehen.

Einrichten von WebSockets in Ihrer Anwendung

Öffnen Sie Startup.cs.

In der Configure-Methode werden Sie Websockets auf dem Server aktivieren und ein Stück Websocket-Middleware bereitstellen, um Websockets zu verwenden und einen eingehenden Websocket zu verbinden und die TranscriptionEngine zu verwenden, um Audio über diesen Socket zu empfangen.

var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
    ReceiveBufferSize = 320
};

app.UseWebSockets(webSocketOptions);

app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
            using (var engine = new TranscriptionEngine())
            {
                await engine.ReceiveAudioOnWebSocket(context, webSocket);
            }
        }
        else
        {
            context.Response.StatusCode = 400;
        }
    }
    else
    {
        await next();
    }
});

Einrichten des Voice Controllers

Der letzte Teil des Codes, der implementiert werden muss, ist das Hinzufügen eines Voice Controllers. Fügen Sie einen neuen Controller unter der Datei Controller hinzu und nennen Sie ihn VoiceController. Fügen Sie eine konstante Zeichenfolge für die BASE_URL Ihres Dienstes hinzu.

const string BASE_URL = "BASE_URL";

Ihr Voice Controller wird zwei HTTP-Anfragen haben. Eine POST-Anfrage für den Ereignis-Webhook und eine GET-Anfrage für den Antwort-Webhook. Diese GET-Anfrage wird eine NCCO mit einer einzigen Connect-Aktion erstellen, die die Voice API anweist, einen WebSocket zu Ihrem Server zu öffnen und den Audiostrom über diesen Socket zurückzuschicken. Stellen Sie den Inhaltstyp auf ein lineares 16-Bit-PCM mit 8 kHz ein. Siehe unten:

[HttpPost]
public HttpStatusCode Events()
{
    return HttpStatusCode.OK;
}

[HttpGet]
public string Answer()
{
    var webSocketAction = new ConnectAction()
    {
        Endpoint = new[]
        {
            new WebsocketEndpoint()
            {
                Uri = $"wss://{BASE_URL}/ws",
                ContentType="audio/l16;rate=8000",

            }
        }
    };

    var ncco = new Ncco(webSocketAction);
    return ncco.ToString();
}

Einrichten und loslegen

Einrichten von IIS Express

Öffnen Sie den Eigenschaften-Dialog für Ihr Projekt, notieren Sie sich unter Debug die Portnummer - für die Demo deaktivieren Sie SSL, das erleichtert die Einrichtung von ngrok.

Einrichtung des Ngrok-Tunnels

Damit die Voice API die Ereignis-/Antwort-Webhooks weiterleiten kann, müssen Sie die Site dem Internet aussetzen - zu Testzwecken können Sie ngrok verwenden, um unseren IIS-Express-Port freizugeben. Öffnen Sie Ihre Befehlszeile und verwenden Sie diesen Befehl, ersetzen Sie PORT_NUMBER durch die Portnummer Ihrer IIS-Express-Instanz.

ngrok http --host-header="localhost:PORT_NUMBER" http://localhost:PORT_NUMBER

Dieser Befehl erzeugt eine Ausgabe wie diese:

ngrok config

Einrichten der Vonage Voice-Anwendung

Der nächste Schritt ist das Einrichten einer Vonage Voice Application.

  • Navigieren Sie zu Ihrem Vonage Dashboard

  • Öffnen Sie im linken Bereich Voice und klicken Sie auf "Eine Anwendung erstellen".

  • Benennen Sie die Anwendung, z. B. 'TranscriptionTest'.

  • Unter Funktionen Voice aktivieren

  • Für Ereignis-URL hinzufügen base_url_of_ngrok_tunnel/voice/events

  • Für Antwort-URL base_url_of_ngrok_tunnel/voice/answer hinzufügen

  • Für Fallback-Antwort-URL base_url_of_ngrok_tunnel/voice/answer hinzufügen

Letzte Handgriffe

Jetzt, wo du die ngrok-URL hast, ändere die BASE_URL in der VoiceController-Datei in diese URL (ohne das 'http://')

Damit sind Sie startklar. Rufen Sie die mit Ihrer Anwendung verknüpfte Vonage-Nummer an, und die App überträgt Ihre Sprache auf die Debug-Konsole.

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/73d57fd8eb/stevelorello.png
Steve LorelloVonage Ehemalige

Ehemaliger .NET Developer Advocate @Vonage, polyglotter Software-Ingenieur, AI/ML