Ditado contínuo

Saiba como capturar e reconhecer entrada de fala de ditado contínuo de formato longo.

APIs importantes: SpeechContinuousRecognitionSession, ContinuousRecognitionSession

Em Reconhecimento de fala, você aprendeu como capturar e reconhecer entradas de fala relativamente curtas usando o método RecognizeAsync ou o método RecognizeWithUIAsync de um objeto SpeechRecognizer, por exemplo, ao compor uma mensagem SMS curta ou fazer uma pergunta.

Para sessões de reconhecimento de fala contínuas mais longas, como ditado ou email, use a propriedade ContinuousRecognitionSession de um SpeechRecognizer para obter um objeto SpeechContinuousRecognitionSession.

Observação

O suporte à linguagem de ditado depende do dispositivo em que seu aplicativo está sendo executado. Para computadores e laptops, somente en-US é reconhecido, enquanto o Xbox e os telefones podem reconhecer todos os idiomas compatíveis com o reconhecimento de fala. Para obter mais informações, consulte Especificar o idioma do reconhecedor de fala.

Configuração

Seu aplicativo precisa de alguns objetos para gerenciar uma sessão de ditado contínuo:

  • Uma instância de um objeto SpeechRecognizer.
  • Uma referência a um dispatcher de interface do usuário para atualizar a interface do usuário durante o ditado.
  • Uma maneira de acompanhar as palavras acumuladas faladas pelo usuário.

Aqui, declaramos uma instância SpeechRecognizer como um campo particular da classe code-behind. Seu aplicativo precisa armazenar uma referência em outro lugar se você quiser que o ditado contínuo persista além de uma única página XAML.

private SpeechRecognizer speechRecognizer;

Durante o ditado, o reconhecedor aciona eventos de um thread em segundo plano. Como um thread em segundo plano não pode atualizar diretamente a interface do usuário em XAML, seu aplicativo deve usar um dispatcher para atualizar a interface do usuário em resposta a eventos de reconhecimento.

Aqui, nós declaramos um campo particular que será inicializado posteriormente com o dispatcher de interface do usuário.

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

Para acompanhar o que o usuário está dizendo, você precisa tratar eventos de reconhecimento acionados pelo reconhecedor de fala. Esses eventos fornecem os resultados do reconhecimento de blocos de expressões do usuário.

Aqui, usamos um objeto StringBuilder para reter todos os resultados do reconhecimento obtidos durante a sessão. Novos resultados são acrescentados ao StringBuilder conforme eles são processados.

private StringBuilder dictatedTextBuilder;

Inicialização

Durante a inicialização do reconhecimento de fala contínua, você deve:

  • Buscar o dispatcher do thread de interface do usuário se você atualizar a interface do usuário do aplicativo nos manipuladores de eventos de reconhecimento contínuo.
  • Inicializar o reconhecedor de fala.
  • Compilar a gramática de ditado interna. Nota O reconhecimento de fala requer pelo menos uma restrição para definir um vocabulário reconhecível. Se nenhuma restrição for especificada, uma gramática de ditado predefinida será usada. Consulte Reconhecimento de fala.
  • Configure os ouvintes de eventos para eventos de reconhecimento.

Nesse exemplo, inicializamos o reconhecimento de fala no evento de página OnNavigatedTo.

  1. Como os eventos acionados pelo reconhecedor de fala ocorrem em um thread em segundo plano, crie uma referência ao dispatcher para atualizações no thread de interface do usuário. OnNavigatedTo é sempre invocado no thread de interface do usuário.
this.dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
  1. Em seguida, inicializamos a instância SpeechRecognizer.
this.speechRecognizer = new SpeechRecognizer();
  1. Depois, adicionamos e compilamos a gramática que define todas as palavras e frases que podem ser reconhecidas pelo SpeechRecognizer.

    Se você não especificar explicitamente uma gramática, uma gramática de ditado predefinida será usada por padrão. Normalmente, a gramática padrão é melhor para ditado geral.

    Aqui, chamamos CompileConstraintsAsync imediatamente, sem adicionar uma gramática.

SpeechRecognitionCompilationResult result =
      await speechRecognizer.CompileConstraintsAsync();

Tratar eventos de reconhecimento

Você pode capturar uma única expressão ou frase curta chamando RecognizeAsync ou RecognizeWithUIAsync.

No entanto, para capturar uma sessão de reconhecimento contínua mais longa, especificamos ouvintes de eventos a serem executados em segundo plano conforme o usuário fala e definimos manipuladores para criar a cadeia de caracteres de ditado.

Em seguida, usamos a propriedade ContinuousRecognitionSession do nosso reconhecedor para obter um objeto SpeechContinuousRecognitionSession que fornece métodos e eventos para gerenciar uma sessão de reconhecimento contínua.

Dois eventos em particular são essenciais:

  • ResultGenerated, que ocorre quando o reconhecedor gerou alguns resultados.
  • Completed, que ocorre quando a sessão de reconhecimento contínua termina.

O evento ResultGenerated é acionado conforme o usuário fala. O reconhecedor escuta o usuário de forma contínua e periodicamente aciona um evento que passa um bloco de entrada de fala. Você deve examinar a entrada de fala usando a propriedade Result do argumento do evento e executar a ação apropriada no manipulador de eventos, por exemplo, acrescentando o texto a um objeto StringBuilder.

Como uma instância de SpeechRecognitionResult, a propriedade Result é útil para determinar se você deseja aceitar a entrada de fala Um SpeechRecognitionResult fornece duas propriedades para isso:

  • Status indica se o reconhecimento foi executado com êxito. Pode haver falha no reconhecimento por vários motivos.
  • Confidence indica a confiança relativa com que o reconhecedor compreendeu as palavras corretas.

Aqui estão as etapas básicas para dar suporte contínuo reconhecimento:

  1. Aqui, registramos o manipulador do evento de reconhecimento contínuo ResultGenerated no evento de página OnNavigatedTo.
speechRecognizer.ContinuousRecognitionSession.ResultGenerated +=
        ContinuousRecognitionSession_ResultGenerated;
  1. Em seguida, verificamos a propriedade Confidence. Se o valor de Confiança for Medium ou melhor, acrescentamos o texto ao StringBuilder. Também atualizamos a interface do usuário conforme coletamos entradas.

    Observe que o evento ResultGenerated é gerado em um thread em segundo plano que não pode atualizar a interface do usuário diretamente. Se um manipulador precisar atualizar a interface do usuário (como o [exemplo de Fala e TTS]), você deverá expedir as atualizações para o thread da interface do usuário por meio do método RunAsync do 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. Em seguida, tratamos o evento Completed, que indica o final do ditado contínuo.

    A sessão termina quando você chama os métodos StopAsync ou CancelAsync (descritos na próxima seção). A sessão também pode terminar quando ocorre um erro, ou quando o usuário para de falar. Verifique a propriedade Status do argumento do evento para determinar por que a sessão terminou (SpeechRecognitionResultStatus).

    Aqui, registramos o manipulador do evento de reconhecimento contínuo Completed no evento de página OnNavigatedTo.

speechRecognizer.ContinuousRecognitionSession.Completed +=
      ContinuousRecognitionSession_Completed;
  1. O manipulador de eventos verifica a propriedade Status para determinar se o reconhecimento foi executado com êxito. Ele também trata o caso em que o usuário parou de falar. Frequentemente, TimeoutExceeded é considerado um reconhecimento bem-sucedido porque significa que o usuário terminou de falar. Você deve tratar esse caso no seu código para obter uma boa experiência.

    Observe que o evento ResultGenerated é gerado em um thread em segundo plano que não pode atualizar a interface do usuário diretamente. Se um manipulador precisar atualizar a interface do usuário (como o [exemplo de Fala e TTS]), você deverá expedir as atualizações para o thread da interface do usuário por meio do método RunAsync do 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";
            });
          }
        }
      }

Fornecer feedback de reconhecimento contínuo

Quando as pessoas conversam, elas frequentemente dependem do contexto para entender completamente o que está sendo dito. Da mesma forma, o reconhecedor de fala precisa de contexto para fornecer resultados de reconhecimento de alta confiabilidade. Por exemplo, sozinhas, as palavras "acento" e "assento" não podem ser diferenciadas até que mais contexto seja coletado das palavras adjacentes. Até que o reconhecedor tenha alguma confiança de que uma ou mais palavras foram reconhecidas corretamente, ele não acionará um evento ResultGenerated.

Isso pode resultar em uma experiência longe da ideal para o usuário, pois ele continua falando e nenhum resultado é fornecido até que o reconhecedor tenha confiança suficiente para acionar um evento ResultGenerated.

Trate o evento HypothesisGenerated para melhorar essa aparente falta de capacidade de resposta. Esse evento é acionado sempre que o reconhecedor gera um novo conjunto de possíveis correspondências para a palavra que está sendo processada. O argumento do evento fornece uma propriedade Hypothesis que contém as correspondências atuais. Mostre as correspondências ao usuário conforme ele continua falando e assegure que o processamento ainda está ativo. Assim que a confiança for alta e um resultado de reconhecimento tiver sido determinado, substitua os resultados Hypothesis temporários pelo Result final fornecido no evento ResultGenerated.

Aqui, acrescentamos o texto hipotético e reticências ("…") ao valor atual da caixa de texto de saída TextBox. O conteúdo da caixa de texto é atualizado conforme novas hipóteses são geradas e até que os resultados finais sejam obtidos do 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;
    });
  }

Iniciar e parar o reconhecimento

Antes de iniciar uma sessão de reconhecimento, verifique o valor da propriedade State do reconhecedor de fala. O reconhecedor de fala deve estar em um estado Idle.

Depois de verificar o estado do reconhecedor de fala, começamos a sessão chamando o método StartAsync da propriedade ContinuousRecognitionSession do reconhecedor de fala.

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

O reconhecimento pode ser interrompido de duas maneiras:

  • StopAsync permite que qualquer evento de reconhecimento pendente seja concluído (ResultGenerated continua sendo acionado até que todas as operações de reconhecimento pendentes sejam concluídas).
  • CancelAsync finaliza a sessão de reconhecimento imediatamente e descarta qualquer resultado pendente.

Depois de verificar o estado do reconhecedor de fala, interrompemos a sessão chamando o método CancelAsync da propriedade ContinuousRecognitionSession do reconhecedor de fala.

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

Observação

Um evento ResultGenerated pode ocorrer após uma chamada para CancelAsync.
Por causa do multithreading, um evento ResultGenerated ainda pode permanecer na pilha quando CancelAsync é chamado. Nesse caso, o evento ResultGenerated ainda é acionado.
Se você definir qualquer campo particular ao cancelar a sessão de reconhecimento, sempre confirme seus valores no manipulador ResultGenerated. Por exemplo, não suponha que um campo será inicializado em seu manipulador se você defini-lo como nulo ao cancelar a sessão.

 

Amostras