# 离线命令词
# 概览
启动AIUI的离线命令词功能,常用语音指令可以完全在本地进行识别,可以减少响应时间,提高交互体验和减少云端交互。
AIUI在没有离线识别的情况下,对例如上一首,下一首,暂停播放这些音乐控制命令,都会将音频上传到AIUI云端,云端在处理后将听写和语义的结果再下发到客户端。
AIUI开启离线命令词识别功能后,会在音频送到AIUI云端的同时送到本地的离线识别引擎进行识别。
# 使用步骤
# 接入使用
# 添加配置
aiui.cfg
中增加离线命令词相关配置:
"speech":{
"intent_engine_type":"mixed"
},
"esr":{
"engine_type": "wfst_fsa",
"pgs_enable": "1",
"res_type":"assets",
"res_path":"esr/common.jet",
"preloads": [
{
"id": 0,
"res_type": "assets",
"res_path": "esr/contact.jet"
}
]
},
# 配置文件说明
intent_engine_mode
控制音频到语义结果的解析方式,取值有:
cloud
纯云端解析,全部使用云端语义和听写功能,只返回在线结果
local
纯离线命令词解析,只使用本地的离线命令词功能,只返回离线结果
mixed
云端本地同时解析,返回最快的有效结果
pipe
本地优先解析,如果有效即返回如果无效请求在线语义返回结果
esr['res_path']
配置离线命令词模型通用资源。
esr['engine_type']
控制离线结果的输出类型,取值有:
wfst
离线听写模式wfst_fsa
离线听写+离线命令词匹配模式fsa
离线命令词匹配模式
esr['pgs_enable']
控制离线听写模式开启时是否有流式听写结果返回,取值有:
1 开启
0 关闭
esr['preloads']
配置初始化时默认编译加载的离线语法资源,可以配置多条预加载的资源。在每一条配置中需要声明编译加载语法的ID和语法文件路径。语法ID的意义可以参考语法动态编译更新
时语法ID的含义。
如上配置之后,SDK在识别时就会按照配置的离线语法进行离线命令词识别,并通过EVENT_RESULT
返回离线结果,结果数据示例请参见离线结果
一节的说明。
# 编写语法文件
离线命令语法是使用 FSA 描述的语法。示例离线语法如下:
#FSA 1.0;
0 1 <action>
1 2 <contact>
2 3 -
2 3 <phoneType>
;
<action>:拨打|呼叫|打电话给;
<contact>:张三|李四;
<phoneType>:移动号码|家庭号码|单位号码;
格式说明:
- 以#开头的行表示注释行;
- 以<开头表示slot槽定义,冒号后面是slot的值定义。slot的即可以在语法文件中定义,也可以通过下面章节介绍的方式进行更新;
- 以数字开头行表示句式网络定义,上面示例语法网络定义可视化表示如下:
只要识别的内容能命中定义的网络,SDK就会返回离线命令词结果。比如说法打电话给张三
会命中0 -> 1(action)和1 -> 2(contact)句式网络定义,那就返回如下离线命令词结果:
{
"ws": [
{
"slot": "action",
"w": "打电话给"
},
{
"slot": "contact",
"w": "张三"
},
{
"slot": "",
"w": "。"
}
]
}
# 结果解析
根据配置文件中esr的engine_type
配置,离线解析时会返回离线流式听写、离线听写,离线命令词结果这几类结果类型的组合。离线流式听写和离线听写结果可以用作识别时的识别过程显示,离线命令词结果中包含识别命中离线语法定义的句式结果,所以可以用作解析交互的意图。例如engine_type
是wfst_fsa
且pgs_enable
处于开启状态,那一次交互会返回多次离线流式识别结果 + 一次离线识别结果 + 一次离线命令词结果。
# 离线流式结果(esr_pgs)
info
{ "data": [ { "params": { "sub": "esr_pgs" }, "content": [ { "dte": "utf8", "dtf": "json", "cnt_id": "0" } ] } ] }
result
{ "text": { "content": "点一" } }
# 离线听写结果(esr_iat)
info
{ "data": [ { "params": { "sub": "esr_iat" }, "content": [ { "dte": "utf8", "dtf": "json", "cnt_id": "0" } ] } ] }
result
{ "text": { "bg": "-1", "ed": "-1", "sc": "26982", "ws": [ { "boundary": "68", "pinyin": "xia4", "sc": "0", "slot": "", "w": "下" }, { "boundary": "76", "pinyin": "yi1", "sc": "0", "slot": "", "w": "一" }, { "boundary": "116", "pinyin": "ye4", "sc": "0", "slot": "", "w": "页" }, { "sc": "0", "slot": null, "w": "。" } ] } }
# 离线命令词结果(esr_fsa)
info
{ "data": [ { "params": { "sub": "esr_fsa" }, "content": [ { "dte": "utf8", "dtf": "json", "cnt_id": "0" } ] } ] }
result
{ "bg": "-1", "ed": "-1", "sc": "30267", "ws": [ { "boundary": "92", "pinyin": "dian3yi1shou3", "sc": "0", "slot": "play", "w": "点一首" }, { "boundary": "144", "pinyin": "liu2de2hua2", "sc": "0", "slot": "singer", "w": "刘德华" }, { "boundary": "156", "pinyin": "de4", "sc": "0", "slot": "de", "w": "的" }, { "boundary": "200", "pinyin": "ge1", "sc": "0", "slot": "musicSuf", "w": "歌" }, { "sc": "0", "slot": null, "w": "。" } ] }
# 进阶使用
# 默认语法槽更新
我们可以通过配置文件中esr
下的preloads
指明初始化时需要加载使用的离线命令词语法,同时离线语法文件中的槽也是可以更新的,如上面contact
的slot,我需要更新成我们设备上对应的联系人,那我们可以在配置中为preloads
资源增加如下的配置:
"esr":{
"engine_type": "wfst_fsa",
"pgs_enable": "1",
"res_type":"assets",
"res_path":"esr/common.jet",
"preloads": [
{
"id": 0,
"res_type": "assets",
"res_path": "esr/contact.jet",
"update_slots": [
{
"slot": "contact",
"res_type": "assets",
"res_path": "esr/contact_update.jet"
}
]
},
]
}
contact_update.jet
中内容是|
分割扩展联系人列表,示例内容如下:
王二|张海洋
如上的配置加载完成后,我们直接说打电话给张海洋
就可以如上面一样返回命中的esr_fsa
结果
# 语法动态编译更新
除了通过上面的静态的配置文件指明需要更新扩展的槽。我们还可以通过下面介绍的命令在程序运行时动态更新槽内容,以下操作都需要在AIUI SDK的working
状态下运行。
# 离线语法编译
String grammarContent = FucUtil.readAssetsFile(this, "esr/contact.jet","utf-8");
AIUIMessage buildMessage = new AIUIMessage(AIUIConstant.CMD_BUILD_GRAMMAR, 1, 0, grammarContent, null);
arg1
字段指明编译语法的ID,后面更新语法槽时通过指定相同的语法ID来更新这个语法文件中槽;
arg2
字段指明是否禁用语法编译自动加载下次识别生效,取值如下:
- 1 只编译语法,编译完成后不自动加载生效(可以通过后面的
CMD_LOAD_GRAMMAR
手动加载编译好的语法) - 0 编译语法后自动加载生效
params
字段指明编译的语法内容。
编译结果及下面操作都会通过EVENT_CMD_RETURN
返回,示例处理如下:
//AIUI事件监听器
private AIUIListener mAIUIListener = new AIUIListener() {
@Override
public void onEvent(AIUIEvent event) {
switch (event.eventType) {
/**
* arg1 表示操作的CMD
* arg2 表示操作成功(0)失败(错误码)
* info 结果信息
*/
case AIUIConstant.EVENT_CMD_RETURN: {
switch (event.arg1) {
case AIUIConstant.CMD_BUILD_GRAMMAR:
case AIUIConstant.CMD_UPDATE_LOCAL_LEXICON: {
Log.d(TAG, "arg1 " + event.arg1 + " ret " + event.arg2 + " info " + event.info);
}
}
}
break;
default:
break;
}
}
};
# 离线语法槽更新
String updateContent = String.format("{\"name\": \"%s\", \"content\": \"%s\"}", "contact", "黄莺莺|窦唯|鲍家街四十三号");
AIUIMessage updateMessage = new AIUIMessage(AIUIConstant.CMD_UPDATE_LOCAL_LEXICON, 1, 0, updateContent,null);
arg1
字段指明槽更新目标的语法ID,语法ID和语法内容的对应在CMD_BUILD_GRAMMAR
时建立。
arg2
字段指明槽更新内容模式是否为追加,取值如下:
0 替换(replace)模式,更新的内容会替换当前槽内容;
1 追加(append)模式,更新的内容会追加到当前槽内容的后面。
params
字段指明槽更新的内容。
# 离线语法加载
AIUIMessage loadMessage = new AIUIMessage(AIUIConstant.CMD_LOAD_GRAMMAR, 1, 0, "", null);
arg1
字段指明需要加载的语法ID,语法ID需要之前通过CMD_BUILD_GRAMMAR
完成编译。
# 离线语法卸载
AIUIMessage loadMessage = new AIUIMessage(AIUIConstant.CMD_UNLOAD_GRAMMAR, 1, 0, "", null);
arg1
字段指明需要卸载的语法ID,语法ID需要之前通过CMD_BUILD_GRAMMAR
或CMD_LOAD_GRAMMAR
完成对应语法的加载。