{
"event": "task_start",
"model": "speech-2.8-turbo",
"language_boost": "Chinese",
"voice_setting": {
"voice_id": "male-qn-qingse",
"speed": 1,
"vol": 1,
"pitch": 0
},
"pronunciation_dict": {
"tone": [
"处理/(chu3)(li3)",
"危险/dangerous"
]
},
"audio_setting": {
"sample_rate": 32000,
"bitrate": 128000,
"format": "mp3",
"channel": 1
},
"session_id": "my-session-001"
}{
"event": "task_continue",
"text": "真正的危险不是计算机开始像人一样思考(sighs),而是人开始像计算机一样思考。计算机只是可以帮我们处理一些简单事务。"
}{
"event": "task_cancel"
}{
"event": "task_flush"
}{
"event": "task_finish"
}{
"session_id": "xxxx",
"event": "connected_success",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
},
"connect_id": "301871346491491"
}{
"session_id": "xxxx",
"event": "task_started",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
},
"connect_id": "301871346491491"
}{
"session_id": "my-session-001",
"connect_id": "301871346491491",
"event": "sentence_start",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}{
"data": {
"audio": "xxx"
},
"extra_info": {
"audio_channel": 1,
"audio_format": "mp3",
"audio_length": 9914,
"audio_sample_rate": 32000,
"audio_size": 157869,
"bitrate": 128000,
"invisible_character_ratio": 0,
"usage_characters": 158,
"word_count": 158
},
"is_final": true,
"session_id": "301871346491491",
"trace_id": "04ee3794e2c9e4a6d5f99e77742f06fd",
"base_resp": {
"status_code": 0,
"status_msg": "success"
},
"connect_id": "301871346491491"
}{
"session_id": "my-session-001",
"connect_id": "301871346491491",
"event": "sentence_end",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}{
"session_id": "my-session-001",
"connect_id": "301871346491491",
"event": "task_canceled",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}{
"session_id": "my-session-001",
"connect_id": "301871346491491",
"event": "task_flushed",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}{
"session_id": "xxxx",
"event": "task_finished",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
},
"connect_id": "301871346491491"
}{
"session_id": "xxxx",
"event": "task_failed",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 1004,
"status_msg": "XXXXXXX"
},
"connect_id": "301871346491491"
}同步语音合成 WebSocket(双向流式)
支持文本流式输入的 WebSocket 语音合成接口,客户端可逐字发送文本,由服务端自动攒句合成。
与 /ws/v1/t2a_v2 的区别
本接口面向文本流式输入场景:把大模型的流式输出直接逐 token 转成语音。
/ws/v1/t2a_v2 | /ws/v1/t2a_v2_bidi(本接口) | |
|---|---|---|
| 攒句责任 | 客户端自行判断句子边界 | 服务端自动攒句 |
| 逐字发送文本 | 每个字触发一次合成,音频碎裂 | 攒成完整句子后再合成 |
| 打断 | 不支持,只能断开连接 | task_cancel,打断后可继续 |
| 句边界事件 | 无 | sentence_start / sentence_end |
task_finish | 立即关闭连接 | 先合成缓冲区残留再关闭 |
| 催出残留但不结束会话 | 无 | task_flush |
task_start 的音色、音频、发音字典等参数与 /ws/v1/t2a_v2 完全一致,已有接入可直接复用。
事件流程
- 建立连接,收到
connected_success - 发送
task_start,收到task_started - 发送
task_continue(可按任意粒度,包括单个字符),服务端攒句后开始合成- 每句合成开始返回
sentence_start - 音频通过
task_continued分块返回 - 该句结束返回
sentence_end
- 每句合成开始返回
- 需要打断时发送
task_cancel,收到task_canceled后可继续发送task_continue - 一轮说完、希望立刻拿到尾句音频时发送
task_flush,收到task_flushed后会话继续 - 发送
task_finish,服务端合成完残留文本后返回task_finished并关闭连接
is_final 表示本次请求的音频结束,sentence_end 表示当前句结束,task_finished 表示整个会话结束。task_start 会返回 2206(事件顺序非法)并关闭连接。攒句与延迟
服务端按标点判断句子边界,因此你发送的文本中的标点会直接影响音频的自然度:| 文本情况 | 服务端行为 |
|---|---|
以句末标点(。!?…!?. 及换行)结尾 | 立即送去合成,不引入额外延迟 |
出现次级标点(,、;:,;:) | 已攒文本达到一定长度才切句,避免切出过短的碎片 |
| 长文本完全没有标点 | 达到长度上限时强制切断,此时句边界与语义无关,听感会断裂 |
| 尾部不带标点,但已攒够长度 | 等待一个短暂的静默窗口后兜底送出 |
| 尾部不带标点且很短 | 继续等待,不会为了低延迟把半个词送去合成 |
task_flush 主动催出。注意不能用 task_finish 代替——它会关闭连接,在一条连接上跑多轮对话时用不了。连接保活
连接空闲超过约 120 秒会被服务端关闭并返回2201。「空闲」指服务端既没有收到上行事件,也没有在下发音频。
2201。发送速率与重试
收到2205 表示服务端排队待合成的文本过多,通常是发送速度超过了合成速度。
2205 不是配额限流,也是软失败:连接和会话都不会关闭。稍后重新发送该条 task_continue 即可,不需要重连、也不需要重新 task_start。task_continue 文本超过 10,000 字符会返回 2204,该条被跳过,连接与会话同样保持。{
"event": "task_start",
"model": "speech-2.8-turbo",
"language_boost": "Chinese",
"voice_setting": {
"voice_id": "male-qn-qingse",
"speed": 1,
"vol": 1,
"pitch": 0
},
"pronunciation_dict": {
"tone": [
"处理/(chu3)(li3)",
"危险/dangerous"
]
},
"audio_setting": {
"sample_rate": 32000,
"bitrate": 128000,
"format": "mp3",
"channel": 1
},
"session_id": "my-session-001"
}{
"event": "task_continue",
"text": "真正的危险不是计算机开始像人一样思考(sighs),而是人开始像计算机一样思考。计算机只是可以帮我们处理一些简单事务。"
}{
"event": "task_cancel"
}{
"event": "task_flush"
}{
"event": "task_finish"
}{
"session_id": "xxxx",
"event": "connected_success",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
},
"connect_id": "301871346491491"
}{
"session_id": "xxxx",
"event": "task_started",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
},
"connect_id": "301871346491491"
}{
"session_id": "my-session-001",
"connect_id": "301871346491491",
"event": "sentence_start",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}{
"data": {
"audio": "xxx"
},
"extra_info": {
"audio_channel": 1,
"audio_format": "mp3",
"audio_length": 9914,
"audio_sample_rate": 32000,
"audio_size": 157869,
"bitrate": 128000,
"invisible_character_ratio": 0,
"usage_characters": 158,
"word_count": 158
},
"is_final": true,
"session_id": "301871346491491",
"trace_id": "04ee3794e2c9e4a6d5f99e77742f06fd",
"base_resp": {
"status_code": 0,
"status_msg": "success"
},
"connect_id": "301871346491491"
}{
"session_id": "my-session-001",
"connect_id": "301871346491491",
"event": "sentence_end",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}{
"session_id": "my-session-001",
"connect_id": "301871346491491",
"event": "task_canceled",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}{
"session_id": "my-session-001",
"connect_id": "301871346491491",
"event": "task_flushed",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}{
"session_id": "xxxx",
"event": "task_finished",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 0,
"status_msg": "success"
},
"connect_id": "301871346491491"
}{
"session_id": "xxxx",
"event": "task_failed",
"trace_id": "0303a2882bf18235ae7a809ae0f3cca7",
"base_resp": {
"status_code": 1004,
"status_msg": "XXXXXXX"
},
"connect_id": "301871346491491"
}发送任务开始事件则正式开始合成任务,当服务端返回的 task_started 事件时,标志着任务已成功开始。
只有在接收到该事件后,才能向服务器发送 task_continue 事件或 task_finish 事件。
当收到服务端返回的 task_started 事件后,任务正式开始,可通过发送 task_continue 事件发送要合成的文本。
与 /ws/v1/t2a_v2 的关键区别:本接口的文本不会一条一次合成,而是进入服务端的攒句缓冲,按下列规则成句后才送去合成,因此可以安全地按逐字/逐 token 粒度发送:
- 遇到句末标点(
。!?…;!?.及换行)立即合成 - 遇到次级标点(
,、:,;:)且已攒够长度时合成 - 累计长度达到上限时强制切分
- 停止发送超过一定时间后,自动合成缓冲区中的残留文本
纯空白文本会被静默丢弃,不会返回错误。 当最后一次收到服务端返回结果后超过 120s 没有发送新事件时,WebSocket 连接自动断开。
发送 task_cancel 事件可立即打断当前合成:服务端会丢弃攒句缓冲区中尚未合成的文本、中断正在进行的合成,并返回 task_canceled 事件。
已经发送给客户端的音频不会撤回。
打断后会话回到 task_started 状态,可以继续发送 task_continue 继续合成,无需重建连接。适用于实时对话中用户插话打断的场景。
发送 task_flush 事件,让服务端立即把攒句缓冲区里剩余的文本送去合成,但不结束会话、不关闭连接。合成完毕后返回 task_flushed。
适用场景:一轮说完了,而最后一片文本很短又不带句末标点。这种残留不会被静默窗口立刻送出(那是为了避免在词中间切开),需要等一个更长的兜底窗口。发 task_flush 可以立刻拿到这段音频。
与 task_finish 的区别:task_finish 会关闭连接,因此在一条连接上进行多轮对话时无法用它催出某一轮的尾句;task_flush 之后会话仍处于 task_started 状态,可以继续发送 task_continue。
缓冲区恰好为空时也会正常返回 task_flushed,不算错误。
服务端收到 task_finish 事件后,会先把攒句缓冲区中剩余的文本送去合成,等全部音频返回后才回复 task_finished 并关闭连接。
因此最后一句不完整的文本也不会丢失,无需客户端在结束前补一个标点。
成功建立连接后会返回 connected_success 事件
服务端返回 task_started 事件,标志着任务已成功开始
服务端攒够一个句子并开始合成时返回 sentence_start 事件。随后该句的音频通过 task_continued 事件分块返回,直到 sentence_end。
可用它统计服务端实际把文本攒成了多少句
服务端返回 task_continued 事件,标志着任务已成功继续
服务端返回 sentence_end 事件,表示当前句子的音频已全部返回。
注意三层结束语义的区别:is_final 表示本次请求的音频结束,sentence_end 表示当前句结束,task_finished 表示整个会话结束
服务端返回 task_canceled 事件,表示打断已生效。此后可继续发送 task_continue
服务端返回 task_flushed,表示本次 task_flush 请求的音频已全部下发完毕。该事件排在本次 flush 产生的音频帧之后,收到它即可认为这一轮的音频结束。此后可继续发送 task_continue。
服务端返回 task_finished 事件,标志着任务已成功结束
如果接收到 task_failed 事件,表示任务失败。此时需要关闭 WebSocket 连接并处理错误。
此页面对您有帮助吗?