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