Reconnaissance vocale à l’aide d’Azure Speech Service

Azure Speech Service est une API basée sur le cloud qui offre les fonctionnalités suivantes :

  • La reconnaissance vocale transcrit des fichiers audio ou des flux en texte.
  • La synthèse vocale convertit le texte d’entrée en synthèse vocale de type humain.
  • La traduction vocale permet une traduction en temps réel en plusieurs langues pour la reconnaissance vocale et la reconnaissance vocale.
  • Les assistants vocaux peuvent créer des interfaces de conversation de type humain pour les applications.

Cet article explique comment la reconnaissance vocale est implémentée dans l’exemple d’application Xamarin.Forms à l’aide du service Azure Speech. Les captures d’écran suivantes montrent l’exemple d’application sur iOS et Android :

Captures d’écran de l’exemple d’application sur iOS et Android

Créer une ressource Azure Speech Service

Azure Speech Service fait partie d’Azure Cognitive Services, qui fournit des API basées sur le cloud pour des tâches telles que la reconnaissance d’images, la reconnaissance vocale et la traduction vocale et la recherche Bing. Pour plus d’informations, consultez Qu’est-ce qu’Azure Cognitive Services ?.

L’exemple de projet nécessite la création d’une ressource Azure Cognitive Services dans votre Portail Azure. Une ressource Cognitive Services peut être créée pour un seul service, tel que le service Speech, ou en tant que ressource multiservices. Les étapes de création d’une ressource de service Speech sont les suivantes :

  1. Connectez-vous à votre Portail Azure.
  2. Créez une ressource multiservices ou à service unique.
  3. Obtenez les informations de clé d’API et de région pour votre ressource.
  4. Mettez à jour l’exemple de fichier Constants.cs .

Pour obtenir un guide pas à pas pour créer une ressource, consultez Créer une ressource Cognitive Services.

Remarque

Si vous n’avez pas d’abonnement Azure, créez un compte gratuit avant de commencer. Une fois que vous disposez d’un compte, une ressource à service unique peut être créée au niveau gratuit pour essayer le service.

Configurer votre application avec le service Speech

Après avoir créé une ressource Cognitive Services, le fichier Constants.cs peut être mis à jour avec la région et la clé API à partir de votre ressource Azure :

public static class Constants
{
    public static string CognitiveServicesApiKey = "YOUR_KEY_GOES_HERE";
    public static string CognitiveServicesRegion = "westus";
}

Installer le package du service NuGet Speech

L’exemple d’application utilise le package NuGet Microsoft.CognitiveServices.Speech pour se connecter au service Azure Speech. Installez ce package NuGet dans le projet partagé et chaque projet de plateforme.

Créer une interface IMicrophoneService

Chaque plateforme nécessite l’autorisation d’accéder au microphone. L’exemple de projet fournit une IMicrophoneService interface dans le projet partagé et utilise les Xamarin.FormsDependencyService implémentations de plateforme de l’interface.

public interface IMicrophoneService
{
    Task<bool> GetPermissionAsync();
    void OnRequestPermissionResult(bool isGranted);
}

Créer la mise en page

L’exemple de projet définit une mise en page de base dans le fichier MainPage.xaml . Les éléments de disposition clés sont un Button élément qui démarre le processus de transcription, un Label pour contenir le texte transcrit et un ActivityIndicator à afficher lorsque la transcription est en cours :

<ContentPage ...>
    <StackLayout>
        <Frame ...>
            <ScrollView x:Name="scroll"
                        ...>
                <Label x:Name="transcribedText"
                       ... />
            </ScrollView>
        </Frame>

        <ActivityIndicator x:Name="transcribingIndicator"
                           IsRunning="False" />
        <Button x:Name="transcribeButton"
                ...
                Clicked="TranscribeClicked"/>
    </StackLayout>
</ContentPage>

Implémenter le service Speech

Le fichier code-behind MainPage.xaml.cs contient toute la logique permettant d’envoyer du texte audio et de recevoir du texte transcrit à partir du service Azure Speech.

Le MainPage constructeur obtient une instance de l’interface IMicrophoneService à partir de :DependencyService

public partial class MainPage : ContentPage
{
    SpeechRecognizer recognizer;
    IMicrophoneService micService;
    bool isTranscribing = false;

    public MainPage()
    {
        InitializeComponent();

        micService = DependencyService.Resolve<IMicrophoneService>();
    }

    // ...
}

La TranscribeClicked méthode est appelée lorsque l’instance transcribeButton est tapée :

async void TranscribeClicked(object sender, EventArgs e)
{
    bool isMicEnabled = await micService.GetPermissionAsync();

    // EARLY OUT: make sure mic is accessible
    if (!isMicEnabled)
    {
        UpdateTranscription("Please grant access to the microphone!");
        return;
    }

    // initialize speech recognizer
    if (recognizer == null)
    {
        var config = SpeechConfig.FromSubscription(Constants.CognitiveServicesApiKey, Constants.CognitiveServicesRegion);
        recognizer = new SpeechRecognizer(config);
        recognizer.Recognized += (obj, args) =>
        {
            UpdateTranscription(args.Result.Text);
        };
    }

    // if already transcribing, stop speech recognizer
    if (isTranscribing)
    {
        try
        {
            await recognizer.StopContinuousRecognitionAsync();
        }
        catch(Exception ex)
        {
            UpdateTranscription(ex.Message);
        }
        isTranscribing = false;
    }

    // if not transcribing, start speech recognizer
    else
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            InsertDateTimeRecord();
        });
        try
        {
            await recognizer.StartContinuousRecognitionAsync();
        }
        catch(Exception ex)
        {
            UpdateTranscription(ex.Message);
        }
        isTranscribing = true;
    }
    UpdateDisplayState();
}

La méthode TranscribeClicked effectue les opérations suivantes :

  1. Vérifie si l’application a accès au microphone et quitte tôt si ce n’est pas le cas.
  2. Crée une instance de SpeechRecognizer classe si elle n’existe pas déjà.
  3. Arrête la transcription continue si elle est en cours.
  4. Insère un horodatage et démarre la transcription continue si elle n’est pas en cours.
  5. Avertit l’application de mettre à jour son apparence en fonction de l’état de la nouvelle application.

Le reste des méthodes de classe sont des helpers pour afficher l’état de MainPage l’application :

void UpdateTranscription(string newText)
{
    Device.BeginInvokeOnMainThread(() =>
    {
        if (!string.IsNullOrWhiteSpace(newText))
        {
            transcribedText.Text += $"{newText}\n";
        }
    });
}

void InsertDateTimeRecord()
{
    var msg = $"=================\n{DateTime.Now.ToString()}\n=================";
    UpdateTranscription(msg);
}

void UpdateDisplayState()
{
    Device.BeginInvokeOnMainThread(() =>
    {
        if (isTranscribing)
        {
            transcribeButton.Text = "Stop";
            transcribeButton.BackgroundColor = Color.Red;
            transcribingIndicator.IsRunning = true;
        }
        else
        {
            transcribeButton.Text = "Transcribe";
            transcribeButton.BackgroundColor = Color.Green;
            transcribingIndicator.IsRunning = false;
        }
    });
}

La UpdateTranscription méthode écrit l’élément fourni LabelnewTextstring nommé .transcribedText Elle force cette mise à jour à se produire sur le thread d’interface utilisateur afin qu’elle puisse être appelée à partir de n’importe quel contexte sans provoquer d’exceptions. Écrit InsertDateTimeRecord la date et l’heure actuelles dans l’instance transcribedText pour marquer le début d’une nouvelle transcription. Enfin, la UpdateDisplayState méthode met à jour les éléments et ActivityIndicator les Button éléments pour refléter si la transcription est en cours ou non.

Créer des services de microphone de plateforme

L’application doit disposer d’un accès microphone pour collecter des données vocales. L’interface IMicrophoneService doit être implémentée et inscrite auprès de chaque DependencyService plateforme pour que l’application fonctionne.

Android

L’exemple de projet définit une IMicrophoneService implémentation pour Android appelée AndroidMicrophoneService:

[assembly: Dependency(typeof(AndroidMicrophoneService))]
namespace CognitiveSpeechService.Droid.Services
{
    public class AndroidMicrophoneService : IMicrophoneService
    {
        public const int RecordAudioPermissionCode = 1;
        private TaskCompletionSource<bool> tcsPermissions;
        string[] permissions = new string[] { Manifest.Permission.RecordAudio };

        public Task<bool> GetPermissionAsync()
        {
            tcsPermissions = new TaskCompletionSource<bool>();

            if ((int)Build.VERSION.SdkInt < 23)
            {
                tcsPermissions.TrySetResult(true);
            }
            else
            {
                var currentActivity = MainActivity.Instance;
                if (ActivityCompat.CheckSelfPermission(currentActivity, Manifest.Permission.RecordAudio) != (int)Permission.Granted)
                {
                    RequestMicPermissions();
                }
                else
                {
                    tcsPermissions.TrySetResult(true);
                }

            }

            return tcsPermissions.Task;
        }

        public void OnRequestPermissionResult(bool isGranted)
        {
            tcsPermissions.TrySetResult(isGranted);
        }

        void RequestMicPermissions()
        {
            if (ActivityCompat.ShouldShowRequestPermissionRationale(MainActivity.Instance, Manifest.Permission.RecordAudio))
            {
                Snackbar.Make(MainActivity.Instance.FindViewById(Android.Resource.Id.Content),
                        "Microphone permissions are required for speech transcription!",
                        Snackbar.LengthIndefinite)
                        .SetAction("Ok", v =>
                        {
                            ((Activity)MainActivity.Instance).RequestPermissions(permissions, RecordAudioPermissionCode);
                        })
                        .Show();
            }
            else
            {
                ActivityCompat.RequestPermissions((Activity)MainActivity.Instance, permissions, RecordAudioPermissionCode);
            }
        }
    }
}

Les AndroidMicrophoneService fonctionnalités suivantes sont les suivantes :

  1. L’attribut Dependency inscrit la classe avec le DependencyService.
  2. La GetPermissionAsync méthode case activée si des autorisations sont requises en fonction de la version du Kit de développement logiciel (SDK) Android et appelle RequestMicPermissions si l’autorisation n’a pas déjà été accordée.
  3. La RequestMicPermissions méthode utilise la Snackbar classe pour demander des autorisations à l’utilisateur si une justification est requise, sinon elle demande directement des autorisations d’enregistrement audio.
  4. La OnRequestPermissionResult méthode est appelée avec un bool résultat une fois que l’utilisateur a répondu à la demande d’autorisations.

La MainActivity classe est personnalisée pour mettre à jour l’instance AndroidMicrophoneService lorsque les demandes d’autorisations sont terminées :

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    IMicrophoneService micService;
    internal static MainActivity Instance { get; private set; }

    protected override void OnCreate(Bundle savedInstanceState)
    {
        Instance = this;
        // ...
        micService = DependencyService.Resolve<IMicrophoneService>();
    }
    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
    {
        // ...
        switch(requestCode)
        {
            case AndroidMicrophoneService.RecordAudioPermissionCode:
                if (grantResults[0] == Permission.Granted)
                {
                    micService.OnRequestPermissionResult(true);
                }
                else
                {
                    micService.OnRequestPermissionResult(false);
                }
                break;
        }
    }
}

La MainActivity classe définit une référence statique appelée Instance, qui est requise par l’objet lors de la AndroidMicrophoneService demande d’autorisations. Il remplace la OnRequestPermissionsResult méthode pour mettre à jour l’objet AndroidMicrophoneService lorsque la demande d’autorisations est approuvée ou refusée par l’utilisateur.

Enfin, l’application Android doit inclure l’autorisation d’enregistrer l’audio dans le fichier AndroidManifest.xml :

<manifest ...>
    ...
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>

iOS

L’exemple de projet définit une IMicrophoneService implémentation pour iOS appelée iOSMicrophoneService:

[assembly: Dependency(typeof(iOSMicrophoneService))]
namespace CognitiveSpeechService.iOS.Services
{
    public class iOSMicrophoneService : IMicrophoneService
    {
        TaskCompletionSource<bool> tcsPermissions;

        public Task<bool> GetPermissionAsync()
        {
            tcsPermissions = new TaskCompletionSource<bool>();
            RequestMicPermission();
            return tcsPermissions.Task;
        }

        public void OnRequestPermissionResult(bool isGranted)
        {
            tcsPermissions.TrySetResult(isGranted);
        }

        void RequestMicPermission()
        {
            var session = AVAudioSession.SharedInstance();
            session.RequestRecordPermission((granted) =>
            {
                tcsPermissions.TrySetResult(granted);
            });
        }
    }
}

Les iOSMicrophoneService fonctionnalités suivantes sont les suivantes :

  1. L’attribut Dependency inscrit la classe avec le DependencyService.
  2. La GetPermissionAsync méthode appelle RequestMicPermissions pour demander des autorisations à l’utilisateur de l’appareil.
  3. La RequestMicPermissions méthode utilise l’instance partagée AVAudioSession pour demander des autorisations d’enregistrement.
  4. La OnRequestPermissionResult méthode met à jour l’instance TaskCompletionSource avec la valeur fournie bool .

Enfin, l’application iOS Info.plist doit inclure un message indiquant à l’utilisateur pourquoi l’application demande l’accès au microphone. Modifiez le fichier Info.plist pour inclure les balises suivantes dans l’élément <dict> :

<plist>
    <dict>
        ...
        <key>NSMicrophoneUsageDescription</key>
        <string>Voice transcription requires microphone access</string>
    </dict>
</plist>

UWP

L’exemple de projet définit une IMicrophoneService implémentation pour UWP appelée UWPMicrophoneService:

[assembly: Dependency(typeof(UWPMicrophoneService))]
namespace CognitiveSpeechService.UWP.Services
{
    public class UWPMicrophoneService : IMicrophoneService
    {
        public async Task<bool> GetPermissionAsync()
        {
            bool isMicAvailable = true;
            try
            {
                var mediaCapture = new MediaCapture();
                var settings = new MediaCaptureInitializationSettings();
                settings.StreamingCaptureMode = StreamingCaptureMode.Audio;
                await mediaCapture.InitializeAsync(settings);
            }
            catch(Exception ex)
            {
                isMicAvailable = false;
            }

            if(!isMicAvailable)
            {
                await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-microphone"));
            }

            return isMicAvailable;
        }

        public void OnRequestPermissionResult(bool isGranted)
        {
            // intentionally does nothing
        }
    }
}

Les UWPMicrophoneService fonctionnalités suivantes sont les suivantes :

  1. L’attribut Dependency inscrit la classe avec le DependencyService.
  2. La GetPermissionAsync méthode tente d’initialiser une MediaCapture instance. En cas d’échec, il lance une demande d’utilisateur pour activer le microphone.
  3. La OnRequestPermissionResult méthode existe pour satisfaire l’interface, mais n’est pas requise pour l’implémentation UWP.

Enfin, le package.appxmanifest UWP doit spécifier que l’application utilise le microphone. Double-cliquez sur le fichier Package.appxmanifest et sélectionnez l’option Microphone sous l’onglet Fonctionnalités de Visual Studio 2019 :

Capture d’écran du manifeste dans Visual Studio 2019

Tester l’application

Exécutez l’application, puis cliquez sur le bouton Transcrire . L’application doit demander l’accès au microphone et commencer le processus de transcription. L’animation ActivityIndicator s’animera, montrant que la transcription est active. À mesure que vous parlez, l’application diffuse en continu des données audio vers la ressource Azure Speech Services, qui répond avec du texte transcrit. Le texte transcrit apparaît dans l’élément Label tel qu’il est reçu.

Remarque

Les émulateurs Android ne peuvent pas charger et initialiser les bibliothèques du service Speech. Le test sur un appareil physique est recommandé pour la plateforme Android.