Community코딩 & 개발github.com

chinese-tts

중국어(영어, 숫자, 링크, 코드 포함) 텍스트를 TTS로 읽을 때 필요한 텍스트 정규화(TN) 및 음성 합성 엔지니어링: 읽기 방식 변환 → 문장 분할, 스트리밍 출력 시 숫자 경계 처리, 연도/전화번호/인증코드/단위/온도/퍼센트/범위/분수/인터넷 용어 읽기, 대체 발음표, 잘못 읽은 경우 디버깅, 로컬 TTS 엔진(Kokoro, Matcha, CosyVoice, Qwen3-TTS, sherpa-onnx, vLLM, WSL2) 선택, 첫 문장 지연, 취소, 캐싱, 백업 음원, GPU 메모리, 음성 입력 및 끼어들기. 139개의 검증된 '원문 → 발음' 대조 예제와 검사 스크립트 포함.

chinese-tts란 무엇인가요?

이 기술(스킬)은 중국어 텍스트를 음성 합성(TTS)으로 읽을 때 발생하는 텍스트 정규화(Text Normalization, TN) 및 엔지니어링 전반을 다룹니다. 사용자가 숫자, 날짜, 링크, 특수 기호 등을 포함한 중국어 문장을 자연스럽게 읽어주는 TTS 시스템을 구축할 때 필요한 모든 규칙과 구현 방법을 제공합니다. 주요 기능으로는 연도(2026년 → '이공이육년')와 일반 숫자(26년 → '이십육년')의 구분, 전화번호/인증코드 숫자 읽기, 단위 앞의 숫자 2 처리(2개 → '두 개'), 스트리밍 출력 시 숫자 경계 유지, 문장 분할 순서(먼저 변환 후 분할) 등이 포함됩니다. 또한 Kokoro, Matcha, CosyVoice, vLLM 등 다양한 로컬 TTS 엔진의 지연 시간, 캐싱 전략, 취소 처리, 백업 음원, GPU 메모리 요구사항 등 엔지니어링 측면도 상세히 다룹니다. 이 스킬은 Claude Code, Cursor, Codex 등 모든 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에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

중국어 음성 합성: 텍스트 정규화 및 엔지니어링

이 스킬은 매일 말하는 AI 데스크펫(하단 '출처 및 유지보수' 참조)에서 비롯되었습니다: Claude 스트리밍 응답을 문장 단위로 로컬 TTS에 전달하여 읽습니다. 아래 규칙은 모두 테스트되었으며, 숫자는 측정된 값입니다.

한 줄 원칙: 읽기 방식은 우리 쪽에서 변환하고, 엔진은 발음만 담당합니다. 엔진에 넘기면 엔진마다 읽는 방식이 달라집니다. 기성 TN 라이브러리로 교체해도 몇몇 부분이 달라집니다. 기성 라이브러리(wetext, PaddleSpeech)는 비교 및 규칙 보완용으로 사용합니다.

흐름

모델의 스트리밍 텍스트
  → ① 필터링: 장식, 이모지, 목록 기호 제거; 코드 블록, 표, 링크는 한 문장으로 변환(스트리밍 시 분할된 것을 인식할 수 있어야 함)
  → ② 읽기 방식 변환: 숫자, 시간, 단위, 기호, 발음 대체표(스트리밍 시 경계 유지)
  → ③ 문장 분할: 첫 번째 단락은 첫 번째 쉼표까지만 자르고, 이후 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, 5분, 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.
    • 경험: 개인 저장소의 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를 실행합니다. 모두 통과해야 합니다.
    • 엔진 수치(지연 시간, 실시간 비율, GPU 메모리)는 2026-10에 8GB VRAM, 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.

관련 스킬