Riconoscimento vocale con il servizio Voce di Azure

Download Sample Scaricare l'esempio

Il servizio Voce di Azure è un'API basata sul cloud che offre le funzionalità seguenti:

  • Il riconoscimento vocale trascrive file audio o flussi in testo.
  • La sintesi vocale converte il testo di input in una sintesi vocale simile a quella umana.
  • La traduzione vocale consente la traduzione multilingue in tempo reale sia per la sintesi vocale che per la sintesi vocale.
  • Gli assistenti vocali possono creare interfacce di conversazione simili a quella umana per le applicazioni.

Questo articolo illustra come viene implementato il riconoscimento vocale nell'applicazione di Xamarin.Forms esempio usando il servizio Voce di Azure. Gli screenshot seguenti mostrano l'applicazione di esempio in iOS e Android:

Screenshots of the sample application on iOS and Android

Creare una risorsa del servizio Voce di Azure

Il servizio Voce di Azure fa parte di Servizi cognitivi di Azure, che fornisce API basate sul cloud per attività quali il riconoscimento delle immagini, il riconoscimento vocale e la traduzione e la ricerca Bing. Per altre informazioni, vedere Informazioni su Servizi cognitivi di Azure.

Il progetto di esempio richiede la creazione di una risorsa di Servizi cognitivi di Azure nella portale di Azure. È possibile creare una risorsa di Servizi cognitivi per un singolo servizio, ad esempio il servizio Voce o come risorsa multiservizio. I passaggi per creare una risorsa del servizio Voce sono i seguenti:

  1. Accedere al portale di Azure.
  2. Creare una risorsa multiservizio o a servizio singolo.
  3. Ottenere le informazioni sulla chiave API e sull'area per la risorsa.
  4. Aggiornare il file di Constants.cs di esempio.

Per una guida dettagliata alla creazione di una risorsa, vedere Creare una risorsa di Servizi cognitivi.

Nota

Se non si ha una sottoscrizione di Azure, creare un account gratuito prima di iniziare. Dopo aver creato un account, è possibile creare una risorsa a servizio singolo al livello gratuito per provare il servizio.

Configurare l'app con il servizio Voce

Dopo aver creato una risorsa di Servizi cognitivi, il file Constants.cs può essere aggiornato con l'area e la chiave API dalla risorsa di Azure:

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

Installare il pacchetto del servizio Voce NuGet

L'applicazione di esempio usa il pacchetto NuGet Microsoft.CognitiveServices.Speech per connettersi al servizio Voce di Azure. Installare questo pacchetto NuGet nel progetto condiviso e in ogni progetto di piattaforma.

Creare un'interfaccia IMicrophoneService

Ogni piattaforma richiede l'autorizzazione per accedere al microfono. Il progetto di esempio fornisce un'interfaccia IMicrophoneService nel progetto condiviso e usa per Xamarin.FormsDependencyService ottenere le implementazioni della piattaforma dell'interfaccia.

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

Creare il layout di pagina

Il progetto di esempio definisce un layout di pagina di base nel file MainPage.xaml . Gli elementi di layout chiave sono un oggetto Button che avvia il processo di trascrizione, un Label oggetto per contenere il testo trascritto e un oggetto ActivityIndicator da mostrare quando la trascrizione è in corso:

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

Implementare il servizio Voce

Il file code-behind MainPage.xaml.cs contiene tutta la logica per inviare audio e ricevere testo trascritto dal servizio Voce di Azure.

Il MainPage costruttore ottiene un'istanza dell'interfaccia IMicrophoneService da DependencyService:

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

    public MainPage()
    {
        InitializeComponent();

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

    // ...
}

Il TranscribeClicked metodo viene chiamato quando viene toccata l'istanza transcribeButton :

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

Il metodo TranscribeClicked esegue le operazioni seguenti:

  1. Controlla se l'applicazione ha accesso al microfono e si chiude in anticipo se non lo fa.
  2. Crea un'istanza della SpeechRecognizer classe se non esiste già.
  3. Arresta la trascrizione continua se è in corso.
  4. Inserisce un timestamp e avvia la trascrizione continua se non è in corso.
  5. Notifica all'applicazione di aggiornarne l'aspetto in base al nuovo stato dell'applicazione.

Il resto dei metodi della MainPage classe sono helper per visualizzare lo stato dell'applicazione:

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

Il UpdateTranscription metodo scrive l'oggetto fornito newTextstring nell'elemento Label denominato transcribedText. Forza l'aggiornamento nel thread dell'interfaccia utente in modo che possa essere chiamato da qualsiasi contesto senza causare eccezioni. Scrive InsertDateTimeRecord la data e l'ora correnti nell'istanza transcribedText per contrassegnare l'inizio di una nuova trascrizione. Infine, il UpdateDisplayState metodo aggiorna gli Button elementi e ActivityIndicator per riflettere se la trascrizione è in corso o meno.

Creare servizi microfono piattaforma

L'applicazione deve avere accesso al microfono per raccogliere i dati vocali. L'interfaccia IMicrophoneService deve essere implementata e registrata con in DependencyService ogni piattaforma per il funzionamento dell'applicazione.

Android

Il progetto di esempio definisce un'implementazione IMicrophoneService per Android denominata 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);
            }
        }
    }
}

Include AndroidMicrophoneService le funzionalità seguenti:

  1. L'attributo Dependency registra la classe con .DependencyService
  2. Il GetPermissionAsync metodo controlla se le autorizzazioni sono necessarie in base alla versione di Android SDK e chiama RequestMicPermissions se l'autorizzazione non è già stata concessa.
  3. Il RequestMicPermissions metodo usa la Snackbar classe per richiedere autorizzazioni all'utente se è necessaria una logica, altrimenti richiede direttamente le autorizzazioni di registrazione audio.
  4. Il OnRequestPermissionResult metodo viene chiamato con un bool risultato dopo che l'utente ha risposto alla richiesta di autorizzazioni.

La MainActivity classe è personalizzata per aggiornare l'istanza al termine delle AndroidMicrophoneService richieste di autorizzazioni:

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 definisce un riferimento statico denominato Instance, richiesto dall'oggetto durante la AndroidMicrophoneService richiesta di autorizzazioni. Esegue l'override del OnRequestPermissionsResult metodo per aggiornare l'oggetto AndroidMicrophoneService quando la richiesta di autorizzazioni viene approvata o negata dall'utente.

Infine, l'applicazione Android deve includere l'autorizzazione per registrare l'audio nel file AndroidManifest.xml :

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

iOS

Il progetto di esempio definisce un'implementazione IMicrophoneService per iOS denominata 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);
            });
        }
    }
}

Include iOSMicrophoneService le funzionalità seguenti:

  1. L'attributo Dependency registra la classe con .DependencyService
  2. Il GetPermissionAsync metodo chiama RequestMicPermissions per richiedere le autorizzazioni all'utente del dispositivo.
  3. Il RequestMicPermissions metodo usa l'istanza condivisa AVAudioSession per richiedere le autorizzazioni di registrazione.
  4. Il OnRequestPermissionResult metodo aggiorna l'istanza TaskCompletionSource con il valore specificato bool .

Infine, l'app iOS Info.plist deve includere un messaggio che indica all'utente perché l'app richiede l'accesso al microfono. Modificare il file Info.plist per includere i tag seguenti all'interno dell'elemento <dict> :

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

UWP

Il progetto di esempio definisce un'implementazione IMicrophoneService per la piattaforma UWP denominata 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
        }
    }
}

Include UWPMicrophoneService le funzionalità seguenti:

  1. L'attributo Dependency registra la classe con .DependencyService
  2. Il GetPermissionAsync metodo tenta di inizializzare un'istanza MediaCapture di . In caso di errore, avvia una richiesta dell'utente per abilitare il microfono.
  3. Il OnRequestPermissionResult metodo esiste per soddisfare l'interfaccia, ma non è necessario per l'implementazione UWP.

Infine, la piattaforma UWP Package.appxmanifest deve specificare che l'applicazione usa il microfono. Fare doppio clic sul file Package.appxmanifest e selezionare l'opzione Microfono nella scheda Funzionalità di Visual Studio 2019:

Screenshot of the manifest in Visual Studio 2019

Testare l'applicazione

Eseguire l'app e fare clic sul pulsante Trascrivi . L'app deve richiedere l'accesso al microfono e iniziare il processo di trascrizione. l'animazione ActivityIndicator , che mostra che la trascrizione è attiva. Mentre si parla, l'app trasmetterà dati audio alla risorsa di Servizi voce di Azure, che risponderà con testo trascritto. Il testo trascritto verrà visualizzato nell'elemento Label quando viene ricevuto.

Nota

Gli emulatori Android non riescono a caricare e inizializzare le librerie del servizio Voce. Il test su un dispositivo fisico è consigliato per la piattaforma Android.