Windows Phone 8–Voice Command,讓App懂你的話–1
過去在WP 7.1時代,如果您想在中文語系的手機裡,使用WP內鍵的語音指令功能,需要將手機調整為如下圖:
這個時候的語音功能非常的微弱,只能「open calendar」、「Call Mother」等簡單的指令,更別說支援其他語言了。
好在WP 8開始支援多語言,讓自己的App或WP本身能使用熟悉的語言(例如:中文)進行指令或程式的操作。
WP 8提供三個Speech Components與App進行互動,概念如下圖:
這三個元件功能概略如下:
(1) voice commands:指定語音指令,開啟與串聯App功能;
(2) speech recognition;在App中增加語音輸入的識別;
(3) text-to-speech (TTS);讓App針對輸入的文字進行讀誦;
得知有這三個元件之後,往下針對Voice Commands的類型與使用方式深入的說明與探討。
當用戶安裝了App後,即可在長按「Start鍵」後使用「Voice Commands」去連結該App,例如:對手機說:「Open」
或「Start」後面接「App名稱」即可以開啟指定的App。藉由這樣的方式,開發者可自訂voice commands允許用戶透過說
的方式,開啟或指定到App中特定的頁面進行功能處理。然而,這自訂的方式為了方便用戶了解,開發者也可以設定要顯
示的help說明,可以說相當方便。
要完成上述的功能,主要有三個步驟需要完成:
(1) 建立Voice Command Definition (VCD) file。它是份XML檔案定義所有Spoken commands,用戶即透過這些command與app互動;
(2) 增加程式來初始化VCD file與手機的語音功能;
(3) 增加程式來處理導向(Navigation)與執行(Execute) Commands;
往下便細部說明這三個步驟的執行方式:
(A) 在WMAppManifest.xml的<Capabilities />宣告需要的Capabilities;
要讓App支援Voice Commands需要先至WMAppManifest.xml增加需要的特性,如下:
1: <Capabilities>
2: <!--
3: 宣告Voice Commands需要的三個Capabilies:
4: 網路支援搜尋、Speech功能與麥克風功能。
5: -->
6: <Capability Name="ID_CAP_NETWORKING"/>
7: <Capability Name="ID_CAP_SPEECH_RECOGNITION" />
8: <Capability Name="ID_CAP_MICROPHONE" />
9: </Capabilities>
主要三個Capability:ID_CAP_SPEECH_RECOGNITION、ID_CAP_MICROPHONE 與 ID_CAP_NETWORKING。
(B) 建立Voice Command Definition File;
在App專案中建立一個新的VCD File,設定該檔案的[Build Action]為Content、[Copy to Output Dictionary]為Copy if newer,如下圖;
建立好了Voice Command definition後,在使用前先了解一下每一組Command在XML裡需要定義那些東西。
(B-1) 每一組Voice command具有以下特性:
‧一個example短語說明用戶如何講指令來完成command;
‧words或phrases指示應用程式將如何組識成一個可用的command;
‧設定應用程式顯示文字,以確認用戶所說的command;
‧指定當command執行時,應用程式要指定前往的screen;
來看一個簡單的sample說:
1: <?xml version="1.0" encoding="utf-8"?>
2: <VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.0">
3: <CommandSet xml:lang="en-us">
4: <CommandPrefix> Contoso Widgets </CommandPrefix>
5: <Example> Show today's specials </Example>
6: <Command Name="showWidgets">
7: <Example> Show today's specials </Example>
8: <ListenFor> [Show] {widgetViews} </ListenFor>
9: <Feedback> Showing {widgetViews} </Feedback>
10: <Navigate Target="/favorites.xaml"/>
11: </Command>
12:
13: <PhraseList Label="widgetViews">
14: <Item> today's specials </Item>
15: <Item> best sellers </Item>
16: </PhraseList>
17:
18: </CommandSet>
19:
20: <!-- Other CommandSets for other languages -->
21:
22: </VoiceCommands>
從上述VCD範例,有幾個注意的地方:
b-1.1. 選擇一個command prefix:
<CommondPrefix />用於聲明應用程式被開打的關鍵字,而其Command Name則聲明應用程式識別的動作。
<CommandPrefix />該標籤是選用的,適用於二種主要的情境:
a. 自己的應用程式名稱是不能併讀。例如:Contoso Widg3ts不能唸的,就需要用到這個標籤;
b. 對Command做了在地化(localizing)。如果Command支援各種語系就需要設定標籤,以支援不同語系的Command;
[注意]
在使用<CommandPrefix />標籤時,需注意不支援「subset match text」,舉例來說:設定了「Contoso Weather」與
「Contoso Weather [phrase]」,但如果用戶說「Contoso [phrase]」或「Weather [phrase]」將無法被識別。
更多相關的可以參考<Voice command element and attribute reference for Windows Phone 8>。
b-1.2. 在VCD File中指定words與phrases:
每一組Command最少具有一個<ListenFor />標籤,<ListenFor />可包括單一word或集合words用來代表一個Command的Action來源,
並且透過<Command />將<ListerFor />包裝起來,另外,<ListenFor />無法透過程式化的方式修改。
<PhraseList />標籤關聯<ListenFor />的應用,但該標籤可透過程式化方式修改。
也代表說<ListenFor />定義用戶要說對的指令,其指令中可替換的內容利用「{}」符號包裝起來,再透過<PhraseList />增加「{}」
中要替換的內容。
舉範例如:定義了<ListenFor>play {movie name}</ListenFor>,然而{movie}再藉由<PhraseList />定義可替換的名稱,因此,
<PhraseList />即可以透過程式化來動態產生對應的值。
====
[補充] 詳細相關Voice Command Element與Attribute的說明;請參考<Windows Phone 8–Voice Command,讓App懂你的話–2>。
==
(C) 初始化VCD File;
在應用程式第一次啟動時,即需要將定義好的VCD File進行初始化並註冊其中的Command至電話中的Speech System裡。如下程式碼:
1: await VoiceCommandService.InstallCommandSetsFromFileAsync(
2: new Uri("ms-appx:///ContosoWidgets.xml"));
上述範例以取得放置於Install folder下的檔案:ContosoWidgets.xml;
(D) 在應用程式中擷取URI參數與執行Voice Commands;
上述提到VCD File定義Command與Navigate Page,Commands被註冊於Speech System後,隨著用戶口述的指令,Speech System
依該定義,將指令的內容透過URI(NavigationContext中的QueryString)的方式,傳入指定的Navigate Page裡,因此,此步驟將擷取
URI的參數以執行Command的任務。然而,要處理送進來的參數即是該Page負責處理Command的任務。
當Speech System識別出該應用程式專用的Command時,將組如成以下的格式,並傳給按照在VCD File中定義<Command />的<Navigate />:
1: "/favorites.xaml?
2: voiceCommandName=showWidgets&
3: widgetViews=best%20sellers&
4: reco=Contoso%20Widgets%Show%20best%20sellers"
5:
6: <!-- %20:代表空白 -->
上述QueryString格式,可以對應於VCD File定義的內容,說明如下:
‧vocieCommandName:對應的是<Command />中的Name屬性;
‧widgetViews:則是由開發人員定義<PhraseList />的Label屬性,根據定義的指令組合而成,空白的部分由%20組合;
‧reco:當match <ListenFor />指定時所組合的完整Command;
[注意]
‧VCD File允許指令不同指令對應不同畫面,所以不需要實作UriMapper來切換至對應的Page。
但如果本身已支援UriMapper時,需確保Voice command保持完整的QueryString通過UriMapper至Page,避免VCD資訊消失。
透過下列程式說明如何處理QueryString:
1: protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
2: {
3: base.OnNavigatedTo(e);
4:
5: // 識別是新的Activiation或是從Tombstone返回;
6: if (e.NavigationMode == System.Windows.Navigation.NavigationMode.New)
7: {
8: // 識別QueryString是否具有VoiceCommandName關鍵字;
9: if (NavigationContext.QueryString.ContainsKey("voiceCommandName"))
10: {
11:
12: // 取得VoiceCommandName中的值
13: string voiceCommandName
14: = NavigationContext.QueryString["voiceCommandName"];
15:
16: // 定義VoiceCommandName要對應的處理方式
17: switch (voiceCommandName)
18: {
19: case "showWidgets":
20: string viewWidget = NavigationContext.QueryString["widgetViews"];
21:
22: // Add code to display specified widgets.
23: break;
24:
25: // Add cases for other voice commands.
26: default:
27:
28: // There is no match for the voice command name.
29: break;
30: }
31: }
32: }
33: }
(E) Localizing voice commands:
VCD File支援指定多種語系的指令,透過建立多種<CommandSet />指定不同xml:lang的類型。如下範例:
1: <VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.0">
2: <!-- 定義各種語系適用的指令 -->
3: <CommandSet xml:lang="en-US" />
4: <CommandSet xml:lang="zh-TW" />
5: </VoiceCommands>
需注意的事,xml:lang是依據OS內鍵的Speech語系,需至「> System > Speech > Speech Language Screen」進行設定。
如果您只有設定的是一種語系,那在Speech Language Screen裡的設定一定要選擇該語系,不然應用程式將不支援voice command。
(F) Programmatically modifying phrase lists:
Voice commands API提供二種方法支援動態的更新phrase list:
(f-1) 透過CommandSet的Name屬性名稱擷取VoiceCommandSet;
(f-2) 透過PhraseList的Label屬性更新VoiceCommandSet指定Lable的<PhraseList />;
動態更新phrase list是非常好用的,可適合用指定定期更新的任務,例如:查詢電影播放時間或是用戶最愛的資料清單。
然而,要更新phrase list首先需取得預計更新的<CommandSet />;可透過VoiceCommandSet物件來進行操作,需注意每一個
VoiceCommandSet在VCD File裡有一個唯一的名稱,因此,要取得VoiceCommandSet即是透過Name來擷取,如下程式範例:
取得VoiceCommandSet:
1: // 利用<CommandSet xml:lang="en-US" Name="en-US" />中的Name屬性;
2: VoiceCommandSet widgetVcs =
3: VoiceCommandService.InstalledCommandSets["en-US"];
更新VoiceCommandSet中的指定Label的PhraseList:
1: // 指令Label更新其中的Phrase List
2: await widgetVcs.UpdatePhraseListAsync("saved",
3: new string[] {"today’s special", "best sellers", "hammer", "plane", "scroll saw"});
要注意當更新了PhraseList後,它將取代原定義於VCD File中的內容,如果想要更新時也保留舊有的Phrase,則需要將舊有的Phrase也加入,
才有辦法完整的保持。例如:原有"today's special",更新時一樣要加入至新的Phrase List。
(G) GUI screens for voice commands:
定義Voice commands時也包含了「GUI screens」協助用戶了解該應用程式提供那些Voice commands與那一種指令可以觸發程式。
‧用戶從應用程式清單選擇一個應用程式;
‧用戶在應用程式裡口述一個voice command,但被系統識別時不是正確的Request actiond時,螢幕會出現一個遮屏,裡面有個「?」可提示;
其GUI screens提供二種類型:
G-1. The What can I say screen:
主要列出系統一般支援的voice commands與範例來說明如何執行程式與觸發互動任務。
要如何出現下列的圖示,可長按「Start」鍵然後說「what can I say?」或是在畫面中按下global listening畫面的「?」鈕。
G-2. The Did you know? screen:
該畫面比較特別,它會列出指定應用程式可用的voice commands得以執行該程式。該畫面於上述的「global listening screen」
屬於同一個畫面只是不同的tab,它內容會包括應用程式名稱(或是VCD File中定義的<CommandPrefix />名稱)與voice command example。
=>點擊「?」鈕後會出現有「apps頁籤」,選擇該頁籤點擊指定的應用程式,則可以看到如第三圖的說明。
[範例]
該範例簡單定義了一組<CommandSet />以支援中文語系,舉例搭公車的測試,其voice command為「VCDProject 搭72車」。
a. Voice command Definition File的格式:
1: <?xml version="1.0" encoding="utf-8"?>
2:
3: <VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.0">
4:
5: <CommandSet xml:lang="zh-TW" Name="myTWCommands">
6:
7: <CommandPrefix>公車</CommandPrefix>
8:
9: <Example> 搭幾號車 </Example>
10:
11: <Command Name="TakeBus">
12: <Example> 搭幾號車 </Example>
13: <ListenFor> 搭 {busnumber} 車 </ListenFor>
14: <Feedback> 搭 {busnumber} 車 </Feedback>
15: <Navigate Target="MainPage.xaml" />
16: </Command>
17:
18: <PhraseList Label="busnumber">
19: <Item> 1 </Item>
20: <Item> 72 </Item>
21: <Item> 33 </Item>
22: </PhraseList>
23:
24: </CommandSet>
25: </VoiceCommands>
b. 在MainPage.xaml中,實作註冊VCD File與在OnNavigated()時處理Speech System傳入的參數:
b-1. 註冊VCD File:
1: private bool voiceCommandInitialized = false;
2:
3: private async void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
4: {
5: if (!this.voiceCommandInitialized)
6: {
7: try
8: {
9: // 向Speech System註冊該應用程式定義的VCD File
10: Uri uri = new Uri("ms-appx:///voicecommands.xml", UriKind.Absolute);
11: // 透過Windows.Phone.Speech.VoiceCommands.VoiceCommandService.InstallCommandSetsFromFileAsync註冊
12: await Windows.Phone.Speech.VoiceCommands.VoiceCommandService.InstallCommandSetsFromFileAsync(uri);
13:
14: this.voiceCommandInitialized = true;
15:
16: MessageBox.Show("install voice command file, successful!");
17: }
18: catch (Exception error)
19: {
20: MessageBox.Show(error.Message + "\r\nVoice Commands failed to initialize.");
21: }
22: }
23: }
b-2. 在OnNavigated()時處理Speech System傳入的參數:
1: protected override void OnNavigatedTo(NavigationEventArgs e)
2: {
3: base.OnNavigatedTo(e);
4:
5: // 判斷NavigationContext中的QueryString是否具有 voiceCommandName
6: if (NavigationContext.QueryString.ContainsKey("voiceCommandName") == true)
7: {
8: // 利用<Command />中定義的Name屬性取值
9: string tCmd = NavigationContext.QueryString["voiceCommandName"].ToString();
10: // 利用<Command />使用<PhraseList>的Label屬性取值
11: string tPhare = NavigationContext.QueryString["busnumber"].ToString();
12: // 取得完整的command
13: string tReco = NavigationContext.QueryString["reco"].ToString();
14: tblQueryStrgin.Text =
15: string.Format("voiceCommandName={0}&\nbusnumber={1}&\nreco={2}", tCmd, tPhare, tReco);
16: }
17: }
[範例程式]
[注意]
‧在處理Voice Command時,如果遇到Exception時,可參考<Handling errors in speech apps for Windows Phone>。
‧WP8手機支援應用程式的Backup,但應用程式裡定義的VCD File並不會被Backup下來:
=>建議在應用程式的"Lauch"事件裡,初始化或增加識別是否需要初始化VCD File的邏輯,避免無法使用Voice Command功能。
======
以上是介紹如何在自己的App裡加上WP 8新API:Speech API,讓應用程式可以支援包括:自訂專屬的Speech Command或
Text-to-Speech APIs允許讀用戶的語言…等。這些功能也讓我聯想到可用於例如:指定開啟家裡的燈、電視等跟其他設備
的結合,讓App能控制的範圍更多更特別。該篇的介紹,希望有助於大家了解Speech API的使用。
References:
‧What's new in Windows Phone 8 SDK for developers (重要)
‧What's new in Windows Phone SDK 8.0 (重要)
‧Speech for Windows Phone 8 (重要)
‧Voice commands for Windows Phone 8
‧Speech recognition for Windows Phone 8
‧Text-to-speech (TTS) for Windows Phone
‧Voice command element and attribute reference for Windows Phone 8 (重要)
‧Text to Speech in Windows Phone 7 (重要)
‧Use Speech on my phone (教學,在手機中怎麼使用語音)
‧Alarm Clock with Voice Commands Sample
‧Updating a Voice Command Phrase List using a Background Agent (重要)
‧More Speech for Windows Phone Samples
‧WP8 Voice Commands: Phrase Lists & WP8 Voice Commands: Dynamic Phrase Lists … From Azure!
‧Windows Phone 8 语音 - Speech for Windows Phone 8