灵云SDK开发手册(C API)  5.2
 全部 结构体 函数 变量 类型定义 枚举 枚举值  
ASR能力

以下描述了如何使用灵云ASR能力。

1. ASR简介

ASR(Automatic Speech Recognition) 语音识别技术,其目标是将输入的语音信号转换为相应的文本或命令。

语音识别分为语法识别和自由说识别。

  1. 语法识别:开发者需要提供语法文件,系统在指定的语法范围进行识别。这种识别计算资源消耗少,识别率较高 但是要求用户的说话必须符合指定的语法。有限命令词汇的识别我们也归为语法识别, 因为可以将这些命令词的集合看做是一种特殊的语法。这种识别常用于命令操作、简单的意图控制等。

  2. 自由说:不限定用户说话的范围、方式和内容。自由说识别常常需要较大的语言模型作为支撑, 因此消耗计算资源较大。但这种识别可以用于诸如输入短信、输入微博、或者比较随意的对话系统等。 针对某些特定领域,也可以采用针对这一领域的语言模型作为支撑,因此对于说话集中在这个领域的内容会获得更好的识别率。 例如可以针对歌曲歌手的名称专门建立“音乐”领域的自由说模型。

2. 选择模块和能力

按照环境准备 进行模块选择。此外,在Android平台下,提供了 armeabi 和 armeabi-v7a 两个版本的标准模块。如果能确认用户设备是armv7a以上CPU, 则可以使用armeabi-v7a中的hci_asr_local_recog.so,这样识别速度更快。

3. 语法识别

3.1 语法文件类型

目前支持的语法类型有jsgf,wordlist,wfst JSGF(Java Speech Grammar Format,国际标准的语法格式),其格式的具体规范请参见:http://www.w3.org/TR/jsgf/。 JSGF语法示例:

#JSGF V1.0;
grammar call;
public <call> = 打电话给 <contactname> ;
<contactname> = ( 张三 | 李四 | 王五 | 赵六 );

wordlist词条语法比较简单,示例:

播放
暂停
停止
打开
下一首
上一首

wfst格式参考 3.4 本地语法加载

在配置串中指定grammarType=wordlist或jsgf或wfst, 直接将词表传给hci_asr_recog()函数,灵云SDK即可在指定的词表范围内进行识别。 如果语法是一个文件,可以读入内存中识别函数,也可以直接在配置中指定isFile=yes,则可以将文件名传入。

char * pszRecogConfig = "audioFormat=pcm16k16bit,encode=none,grammarType=wordlist,isFile=yes";
ASR_RECOG_RESULT asrResult;
errCode = hci_asr_recog(nSessionId, pBuff, nLen, pszRecogConfig, "wordlist.txt", &asrResult);

3.2 语法权重


语法识别支持权重设置,权重可以是任意浮点数,后面不带数字,缺省为1

wordlist文件权重示例:

四川长虹 /2/
山西电力 /0.5/

Jsgf 语法文件权重示例:

<size> = /10/ small | /2/ medium | /1/ large;
<color> = /0.5/ red | /0.1/ navy blue | /0.2/ sea green;
<action> = please (/20/save files |/1/delete all files);
<place> = /20/ <city> | /5/ <country>;

3.3 语法ID识别

除了指定语法内容外,还可以通过直接指定语法ID的方式进行识别:

char * pszRecogConfig = "audioFormat=pcm16k16bit,encode=none,grammarType=id,grammarId=10";
ASR_RECOG_RESULT asrResult;
// pBuff是16K 16bit PCM音频数据的缓冲区指针,nLen是其字节数
errCode = hci_asr_recog(nSessionId, pBuff, nLen, pszRecogConfig, NULL, &asrResult);

在配置串中指定grammarType=id, 并指定具体的grammarId, 灵云SDK即按照ID所指定的语法进行识别。 具体的grammarId有两种可能:

  1. 如果是云端语法识别,需要开发者通过开发者社区自行上传语法文件,并获得可以使用的ID。详情请咨询捷通华声。

  2. 如果是本地语法识别,需要事先通过 hci_asr_load_grammar() 加载语法,得到语法id,再进行使用。参见 3.4 本地语法加载

3.4 本地语法加载

在本地识别情况下,由于装载语法需要一定的编译时间,因此如果是事先能够确定的语法文件, 最好通过 hci_asr_load_grammar() 事先加载,然后一直通过其返回的id使用,加载语法数量上限为256。示例如下:

// 必须是utf-8编码, 有些平台下可能需要转码
char * pszWordList = "播放\r\n暂停\r\n停止\r\n打开\r\n下一首\r\n上一首\r\n";
// 装载语法
errCode = hci_asr_load_grammar("grammarType=wordlist", pszWordList, &nGrammarId);
// 识别
char szRecogConfig[1000];
sprintf(szRecogConfig, "audioFormat=pcm16k16bit,encode=none,grammarType=id,grammarId=%d", nGrammarId);
errCode = hci_asr_recog(nSessionId, pBuff, nLen, szRecogConfig, NULL, &asrResult);
// 可以使用此id进行多次识别
// 不再使用此id时,进行卸载

如果直接将语法传入 hci_asr_recog() ,实际上系统会每次都去进行编译,每次识别完成后再卸载语法, 因此会影响识别的速度。只有在每次的语法都是临时生成的情况下,例如每次是在某个歌手的歌名列表中选择, 事先不能确定,而且每次都有可能不一样,此时可以采用直接传语法,一步调用 hci_asr_recog() 的方式。

另外在使用 hci_asr_load_grammar() 加载语法后,可以使用 hci_asr_save_compiled_grammar() 对已加载的 语法文件进行保存。保存后的语法文件可以使用wfst类型的方式进行载入,对于大的语法文件可以大大提高语法 加载速度。

4. 自由说识别

使用语法识别时,启动Session时,需要指定本地自由说识别能力(asr.local.freetalk)或云端自由说识别能力(asr.cloud.freetalk)。

自由说的示例如下:

char * pszRecogConfig = "audioFormat=pcm16k16bit,encode=opus";
ASR_RECOG_RESULT asrResult;
errCode = hci_asr_recog(nSessionId, pBuff, nLen, pszRecogConfig, NULL, &asrResult);

5. 意图识别

使用意图识别时,需要在启动Session时,指定云端意图识别能力 (asr.cloud.dialog)或本地意图识别能力(asr.local.dialog) 意图识别即在完成识别工作后进行意图获取和意图内容获取。 意图识别的示例如下:

//云端意图识别,必须传入intention
char * pszRecogConfig = "intention=weather,needContent=yes";
ASR_RECOG_RESULT asrResult;
errCode = hci_asr_recog(nSessionId, pBuff, nLen, pszRecogConfig, NULL, &asrResult);

可以看到,意图识别只要Session启动时指定相应能力即可,在调用 hci_asr_recog() 时 无需在配置项中指定 grammarType和grammarId,也无需传入grammarData参数。

本地意图识别可在hci_asr_session_start处指定dialogMode,默认是freetalk,也可指定为grammar,可以选择在语音识别阶段使用哪种能力

本地意图识别的示例如下:

// 启动 ASR Session
int nSessionId = -1;
string strSessionConfig = "capkey=" + cap_key;
strSessionConfig += "," + recog_config;
err_code = hci_asr_session_start( strSessionConfig.c_str(), &nSessionId );
// 识别
ASR_RECOG_RESULT asrResult;
err_code = hci_asr_recog( nSessionId, voiceData.buff_, voiceData.buff_len_, NULL, NULL, &asrResult );

6. 实时识别

本地语法识别与云端自由说识别支持实时识别模式。在实时识别模式下,调用 hci_asr_recog() 函数并不将传入的pvVoiceData当成所有的识别数据进行一次完整的识别,用户可以将音频数据分多次调用 hci_asr_recog()。 SDK内部会同时进行端点检测,检测到语音起点后会随时将数据传给引擎,因此可以在边录音的时候边进行引擎的识别工作, 在最后检测到末端时再返回最终的识别结果,这样能有更快的响应速度。

实时识别的示例如下:

char * pszSessionConfig = "capKey=asr.local.grammar.v4,realtime=yes";
int nSessionId;
errCode = hci_asr_session_start(pszSessionConfig, &nSessionId);
char * pszRecogConfig = "audioFormat=pcm16k16bit,encode=none,grammarType=id,grammarId=10";
while (true)
{
// 每次得到的数据放在 pBuf中,长度为 nLen
...
ASR_RECOG_RESULT asrResult;
errCode = hci_asr_recog(nSessionId, pBuf, nLen, pszRecogConfig, NULL, &asrResult);
if (errCode == HCI_ERR_ASR_REALTIME_END)
{
// 正常检测到端点
//传入NULL和0,获取识别结果,退出循环
errCode = hci_asr_recog(nSessionId, NULL , 0 ,pszRecogConfig, NULL, &asrResult);
break;
}
else if (errCode == HCI_ERR_ASR_REALTIME_WAITING)
{
// 等待数据,继续循环
continue;
}
else
{
// 其它错误,一般不会出现,出现很可能是由于输入数据无效,或实时识别过程错误。
// 如果实时识别过程错误,则自动取消该次实时识别
// 否则可以手动终止本次实时识别, 然后退出循环
// 也可以继续循环,则下次hci_asr_recog()发送的数据会作为前次数据的延续
break;
}
}

在实时识别模式下,首先要在启动会话时配置 realtime=yes。然后调用 hci_asr_recog() 开启一次新的识别, 识别过程处于端点检测过程中返回HCI_ERR_ASR_REALTIME_WAITNG。如果音频传入过程中端点检测过程结束(没有音频输入,缓冲区满, 检测到末端)结束,则会返回 HCI_ERR_ASR_REALTIME_END, 需要用户继续调用该接口且传入参数中 pvVoiceData传入NULL或者uiVoiceDataLen为0,此时SDK将识别结果填写在psAsrRecogResult中,返回HCI_ERR_NONE。

如果在一次实时识别过程中,pvVoiceData传入NULL或者uiVoiceDataLen为0表示强制停止此次实时识别, 此时也会填充识别结果到psAsrRecogResult中并且返回HCI_ERR_NONE。

调用 hci_asr_recog() ,返回如下错误码则表示实时识别过程出错: HCI_ERR_DATA_SIZE_TOO_LARGE(20: 传入的数据量超过可处理的上限,单次识别音频数据经过端点检测处理后的大小超过320K), HCI_ERR_ASR_ENGINE_FAILED(209: 本地引擎识别失败), HCI_ERR_SERVICE_CONNECT_FAILED(8: 连接服务器失败,服务器无响应), HCI_ERR_SERVICE_TIMEOUT(9: 服务器访问超时), HCI_ERR_SERVICE_DATA_INVALID(10: 服务器返回的数据格式不正确), HCI_ERR_SERVICE_RESPONSE_FAILED(11: 服务器返回操作失败),此时SDK将取消该次实时识别, 如果用户继续调用该接口传输数据则自动开启一次新的实时识别。 其他情况,如果返回非 HCI_ERR_ASR_REALTIME_WATING 并且非 HCI_ERR_ASR_REALTIME_END 的结果时, 该次调用发送的数据不会被使用,实时识别任务不取消,下次再调用 hci_asr_recog() 发送的数据作为 前一次发送的延续。 实时识别只使用每次新开启时的pszConfig和pszGrammarData数据,在实时识别过程中再传入的pszConfig和pszGrammarData 总是会被忽略。

7. 实时反馈


云端自由说支持实时反馈识别,实时反馈即在实时识别基础上并不只在最后一次获取结果时反馈识别结果,在中间 返回过程中也会返回识别结果,此时需要开发者根据结果结构体中字段进行判断,如果uiResultItemCount > 0则存 反馈结果。实时反馈结果不同于实时识别结果,实时反馈结果会根据分段(参考vadSeg配置字段)返回结果。结果为JSON格式,示例如下:

识别完成结果示例:

{
"SegmentCount": 1,
"Segment": [{
"SegmentIndex": 1,
"Text": "今天天气怎么样",
"Score": 3300,
"StartTime": 260,
"EndTime": 3080
}]
}

获取到识别结果后,需要根据SegmentIndex分段序号来进行分段结果显示,分段序号从1开始,SegmentIndex改变或已经获取到下一个分段则表明前一个分段结果已经完整。

8. 双路识别

如果需要使用双路识别功能,只需要在sessionstart的配置中,用"#"隔开,并写入第二路的参数即可,识别的调用方法和单路识别一致。 双路识别的例子如下:

string strSessionConfig = "realtime=yes,capkey=asr.local.grammar.v4";
strSessionConfig += "#realtime=yes,capkey=asr.cloud.freetalk";
errCode = hci_asr_session_start( strSessionConfig.c_str(), &nSessionId );
//recog
...