連續聽寫
瞭解如何擷取和辨識長格式、連續聽寫語音輸入。
重要 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 頁面事件中初始化語音辨識。
- 由於語音辨識器引發的事件發生在背景執行緒上,因此請建立發送器的參考,以更新UI執行緒。 OnNavigatedTo 一律會在UI執行緒上叫用。
this.dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
- 然後, 我們會初始化 SpeechRecognizer 執行個體。
this.speechRecognizer = new SpeechRecognizer();
然後,我們新增並編譯文法,以定義SpeechRecognizer可辨識的所有單字和片語。
如果您未明確指定文法,預設會使用預先定義的聽寫文法。 一般而言,預設文法最適合一般聽寫。
在這裡,我們會立即呼叫 CompileConstraintsAsync ,而不需要新增文法。
SpeechRecognitionCompilationResult result =
await speechRecognizer.CompileConstraintsAsync();
處理辨識事件
您可以呼叫 RecognizeAsync 或 RecognizeWithUIAsync 來擷取單一、簡短的語句或詞組。
不過,為了擷取較長的連續辨識會話,我們會指定事件接聽程式在使用者說話時在背景中執行,並定義處理常式來建置聽寫字元串。
接著,我們會使用辨識器的 ContinuousRecognitionSession 屬性來取得 SpeechContinuousRecognitionSession 物件,以提供管理連續辨識會話的方法和事件。
特別有兩個事件很重要:
- ResultGenerated,會在辨識器產生一些結果時發生。
- 已完成,會在連續辨識會話結束時發生。
ResultGenerated 事件會在使用者說話時引發。 辨識器會持續接聽使用者,並定期引發事件,以傳遞大量語音輸入。 您必須使用 事件自變數的 Result 屬性來檢查語音輸入,並在事件處理常式中採取適當的動作,例如將文字附加至 StringBuilder 物件。
做為SpeechRecognitionResult的執行個體,Result 屬性有助於判斷您是否要接受語音輸入。 SpeechRecognitionResult 提供下列兩個屬性:
以下是支援連續辨識的基本步驟:
speechRecognizer.ContinuousRecognitionSession.ResultGenerated +=
ContinuousRecognitionSession_ResultGenerated;
然後檢查 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();
});
}
}
接著,我們會處理 Completed 事件,指出連續聽寫的結尾。
當您呼叫 StopAsync 或 CancelAsync 方法時,會話會結束(如下一節所述)。 會話也可以在發生錯誤時結束,或使用者已停止說話時結束。 檢查事件自變數的 Status 屬性,以判斷會話結束的原因(SpeechRecognitionResultStatus)。
speechRecognizer.ContinuousRecognitionSession.Completed +=
ContinuousRecognitionSession_Completed;
事件處理常式會檢查 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,請勿假設處理常式中的欄位已初始化。
相關文章
範例