基于websocket协议的产品接入
一、产品介绍
基于websocket协议的API请求DUI全链路产品,获得对话交互结果
1.1 适用场景
1)轻量级嵌入式设备,基于协议开发
2)采用云对云的方式,使用DUI全链路产品,基于协议开发
3)其他特殊场景,需要基于协议开发
4)支持语音、文本、意图三种输入
1.2 使用限制
需要先前往控制台创建全链路产品,并且将产品成功发布,才能正常使用基于websocket协议的API。
二、接入说明
2.1 接入前的准备
1)登录DUI控制台
2)创建全链路产品
3)进行产品配置
4)添加技能
5)进行产品技能测试
6)配置授权
7)发布产品
2.2 建立websocket连接
本API正式环境的地址是wss://dds.dui.ai/dds/v2/[分支号],其中[分支号]是DUI控制台分支管理页面的内容。如下图所示: 在产品详情页的发布管理页面,选择分支管理,获取分支号。
2.2.1 连接上需要携带的公共参数
参数名 | 含义 | 是否必须 | 取值示例 |
serviceType | 表示使用何种协议 | 是 | websocket |
productId | 产品标识 | 是 | 278578090 |
productVersion | 指定使用的产品版本 | 否 | 1 |
连接上需要携带的参数,包含了授权参数,授权有两种场景,一种是设备对接云,一种是云对云。具体参数信息如下:
2.2.2 设备对接云端API的授权参数
参数名 | 含义 |
是否必须 |
取值示例 |
deviceName | 设备激活时获取到的device profile中deviceName字段 |
是 |
0ddddeeeeeeeeeeee88888888260c8ab |
nonce | 随机字符串, 32字符以内 | 是 | bf7c8674 |
sig | 签名,对query parameter中的参数按照预先约定的顺序排序 (devicename + nonce + productId + timestamp),然后基于 deviceSecret对参数做签 名:hmacsha1(deviceSecretSecret, devicename + nonce + productId + timestamp) | 是 | 0ddddddddd94dd87788888888260c8ab |
timestamp | unix时间戳(毫秒) | 是 | 1546059559999 |
特别说明:获取DeviceName,需要走设备激活流程,请求设备激活接口,接口详情如下:
设备激活接口简介
设备使用前必须的鉴授权环节,设备通过此接口,与DUI产品绑定并获得鉴权秘钥(device profile),后续基于鉴权秘钥与云端进行语音对话请求。设备方需要妥善保管鉴权秘钥,如丢失可调用此接口进行重新获取,重新获取的秘钥与原来的秘钥不相同,且原秘钥会失效。
接口请求地址
https://auth.dui.ai/auth/device/register
接口请求类型
POST
接口请求参数
Headers
参数名 参数值 是否必须 Content-Type application/json 是
Query
参数名 是否必须
示例 备注 productKey 是 0d397453dd94dd87788888888260c8cb 来自dui控制台,产品授权管理页面 format 是 plain
传入plain即可 productId 是 100000001 产品id,来自dui控制台,产品授权管理页面 timestamp 是 1546059559999 unix时间戳(毫秒) nonce 是 bf7c8674 随机字符串,32字符以内 sig 是 0ddddddddd94dd87788888888260c8ab 签名,对query parameter中的参数按照预先约定的顺序排序 (productKey + format+ nonce + product id + timestamp),然后基于product secret对参数做签名:hmacsha1(productSecret,productKey + format+ nonce + product id + timestamp) ,本文末尾有签名示例代码。
Request Body
request body中通过json格式上报设备信息,上报到思必驰的设备信息有三个作用:
1)确认设备的唯一性(针对各种设备的必填字段)
2)方便后续针对不同类型的设备进行优化(针对各种设备的选填字段)
3)查询统计分析,方便客户按照不同维度统计自己设备的激活情况
Android
名称 类型 是否必须
字段说明
示例 platform string 是 平台类型,android设备填android即可
android deviceId string 是 设备ID 5235894f-3028-33f4-a948-c86549cc4808 packageName string 是 包名 com.aispeech.dui.demo applicationLabel string 否 应用名称 DUI Demo applicationVersion string 否 版本 0.1.0-20171031163815 buildVariant string 是 构建类型: debug 或 release release buildSdkInt string 否 framework level 19 displayMatrix string 是 屏幕分辨率 720*1280 buildModel string 是 型号 Coolpad 8675 buildManufacture string 是 制造商 XiaoMi buildDevice string 是 设备名称 8675 imei string 否 IMEI号 356704081123748 mac string 否 MAC地址 44:45:53:54:00:00 androidId string 否 Android ID 9774d56d682e549c
iOS
名称 类型 是否必须 字段说明
备注 platform string 是 平台类型,ios设备填ios即可
ios deviceId string 是 设备ID 0060D69C-AB7A-44E9-8754-7A12EC2AEDAD packageName string 是 包名 com.aispeech.dui.demo applicationLabel string 否 应用名称 DUI Demo applicationVersion string 否 版本 0.1.0-20171031163815 buildSdkInt string 否 framework level level 19 displayMatrix string 否 屏幕分辨率 750x1334 buildModel string 是 型号 iPhone 6 buildManufacture string 是 制造商 Apple buildDevice string 是 设备名称 iPhone
嵌入式
名称
类型 是否必须
字段说明
备注 platform string 是 平台类型,嵌入式设备填嵌入式操作系统或芯片型号即可
linux deviceName string 是 设备名称,要求是接入方所有设备中唯一的一个字段,比如mac地址、uid号等 0060D69C-AB7A-44E9-8754-7A12EC2AEDAD instructionSet string 否 指令集 armv6 chipModel string 否 芯片型号 RK3308
正确返回示例
{ "deviceInfo": { ...... }, "deviceName": "0000-0001", "deviceSecret": "1518b5f911864150a092ba6952be534d", "productId": "666666" }
错误返回示例
{ "errId": 401, "error": "signature mismatch." }
通用http status解释
- 200 ok
- 400 请求错误
- 401 因为权限问题激活失败
- 500 内部系统错误
特别说明
嵌入式设备的请求body里,deivceName字段,需要有唯一性保证,否则如不同设备使用相同的deviceName,第二个激活的设备会使第一个激活设备的设备秘钥失效,可能会对用户体验造成不确定的影响。
附录 签名代码示例
JAVA
String content = productKey + format + nonce + productId + timestamp; String signature = SecureUtil.hmacSha1(productSecret).digestHex(content);
2.2.3 云端对接云端的授权参数
参数名 | 含义 |
是否必须 |
取值示例 |
apikey | DUI控制台生成的绑定过ip的访问标识 |
是 |
0ddddeeeeeeeeeeee88888888260c8ab |
2.2.4 全双工通信的参数
参数名 | 含义 | 是否必须 | 取值示例 |
communicationType |
通信交互类型。 目前只有全双工需要此参数,取值只能为 fullDuplex。 如果采用半双工,则不要带上此参数。 |
否 | fullDuplex |
注意: 上述参数用于判别客户端想采用半双工还是全双工的通信交互方式。
1. 如果客户端采用半双工,则不要带上该参数。
2. 如果客户端采用全双工,则需要带上该参数,且取值必须为 fullDuplex。
2.2.5 一条完整的云端对接云端的连接示例
wss://dds.dui.ai/dds/v2/test?serviceType=websocket&productId=278578090&apikey=0ddddeeeeeeeeeeee88888888260c8ab
注意:以上productId和apikey需要更换为开发者自己创建的产品ID和apikey,否则请求不通过。
2.2.6 在以下情况下建立连接会失败
1)产品没有发布
2)产品分支号没有对应已经发布过的产品版本
3)授权参数不正确,服务端鉴权不通过
2.2.7 正确建立websocket连接的报文
2.3 发送语音请求
websocket连接建立成功之后,调用端首先向服务端发送一个opcode为text的报文;这个报文的payload是一个json字符串。
2.3.1 语音请求text参数
参数名 | 含义 | 是否必须 | 取值示例 |
topic | 用于区分语音请求,文本请求 | 是 | recorder.stream.start |
recordId | uuid,标识一次请求,32字符 | 否 | DUIddeeeeeeeeeeee88888888260c8ab |
sessionId |
uuid,服务端通过相同的sessionId关联多轮请求的上下文; 首轮对话请求不需要携带; 非首轮对话请求取值是上一轮服务端返回结果中的sessionId |
否 | DUIddeeeeeeeeeeee88888888260c8ab |
audio.audioType | 音频类型,推荐使用压缩过的音频格式,以节省带宽,推荐ogg,不支持ogg vorbis,只支持ogg speex | 是 | ogg, wav,mp3,flv,amr,opus |
audio.sampleRate | 音频数据采样率,推荐使用16000; (ogg支持8000、16000;wav支持8000、16000;mp3支持16000、22050、44100;amr支持8000) | 是 | 16000 |
audio.channel | 声道 | 是 | 1 |
audio.sampleBytes | 音频数据每采样点大小 | 是 | 2 |
wakeupWord | 触发当次请求的唤醒词,用于oneshot使用场景 | 否 | 你好小驰 |
asrParams.enableVAD | 是否使用云端vad | 否 | true,false |
asrParams.realBack | 是否使用实时识别结果 | 否 | true,false |
asrParams.enablePunctuation | 识别结果是否开启标点符号 | 否 | true,false |
asrParams.enableTone | 是否使用拼音带声调 | 否 | true,false |
asrParams.enableConfidence | 识别结果是否返回置信度 | 否 | true,false |
asrParams.enableNumberConvert | 识别结果中文数字转成阿拉伯数字 | 否 | true,false |
asrParams.phraseHints | 使用热词识别(pattern要在第二路,或者第三路lm中存在) | 否 | [{"type": "vocab", "name": "行政区", "data":["黄浦区"]}] |
asrParams.enableEmotion |
开启情感识别,返回性别、年龄、情绪 | 否 | true,false |
asrParams.enableAudioDetection |
是否开启云端音频检测,如果未检测到有效音频,则会终止后续对话流程 | 否 | true,false |
asrParams.res |
切换识别生效的语言模型 | 否 | aienglish(此处填写三路模型对应的识别引擎) |
asrParams.vadPauseTime | 支持调用端指定vad在结束语音时采用的静音时长,取值范围是200~2000,单位是ms,默认500ms | 否 | 1000 |
asrParams.enableCloudVAD | 是否开启云端vad检测,开启云端会返回asr.vad.start的topic表示vad start | 否 | true,false |
asrParams.enableProcessedWavTime | 是否开启返回ProcessedWavTime字段 | 否 | true,false |
context.skill.task | 在非首轮中可能用到,用于指定调用端使用了上一轮nbest结果中的哪一个task | 否 | 查天气 |
aiType | 指定云端服务的类型,asr表示识别结果,不设置该字段表示对话结果 | 否 | asr |
asrPlus.enableAsrPlus | 是否开启声纹 | 否 | true,false |
asrPlus.users | 注册的声纹用户列表,开启声纹后此字段必须填 | 否 | ["user1", "user2"] |
asrPlus.organization | 注册的声纹厂商、机构、组织,开启声纹后此字段必须填 | 否 | "AISPEECH" |
2.3.2 语音请求binary数据
调用端发送完opcode为text的报文之后,接着发送语音数据,opcode为binary,payload是语音数据;
语音数据建议分帧发送,每帧包含的语音时长是100毫秒;
语音数据发送完毕之后,再发送一个opcode为binary,payload是空,表示语音数据发送完毕。
2.4 发送文本请求
2.4.1 文本请求参数
参数名 | 含义 | 是否必须 | 取值示例 |
topic | 用于区分语音请求,文本请求 | 是 | nlu.input.text |
recordId | uuid,标识一次请求,32字符 | 否 | DUIddeeeeeeeeeeee88888888260c8ab |
sessionId |
uuid,服务端通过相同的sessionId关联多轮请求的上下文; 首轮对话请求不需要携带; 非首轮对话请求取值是上一轮服务端返回结果中的sessionId |
否 | DUIddeeeeeeeeeeee88888888260c8ab |
refText | 请求的文本 | 是 | 苏州的天气 |
aiType | 指定云端服务的类型,asr表示识别结果,不设置该字段表示对话结果 | 否 | asr |
2.5 发送触发意图请求
2.5.1 触发意图请求参数
参数名 | 含义 | 是否必须 | 取值示例 |
topic | 用于区分语音请求,文本请求,指定意图请求 | 是 | dm.input.intent |
recordId | uuid,标识一次请求,32字符 | 否 | DUIddeeeeeeeeeeee88888888260c8ab |
sessionId |
uuid,服务端通过相同的sessionId关联多轮请求的上下文; 首轮对话请求不需要携带; 非首轮对话请求取值是上一轮服务端返回结果中的sessionId |
否 | DUIddeeeeeeeeeeee88888888260c8ab |
intent | 意图名称 | 是 | 查天气 |
task | 任务名称 | 是 | 查天气 |
skillId | 技能id,和skill两个字段中必须有一个 | 否 | 0000000000000000 |
skill | 技能名称,和skillId两个字段中必须有一个 | 否 | 查天气 |
slots | 语义槽名称,语义槽取值集合 | 否 | {"城市":"苏州"} |
2.6 上传自定义配置
自定义配置配合技能开发进行生效,具体请参照 配置对话回复 中的 资源查询结果引用——$参数名称$。
2.6.1 上传技能级配置
上传的数据仅在指定的技能中使用,如用户微信是否在登录状态。
参数名 | 含义 | 是否必须 | 取值示例 |
topic | string类型,表示技能级配置topic | 是 |
skill.settings |
recordId | string类型,uuid,标识一次请求,32字符 | 否 |
DUIddeeeeeeeeeeee88888888260c8ab |
skillId | string类型,技能ID标识 | 是 |
0000000000000000 |
option | string类型,执行选项,设置、删除或查询 | 否 |
set(默认)/ delete / get |
settings | json数组类型,每个元素标识一组设置的k-v列表 | 是 |
[{"key":"key1","value":"value1"}] |
settings[0].key | string类型,自定义key名称 | 是 |
city |
settings[0].value | string类型,自定义key对应的取值,当option是delete和get时不需要 | 否 |
苏州 |
2.6.2 上传系统级配置
上传的数据是公用的,有多个技能会关心并使用此类配置。如设备所在位置信息。
参数名 | 含义 | 是否必须 | 取值示例 |
topic | string类型,表示系统级设置topic | 是 |
system.settings |
recordId | string类型,uuid,标识一次请求,32字符 | 否 |
DUIddeeeeeeeeeeee88888888260c8ab |
option | string类型,执行选项,设置、删除或查询 | 否 |
set(默认)/ delete / get |
settings | json数组类型,每个元素标识一组设置的k-v列表 | 是 |
[{"key":"key1","value":"value1"}] |
settings[0].key | string类型,自定义key名称 | 是 |
city |
settings[0].value | string类型或者json,自定义key对应的取值,当option是delete和get时不需要 | 否 |
苏州 |
2.6.3 上传配置的响应
参数名 | 含义 | 取值示例 |
recordId | string类型,uuid, 标识一次请求 | DUIddeeeeeeeeee88888888260c8ab |
settings[0].key | option是get时返回,string类型,查询自定义的key名称 | city |
settings[0].value | option是get时返回, string类型,查到的value,如果没查到则是一个null | 苏州 |
error.errId | 错误码,出错时返回 | 1 |
error.errMsg | 错误信息,出错时返回 | params error |
2.7 回复的对话结果(包括触发意图回复结果)
当请求的text报文没有aiType字段时,回复的是对话结果。
2.7.1 对话结果参数
参数名 | 含义 | 取值示例 |
dm.intentName | 意图名称 | 查天气 |
dm.input | 识别结果或者客户端发送的文本 | |
dm.intentId | 意图id | 0000000000000000 |
dm.runSequence | 本地执行command和播报nlg的先后顺序 | nlgFirst |
dm.widget | 显示控件 | |
dm.widget.widgetName | 控件名称,冗余为了兼容老字段 | card |
dm.widget.subTitle | 副标题 | 好听的歌 |
dm.widget.name | 控件名称 | card |
dm.widget.extra | 用于透传webapi返回字段 | |
dm.widget.title | 主标题 | 忘情水 |
dm.widget.buttons[].name | 按钮显示提示 | 播放 |
dm.widget.duiWidget | 控件类型,冗余为了兼容老字段 | media |
dm.widget.type | 控件类型 | media |
dm.widget.count | 列表控件内容数 | 1 |
dm.widget.content | 列表控件内容 | |
dm.widget.currentPage | 列表控件当前页 | 2 |
dm.widget.totalPages | 列表总共页数 | 5 |
dm.widget.itemsPerPage | 每页显示数 | 5 |
dm.widget.match | 内容是否匹配 | 1 |
dm.nlg | 系统生成的对话回复 | 今天的天气是晴 |
dm.task | 任务名称 | 查天气 |
dm.shouldEndSession | 表示对话是否结束 | true,false |
skillId | 技能id | 0000000000000000 |
speakUrl | 语音播报nlg的链接 | https://dds.dui.ai/xxx |
error.errId | 错误id | 010400 |
error.errMsg | 错误信息 | It's time to do qa. |
recordId | uuid,标识一次请求,32字符 | DUIddeeeeeeeeeeee88888888260c8ab |
sessionId |
uuid,服务端通过相同的sessionId关联多轮请求的上下文; 首轮对话请求不需要携带; 非首轮对话请求取值是上一轮服务端返回结果中的sessionId |
DUIddeeeeeeeeeeee88888888260c8ab |
contextId |
向前兼容(sessionId替代了)待废弃 |
2.8 回复的识别结果
当请求的text报文有aiType字段,并且aiType字段为asr时,回复的是识别结果。
2.8.1识别结果参数
参数名 | 含义 | 取值示例 |
recordId | 请求id | DUIddeeeeeeeeeeee88888888260c8ab |
eof | 标识识别是否结束 | 1表示结束,0表示未结束 |
var | 识别中间结果 | 播放 |
text | 识别最终结果 | 播放西游记 |
conf | 置信度,开启enableConfidence后返回 | 1 |
age | 年龄段,开启enableEmotion后返回 |
child 儿童 adult 成人 elder 老人 |
ageScore | 年龄段得分,开启enableEmotion后返回 | 10.31 |
gender | 性别,开启enableEmotion后返回 |
male 男性 female 女性 |
genderScore | 性别得分,开启enableEmotion后返回 | 11.021 |
emotion | 情绪,开启enableEmotion后返回 |
happy 高兴 angry 生气 sad 伤心 neutral 中性 |
emotionScore | 情绪得分,开启enableEmotion后返回 | 10.31 |
audioDetection |
音频检测结果 开启enableAudioDetection后会和rec一起同步返回 |
1, 句子音频包含有效语音 0, 句子音频未包含有效语音 |
processedWavTime | 已处理的有效音频时长,开启enableProcessedWavTime后才会返回 | 1088 |
2.9 声纹结果
当请求参数携带asrPlus,并且开启时,会有声纹相关的topic返回
2.9.1声纹结果参数
参数名
|
含义
|
类型
|
取值示例
|
---|---|---|---|
topic | topic | string | asrplus.voiceprint.result |
recordId | 请求id | string | DUIddeeeeeeeeeeee88888888260c8ab |
sessionId | 会话id | string | 96e446beee364ce4ab8fb7899609861b |
speakerLabels[0].bg | 音频开始时间 | int | 160 |
speakerLabels[0].ed | 音频结束时间 | int | 4380 |
speakerLabels[0].rec | 识别结果 | string | "今天天气怎么样" |
speakerLabels[0].speakerId | 说话人id | string | "100001" |
2.10 VAD结果
当请求中开启了enableCloudVAD后,服务会返回一条特定的响应,表示云端vad start, 报文如下:
参数名 | 含义 | 类型 | 取值示例 |
topic | topic | string | asr.vad.start |
recordId | 请求id | string | DUIddeeeeeeeeeeee88888888260c8ab |
sessionId | 会话id | string | 96e446beee364ce4ab8fb7899609861b |
vadState | vad状态 | int | 1 |
2.11 错误码列表
errId | errMsg | 含义 |
010104 | product info error | 产品id错误 |
010105 | 检测到敏感词 | 检测到敏感词 |
010304 | asr calc service internal error. | 请求识别服务错误 |
010305 | asr result is null | 识别结果为空 |
010306 | asr calc service connect timeout. | 连接识别服务超时 |
010307 | asr calc service close socket. | 识别服务关闭连接 |
010308 | asr calc service socket send error. | 发送识别报文错误 |
010309 | server receive audio in wrong sequence. | 服务收到识别报文乱序 |
010310 | asr calc service server busy. | 识别服务过载 |
010311 | asr calc service audio too large. | 服务收到音频过大 |
010316 | connect asr service error. | 连接识别服务错误 |
010400 | It's time to do qa. | 说法未标注 |
010402 | nlu service error. | 请求语义服务出错 |
010403 | meet exiting command. | 说法命中退出词 |
010404 | no dispatch status. | 技能调度失败 |
010405 | request cnluserver error. | 请求语义服务错误 |
010406 | request oliveserver error. | 请求内置语义服务错误 |
010410 | request body invalid. | 请求中控的body非法 |
010411 | Do not have product info. | 获取不到对应产品信息 |
010412 | Do not have bundle info, can not get skillId. | 获取不到之前上下文信息(execute return信息没有找到之前上下文信息,查询数据返回理论上只出现在非首轮) |
010413 | Do not find this skillId. | 未找到skillId对应技能配置信息(triggerIntent和sysnc接口) |
010414 | Do not contain sessionId. | 请求中控时未携带sessionId |
010415 | Do not contain retry audio. | 命中透传音频技能时,传输音频的body未携带audio数据 |
010501 | connect dm service error. | 请求cdmserver失败 |
010502 | dm service error. | 对话服务内部错误 |
010504 | over max retry times | 错误重试次数超过限制 |
010505 | fallback skill respond ok. | 命中兜底技能 |
010507 | ba skill respond ok. | 命中BA技能 |
010801 | RUYI service error. | 请求RUYI服务错误 |
080002 | webhook timeout. | 请求web api超时 |
080003 | webhook error. | 请求web api错误 |
080004 | Semantic parsing failure | 首轮语义结果为空 |
080005 | Do not support this task | 不支持的技能任务 |
080007 | The input sequence is incorrect | 当前输入不在之前条件输入的下一轮对话列表中 |
080008 | Do not hava asr result | 首轮识别为空;对话中识别为空 |
080010 | Do not hava any matching condition | 定制的输出nlg条件出错 |
080012 | 响应超时,暂时不能为你提供服务 | 本地api调用超时 |
080013 | Api can not be null | 数据源未定义 |
080014 | Retrytime up to maximum | 到达错误重试次数退出 |
080015 | ba timeout | 请求BA服务超时 |
080016 | proxy invalid. | 自定义技能未按协议返回 |
080017 | proxy return empty. | 自定义技能服务返回nlg为空 |
080018 | proxy service error. | 请求自定义技能服务错误 |
080019 | Do not have this intent | 不存在意图的对话资源 |
010700 | request dm dispatcher error. | 请求新中控对话服务错误 |
三、示例代码
3.1多轮对话交互python示例代码
3.2多轮对话交互java示例代码