DSK接入协议

一. DSK协议

1.1 概述

DSK协议为自定义开发过程中需要依赖的协议,本质上规定了开发过程中客户端与服务端数据交互的格式。

1.2 使用场景

适用于有开发运维能力或拥有自有NLP服务的开发者和第三方平台接入。

识别和语义的定制同任务型技能的定制过程一致。

二. 协议接入

2.1 接入流程

1)学习DSK协议,详细了解DSK协议各字段所表达的意思。
2)开发者开发自有服务,根据DSK协议,接收来自DUI技能平台(相当于客户端)发送过来的请求,服务端的主要功能就是解析请求的JSON数据,根据相同字段的不同内容,决定服务端返回的数据。
3)服务端开发完毕并启动,在DUI技能平台填写正确的服务地址,进行测试。参考文档《创建自定义技能》来完成控制台上的配置。

2.2 请求格式

2.2.1 请求参数

JSON格式的请求体参数如下所示,主要包括三部分: request, session, context。
request是与当前请求相关的数据,session是与当前技能会话相关的数据,context是全局共享的数据。详见《DSK协议基本概念

参数 必填(Y/N) 类型 说明
version Y string 协议版本号
session Y object 当前会话信息
session.sessionId Y string 会话唯一标识
session.new N boolean 是否新创建的session,非必须,默认false。true 表示开启新会话
context Y object 全局共享的数据
context.skill Y object 技能信息
context.skill.settings N object 技能级配置
context.user Y object 用户信息
context.device Y object 设备信息
context.product Y object 产品信息
context.system.settings N object 系统级配置
request Y object 当前请求相关的信息,分三种类型start, continue


Start Request

参数 必填(Y/N) 类型 说明
request.type Y string 取值为start
request.requestBodyType Y string 请求内容类型:nluResult, triggerIntent, executeReturn, syncSession等。 以下内容以nluResult举例
request.requestId Y string 请求的唯一标识
request.task Y string 任务名
request.slots Y array 合并后的slots
request.audio N object 音频(base64编码),只有配置了"透传音频"时才有此键
request.inputs Y array 用户语义解析记录列表,按照由远到近排序
request.inputs[].input Y string 用户输入的文本,一般是语音识别结果
request.inputs[].audio N object 音频内容, 只有配置了"透传音频"时才有此键
request.inputs[].audio.content N base64 string 音频(base64编码),只有配置了"透传音频"时才有此键
request.inputs[].slots[].name N string 语义槽名称,其中intent是一种特殊的slot
request.inputs[].slots[].value N string 语义槽取值
request.inputs[].slots[].rawvalue N string 原始value
request.inputs[].slots[].rawpinyin N string 原始value的拼音
request.inputs[].slots[].pos N array value在文本中的位置


Continue Request
与Start Request基本一样, 区别是Continue Request不是第一个请求

参数 必填(Y/N) 类型 说明
request.type Y string 这里取值continue
request.requestBodyType Y string 请求内容类型:nluResult, triggerIntent, executeReturn, syncSession等。 以下内容以nluResult举例
request.requestId Y string 请求标识
request.task Y string 任务名
request.slots Y array 合并后的slots
request.inputs Y array 用户输入的文本, 一般是语音识别结果

 

2.2.2 HTTP请求头

POST /your-skill-path HTTP/1.1
Content-Type : application/json;charset=UTF-8
Host : your.skill.host.com
Accept : application/json
Accept-Charset : utf-8
Authorization : Bearer %BEARER TOKEN%
Content-Length : N

2.2.3 HTTP 请求体

JSON格式的请求体格式如下所示:

{
    "version": "1.0",
    "session": {
        "new": true,
        "sessionId": "this-is-session-id",
        "attributes": {
            "key": "this-is-value"
        }
    },
    "context": {
        "skill": {
            "skillId": "this-is-skill-id",
"settings": { } }, "user": { "userId": "this-is-user-id" }, "device": { "deviceName": "this-is-device-name" }, "product": { "productId": "this-is-product-id", "productVersion":"1" },
"system": {
"settings": { }
} }, "request": {} }

当前request 分三种类型: start, continue:


1)请求体 : Start Request

{
    "version": 1.0,
    "session": {...},
    "context": {...},
    "request": {
        "type": "start",
"requestBodyType": "nluResult", "requestId": "this-is-request-id", "task": "查天气", "slots": [ // 合并后的slots {"name": "intent", "value": "查城市天气"}, {"name": "city", "value": "北京", "rawvalue": "北京", "rawpinyin": "bei jing", "pos": [1, 2]} ], "inputs": [ { "input": "我要查天气", "audio": { // 如果创建技能时,配置了透传音频选项,则请求体中会携带音频信息 "audioType": "ogg", "sampleRate": 16000, "channel": 1, "sampleBytes": 2, "content": "base64_encoded_audio_data" }, "task": "查天气", "timestamp": 1514882440, "slots": [ {"name": "intent", "value": "查城市天气"} ] }, { "input": "北京", "audio": { // 如果创建技能时,配置了透传音频选项,则请求体中会携带音频信息
"audioType": "ogg", "sampleRate": 16000, "channel": 1, "sampleBytes": 2, "content": "base64_encoded_audio_data" }, "task": "查天气", "timestamp": 1514882444, "slots": [ {"name": "intent", "value": "查城市天气"}, {"name": "city", "value": "北京", "rawvalue": "北京", "rawpinyin": "bei jing", "pos": [1, 2]} ] } ] } }


2)请求体 : Continue Request

{
    "version": 1.0,
    "session": {...},
    "context": {...},
    "request": {
        "type": "continue",
"requestBodyType": "nluResult", "requestId": "this-is-request-id", "task": "查天气", "slots": [ // 合并后的slots {"name": "intent", "value": "查城市天气"}, {"name": "city", "value": "北京", "rawvalue": "北京", "rawpinyin": "bei jing", "pos": [1, 2]} ], "inputs": [ { "input": "我要查天气", "audio": { // 如果创建技能时,配置了透传音频选项,则请求体中会携带音频信息
"audioType": "ogg", "sampleRate": 16000, "channel": 1, "sampleBytes": 2, "content": "base64_encoded_audio_data" }, "task": "查天气", "timestamp": 1514882440, "slots": [ {"name": "intent", "value": "查城市天气"} ] }, { "input": "北京", "audio": { //
如果创建技能时,配置了透传音频选项,则请求体中会携带音频信息
"audioType": "ogg", "sampleRate": 16000, "channel": 1, "sampleBytes": 2, "content": "base64_encoded_audio_data" }, "task": "查天气", "timestamp": 1514882444, "slots": [ {"name": "intent", "value": "查城市天气"}, {"name": "city", "value": "北京", "rawvalue": "北京", "rawpinyin": "bei jing", "pos": [1, 2]} ] } ] } }

 

2.3 响应格式

2.3.1 响应参数

第三方平台需要把数据结构化成DUI的数据格式,避免使用null标记空值字段,DUI将会校验关键字段的合法性。

参数 必填(Y/N) 类型 说明
version Y string 版本号
session Y object 上下文信息
response.speak Y object 对话交互中语音播报的内容
response.speak.type Y string 对话输出,音频或者语音合成;"text":纯文本;"audio":音频资源;"ssml":合成SSML标记
response.speak.text N string

合成文本,speak.type是"text"时必须有

注意:和response.speak.ssml只能二选一,两个都填了会出现都不生效的情况

response.speak.audioUrl N string 对话语音输出音频,speek.type为"audio"时必须有
response.speak.ssml N string

用于合成的ssml标记文本,speek.type为"ssml"时必须有

注意:和response.speak.text只能二选一,两个都填了会出现都不生效的情况

response.widget N object 对话交互中要显示的内容, DUI控件包含: 文本(text)、内容卡片(content)、列表(list)、多媒体(media)、内嵌网页(web)、自定义。
response.execute N object 执行本地命令或本地查询, nativecmd没有返回值, nativeapi有返回值(nativeapi保留备用)
shouldEndSession Y boolean 对话是否结束,false:继续对话,true:结束对话
confidence N float 置信度
yield N boolean 是否让出调度权。默认false,如果为true将在DUI技能中再次调度。参考《示例 skill yield&re-dispatch


其中widget包括文本、内容卡片、列表、多媒体、内嵌入网页等,详见文档《DUI控件介绍》 《控件数据格式

2.3.2 正确响应


HTTP 响应头

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Content-Length: N


HTTP 响应体

第三方平台需要把数据结构化成DUI的数据格式。


JSON字符串:
{
    "version": "1.0",
    "session": {
        "nextIntents": ["下一轮意图1","下一轮意图2"],
        "attributes": {...}    // 保留备用      
    },
    "response": {
        "speak": {
            "type": "text",
            "text": "北京晴, 26到32度"
        },
        "widget": {
            "type": "content",
            "name": "the widget name",
            "title": "the title",
 
            "subTitle": "sub-title",
            "label": "label",
            "imageUrl":"URL of the image to be shown",
            "linkUrl":"URL of the attribute to be associated with the card",
            "extra": {
                "key1": "val1",
                "key2": "val2"
            },
            "recommendations": ["推荐说法1", "推荐说法2"]
        },
        "execute": {                                // 执行本地命令或本地查询, 可以有返回值, 也可以没返回值
            "url": "nativecmd://settings/openwifi", // 命令URL, nativecmd没有返回值, nativeapi有返回值
            "args": {                               // 参数
                "arg1": "val1",
                "arg2": "val2"
            }
        }
    },
    "yield": false,
    "shouldEndSession": false,
    "confidence": 0.9
  }
}

2.3.3 异常

使用标准HTTP状态来表达 API 请求的成功或是错误。以下是有可能遇到的HTTP状态:
200:表示请求成功
非200:表示请求失败

2.4 示例demo

2.4.1 下载Python示例

Python 代码下载:
Minion

2.4.2 下载Java示例

Java demo下载:
Minion

2.5 其他说明

2.5.1 注意事项

1)对话回复部分为“接入服务代理”,配置时暂只支持填写web服务地址(即http://、https://),且服务地址必须为服务的公网IP地址,否则DUI网站请求将无法到达开发者的服务地址。
2)提供的Java示例是Spring Boot工程,需开发者自己创建一个工程,模仿示例可以写出一个最简单的demo。Spring Boot基础教程:https://gitee.com/didispace/SpringBoot-Learning
3)Java示例中用到了Redis数据库、fastjson等工具,开发者需要在pom.xml中提供相关依赖:
Minion
4)Java示例中的端口、数据库设置通过application.properties文件设置,开发者可根据实际情况自行设置:
Minion
5) 使用python示例需要安装python3和python3-flask模块,重启脚本,计数会清零。

2.5.2 常见问题

Q1:使用Python示例后,在线测试时,输入调用名,回复出错,查看json时,"nlg" 为 "xxx服务有故障,暂时不能为你提供服务" (XXX为技能名称)

A1:请检查下代码中定制的调用名是否和网站上配置的一致。如果改动了调用名,代码中也同样需要改变。


Q2: 使用Java示例后,在线测试时,回复提示SSM错误

A2: 如果开发者使用的是windows系统,当出现SSM错误时,可以查看是否是因为防火防设置导致无法ping通。


Q3: 使用Java示例后,在线测试时,用调用名唤醒技能成功,但是后续回复为“error”。

A3: 请检查eclipse的报错信息,如果报错信息为“Exception thrown :org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool”, 开发者需要检查是否已安装java redis。