语音交互过程示例
建立链接
用户发起建立websocket链接,其中请求类似wss://{server}/open_api?sn={sn} 其中sn作为本次识别唯一的标识,建议采用UUID字符串,长度为32,用于问题追查。
example:
wss://vop.baidu.com/ws_api?sn=42e7-f8af-4e09-80cd-9872
识别开始
发送START指令,开始本次识别。使用WebSocket协议opcode=1(Text Frame)发送该指令,内容示例如下
{
"type":"START",
"data":{
"pam":"{\"aue\":3,\"time_stamp\":26399646,\"signature\":\"ef64170e26c72500a29d57a6eecd10c0\",\"methods\":[\"ASR\",\"UNIT\",\"TTS\"],\"ak\":\"7f8cc852-21e5-431f-88b1-9a0603c87d13\",\"pk\":\"gyasr6hk\",\"fc\":\"s2qx05\"}",
"format":"pcm",
"sample":16000,
"cuid":"gyasr6hk_7f8cc852-21e5-431f-88b1-9a0603c87d13",
"dev_pid":1550,
"dev_key":"com.baidu.iot",
"user":"baidu_iot"
}
}
pam为json格式字符串,用于设备鉴权,展开说明如下
{
"fc":"s2qx05",
"pk":"gyasr6hk",
"ak":"7f8cc852-21e5-431f-88b1-9a0603c87d13",
"signature":"ef64170e26c72500a29d57a6eecd10c0", ## md5(ak + "&" + time_stamp + sk) 转换成十六进制字符串
"time_stamp":26399646, ## 分钟级别时间戳
"methods":[ ## 调用的AI能力
"ASR", ## 语音识别
"UNIT", ## 语义解释
"TTS" ## 语音合成
],
"aue":3 ## TTS参数,指定生成的音频格式
}
上传音频
只支持16k、16bit,单声道 "pcm" 音频。音频长度不能超过60s。 使用WebSocket协议opcode=2(Binary Frame)发送音频数据,建议每包发送5120字节。
识别结束或取消
发送FINISH指令,结束本次识别,等待服务端下发识别结果。
{
"type":"FINISH"
}
或 发送CANCEL指令,取消本次识别,取消识别后不会收到识别结果。
{
"type":"CANCEL"
}
读取语音识别结果
识别结果包含两种类型:
- 中间临时识别结果(MID_TEXT)
- 最终识别结果(FIN_TEXT)
语音识别服务会边识别音频数据,边下发结果,并在识别全部数据后,下发完整结果。 所以客户端会收到多个中间临时识别结果及一个最终识别结果,示例如下
{
"err_msg":"OK",
"err_no":0,
"log_id":2289030407,
"result":"调",
"sn":"42e7-f8af-4e09-80cd-9872",
"type":"MID_TEXT"
}
{
"err_msg":"OK",
"err_no":0,
"log_id":2289030407,
"result":"调到",
"sn":"42e7-f8af-4e09-80cd-9872",
"type":"MID_TEXT"
}
{
"err_msg":"OK",
"err_no":0,
"log_id":2289030407,
"result":"调到中",
"sn":"42e7-f8af-4e09-80cd-9872",
"type":"MID_TEXT"
}
...
{
"err_msg":"OK",
"err_no":0,
"log_id":2289030407,
"result":"调到中央一台",
"sn":"42e7-f8af-4e09-80cd-9872",
"type":"FIN_TEXT"
}
err_no说明:
错误码 | 错误码描述 |
---|---|
0 | 识别成功 |
-3003 | 服务后端错误 |
-3004 | 声学模型ID异常 |
-3005 | 无效音频 |
-3006 | 音频过长 |
-3015 | 身份鉴权失败 |
注意:
- 如果err_no不为0,后面不会再有数据发送,直接结束。
- 如果err_no为0,识别最终结果为type=FIN_TEXT
第三方结果
在前面的START指令中,除了语音识别(ASR)外,我们还用到了语义解析(UNIT)和语音合成(TTS),下面简单说明语义解析(UNIT)和语音合成(TTS)结果。
UNIT
语义解析(UNIT)会对语音识别(ASR)返回结果进行解析和查询,最终返回查询结果。 返回示例如下
{
"type":"THIRD_DATA",
"third_type":"iot",
"data":"{"action_type":"asrnlp_tts","query":["调到中央一台,"],"intent":"BUILT_CHAT","custom_reply":[]}"
}
其中data为json格式字符串,展开如下
{
"action_type":"asrnlp_tts",
"query":[
"调到中央一台,"
],
"intent":"BUILT_CHAT",
"custom_reply":[
]
}
err_code说明:
错误码 | 错误码描述 |
---|---|
0 | 请求成功 |
1 | 权限不足 |
2 | 签名校验识别 |
3 | AI服务配置不足 |
4 | 请求参数有误 |
5 | 服务器内部错误 |
6 | BOS服务异常 |
7 | 语音合成失败 |
8 | 语义解析失败 |
action_type说明
action_type | 说明 |
---|---|
asr_none | 仅asr,返回数据不带tts字段,无音频数据返回 |
asrnlp_none | 仅asr、nlp,无音频数据返回 |
asrnlp_tts | 全链路能力,短语音场景,服务端直接下发音频数据(短音频返回示例见下节 音频结果) |
asrnlp_url | 全链路能力,返回为媒资或长语音,服务端不直接下发媒资数据,仅下发音频的url |
asrnlp_mix | 全链路能力,返回为媒资,同时带tts,即服务端会下发一段音频数据,同时下发媒资的url,设备端需先播放音频数据,再播放url对应的媒资 |
音频结果
音频结果分为两种:
- 短音频
- 长音频
短音频
短音频由服务端通过websocket直接下发音频数据,音频数据分多包下发,每包数据分为两帧:
- 第一帧数据通过opcode=1(Text Frame)下发 ,主要为合成参数及进度之类的数据
- 第二帧数据通过opcode=2(Binary Frame)下发,为音频数据
第一帧数据示例如下:
{
"type":"TTS_DATA",
"next_frame":true, ## 类型:bool,表示是否需要与下一帧数据一起使用,true为需要,false不需要,在tts合成失败的时候,只有text frame数据,没有二进制音频数据
"tts_header":"{\"aue\":3,\"err\":0,\"err_msg\":\"success.\",\"idx\":-1,\"per\":0,\"percent\":5,\"rate\":2,\"sn\":\"TS_EX-3185283798515839904482248223216\",\"tex\":\"没有这个台\"}\n"
}
tts_header为json格式字符串,展开说明如下:
{
"err":0,
"err_msg":"success.",
"sn":"TS_EX-3185283798515839904482248223216",
"idx":-1, ## idx为负数时,表示合成最后一包数据,合成结束
"percent":5, ## progress of audio
"per":0, ## speaker,合成成功后,只有第一个包会发
"rate":2, ## 码率, 合成成功后,只有第一个包会发
"aue":3, ## 音频编码,合成成功后,只有第一个包会发
"tex":"没有这个台" ## 合成字段,合成成功后,只有第一个包会发
}
err说明:
错误码 | 错误码描述 |
---|---|
0 | 识别成功 |
-3003 | 服务后端错误 |
-3004 | 声学模型ID异常 |
-3005 | 无效音频 |
-3006 | 音频过长 |
-3015 | 身份鉴权失败 |
长音频
长音频(包括媒资)不会直接下发音频数据,改为下发音频的url 在UNIT返回结果中,对应的data示例如下:
{
"query":"今天上海天气怎么样",
"intent":"USER_WEATHER",
"actionType":"xxxxx",
"slot":[
{
"name":"user_loc",
"value":"上海"
},
{
"name":"user_time",
"value":"2020-02-24"
}
],
"custom_reply":[
{
"type":"url",
"value":"http://xxx.xxx.com" ## 音频的url
}
]
}
心跳包
心跳包结构如下,通过opcode=1(Text Frame)传输:
{
"type":"HEARTBEAT"
}
心跳包的两种使用场景:
- 服务端下发: 在用户发送大量的静音(无效)音频时, 服务端没有识别结果变动,此时服务端会下发心跳包
- 客户端上传: 用户5秒内没有数据上传,但后续还需要继续上传数据时,可以向服务端发送心跳包,告诉服务端连接正常