豆包TTS(TTS + 播客 + ASR)
概述
豆包语音(火山引擎)被广泛认为是顶级的AI中文语音服务,也是Liz写作管线的质量默认提供方。除非受阻,否则首选火山引擎豆包而非通用TTS替代方案。
本技能涵盖三款豆包语音产品:TTS(文字转语音,用于文章音频)、播客(AI双人对话)和ASR(语音转文字,可选说话人分离)。在新一代控制台上,一个API Key通过X-Api-Key即可认证这些服务。各产品的端点和资源ID仍然不同。
ElevenLabs拥有更简洁的HTTP API,但对于此工作流,其首选语音/模型质量较弱——仅作为最后备选方案(elevenlabs-tts)。不得因其便利性而选用。
新手入门(新一代控制台 —— 推荐)
新设置不要从旧版控制台开始——它更难导航。请使用新版豆包语音控制台:
- 打开火山引擎豆包语音新版控制台。
- 充值/激活您需要的语音产品(TTS、ASR、播客等)。
- 在新控制台的API Key管理中创建或复制单一API Key。
- 将其存储为写入配置文件密钥路径下的
DOUBAO_API_KEY(规范名称)。别名DOUBAO_SPEECH_API_KEY/遗留名称DOUBAO_TTS2_API_KEY也可接受。 - 将密钥交给代理。如果认证或产品路由不明确,还需提供豆包语音产品简介/能力总览文档(或来自参考资料/参考文献的相关API页面)。
一钥多用: 在新控制台充值后,该API Key即为TTS、ASR(语音转文字)、播客生成以及相关接受X-Api-Key的豆包语音调用的凭证。对于新控制台工作流,您不再需要单独的App ID + Access Token对。
现有的捆绑脚本(tts-generate.py、podcast-generate.py、asr-transcribe.py)仍然读取遗留的App ID / Access Token环境变量和旧版控制台的标头格式。在脚本迁移完成前,请保持这些变量已填充;对于新的代理代码,优先使用DOUBAO_API_KEY + X-Api-Key。
何时使用
- TTS: Liz要求将写作项目、
final.md、文章或lizliz.xyz帖子转换为语音音频(豆包/火山引擎/字节跳动TTS)。 - 播客: Liz要求将文章、TXT、URL或主题转换为双人AI播客(豆包语音播客大模型)。独立产品——通过新控制台激活(参考资料中也列出了旧版激活深度链接)。
- ASR: Liz要求将MP3 / WAV / OGG / 语音备忘录 / 视频音频转录为逐字文本(优先使用Flash ASR)。
- 调试豆包语音、负载、文章音频放置、lizliz.xyz音频链接或ASR质量。
不要用于:
- ElevenLabs优先生成 →
elevenlabs-tts - 音乐标记/源分离/MIDI/节拍检测 → 单独的SAMI/智能K歌产品线(参见
references/volcengine-audio-ecosystem.md) - 实时S2S语音助手 → 端到端实时语音大模型(超出范围;参见参考资料)
核心规则
- 不要朗读Markdown。 去除YAML、标题标记、强调、脚注、表格竖线、水平线、原始URL、图片、代码围栏,除非内容本身必须被朗读。
- 默认不朗读参考资料/脚注。 在
参考资料/参考文献/脚注/Sources/引用之前停止。仅当Liz要求时才包含来源附录音频。 - 保持文章语气。 保留中文标点节奏、段落分隔、引号和英文技术术语。
- 当Liz已选择默认语音时,跳过多语音冒烟测试。
- 默认语音:
zh_female_vv_uranus_bigtts(Vivi2.0),除非Liz选择其他语音或配额受限。 - 生产TTS路由: 已验证的V1
https://openspeech.bytedance.com/api/v1/tts,使用cluster: volcano_tts。V3流式是迁移/实时路径,而非文章默认。 - 新工作优先使用新控制台
DOUBAO_API_KEY;遗留App ID / Access Token仅用于现有脚本或迁移前的V1 Bearer负载。 - ElevenLabs仅作为最后备选——配额/认证/平台失败,或明确请求。在文件名/清单中保持提供者可见。
- 当Liz提到豆包TTS/文章音频时,从此技能开始(
skill_view/注册表)——不要首先广泛搜索埋藏的笔记。
环境契约
密钥不放在此文件中。仅记录变量名和路径。
规范密钥 + 符号链接:
/home/ubuntu/.hermes/secrets/doubao-tts.env
/home/ubuntu/.hermes/secrets/elevenlabs.env
/home/ubuntu/.hermes/profiles/writing/.env.d/*.env -> /home/ubuntu/.hermes/secrets/*.env
/home/ubuntu/.hermes/profiles/trading/.env.d/*.env -> /home/ubuntu/.hermes/secrets/*.env
/home/ubuntu/.hermes/.env.d/*.env -> /home/ubuntu/.hermes/secrets/*.env
同时,在方便时镜像到profile .env(旧脚本仅加载.env)。新脚本应加载.env和.env.d/*.env。
写入配置文件主目录: /home/ubuntu/.hermes/profiles/writing/.env
推荐:单一API Key(新控制台)
DOUBAO_API_KEY=... # 规范名称 — X-Api-Key用于TTS / ASR / 播客(新控制台)
# 接受的别名(相同值):
DOUBAO_SPEECH_API_KEY=...
DOUBAO_TTS2_API_KEY=... # 来自TTS 2.0示例的历史名称;保持为别名
新代码的解析顺序:DOUBAO_API_KEY → DOUBAO_SPEECH_API_KEY → DOUBAO_TTS2_API_KEY。
可选(共享):DOUBAO_TTS_CLUSTER=volcano_tts,DOUBAO_TTS_VOICE_TYPE=zh_female_vv_uranus_bigtts。
遗留认证(旧控制台)— 现有脚本 / V1 HTTP
新设置已弃用。 在tts-generate.py、podcast-generate.py和asr-transcribe.py仍需要时保持填充。
DOUBAO_TTS_APP_ID=... # 旧控制台App ID → X-Api-App-Key / X-Api-App-Id / V1 app.appid
DOUBAO_TTS_ACCESS_TOKEN=... # 旧Access Token → X-Api-Access-Key / V1 Authorization: Bearer; …
DOUBAO_TTS_SECRET_KEY=... # 可选;某些SDK变体
别名(兼容):VOLCENGINE_TTS_*、VOLC_TTS_*。
| 路径 | 认证格式 |
|---|---|
| 新控制台 | 仅X-Api-Key: $DOUBAO_API_KEY(ASR Flash、TTS V3及相关新控制台API) |
| 旧控制台 / 当前脚本 | X-Api-App-Key/X-Api-App-Id + X-Api-Access-Key,或V1 Authorization: Bearer; <token> + JSON app.appid/app.token |
请勿将API Key互换放入V1 Bearer;标头或将Access Token放入X-Api-Key——格式不同。
Shell导出陷阱——直接执行source .env可能不会导出到子进程Python:
set -a; . /home/ubuntu/.hermes/profiles/writing/.env; set +a
存在性检查(不输出密钥):
python3 - <<'PY'
import os, re
for name in sorted(k for k in os.environ if re.search(r'(DOUBAO|VOLC|TTS)', k)):
print(f"{name}=<set>")
PY
如果既没有设置DOUBAO_API_KEY(或其别名),也没有设置遗留的App ID / Access Token:停止。不要回退到Edge/OpenAI或声称生成了豆包音频。
TTS(文字→语音)
V1 HTTP — 生产默认
已验证可用于文章音频。官方文档现在将其列为历史/小模型文档,但该端点仍然活跃,并且是Liz在此服务器上的可靠路由。完整参数说明:V1 HTTP API。
此路径仍使用遗留的App ID + Access Token在JSON正文中,以及Authorization: Bearer; <AccessToken>——不是DOUBAO_API_KEY / X-Api-Key。捆绑的tts-generate.py匹配此格式。
POST https://openspeech.bytedance.com/api/v1/tts
Authorization: Bearer; <AccessToken>
Content-Type: application/json
(Bearer;带分号是官方格式。)
{
"app": {"appid": "APPID", "token": "TOKEN", "cluster": "volcano_tts"},
"user": {"uid": "unique_user_identifier"},
"audio": {
"voice_type": "zh_female_vv_uranus_bigtts",
"encoding": "mp3",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
},
"request": {
"reqid": "uuid",
"text": "plain text",
"text_type": "plain",
"operation": "query",
"with_frontend": 1
}
}
成功:code == 3000;音频位于base64 data。每次调用使用唯一reqid(UUID)。
限制: 官方小模型文档引用每个请求约1024 UTF-8字节;HTTP也有约60秒RPC超时。对于Liz的bigtts App,实际安全块大小约为1800–2000字符。5000+字符的块常常失败,返回code:3031 / RPC timeout。
V3 / TTS 2.0 流式 — 迁移与实时
优先用于实时/流式文本;在协议助手被接入脚本之前,保持使用V1进行批量文章音频。
| 端点 | 角色 |
|---|---|
wss://openspeech.bytedance.com/api/v3/tts/bidirection | 双向流(LLM token → 音频) |
wss://openspeech.bytedance.com/api/v3/tts/unidirectional/stream | 全文输入,音频流输出(WS) |
https://openspeech.bytedance.com/api/v3/tts/unidirectional | HTTP Chunked单向 |
https://openspeech.bytedance.com/api/v3/tts/unidirectional/sse | HTTP SSE单向 |
双向标头(新控制台):
X-Api-Key: $DOUBAO_API_KEY
X-Api-Resource-Id: seed-tts-2.0
X-Api-Connect-Id: <uuid>
X-Control-Require-Usage-Tokens-Return: *
(DOUBAO_SPEECH_API_KEY / DOUBAO_TTS2_API_KEY别名解析为相同的标头值。)
资源ID:seed-tts-2.0 / seed-tts-1.0 / seed-tts-1.0-concurr / seed-icl-2.0 / seed-icl-1.0(+ concurr)。完整负载、附加功能(disable_markdown_filter、字幕、方言)和异步长文本(/api/v3/tts/submit|query)→ references/tts-streaming-v3.md。官方页面:双向流式 TTS 2.0,V3 HTTP Chunked/SSE。
已知语音
在当前App上进行语音冒烟测试,而不是盲目相信指南。常见比较集:
| voice_type | 备注 |
|---|---|
zh_female_vv_uranus_bigtts | 默认 Vivi2.0 — 模型doubao-seed-tts-2.0;不要发送emotion/neutral(忽略) |
zh_female_xueayi_saturn_bigtts | 薛艾依 / 绘本艾依 — 在V1上观察到工作正常 |
zh_female_wanwanxiaohe_moon_bigtts | 先前认证/资源不匹配 — 套餐变更后重测 |
zh_female_shuangkuaisisi_moon_bigtts | 先前认证/资源不匹配 — 套餐变更后重测 |
Vivi默认:速度1.0,音量1.0,采样率24000,格式mp3。如果过于活泼,可在基线1.0后尝试速度0.98。
通过控制台或OpenAPI ListSpeakers / ListBigModelTTSTimbres发现语音。
文本清理检查清单
MP3是烘烤后的产物——在合成前清理。在内存或/tmp中工作;切勿为TTS修改源手稿。
- 去除YAML frontmatter(
---\n...\n---)。 - 从
## 参考资料/参考文献/脚注/Sources/引用/ Claim Check起截断。 - 去除所有HTML(
<a id>、<span>等)。泄漏会被读作“IA Intro”。 - 完全去除引用链接:
[N](#ref-N)→ 删除(不是裸N)。 - 去除MD:
#、**、*、[text](url)→text、图片、---、反引号、>、[^N]。 - 去除顶部音频链接(
[收听音频版...](...))。 - 将清理后的文本保存在
/tmp下以供审计。
自动化:scripts/strip-for-tts.py。
文章音频工作流
技能目录:
SKILL_DIR="$HOME/.hermes/profiles/writing/skills/media/doubao-tts"
VENV_PY="/home/ubuntu/.hermes/hermes-agent/venv/bin/python3"
- 清理:
python3 "$SKILL_DIR/scripts/strip-for-tts.py" <final.md> /tmp/<slug>-tts.txt - 生成(分块 → 在CF 25 MiB下分2部分):
python3 "$SKILL_DIR/scripts/tts-generate.py" /tmp/<slug>-tts.txt /tmp/<slug>-tts/ <slug>
→<slug>-part1.mp3、<slug>-part2.mp3。如果总大小小于25 MiB则合并:
ffmpeg -y -i "concat:...-part1.mp3|...-part2.mp3" -c copy /tmp/<slug>-tts/<slug>.mp3 - 放置站点音频:
public/audio/articles/<slug>/<slug>.mp3(或项目约定)。 - 在顶部附近添加链接:
[收听音频版](/audio/articles/<slug>/<slug>.mp3)。 - 验证大小、时长、链接;推送写作+站点仓库(写作Action同步Markdown,不同步任意本地音频)。
仅音频占位(正文未就绪):最小的final.md,包含frontmatter + 占位符 + 音频链接;将MP3拷贝到站点public/audio/articles/中;仅进行轻度同步检查——而非完整的发布审计。
多部分源叙述: 边界文件tts-part-N.txt;text_type: plain;每段一个MP3 + 清单;ffprobe每个文件。
分块与质量
- 每个请求最多约2000字符;在
\n\n处拆分。 - 连接:
ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp3。 - 为满足CF Pages 每个文件25 MiB的限制,分成2个或更多部分。
- 优先使用豆包原生比特率(~160 kbps)。发布的最低要求:96 kbps。仅当超出限制时重新编码:
ffmpeg -i in.mp3 -codec:a libmp3lame -b:a 96k -ac 1 out.mp3。参见references/cf-pages-size-limit.md。
播客(AI 播客)
与TTS不同的独立产品。完整协议:references/podcast-api.md。会话陷阱:references/podcast-session-learnings.md。发布:references/lizliz.xyz-podcast-page.md。官方WS协议:播客 API websocket-v3。
wss://openspeech.bytedance.com/api/v3/sami/podcasttts
新控制台(推荐用于新客户端):
X-Api-Key: $DOUBAO_API_KEY
X-Api-Resource-Id: volc.service_type.10050
X-Api-App-Key: aGjiRDfUWi # 固定产品密钥(协议文档仍然要求)
X-Api-Request-Id: <uuid>
遗留 / 当前 podcast-generate.py 标头:
X-Api-App-Id / X-Api-Access-Key / X-Api-Resource-Id: volc.service_type.10050
X-Api-App-Key: aGjiRDfUWi # 固定
二进制帧 message_type = 0b0001(头部字节1 0x14)。不要使用TTS双向0b0011 → "unsupported message type (3)"。
| action | 模式 |
|---|---|
| 0 | 长文本/URL摘要 → 双人对话(默认) |
| 3 | 直接nlp_texts对话合成 |
| 4 | prompt_text网络搜索摘要 |
Liz默认设置(2026-07): action=0, mp3/24000/speech_rate=0, speakers dayi+mizai, indo