연속 받아쓰기

긴 형식의 연속 받아쓰기 음성 입력을 캡처하고 인식하는 방법을 알아봅니다.

중요 API: SpeechContinuousRecognitionSession, ContinuousRecognitionSession

음성 인식에서는 짧은 메시지 서비스(SMS) 메시지를 작성하거나 질문을 할 때와 같이 SpeechRecognizer 개체의 RecognizeAsync 또는 RecognizeWithUIAsync 메서드를 사용하여 비교적 짧은 음성 입력을 캡처하고 인식하는 방법을 알아보았습니다.

받아쓰기 또는 이메일과 같이 더 긴 연속 음성 인식 세션의 경우 SpeechRecognizerContinuousRecognitionSession 속성을 사용하여 SpeechContinuousRecognitionSession 개체를 가져옵니다.

참고 항목

받아쓰기 언어 지원은 앱이 실행 되는 디바이스 에 따라 다릅니다. Pc와 노트북의 경우 en-US만 인식되고 Xbox 및 휴대폰은 음성 인식에서 지원되는 모든 언어를 인식할 수 있습니다. 자세한 내용은 음성 인식기 언어 지정을 참조하세요.

설정

연속 받아쓰기 세션을 관리하려면 앱에 몇 가지 개체가 필요합니다.

  • SpeechRecognizer 개체의 인스턴스입니다.
  • 받아쓰기 중에 UI를 업데이트하는 UI 디스패처에 대한 참조입니다.
  • 사용자가 말한 누적된 단어를 추적하는 방법입니다.

여기서는 SpeechRecognizer인스턴스를 코드 숨김 클래스의 프라이빗 필드로 선언합니다. 연속 받아쓰기를 단일 XAML(Extensible Application Markup Language) 페이지 너머까지 지속하려면 앱이 다른 곳에 참조를 저장해야 합니다.

private SpeechRecognizer speechRecognizer;

받아쓰기 중에 인식기가 백그라운드 스레드에서 이벤트를 발생시킵니다. 백그라운드 스레드는 XAML에서 UI를 직접 업데이트하지 못하므로 앱에서 디스패처를 사용하여 인식 이벤트에 대한 응답으로 UI를 업데이트해야 합니다.

여기서는 나중에 UI 디스패처를 사용하여 초기화될 프라이빗 필드를 선언합니다.

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

사용자가 말하는 내용을 추적하려면 음성 인식기에서 발생시키는 인식 이벤트를 처리해야 합니다. 이러한 이벤트는 사용자 발화 청크의 인식 결과를 제공합니다.

여기서는 StringBuilder 개체를 사용하여 세션 중에 얻은 모든 인식 결과를 저장합니다. 새 결과가 처리될 때 StringBuilder에 추가됩니다.

private StringBuilder dictatedTextBuilder;

초기화

연속 음성 인식이 초기화되는 동안 다음을 수행해야 합니다.

  • 연속 인식 이벤트 처리기에서 앱의 UI를 업데이트하는 경우 UI 스레드용 디스패처를 가져옵니다.
  • 음성 인식기를 초기화합니다.
  • 기본 제공 받아쓰기 문법을 컴파일합니다. 참고 음성 인식에는 인식 가능한 어휘를 정의하는 데 하나 이상의 제약 조건이 필요합니다. 제약 조건을 지정하지 않으면 미리 정의된 받아쓰기 문법이 사용됩니다. See 음성 인식을 참조하세요.
  • 인식 이벤트용 이벤트 수신기를 설정합니다.

이 예제에서는 OnNavigatedTo 페이지 이벤트에서 음성 인식을 초기화합니다.

  1. 음성 인식기에서 발생시키는 이벤트는 백그라운드 스레드에서 발생하므로 UI 스레드 업데이트를 위해 디스패처에 대한 참조를 만듭니다. OnNavigatedTo는 항상 UI 스레드에서 호출됩니다.
this.dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
  1. 그런 다음 SpeechRecognizer 인스턴스를 초기화합니다.
this.speechRecognizer = new SpeechRecognizer();
  1. 그런 다음 SpeechRecognizer에서 인식할 수 있는 모든 단어와 구를 정의하는 문법을 추가하고 컴파일합니다.

    문법을 명시적으로 지정하지 않으면 미리 정의된 받아쓰기 문법이 기본적으로 사용됩니다. 일반적으로 기본 문법은 일반적인 받아쓰기에 가장 적합합니다.

    여기서는 문법을 추가하지 않고 CompileConstraintsAsync를 즉시 호출합니다.

SpeechRecognitionCompilationResult result =
      await speechRecognizer.CompileConstraintsAsync();

인식 이벤트 처리

RecognizeAsync 또는 RecognizeWithUIAsync를 호출하여 간단한 단일 발화 또는 구를 캡처할 수 있습니다.

그러나 더 긴 연속 인식 세션을 캡처하기 위해 사용자가 말하는 대로 백그라운드에서 실행할 이벤트 수신기를 지정하고 받아쓰기 문자열을 빌드하는 처리기를 정의합니다.

그런 다음 인식기의 ContinuousRecognitionSession 속성을 사용하여 연속 인식 세션을 관리하기 위한 메서드와 이벤트를 제공하는 SpeechContinuousRecognitionSession 개체를 가져옵니다.

특히 다음 두 이벤트가 중요합니다.

  • ResultGenerated는 인식기에서 몇 가지 결과를 생성할 때 발생합니다.
  • Completed는 연속 인식 세션이 종료될 때 발생합니다.

ResultGenerated 이벤트는 사용자가 말할 때 발생합니다. 인식기가 지속적으로 사용자를 수신 대기하고 주기적으로 음성 입력 청크를 전달하는 이벤트를 발생시킵니다. 이벤트 인수의 Result 속성을 사용하여 음성 입력을 검사하고 StringBuilder 개체에 텍스트를 추가하는 등 이벤트 처리기에서 적절한 작업을 수행해야 합니다.

SpeechRecognitionResult의 인스턴스인 Result 속성은 음성 입력을 허용할지 여부를 결정하는 데 유용합니다. SpeechRecognitionResult는 다음과 같은 두 가지 속성을 제공합니다.

  • Status는 인식에 성공했는지 여부를 나타냅니다. 인식은 다양한 이유로 실패할 수 있습니다.
  • Confidence는 인식기에서 올바른 단어를 해석한 상대적인 신뢰도를 나타냅니다.

연속 인식을 지원하기 위한 기본 단계는 다음과 같습니다.

  1. 여기서는 OnNavigatedTo 페이지 이벤트에 ResultGenerated 연속 인식 이벤트용 처리기를 등록합니다.
speechRecognizer.ContinuousRecognitionSession.ResultGenerated +=
        ContinuousRecognitionSession_ResultGenerated;
  1. 그런 다음 Confidence 속성을 검사합니다. Confidence 값이 Medium 이상이면 StringBuilder에 텍스트를 추가합니다. 입력을 수집할 때 UI도 업데이트합니다.

    참고ResultGenerated 이벤트는 UI를 직접 업데이트할 수 없는 백그라운드 스레드에서 발생합니다. 처리기에서 UI를 업데이트해야 하는 경우([음성 및 TTS 샘플]에서와 마찬가지로) 디스패처의 RunAsync 메서드를 통해 UI 스레드 업데이트를 디스패치해야 합니다.

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. 그런 다음 연속 받아쓰기의 끝을 나타내는 Completed 이벤트를 처리합니다.

    이 세션은 StopAsync 또는 CancelAsync 메서드를 호출하면 종료됩니다(다음 섹션 설명). 오류가 발생하거나 사용자가 말하기를 중지한 경우에도 세션이 종료될 수 있습니다. 이벤트 인수의 Status 속성을 확인하여 세션이 종료된 이유를 확인합니다(SpeechRecognitionResultStatus).

    여기서는 OnNavigatedTo 페이지 이벤트에 Completed 연속 인식 이벤트용 처리기를 등록합니다.

speechRecognizer.ContinuousRecognitionSession.Completed +=
      ContinuousRecognitionSession_Completed;
  1. 이벤트 처리기는 상태 속성을 검사하여 인식이 성공했는지 여부를 확인합니다. 사용자가 말하기를 중지한 경우도 처리합니다. 종종 TimeoutExceeded는 사용자가 말하기를 완료했음을 의미하므로 성공적인 인식으로 간주됩니다. 좋은 환경을 위한 코드에서 이 경우를 처리해야 합니다.

    참고ResultGenerated 이벤트는 UI를 직접 업데이트할 수 없는 백그라운드 스레드에서 발생합니다. 처리기에서 UI를 업데이트해야 하는 경우([음성 및 TTS 샘플]에서와 마찬가지로) 디스패처의 RunAsync 메서드를 통해 UI 스레드 업데이트를 디스패치해야 합니다.

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

지속적인 인식 피드백 제공

사람들은 대화할 때 종종 컨텍스트에 의존하여 말하는 내용을 완전히 이해합니다. 이와 마찬가지로 음성 인식기에도 신뢰도가 높은 인식 결과를 제공하기 위해 컨텍스트가 종종 필요합니다. 예를 들어, "weight"와 "wait"라는 단어는 주변 단어에서 더 많은 컨텍스트를 모을 수 있을 때까지는 구별할 수 없습니다. 인식기가 단어 또는 여러 단어가 올바르게 인식되었다고 확신할 때까지는 ResultGenerated 이벤트를 발생시키지 않습니다.

이렇게 하면 사용자가 계속 말할 때 이상적인 환경이 될 수 있으며, 인식기가 ResultGenerated 이벤트를 발생시키기에 충분히 높은 신뢰도를 가질 때까지 결과가 제공되지 않습니다.

HypothesisGenerated 이벤트를 처리하여 이와 같이 명백한 응답성 부재를 개선합니다. 이 이벤트는 인식기가 처리 중인 단어에 대한 새로운 잠재적 일치 집합을 생성할 때마다 발생합니다. 이벤트 인수는 현재 일치 항목을 포함하는 Hypothesis 속성을 제공합니다. 계속 말할 때 사용자에게 이를 표시하고 아직 처리가 활성 상태임을 확신시킵니다. 신뢰도가 높고 인식 결과가 결정되면 중간 Hypothesis 결과를 ResultGenerated 이벤트에 제공된 최종 Result 결과로 바꿉니다.

여기서는 가상 텍스트와 줄임표("...")를 출력 TextBox의 현재 값에 추가됩니다. 텍스트 상자의 내용은 새 가설이 생성되고 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;
    });
  }

인식 시작 및 중지

인식 세션을 시작하기 전에 음성 인식기 State 속성 값을 확인합니다. 음성 인식기가 Idle 상태여야 합니다.

음성 인식기의 상태를 검사한 후 음성 인식기의 ContinuousRecognitionSession 속성의 StartAsync 메서드를 호출하여 세션을 시작합니다.

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

인식은 다음 두 방법으로 중지할 수 있습니다.

  • StopAsync를 통해 보류 중인 모든 인식 이벤트가 완료됩니다(보류 중인 모든 인식 작업이 완료될 때까지 ResultGenerated가 계속 발생함).
  • CancelAsync는 즉시 인식 세션을 종료하고 보류 중인 모든 결과를 삭제합니다.

음성 인식기의 상태를 검사한 후에 음성 인식기의 ContinuousRecognitionSession 속성의 CancelAsync 메서드를 호출하여 세션을 중지합니다.

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

참고 항목

ResultGenerated 이벤트는 CancelAsync를 호출한 후에 발생할 수 있습니다.
다중 스레딩 때문에 CancelAsync가 호출될 때 ResultGenerated 이벤트가 스택에 남을 수 있습니다. 이 경우 ResultGenerated 이벤트가 계속 발생합니다.
인식 세션을 취소할 때 프라이빗 필드를 설정하는 경우 ResultGenerated 처리기에서 항상 그 값을 확인합니다. 예를 들어, 세션을 취소할 때 필드를 null로 설정하는 경우에는 처리기에서 필드가 초기화된다고 가정하지 마세요.

 

샘플