# 概览
AIUI的离线命令词识别可以提高常见命令词的识别速度,提升体验效果。
AIUI在没有离线识别的情况下,对例如上一首,下一首,暂停播放这些音乐控制命令,都会将音频上传到AIUI云端,云端在处理后将听写和语义的结果再下发到客户端。
AIUI开启离线命令词识别功能后,会在音频送到AIUI云端的同时送到本地的离线识别引擎进行识别。
# 感性认识
离线功能的核心是编写的离线命令词语法。先举个例子,感性的认识一下
#BNF+IAT 1.0 UTF-8;
!grammar main;
!slot <sleep>;
!start <sleep>;
<sleep>:你去睡觉吧!id(2001)|你去休息吧!id(2001)|睡觉去吧!id(2001)
当如上的离线语法构建启用后,你在说‘你去睡觉吧’,‘你去休息吧,‘睡觉去吧’中任何一句后,离线引擎都会识别成功返回对应项的信息结果给你(返回结果在下文中有示例)。
离线命令词并不会返回听写或者语义的结果,它是把音频与编写的离线语法中的规则做匹配,返回离线语法中对应匹配项的信息。
# 使用步骤
# 下载SDK
登录讯飞开放平台 (opens new window),进入控制台 (opens new window),选择您要添加离线命令词功能的应用,点击SDK下载,添加离线命令词识别功能后,下载离线命令词SDK;
# 导入SDK
打开SDK包,进入res/asr/目录,将里面的common.jet放入工程src/main/assets/asr/下,进入libs目录将Msc.jar放入工程libs/下,libmsc.so放入工程src/main/jniLibs/armeabi下;
# 添加配置
将配置文件中intent_engine_type设为local
或者mixed
模式,同时添加asr
配置。
① 云端模式:
"speech":{
"intent_engine_type":"cloud"
}
AIUI的默认模式,不开启离线功能,全部使用云端语义和听写功能。
② 本地模式:
"speech":{
"intent_engine_type":"local"
}
AIUI完全离线,只使用本地的离线命令词功能。 在此模式下AIUI功能非常受限,只能完成简单命令词的识别。
③ 混合模式:
"speech":{
"intent_engine_type":"mixed"
}
混合模式下,音频会同时送到本地离线引擎和云端解析。 结果选择策略是哪个先返回有效结果,就采用哪个。
asr配置示例如下:
// 离线语法识别参数
"asr":{
"threshold":"50",
"res_type":"assets",
"res_path":"asr/common.jet"
}
# 编写语法文件
离线命令语法是使用巴科斯范式(BNF)描述语音识别的语法。语法文件包括HEADER和BODY。
!grammar main;
!slot <sleep>;
!start <sleep>;
<sleep>:你去睡觉吧!id(2001)|你去休息吧!id(2001)|睡觉去吧!id(2001)
语法编写的具体文档可以参考讯飞云平台上识别语法分享–在线语法和离线语法编写指南 (opens new window)。
# 构建离线语法
编写好语法文件后,可将其放入assets目录下,在构建语法时,从文件中读取语法字符串,再传入AIUIMessage中,使用CMD_BUILD_GRAMMAR
命令构建语法,构建示例如下:
AIUIMessage buildGrammar = new AIUIMessage(AIUIConstant.CMD_BUILD_GRAMMAR,
0, 0, grammar_str, null); //grammar_str为编写的离线语法字符串
mAIUIAgent.sendMessage(buildGrammar);
每次调用命令构建的语法都会覆盖先前对应的GrammerID的离线语法。
该命令通过EVENT_CMD_RETURN事件返回执行结果,事件中的的arg1表示对应于哪条命令,arg2参数可以判断结果,为0表示成功,结果解析Linux版本示例如下,其他版本请以此为参考:
case AIUIConstant::EVENT_CMD_RETURN:
{
//cout << "onEvent --> EVENT_CMD_RETURN: arg1 is " << event.getArg1() << endl;
...
if (AIUIConstant::CMD_BUILD_GRAMMAR == event.getArg1()) {
if (event.getArg2() == 0)
{
cout << "build grammar success." << endl;
}
else
{
cout << "build grammar error, errcode = " << event.getArg2() << endl;
cout << "error reason is " << event.getInfo() << endl;
}
}
...
} break;
构建成功后,即可交互使用离线命令词功能了。
构建使用离线语法中的错误码参考AIUI错误码。
# 离线语法槽更新
在离线语法中有槽的定义(具体定义可以参考上面提到的语法文档),主要作用就是在语法构建生效后,可以动态更新当前生效的语法中的部分内容。
定义了一个打电话的离线语法
!slot contact
!start <call>
<call>:打电话给<contact>
<contact>:张三|李四
已经通过AIUI构建了语法,并且使用了。假如当前通讯录有新联系人添加,那我们也要更新离线语法中(slot)槽contact的内容:
{
"name": "contact", //槽名称
"content":"张三\n李四\n王二\n" //词表内容
}
使用命令CMD_UPDATE_LOCAL_LEXICON(17),将params设置为上面的json,发送给AIUI即可,示例代码如下:
JSONObject paramJson = new JSONObject();
paramJson.put("name", "contact");
paramJson.put("content", "张三\n李四\n王二\n");
AIUIMessage updateMessage = new AIUIMessage(AIUIConstant.CMD_UPDATE_LOCAL_LEXICON,
0, 0, paramJson.toString(), null);
mAIUIAgent.sendMessage(updateMessage);
该命令也是通过EVENT_CMD_RETURN事件返回执行结果,结果解析Linux版本示例如下,其他版本请以此为参考:
case AIUIConstant::EVENT_CMD_RETURN:
{
//cout << "onEvent --> EVENT_CMD_RETURN: arg1 is " << event.getArg1() << endl;
...
if (AIUIConstant::CMD_UPDATE_LOCAL_LEXICON == event.getArg1()) {
if (event.getArg2() == 0)
{
cout << "update lexicon success" << endl;
}
else
{
cout << "update lexicon error, errcode = " << event.getArg2() << endl;
cout << "error reason is " << event.getInfo() << endl;
}
}
...
} break;
SDK或者串口的具体使用方式可以参考上面构建语法时的操作。
# 结果解析
通过解析结果params下的sub字段,判断结果属于哪种类型,离线命令词识别结果sub字段为asr
。
离线命令识别结果(asr)举例如下:
"result": {
"sid": "",
"intent": {
"ws": [{
"slot": "<sleep>",
"cw": [{
"w": "你去睡觉吧",
"id": 2001,
"sc": 54
}]
}],
"rc": 0
}
},
"info": {
"data": [{
"params": {
"sub": "asr"
}
}]
}
主要解析intent中ws下的字段,根据先前编写的离线语法文件,很容易理解代表的字段。
id的字段跟语法中声明的对应,id的声明方法参考上面提到的语法文档。
# 注意事项
# 离线命令识别与线上语义结合
AIUI在纯离线模式下,功能很受限。如果需要使用离线命令的话,推荐使用混合模式,提高常见命令短语的识别速度,提升体验。
离线命令词的功能会比线上识别要弱一点,所以可能存在说法在离线命令词没有识别结果,在云端听写会正确听写结果。 如果在云端没有配置对应的语义,本次结果就会拒识。所以混合模式下,在本地定义离线命令语法的同时在云端说法也有对应的语义,这样会减少拒识的情况,提升体验。