Share via


連續聽寫

瞭解如何擷取和辨識長格式、連續聽寫語音輸入。

重要 API:SpeechContinuousRecognitionSession、ContinuousRecognitionSession

在語音辨識中,您已瞭解如何使用 SpeechRecognizer 物件的 RecognizeAsync 或 RecognizeWithUIAsync 方法來擷取和辨識相對簡短的語音輸入,例如在撰寫簡短訊息服務 (SMS) 訊息或提出問題時。

針對較長的連續語音辨識會話,例如聽寫或電子郵件,請使用SpeechRecognizer的ContinuousRecognitionSession 屬性來取得SpeechContinuousRecognitionSession 物件。

注意

聽寫語言支援取決於 應用程式執行所在的裝置 。 針對電腦和膝上型電腦,只能辨識 EN-US,而 Xbox 和手機可以辨識語音辨識語音辨識支援的所有語言。 如需詳細資訊,請參閱 指定語音辨識器語言

設定

您的應用程式需要一些物件來管理連續聽寫會話:

  • SpeechRecognizer 物件的 執行個體。
  • UI 發送器在聽寫期間更新UI的參考。
  • 追蹤使用者所說累積字組的方法。

在這裡,我們將SpeechRecognizer執行個體宣告為程式碼後置類別的私人欄位。 如果您想要將連續聽寫保存在單一可延伸應用程式標記語言 (XAML) 頁面之外,您的應用程式必須儲存其他地方的參考。

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 執行緒的發送器。
  • 初始化語音辨識器。
  • 編譯內建聽寫文法。 注意:語音辨識至少需要一個條件約束來定義可辨識的詞彙。 如果未指定任何條件約束,則會使用預先定義的聽寫文法。 請參閱語音辨識
  • 設定辨識事件的事件接聽程式。

在此範例中,我們會在 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,會在辨識器產生一些結果時發生。
  • 已完成,會在連續辨識會話結束時發生。

ResultGenerated 事件會在使用者說話時引發。 辨識器會持續接聽使用者,並定期引發事件,以傳遞大量語音輸入。 您必須使用 事件自變數的 Result 屬性來檢查語音輸入,並在事件處理常式中採取適當的動作,例如將文字附加至 StringBuilder 物件。

做為SpeechRecognitionResult的執行個體,Result 屬性有助於判斷您是否要接受語音輸入。 SpeechRecognitionResult 提供下列兩個屬性:

  • 狀態 指出辨識是否成功。 辨識可能會因為各種原因而失敗。
  • 信賴 表示辨識器瞭解正確字組的相對信賴度。

以下是支援連續辨識的基本步驟:

  1. 在這裡,我們會在 OnNavigatedTo 頁面事件中註冊 ResultGenerated 連續辨識事件的處理常式。
speechRecognizer.ContinuousRecognitionSession.ResultGenerated +=
        ContinuousRecognitionSession_ResultGenerated;
  1. 然後檢查 Confidence 屬性。 如果 [信賴度] 的值是 [中 ] 或更好,我們會將文字附加至 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 頁面事件中註冊 ResultGenerated 連續辨識事件的處理常式。

speechRecognizer.ContinuousRecognitionSession.Completed +=
      ContinuousRecognitionSession_Completed;
  1. 事件處理常式會檢查 Status 屬性,以判斷辨識是否成功。 它也會處理使用者已停止說話的情況。 通常, 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 事件,以改善這種明顯缺乏回應性。 每當辨識器針對正在處理的字組產生一組新的潛在相符專案時,就會引發此事件。 事件自變數會提供 包含目前相符項目的假設 屬性。 在使用者繼續說話時向使用者顯示這些內容,並向他們保證處理仍在作用中。 一旦信賴度很高,且已判斷辨識結果,請將臨時假設結果取代為 ResultGenerated 事件中提供的最終結果。

在這裡,我們會將假設文字和省略號 (“...”) 附加至輸出 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 屬性的值。 語音辨識器必須處於 閑置 狀態。

檢查語音辨識器的狀態之後,我們會呼叫語音辨識器的ContinuousRecognitionSession屬性的 StartAsync 方法來啟動會話。

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

可透過兩種方式停止辨識:

  • StopAsync 可讓任何擱置中的辨識事件完成(ResultGenerated 會繼續引發,直到所有擱置的辨識作業完成為止)。
  • CancelAsync 會立即終止辨識會話,並捨棄任何擱置的結果。

檢查語音辨識器的狀態之後,我們會呼叫語音辨識器的ContinuousRecognitionSession屬性的 StartAsync 方法來啟動會話。

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

注意

在呼叫 CancelAsync 之後,可能會發生 ResultGenerated 事件。
由於多執行緒處理,呼叫 CancelAsync 時,ResultGenerated 事件可能仍會保留在堆棧上。 如果是, ResultGenerated 事件仍會引發。
如果您在取消辨識會話時設定任何私人欄位,請一律在 ResultGenerated 處理常式中確認其值。 例如,如果您取消會話時將其設定為 null,請勿假設處理常式中的欄位已初始化。

 

範例