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

Cle****-he UID.1073626
2015-09-22 发表

本帖最后由 Clever-he 于 2015-9-22 09:50 编辑

上篇文章中介绍了(53078485群)大咖Aran的博客:***链接停止解析***;而这篇博客我们将接着上篇文章的内容为大家带来大咖Aran的讲解:讲讲如何使用Cortana调用App的后台任务。

相比Cortana语音调用前台的App,调用后台任务有个优点就是App不用被启动即可为用户提供服务。

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


创建后台任务

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

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

完成如下代码:
[mw_shl_code=csharp,true]//------------------------------------------------------
//
// 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);
}
}
}[/mw_shl_code]

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

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



注册App后台服务

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


编写VCD文件

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

添加的代码如下:
[mw_shl_code=csharp,true]<Command Name="QueryTrain">
<Example> 查询去某地的火车 </Example>
<ListenFor >查询{DateTime}从{From}到{To}的火车</ListenFor>
<Feedback> 正在查询{DateTime}从{From}到{To}的火车 </Feedback>
<VoiceCommandService Target="XiaoMiService"/>
</Command>


<Command Name="CancelTrain">
<Example> 取消去某地的火车 </Example>
<ListenFor >取消去{City}的火车</ListenFor>
<Feedback> 正取消去{City}的火车 </Feedback>
<VoiceCommandService Target="XiaoMiService"/>
</Command>

<!--PhraseTopic 可以提高识别率,内部属性Subject可指定该关键字类型,比如 城市名 姓名 地址 等类型-->
<PhraseTopic Label="City" Scenario="Natural Language">
<Subject>City/State</Subject>
</PhraseTopic>
<PhraseTopic Label="From" Scenario="Natural Language">
<Subject>City/State</Subject>
</PhraseTopic>
<PhraseTopic Label="To" Scenario="Natural Language">
<Subject>City/State</Subject>
</PhraseTopic>
<PhraseTopic Label="DateTime" Scenario="Natural Language">
<Subject>Date/Time</Subject>
</PhraseTopic>[/mw_shl_code]

上面的Command节点中,使用了VoiceCommandService元素来标注该语音指令是要启动后台任务服务,而后台任务服务名称为XiaoMiService。


注册VCD文件

注册vcd文件上篇文章一毛一样:
[mw_shl_code=csharp,true]/// <summary>
/// 注册语音指令
/// </summary>
private async Task InsertVoiceCommands()
{
await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(
await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///VoiceCommandsFile.xml")));
}[/mw_shl_code]

Ok,打开一次App完成VCD语音指令的注册,然后尽情的使用Cortana吧:Ok,打开一次App完成VCD语音指令的注册,然后尽情的使用Cortana吧:
***图片停止解析***


推荐一个UWP开发群:53078485 大家可以进来一起学习

敬告:
为防止不可控的内容风险,本站已关闭新用户注册,新贴的发表及评论;
你现在看到的内容只是互联网用户曾经发表的言论快照,仅用于老用户留存纪念,且仅与科技行业相关,全部内容不代表本站观点及立场;
本站重新开放前已针对包括用户隐私、版权保护、信息安全、国家政策在内的各种互联网法律法规要求,执行了隐患内容的自查、屏蔽和删除;
本站目前所属个人主体,未有任何盈利安排与计划,且与原WFUN.COM所属公司不存在任何关联关系;
如果本帖内容或者相关资源侵犯到您的合法权益,或者您认为存在问题,那么请您务必点此举报或投诉!
全部回复:
surgs UID.729361
2015-09-22 回复

哈撒,这难道就是代码?这么叼!

surgs UID.729361
2015-09-22 回复

哈撒,这难道就是代码?这么叼!作为用户,真心佩服开发者。

fanx****zeng UID.551053
2015-09-22 回复

技术贴,支持一下

zqc7****1701 UID.1157936
2015-09-22 使用 Lumia 930 回复

虽然看不懂,但是还是要顶一下

tmp00000 UID.995403
2015-09-22 回复

不错,有参考价值

vbfool UID.352791
2015-09-22 回复

今天闲的无聊,用这个功能写了个小娜调用豆瓣搜书的小程序,准备到时候把功能再添加一些。

bi****gi UID.1180610
2015-09-28 回复

内容已屏蔽

本站使用Golang构建,点击此处申请开源鄂ICP备18029942号-4联系站长投诉/举报