Dettatura continua

Informazioni su come acquisire e riconoscere l'input vocale di dettatura continua in formato lungo.

API importanti: SpeechContinuousRecognitionSession, ContinuousRecognitionSession

In Riconoscimento vocale si è appreso come acquisire e riconoscere input vocali relativamente brevi usando i metodi RecognizeAsync or RecognizeWithUIAsync di un oggetto SpeechRecognizer, ad esempio quando si compone un messaggio SMS o si pone una domanda.

Per sessioni di riconoscimento vocale continue e più lunghe, ad esempio dittatura o e-mail, usare la proprietà ContinuousRecognitionSession di un elemento SpeechRecognizer per ottenere un oggetto SpeechContinuousRecognitionSession.

Nota

Il supporto della lingua di dettatura dipende dal dispositivo in cui è in esecuzione l'app. I PC e i portatili riconoscono solo en-US, mentre la Xbox e i telefoni possono riconoscere tutte le lingue supportate dal riconoscimento vocale. Per altre informazioni, vedere Specificare la lingua per il riconoscimento vocale.

Impostazione

L'app necessita di alcuni oggetti per gestire una sessione di dettatura continua:

  • Un'istanza di un oggetto SpeechRecognizer.
  • Un riferimento a un dispatcher dell'interfaccia utente per aggiornare l'interfaccia utente durante la dettatura.
  • Un modo per tenere traccia delle parole accumulate pronunciate dall'utente.

In questo caso, si dichiara un'istanza di speechRecognizer come campo privato della classe code-behind. L'app deve archiviare un riferimento altrove se si vuole che la dettatura continua persista oltre una singola pagina XAML (Extensible Application Markup Language).

private SpeechRecognizer speechRecognizer;

Durante la dettatura, il riconoscimento genera eventi da un thread in background. Poiché un thread in background non può aggiornare direttamente l'interfaccia utente in XAML, l'app deve usare un dispatcher per aggiornare l'interfaccia utente in risposta agli eventi di riconoscimento.

In questo caso, si dichiara un campo privato che verrà inizializzato in un secondo momento con il dispatcher dell'interfaccia utente.

// Speech events may originate from a thread other than the UI thread.
// Keep track of the UI thread dispatcher so that we can update the
// UI in a thread-safe manner.
private CoreDispatcher dispatcher;

Per tenere traccia di ciò che l'utente dice, è necessario gestire gli eventi di riconoscimento generati dal riconoscimento vocale. Questi eventi forniscono i risultati di riconoscimento per blocchi di espressioni utente.

In questo caso, si usa un oggetto StringBuilder per contenere tutti i risultati di riconoscimento ottenuti durante la sessione. I nuovi risultati vengono aggiunti all'oggetto StringBuilder man mano che vengono elaborati.

private StringBuilder dictatedTextBuilder;

Inizializzazione

Durante l'inizializzazione del riconoscimento vocale continuo, è necessario:

  • Recuperare il dispatcher per il thread dell'interfaccia utente se si aggiorna l'interfaccia utente dell'app nei gestori degli eventi di riconoscimento continuo.
  • Inizializzare il riconoscimento vocale.
  • Compilare la grammatica di dettatura predefinita. Nota Il riconoscimento vocale richiede almeno un vincolo per definire un vocabolario riconoscibile. Se non viene specificato alcun vincolo, viene utilizzata una grammatica di dettatura predefinita. Vedere Riconoscimento vocale.
  • Configurare i listener di eventi per gli eventi di riconoscimento.

In questo esempio si inizializza il riconoscimento vocale nell'evento della pagina OnNavigatedTo.

  1. Poiché gli eventi generati dal riconoscimento vocale si verificano in un thread in background, creare un riferimento al dispatcher per gli aggiornamenti al thread dell'interfaccia utente. OnNavigatedTo viene sempre richiamato sul thread dell'interfaccia utente.
this.dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
  1. Si inizializza quindi l'istanza di SpeechRecognizer.
this.speechRecognizer = new SpeechRecognizer();
  1. A questo punto, si aggiunge e compila la grammatica che definisce tutte le parole e le frasi che SpeechRecognizerè in grado di riconoscere.

    Se non si specifica una grammatica in modo esplicito, per impostazione predefinita viene usata una grammatica di dettatura predefinita. In genere, la grammatica predefinita è ideale per la dettatura generale.

    Qui, si chiama immediatamente CompileConstraintsAsync senza aggiungere una grammatica.

SpeechRecognitionCompilationResult result =
      await speechRecognizer.CompileConstraintsAsync();

Gestire gli eventi di riconoscimento

È possibile acquisire una breve espressione o frase chiamando RecognizeAsync o RecognizeWithUIAsync.

Tuttavia, per acquisire una sessione di riconoscimento continua più lunga, si specificano i listener di eventi da eseguire in background mentre l'utente parla e si definiscono i gestori per compilare la stringa di dettatura.

Si usa quindi la proprietà ContinuousRecognitionSession del riconoscimento per ottenere un oggetto SpeechContinuousRecognitionSession che fornisce metodi ed eventi per gestire una sessione di riconoscimento continua.

Due eventi, in particolare, sono critici:

  • ResultGenerated, che si verifica quando il riconoscimento ha generato alcuni risultati.
  • Completed, che si verifica al termine della sessione di riconoscimento continua.

L'evento ResultGenerated viene generato quando parla l'utente. Lo strumento di riconoscimento ascolta continuamente l'utente e periodicamente genera un evento che passa un blocco di input vocale. È necessario esaminare l'input vocale usando la proprietà Result dell'argomento dell'evento ed eseguire l'azione appropriata nel gestore dell'evento, ad esempio aggiungere testo a un oggetto StringBuilder.

Come istanza di SpeechRecognitionResult, la proprietà Result è utile per determinare se accettare o meno l'input vocale. Un elemento SpeechRecognitionResult fornisce due proprietà per:

  • Status indica se il riconoscimento è andato a buon fine. Il riconoscimento potrebbe non riuscire per diversi motivi.
  • Confidence indica la sicurezza relativa con cui il riconoscimento ha compreso le parole corrette.

Ecco i passaggi di base per supportare il riconoscimento continuo:

  1. Qui, si registra il gestore per l'evento di riconoscimento continuo ResultGenerated nell'evento della pagina OnNavigatedTo.
speechRecognizer.ContinuousRecognitionSession.ResultGenerated +=
        ContinuousRecognitionSession_ResultGenerated;
  1. Si controlla quindi la proprietà Confidence. Se il valore di Confidence è Medium o un valore migliore, si aggiunge testo a StringBuilder. Durante la raccolta dell'input, si aggiorna anche l'interfaccia utente.

    Nota L'evento ResultGenerated viene generato su un thread in background che non può aggiornare direttamente l'interfaccia utente. Se un gestore deve aggiornare l'interfaccia utente (come [l'esempio Voce e TTS]), è necessario inviare gli aggiornamenti al thread dell'interfaccia utente attraverso il metodo RunAsync del dispatcher.

private async void ContinuousRecognitionSession_ResultGenerated(
      SpeechContinuousRecognitionSession sender,
      SpeechContinuousRecognitionResultGeneratedEventArgs args)
      {

        if (args.Result.Confidence == SpeechRecognitionConfidence.Medium ||
          args.Result.Confidence == SpeechRecognitionConfidence.High)
          {
            dictatedTextBuilder.Append(args.Result.Text + " ");

            await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
              dictationTextBox.Text = dictatedTextBuilder.ToString();
              btnClearText.IsEnabled = true;
            });
          }
        else
        {
          await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
              dictationTextBox.Text = dictatedTextBuilder.ToString();
            });
        }
      }
  1. Si gestisce quindi l'evento Completed, che indica la fine della dettatura continua.

    La sessione termina quando si chiama il metodo StopAsync o CancelAsync (descritti nella sezione successiva). La sessione può anche terminare quando si verifica un errore o quando l'utente smette di parlare. Controllare la proprietà Status dell'argomento dell'evento per determinare perché la sessione è terminata (SpeechRecognitionResultStatus).

    Qui, si registra il gestore per l'evento di riconoscimento continuo Completed nell'evento della pagina OnNavigatedTo.

speechRecognizer.ContinuousRecognitionSession.Completed +=
      ContinuousRecognitionSession_Completed;
  1. Il gestore dell'evento controlla la proprietà Status per determinare se il riconoscimento è andato a buon fine. Gestisce anche il caso in cui l'utente ha smesso di parlare. Spesso, un elemento TimeoutExceeded viene considerato un riconoscimento riuscito perché indica che l'utente ha finito di parlare. È consigliabile gestire questo caso nel codice per un'esperienza ottimale.

    Nota L'evento ResultGenerated viene generato su un thread in background che non può aggiornare direttamente l'interfaccia utente. Se un gestore deve aggiornare l'interfaccia utente (come [l'esempio Voce e TTS]), è necessario inviare gli aggiornamenti al thread dell'interfaccia utente attraverso il metodo RunAsync del dispatcher.

private async void ContinuousRecognitionSession_Completed(
      SpeechContinuousRecognitionSession sender,
      SpeechContinuousRecognitionCompletedEventArgs args)
      {
        if (args.Status != SpeechRecognitionResultStatus.Success)
        {
          if (args.Status == SpeechRecognitionResultStatus.TimeoutExceeded)
          {
            await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
              rootPage.NotifyUser(
                "Automatic Time Out of Dictation",
                NotifyType.StatusMessage);

              DictationButtonText.Text = " Continuous Recognition";
              dictationTextBox.Text = dictatedTextBuilder.ToString();
            });
          }
          else
          {
            await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
              rootPage.NotifyUser(
                "Continuous Recognition Completed: " + args.Status.ToString(),
                NotifyType.StatusMessage);

              DictationButtonText.Text = " Continuous Recognition";
            });
          }
        }
      }

Fornire un feedback sul riconoscimento in corso

Quando le persone conversano, spesso si basano sul contesto per comprendere bene cosa viene detto. Analogamente, il riconoscimento vocale spesso necessita di contesto per fornire risultati di riconoscimento altamente attendibili. Ad esempio, da sole le parole "anno" e "hanno" sono indistinguibili finché non si deduce più contesto dalle parole circostanti. Finché il riconoscimento ha una qualche sicurezza che una o più parole siano state riconosciute correttamente, non genererà l'evento ResultGenerated.

Questo può produrre un'esperienza non proprio ideale per l'utente perché continua a parlare e non vengono forniti risultati finché il riconoscimento non ha acquisito la sicurezza necessaria per generare l'evento ResultGenerated.

Gestire l'evento HypothesisGenerated per migliorare questa apparente mancanza di reattività. Questo evento viene generato ogni volta che il riconoscimento genera un nuovo set di potenziali corrispondenze per la parola elaborata. L'argomento dell'evento fornisce una proprietà Hypothesis che contiene le corrispondenze correnti. Mostrarli all'utente mentre continua a parlare e rassicurarlo che l'elaborazione è ancora attiva. Quando la sicurezza è elevata ed è stato determinato un risultato di riconoscimento, sostituire i risultati Hypothesis provvisori con l'elemento Result fornito nell'evento ResultGenerated.

Qui, si aggiungono il testo ipotetico e i puntini di sospensione ("…") al valore corrente dell'elemento TextBox di output. Il contenuto della casella di testo viene aggiornato man mano che vengono generate nuove ipotesi e finché non si ottengono risultati finali dall'evento ResultGenerated.

private async void SpeechRecognizer_HypothesisGenerated(
  SpeechRecognizer sender,
  SpeechRecognitionHypothesisGeneratedEventArgs args)
  {

    string hypothesis = args.Hypothesis.Text;
    string textboxContent = dictatedTextBuilder.ToString() + " " + hypothesis + " ...";

    await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
      dictationTextBox.Text = textboxContent;
      btnClearText.IsEnabled = true;
    });
  }

Avviare e arrestare il riconoscimento

Prima di avviare una sessione di riconoscimento, verificare il valore della proprietà State del riconoscimento vocale. Il riconoscimento vocale deve trovarsi in uno stato Idle.

Dopo aver verificato lo stato del riconoscimento vocale, si avvia la sessione chiamando il metodo StartAsync della proprietà ContinuousRecognitionSession del riconoscimento vocale.

if (speechRecognizer.State == SpeechRecognizerState.Idle)
{
  await speechRecognizer.ContinuousRecognitionSession.StartAsync();
}

Il riconoscimento può essere arrestato in due modi:

  • StopAsync consente il completamento di eventuali eventi di riconoscimento in sospeso (ResultGenerated continua a essere generato finché tutte le operazioni di riconoscimento in sospeso non sono state completate).
  • CancelAsync termina immediatamente la sessione di riconoscimento ed elimina eventuali risultati in sospeso.

Dopo aver verificato lo stato del riconoscimento vocale, si interrompe la sessione chiamando il metodo CancelAsync della proprietà ContinuousRecognitionSession del riconoscimento vocale.

if (speechRecognizer.State != SpeechRecognizerState.Idle)
{
  await speechRecognizer.ContinuousRecognitionSession.CancelAsync();
}

Nota

Può verificarsi un evento ResultGenerated dopo una chiamata a CancelAsync.
A causa del multithreading, un evento ResultGenerated potrebbe rimanere nello stack quando viene chiamato CancelAsync. In questo caso, viene ancora generato l'evento ResultGenerated.
Se si impostano campi primati quando si annulla la sessione di riconoscimento, confermare i relativi valori nel gestore ResultGenerated. Ad esempio, non supporre che un campo venga inizializzato nel gestore se lo si imposta su null quando si annulla la sessione.

 

Esempi