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

Création d'un service de transcription .NET en temps réel

Publié le May 18, 2021

Temps de lecture : 5 minutes

Il n'a jamais été aussi facile de créer des services de transcription de la parole vers le texte. Dans cette démo, vous construirez un service de transcription en temps réel extrêmement simple, mais puissant, en ASP.NET en utilisant le SDK .NET de Vonage de Vonage et Speech SDK de Microsoft Azure.

Conditions préalables

  • Visual Studio 2019 version 16.3 ou supérieure

  • Un Account Azure

  • Optionnel : Ngrok pour le déploiement de tests

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.

Créer une ressource Azure Cognitive Services

  • Accédez à votre tableau de bord Azure

  • Ouvrez le menu Hamburger et sélectionnez "Créer une ressource"

  • Recherche de discours et création d'une ressource de discours :

Speech Resource page

  • Remplissez le formulaire de création. À titre de démonstration, vous pouvez utiliser les entrées suivantes

    • Nom : TranscriptionTest

    • Abonnement : pay-as-you-go

    • Lieu : Est des États-Unis

    • Niveau de tarification : F0

    • Groupe de ressources : Transcription

Cela prendra un certain temps pour démarrer. Une fois qu'il est déployé, vous allez naviguer jusqu'à la section "Quick Start" pour rassembler vos clés d'accès. Vous recherchez la valeur Key1 donc cherchez la section en surbrillance :

Quick Start Section

Conservez cette valeur de clé hors ligne quelque part pour le moment.

Construire le service de transcription en temps réel

Configuration du projet

Ouvrez Visual Studio et créez un nouveau projet ASP.NET Core WebApplication. Par exemple, "TranscriptionBlogPostDemo"

Maintenant, vous allez créer une application web MVC pour cette démonstration en ASP.NET Core 3.0.

Web Application Type Selection

Une fois ce projet créé, ajoutez les paquets nuget suivants au projet :

  • Nexmo.Csharp.Client

  • Newtonsoft.Json

  • Microsoft.CognitiveServices.Speech

Moteur de transcription

Une fois ces projets importés, créez une nouvelle classe appelée TranscriptionEngine.

Tout d'abord, définissez quelques constantes pour le SDK vocal et pour la gestion de la mémoire tampon WebSocket.

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

Ensuite, ajoutez le champ suivant à la classe :

  • _config - il contient les informations relatives à l'abonnement et à la région de l'analyseur de la parole. La région utilisée dans la démo est eastus - dérivée de la région pour laquelle vous avez configuré votre service vocal. Pour une correspondance entre la région et la chaîne d'entrée, voir la documentation Microsoft Azure Speech Service Supported Regions Documentation

  • InputStream - il s'agit d'un flux push qui servira de tampon pour le service Azure Speech-to-text.

  • _audioInput - il s'agit de l'entrée de l'outil de reconnaissance vocale

  • _recognizer - il s'agit du reconnaisseur qui effectuera la tâche de reconnaissance vocale

Ils peuvent être définis comme suit :

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;

Étant donné que plusieurs des champs sont des IDisposable, cette classe doit implémenter IDisposable et se débarrasser simplement de tous les champs jetables en descendant.

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

Ajoutez ensuite un constructeur qui initialisera l'_audioInput avec le flux d'entrée push défini ci-dessus :

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

Ensuite, ajoutez la méthode qui écoutera les événements de reconnaissance vocale provenant de l'outil de reconnaissance

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

À partir de là, vous pouvez ajouter une fonction pour arrêter et démarrer la reconnaissance vocale.

La méthode start accepte une chaîne de langue, définit la langue du SpeechConfig, initialise le Recognizer avec la configuration et la source d'entrée audio, enregistre l'événement RecognizerRecognized que vous avez créé plus tôt, et démarre une reconnaissance continue.

Votre méthode stop désenregistrera l'événement RecognizerRecognized et arrêtera l'outil de reconnaissance.

NOTE : Le StopContinuousRecognitionAsync peut prendre jusqu'à 20 secondes car il n'y a pas de mécanisme pour annuler le flux d'entrée en cours d'exécution à ce jour. Cette démo atténue explicitement ce problème en ne réutilisant pas l'outil de reconnaissance entre les appels, et en ne bloquant pas l'arrêt du socket pour que cela se termine.

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

La dernière tâche de cette classe sera de recevoir de l'audio sur le websocket que vous allez mettre en place, et de l'envoyer vers le PushAudioStream que vous avez créé plus tôt. Ce dernier sera attendu une fois la socket web établie et continuera à l'être jusqu'à ce que la socket web soit fermée.

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

NOTE : Le tampon initial que vous recevez en retour du websocket contiendra des métadonnées pour l'appel - et si vous le souhaitez, vous pouvez extraire ces données du premier ReceiveAsync - pour les besoins de la démo, cela n'est pas fait, car le tampon et le Recognizer sont suffisamment robustes pour être gérés.

Mise en place de WebSockets dans votre application

Ouvrir Startup.cs.

Dans la méthode de configuration, vous activerez les websockets sur le serveur et fournirez un intergiciel de websocket pour utiliser les websockets, et pour connecter un websocket entrant et utiliser le TranscriptionEngine pour recevoir de l'audio sur ce socket.

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

Configuration du Voice Controller

Le dernier élément de code à mettre en œuvre est l'ajout d'un contrôleur Voice. Ajoutez un nouveau contrôleur sous le fichier Controller et nommez-le VoiceController. Ajoutez une chaîne constante pour le BASE_URL de votre service.

const string BASE_URL = "BASE_URL";

Votre Voice Controller aura deux requêtes HTTP. Une demande POST pour le webhook d'événement et une demande GET pour le webhook de réponse. Cette demande GET va construire un NCCO avec une action de connexion unique qui demandera à l'API Voice d'ouvrir une WebSocket vers votre serveur et de renvoyer le flux audio sur cette socket. Définissez le type de contenu à un PCM linéaire de 16 bits fonctionnant à 8 kHz. Voir ci-dessous :

[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();
}

Mise en place et fonctionnement

Configuration de IIS Express

Ouvrez la boîte de dialogue des propriétés de votre projet, sous debug notez le numéro de port - pour la démo, désactivez SSL, ce qui facilitera l'installation de ngrok.

Mise en place du tunnel de Ngrok

Pour que l'API Voice transmette les webhooks Event/Answer, vous devez exposer le site à l'internet - à des fins de test, vous pouvez utiliser ngrok pour exposer notre port express IIS. Ouvrez votre ligne de commande et utilisez cette commande, remplacez PORT_NUMBER par le numéro de port de votre instance IIS Express.

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

Cette commande produit un résultat comme celui-ci :

ngrok config

Configuration de l'application Voice de Vonage

L'étape suivante consiste à mettre en place une application Voice de Vonage.

  • Naviguez vers votre tableau de bord Vonage

  • Dans le volet de gauche, ouvrez Voice et cliquez sur "Créer une application".

  • Nommez l'application, par exemple "TranscriptionTest".

  • Sous Capacités, activer Voice

  • Pour l'URL de l'événement, ajouter base_url_of_ngrok_tunnel/voice/events

  • Pour l'URL de la réponse, ajouter base_url_of_ngrok_tunnel/voice/answer.

  • Pour l'URL de réponse de repli, ajouter base_url_of_ngrok_tunnel/voice/answer.

Dernières touches

Maintenant que vous avez l'URL de ngrok, changez le BASE_URL dans le fichier VoiceController en cette url (en excluant le 'http://')

Vous êtes alors opérationnel. Appelez le numéro Vonage lié à votre application, et l'Applications transcrira votre discours dans la console de débogage.

Liens supplémentaires Ressources

Partager:

https://a.storyblok.com/f/270183/384x384/73d57fd8eb/stevelorello.png
Steve LorelloAnciens de Vonage

Ancien développeur .NET Advocate @Vonage, ingénieur logiciel polyglotte full-stack, AI/ML