ASR(语音识别)能力对接说明 #
中控 WebSocket 全双工接口 ASR 调用方式的说明,链接方式为 WebSocket 协议,控制报文为使用 UTF-8 编码的 JSON 文本。
调用流程 #
- 建立 WebSocket 连接(无需鉴权),如果在本地启动中控,地址通常为
ws://localhost:8070/v1; - 发送 Starter 包,内容为后续请求的通用配置信息,如果格式错误或超过 10 秒未发送会被断开 WebSocket 连接;
- 收到响应,表示鉴权成功或失败;
- 发送 Data 二进制数据包,内容为 PCM 音频;
- 音频发送完成后,发送 EOF 包;(可选,不发送则需额外发送 500 毫秒以上的环境静音,帮助 VAD 结束)
- 收到对应ASR结果,格式为 JSON 文本;
- 发送 EOF 请求包的情况下,收到 EOF 结果包,表示所有识别结果发送完毕;
- 如果当前没有更多语音识别任务,可以直接断开(没有链接断开报文的设计);
sequenceDiagram
participant Client
participant CS as Control System
Client-->>CS: 1. Establish Connection
activate CS
Client->>CS: 2. Request: Starter
CS-->>Client: 3. Response: Authentication
loop
Note right of Client: 重复4-7步至全部请求发送完毕
loop
Note right of Client: 按规定频率发送多个音频包
Client->>CS: 4. Request: Data
end
Client->>CS: 5. Request: EOF (optional)
CS-->>Client: 6. Response
CS-->>Client: 7. Response: EOF (optional)
end
Client-->>CS: 8. Close Connection
deactivate CS
请求报文格式 #
Starter #
每次建立连接后发送的第一个包,表示此连接的目的和后续数据包的解析方式。格式为 JSON 文本,包含以下字段:
| 字段 | 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
auth | AuthN Token | string | 空字符串 | 设备鉴权 Token,如服务端开启鉴权则必填 |
type | Workflow Type | string | 必填 | 填写能力对应的服务引擎编号,例如:“ASR5”,完整列表参见快速参考的服务引擎列表部分 |
device | Device ID | string | 空字符串 | 设备 ID,建议填写,以便追溯和定位问题 |
session | Session ID | string | 随机 UUIDv4 | 建议调用者自行生成 Session ID 并填写,以便追溯和定位问题 |
asr | ASR Config | object | 必填 | ASR 专属配置,具体信息见下 |
ASR Config 配置见下:
| 字段 | 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
language | Language Code | string | zh-CN | 可选字段,待识别的语言 |
mic_volume | Microphone Volume | float | 1.0 | 可选字段,麦克风音量用于 ASR 进行自增益,支持范围为 0 到 1 |
subtitle | Subtitle Format | string | 空字符串 | 可选字段,返回字幕的格式,空表示不返回,支持:srt |
subtitle_max_length | Subtitle Max Length | int | 0 | 可选字段,返回每行字幕/句级别时间戳的最大字数,0表示不限制字数,仅在返回字幕或返回句级别时间戳时有效 |
subtitle_cut_by_punc | Subtitle Cut by Punctuation | bool | false | 可选字段,是否根据标点符号对字幕/句级别时间戳进行换行并去掉标点,仅在返回字幕或返回句级别时间戳时有效。标点符号范围见 字幕换行标点符号 |
subtitle_custom_punc | Custom Subtitle Punctuation | string list | 字幕换行标点符号 | 可选字段,使用自定义用于换行的标点符号,而不使用默认的标点符号,仅在返回字幕或句级别时间戳且 subtitle_cut_by_punc 为 true 时有效。 |
subtitle_punc_keep | Keep Subtitle Punctuation | bool | false | 可选字段,是否保留换行的标点符号,仅在返回字幕或句级别时间戳且 subtitle_cut_by_punc 为 true 时有效。 |
intermediate | Return Intermediate Result | bool | false | 可选字段,是否返回中间结果 |
sentence_time | Return Sentence-Level Timestamp | bool | false | 可选字段,是否返回句级别时间戳 |
word_time | Return Word-Level Timestamp | bool | false | 可选字段,是否返回字级别时间戳 |
cache_url | Return Cache URL for Data | bool | false | 可选字段,是否将字幕文件上传 Object Store 存储并返回缓存 URL |
pause_time_msec | Speech Pause Time (msec) | int | 500 | 可选字段,语音暂停时间,用于判断语音的边界和分段,默认为500毫秒 |
Data #
Starter 包发送并成功建立连接后,后续可重复发送多个二进制 Data 包流式提交音频。
输入的音频流格式为 PCM,使用 16KHz 采样率,16bit 数据位宽,单通道,小端。即 sox -t raw -r 16000 -e signed -b 16 -c 1 可转格式,或 ffmpeg -acodec pcm_s16le -ac 1 -ar 16000 -f s16le 可转格式。
流式与非流式 ASR 对于音频的发送速率要求不同:
- 流式 ASR:音频按照从麦克风读取的速率发送,建议为每 40 毫秒发送 1280 字节,或每 160 毫秒发送 5120 字节。
- 非流式 ASR:音频数据可以一次性发送,每个 Data 包的大小限制在 1920KB(1 分钟) 以内。
EOF #
音频包发送完成后,发送 EOF 包,表示结束识别
流式与非流式 ASR 对于 EOF 包的用法要求不同:
- 流式 ASR:音频 Data 包发送完成后,发送 EOF 包。可选,不发送则需额外发送 500 毫秒以上的环境静音,帮助 VAD 结束。
- 非流式 ASR:音频 Data 包发送完成后,必须发送 EOF 包。
如果需要获取字幕,无论是否为流式,都必须发送 EOF 包,以通知 ASR 服务端进行字幕生成。
格式为 JSON 文本,包含以下字段:
| 字段 | 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
signal | 结束标记 | string | 必填 | 固定为 eof |
trace | Trace ID | string | 随机 UUIDv4 | 可选字段,建议调用者自行生成 Trace ID 并填写,以便追溯和定位问题 |
返回报文格式 #
鉴权结果 #
发送 Starter 请求后会返回包含鉴权结果的报文。格式为 JSON 文本,包含以下字段:
| 字段 | 名称 | 类型 | 是否必现 | 说明 |
|---|---|---|---|---|
service | Service Name | string | Yes | 当前请求对应的服务模块,即auth |
session | Session ID | string | Yes | 当前连接的 Session ID |
status | Status Name | enum | Yes | 当前会话的状态,正常为 ok,失败为 fail |
error | Error Message | string | No | 如果失败,返回的错误信息 |
ASR 结果数据 #
ASR会持续返回多个文字识别结果数据包,并在收到 EOF 请求后返回字幕、字幕文件地址数据包。如果在 Starter 请求中未要求返回字幕和字幕地址,则仅返回文字识别结果。
返回报文的格式为 JSON 文本,包含以下字段:
| 字段 | 名称 | 类型 | 是否必现 | 说明 |
|---|---|---|---|---|
service | Service Name | string | Yes | 当前请求对应的服务模块,即asr |
session | Session ID | string | Yes | 当前连接的 Session ID |
trace | Trace ID | string | Yes | 当前句子对应的 Trace ID |
status | Status Name | enum | Yes | 当前会话的状态,正常为 ok,失败为 fail |
error | Error Message | string | No | 如果失败,返回的错误信息 |
asr | ASR Content | object | No | 如果成功,返回的识别结果,具体字段含义见下 |
具体识别结果位于 ASR Content 中:
| 字段 | 名称 | 类型 | 是否必现 | 说明 |
|---|---|---|---|---|
index | Index No. | int | Yes | 返回包序列号 |
type | Package Type | enum | Yes | 文字结果包为 text,中间结果包为 intermediate,字幕包为 subtitle,字幕地址包为 subtitle_url,表示全部发送完毕为 eof |
text | Text | string | Yes | 文字识别结果,在字幕包中亦会出现,但内容为空 |
subtitle | Subtitle | string | No | 字幕内容,仅在字幕包中有 |
subtitle_url | Subtitle URL | string | No | 字幕内容下载地址,仅在字幕包中有 |
sentence_time | Sentence-Level Timestamp | object | No | 句子级别时间戳 |
word_times | Word-Level Timestamp | object | No | 字级别时间戳 |
文字结果 #
每句被完整识别的文字都会返回一条报文,中间识别结果不返回,如果无法识别或识别结果为空白字符,亦不返回。
文字结果样例:
{
"service": "asr",
"status": "ok",
"session": "eab708a8-7aca-4237-a0a3-a6422ade8a23",
"trace": "c9cb36d8-3ca9-4e2b-9034-29f2c4edc3de",
"asr": {
"index": 1,
"type": "text",
"text": "你好。"
}
}
字幕结果 #
请求字幕且发送 EOF 后,返回生成的字幕结果。
字幕结果样例:
{
"service": "asr",
"status": "ok",
"session": "eab708a8-7aca-4237-a0a3-a6422ade8a23",
"trace": "9a971f17-f871-4b73-9084-b856b67537d5",
"asr": {
"index": 3,
"type": "subtitle",
"subtitle": "1\n00:00:00,000 --> 00:00:01,280\n你好。\n\n2\n00:00:02,960 --> 00:00:04,240\n再见。\n\n"
}
}
字幕地址 #
请求字幕、请求 Cache URL、且发送 EOF 后,返回上传 Object Store 存储的字幕文件缓存 URL。
{
"service": "asr",
"status": "ok",
"session": "eab708a8-7aca-4237-a0a3-a6422ade8a23",
"trace": "25b30001-0b5a-4e9e-892c-4cc4d5bf134d",
"asr": {
"index": 4,
"type": "subtitle_url",
"subtitle_url": "https://aigc.blob.core.chinacloudapi.cn/audio/asr-srt/eab708a8-7aca-4237-a0a3-a6422ade8a23_25b30001-0b5a-4e9e-892c-4cc4d5bf134d.srt"
}
}
EOF #
收到 EOF 请求的情况下,发送 EOF 结果包,表示结果全部发送完毕。
EOF 样例:
{
"service": "asr",
"status": "ok",
"session": "eab708a8-7aca-4237-a0a3-a6422ade8a23",
"trace": "16ff049a-41fb-4c7a-ac5e-b26dbc3218e5",
"asr": {
"index": 5,
"type": "eof"
}
}
实际流程样例解析 #
Case 1: 最小配置流程 #
Request: Starter
{
"type": "ASR5",
"asr": {}
}
Request: 二进制 Data 略
Response: 1
{
"service": "auth",
"status": "ok",
"session": "4ea613f2-b1d4-47cf-8033-db59aae66721"
}
Response: 2
{
"service": "asr",
"session": "4ea613f2-b1d4-47cf-8033-db59aae66721",
"trace": "e1c44bdc-4f9a-487c-806e-005679db7d0d",
"asr": {
"index": 1,
"type": "text",
"text": "早知道你喜欢十里春光"
}
}
Response: 3
{
"service": "asr",
"session": "4ea613f2-b1d4-47cf-8033-db59aae66721",
"trace": "f7551818-5025-4d83-b41b-136bb19b5b5f",
"asr": {
"index": 2,
"type": "text",
"text": "我一定会在麦田里种满玫瑰和山茶"
}
}
Response: 4
{
"service": "asr",
"session": "4ea613f2-b1d4-47cf-8033-db59aae66721",
"trace": "89d3a8b4-a291-4cdc-9b78-d3f912d06223",
"asr": {
"index": 3,
"type": "text",
"text": "你路过这片土地才算浪漫"
}
}
Case 2: 完整配置流程 #
Request: Starter
{
"auth": "XSMLTGKQVVCPJCQHJZ4VEDMGIY",
"type": "ASR5",
"session": "8f97055c-bd29-41c7-92d1-3933fed566fa",
"asr": {
"subtitle": "srt",
"cache_url": true,
"intermediate": true,
"mic_volume": 0.67
}
}
Response: 1
{
"service": "auth",
"status": "ok",
"session": "8f97055c-bd29-41c7-92d1-3933fed566fa"
}
Request: 二进制 Data 略
Request: EOF
{
"signal": "eof",
"trace": "52517513-875a-47b6-bd30-f11a75e26745"
}
Response: 2
{
"service": "asr",
"status": "ok",
"session": "8f97055c-bd29-41c7-92d1-3933fed566fa",
"trace": "dcf88fbe-6cda-452d-8f51-e316cb4a0943",
"asr": {
"index": 1,
"type": "intermediate",
"text": "介"
}
}
Response: 3
{
"service": "asr",
"status": "ok",
"session": "8f97055c-bd29-41c7-92d1-3933fed566fa",
"trace": "879d4700-746f-411b-954c-f83a2c6cd300",
"asr": {
"index": 2,
"type": "intermediate",
"text": "介绍下长"
}
}
Response: 4
{
"service": "asr",
"status": "ok",
"session": "8f97055c-bd29-41c7-92d1-3933fed566fa",
"trace": "20e6a5e5-6d5d-4284-9013-4d410f1a5d37",
"asr": {
"index": 3,
"type": "intermediate",
"text": "介绍下长宁图书"
}
}
Response: 5
{
"service": "asr",
"status": "ok",
"session": "8f97055c-bd29-41c7-92d1-3933fed566fa",
"trace": "cf7733e2-da28-442d-b5bb-282fc8f352f3",
"asr": {
"index": 4,
"type": "text",
"text": "介绍一下长宁图书馆。",
"sentence_time": {
"begin_ms": 2080,
"end_ms": 4640
},
"word_times": [
{
"begin_ms": 2080,
"end_ms": 2560,
"text": "介"
},
{
"begin_ms": 2560,
"end_ms": 2800,
"text": "绍"
},
{
"begin_ms": 2800,
"end_ms": 2920,
"text": "一"
},
{
"begin_ms": 2920,
"end_ms": 3040,
"text": "下"
},
{
"begin_ms": 3040,
"end_ms": 3280,
"text": "长"
},
{
"begin_ms": 3280,
"end_ms": 3480,
"text": "宁"
},
{
"begin_ms": 3480,
"end_ms": 3640,
"text": "图"
},
{
"begin_ms": 3640,
"end_ms": 3880,
"text": "书"
},
{
"begin_ms": 3880,
"end_ms": 4640,
"text": "馆"
}
]
}
}
Response: 6
{
"service": "asr",
"session": "8f97055c-bd29-41c7-92d1-3933fed566fa",
"trace": "3dcafe20-d6e0-4bce-a2ba-932b442e9e92",
"asr": {
"index": 5,
"type": "subtitle",
"subtitle": "1\n00:00:00,000 --> 00:00:02,280\n介绍一下长宁图书馆\n\n"
}
}
Response: 7
{
"service": "asr",
"session": "8f97055c-bd29-41c7-92d1-3933fed566fa",
"trace": "3dcafe20-d6e0-4bce-a2ba-932b442e9e92",
"asr": {
"index": 6,
"type": "subtitle_url",
"subtitle_url": "https://aigc.blob.core.chinacloudapi.cn/audio/asr-srt/8f97055c-bd29-41c7-92d1-3933fed566fa_3dcafe20-d6e0-4bce-a2ba-932b442e9e92.srt"
}
}
Response: 8
{
"service": "asr",
"session": "8f97055c-bd29-41c7-92d1-3933fed566fa",
"trace": "2bd4cbce-0f72-402c-8e88-0f2704a22868",
"asr": {
"index": 7,
"type": "eof"
}
}