| name | tts-synthesis |
| description | Synthesize TTS audio from course transcripts with pluggable engines (OpenAI gpt-4o-mini-tts default, edge-tts fallback). Use when turning a class transcript.txt into per-slide MP3s plus a concatenated full.mp3, handling [slide N] / [pause:ms] markers, retries, and per-slide speaker_affect overlays. Triggered after coherence-review passes and before/within asset-build, or as a standalone step. Also invoke for "์ค๋์ค ์์ฑ", "TTS ํฉ์ฑ", "๊ฐ์ ์์ฑ ๋ง๋ค์ด", "voice ๋ณ๊ฒฝ", "speed ์กฐ์ ". |
TTS Synthesis โ Pluggable Audio Pipeline
transcript.txt๋ฅผ per-slide MP3 + full.mp3๋ก ํฉ์ฑํ๋ค. OpenAI gpt-4o-mini-tts + nova + speed 1.3๊ฐ ๊ธฐ๋ณธ. edge-tts๋ offline/๋ฌด๋ฃ ๋์.
์ ์ด ์คํฌ์ด ์กด์ฌํ๋๊ฐ
์๋ ํ๋ค์ค์ Non-Goal์ด์์ผ๋ Phase 7์์ ํ์ฅ. TTS ํฉ์ฑ์ (1) transcript ๋ง์ปค ํ์ฑ, (2) ์์ง๋ณ API ํธ์ถ, (3) pause ๋ฌด์ ์ฝ์
+ concat, (4) retry๊ฐ ๋ชจ๋ ์ฝํ์์ด ์คํฌ๋ฆฝํธํํ์ง ์์ผ๋ฉด ์ฌ์ฌ์ฉ์ด ์ด๋ ต๋ค.
์คํ
ํ์ค ํธ์ถ
python3 scripts/synthesize-tts.py \
course/sections/<sec>/classes/<cls>/transcript.txt \
course/sections/<sec>/classes/<cls>/audio
์๋ ๊ธฐ๋ณธ๊ฐ (openai + nova + speed 1.3 + default ์น๊ทผ ko instructions)์ ์ฌ์ฉ.
๋ํผ (pipefail ๋ณด์ฅ)
bash .claude/skills/tts-synthesis/scripts/run.sh \
<transcript.txt> <out_dir> [์ถ๊ฐ ํ๋๊ทธ]
๋ํผ๊ฐ set -o pipefail + tee์ ์ค์ exit ์ ํ + .env ๋ก๋ฉ์ ์ฑ
์์ง๋ค.
์์ง ์ ํ
--engine edge --voice ko-KR-SunHiNeural
--voice shimmer
--model tts-1-hd
--speed 1.0
์
๋ ฅ ๋ง์ปค ๊ท๊ฒฉ
[slide N] (์ค ๋จ๋
, N=1..) โ TTS ํ์ฒ๋ฆฌ์ฉ ์ค๋์ค ๊ตฌ๊ฐ ๋ถํ ๊ธฐ์ค
[pause:Xms] โ ๋ฌด์ ์ฝ์
(๊ธฐ๋ณธ 300~800). speed ํ๋ผ๋ฏธํฐ์ ์ํฅ๋ฐ์ง ์์ (์๋ณธ ์ ์ง, ์ฌ์ฉ์ ํ์ธ๋ ์ ํธ)
[emph]...[/emph] โ SSML ๋ณํ ์ <emphasis> (OpenAI๋ instructions๋ก ๋์ฒด)
์ถ๋ ฅ ๊ตฌ์กฐ
<out_dir>/
slide_01.mp3 ~ slide_NN.mp3 # ์ฌ๋ผ์ด๋๋ณ
full.mp3 # ์ ์ฒด concat
์์ด์ ํธ/์ค์ผ์คํธ๋ ์ดํฐ ์ฐ๊ฒฐ
์ด ์คํฌ์ tts-synthesizer ์์ด์ ํธ์ ๋จ์ผ ์ฑ
์ ์คํฌ. course-builder ์ค์ผ์คํธ๋ ์ดํฐ Phase 5์ step 4 ๋ก ํตํฉ๋์ด ์์ผ๋ฉฐ, asset-builder ๊ฐ build-bundle.sh ์์์ ์๋ ์์ ํธ์ถํ๋ค:
Phase 5 (build):
step 1 gate (asset-builder)
step 2 Marp HTML (asset-builder)
step 3 Marp PNG (asset-builder, SKIP_PLAYER ๊ฐ๋ฅ)
step 4 TTS ํฉ์ฑ โ tts-synthesizer (์ด ์คํฌ), per-class
step 5 manifest (asset-builder)
step 6 player HTML (asset-builder, SKIP_PLAYER ๊ฐ๋ฅ)
step 7 SSML ๊ฒ์ฆ (asset-builder)
step 8 bundle.zip (asset-builder)
์๋ ํธ์ถ ์กฐ๊ฑด (๋ชจ๋ ์ถฉ์กฑ):
coherence_report.overall == "pass" โ gate ํต๊ณผ
OPENAI_API_KEY ์กด์ฌ (์์ผ๋ฉด edge-tts ํด๋ฐฑ)
SKIP_TTS != 1
audio/full.mp3 ๋ฏธ์กด์ฌ ๋๋ FORCE_TTS=1
standalone ํธ์ถ(๋น๋ ์ธ๋ถ ์ฌ์ฉ์ ํธ๋ฆฌ๊ฑฐ)๋ ์ง์ โ tts-synthesizer ์์ด์ ํธ๋ฅผ ์ง์ invoke.
ํ์ง ๊ท์น
Retry
transient ์คํจ(edge-tts rate limit, OpenAI 429/5xx)๋ 4ํ exponential backoff๋ก ์๋ ๋ณต๊ตฌ.
Idempotency
๋์ผ transcript + ๊ฐ์ ํ๋ผ๋ฏธํฐ ์ฌ์คํ ์ ๊ฒฐ๊ณผ ํ์ผ ํฌ๊ธฐ๋ ยฑ2% ๋ด ์ผ์น (TTS ์์ฒด์ ๋ฏธ์ธ ๋ณ๋). audio/ ๋๋ ํ ๋ฆฌ ํต์งธ๋ก ์ญ์ ํ ์ฌ์คํ์ ๊ธฐ๋ณธ ์ ๋ต์ผ๋ก.
Speaker affect ์ฃผ์
(Phase 7 ํ์ฅ)
--beats <beats.json>์ ์ฃผ๋ฉด slide๋ณ๋ก beat์ speaker_affect(hook=ํธ๊ธฐ์ฌ, teach=์ฐจ๋ถ, example=ํฅ๋ถ, practice=์ง๋ฌธ, recap=ํ์ )๋ฅผ ๊ธฐ๋ณธ instructions์ ๋ง์์ slide๋ง๋ค ๋ค๋ฅธ ๋์์ค๋ก ํฉ์ฑ.
์ฒดํฌ๋ฆฌ์คํธ
์ฐธ๊ณ
- ์๋ณธ ์คํฌ๋ฆฝํธ:
scripts/synthesize-tts.py (canonical, ์ด ์คํฌ์ด ํธ์ถ)
- ์ค์ธก char/sec rate:
skills/script-writing/SKILL.md ยง"๊ธธ์ด ๊ณ์ฐ"
- pause ๋ณด์กด ์ ์ฑ
์ ์ฌ์ฉ์ ํ์ (memory/feedback_tts_config.md)