# 消息格式
当设备和 IVS 建立连接之后,设备和 IVS 云端之间通过 HTTP/2 进行通讯。一个典型的交互流程是,设备向云端发出 event(事件)表示当前发生了什么事,云端向设备返回 directive(指令)以告诉设备应该做什么。下图为发送给 IVS 的识别事件,其中 Multipart 消息由两个部分组成:一个 JSON 格式的事件本体,以及一个从设备麦克风捕获的音频数据。
关于创建和维护连接的文档,请参阅传输协议章节。
# HTTP/2 消息头部
每一个向 IVS 发起的请求,都要求以下头部:
Method: {{verb}}
Scheme: https
Path: /{{events or directives}}
Authorization: Bearer {{access_token}}
Content-Type: multipart/form-data; boundary={{boundary_term}}
# Method
iFLYOS支持以下请求方法
POST
向云端发送事件采用POSTGET
用指令建立下行通道采用GET
# Scheme
访问 IVS API 的协议头部为 HTTPS
# Path
所有的事件上报通过以下路径:
Path: /v20180810/events
所有的下行指令订阅通过以下路径:
Path: /v20180810/directives
# 鉴权
当用户授权你的产品代表他们访问 IVS 时,使用讯飞账号登录会返回一个 access_token
。设备调用 IVS 的每一个请求都必须在请求头包含 access_token
。
Authorization: Bearer {{access_token}}
# Content Type
Content-Type
描述的是包含在请求体中的内容。这个描述让 IVS 可以正确地处理请求数据。Content-Type
应当始终为 multipart/form-data
,请求体通过边界符(boundary term)来区分 Multipart 消息的不同部分。在同一个请求中需要保证只使用一个边界符,且不会出现在消息内容中。
Content-Type: multipart/form-data; boundary={{boundary_term}}
# HTTP/2 Multipart 消息
IVS 能接收并处理 HTTP/2 编码的 Multipart 消息。Multipart 消息由一个或多个 JSON 格式的指令/事件以及相关的二进制音频附件(如果需要)组成。
# JSON 头部
每个 Multipart 请求的 JSON 部分都需要以下头部:
Content-Disposition: form-data; name="metadata"
Content-Type: application/json; charset=UTF-8
# JSON 内容
所有发送到iFLYOS的 JSON 格式的事件都按照以下格式:
{
"event":{
"header": {
"namespace": "SpeechRecognizer",
"name": "Recognize",
"messageId": "e52e7a4c...",
},
"payload": {
}
}
}
每一个事件都有唯一的头部(header
)和内容(payload
)。在头部中,namespace
和 name
标识接口和事件,messageId
是设备必须为每个请求生成的唯一标识符。
# 二进制音频头部
每一个携带二进制音频附件的 Multipart 请求需要以下头部:
Content-Disposition: form-data; name="audio"
Content-Type: application/octet-stream
# 二进制音频内容
Multipart 消息的这一部分代表二进制音频,只有识别事件需要携带音频附件。更多相关信息可以查阅 语音识别 接口。
# HTTP/2 响应
IVS 会向你的设备发送两种类型的响应。第一个类型,类似请求,由一个或多个 JSON 格式的指令及其相关的二进制音频附件(如果需要)组成的 Multipart 消息;第二种是异常消息,异常消息不是 Multipart 消息,并且在发送错误时才会返回给设备。每个异常信息包含一个错误代码及一个描述。
# 示例
# 示例 1
该示例展示了一个 Recognize 事件,并且响应内容为一个 Speak 指令。
# 请求
// 注意: HTTP/2 是一种非人类可读的二进制协议,以下消息体仅作示范
Method: POST
Scheme: https
Path: /v20180810/events
Authorization: Bearer {{access_token}}
Content-Type: multipart/form-data; boundary=this-is-a-boundary
--this-is-a-boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json; charset=UTF-8
{
"context": [
{
"header": {
"namespace": "AudioPlayer",
"name": "PlaybackState"
},
"payload": {
"token": "abcd1234",
"offsetInMilliseconds": 7000,
"playerActivity": "PLAYING"
}
},
{
"header": {
"namespace": "Alerts",
"name": "AlertsState"
},
"payload": {
"allAlerts": [
{
"token": "foo-bar",
"type": "ALARM",
"scheduledTime": "2015-10-30T22:34:51+00:00"
}
],
"activeAlerts": [
]
}
},
{
"header": {
"namespace": "Speaker",
"name": "VolumeState"
},
"payload": {
"volume": 25,
"muted": false
}
},
{
"header": {
"namespace": "SpeechSynthesizer",
"name": "SpeechState"
},
"payload": {
"token": "zxcv8523",
"offsetInMilliseconds": 0,
"playerActivity": "FINISHED"
}
}
],
"event": {
"header": {
"namespace": "SpeechRecognizer",
"name": "Recognize",
"messageId": "messageId-123",
"dialogRequestId": "dialogRequestId-321"
},
"payload": {
"profile": "CLOSE_TALK",
"format": "AUDIO_L16_RATE_16000_CHANNELS_1"
}
}
}
--this-is-a-boundary
Content-Disposition: form-data; name="audio"
Content-Type: application/octet-stream
{{音频二进制数据}}
--this-is-a-boundary--
# 响应
Status: 200
Content-Type: multipart/related; boundary=this-is-a-boundary; type="application/json"
--this-is-a-boundary
Content-Type: application/json; charset=UTF-8
{
"directive": {
"header": {
"namespace": "SpeechSynthesizer",
"name": "Speak",
"messageId": "ewq-321",
"dialogRequestId": "dialogRequestId-321"
},
"payload": {
"url": "cid:1234-5678-0123-4567-8901",
"format": "AUDIO_MPEG"
"token": "kr17447380422"
}
}
}
--this-is-a-boundary
Content-Type: application/octet-stream
Content-ID: <1234-5678-0123-4567-8901>
{{binary audio attachment}}
--this-is-a-boundary--
# 示例 2
该示例展示了一个 Recognize 事件,并且响应了一个 Speak 指令和一个 ExpectSpeech 指令。
# 请求
// 注意: HTTP/2 是一种非人类可读的二进制协议,以下消息体仅作示范
Method: POST
Scheme: https
Path: /v20180810/events
Authorization: Bearer {{access_token}}
Content-Type: multipart/form-data; boundary=this-is-a-boundary
--this-is-a-boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json; charset=UTF-8
{
"context": [
{
"header": {
"namespace": "AudioPlayer",
"name": "PlaybackState"
},
"payload": {
"token": "1234",
"offsetInMilliseconds": "15874",
"playerActivity": "PLAYING"
}
},
{
"header": {
"namespace": "Alerts",
"name": "AlertsState"
},
"payload": {
"allAlerts": [
{
"token": "foo-bar",
"type": "ALARM",
"scheduledTime": "2015-10-30T22:34:51+00:00"
}
],
"activeAlerts": [
]
}
},
{
"header": {
"namespace": "Speaker",
"name": "VolumeState"
},
"payload": {
"volume": 25,
"muted": false
}
},
{
"header": {
"namespace": "SpeechSynthesizer",
"name": "SpeechState"
},
"payload": {
"token": "zlkv8723",
"offsetInMilliseconds": 0,
"playerActivity": "FINISHED"
}
}
],
"event": {
"header": {
"namespace": "SpeechRecognizer",
"name": "Recognize",
"messageId": "bnm-123",
"dialogRequestId": "dialogRequestId-201"
},
"payload": {
"profile": "CLOSE_TALK",
"format": "AUDIO_L16_RATE_16000_CHANNELS_1",
}
}
}
--this-is-a-boundary
Content-Disposition: form-data; name="audio"
Content-Type: application/octet-stream
{{音频二进制数据}}
--this-is-a-boundary--
# 响应
Status: 200
Content-Type: multipart/related; boundary=this-is-a-boundary; type="application/json"
--this-is-a-boundary
Content-Type: application/json; charset=UTF-8
{
"directive": {
"header": {
"namespace": "SpeechSynthesizer",
"name": "Speak",
"messageId": "lkj-321",
"dialogRequestId": "dialogRequestId-201"
},
"payload": {
"url": "cid:1234-5678-0123-4567-8901",
"format": "AUDIO_MPEG",
"token": "sn2716057"
}
}
}
--this-is-a-boundary
Content-Type: application/octet-stream
Content-ID: <1234-5678-0123-4567-8901>
{{音频二进制数据}}
--this-is-a-boundary
Content-Type: application/json; charset=UTF-8
{
"directive": {
"header": {
"namespace": "SpeechRecognizer",
"name": "ExpectSpeech",
"messageId": "fyr-212",
"dialogRequestId": "dialogRequestId-201"
},
"payload": {
"timeoutInMilliseconds": 8000
}
}
}
--this-is-a-boundary--
← 传输协议 交互约定(客户端&服务端) →