OpenRouter

把 TTS 接進產品前,先處理音訊位元組與錯誤分類

OpenRouter 用一個 OpenAI 相容端點統一多家 TTS 模型,但真正的工程量在回應驗證、格式限制與重試分類。

把 TTS 接進產品前,先處理音訊位元組與錯誤分類 — 文章封面
本頁內容6 個段落
  1. 一個端點,換來的是驗證責任
  2. 先驗證,再寫檔
  3. 格式與模型是綁在一起的
  4. 重試要分類,不要一律 backoff
  5. 這件事對建置順序的影響
  6. 參考來源

一個端點,換來的是驗證責任

OpenRouter 在 2026 年 9 月 11 日發布的教學裡,把 text-to-speech 收斂成一個 OpenAI 相容的 POST /api/v1/audio/speech 端點。請求只需要 modelinput,加上多數模型都要求的 voice;換供應商時,端點、認證與回應處理都不變,只有 model 與 voice 這一對要一起換。

這聽起來像省事,實際上把工作往下推了一層。成功回應是 raw audio bytes,失敗回應是 JSON。也就是說,如果你沒有先檢查狀態碼與 Content-Type 就把 response.content 寫成 output.mp3,你存下來的很可能是一段錯誤訊息,而不是音檔。

先驗證,再寫檔

教學裡的 Python 範例示範了正確順序:raise_for_status() 先擋掉 4xx/5xx,再確認 Content-Typeaudio/mpeg,最後才 write_bytes。cURL 版本則靠 --fail-with-body 讓失敗時回傳非零退出碼,並提醒失敗後要用 cat output.mp3 讀錯誤、刪掉檔案再重試。

JavaScript 版本多了一步:內容型別不符時先 response.body?.cancel(),避免留下半截串流。這些檢查看起來瑣碎,但它們決定了你的 pipeline 是「偶爾產出 JSON 假音檔」還是「明確失敗」。

格式與模型是綁在一起的

response_formatspeed 都是選填,但教學建議明確指定格式,因為各模型支援度不同。端點在省略時預設 PCM,而 Mistral Voxtral Mini TTS 只接受 MP3,對它要求 PCM 會拿到 400。PCM 回傳 audio/pcm,可帶 rate 與 channels 參數,但把副檔名改成 .mp3 不會轉換格式。

voice 也不是通用識別碼。Grok Voice TTS 1.0 列出 eveararexsalleo 五個內建聲音;換供應商時必須同時更新 model 與 voice。Microsoft MAI-Voice-2 走 Azure 風格的聲音名稱,並透過 provider.options.azure 傳入 stylestyledegreespeed 支援 0.5 到 2.0。這些都是供應商專屬設定,不支援的供應商可能直接忽略。

教學也提到,截至 2026 年 9 月,live catalog 裡沒有 OpenAI 的語音模型,所以依賴特定供應商欄位前要先查目前模型清單。

重試要分類,不要一律 backoff

生產環境的建議很具體:長文本按句子或段落切段、依序請求、再用理解格式的工具合併,這樣第一段能更早回來。每一段都要套同一組檢查,並把 X-Generation-Id 連同 model、voice、格式與自家 request ID 一起記錄。

重試只針對 429、502、503、524、529,並遵循 Retry-After,否則用有上限的指數退避。400、401、402 不該進退避迴圈,要先修請求、憑證或額度。計價方面,TTS 模型按輸入字元計費,費率依模型與供應商而異。

這件事對建置順序的影響

如果你正在評估語音功能,這個端點確實降低了「接第二家 TTS」的成本,但代價是你要自己承擔格式與錯誤處理的複雜度。這跟我們先前在挑選 AI 語音代理平台時談到的順序一致:先拆解部署層級與成本,再談功能。

實務上的下一步很簡單:先用 curl "https://openrouter.ai/api/v1/models?output_modalities=speech" 確認目前可用的語音模型,然後把「狀態碼檢查、Content-Type 檢查、空回應檢查、generation ID 記錄」寫成一個共用函式,再開始接 UI。這四件事沒做好,之後換模型只會放大問題。

參考來源

本文由 AI 協助自上述來源整理,經人工審核後發布。

分享X電郵