7.6 KiB
7.6 KiB
火山引擎大模型语音流式接入 2026-05-08
背景
本次接入火山引擎豆包语音能力,覆盖两类运行态语音链路:
- 大模型流式语音识别 ASR,使用 WebSocket 双向流式优化模式。
- 大模型语音合成 TTS,使用实时交互场景的 WebSocket 双向流式接口,并提供一次性文本输入的 HTTP SSE 单向流式接口。
语音能力属于外部副作用,按 server-rs DDD 分层落在 platform-speech;api-server 只负责平台账号鉴权、环境配置校验、协议代理和错误映射。前端不得直接持有火山引擎密钥。
官方文档依据
- ASR:
https://www.volcengine.com/docs/6561/1354869?lang=zh - TTS WebSocket 双向流式:
https://www.volcengine.com/docs/6561/1329505?lang=zh - TTS WebSocket 单向流式:
https://www.volcengine.com/docs/6561/1719100?lang=zh - TTS HTTP Chunked / SSE 单向流式:
https://www.volcengine.com/docs/6561/1598757?lang=zh
环境变量
真实值只能放在本地未提交的 .env.local / .env.secrets.local 或生产服务器环境文件,禁止提交到仓库。
VOLCENGINE_SPEECH_API_KEY=
VOLCENGINE_SPEECH_APP_ID=
VOLCENGINE_SPEECH_ACCESS_KEY=
VOLCENGINE_SPEECH_ASR_RESOURCE_ID=volc.seedasr.sauc.concurrent
VOLCENGINE_SPEECH_TTS_RESOURCE_ID=seed-tts-2.0
VOLCENGINE_SPEECH_REQUEST_TIMEOUT_MS=180000
VOLCENGINE_SPEECH_ASR_WS_URL=wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async
VOLCENGINE_SPEECH_TTS_BIDIRECTION_WS_URL=wss://openspeech.bytedance.com/api/v3/tts/bidirection
VOLCENGINE_SPEECH_TTS_SSE_URL=https://openspeech.bytedance.com/api/v3/tts/unidirectional/sse
配置规则:
- 优先使用新版控制台
VOLCENGINE_SPEECH_API_KEY,上游请求头写X-Api-Key。 - 若只配置旧版控制台信息,则使用
VOLCENGINE_SPEECH_APP_ID和VOLCENGINE_SPEECH_ACCESS_KEY。 - ASR 默认资源 ID 选 ASR 2.0 并发版;如账号是小时版,部署时改成
volc.seedasr.sauc.duration。 - TTS 默认资源 ID 选
seed-tts-2.0;旧音色或 1.0 计费资源由部署环境覆盖。
ASR 协议边界
客户端连接:
GET /api/speech/volcengine/asr/stream
Authorization: Bearer <Genarrative JWT>
浏览器与 api-server 使用 WebSocket 二进制帧透传:
- 首包必须是 JSON 文本,表示 ASR full client request 的业务参数。
- 后续二进制帧是音频分片。
- 浏览器发送文本帧
{"type":"finish"}时,后端把最后一个空音频包按负包发送给火山。 - 后端把火山 full server response 解析成 JSON 文本帧发回浏览器。
ASR 上游连接:
wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async
X-Api-Key: <VOLCENGINE_SPEECH_API_KEY>
X-Api-Resource-Id: <VOLCENGINE_SPEECH_ASR_RESOURCE_ID>
X-Api-Request-Id: <uuid>
X-Api-Sequence: -1
ASR 二进制协议:
- 4 字节 header,大端整数。
- full client request:message type
0b0001,JSON 序列化,gzip 压缩。 - audio only request:message type
0b0010,raw payload,gzip 压缩。 - 最后一包音频使用 flags
0b0010。 - full server response:message type
0b1001,payload 为 gzip JSON。 - error response:message type
0b1111,payload 为错误 JSON 或 UTF-8 文本。
首包参数由前端传入,但后端会兜底:
{
"user": { "uid": "current-user-id" },
"audio": {
"format": "pcm",
"codec": "raw",
"rate": 16000,
"bits": 16,
"channel": 1
},
"request": {
"model_name": "bigmodel",
"enable_itn": true,
"enable_punc": true,
"show_utterances": true,
"result_type": "full"
}
}
TTS 协议边界
WebSocket 双向流式
客户端连接:
GET /api/speech/volcengine/tts/bidirection
Authorization: Bearer <Genarrative JWT>
浏览器向后端发送 JSON 文本帧:
{ "type": "start_connection" }
{ "type": "start_session", "sessionId": "...", "payload": { "user": {}, "req_params": {} } }
{ "type": "task_request", "sessionId": "...", "payload": { "req_params": { "text": "..." } } }
{ "type": "finish_session", "sessionId": "..." }
{ "type": "finish_connection" }
后端转成火山 WebSocket V3 二进制帧,并把上游返回帧统一解析成 JSON 文本或音频二进制帧回传浏览器。
TTS 双向上游连接:
wss://openspeech.bytedance.com/api/v3/tts/bidirection
X-Api-Key: <VOLCENGINE_SPEECH_API_KEY>
X-Api-Resource-Id: <VOLCENGINE_SPEECH_TTS_RESOURCE_ID>
X-Api-Connect-Id: <uuid>
V3 事件帧:
- Full-client request + event number 用于
StartConnection、StartSession、TaskRequest、FinishSession、FinishConnection。 - Full-server response + event number 用于
ConnectionStarted、SessionStarted、SessionFinished等状态事件。 - Audio-only response + event number 用于返回音频二进制。
- 错误帧必须转成结构化 JSON 错误,不把上游密钥或完整请求头写入日志。
HTTP SSE 单向流式
客户端请求:
POST /api/speech/volcengine/tts/sse
Authorization: Bearer <Genarrative JWT>
Content-Type: application/json
Accept: text/event-stream
请求体:
{
"text": "你好,欢迎来到百梦。",
"speaker": "zh_female_cancan_mars_bigtts",
"audioParams": {
"format": "mp3",
"sampleRate": 24000
}
}
后端转换为火山 HTTP SSE 请求体:
{
"user": { "uid": "current-user-id" },
"req_params": {
"text": "...",
"speaker": "...",
"audio_params": {
"format": "mp3",
"sample_rate": 24000
}
}
}
上游 SSE 的常见事件:
352:TTSResponse,data为 base64 音频片段。351:TTSSentenceEnd,sentence为字幕或时间戳数据。152:SessionFinish,合成完成,可含usage.text_words。153:SessionFailed,合成失败。
后端保持 SSE 形态透传,但会补齐平台 requestId 与上游 X-Tt-Logid 作为排障信息。
api-server 路由
| 方法 | 路由 | 说明 |
|---|---|---|
GET |
/api/speech/volcengine/config |
返回前端可见的默认资源和推荐音频参数,不返回密钥 |
GET |
/api/speech/volcengine/asr/stream |
ASR WebSocket 双向流式代理 |
GET |
/api/speech/volcengine/tts/bidirection |
TTS WebSocket 双向流式代理 |
POST |
/api/speech/volcengine/tts/sse |
TTS HTTP SSE 单向流式代理 |
所有路由必须走 require_bearer_auth。
验收
代码级验收:
cargo fmt --manifest-path server-rs/Cargo.toml --all --check
cargo test --manifest-path server-rs/Cargo.toml -p platform-speech
cargo test --manifest-path server-rs/Cargo.toml -p api-server volcengine_speech
cargo check --manifest-path server-rs/Cargo.toml -p api-server
npm run check:encoding
联调验收:
- 启动
npm run api-server。 - 检查
/healthz返回 200。 - 未登录访问语音路由返回 401。
- 已登录后
/api/speech/volcengine/config不返回任何密钥字段。 - ASR WebSocket 发送首包和 200ms PCM 分片后能收到识别 JSON。
- TTS SSE 能收到
352音频事件与最终152完成事件。 - TTS 双向 WebSocket 能复用连接完成至少一个 session。
注意事项
- 不把
VOLCENGINE_ACCESS_KEY_ID、VOLCENGINE_SECRET_ACCESS_KEY、API Key、Access Token 或完整 Authorization 写入文档、日志、测试快照或前端状态。 - 中文语音默认使用 16k 单声道 PCM ASR;TTS 默认使用 24k mp3,运行时可按玩法需要改为 pcm。
- 火山返回的
X-Tt-Logid是排障关键信息,应记录 logid,但不能记录密钥。 - 语音流式能力是平台副作用,不涉及 SpacetimeDB 表结构变更,本次无需修改
migration.rs。