Riconoscimento vocale con il servizio Voce di Azure
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:
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:
- Accedere al portale di Azure.
- Creare una risorsa multiservizio o a servizio singolo.
- Ottenere le informazioni sulla chiave API e sull'area per la risorsa.
- 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:
- Controlla se l'applicazione ha accesso al microfono e si chiude in anticipo se non lo fa.
- Crea un'istanza della
SpeechRecognizer
classe se non esiste già. - Arresta la trascrizione continua se è in corso.
- Inserisce un timestamp e avvia la trascrizione continua se non è in corso.
- 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 newText
string
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:
- L'attributo
Dependency
registra la classe con .DependencyService
- Il
GetPermissionAsync
metodo controlla se le autorizzazioni sono necessarie in base alla versione di Android SDK e chiamaRequestMicPermissions
se l'autorizzazione non è già stata concessa. - Il
RequestMicPermissions
metodo usa laSnackbar
classe per richiedere autorizzazioni all'utente se è necessaria una logica, altrimenti richiede direttamente le autorizzazioni di registrazione audio. - Il
OnRequestPermissionResult
metodo viene chiamato con unbool
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:
- L'attributo
Dependency
registra la classe con .DependencyService
- Il
GetPermissionAsync
metodo chiamaRequestMicPermissions
per richiedere le autorizzazioni all'utente del dispositivo. - Il
RequestMicPermissions
metodo usa l'istanza condivisaAVAudioSession
per richiedere le autorizzazioni di registrazione. - Il
OnRequestPermissionResult
metodo aggiorna l'istanzaTaskCompletionSource
con il valore specificatobool
.
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:
- L'attributo
Dependency
registra la classe con .DependencyService
- Il
GetPermissionAsync
metodo tenta di inizializzare un'istanzaMediaCapture
di . In caso di errore, avvia una richiesta dell'utente per abilitare il microfono. - 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:
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.