# 概览

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在纯离线模式下,功能很受限。如果需要使用离线命令的话,推荐使用混合模式,提高常见命令短语的识别速度,提升体验。

离线命令词的功能会比线上识别要弱一点,所以可能存在说法在离线命令词没有识别结果,在云端听写会正确听写结果。 如果在云端没有配置对应的语义,本次结果就会拒识。所以混合模式下,在本地定义离线命令语法的同时在云端说法也有对应的语义,这样会减少拒识的情况,提升体验。