用 dots.tts 生成中文旁白,先做台灣讀音文字前處理,再用 ASR 驗收結果。
這個專案不修改模型權重,也不是微調;它是 dots.tts 外面的文字處理、分段生成與驗收工具。
- Linux
- NVIDIA GPU 與 CUDA
- Python 3.12(dots.tts 支援 3.10–3.12)
- uv
ffmpeg:從影片、非 WAV 音檔,或非 48 kHz 的來源(含瀏覽器錄音)準備參考音檔時需要
這個 repo 沒有自己的 pyproject.toml 或 uv.lock。請在 dots.tts 的虛擬環境安裝依賴,再用同一個 Python 啟動本專案。
如果兩個 repo 都放在 ~/Workspace/Toys,可以直接執行:
cd ~/Workspace/Toys
git clone https://github.com/studio-dots-ai/dots.tts.git
cd dots.tts
uv venv --python 3.12 .venv
uv pip install --python .venv/bin/python --torch-backend cu128 \
-e . -c constraints/recommended.txt
# 要使用 WebUI 的「拼音前處理」才需要這個選配套件
uv pip install --python .venv/bin/python pypinyinUbuntu/Debian 可用以下指令安裝 ffmpeg:
sudo apt install ffmpeg第一次生成時會下載 TTS 模型;第一次做 ASR 驗收時還會下載 Breeze-ASR-25。兩者都需要網路、磁碟空間與 GPU 記憶體。
fresh clone 不會附帶個人聲音檔(ref/*.wav 不進版控,逐字稿的 .txt 才進)。準備一段約 10 秒的單聲道 WAV,並把實際唸的逐字稿存成同名 .txt:
ref/my_voice.wav
ref/my_voice.txt
逐字稿必須和錄音完全一致。錄音規格與範例稿請看 RECORDING.md。
預設會使用 ref/標準sample.wav(逐字稿在 ref/標準sample.txt);沒有這個檔案時開頁面不會預選任何參考音檔,自己從選單挑或上傳即可。
準備好的參考音檔本身就不該留頭尾空白——prep_reference 預設會修掉。WebUI 生成時還會再修一次,但那是保險,不是替代品。
參考音檔一律放在 repo 內的 ref/(錄好的片段在 ref/clips/),下拉選單也只掃這兩個目錄。素材放在 repo 外的話,換一台機器或搬一次資料夾就整組失效,而且逐字稿沒有能跟著走的地方。手上有影片或外部音檔時先收進來:
"$TWTTS_PY" -m twtts.prep_reference ~/Videos/my_clip.mp4 --out ref/標準sample.wavcd ~/Workspace/Toys/tw-tts
TWTTS_PY=../dots.tts/.venv/bin/python
"$TWTTS_PY" app.py開啟 http://127.0.0.1:7861,接著:
- 在「旁白稿」貼上文字,段落之間用空行分隔。
- 選擇或上傳參考音檔,填入參考音檔逐字稿。
- 先看「改寫預覽」,再按「生成旁白」。
- 需要時勾選「拼音前處理」。它會保留漢字並加上帶調號拼音;這是實驗功能,需要先安裝
pypinyin。 - 生成後可在「驗收:ASR 回轉錄」檢查字元錯誤率。
輸出會放在 out/webui/,包含各段 WAV、manifest.json,以及記住上次設定的 session.json。
dots.tts 的 prompt_audio_path 只吃一個檔案。手上有好幾小段錄音時,展開 WebUI 的「追加樣本音(串在參考音檔後)」,最多可再接四段:
- 每按一次「+ 追加一段」就多一格;每格有「加入」勾選、音檔與逐字稿,可用「↑ / ↓」調順序、「移除」刪掉。
- 取消「加入」就把那段排除在串接之外,欄位還留著。要比較「有沒有這段參考」的差別時,不必先移除再找回來。
- 每格都能上傳檔案或直接按麥克風當場錄一段,錄完可在波形上裁切。瀏覽器錄下來的音檔常是 44.1 kHz,會自動用 ffmpeg 轉成 48 kHz 單聲道——所以錄音這條路需要裝
ffmpeg。 - 「修掉頭尾靜音(含上面的參考音檔)」預設開啟,而且沒有追加任何片段時也照修。 錄音前後一定有按鈕操作留下的空白,不修的話那些死時間會被當成語調一起 clone。門檻是相對於錄音自己的音量(峰值往下 35 dB,並以噪聲底往上 8 dB 為底線),不是固定的絕對值——一般房間的底噪就落在 −45 dB 上下,用固定門檻等於完全沒修。按錄音鍵的喀聲只有幾毫秒,要連續 60 ms 超過門檻才算開始說話,所以它不會把起點釘在最前面。
- 生成時會照畫面上的順序串成一個參考音檔(段間插入 0.25 秒靜音,接點做極短淡入淡出避免爆音),逐字稿也照同樣順序接起來。缺任何一段逐字稿都會直接擋下——音檔與文字對不上就是字級錯誤的來源。
- 「試聽串接結果」會播出實際要餵給模型的那一份(已套用修剪與串接),接壞了在這裡就聽得出來;「存成 ref/ 檔案」會把結果寫成
ref/<檔名>.wav與同名.txt,之後直接從下拉選單選用。存檔後追加欄位會清空,避免同一段被串進去兩次。既有檔名不會被覆蓋。 - 各段要用同一支麥克風、同樣距離與音量,否則音色會在接點跳掉(規格見
RECORDING.md)。總長仍建議落在 8–12 秒附近:dots.tts 的參考音檔不是越長越像。
串接的暫存檔是 out/webui/ref_joined.wav,每次生成都會覆寫。
錄過或上傳過的片段都會自動收進 ref/clips/,連同 <檔名>.txt 逐字稿。gradio 自己的暫存檔會被清掉,收進來之後才不會「錄完關掉分頁就沒了」。
- 追加欄位下方的片段庫選單列出所有片段(檔名、長度、逐字稿開頭),可多選:
- 「加入選取的片段」把它們接到目前欄位後面,逐字稿一起帶回來。
- 「刪除選取的片段(不可復原)」刪掉音檔與逐字稿;正在用該片段的欄位會一併清空,不會留下指向已刪檔案的路徑。
- 片段庫裡的檔案也會出現在最上面的「參考音檔」選單,所以錄好的片段可以直接當主樣本。
- 逐字稿都可以改,改完離開欄位就存回去:追加欄位寫回
ref/clips/<檔名>.txt,主參考音檔寫回它自己的同名.txt。 - 內容一樣的片段只會存一份——在波形上來回裁切不會在片段庫裡堆出一串相同的副本。
- 選單只列 repo 內的檔案。硬要用 repo 外的檔案仍可直接在選單貼路徑,但逐字稿不會寫到那邊去(畫面會直接說明)——在別人的目錄憑空生一個
.txt不是這個工具該做的事。請先用prep_reference收進ref/。
ref/clips/ 是個人錄音,已加進 .gitignore。
重啟後回得來。 逐字稿一律落在磁碟的 .txt(主參考音檔在它自己的同名 .txt,追加片段在 ref/clips/<檔名>.txt),而「上次用哪一支參考音檔、追加了哪幾段」記在 out/webui/session.json。重開 WebUI 會直接帶回上次的參考音檔、逐字稿與追加欄位。
- 逐字稿以磁碟上的
.txt為準,session.json只是備援——你可以直接用編輯器改.txt,下次開頁面就是改過的版本。 - 記下的是片段庫裡的路徑,不是 gradio 的暫存檔;當場錄的樣本也回得來。
- 上次那支檔案被刪掉、或
session.json壞了,就安靜退回ref/ref_a.*的預設值。 - 追加欄位只記得片段庫裡的片段。從 repo 外直接選檔的那種不記——重啟後那個路徑未必還在。
「驗收:ASR 回轉錄」除了 CER,還會把原稿有、但 ASR 沒聽出來的字列在「沒聽出」欄,並拿它們去比對片段庫的逐字稿:
段 字數 錯誤數 CER ASR 聽到 沒聽出
1 7 2 28.6% 研究平直很重要 品質
2 5 1 20.0% 氣業要導入 企
- 第 1 段 沒聽出「品質」→ 片段庫有 clip_20260806_141119(唸過 品質)
- 第 2 段 沒聽出「企」 → 片段庫有 clip_20260806_141119_2(唸過 企)
比對的是逐字稿內容——追加樣本音之所以有用,是因為參考音檔裡真的出現過那個音。找到的片段會直接預選在片段庫選單上,按「加入選取的片段」就排進追加欄位。片段庫裡沒有唸過那些字的片段時,它會直接說「建議錄一段有唸到某某的樣本音」。
換句話說:對不上的字代表模型沒聽過那個音、只能猜;補一段唸過它的樣本音,比拿同一份參考音檔反覆重生成有效——後者只是換一個隨機狀態再猜一次。
python -m twtts.verify 也會在最差的幾段底下印出「沒聽出」,但片段庫比對只在 WebUI 有。
tw-tts 將台灣華語的讀音處理接在 dots.tts 前面:
- 讀取
lexicon/tw_readings.tsv與已通過篩選的詞典覆寫。 - 依空行切成多段,避免單次生成太長。
- 呼叫 dots.tts 生成音訊。
- 用
Breeze-ASR-25把音訊轉回文字,檢查模型是否真的唸對。
文字詞典的安全清單在 lexicon/safelist.txt,實際替換表在 lexicon/resolved.tsv。
dots.tts 沒有可以直接指定音素的介面。參考音檔主要決定音色與語調,讀音仍可能受模型原本的語料影響,所以本專案改餵給模型的文字。
例如,某些詞可以用讀音相同的漢字替換:
| 原詞 | 文字覆寫 | 目的 |
|---|---|---|
| 品質 | 品值 | 讓第二字使用台灣讀音 |
| 企業 | 氣業 | 讓第一字使用台灣讀音 |
| 覺得 | 覺德 | 避開模型的輕聲讀法 |
這些替換看起來不一定是正常書面語,但 TTS 需要的是聲音。每個覆寫條目都應先經過 ASR 篩選;換參考音檔、模型或 seed 後,應重新篩選詞典。
以下指令假設你仍在 repo 根目錄,並已設定上面的 TWTTS_PY。
"$TWTTS_PY" app.py [--host 127.0.0.1] [--port 7861]另外支援 --model 指定模型與 --share 建立 Gradio 分享連結。
不載入 TTS 模型,只查看詞典會如何改寫文字:
"$TWTTS_PY" -m twtts.preprocess \
--text "研究這個項目的數據品質" --report也可以讀寫檔案:
"$TWTTS_PY" -m twtts.preprocess \
--in script.txt --out script.rewritten.txt"$TWTTS_PY" -m twtts.narrate \
--in script.txt \
--outdir out/narration \
--prompt-audio ref/my_voice.wav \
--prompt-text "$(cat ref/my_voice.txt)"預設會產生 out/narration/seg01.wav、seg02.wav……以及 manifest.json。script.txt 請用空行分段。
目前拼音前處理只有 WebUI 選項;preprocess 與 narrate CLI 尚未提供拼音旗標。
"$TWTTS_PY" -m twtts.verify \
--manifest out/narration/manifest.json \
--report out/verify.json驗收會輸出每段的 CER;超過預設門檻時會以 exit code 1 結束。最差的幾段底下會列出「沒聽出」的字,--report 的 JSON 也帶 misheard 欄位。WebUI 的驗收還會拿這些字比對片段庫,指出可以追加哪一段樣本音。
從影片或長錄音裁切、修剪靜音並輸出 48 kHz 單聲道 WAV:
"$TWTTS_PY" -m twtts.prep_reference input.mp4 \
--out ref/my_voice.wav --start 0 --end 10 --peak-db -6換了參考音檔後,重新測試詞典覆寫:
"$TWTTS_PY" -m twtts.screen_lexicon \
--prompt-audio ref/my_voice.wav \
--prompt-text "$(cat ref/my_voice.txt)" \
--out lexicon/safelist.txt \
--report out/screen.json這個流程會更新 lexicon/safelist.txt、同目錄的 resolved.tsv 與報告檔。它會生成許多測試音訊,通常需要一段時間與 GPU 記憶體。
要先確認參考音檔能固定說話人,再執行完整篩選:
"$TWTTS_PY" -m twtts.accent_gate --self-check \
--prompt-audio ref/my_voice.wav \
--prompt-text "$(cat ref/my_voice.txt)"pypinyin是一般漢語拼音工具,不是完整的台灣華語 G2P。台灣特有讀音仍以本專案已驗證的詞典覆寫為準。- 拼音前處理是實驗功能;模型可能把 inline 拼音當成英文或產生其他誤讀,請用 ASR 驗收,不要只看文字預覽。
lexicon/resolved.tsv綁定參考音檔、模型與 seed。換其中任何一項都應重新跑screen_lexicon;追加樣本音會改變實際餵給模型的參考音檔,同樣算換過。- 目前生成器固定使用
bfloat16與 CUDA;沒有 NVIDIA GPU 的環境不在已驗證範圍內。 - 參考音檔的逐字稿若不正確,後續的音色與讀音量測都不可靠。
- 這個工具沒有微調模型;要從根本改變模型的語音特徵,仍需要另外訓練或微調模型。
RECORDING.md:錄音規格、建議稿與自檢流程lexicon/tw_readings.tsv:台灣讀音詞典來源lexicon/resolved.tsv:目前已驗證的覆寫結果AGENTS.md:專案結構、測試與開發約定
本 repo 目前沒有附 LICENSE 檔。dots.tts 的授權與使用限制請以其原始專案為準,兩者不要混為一談。
執行不需要模型或 GPU 的快速測試:
cd ~/Workspace/Toys/tw-tts
TWTTS_PY=../dots.tts/.venv/bin/python
"$TWTTS_PY" -m unittest discover -s testsnarrate、verify、screen_lexicon 與模型、GPU 有關,不列入日常快速測試。不要把生成的音訊、out/ 或未授權的聲音檔提交到 Git。