挑一個聲音,
比挑一個模型難得多。
這份研究把 ElevenLabs 當成雲端語音供應商從頭量過一遍:模型陣容怎麼選、額度實際怎麼扣、 哪些參數在文件上寫著能用但實際會被拒絕。然後我們做了一件文件不會幫你做的事—— 用同一份稿子、同一組參數,讓 88 個聲音各說一次,做成一個可以盲測、對決、排名的實驗室。
五個結論
如果只讀一段,讀這裡。
- 真正的戰略功能是時間戳,不是音色。
with-timestamps端點回傳字元級對齊, 讓「生成」與「字幕時間軸」在同一次請求裡完成。市面上的本地引擎多半只能事後靠強制對齊補回來。 - 共享語音庫可以直接合成,不必先加進帳號。 這是這次最大的意外—— 八百多個社群聲音全部立即可用,帳號內建的三十一個只是起點。整個實驗室就是建立在這個發現上。
- v3 也支援時間戳。 就算句子裡放滿
[whispers]、[giggles]這類情緒標籤, 對齊依然回得來;把標籤字元從對齊裡剝掉,剩下的時間軸剛好對上顯示文字。 - 「多語言」不等於「每個語言的參數都一樣」。 語言正規化開關對日語有效、對中文直接被 API 拒絕, 中文的數字與日期必須自己先寫成漢字。
- 音色不是你在挑的東西,節奏才是。 這是做完 4,954 段音檔之後最強烈的感受, 也是實驗室要用兩兩比較而不是打星等的原因。
模型陣容:該用哪一個
三個真正需要記住的選項,其餘都是它們的變體或已被取代。
| 模型 | 單次上限 | 成本 | 它擅長什麼 | 什麼時候別用 |
|---|---|---|---|---|
Multilingual v2eleven_multilingual_v2 |
10,000 字元 | 1 credit/字元 | 長篇的一致性主力。完整參數支援、時間戳、請求接合(previous_text/next_text)、seed。 |
需要誇張演技時。它穩,但不會演。 |
Eleven v3eleven_v3 |
5,000 字元 | 1 credit/字元 | 情緒標籤([whispers]/[laughs]/[sarcastic])。角色台詞、動畫感演出。 |
長篇。上限只有一半,而且不支援 <break>,停頓只能靠標點。 |
Flash v2.5eleven_flash_v2_5 |
40,000 字元 | 0.5 credit/字元 | 草稿、迭代、即時互動(約 75 ms)。半價。 | 成品。省下來的錢,會在重錄的時候還回去。 |
比較用的核心語料一律走 Multilingual v2 並固定 seed——公平比較的前提是只有聲音這一個變數。 情緒台詞另外走 v3。Turbo 系列已被官方標為棄用,直接當它不存在。
時間戳:這才是差距所在
POST /v1/text-to-speech/{voice_id}/with-timestamps 回傳的不只是音檔,還有
alignment 與 normalized_alignment:每個字元的起訖秒數。
這代表字幕、卡拉OK 高亮、逐字時間軸這些東西,不需要事後再跑一次對齊模型,
在生成的當下就已經拿到了。
實驗室裡的字元高亮就是直接吃這份資料。日文的難處在於一個漢字可能對應多個音拍, 而 API 給的是字元級而非音節級——但對於「唸到哪裡了」這個用途,字元級已經精準得驚人。
v3 的情緒標籤本身也會出現在對齊陣列裡。處理方式很單純:把方括號涵蓋的字元連同它們的時間一起刪掉, 剩下的序列剛好就是顯示文字,時間軸完全不用重算。我們在 4,954 段音檔上逐段驗證過這件事成立。
/v1/forced-alignment 接受最大 1 GB 的音檔加上逐字稿,回傳字元與詞層級的時間戳與信心值。
剪輯過的音檔要重新對回時間軸時,這是唯一的正解。
額度:實際上怎麼扣
計價單位是送出去的字元數,不是產出的音檔長度。這件事有幾個不直覺的後果:
- v3 的情緒標籤是要錢的。
[cheerfully]十二個字元就是十二個 credit,即使它不發出任何聲音。 - 失敗的請求不扣額度,但被截斷的成功請求會。超過單次上限要自己切段。
character_count是最終一致的:剛跑完一批之後查,數字會落後一段時間才追上。- 額度按月重置且不累積。剩下的到期就沒了。
查詢方式是 GET /v1/user/subscription,回傳 tier、character_count、
character_limit、next_character_count_reset_unix 以及語音欄位配額。
任何會花錢的批次跑之前,先算好預估成本再送出——我們的生成器把這件事寫死成一道閘門。
TTS 降價約 55%、STT 降 45%,同時引入 pay-as-you-go。但對既有訂閱者是選擇性加入的—— 要在後台按下切換,否則你還在舊價目表上。這是一個很容易錯過幾個月的按鈕。
實測踩到的坑
以下每一條都是打到線上 API 之後才知道的,文件上找不到或寫得不明顯。
- 中文不接受語言正規化。
apply_language_text_normalization對language_code: zh會回language_text_normalization_not_supported;日文可以。 所以中文稿裡的數字、日期、金額都得自己先寫成漢字,而且「兩點」不能寫成「二點」。 pcm_*是裸資料。 沒有 WAV 標頭,直接存檔播不出來。要自己包一層——wav_*家族才是含標頭的那個。- seed 是盡力而為。 同樣的 seed 加同樣的參數只是「嘗試」重現,不保證位元相同。 當它是降低變異的工具,不是快取鍵。
- 並行數有上限。 Creator 方案的 TTS 並行是 5(Flash 10)。我們用五條連線跑, 穩定在每秒三段左右;再往上推就會開始吃到 429。
- Windows 會先於 API 倒下。 每次請求都開新 socket 的話,兩千段音檔就會把暫時連接埠耗盡
(
WinError 10048)。每個工作執行緒維持一條 keep-alive 連線就解決了。 - 偶發失敗是正常的。 幾千段裡有零星幾段會無故失敗;生成器設計成可續跑, 重跑一次就只補那幾段,不會重花錢。
- API key 自己也有額度上限,而且它跟帳號的上限是兩件事。
我們在跑到第四百段時被擋下來,錯誤訊息是
This request exceeds your API key (<名稱>) quota of 30000—— 帳號還有十萬額度沒動,但那把 key 被設了三萬的天花板。/v1/user/subscription不會告訴你這件事。批次跑之前要檢查的是 key,不只是帳號。
共享語音庫:這次最大的發現
帳號的語音庫裡有三十一個聲音,看起來就是全部了。但 GET /v1/shared-voices
能列出社群共享的公開聲音——我們抓下日、英、中三種語言共八百多個。
真正關鍵的是下一件事:這些聲音可以直接拿 voice_id 去合成,不需要先「加入我的語音庫」。
我們用一個沒加進帳號的聲音打了一次 with-timestamps,回 200。
這把可用的聲音數量從三十一擴大到八百以上,而且完全不佔語音欄位配額。
於是選角本身變成一件有內容的工作。這個實驗室的 88 個聲音是手挑的, 每種語言都刻意覆蓋可愛/動畫、自然對話、旁白、男聲,並且至少放一個地方腔—— 日語有關西腔與九州腔,中文有台灣國語與北京普通話的直接對照。
所有付費方案(Starter 以上)都含商業授權,這一點比多數可以本地跑的開源引擎乾淨得多—— 它們的基礎權重經常是非商業授權。專業聲音複製只能複製自己的聲音並需要驗證; 即時複製對付費用戶開放,但那是另一個需要逐案判斷權利的題目。
方法:這個語料庫是怎麼做出來的
如果實驗設計是壞的,聽起來再厲害的結論都不算數。
- 只留一個變數。 每一句台詞由所有聲音各說一次,模型相同、
voice_settings相同(stability 0.5/similarity 0.75/speed 1.0)、seed 相同、 輸出格式相同(mp3 44.1 kHz/128 kbps)。你聽到的差別只可能來自聲音。 - 台詞是自己寫的。 日語的「心動台詞集」帶有動畫的味道,但每一句都是原創, 不是任何作品的引用。每句附假名、羅馬字、繁體中文與英文對照,以及一條語法或語感筆記。
- 刻意設計的難句。 每種語言都有一組專門用來逼出破綻的句子: 日語的長音/促音/拗音/量詞音變/日期讀法,中文的破音字(長・行・樂・還・覺・差)與號碼裡的「么」。 平順的句子人人都唸得好,差距要靠難句才看得出來。
- 判斷用兩兩比較,不用打分。 絕對評分會漂移也會壓縮——大多數聲音都會落在三分或四分。 「比較想再聽哪一個」既省力又穩定,再用 Bradley–Terry 最大概似估計擬合成排名。 大約每個聲音累積八場比較,順序就會定下來。
- 每一段音檔都有出處。 模型、聲音、參數、seed、字元數、預估額度、延遲、 位元組數與字元對齊全部隨檔記錄,所以任何一段都能被追溯,也能被單獨重生成。
生成器本身是可續跑的:已存在的音檔絕不重跑,所以中斷不用付代價,失敗的段落可以單獨補。 預算是一道硬閘門,跑之前先印出預估成本。
接下來
這個語料庫是一個起點而不是結論。接下來值得做的幾件事:把 Scribe 語音辨識接上來, 對每一段生成音檔做自動聽寫比對,用來抓出唸錯字的段落;把長篇朗讀擴大到真正的段落級測試, 驗證請求接合在跨段落時的韻律連續性;以及把排行的結果,變成影片管線裡真正的預設聲音。
但在那之前,先去聽。排名是聽出來的,不是讀出來的。