• Win10/UWP开发—使用Cortana语音与App后台Service交互


    上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比调用前台的App,调用后台任务有个有点就是App不用被启动即可为用户提供服务。

    要想使用Cortana调用App后台任务,首先我们需要定义VCD文件,我们依旧使用上篇中的代码,让它支持Cortana调用后台任务。

    创建后台任务

    新增一个[Windows运行时组件]项目,暂时起名叫做:XiaoMiBackgroundTask

    创建一个类,暂且叫做XiaoMiTask,并继承IBackgroundTask

    完成如下代码:

    //------------------------------------------------------
    //
    // 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);
            }
        }
    }

    代码意思就不解释了,写的一手详细的注释不是吗?

    回到我们的主程序中,在引用里添加该后台应用服务的引用。

    注册App后台服务

    打开Package.appxmanifest文件,切换到"声明"选项卡,添加一个应用服务的声明,名称随便填,一会VCD文件里要用到这个名字,这里填写XiaoMiService,别以为是小米的意思哈,哥是米黑,是小秘。入口点填写上面创建的后台服务的"命名空间.类名",截图如下:

    编写VCD文件

    在vcd语音指令中添加两个新的Command节点,以及定义需要的PhraseTopic,对VCD文件不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互

    添加的代码如下:

     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 大家可以进来一起学习

  • 相关阅读:
    MySql的性能优化
    MySql的备份还原
    MySql的数据目录
    MySql的事务
    MySql的视图
    算法笔记_006:全源最短路径问题【动态规划法】
    算法笔记_005:堆排序问题【变治法】
    算法笔记_004:8枚硬币问题【减治法】
    算法笔记_003:矩阵相乘问题【分治法】
    使用MongoDB和JSP实现一个简单的购物车系统
  • 原文地址:https://www.cnblogs.com/Aran-Wang/p/4816338.html
Copyright © 2020-2023  润新知