密级公开
版本10D.2

AICP ASR WebSocket开发手册

1. 概述#

1.1 功能介绍#

ASR 语音识别的Websocket接口, 主要用于实时流式语音识别。音频通过接口进行分片实时传输,服务器端在收到语音就开始进行识别,并可以自动进行断句,返回每句的最终识别结果,也可以在识别过程中即时返回中间临时识别结果。此接口主要适用于IVR电话交互、实时会议转写等场景,也可以用于输入法等实时短语音的场景。

1.2 模型特征串#

AICP-10 提供的 ASR 能力接口中,模型特征串形式为:{lang}_{samplerate}_{domain}{lang}表示语言编码,{samplarate} 可以是 8K 或者16K,表示识别模型的训练时所用的采样率, {domain}表示领域编码。

模型特征串的概念和语言编码,请参见 《AICP 10 开发通用规范》

领域是针对识别任务的一种性能优化手段。不同领域的模型,可以对这种领域里的常见词汇、常见说话方式等进行针对性优化,就有可能得到更准确的结果。

目前常见的模型特征串如下:

模型特征串实际应用
cn_16k_common手机输入法,实体机器人交互,APP导航
cn_16k_huiyi会议实时转写,录音笔离线音频转写
cn_8k_common电话导航,电话外呼
cn_8k_zhijian电话语音质检分析

1.3 访问认证#

访问接口所需的认证机制,请参见 《AICP 10 开发通用规范》

2. 接口功能描述#

WebSocket接口,支持三种不同的流式请求方式,将分别通过不同的接口来提供。

2.1 流式一句话识别#

流式一句话识别的接口支持用户将一整段语音分段,以流式输入,最后得到识别结果。语音识别引擎在获得分段的输入语音的同时,就可以同步地对这段数据进行特征提取和解码工作,而不用等到所有数据都获得后再开始工作。因此这样就可以在最后一段语音结束后,仅延迟很短的时间(也即等待处理最后一段语音数据以及获取最终结果的时间)即可返回最终识别结果。这种流式输入方式能缩短整体上获得最终结果的时间,极大地提升用户体验。

这种方式不做静音检测(VAD),因此也不会根据静音检测结果进行断句,无法给出语音开始和结束的事件。因此,也称为不分句模式。

通常,这种模式用于较短的一句话识别,例如可以用于手机输入法、智能家居语音交互等场景。

主要交互流程如下:

客户端客户端接口服务接口服务启动和确认请求【开始识别】+配置响应【识别启动】发送和识别音频流分片音频流分片结果响应【中间结果】音频流分片结果响应【中间结果】音频流分片停止和完成请求【结束识别】结果响应【剩余未返回的最终结果】响应【识别结束】

会话停止条件:

  • 用户主动结束
  • 音频长度超过最大长度限制

2.2 流式实时转写(连续模式)#

流式实时转写连续模式的接口,通常是针对长语音的,并且引入了语音的端点检测功能。语音数据也是分段输入,但是连续识别模式将会在处理数据之前进行端点检测,如果是语音才会进行实际的解码工作,如果检测到静音,将直接丢弃。如果检测到一段语音的结束点,就会直接将当前这一段的识别结果返回,然后继续检测后面的语音数据。因此在连续识别模式中,可能多次返回识别结果。

通常,这种模式用于长时间连续语音的实时转写,例如会议转写系统、实时语音质检。

主要交互流程如下:

客户端客户端接口服务接口服务启动和确认请求【开始识别】+配置响应【识别启动】发送和识别音频流分片音频流分片响应【第一句中间结果】音频流分片响应【第一句中间结果】音频流分片响应【第二句中间结果】音频流分片响应【第一句最终结果】音频流分片响应【第二句中间结果】音频流分片响应【第三句中间结果】音频流分片响应【第二句最终结果】停止和完成请求【结束识别】结果响应【剩余未返回的最终结果】响应【识别结束】

会话停止条件:

  • 用户主动结束
  • 音频长度超过最大长度限制
  • 音频开始的静音长度超过"静音头"限制
  • 音频开始识别后的中间静音长度超过"结束静音"限制

2.3 流式实时转写(首句模式)#

流式实时转写首句模式,和连续模式接口类似,也会进行语音的端点检测,如果检测到静音,将直接丢弃,检测到语音才会馈入核心进行实际的解码工作,如果检测到一段语音的结束点,就会将当前这一段的识别结果返回。和连续识别不同的是,在首句模式下,返回第一段的识别结果后,将不再继续识别后续的音频。这主要是因为在和用户进行语音交互的场景下,当用户说完一句话后,往往会等待后续的交互操作,例如聆听根据识别结果播报的相关内容,因而没有必要继续识别后续的音频。

通常,这种模式应用于电话交互(例如电话导航、外呼)或者实体机器人语音交互的场景。通常在这种情况下,当等待用户说话时,系统往往在播报一些内容,此时系统可以通过此接口返回的“语音开始”的事件来进行播报语音的打断工作。

主要交互流程如下:

客户端客户端接口服务接口服务启动和确认请求【开始识别】+配置响应【识别开始】发送和识别音频流分片音频流分片事件【句子开始】音频流分片结果响应【第一句中间结果】音频流分片结果响应【第一句中间结果】音频流分片停止和完成事件【句子结束】结果响应【第一句最终结果】响应【识别结束】其后所有音频流被忽略

会话停止条件:

  • 用户主动结束
  • 音频开始的静音长度超过"静音头"限制
  • 一句话识别结束(满足"静音尾" 配置或者 "最大一句话长度" 配置)

3. 握手阶段#

3.1 握手阶段请求#

3.1.1 请求URI#

WebSocket接口,使用不同的URI来区分提供的三种功能。

  • 流式一句话

    ws(s)://ip:port/v10/asr/freetalk/{property}/short_stream?appkey={appkey}[&access-token={token}]

  • 流式实时转写首句模式

    ws(s)://ip:port/v10/asr/freetalk/{property}/utterance_stream?appkey={appkey}[&access-token={token}]

  • 流式实时转写连续模式

    ws(s)://ip:port/v10/asr/freetalk/{property}/continue_stream?appkey={appkey}[&access-token={token}]

参数类型必选说明
propertystring模型特征串,服务器端利用此值来调用不同的模型
appkeystring分配给开发者的 appkey
access-tokenstring通过 get-access-token 获取到的令牌

access-token 是可选的,开发者优先应选用 X-Hci-Access-Token HTTP Header 来传递 access token。当无法设置 X-Hci-Access-Token时,可以使用此 URL 参数来传递 access token。

3.2 请求参数#

3.2.1 HTTP Header#

参数类型必选说明
X-Hci-Access-Tokenstringget-access-token 接口获取的令牌

X-Hci-Access-Token 是开发者使用分配给开发者的 appkeysecret 访问系统服务接口 get-access-token 获取到的令牌,详细见《系统服务 HTTP 开发手册》。

注意: 在 HTML5 中,由于 Javascript 中在创建 WebScoket 对象时,无法设置HTTP 头域,此时可以通过URL中的 access-token 参数来传入获取的令牌。

3.3 握手阶段响应#

正常协议升级,HTTP 状态码为 101 Switching Protocols,此时没有其它响应。

如果没有给出令牌或者令牌无效、过期,则会返回 UNAUTHENTICATED 错误(HTTP Response Code 401: Unauthorized)。

其它响应的状态码及错误码,请参见 《AICP 10 开发通用规范》

3.4 握手阶段示例#

  • 以HTTP方式进行握手和协议升级

客户端发送请求:

GET /v10/freetalk/cn_16k_common/short_stream?appkey=xxxxxx HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13
X-Hci-Access-Token: xxxxxxxx

服务器响应,完成握手和协议升级:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

4. 连接阶段#

4.1 连接阶段请求#

4.1.1 开始识别#

客户端发送"开始识别"请求,使用文本类型的数据帧(text message)发送,命令和本次会话的参数以json字符串的形式提供。

参数类型必选缺省说明
commandstring-START,表示开始识别请求
configobject-配置信息
extraInfostring客户端设置的信息串,服务器端只做记录,或将来作为定制版本的一些特殊信息
recordIdstring客户端设置的信息串,服务器端记录详细记录或者音频文件时会作为文件名的一部分,以便将来和客户端的信息关联。
只能包括数字、大小写字母、下划线。其它字符在作为文件名时会被转为下划线,最长64字节,超过会被截断
userIdstring用户Id,如果使用用户独享的热词时需要给出

config 结构如下:

参数类型必选缺省说明
profilestringDEFAULT配置集名称
缺省为 DEFAULT,表示缺省配置集
audioFormatstring-支持语音的格式, 取值参见下面的audioFormat 取值表格。
encParamsstring空串编码参数,在裸音频格式 (pcm_xxx, alaw_xxx, ulaw_xxx) 下面无效,
在其它压缩音频下需要根据不同的格式进行设置。格式为 param1:value1;param2:value2
不同格式可能有不同的参数值,但一般都会定义 arac 两个参数,表示原始音频采样率和声道数。
具体格式的参数值请参见附录文档。
vadHeadnumber10000如果音频开始的静音持续时间大于此值,在流式实时转写首句模式/连续模式下将返回"开头静音超时"的事件,然后主动结束会话。
为0 表示不检测"开始静音超时"的情况。
在流式实时转写首句模式和连续模式下有效。
取值范围 [0-600000],单位为ms,也即0-10min,
默认为10000ms, 也即10s。建议取值范围为 0 或者在 1s-60s。
vadTailnumber500如果检测语音结尾的静音长度超过此值时,则认为一句话结束。
在流式实时转写首句模式和流式实时转写连续模式下有效。
取值范围 [50-30000],单位为ms,也即50ms-30s,默认为500ms。建议取值范围在 200ms-3s。
vadEndnumber0如果开始识别后,检测到中间的静音长度超过此值时,则认为整体识别过程结束,会返回"结束静音超时"的事件,然后主动结束会话。
为0 表示不检测中间的长时间静音情况。如果不为0,通常应该大于 vadTail。
仅在流式实时转写连续模式下有效。
取值范围 0 或 [200-3600000],单位为ms,也即200ms-1h,默认为0。建议取值范围在 0 或者在 800ms-5s。
vadMaxSegmentnumber30如果检测到语音持续时间超过此值时,强制认为一句话结束。
在流式实时转写首句模式和流式实时转写连续模式下有效。
取值范围 [10-600], 单位为s,也即10s-10min,默认为30s。建议取值范围在 10s-60s。
vadThresholdnumber10端点检测的灵敏度阈值,在噪声环境下可以调得稍大一些。
在流式实时转写首句模式和流式实时转写连续模式下有效。
取值范围 [1-100],但最好在[8-20]的范围内调整。
interimResultsboolfalse是否输出中间结果
nbestnumber1候选结果数量,可以为 1 至 10 之间的数字
outputPinyinboolfalse是否输出拼音
addPuncboolfalse是否加标点
digitNormboolfalse是否执行数字归一化
textSmoothboolfalse是否执行文本顺滑
wordFilterboolfalse是否执行敏感词过滤
makeParagraphboolfalse是否执行自动文本分段
tppContextRangenumber5000使用后面的多长范围的句子来进行文本后处理。仅在流式实时转写连续模式下有效。
取值范围 0 或者 [1000-30000], 单位为ms,也即 1s-30s。0表示不使用后面的句子,否则表示使用后面句子的范围
wordTypestringDISABLED分词类型。可以为 DISABLED (不输出分词结果), WORD (按词), CHAR (按字)
wordTppboolfalse当输出分词结果时,是输出原始结果分词信息(false
还是输出后处理结果分词结果 (true)
vocabIdstring空串识别所使用的热词Id,可以同时指定多个热词Id,以 ';' 隔开。
vocabstring空串识别所使用的热词内容,UTF-8编码。
注意词表中的回车等特殊字符需要按照 json 规范进行转义。
senswordIdstring空串识别时使用的敏感词Id,可以替代服务器端使用的敏感词, 必须同时打开 wordFilter
senswordstring空串识别所使用的敏感词内容,UTF-8编码。
注意词表中的回车等特殊字符需要按照 json 规范进行转义。
olmIdstring空串识别时使用的小语料优化模型Id
saobjectnull是否要进行进行质检相关工作,无此项不做质检工作
startOffsetnumber0此会话的语音起始时间戳的调整值(ms为单位)
如果不为0,结果中输出的时间戳都会按照此起始值进行调整,主要用于断线重连后继续以前会话

audioformat 取值:  

audioFormat备注
pcm_s16le_8k8K signed 16bit,小端字节序, 单声道
pcm_s16le_16k16K signed 16bit,小端字节序, 单声道
alaw_8k8K 8bit alaw, 单声道
alaw_16k16K 8bit alaw, 单声道
ulaw_8k8K 8bit ulaw, 单声道
ulaw_16k16K 8bit ulaw, 单声道
jtx_speexspeex 压缩格式,使用捷通定义的封包格式,具体封包格式见附录
jtx_opusopus 压缩格式,使用捷通定义的封包格式,具体封包格式见附录

注意: 在流式实时识别时,可以在传输音频之前先进行压缩,可以减少网络传输的流量。一些简单的压缩方法(alaw, ulaw)引入的压缩解压时间很短,但压缩比率也不高。某些复杂一些的压缩算法(speex/opus)压缩比率较大,但需要额外的时间消耗,因此需要根据实际情况决定是否使用压缩音频传输。

sa 对象的结构如下:

参数类型必选缺省说明
checkEmotionboolfalse是否进行情绪检测,并输出结果
checkGenderboolfalse是否进行性别检测,并输出结果
outputSpeedboolfalse是否进行语速信息
outputVolumeboolfalse是否输出音量统计信息

配置集和参数:

  • 配置集(profile)是在管理后台进行配置的,服务器端会使用此配置集中定义的配置作为缺省的配置参数。
  • 表中各个参数的“缺省值”,表示在没有找到配置集的情况下的缺省值。此时识别会继续,但会返回 warning 信息。
  • 表中各个参数的“缺省值”,也是一个配置集在初始创建时的值,但如果在管理后台中对配置集进行了更改,则会以后台更改后的作为“缺省值”。
  • 如果在请求中同时定义了其它参数,则优先使用请求中带的参数

动态优化资源:

  • 如果 vocabId 指定的是用户独享的热词,必须同时指定创建此热词时候的 userId,如果不是此 userId 创建的热词,此热词会被忽略,并给出 wanring 字段。
  • 如果 vocabId 指定的是用户共享的热词,则 userId 被忽略;使用敏感词和小语料优化模型时,userId 也会被忽略。
  • 如果 vocabId 中设置多个热词ID,这些热词必须是用户共享的热词,或者同一个 userId 创建的用户独享热词。
  • 如果 vocabId 中设置多个热词ID,或者同时设置了 vocabIdvocab 的时候,这些热词会同时生效。
  • vocabId 无效或者 vocab 无效的时候,服务仍然会返回识别结果,等同于不使用热词。但此时在请求响应中会包括 warning 字段。如果同时指定了多个热词ID时,如果有一个无效,那么只会忽略掉无效的热词ID,但如果同时指定有 vocabvocab 无效时,目前会导致所有热词都无效。
  • 暂不支持同在 senswordId 中设置多个敏感词ID,当同时设置 senswordIdsensword 的时候, senswordId 优先,除非 senswordId 无效,此时会使用 sensword
  • senswordId 无效或者 sensword 无效的时候,会继续识别,但会返回 warning 信息。
  • 当指定了热词/敏感词用户资源的同时,在后台维护的配置集中也配置了系统资源的话,会根据配置的系统资源的处理方式决定是合并用户资源和系统资源,还是仅使用用户资源。小语料优化模型无法合并,在这种情况下,总是仅使用用户资源。
  • 动态优化资源(热词、敏感词、小语料优化模型)的格式和规范参见 《ASR 优化指南》
  • 动态优化资源 ID 的获取方法请参见 《统一资源管理接口开发手册》

其它

  • 如果没有设置后处理相关操作,但 wordTpp 设为 true,还是会输出原始分词结果。

vadHead, vadTail, vadEnd, vadMaxSegment, vadThreshold 在不同的模式下生效情况不一样,列表如下:

配置项流式一句话识别流式实时转写(首句模式)流式实时转写(连续模式)
vadHead
为0时不判断"开头静音超时"
其它情况判断"开头静音超时", 断开会话

为0时不判断"开头静音超时"
其它情况判断"开头静音超时", 断开会话
vadTail
判断"一句话结束",断开会话

判断"一句话结束",用于分句
vadEnd
为0时不判断"结束静音超时"
其它情况判断"结束静音超时",断开会话
vadMaxSegment
判断"一句话结束",断开会话

判断"一句话结束",用于分句
vadThreshold

vadTail 是用于判断一句话是否结束的静音阈值,vadEnd 是判断整个会话是否结束的静音阈值,因此一般情况下, vadEnd 都应该大于 vadTail。如果 vadEnd (不为0时) 小于 vadTail,则仍会使用 vadTail 来进行一句话结束的判断,这句话结束后会立刻返回 EXCEEDED_END_SILENCE 事件并结束会话。

4.1.2 发送音频数据#

在收到“开始识别”的响应之后,可以开始发送音频数据。为节省流量,音频以二进制数据帧形式(binary message)的方式发送。

音频数据将分片发送,也即在获得一定量音频数据的同时就可以发送一个binary message,每个分片必须在40ms~1000ms之间,建议在需要实时反馈的情况下100ms,不需要实时反馈的情况下500ms。

4.1.3 结束识别#

对于识别中的对话,需要在Websocket上发送“结束识别”的请求来取消或结束识别。 "结束识别"请求使用文本类型的数据帧 (text message)发送,命令和参数以json字符串的形式提供。

参数类型必选说明
commandstringEND,表示结束识别请求
cancelboolentrue时表示取消识别,也即丢弃识别中和未识别的语音数据并结束,不返回剩余的识别结果。
false则表示继续处理识别中和未识别的语音数据直到处理完所有之前发送的数据。

4.2 连接阶段响应#

由于WebSocket是全双工的,因此所谓响应就是从服务器端发送给客户端的消息,而且,也并不是所有的请求信息都有一条对应的响应。

4.2.1 开始识别请求响应#

服务器端收到“开始识别”请求时,会给出如下响应消息,以json字符串形式放置在text message中。

参数类型必选说明
respTypestringSTART,表示开始识别响应
traceTokenstring服务内部的跟踪令牌,可用于在日志中追溯具体流程。
warningarray可能的警告信息

warning 是一个数组,每一项的结构如下:

参数类型必选说明
codenumber警告代码,具体的警告错误码见后
messagestring警告的详细信息

warning 字段说明有正常流程之外的情况发生,但可以继续识别下去。其 code 包括:

code说明
100输入引擎的采样率和模型的采样率不一致,自动进行了升采样或降采样
101vocabId 对应的热词找不到,或者无效
102vocab 的热词内容非法或者无效
103senswordId 对应的热词找不到,或者无效
104sensword 的热词内容非法或者无效

4.2.2 事件响应#

服务器端检测到某些事件时,会给出如下响应消息,以json字符串形式放置在text message中。

参数类型必选说明
respTypestringEVENT,表示事件的响应
traceTokenstring服务内部的跟踪令牌,可用于在日志中追溯具体流程。
eventstring具体的事件,见event取值表
timestampnumber事件发生的具体时间,以会话开始作为0点,ms为单位。

event 取值表: 

事件说明
VOICE_START检测到句子开始
VOICE_END检测到句子结束
EXCEEDED_SILENCE开头静音超长,也即音频一开始长时间没有检测到声音
EXCEEDED_END_SILENCE结束静音超长,也即开始识别时候之后,中间长时间没有检测到声音
EXCEEDED_AUDIO输入音频超长
NOISE可能是噪音

输入音频超长(EXCEEDED_AUDIO)是指一通会话的总的音频长度大于后台配置的最大允许长度(比如5h)。

可能是噪音(NOISE) 是指检测到句子开始了,但持续一段时间都没有识别出有效内容来,因此有可能此句话是噪音。此事件只是一个提示,在输出此事件后,还会继续识别。

在流式一句话模式下:

  • 不会返回VOICE_STARTVOICE_ENDEXCEEDED_SILCENCEEXCEEDED_END_SILCENCE事件。
  • 返回EXCEEDED_AUDIO事件后,服务器将会输出当前未输出的识别结果,然后主动关闭会话。

在实时转写首句模式下:

  • 返回VOICE_START事件,表示检测到语音,此时IVR可以做打断。
  • 返回VOICE_END事件后,表示一句话结束,服务器将会输出当前这句话的识别结果,然后主动关闭会话。
  • 只会返回最多一组VOICE_STARATVOICE_END事件
  • 如果返回EXCEEDED_SILENCE事件,表示超过vadHead没有检测到声音,通常表示用户一直没有说话。此时服务器会主动关闭会话。
  • 不会返回EXCEEDED_END_SILENCE事件
  • 不会返回EXCEEDED_AUDIO事件,通常是检测到静音超长或者一句话结束,就会关闭会话了。

在实时转写连续模式下:

  • 可能会返回多个VOICE_START或者VOICE_END事件。
  • 返回VOICE_END事件后,后续的音频仍然会继续识别。
  • 由于可能会有更长上下文范围的后处理(tppContextRange 不为0),因此在返回VOICE_END事件后,可能会延迟一段时间输出前面这句话的最终结果,甚至可能在其它事件之后。
  • 如果返回EXCEEDED_SILENCE事件,表示超过vadHead没有检测到声音,通常表示用户一直没有说话。此时服务器会主动关闭会话。
  • 如果返回EXCEEDED_END_SILENCE事件,表示在识别过程中出现超过vadEnd没有检测到声音,通常表示用户在连续说了几句话之后不再说话。此时服务器会输出当前未输出的结果,然后主动关闭会话。
  • 返回EXCEEDED_AUDIO事件后,服务器将会输出当前未输出的识别结果,然后主动关闭会话。

4.2.3 识别结果响应#

识别结果响应,包括中间临时结果和最终结果,采用同样的输出格式。

参数类型必选说明
respTypestringRESULT,表示识别结果的响应
traceTokenstring服务内部的跟踪令牌,可用于在日志中追溯具体流程。
sentenceobject一句话的结果

sentence 元素是一个json object,其结构如下:

参数类型必选说明
startTimenumber一句的起始时间戳,单位ms
endTimenumber一句的结束时间戳,单位ms
isFinalbooleantrue表示是最终结果, false表示为中间临时结果
resultobject调用成功表示识别结果,调用失败时无此字段
alternativesarray多候选时,如果除了第一候选结果外还有其它候选结果则有此字段,不包括第一候选结果。
如果不要求多候选结果或者识别候选结果只有1个时,没有此字段
analysisobject当输入配置中sa不为空时会输出此字段,否则无此字段

如果在“开始识别”请求中的interimResults配置项为false,将不会出现中间临时结果,也即不会出现isFinalfalse的响应。

result 的结构如下:

参数类型必选说明
textstring识别结果
pinyinstring对应的拼音,当 outputPinyin 设为 false 时,没有此项
confidencenumber识别结果的置信度,介于 [0.0-1.0] 之间。此值仅会在最终结果时被赋值,在中间结果时统一置为0.0
注意,目前置信度作用不是太大,不要过多依赖此值
wordsarray分词信息。在中间结果时总是为空,只有在最终结果中才会输出分词信息。
可选,如果客户端发送的 wordType 配置为 DISABLED,那么将没有此字段

alternatives 中的每个元素是一个 json object, 其结构和 result 一致。

注意:

  • 如果nbest等于1,则没有alternative字段。
  • 如果nbest大于1,但最终候选结果只有1个,那么也将没有alternatives字段。
  • alternative的元素个数加上result,是实际的候选结果个数,可能会小于nbest配置的数目,但不会大于nbest数目。

words 中的每个元素是一个 json object,其结构如下:

参数类型说明
stnumber分词在音频流中的开始时间偏移,单位: ms
etnumber分词在音频流中的结束时间偏移,单位: ms
wstring分词对应的文本
pystring分词对应的拼音,当 outputPinyin设为 false 时,没有此项
cnumber置信度
tstring分词的类型,详见分词类别说明

分词类别说明:

类型全名说明
UUserword用户热词
PPunctuation标点
SSmoothed顺滑词
MMasked被过滤的敏感词
DDigitNorm数字归一化词

为节省传输的内容,这里的参数、分词类型都用比较简单的词汇替代。有可能会是多个字符,例如UM,表示既是用户热词又是敏感词。当是正常词没有任何特殊分词标识时,t 项被省略。

如果单元类型为标点符号,其st, et 值相同。目前打标点功能对中文识别只会增加",""。""?"三种,其st, et值一定与和前一单元的et相同。如果将来会增加其它标点符号,如果是左引号、左书名号之类,其st,et 会与下一单元的st相同。

由于存在文本后处理的操作,例如打标点、数字归一化等,因此可以选择输出原始识别结果的分词信息还是后处理结果的分词信息。当输出原始识别结果时,分词结果是和原始音节一一对应的,也不会出现上述后处理相关的分词类型属性( P, S, M, D),但可能会有 U 类型。当输出后处理结果的分词信息时,则会增加标点单元、显示数字归一化后的单元、会标识后处理的分词类型属性等。

如果输出的是后处理分词信息,则会出现如下示例情况:

  • “百分之十二”,分词输出的单元内容为“百分之”、“十二”,但整句的输出为"12%"。
  • “嗯我们开始吧”,分词输出的单元内容为“嗯”(顺滑词)、“我们”、“开始”、“吧”,但整句的输出为"我们开始吧"。
  • “这个是法轮功的视频”,分词输出的单元内容为“这个”、“是”、“法轮功”(敏感词)、“的”、“视频”,但整句的输出为"这个是***的视频"。

analysis 对象为质检相关的信息,其结构如下:

参数类型说明
emotionsarray情绪信息数组,如果 checkEmotion 为 false 或者没有检测到情绪信息时,没有此字段
genderobject性别信息,如果 checkGener 为false,没有此字段
speednumber语速,如果 outputSpeed 为 false, 则无此字段
avgVolnumber平均音量,如果 outputVolume 为 false, 则无此字段
maxVolnumber最大音量,如果 outputVolume 为 false, 则无此字段

emotions 的每一个元素是一个json object, 其结构如下:

参数类型说明
stnumber音频开始时间,单位ms
etnumber音频结束时间,单位ms
cnumber置信度,范围[0.0, 1.0]
estring情绪, HAPPY, ANGRY, SAD, DISGUSTED 之一

gender 对象为性别信息,其结构如下:

参数类型说明
cnumber置信度,范围[0.0, 1.0]
gstring性别,FEMALE, MALE 之一

注意:

  • 目前版本中,一个分句中进行情绪检测时最多也只会检出一个结果,因此要么没有 emotions 字段,要么 emotions 数组元素个数为1
  • 如果设置了 checkEmotion, 但没有检测到情绪信息时,结果中也不会输出 emotions
  • 目前版本中,情绪检测也只能检出 ANGRY 类。
  • 如果 sa 配置不为空,但 analysis 中不需要任何输出项时(或者是 sa 之下配置的均为 false,或者即使配置了情绪检测,也没有检测出情绪),输出为 {}
  • emotionsgender 目前只会在最终结果中输出,在中间临时结果里不会输出

4.2.4 结束识别请求响应#

参数类型必选说明
respTypestringEND,表示结束识别响应
traceTokenstring服务内部的令牌,可用于在日志中追溯具体流程。
reasonstring结束原因,参见下表

reason 的可能取值:

结束原因说明
NORMAL正常结束
CANCEL用户取消,也即客户端发送”结束识别“指令时cancel参数为true
ERROR识别过程中发生错误

4.2.5 错误响应#

参数类型必选说明
respTypestringERROR,表示错误响应
traceTokenstring服务内部的跟踪令牌,可用于在日志中追溯具体流程。
errCodenumber错误码,请参见 《AICP 10 开发通用规范》
errMessagestring处理结果的详细描述,主要是错误状态

这里的错误响应,通常是指不影响流程,但当前会话无法再进行下去的错误,包括如下情况:

  • 配置串错误,包括存在不识别的配置串,或者配置串值的范围不合法
  • 时序不正确,比如没有发“开始识别”指令,就发送了“结束识别”指令
  • 音频分片大小不合理 (每个分片必须在40ms~1000ms之间)
  • 识别过程中发生错误,比如音频解码发生错误

出现错误响应时,如果已经在一个会话中了,会再发送一个"结束识别”的响应,表示识别会话结束。如果会话还没有开始,那么发送此错误响应后不做其它操作。此后的音频数据都被忽略,直到收到下一个“开始识别”请求。

返回错误响应后,连接不会关闭,只是会关闭当前会话。客户端仍然可以在同一连接上启动新的会话。但如果在一定时间内出现错误响应的次数超过一定阈值时,服务器端也会发送“严重错误”响应,然后主动关闭连接。

4.2.6 严重错误响应#

参数类型必选说明
respTypestringFATAL_ERROR,表示严重错误响应
traceTokenstring服务内部的跟踪令牌,可用于在日志中追溯具体流程。
errCodenumber错误码,请参见 《AICP 10 开发通用规范》
errMessagestring处理结果的详细描述,主要是错误状态

严重错误,通常指流程无法继续的情况。比如当出现以下情况:

  • 服务端收到“开始识别”请求,等待音频数据超时,或者收到分片音频后,等待下一个分片超时,目前超时时间缺省均为20s
  • 连接空闲时间(也即连接上没有任何有效会话)超过一定阈值,目前连接空闲超时时间缺省为2min
  • 在没有任何有效会话的时候超过一定时间还收到音频流
  • 在一段时间内连续出现错误情况超过一定次数

出现严重错误响应时,流程不再继续,服务器端会主动断连。

4.3 连接阶段示例#

  • 客户端发送"开始识别"请求
{
"command": "START",
"config":
{
"audioFormat": "ulaw_8k",
"addPunc": true,
"vadTail": 400,
"interimResult": true
},
"extraInfo": "abcdefgh"
}
  • 服务器端发送“开始识别”响应
{
"respType": "START",
"traceToken": "token_abcd_12345"
}
  • 服务器端发送“开始识别”响应,但是带警告信息
{
"respType": "START",
"traceToken": "token_abcd_12345",
"warning":
[
{
"code": 100,
"message": "speech sample rate automatically changed from 44100 to 16000"
},
{
"code": 101,
"message": "vocabId xxxxx not found"
}
]
}
  • 客户端开始分片发送音频数据

通过Binary Frame发送语音数据

  • 服务器端检测到了“句子开始”,发送“句子开始”事件
{
"respType": "EVENT",
"traceToken": "token_abcd_12345",
"event": "VOICE_BEGIN",
"timestamp": 100
}
  • 服务器端有了中间临时识别结果
{
"respType": "RESULT",
"traceToken": "token_abcd_12345",
"sentence":
{
"startTime": 100,
"endTime": 1500,
"isFinal": false,
"result":
{
"text": "第一句中间结果",
"score": 0.0
},
}
}
  • 服务器端检测到了“句子结束”,发送“句子结束"事件
{
"respType": "EVENT",
"traceToken": "token_abcd_12345",
"event": "VOICE_END",
"timestamp": 1500
}
  • 服务器端有了某句的最终识别结果
{
"respType": "RESULT",
"traceToken": "token_abcd_12345",
"sentence":
{
"startTime": 100,
"endTime": 1500,
"isFinal": true,
"result":
{
"text": "第一句最终结果",
"score": 0.98
},
}
}
  • 带多候选和分词结果示例:
{
"respType": "RESULT",
"traceToken": "token_abcd_12345",
"sentence":
{
"startTime": 100,
"endTime": 1500,
"isFinal": true,
"result":
{
"text": "欢迎使用语音云服务。",
"confidence": 0.9
"words":
[
{
"st": 400,
"et": 1000,
"w": "欢迎",
"c": 0.82,
},
{
"st": 1000,
"et": 1450,
"w": "使用",
"c": 0.33,
},
{
"st": 1450,
"et": 2000,
"w": "语音云",
"c": 0.33,
},
{
"st": 2000,
"et": 2450,
"w": "服务",
"c": 0.33,
},
{
"st": 2450,
"et": 2450,
"w": "。",
"c": 0.0,
"t": "P"
},
]
},
"alternatives":
[
{
"text": "欢迎试用语音云服务。",
"confidence": 0.8
"words":
[
...
]
},
]
}
}
  • 带质检结果的示例:
{
"respType": "RESULT",
"traceToken": "token_abcd_12345",
"sentence":
{
"startTime": 100,
"endTime": 1500,
"isFinal": true,
"result":
{
"text": "欢迎使用语音云服务。",
"confidence": 0.9
},
"analysis":
{
"speed": 5.46,
"avgVol": 0.035,
"maxVol": 0.188,
"emotions":
[
{
"st": 100,
"et": 1500,
"c": 0.3,
"e": "ANGRY"
}
],
"gender":
{
"c": 0.89,
"g": "FEMALE"
}
},
}
}
  • 客户端发送“结束识别”指令
{
"command": "END",
"token": "token_abcd_12345",
"cancel": false
}
  • 识别结束响应

如果上面“结束识别”指令中的cancelfalse,会继续识别并先返回剩余的结果,然后返回“结束识别”响应;如果为true,则直接返回“结束识别”响应。

{
"respType": "END",
"traceToken": "token_abcd_12345",
"reason": "NORMAL"
}
  • 错误响应示例
{
"respType": "ERROR",
"errCode": 3,
"errMessage": "Parse Task Config Failed",
}
  • 严重错误响应示例
{
"respType": "FATAL_ERROR",
"errCode": 10,
"errMessage": "Too many errors",
}

5. 附录#

5.1 jtx_opus 编码#

5.1.1 开始识别请求#

audioFormat 取值为 jtx_opus 时,在“开始识别”请求的 config 配置中,需要设置 encParams 参数:

参数类型必选缺省说明
arint-音频的采样率
acint1通道数,目前只能选择为1

以下是请求示例:

{
"command": "START",
"config":
{
"audioFormat": "jtx_opus",
"encParams": "ar:16000",
"addPunc": true,
"vadTail": 400,
"interimResult": true
},
"extraInfo": "abcdefgh"
}

音频采样率一般需要和所配置的 property 模型特征串中的采样率一致。

5.1.2 编码流程#

在使用 jtx_opus 编码方式时,在发送音频数据分片时均应按 opus 格式进行编码,并按照捷通自定义的格式进行封包。编码后的数据格式如 jtx_packet 结构体所示:

struct jtx_opus_packet {
uint16_t length; // Big Endian
uint8_t payload[length];
};
struct jtx_packet {
uint32_t origin_audio_length; // 原始音频数据长度,Big Endian
jtx_opus_packet packets[N];
}

编码时需要选择 帧长 (frame size) 和 码流率 (bitrate)。

帧长单位为ms,opus 支持帧长为 2.5、5、10、20、40、60、80、100 和 120。音频数据时长必须能够被帧长整除。例如:音频数据时长为 200ms,则 frame size 可以选择 2.5、5、10、20、40 或 100。通常情况下,音频数据分片时长均为 10ms 和 20ms 的整数倍,建议 frame size 使用 20ms, 20ms 不可用时,选择 10ms。

将音频分片根据 frame size 分割成多个 frame,并将每个 frame 通过 opus_encode 函数编码获得 jtx_packet.payload。

对于最后一个分片,时长有可能不是 frame size 的整数倍,此时需要丢弃尾部的不足 frame size 的部分音频数据。

码流率决定了编码音频的压缩率,单位: bps (bits per second),对于 pcms16le_16k 原始数据,采样率为 16000,声道数为 1,采样为 2 字节整型,其码率为 16000 * 1 * 2 * 8 = 256000 bps 。若需要压缩 10 倍,则码率应设置为 _25600

以下为 C++ 语言代码,演示如何进行编码。

#include <opus.h>
#include <opus_types.h>
#include <opus_defines.h>
#include <stdint.h>
#include <vector>
#include <iostream>
#include <memory>
#include <cstring>
class JTOpusEncoder {
public:
JTOpusEncoder(int ar, int ac, int bitrate) : ar_(ar), ac_(ac) {
int error;
encoder_ = opus_encoder_create(ar, ac, OPUS_APPLICATION_VOIP, &error);
opus_encoder_ctl(encoder_, OPUS_SET_BITRATE(bitrate));
}
~JTOpusEncoder() { opus_encoder_destroy(encoder_); }
void Encode(const void *audio_slice, size_t length,
std::vector<uint8_t> &out) {
const size_t frame_size = 20; // 20ms
const size_t frame_size_in_bytes =
ar_ * ac_ * sizeof(short) / 1000 * frame_size;
const size_t frame_size_in_samples = ar_ / 1000 * frame_size;
out.resize(length);
const uint8_t *src = reinterpret_cast<const uint8_t *>(audio_slice);
uint8_t *dst = out.data();
size_t available_out_size = length - 4;
dst[0] = static_cast<uint8_t>(length>>24);
dst[1] = static_cast<uint8_t>(length>>16);
dst[2] = static_cast<uint8_t>(length>>8);
dst[3] = static_cast<uint8_t>(length>>0);
dst += 4;
while (length >= frame_size_in_bytes) {
opus_int16 *pcm = (opus_int16 *)(src);
int bytes = opus_encode(encoder_, pcm, frame_size_in_samples, dst + 2,
available_out_size - 2);
dst[0] = static_cast<uint8_t>(bytes >> 8);
dst[1] = static_cast<uint8_t>(bytes);
dst += 2 + bytes;
available_out_size -= 2 + bytes;
src += frame_size_in_bytes;
length -= frame_size_in_bytes;
}
out.resize(dst - out.data());
}
private:
int ar_;
int ac_;
OpusEncoder *encoder_;
};

5.2 jtx_speex 编码#

jtx_speex 编码和 jtx_opus 基本一致。

在“开始识别”请求的 config 配置中,需要设置 encParams 参数,包括 arac,含义和 jtx_opus 一致。

在发送音频时,同样需要将音频分片按 speex 格式进行编码,并按照捷通自定义的格式进行封包,封包方式同 jtx_opus

编码时需要选择 quality 项,这点和 jtx_opusbitrate 类似,也是确定了压缩级别。

以下为 C++ 语言代码,演示如何进行编码。

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <speex/speex.h>
#include <vector>
class JtxSpeexEncoder {
public:
// 构造函数, compexity 取值范围 [0,10], 对于语音场景建议取值 [2, 4]
JtxSpeexEncoder(int ar, int ac, int bitrate, int complexity = -1)
: ar_(ar), ac_(ac), bits_() {
speex_bits_init(&bits_);
int mode = -1;
if (ar == 8000)
mode = SPEEX_MODEID_NB;
else if (ar == 16000)
mode = SPEEX_MODEID_WB;
else if (ar == 32000)
mode = SPEEX_MODEID_UWB;
else
abort();
if (ac != 1) abort(); // 只支持单声道
encoder_ = speex_encoder_init(speex_lib_get_mode(mode));
speex_encoder_ctl(encoder_, SPEEX_SET_BITRATE, &bitrate);
if (complexity >= 0) // 不设置时,默认为 2
speex_encoder_ctl(encoder_, SPEEX_SET_COMPLEXITY, &complexity);
}
~JtxSpeexEncoder() {
speex_bits_destroy(&bits_);
speex_encoder_destroy(encoder_);
encoder_ = nullptr;
}
void Encode(const void *audio, size_t audio_length, std::vector<uint8_t> &out) {
size_t frame_time = 20; // speex frame time 固定为 20ms
size_t bytes_in_one_frame = ar_ * ac_ * sizeof(spx_int16_t) * frame_time / 1000;
out.resize(audio_length);
const uint8_t *src = reinterpret_cast<const uint8_t *>(audio);
uint8_t *dst = out.data();
dst[0] = static_cast<uint8_t>(audio_length >> 24);
dst[1] = static_cast<uint8_t>(audio_length >> 16);
dst[2] = static_cast<uint8_t>(audio_length >> 8);
dst[3] = static_cast<uint8_t>(audio_length);
dst += 4;
int dst_left = static_cast<int>(out.size() - 4);
while (audio_length >= bytes_in_one_frame) {
const spx_int16_t *pcm = reinterpret_cast<const spx_int16_t *>(src);
speex_bits_reset(&bits_);
speex_encode_int(encoder_, const_cast<spx_int16_t *>(pcm), &bits_);
auto bytes = speex_bits_nbytes(&bits_);
assert(dst_left - 2 >= bytes);
speex_bits_write(&bits_, (char *)dst + 2, bytes);
dst[0] = static_cast<uint8_t>(bytes >> 8);
dst[1] = static_cast<uint8_t>(bytes);
dst += 2 + bytes;
dst_left -= 2 + bytes;
src += bytes_in_one_frame;
audio_length -= bytes_in_one_frame;
}
out.resize(dst - out.data());
}
private:
int ar_, ac_;
SpeexBits bits_;
void *encoder_;
};

6. 版本记录#

接口版本平台支持版本组件及支持版本修改内容
10.5.010D.1aicp_asr_ft 10.8.01. 新增小语料优化模型设置功能 (olmId)
2. 新增 userId 参数
3. 新增配置集参数(profile)
10.4.010C.1aicp_asr_ft 10.6.01. 新增 tppContextRange 参数
10.3.010C.0aicp_asr_ft 10.5.01. 新增敏感词设置功能
2. 质检功能新增性别检测
10.2.010B.0aicp_asr_ft 10.2.01. 新增 recordId 字段
2. 新增输出拼音、文本后处理相关字段
3. 支持多热词
10.1.010A.1aicp_asr_ft 10.0.01. 新增热词设置功能(增加 vocabvocabId 字段)
2. 新增 warning 输出字段
10.0.010A.0aicp_asr_ft 10.1.0初始版本