Win10/UWP開發—使用Cortana語音與App後臺Service交互

上篇文章中咱們介紹了使用Cortana調用前臺App,不熟悉的移步到:Win10/UWP開發—使用Cortana語音指令與App的前臺交互,這篇咱們講講如何使用Cortana調用App的後臺任務,相比調用前臺的App,調用後臺任務有個有點就是App不用被啓動便可爲用戶提供服務。html

要想使用Cortana調用App後臺任務,首先咱們須要定義VCD文件,咱們依舊使用上篇中的代碼,讓它支持Cortana調用後臺任務。api

 

建立後臺任務

新增一個[Windows運行時組件]項目,暫時起名叫作:XiaoMiBackgroundTaskapp

建立一個類,暫且叫作XiaoMiTask,並繼承IBackgroundTaskasync

完成以下代碼:學習

//------------------------------------------------------
//
// FileName:    XiaoMiTask.cs
// Namespace:   XiaoMiBackgroundTask
// Assembly:    XiaoMiBackgroundTask
// Description:     
// Author:      aran_wang
// Created On:  2015-09-10
//------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.ApplicationModel.AppService;
using Windows.ApplicationModel.Background;
using Windows.ApplicationModel.VoiceCommands;
using Windows.Storage;
 
namespace XiaoMiBackgroundTask
{
    /*
    VoiceCommandServiceConnection 類是接受Cortana傳遞過來的信息以及給Cortana迴應信息的
    裏面有幾個重要的方法:
        GetVoiceCommandAsync        檢索用戶的語音命令提交Cortana經過語音或文本。
        ReportFailureAsync          發送一個響應,代表Cortana語音命令處理失敗了。
        ReportProgressAsync         發送一個響應,Cortana在處理語音命令。
        ReportSuccessAsync          發送一個響應,Cortana語音命令已成功了。
        RequestAppLaunchAsync       發送一個響應,要求Cortana啓動前臺應用
        RequestConfirmationAsync    發送一個響應,指示Cortana語音命令須要確認。
        RequestDisambiguationAsync  發送一個響應,表示Cortana語音命令返回多個結果,須要用戶選擇一個。
    */
 
    public sealed class XiaoMiTask : IBackgroundTask
    {
        BackgroundTaskDeferral _taskDerral;
        VoiceCommandServiceConnection _serviceConnection;
        public async void Run(IBackgroundTaskInstance taskInstance)
        {
            _taskDerral = taskInstance.GetDeferral();
            var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
 
            // 驗證是否調用了正確的app service
            if (details == null || details.Name != "XiaoMiService")
            {
                _taskDerral.Complete();
                return;
            }
            _serviceConnection = VoiceCommandServiceConnection.FromAppServiceTriggerDetails(details);
            // 獲取被識別的語音命令
            var cmd = await _serviceConnection.GetVoiceCommandAsync();
            switch (cmd.CommandName)
            {
                case "QueryTrain":
                    var date = cmd.Properties["DateTime"][0];
                    var from = cmd.Properties["From"][0];
                    var to = cmd.Properties["To"][0];
                    await QueryTrain(date, from, to);
                    break;
                case "CancelTrain":
                    var cancelTrain = cmd.Properties["City"][0];
                    CancelTrain(cancelTrain);
                    break;
            }
            _taskDerral.Complete();
        }
 
        private void CancelTrain(string cancelTrain)
        {
            //取消火車 交互相似
            Debug.WriteLine(cancelTrain);
        }
 
        private async Task QueryTrain(string date, string from, string to)
        {
            // msgback是返回給Cortana 要顯示的內容
            var msgback = new VoiceCommandUserMessage();
            // msgRepeat是指當cortana對用戶語音指令不明確的時候顯示的,通常用來消除用戶歧義
            // 好比存在讓用戶選擇某個選項時,用戶沒有按照預期的操做方式去操做,cortana會顯示第二消息來告訴一些操做提示信息
            var msgRepeat = new VoiceCommandUserMessage();
 
            //模擬火車列表,真實狀況下須要調用api獲取火車信息
            var trainList = new List<VoiceCommandContentTile>();
            for (var i = 0; i < 6; i++)
            {
                trainList.Add(new VoiceCommandContentTile
                {
                    AppContext = i, //用來存儲該條Tile的標識  通常存儲數據id
                    ContentTileType = VoiceCommandContentTileType.TitleWith68x68IconAndText,
                    Image = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Images/300300.jpg")),
                    Title = $"D{i + 3}8{i * 2}",
                    TextLine1 = $"出發:{DateTime.Now.AddHours(i)} - 到達:{DateTime.Now.AddHours(i + 2)}"
                });
            }
 
            TrainList:
 
            msgback.DisplayMessage = msgback.SpokenMessage = $"我找到了{date}從{from}到{to}的火車列表,請選擇:";
            msgRepeat.DisplayMessage = msgRepeat.SpokenMessage = "你要告訴我你想預約哪一個車次的火車:";
            // 把查詢到的火車列表發回到Cortana ,注意 列表最多顯示10個
            var response = VoiceCommandResponse.CreateResponseForPrompt(msgback, msgRepeat, trainList);
 
            // 用戶選擇了哪一個項
            var selectedRes = await _serviceConnection.RequestDisambiguationAsync(response);
 
            //建立諮詢用戶是否肯定要預約該車次的信息
            msgback.DisplayMessage = msgback.SpokenMessage = $"您肯定要預約 {selectedRes.SelectedItem.Title} 次列車嗎?";
            msgRepeat.DisplayMessage = msgRepeat.SpokenMessage = "請選擇是或者不是";
            response = VoiceCommandResponse.CreateResponseForPrompt(msgback, msgRepeat);
 
            //返回讓用戶選擇 是 或者 不是 的信息給cortana
            var result = await _serviceConnection.RequestConfirmationAsync(response);
            //若是用戶選擇是
            if (result.Confirmed)
            {
                //提示預約成功
                msgback.DisplayMessage = msgback.SpokenMessage = $"您成功預約了 {selectedRes.SelectedItem.Title} 次列車,{date}從{from}到{date},{selectedRes.SelectedItem.TextLine1}!";
                msgRepeat.DisplayMessage = msgRepeat.SpokenMessage = $"您成功預約了 {selectedRes.SelectedItem.Title} 次列車。";
                response = VoiceCommandResponse.CreateResponseForPrompt(msgback, msgRepeat);
            }
            else
            {
                goto TrainList;
            }
            // 返回一個操做成功的指令
            await _serviceConnection.ReportSuccessAsync(response);
        }
    }
}

代碼意思就不解釋了,寫的一手詳細的註釋不是嗎?spa

回到咱們的主程序中,在引用裏添加該後臺應用服務的引用。code

註冊App後臺服務

打開Package.appxmanifest文件,切換到"聲明"選項卡,添加一個應用服務的聲明,名稱隨便填,一會VCD文件裏要用到這個名字,這裏填寫XiaoMiService,別覺得是小米的意思哈,哥是米黑,是小祕。入口點填寫上面建立的後臺服務的"命名空間.類名",截圖以下:xml

編寫VCD文件

在vcd語音指令中添加兩個新的Command節點,以及定義須要的PhraseTopic,對VCD文件不熟悉的移步到:Win10/UWP開發—使用Cortana語音指令與App的前臺交互htm

添加的代碼以下:blog

 1 <Command Name="QueryTrain">
 2   <Example> 查詢去某地的火車  </Example>
 3   <ListenFor >查詢{DateTime}從{From}到{To}的火車</ListenFor>
 4   <Feedback> 正在查詢{DateTime}從{From}到{To}的火車 </Feedback>
 5   <VoiceCommandService Target="XiaoMiService"/>
 6 </Command>
 7  
 8  
 9 <Command Name="CancelTrain">
10   <Example> 取消去某地的火車  </Example>
11   <ListenFor >取消去{City}的火車</ListenFor>
12   <Feedback> 正取消去{City}的火車 </Feedback>
13   <VoiceCommandService Target="XiaoMiService"/>
14 </Command>
15  
16 <!--PhraseTopic 能夠提升識別率,內部屬性Subject可指定該關鍵字類型,好比 城市名 姓名  地址 等類型-->
17 <PhraseTopic Label="City" Scenario="Natural Language">
18   <Subject>City/State</Subject>
19 </PhraseTopic>
20 <PhraseTopic Label="From" Scenario="Natural Language">
21   <Subject>City/State</Subject>
22 </PhraseTopic>
23 <PhraseTopic Label="To" Scenario="Natural Language">
24   <Subject>City/State</Subject>
25 </PhraseTopic>
26 <PhraseTopic Label="DateTime" Scenario="Natural Language">
27   <Subject>Date/Time</Subject>
28 </PhraseTopic>

上面的Command節點中,使用了VoiceCommandService元素來標註該語音指令是要啓動後臺任務服務,然後臺任務服務名稱爲XiaoMiService。

註冊VCD文件

註冊vcd文件上篇文章一毛同樣:

1 /// <summary>
2 /// 註冊語音指令
3 /// </summary>
4 private async Task InsertVoiceCommands()
5 {
6     await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(
7         await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///VoiceCommandsFile.xml")));
8 }

Ok,打開一次App完成VCD語音指令的註冊,而後盡情的使用Cortana吧:

 

推薦一個UWP開發羣:53078485 你們能夠進來一塊兒學習

相關文章
相關標籤/搜索