Community程式設計與開發github.com

中文語音合成:文本規範化與工程

讓程式把中文(夾雜英文、數字、鏈接、程式碼)朗讀出來時的文本規範化(TN)與語音合成工程,包括轉念法、切句、流式邊界控制、引擎選型與錯誤排查,附 139 條驗收對照用例。

中文語音合成:文本規範化與工程 是什麼?

此技能專注於中文 TTS(文字轉語音)的文本規範化(Text Normalization)與工程實作,解決數字、年份、電話、單位、溫度、百分比、範圍、分數、網路用語等念法轉換問題。支援本地 TTS 引擎(Kokoro、Matcha、CosyVoice、Qwen3-TTS、sherpa-onnx、vLLM、WSL2)的選型、首句延遲、取消、快取、備援音源、視訊記憶體管理,以及語音輸入與插話。提供完整的流程規則:先轉念法再切句,流式輸出時透過「扣住邊界」機制(數字後等 2 字、段落銜接等)確保逐字與整段念法一致。附有 139 條驗收對照用例(golden-cases.json)與檢查腳本(check-tn.mjs),可快速驗證實作正確性。適用於朗讀、語音助手、AI 角色對話、有聲書、播報、TTS 前處理等場景,亦可用於英文關於中文文本規範化的技術討論。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/RedCarpG/redcarpg-skills/tree/HEAD/skills/chinese-tts

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

中文語音合成:文本規範化與工程 是做什麼的?

這個 skill 來自一個天天在說話的 AI 桌寵(見文末「來源與維護」):Claude 串流回覆,逐句交給本機 TTS 唸出來。下面的規則都有測試,數字都是量過的。

一句話原則:唸法在自己這層轉好,引擎只管發音。 交給引擎的話,換一個引擎唸法就變;整個換成現成的 TN 庫,也有幾處會變差。現成庫(wetext、PaddleSpeech)拿來對照、補規則。

流程

模型的串流文字
  → ① 過濾:去掉裝飾、emoji、列表符號;程式碼區塊、表格、鏈接換成一句話(串流時要能認出被拆開的)
  → ② 轉唸法:數字、時間、單位、符號、唸法替換表(串流時扣住邊界)
  → ③ 切句:第一段切到第一個逗號,之後超過 40 字在逗號處切
  → ④ 合成:只比唸到的地方提前約 20 秒;打斷時真的停掉推理

順序不能換:先轉唸法,再切句。 先切句、後清理時實測出三個錯:

原文先切句的結果問題
下午14:30開會下午14: / 30開會冒號被當成逗號,時間被切開
看這裡:https://…/pull/7 就行https: / //…/pull/7 就行鏈接被切成兩半,地址被逐字唸
大概3~5天大概35天~ 被當裝飾去掉,唸成「三十五天」

半角 : 只在後面跟空白時才當逗號。

串流要扣住邊界

整句轉對了,串流不一定對。逐字串流時「工作了26年」「80年代」被唸成「二六年」「八零年代」,因為數字後面的字還沒到;-10°C 那段被當成英文原樣唸了。

  • 數字後面再等 2 個字才放出去;單位隔著空格也要能認(跑了 5 先扣住,等 km)。
  • 轉下一段時帶上上一段末尾幾個漢字(判斷「了 26 年」要看到前面的「了」)。
  • 最多扣 200 字,程式碼區塊、表格最多扣 4000 字,到上限就放。
  • 每條測試都按「逐字餵」和「整段餵」各跑一遍,結果要一樣。

規則速查(詳見 references/rules.md)

類例子唸法
年份2026年、2026屆、26年見逐位:二零二六年、二零二六屆、二六年見
年數工作了26年、80年代、26年前照數量:二十六年、八十年代、二十六年前
號碼電話、驗證碼、編號27149、房間1201逐位,1 唸「幺」,橫槓和空格處停一下
五位數95588 / 價格 12999沒量詞、不以 0 結尾、前面不是說錢的 → 號碼;否則照數量
網路用語666、2333、520 單獨出現 / 666個讚、花了888逐位 / 照數量(只認一張固定單子)
單位前的 22個、2L、2℃兩個、兩升;溫度除外:二攝氏度
單位60km/h、3kWh、5min、10mg每小時六十公里、三度電、五分鐘、十毫克
不轉的單位4g網路、5A景區、16GB原樣交給引擎
範圍、百分比3~5%、3-5km、-1.5~2百分之三到五、三到五公里、負一點五到二
時間14:30、13:00、9:05十四點半、十三點、九點零五(24 小時制)
日期、分數10/26 交 / 有7/12的觀眾十月二十六號 / 十二分之七(前面是「有、佔、約」才當分數)
符號#15、2x、x3、100w十五號、兩倍、乘三、一百萬

用對照用例檢查

references/golden-cases.json 有 115 條整段用例和 24 條串流用例,都是原項目驗收過的唸法。scripts/check-tn.mjs 拿它們測你的實現:

node scripts/check-tn.mjs ./my-tn.mjs                  # 模組匯出 normalize(text) 和(可選)createStream()
node scripts/check-tn.mjs ./my-tn.mjs --only 號碼      # 只看某一組
  • 比較時忽略空白和常見標點,只比唸法。帶 note 的用例是「參考」,只報出來不算失敗。
  • 新寫 TN 時把它當驗收線;改規則時跑一遍,防止改好一處、壞了另一處。
  • 有爭議的唸法(比如「這台電腦 12999」會被當成號碼)原項目是接受了的。你的產品想要別的唸法,就改用例,並在用例旁寫為什麼。

唸錯了怎麼查

分四類:唸之前沒寫成唸法;多音字是模型猜錯;參考錄音有問題;隨機的(重抽一次就好)。

用當前聲音和另外兩個聲音各唸同一句:每個聲音都在同一個字上錯,就加唸法替換表;只有一個聲音怪,就換聲音。每次把原文和轉出來的唸法一起記進日誌(jsonl),回頭查得到。

工程(詳見 references/engines.md)

  • 首句延遲: 第一段只切到第一個逗號。Matcha 第一個字到達後 0.65 秒出第一段音訊。
  • 最有效的提速是快取: 沒合成過的句子 CosyVoice 首塊 2.6–3 秒,命中快取 6 毫秒。使用者一開口就預合成墊話(「嗯」「我想想」)。
  • 取消要真的停掉推理: vLLM 連線一斷就 abort_request,否則下一句要等 4.9 秒(做了以後 0.8–1.7 秒)。
  • 英文會被靜默跳過: 有的引擎不唸 GitHub、PR、%;依賴升級前重新驗證英文。
  • 備援音源: 主音源沒就緒或一開口就出錯,就換備援;唸到一半出錯不重唸。服務的 HTTP 起來了不等於模型載入好了,遇到 503 要重試。

來源與維護

  • 來源: Cirra(AI 桌寵,RedCarpG/cirra-deskpet)和它的語音服務 cirra-voice,2026-10 至 2026-11。
    • 程式碼:sidecar/src/tts/speech/(numbers.ts、units.ts、links.ts、filter.ts、overrides.ts、speech.test.ts)、sidecar/src/tts/splitter.ts、sidecar/src/tts/pronunciations.ts。
    • 文件:docs/speech.md、docs/speech-tn.md(119 句三方對照)、docs/tts.md、docs/voices.md、docs/voice-chat.md、docs/voice-chat-2.md、docs/voice-install.md、docs/perf-checkup.md。
    • 經驗:私人 repo 的 lessons/chinese-tts.md。
  • 源頭: RedCarpG/redcarpg-skills 的 skills/chinese-tts/。~/.claude/skills/ 裡的是安裝出來的副本,不要直接改。references/golden-cases.json 是 2026-11-10 從 Cirra 的 speech.test.ts 用腳本抽出來的,兩邊不會自動同步。
  • 怎麼改:
    • 在 redcarpg-skills 裡改,走 PR;manifest.json 版本加一,node scripts/validate.mjs 通過後發版(tag chinese-tts-v<版本>),再重裝本機副本。先看 lessons/chinese-tts.md 有沒有新條目可以收進來。
    • Cirra 的 TN 規則有變化時,重新抽一次用例(抽的辦法:讀 speech.test.ts 裡 readNumbers 那組和「串流」那組的 [原文, 唸法]),並用 Cirra 編好的 sidecar/dist/tts/ 接一個適配模組跑 check-tn.mjs,應該全過。
    • 引擎的數字(延遲、即時率、視訊記憶體)是 2026-10 在一台 8 GB 視訊記憶體、CPU 沒有 VNNI 的電腦上量的,換了硬體要重新量。
  • 更新記錄:
    • 2026-11-12 · 1.0.0,搬進 redcarpg-skills 公開發佈。改掉本機絕對路徑,來源項目寫成連結;內容不變。
    • 2026-11-10 · Cirra · 初版:流程和順序、串流邊界、規則速查和細則、唸錯排查、引擎工程;139 條對照用例和 check-tn.mjs(用 Cirra 的實現跑過,全過);evals/ 裡兩個測試提示。

Individual skills in this repo

This repo contains 5 individual skills — each has its own dedicated page.

frontend-verification

改完网页/前端界面(CSS、布局、组件、动画、响应式、深色模式、打印)之后怎样验证并拿出证据:先用内置浏览器预览,覆盖不到时用无头 Chrome 截图或读 DOM(预览面板被隐藏、批量截多个视口、要先进入某个状态、要拿 DOM 结果),附可直接运行的 shot.sh / shot.mjs 脚本。还收录无头 Chrome 的坑(requestAnimationFrame 动画停在第一帧、375 宽被撑成 500、深色模式跟随系统)、字体不显示或像宋体的排查、整页截图里滚动动画区块空白、vitest 排除 .claude worktree,以及桌面/手机/英文/繁體/深浅色/打印的核对清单。只要改了界面、要截图、要查响应式或深色模式、动画不动,或者准备说“界面改好了”,就用这个 skill,哪怕用户只说“看看效果”。Use after any UI/CSS/layout/animation change to verify it, take screenshots at several viewports, check dark mode / mobile / print, or debug animations frozen in headless Chrome.

immersive-cultural-ui

做重氛围、带东方古典或神秘学气质的沉浸式网页:深色夜空、细金线、薄雾、宣纸纹理、竖排中文、书法批注、景深视差、开场时逐层亮起。适用于命理排盘(八字、紫微、占星、塔罗)、黄历与二十四节气、星图、典籍诗词、博物馆展品、节庆和有仪式感的产品页。只要用户想要「有氛围、沉浸、古风、国风、东方、神秘、仪式感」的页面,或者要竖排、书法字体、星空、水墨、宣纸效果,即使没有点名风格,也用这个 skill。它提供一套带具体数值的风格配方(天书),装饰、动效、竖排和字体的做法,可复用代码和交付前检查清单。和 web-design-engineer 配合:那边管通用流程,这里管这一种风格。Also use for English requests for immersive, mystical, Chinese-classical, almanac, astrology, tarot or museum-exhibit pages.

RedCarpG/animation-capture

把会动的东西按固定时间一帧一帧录下来,做成左右对比的 GIF 或逐帧对照图,给人验收、对比改动前后、放进说明或 PR:网页的 CSS 过渡和动画、element.animate()、requestAnimationFrame 写的 JS 动画、canvas 游戏、three.js / VRM 角色、PixiJS / Live2D 角色都适用。附脚本:record.mjs(无头 Chrome + 假时钟,页面不用改,渲染多慢时间轴都准,两次录的逐帧一样)、make_gif.py(几个变体并排、标签、共用调色板)、clock-shim.js。还讲先逐帧记数值再录 GIF、开关前后怎么做变体、怎么取景,以及实测过的坑(Chrome 虚拟时间不可靠、等加载时别推时钟、Vite 首次打开会刷新页面、Live2D 运行库要先加载、无头 Chrome 用完要关、别人模型的许可)。只要用户想「录个 GIF」「做个动图给我看」「对比一下改之前和改之后的动画」「把动作录下来」「验收一下动画效果」,或者要给动画、动效、角色动作拿出能看的证据,就用这个 skill,即使没提 GIF。Also use for English requests to record an animation as frames or a GIF, make a before/after comparison of motion, or capture deterministic frames from a web page, canvas, three.js, VRM or Live2D scene.

RedCarpG/live2d-vrm-animation

在网页或桌面应用里让 Live2D(Cubism,PixiJS)和 VRM(three.js + @pixiv/three-vrm)角色动起来:加载顺序、程序姿势和动作片段互相覆盖、在物理之前叠加、VTube Studio 模型补齐(没有 Idle、没眨眼、头角度是物理输出、8K 贴图、包围盒被特效带偏)、动作通道和定住、表情存取和道具冲突、three.js AnimationMixer 的坑(不写没变的值、LoopOnce 提前关掉)、程序「带动层」让手 K 和 AI 动作不僵、动捕片段只取上半身、弹簧骨骼延迟和跟节拍、裙子穿模、让 AI 生成表情和动作的数据格式与校验规则,以及逐帧记录的验证方法。只要用户在做虚拟形象、桌宠、VTuber 工具、数字人,提到 Live2D、Cubism、model3.json、motion3、exp3、physics3、VTube Studio、VRM、VRMA、three-vrm、Mixamo、动捕、SpringBone,或者抱怨「动作一顿一顿的」「动作僵」「手放下又抬起来闪一下」「头不跟着动」「定不住」「表情看不出来」「做动作脸上没表情」「手指僵、直板手」「托腮够不到下巴」「眼睛呆、一直盯着」「腿站不稳、脚滑」,就用这个 skill。Also use for English requests about animating Live2D or VRM avatars, procedural idle motion, physics, expressions, or AI-generated character motions.

vrm-model-conversion

把带骨架的 3D 人物模型(FBX、PMX/MMD、XPS、glTF/GLB、.blend;来自 Mixamo、MMD、Unity/VRChat、Daz Genesis、Auto-Rig Pro、Rigify、3ds Max Biped、游戏提取)在 Blender 后台转成 VRM 1.0,给 three-vrm 网页、桌宠、VTuber 软件、VRChat 外的应用用。管:解压和挑哪份源文件、各格式怎么导入、骨头名自动对应到 VRM 标准骨骼、A-pose 转 T-pose、表情(已有形态键直接绑;只有脸部骨头的烘成形态键)、头发和衣服的弹簧骨骼(没有物理骨的就加骨链、按位置重新分权重)、碰撞体、MToon 材质和发片透明、贴图缩小、VRM meta 和许可,以及一份检查清单。附可复用的 Blender 脚本 vrm_kit.py(参数化,不写死文件名)、模板 build_template.py、不用 Blender 的检查脚本 inspect_vrm.py。只要用户想「把这个模型转成 VRM」「这个 FBX/PMX 能不能给 three-vrm 用」「给模型加表情、加头发物理、加弹簧骨」「VRM 的表情不动、头发不飘、裙子穿模、碰撞体没用」「下载了个模型想当桌宠/虚拟形象」,就用这个 skill,即使没说 VRM。Also use for English requests to convert FBX/PMX/glTF/blend avatars to VRM, set up VRM expressions, spring bones or colliders, or debug a VRM export from Blender.

相關技能