Communityコーディング&開発github.com

中文语音合成:文本规范化与工程

让程序将中文(夹杂英文、数字、链接、代码)念出来时的文本规范化(TN)和语音合成工程:先转念法再切句、流式输出时扣住数字边界、年份/电话/验证码/单位/温度/百分比/范围/分数/网络用语的念法、念法替换表、查错方法;以及本机 TTS 引擎的选型、首句延迟、缓存、取消、后备音源、显存管理等。

中文语音合成:文本规范化与工程 とは?

このスキルは、AIエージェントがテキスト読み上げ(TTS)を行う際に、中国語のテキストを正しく読み上げるためのテキスト正規化(TN)と音声合成エンジニアリングを提供します。流れとしては、まずフィルタリング、次に読み方への変換(数字・日付・単位・URLなど)、そして文の分割、最後に音声合成を行います。特にストリーミング出力時に、数字の境界(例:「26年」が「二六年」にならないように)を適切に保持するための待機ルールや、先に分割すると生じる問題(例:時間表記の「14:30」がコロンで分割される)を回避するための処理順序の重要性を説明しています。また、139の確認済みテストケースとテストスクリプトが付属しており、実装の正しさを検証できます。このスキルは、Claude(Claude Code)、Cursor、Codex、Windsurf、CopilotなどのAIエージェントが中国語の読み上げを行う際に、数字や記号の誤読、ストリーミング時の遅延や不整合、エンジンの選定やキャッシュ、取消しといった実践的な問題を解決します。

対応✓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に質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

中文语音合成:文本规范化和工程

这个 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.

関連スキル