版本:1.0.1-alpha
本文是对在 Rokid 开发者社区 上开发 CloudApp 的协议的详细描述。
在了解本文所描述协议之前,需要对以下概念作如下说明:
Request 是 CloudDispatcher 产生的用于向 CloudApp 获取对应返回结果的请求。目前有两种类型的请求:一种是 IntentRequest,一种是 EventRequest。IntentRequest 是根据语音识别和语义理解(NLP)的结果创建的,其中会带有(NLP)的信息。EventRequest 是在当有某种事件发生时产生的,并通过 CloudDispatcher 转发给当前 CloudApp,比如当某个TTS播放结束的时候会产生一个 TTS 结束的事件,当前 CloudApp 可以选择处理或者不处理。
为了保证 Https 链接访问的安全性,在 http 请求的 hearder 中增加了 Singature 来校验请求是否来源于 Rokid。
Http Hearder 中相关内容的示例如下:
Content-Type: application/json;charset=utf-8
Signature: DAF1E1062C21E3BB80A55BA32F41D935
您可以在「技能开发的-配置」中,填写您自定义的认证 key(支持大小写英文和数字,最长不超过36位)。
认证 key 的生成规则为:
Signature = MD5(Secret + MD5(Body))
Request 的整体协议定义如下所示:
{
"version": "2.0.0",
"session": {
"sessionId": "D75D1C9BECE045E9AC4A87DA86303DD6",
"newSession": true,
"attributes": {
"key1": {"type":"","value":""}
}
},
"context": {
"application": {
"applicationId": "skill 本身的 Id",
"media": {
"state": "PLAYING/PAUSED/IDLE",
"itemId": "Skill 响应的 MediaId",
"token": "Skill 响应的 MediaToken",
"progress": "当前的播放进度单位毫秒",
"duration": "当前 Media 的总长度单位毫秒"
},
"voice": {
"state": "PLAYING/PAUSED/IDLE",
"itemId": "Skill 响应的 VoiceId"
}
},
"device": {
"basic": {
"vendor": "注册生产商 ID",
"deviceType": "该生产商设定的设备型号",
"deviceId": "该型号下的设备 ID",
"masterId": "设备主人 ID",
"voicetrigger": "设备当前的激活词",
"locale": "zh-cn",
"timestamp": 1478009510909
},
"screen": {
"x": "640",
"y": "480"
},
"media": {
"state": "PLAYING / PAUSED / IDLE"
},
"voice": {
"state": "PLAYING / PAUSED / IDLE"
},
"location": {
"latitude": "30.213322455923485",
"longitude": "120.01190010997654",
"country": "国家",
"state": "州/省份",
"city": "城市",
"area": "区县",
"district": "地区,行政",
"street": "街道",
"timeZone": "时区"
}
},
"user": {
"userId": "当前用户的ID"
}
},
"request": {
"reqType": "INTENT / EVENT",
"reqId": "当前请求的 Id",
"content": {
"intent": "play_random",
"sentence": "用户语句",
"slots": {
"key1":{"type":"","value":""},
"key2":{"type":"","value":""}
}
}
}
}
Session 向所请求的 CloudApp 表明了会话的信息,每一次对 CloudApp 的请求都会产生会话信息,会话的信息和状态由开放平台的系统更新。Session 也提供了 attributes 字段留给 CloudApp 来保存一些上下文信息。具体阐述如下:
"session": {
"sessionId": "D75D1C9BECE045E9AC4A87DA86303DD6",
"newSession": true,
"attributes": {
"key1": {"type":"","value":""}
}
}
字段 | 类型 | 可能值 |
---|---|---|
sessionId | string | 每次会话的唯一ID,由系统填充 |
newSession | boolean | true / false (由系统填充) |
attributes | key-object map | 一个string-object map |
Context 向所请求的 CloudApp 提供了当前的设备信息,用户信息和应用状态,用以帮助 CloudApp 更好的去管理逻辑状态以及对应的返回结果。
"context": {
"application": {},
"device": {},
"user": {}
}
字段 | 类型 | 可能值 |
---|---|---|
application | ApplicationInfo object | ApplicationInfo 对象 |
device | DeviceInfo object | DeviceInfo 对象 |
user | UserInfo object | UserInfo 对象 |
ApplicationInfo 包含了当前的应用信息,目前有 applicationId、media、voice 可用。
"application": {
"applicationId": "application id for requested CloudApp",
"media": {},
"voice": {}
}
字段 | 类型 | 可能值 |
---|---|---|
applicationId | string | 应用 ID 字符串 |
media | object | mediaInfo 对象 |
voice | object | voiceInfo 对象 |
DeviceInfo 是对此次请求发生时当前设备信息的描述。
"device": {
"basic":{},
"screen":{},
"media": {},
"voice": {},
"location": {}
}
字段 | 类型 | 可能值 |
---|---|---|
basic | BasicInfo object | BasicInfo 对象 |
screen | ScreenInfo object | ScreenInfo 对象 |
media | MediaStatus object | 当前设备上 CloudAppClient 的 MediaPlayer 状态 |
location | LocationInfo object | 当前设备的地理位置信息 |
"basic":{
"vendor":"vendor id",
"deviceType":"device type",
"deviceId": "010116000100",
"masterId": "设备主人ID",
"voicetrigger": "设备当前的激活词",
"locale": "zh-cn",
"timestamp": 1478009510909
}
字段 | 类型 | 可能值 |
---|---|---|
vendor | string | 注册生产商 ID |
deviceType | string | 该生产商设定的设备型号 |
deviceId | string | 该型号下的设备 ID |
masterId | string | 对应设备的主人 ID |
voicetrigger | string | 对应设备当前的激活词 |
locale | string | 国家及语言,标准 locale 格式 |
timestamp | long | 当前时间,unix timestamp |
当前设备显示的设备信息:
"screen":{
"x":"640",
"y":"480"
}
字段 | 类型 | 可能值 |
---|---|---|
x | string | X 方向上的像素大小 |
y | string | Y 方向上的像素大小 |
当前设备上 CloudAppClient 中 MediaPlayer 的状态:
"media": {
"state": "PLAYING / PAUSED / IDLE"
}
字段 | 类型 | 可能值 |
---|---|---|
state | string | PLAYING / PAUSED / IDLE |
"location": {
"latitude": "30.213322455923485",
"longitude": "120.01190010997654",
"country": "国家",
"state": "州/省份",
"city": "城市",
"area": "区县",
"district": "地区,行政",
"street": "街道",
"timeZone": "时区"
}
当当前设备存在地理位置信息时会通过 location 提供给 CloudApp。基于地理位置的 CloudApp 可以根据此信息来处理逻辑。location 信息包括 纬度(latitude) 和 经度(longtitude) 等。
UserInfo 展示了与当前的用户信息,通常是设备对应手机应用的账号。
"user": {
"userId": "user id string"
}
字段 | 类型 | 可能值 |
---|---|---|
userId | string | 用户 ID |
注意:该用户 id 和 MasterId 的区别在于,用户 Id 为当前使用者的 Id,MasterId 为机器主人的 ID,机器主人不一定是当前使用的用户,目前 UserId 和 MasterId 是一致的,但后期上了声纹以后该两者会不一致。
Request 是当前请求的真正内容:
"request": {
"reqType": "INTENT / EVENT",
"reqId": "string",
"content": {}
}
字段 | 类型 | 可能值 |
---|---|---|
reqType | string | INTENT / EVENT |
reqId | string | 当前请求的唯一 ID |
content | request content object | IntentRequest 或 EventRequest 的对象 |
IntentRequest 是基于 NLP 的结果产生的请求,其中包括了 NLP 的所有信息:ApplicationId, Intent 和 Slots。IntentRequest 将会发给对应的 CloudApp 根据 intent 和 slots 进行相应的逻辑处理。
"content": {
"applicationId": "com.rokid.cloud.music",
"intent": "play_random",
"slots": {
"key1":{"type":"","value":""},
"key2":{"type":"","value":""}
}
}
字段 | 类型 | 可能值 |
---|---|---|
intent | string | CloudApp 对应的 nlp intent |
slots | object | CloudApp 对应的 nlp slots 对象 |
sentence | string | CloudApp 对应的 用户说的话 |
intent - 表明了当前具体的意图,目前我们有三个系统级的 Intent 请求具体如下。
"content": {
"slots": {
"domain": {
"type": "app",
"value": "domainid"
},
"openaction": {
"type": "openaction",
"value": "打开"
}
},
"intent": "ROKID.INTENT.WELCOME",
"sentence": "打开XXX"
}
开发者可以在这个 Intent 中给用户做欢迎引导语句也可以执行对应的操作
"content": {
"intent": "ROKID.INTENT.EXIT",
"sentence": "退出XXX",
"slots": {
"closeaction": {
"type": "closeaction",
"value": "退出"
},
"domain": {
"type": "app",
"value": "domainid"
}
}
}
开发者不能对该 Request 做响应,但是开发者可以通过该 Request 记录服务的业务日志
"content": {
"intent": "ROKID.INTENT.UNKNOWN",
"sentence": "用户说的话",
"slots": {
"asrvalue": {
"type": "asrvalue",
"value": "用户说的话"
},
"unknowtype": {
"type": "unkonwtype",
"value": "pickup"
}
}
}
开发者可以在该 Request 请求时响应自定义的响应内容,比如游戏类的技能,可以换一个题目等操作,然后开发者也可以直接退出该技能,unknowtype 有两种一个是 pickup,一个是 confirm
slots 是对象类型,含有如下两个字段:
字段 | 类型 | 说明 |
---|---|---|
type | String | slot类型 |
value | String | slot值 |
注意:Slots 对象其实对应的是一个 HashMap<String,Slot>,其实 Slot 目前有 type 和 value 两个字段。其中 HashMap的key 是当前 NLP 那边配置的 slot 名称,Slot 里面的 Type 值分为两种情况: 1、有引用系统词表,则该 type 为系统词表的名称; 2、如果没有引用系统词表,则和 key 一致为用户自定义名称,Slot 里面的 value 为用户真正需要的业务值,该值是一个 String 类型,但是需要注意的是该 String 有可能是一个 Json 的 String,开发者需要根据 Type 去进行数据的解析。如下 number 这个 slot 的定义响应
"slots": {
"number": {
"type": "ROKID.NUMBER_ZH",
"value": "{\"number\":\"3.000000\",\"text\":\"三\"}"
}
当 CloudAppClient 在执行中发生了一个事件,则会产生一 个 EventRequest。CloudApp 可以根据自己的需要选择处理或者不处理当前收到的事件。
"content": {
"event": "Media.NEAR_FINISH",
"extra": {
"key1": "value1",
"key2": "value2"
}
}
字段 | 类型 | 可能值 |
---|---|---|
event | string | 事件类型 |
extra | string-string map | 自定义字段,目前暂无定义,作扩展用 |
特别注意:为防止开发者在我们后续增加 Event 事件的时候出现服务异常,建议开发者对于不在自己 Skill 范围之内的 Event 做忽略处理,忽略响应的内容如下:
{
"version": "2.0.0",
"session": {
},
"response": {
"action": {
"version": "2.0.0",
"type": "NORMAL",
"shouldEndSession": false,
"directives": [
]
}
}
}
"content": {
"event": "Media.PAUSED",
"extra": {
"media": {
"itemId":"MediaItem 里面的 ItemId",
"token": "MediaItem 里面的 token",
"progress": "当前进度",
"duration": "音频文件的总长度"
}
}
}
"content": {
"event": "Voice.STARTED",
"extra": {
"voice": {
"itemId":"voiceItem 里面的 ItemId"
}
}
}
根据之前的描述,Response 是 CloudApp 向客户端的返回结果。
整体协议示例如下:
{
"version": "2.0.0",
"session": {
"attributes": {
"key1": {"type":"","value":""}
}
},
"response": {
"card": {
"type": "ACCOUNT_LINK"
},
"action": {
"version": "2.0.0",
"type": "NORMAL / EXIT",
"form": "scene/cut/service",
"shouldEndSession": true,
"directives": [
{
"type":"voice",
"action": "PLAY/PAUSE/RESUME/STOP",
"disableEvent":false,
"item": {
"itemId":"string of itemid",
"tts": "tts content"
}
},
{
"type":"media",
"action": "PLAY/PAUSE/RESUME/STOP",
"disableEvent":false,
"item": {
"itemId":"string of itemid",
"token": "xxxx",
"type": "AUDIO/VIDEO",
"url": "media streaming url",
"offsetInMilliseconds": 0
}
},
{
"type":"display",
},
{
"type":"confirm",
"confirmIntent": "nlp intent to confirm",
"confirmSlot": "nlp slot to confirm",
"optionWords": [
"word1",
"word2"
]
},
{
"type":"pickup",
"enable": true,
"durationInMilliseconds": 1000
}
]
}
}
}
2.0.0
.card
和 action
两个部分。Card 用于向 Rokid App 推送 push 消息。目前支持两种卡片类型:
ACCOUNT_LINK
类型chat
类型更多card功能类型将在后续更新。
Account_link 类型将会向 Rokid App 发送一张账户授权的卡片,用于用户使用 Rokid 账号进行 Oauth 登录。如下:
{
"response": {
"card" : {
"type" : "ACCOUNT_LINK",
},
"action": {···},
···
}
}
字段 | 类型 | 可能值 |
---|---|---|
type | string | ACCOUNT_LINK |
Chat 类型将会向 Rokid App 发送一张无标题的纯文本卡片,用于展示若琪向用户说出的 TTS 内容。如下:
{
"response": {
"card" : {
"type" : "chat",
"content" : "自定义词汇"
},
"action": {···},
···
}
}
字段 | 类型 | 可能值 |
---|---|---|
type | string | chat |
content | string | 需要在手机 APP 收到的卡片中展示的 TTS 语句 |
Action 中最关键的部分是 directives
,其中包含:
voice
表示了语音交互的返回;media
是对媒体播放的返回;confirm
表示对特定语句进行确认时的返回;pickup
表示需要设备继续拾音时的返回。"action": {
"version": "2.0.0",
"type": "NORMAL / EXIT",
"form": "scene/cut/service",
"shouldEndSession": true,
"directives": [
{
"type":"voice",
},
{
"type":"media",
},
{
"type":"display",
//todo
},
{
"type":"confirm",
},
{
"type":"pickup",
}
]
}
}
字段 | 类型 | 可能值 |
---|---|---|
version | string | action 协议的版本,当前为 2.0.0 |
type | string | NORMAL / EXIT |
form | string | scene / cut / service |
shouldEndSession | boolean | true / false |
directives | array | directives 对象 |
NORMAL
或 EXIT
。 当 type
是 NORMAL
时,voice
和 media
会同时执行;当 type
是 EXIT
时,action 会立即退出,清除系统端的应用 session,并且在这种情况下,voice
和 media
将会被忽略。shouldEndSession
为 true
时,CloudAppClient 将会忽略 EventRequests,即在 action 执行过程中不会产生 EventRequest。voice
, media
, confirm
, pickup
四种类型。Voice 定义了 CloudApp 返回的语音交互内容。具体定义如下:
{
"type":"voice",
"action": "PLAY/PAUSE/RESUME/STOP",
"disableEvent":false,
"item": {
"itemId":"string of itemid",
"tts": "tts content"
}
字段 | 类型 | 可能值 |
---|---|---|
action | string | PLAY / PAUSE / RESUME / STOP |
disableEvent | boolean | 是否需要关闭 Event 事件的接收 |
item | item object | voice 的 item 对象 |
Item 定义了 voice 的具体内容。
"item": {
"itemId":"string of itemid",
"tts": "tts content"
}
字段 | 类型 | 可能值 |
---|---|---|
itemId | string | tts 内容的 ID |
tts | string | tts 内容 |
Media 用来播放 CloudApp 返回的流媒体内容。有 audio 和 video 两种类型,目前第一版暂时只对 audio 作了支持,后续会支持 video。
{
"type":"media",
"action": "PLAY/PAUSE/RESUME/STOP",
"disableEvent":false,
"item": {
"itemId":"string of itemid",
"token": "xxxx",
"type": "AUDIO/VIDEO",
"url": "media streaming url",
"offsetInMilliseconds": 0
}
}
字段 | 类型 | 可能值 |
---|---|---|
action | string | PLAY / PAUSE / RESUME / STOP |
disableEvent | boolean | 是否需要关闭 Event 事件的接收 |
item | media item object | media 的具体内容 |
"item": {
"itemId":"string of itemid",
"token": "xxxx",
"type": "AUDIO/VIDEO",
"url": "media streaming url",
"offsetInMilliseconds": 0
}
字段 | 类型 | 可能值 |
---|---|---|
itemId | string | Media 内容的 ID |
token | string | 用于鉴权的 token,由 CloudApp 填充和判断 |
type | string | AUDIO / VIDEO |
url | string | 可用的流媒体播放链接 |
offsetInMilliseconds | long | 毫秒数值,表明从哪里开始播放 |
表明此次返回中,是否存在需要 confirm 的内容。了解用法指南。
{
"type":"confirm",
"confirmIntent": "nlp intent to confirm",
"confirmSlot": "nlp slot to confirm",
"optionWords": [
"word1",
"word2"
]
}
字段 | 类型 | 可能值 |
---|---|---|
confirmIntent | string | 需要进行 confirm 的 intent 内容 |
confirmSlot | string | 需要进行 confirm 的 slot 内容 |
optionWords | array | 动态新增的 confirm 内容 |
Pickup 用来控制拾音状态(可以理解为手机app上的对话框)。当 CloudApp 没有可执行的内容时,会执行 Pickup,如果 Pickup 为空,则按照 Pickup.enable=false 执行。
{
"type":"pickup",
"enable": true,
"durationInMilliseconds": 1000,
"retryTts":"自定义语句"
}
字段 | 类型 | 可能值 |
---|---|---|
enable | boolean | true / false |
durationInMilliseconds | int | 在没有用户说话时拾音状态持续多久,单位毫秒 |
retryTts | string | 定义在 pickup 未命中或超时后将会提示的语句 |