Windows Phone 8–Voice Command,讓App懂你的話–2
在撰寫<Windows Phone 8–Voice Command,讓App懂你的話–1>時,我發現在往下看範例時,
應該先了解一下VCD File裡所有的標籤與屬性的意義,有助於了解VCD File的定義與操作方式。
因此,針對Voice command element與attribute加以深入說明。
〉Voice Command Definition (VCD) file:
以下簡略列出一個範例,了解其VCD File的內容與定義的格式:
1: <?xml version="1.0" encoding="utf-8"?>
2:
3: <VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.0">
4: <!-- CommandSet:一種語系一個 -->
5: <CommandSet xml:lang="" Name="">
6: <CommandPrefix></CommandPrefix>
7: <Example></Example>
8:
9: <Command Name="">
10: <Example></Example>
11: <ListenFor></ListenFor>
12: <Feedback></Feedback>
13: <Navigate Target="" />
14: </Command>
15:
16: <!-- PhraseList依照{}的類型增長 -->
17: <PhraseList Label="">
18: <Item></Item>
19: <Item></Item>
20: </PhraseList>
21:
22: </CommandSet>
23: </VoiceCommands>
往下針對每一個elements 與attributes 加以說明其定義與組合的方式:
(A) elements與attributes說明表:
Element | Description |
VoiceCommands | voice command manifest的root element (必要element)。 xmlns:屬性其值為固定:http://schemas.microsoft.com/voicecommands/1.0。 該element可以包括一至多個<CommandSet />,而每一個<CommandSet />代表一種語系的voice command。 |
CommandSet | <VoiceCommand />下的child element (必要element)。 一個<CommandSet />代表一種語系於應用程式中所支援的所有voice command,支援二種屬性,如下: ‧xmlns:lang:定義<CommandSet />屬於何種語系,在<VoiceCommand />中必須為唯一值。 ‧Name:選擇用的屬性,可為任何字串,用途在於程式化參考與更新該<CommandSet />的<PhraseList />。 該<CommandSet />包括以下的child elements,需注意這些child是有順序性,不可以更換出現位置: ‧<CommandPrefix /> (0 or 1); ‧<Example /> (1 only); ‧<Command /> (1 to 100); ‧<PhraseList /> (0 to more); |
CommandPrefix | <CommandSet />中選擇性的child element,如果該element出現代表它需出現在所有<CommandSet />中child element的第一個。建議定義一個user-friendly name,讓用戶在下達voice command時可以唸的出來,有助於當應用程式名稱非常難唸時很好用。 |
Command | <CommandSet />中必要element。具有Name屬性。定義一個應用程序操作,用戶可以啟動的演講和什麼樣的用戶可以說,開始行動。每一個<Command />關聯至應用程式中指定的一個Page。 該<Command />包括以下的child elements: ‧<Example /> (1 only); ‧<ListenFor /> (up to 10); ‧<Facebook /> (1 only); ‧<Navigate /> (1 only); |
Example | <Command />中必要的element。<CommandSet />中選擇性的element。 提供一個範例告知用戶如何說出指令。 定義的Example會出現至下列的Screen: 1. 在what can I say screen的apps頁籤中,各個應用程式名稱下出現一句範例; 2. 在what can I say screen的open頁籤中,呈現二個額外的範例說明:應用程式名稱 + 範例字段,可連結至apps頁籤。 3. 在some error screens。 4. 在Listening screens。 5. 在Did you know? help screen中列出該應用程式的指令清單。 上述幾個點,透過下圖說明: |
ListenFor | <Command />中必要的element。該內容包括word或phrase讓應用程式識別與組織成一個指令。它可能include或reference到<PhraseList />中的Label屬性值,並且在<ListenFor />中用「{Label value}」給包裝起來。 一個<Command />可最多擁有10組<ListenFor />,而其中每一個<LisenFor />均可以被組織成一個active the command。 使用「[]」方框包住的word代表是選擇性使用的話,在口訴指令時可以使用或省略其word。 另外,設定一組 <ListenFor>Find {*}</ListenFor>:指定星字符號是任何一種word或phrase,口訴指令只要說:Find。 |
Feedback | <Command />中必要的element。定義當指令被正確識別後,出現的回饋字段。 如果<Feedback />包含參考的<PhraseList />元素,代表其<Command />下的每一個<ListenFor />均要參考到該<PhraseList />,這樣組合字段才能正確匹配。 |
Navigate | <Command />中必要的element。透過Target屬性指令當voice command被系統執行時要導向應用程式的那一個Page。 在Target屬性中除了可以指定Page名稱,也可以加上QueryString。如果沒有指定Target值,預設指定main page。 如下: <Navigate Target="Page2.xaml?myParam=someValue"/> |
PhraseList | <CommandSet />中選擇使用的element,必要有Label屬性。該Label值必須與<ListenFor />或<Feedback />中使用{}包裝起來的值相同。選擇用的Disambiguate屬性(default為true),用於控制<PhraseList />有些易混淆的word或phrase,在組合voice command的參數至QueryString時詳細指出。 最多有2,000個<Item />,其限制受限於同一個<CommandSet />下的<PhraseList />總合。每一個<Item />可被組合成對應的active command。 |
Item | <PhraseList />中選擇使用的element,內容可為多個words或phrases的組合。一個<CommandSet />可擁有最多2,000個<Item />,所有<PhraseList />的總合。 |
(B) []與{}符號的定義:
Special character | Description |
{} | 用於包括<PhraseList />的Label屬性值,例如:{myphraselist}。可使用於<ListenFor />或<Feedback />之中,而且二者使用的<PhraseList />必須相同。 |
[] | 用於指定接近的單字或片語時,是選擇性使用的。接近的單字或片語,舉例來說: <ListenFor>[start] [begin] new game</ListenFor>,用戶說"start new game"、"begin new game"或"new game",其實都是符合條件的。 每一個[]所包括的內容是獨立應用的,它們出現的順序需按照<ListenFor />中所定義的排列。例如:new game,可以說"start new game"是正確的,但說成"begin start new game"即是錯誤的。因[start]在[begin]前面。 |
要注意,不可以寫成 [[start] new game]或[{myphraselist}]這種巢狀式組合的字段。
以上主要針對VCD File內容中的element與attribute做了一個詳細的說明,有助於了解voice command如何定義,並且在定義的時候,
也可以思考未來更新<PhraseList />中<Item />的機制。
接下來針對處理Voice Command時必要的元素加以說明。
〉Windows.Phone.Speech.VoiceCommands:
主要的voice command functionally,包括初始化Voice Command Definition (VCD)檔案與處理VCD檔案中的每一個元素。
該Namespace有二個主要的類別:
類別 | 說明 |
VoiceCommandService | 靜態類別。負責初始化、安裝VCD檔案中的每一個Command sets,也支援取得被安裝過的Command sets。 |
VoiceCommandSet | 代表一個被安裝過的Command Set。 |
往下細部來看這二個類別。
(A) VoiceCommandService Class:
此為靜態類別。負責初始化、安裝VCD檔案中的每一個Command sets,也支援取得被安裝過的Command sets。
以下是它可用的方法與屬性:
類型 | 名稱 | 說明 |
Method | InstallCommandSetsFromFileAsync | 安裝Voice Command Definition中定義的<CommandSet />元素。 |
Attribute | InstalledCommandSets | 屬於唯讀(Read-Only)。該dictionary中包括所有安裝的Command sets,可透過指定的Name來取得Voice Command Definition檔案中的Command sets。 |
(B) VoiceCommandSet:
代表一個被安裝過的Command set。也就是透過VoiceCommandService.InstalledCommandSets("Name");方法取得的Command set物件。
要針對<CommandSet />中引用的<PhraseList />透過程式化動態更新,即需要取得VoiceCommandSet物件,以下是該類別的方法與屬性:
類型 | 名稱 | 說明 |
Method | UpdatePhraseListAsync | 填充<PhraseList />中每一個<Item />項目後,利用此方法更新VoiceCommandSet物件所參考的Phrase List。 |
Attribute | Language | 取得該VoiceCommandSet物件指定的語系。 |
Attribute | Name | 取得該VoiceCommandSet物件的名稱。 |
以下是針對Voice Command中重要的API與Voice command definition檔案的說明,往下介紹二個必要常用的範例。
[範例]
本篇範例延用<Windows Phone 8–Voice Command,讓App懂你的話–1>的公車語音範例,加以說明:
1. 動態更新<PhraseList />,依賴外部匯入的詞彙清單;
1: private async void Button_Click_1(object sender, RoutedEventArgs e)
2: {
3: // 動態更新<PhraseList />中的<Item />
4: // 利用<CommandSet />中的Name屬性取得值
5: VoiceCommandSet tCmdSet = VoiceCommandService.InstalledCommandSets["myTWCommands"];
6: // 更新該<CommandSet />中指定Label屬性的<PhraseList />
7: await tCmdSet.UpdatePhraseListAsync("busnumber", new string[] { "100", "55688", "983", "189", "101" });
8: }
2. 透過background agent更新<PhraseList />;
2-1. 在專案中先建立一個Windows Phone Schedule Task Agent的Background Agent專案,並且加上動態載入新Phrase List的邏輯;
1: protected override void OnInvoke(ScheduledTask task)
2: {
3: // 啟動更新CommandSet
4: BgUpdatePhraseList();
5:
6: NotifyComplete();
7: }
8:
9: private async void BgUpdatePhraseList()
10: {
11: // 建立一個更新完畢後要通知的Toast物件
12: Microsoft.Phone.Shell.ShellToast tToast = new Microsoft.Phone.Shell.ShellToast();
13: tToast.Title = "VCDBackgroundApp";
14:
15: try
16: {
17: // 取得該應用程式目前Speech System已安裝的CommandSets集合。
18: System.Collections.Generic.IReadOnlyDictionary<String, VoiceCommandSet> CommandSets =
19: VoiceCommandService.InstalledCommandSets;
20: // 取得指定VCD File中定義的<CommandSet />Name。
21: VoiceCommandSet EnglishVCS = CommandSets["myTWCommands"];
22:
23: // 更新該<CommandSet />中引用的<PhraseList />Label。
24: String[] tBusNumber = { "909", "253", "476", "001", "1", "72", "33" };
25: String[] tStopName = { "大坪林", "士林", "圓山", "台北車站" };
26: await EnglishVCS.UpdatePhraseListAsync("stopname", tStopName);
27: await EnglishVCS.UpdatePhraseListAsync("busnumber", tBusNumber);
28: tToast.Content = "更新 Phraselists 成功!";
29: tToast.Show();
30: }
31: catch (Exception err)
32: {
33: Debug.WriteLine(err.ToString());
34: Debug.WriteLine(err.Message + " " + err.StackTrace);
35: tToast.Content = "更新 Phraselists 失敗!";
36: tToast.Show();
37: }
38: }
2-2. 在主程式中加入一個PeriodicTask物件,指定ScheduleActionService進行Schedule Task的任務;
1: private void Button_Click_2(object sender, RoutedEventArgs e)
2: {
3: try
4: {
5: // 定義一個PeriodicTask物件,設定期限為1天
6: PeriodicTask task = new PeriodicTask("MyTask");
7: task.Description = "定期更新 voice command phrase lists.";
8: task.ExpirationTime = DateTime.Now.AddDays(1);
9:
10: // 識別目前是否有存在的PeriodicTask,有便移除
11: if (ScheduledActionService.Find(task.Name) != null)
12: {
13: ScheduledActionService.Remove(task.Name);
14: }
15:
16: //加入該PeriodicTask
17: ScheduledActionService.Add(task);
18:
19: #if DEBUG
20: // 指定在5秒後,執行background task
21: // LaunchForTest() 只支援在debug模式下運作
22: ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(5));
23: #endif
24: }
25: catch (Exception err)
26: {
27: Debug.WriteLine(err.ToString());
28: Debug.WriteLine(err.Message + " " + err.StackTrace);
29: }
30: }
需注意Shcedule Task Agent在正式版運作時,系統採用每30分鐘更新一次,以上範例是透過ScheduledActionService.LaunchForTest指定
5秒內更新的效果,在正式版需注意。
[範例程式]
[補充]
‧註冊Voice command File遇到錯誤訊息:
‧0x80045584:主要是<CommandSet />中xml:lang屬性值設定的語系錯誤。
======
連續撰寫二篇有關Voice Command操作的文章,希望能讓大家跟我一樣了解如何使用Voice Command使應用程式有更好的操作體驗。
相關其他Speech API的使用,請往下繼續收看。
References:
‧Voice command element and attribute reference for Windows Phone 8 (重要)
‧Handling errors in speech apps for Windows Phone (錯誤代碼查詢)
‧System voice commands for Windows Phone 8 (WP8各語系Command的說明)
‧Speech For Windows Phone: Refreshing a phrase list using a background agent (重要)
‧App capabilities and hardware requirements for Windows Phone
‧App policies for Windows Phone
‧Speech-Enabling a Windows Phone 8 App with Voice Commands (重要)