學習如何捕捉並辨識長格式、連續的語音輸入。
重要 API: SpeechContinuousRecognitionSession、 ContinuousRecognitionSession
在語音辨識中,你會學會如何利用 SpeechRecognitionr 物件的 RecognizeAsync 或 RecognizeWithUIAsync 方法捕捉並辨識相對較短的語音輸入,例如在撰寫短訊服務(SMS)訊息或提問時。
對於較長且持續的語音辨識會話,如聽寫或電子郵件,請使用 SpeechRecognitionr 的 ContinuousRecognitionSession 屬性來取得 SpeechContinuousRecognitionSession 物件。
備註
語音輸入語言的支援取決於你應用程式執行的 裝置 。 對於個人電腦和筆記型電腦,只有 en-US 能被辨識,而 Xbox 和手機則能辨識所有語音辨識支援的語言。 欲了解更多資訊,請參閱 「指定語音識別語言」。
設定
你的應用程式需要幾個物件來管理持續的語音輸入工作:
- 一個 SpeechRecognitionr 物件的實例。
- 指的是 UI dispatcher,在語音輸入時用來更新 UI。
- 一種追蹤使用者累積說過字數的方法。
在這裡,我們將 SpeechRecognitionr 實例宣告為程式碼背後類別的私有欄位。 如果你想讓連續的語音輸入能持續存在於單一可擴充應用程式標記語言(XAML)頁面之外,應用程式就必須在其他地方儲存參考。
private SpeechRecognizer speechRecognizer;
在語音辨識過程中,識別器會從背景執行緒中觸發事件。 由於背景執行緒無法直接在 XAML 中更新使用者介面,你的應用程式必須使用派遣器來回應識別事件來更新使用者介面。
這裡,我們宣告一個私有欄位,之後會用 UI dispatcher 初始化。
// 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 執行緒的調度器。
- 初始化語音辨識器。
- 編譯內建的聽寫語法。 注意 語音辨識需要至少一個約束條件來定義可辨識的詞彙。 若未指定限制,則使用預先定義的口述文法。 詳見 語音辨識。
- 設定識別事件的事件監聽器。
在這個範例中,我們在 OnNavigatedTo 頁面事件中初始化語音辨識。
- 由於語音識別器所引發的事件發生在背景執行緒上,請建立對調度器的參考,用於更新 UI 執行緒。 OnNavigatedTo 總是在 UI 執行緒中被調用。
this.dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
- 接著我們初始化 SpeechRecognitionr 實例。
this.speechRecognizer = new SpeechRecognizer();
接著,我們會加入並彙整定義所有能被 語音識別器辨識的單字和片語的文法。
如果你沒有明確指定文法,預設會使用預設的聽寫文法。 通常,預設語法最適合一般聽寫。
在這裡,我們會立即呼叫 CompileConstraintsAsync ,且不加文法。
SpeechRecognitionCompilationResult result =
await speechRecognizer.CompileConstraintsAsync();
處理辨識事件
你可以透過呼叫 RecognizeAsync 或 RecognizeWithUIAsync 來擷取一個簡短的語句或片語。
然而,為了捕捉更長且連續的識別會話,我們指定事件監聽器在使用者說話時於背景執行,並定義處理程序來建立聽寫字串。
接著,我們利用識別器的 ContinuousRecognitionSession 屬性取得 SpeechContinuousRecognitionSession 物件,提供管理連續識別會話的方法與事件。
有兩個事件特別關鍵:
- ResultGenerated,當識別器產生了一些結果時。
- 完成,即連續識別會話結束。
當使用者說話時, ResultGenerated 事件會被觸發。 識別器會不斷地聆聽使用者,並定期觸發事件以傳遞收集的語音片段。 你必須利用事件參數的 Result 屬性檢查語音輸入,並在事件處理器中採取適當行動,例如將文字附加到 StringBuilder 物件上。
作為 SpeechRecognitionResult 的一個實例, Result 屬性對於判斷你是否要接受語音輸入非常有用。 語音辨識結果 提供了兩個屬性:
以下是支持持續識別的基本步驟:
- 在此,我們在 OnNavigatedTo 頁面事件中註冊了 ResultGenerated 連續識別事件的處理器。
speechRecognizer.ContinuousRecognitionSession.ResultGenerated +=
ContinuousRecognitionSession_ResultGenerated;
接著檢查 信心 性質。 如果信心值為 中 等或以上,我們會將文字附加到 StringBuilder。 我們也會在收集輸入時更新使用者介面。
請注意,ResultGenerated 事件是在背景執行緒中被觸發,無法直接更新使用者介面。 如果處理器需要更新使用者介面(如 [Speech and TTS 範例]),您必須透過 dispatcher 的 RunAsync 方法將更新發送到使用者介面執行緒。
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)。
在這裡,我們在 OnNavigatedTo 頁面事件中註冊 Completed 連續識別事件的處理程序。
speechRecognizer.ContinuousRecognitionSession.Completed +=
ContinuousRecognitionSession_Completed;
事件處理器會檢查 Status 屬性,以判斷辨識是否成功。 它也能處理使用者停止說話的情況。 通常,逾時已 過 時被視為成功識別,因為這表示使用者已經說完話。 你應該在程式碼中處理這個案例,這樣才能有良好的體驗。
請注意,ResultGenerated 事件是在背景執行緒中被觸發,無法直接更新使用者介面。 如果處理程式需要更新 UI(如 [Speech and 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 事件之前,不會提供任何結果。
處理 假設生成 事件以改善這種明顯的回應不足。 每當識別器為該單字產生新的潛在匹配組合時,此事件就會被觸發。 事件參數提供一個包含當前匹配的 假設 屬性。 在使用者繼續發言時,將這些資料展示給他們,並讓他們放心處理仍在進行中。 一旦信心度升高且已確定識別結果,則以 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;
});
}
開始與停止辨識
在開始識別會話前,檢查語音識別器 狀態 屬性的值。 語音辨識器必須處於 閒置 狀態。
檢查語音辨識器的狀態後,我們會呼叫語音辨識器的 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();
}
備註
在呼叫 CancelAsync 後,可能會發生 ResultGenerated 事件。
由於多執行緒的關係,當呼叫 CancelAsync 時,ResultGenerated 事件仍可能保留在堆疊上。 如果是這樣, ResultGenerated 事件仍然會觸發。
如果你在取消識別會話時設定任何私有欄位,請務必在 ResultGenerated 處理器中確認它們的值。 舉例來說,如果你在取消會話時把欄位設為 null,就不要假設某欄位在處理器裡已經被初始化了。
相關文章
範例