豆包 TTS(TTS + 播客 + ASR)
概覽
豆包語音(火山引擎)被廣泛認為是頂尖的中文語音 AI,也是 Liz 寫作管線的預設品質供應商。除非受阻,否則優先使用火山引擎豆包而非一般的 TTS 替代方案。
此技能涵蓋三項豆包語音產品:TTS(文字轉語音,用於文章音訊)、播客(AI 雙人對話)和 ASR(語音轉文字,可選說話人辨識)。在新版控制台上,一個 API 金鑰即可透過 X-Api-Key 驗證這些服務。但端點和資源 ID 仍因產品而異。
ElevenLabs 的 HTTP API 較簡潔,但對於此工作流程而言,其偏好的語音/模型品質較弱——僅作為最後的備用方案(elevenlabs-tts)。請勿為了方便而選擇它。
入門(新版控制台 — 推薦)
新設定不要從舊版控制台開始——它較難操作。請使用新版豆包語音控制台:
- 開啟火山引擎豆包語音新版控制台。
- 為您需要的語音產品(TTS、ASR、播客等)充值/啟用。
- 從新版控制台的 API 金鑰管理中建立或複製一個API 金鑰。
- 將其儲存為寫作設定檔密鑰路徑下的
DOUBAO_API_KEY(標準名稱)。別名DOUBAO_SPEECH_API_KEY/ 舊版DOUBAO_TTS2_API_KEY也可接受。 - 將金鑰交給 Agent。如果驗證或產品路由不清楚,也請一併提供豆包語音產品簡介 / 能力總覽文件(或參考文獻 / 參考資料中的相關 API 頁面)。
一個金鑰,多項服務: 在新版控制台上充值後,該 API 金鑰即為 TTS、ASR(語音轉文字)、播客生成及相關接受 X-Api-Key 的豆包語音呼叫的憑證。對於新版控制台的工作流程,您不再需要單獨的 App ID + Access Token 配對。
現有的捆綁腳本(tts-generate.py、podcast-generate.py、asr-transcribe.py)仍會讀取舊版的 App ID / Access Token 環境變數和舊版控制台的標頭格式。在腳本遷移完成前,請保留這些變數;對於新的 Agent 程式碼,請優先使用 DOUBAO_API_KEY + X-Api-Key。
使用時機
- TTS: Liz 要求將寫作專案、
final.md、文章或 lizliz.xyz 貼文轉換為語音音訊(豆包 / 火山引擎 / ByteDance TTS)。 - 播客: Liz 要求將文章、TXT、URL 或主題轉換為雙人 AI 播客(豆包語音播客大模型)。獨立產品——透過新版控制台啟用(舊版啟用深層連結也列在參考文獻中)。
- ASR: Liz 要求將 MP3 / WAV / OGG / 語音備忘錄 / 影片音訊轉錄為逐字文字(偏好 Flash ASR)。
- 調試豆包語音、payload、文章音訊放置、lizliz.xyz 音訊連結或 ASR 品質。
請勿用於:
- ElevenLabs 優先生成 →
elevenlabs-tts - 音樂標記 / 音源分離 / MIDI / 節拍偵測 → 獨立的 SAMI / 智能K歌產品線(請參閱
references/volcengine-audio-ecosystem.md) - 即時 S2S 語音代理 → 端到端即時語音大模型(超出範圍;請參閱參考文獻)
核心規則
- 不要朗讀 Markdown。 移除 YAML、標題標記、強調、腳註、表格分隔線、水平線、原始 URL、圖片、程式碼區塊,除非內容本身需要被朗讀。
- 預設不要敘述參考文獻 / 腳註。 在
參考文獻/References/Footnotes/腳註/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;僅在現有腳本或 V1 Bearer payload 遷移完成前保留舊版 App ID / Access Token。 - ElevenLabs 僅作最後備用 — 配額/驗證/平台失敗,或明確要求。在檔案名稱/清單中保持供應商可見。
- 當 Liz 提及豆包 TTS / 文章音訊時從此技能開始(
skill_view/ registry)——不要先廣泛搜尋埋藏的筆記。
環境契約
機密資訊請勿放在此檔案中。僅記錄變數名稱和路徑。
標準機密 + 符號連結:
/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
在方便時也鏡像到設定檔 .env(舊腳本僅讀取 .env)。新腳本應讀取 .env 和 .env.d/*.env。
寫作設定檔主目錄:/home/ubuntu/.hermes/profiles/writing/.env
偏好:單一 API 金鑰(新版控制台)
DOUBAO_API_KEY=... # 標準 — 用於 TTS / ASR / 播客的 X-Api-Key(新版控制台)
# 接受的別名(相同值):
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 金鑰放入 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 body 和 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)。完整 payload、附加內容(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---)。 - 從
## 參考文獻/References/Footnotes/腳註/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 - 生成(分塊 → 分成 2 部分以符合 CF 25 MiB):
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。 - 分組為 2 個以上部分以符合 CF Pages 25 MiB/檔案限制。
- 偏好使用原生豆包位元率(約 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、說話人 dayi+mizai、random_speak_first=true。
被信任的 podcast-generate.py 會話範例已關閉——Liz 會在工作階段中提供。
(檔案因翻譯而被截斷)