Local TTS
기본 음성: Qwen3-TTS 1.7B CustomVoice, 스피커 aiden, 8-bit GGUF (Q8_0), qwentts.cpp (C++/ggml, MIT) 구동, 다음 스타일 지시 포함:
따뜻하고, 맑고, 호기심 가득한, 마치 친근한 기술 설명 영상 내레이터처럼. 편안하고 일정한 속도.
블라인드 청취 테스트에서 Kokoro, Chatterbox, PyTorch Qwen3-TTS, VoxCPM2 및 Phonon을 이겼습니다 (자세한 내용은 references/benchmarks.md 참조). 8GB RTX 4070 노트북 GPU에서 모델 로딩을 포함해 약 실시간의 4배 속도로 실행됩니다: 18분 내레이션을 약 4.5분 만에 처리합니다.
설정 (머신당 한 번)
python -I <skill>/scripts/say.py --check를 먼저 실행하세요. OK가 출력되면 이 섹션은 건너뛰십시오. 그렇지 않으면 엔진을 설정하거나 사용자에게 설정을 요청하세요. 10-20분 정도 걸리며 약 2.5GB의 디스크 공간이 필요합니다.
- qwentts.cpp 빌드. 미리 빌드된 Windows 바이너리가 없으므로 소스에서 빌드하세요:
Windows에서는 VS 2022(또는 최신) 빌드 도구(C++ 워크로드 포함), CMake, Ninja 및 CUDA 툴킷을 설치한 후, 리포지토리에서git clone --recurse-submodules https://github.com/ServeurpersoCom/qwentts.cpp ~/tools/qwentts.cpp cd ~/tools/qwentts.cpp ./buildcuda.sh # NVIDIA (Linux); AMD/Intel의 경우 ./buildvulkan.sh; CPU 전용(e.g. macOS)의 경우 ./buildcpu.shbuildcuda.cmd를 실행하세요.vcvars64.bat가 다른 위치에 있으면 해당 스크립트 상단의 경로를 편집하세요. 단일 GPU만 대상으로 하려면 cmake 라인에-DCMAKE_CUDA_ARCHITECTURES=89(RTX 40xx; 86 = RTX 30xx, 120 = RTX 50xx)를 추가하세요. - 가중치 다운로드 (~2 GB) Hugging Face의
Serveurperso/Qwen3-TTS-GGUF에서:pip install -U huggingface_hub hf download Serveurperso/Qwen3-TTS-GGUF qwen-talker-1.7b-customvoice-Q8_0.gguf qwen-tokenizer-12hz-Q8_0.gguf --local-dir ~/tools/qwen-gguf - say.py가 이들을 가리키도록 설정 다른 폴더를 사용한 경우:
QWEN_TTS_HOME(체크아웃 폴더),QWEN_TTS_EXE(바이너리) 또는QWEN_TTS_MODELS(.gguf 폴더)를 설정하세요. Windows에서say.py는 PATH에%CUDA_PATH%\bin\x64를 자동으로 추가합니다 (CUDA_BIN으로 재정의 가능). say.py --check를 다시 실행한 후, 한 줄을 테스트로 음성 출력하세요.
하드웨어: Q8_0의 경우 8GB VRAM이면 충분합니다 (~3GB 사용). GPU가 없으면 CPU 빌드가 약 4분의 1 속도로 작동합니다. GGML_BACKEND=CPU는 GPU 빌드를 강제로 CPU에서 실행하도록 합니다.
생성 전에
- GPU를 다른 것이 사용 중인가요? 게임이나 GPU 집약적인 앱이 실행 중이면 생성 속도가 약 4배 느려지고 해당 앱이 버벅거릴 수 있습니다. 긴 작업을 시작하기 전에 물어보세요. 사용자가 그러한 앱을 지정하면
TTS_BUSY_APPS=app1,app2를 설정하고say.py가 실행 중일 때 경고합니다. - 더 나은 모델을 확인할 가치가 있나요? 아래 "계속해서 더 나은 모델 찾기"를 참조하세요. 마지막 확인이 약 6주 이상 지났고 작업이 (한 줄 테스트가 아닌) 실제 내레이션이라면 먼저 빠른 스캔을 수행하세요.
- 텍스트가 사람처럼 들리나요? 음성은 AI스러운 표현을 매번 같은 억양으로 읽으므로, 페이지에서보다 패턴이 더 두드러집니다. 몇 줄 이상의 내레이션의 경우
whiteboard-explainer스킬(동일 플러그인,references/)에서natural-narration.md를 읽고scripts/aispeak_scan.py를 실행하세요. 이 스크립트는 script.py 또는 일반 텍스트 파일을 입력으로 받습니다.
생성
스크립트는 표준 라이브러리만 사용하므로 Python 3.10+이면 작동합니다. <skill>은 이 스킬의 폴더입니다.
python -I <skill>/scripts/say.py "첫 번째 줄." "두 번째 줄." -o out.wav # 하나의 WAV, 0.35초 간격
python -I <skill>/scripts/say.py --file lines.txt -o clips/ # 000.wav, 001.wav, ...
옵션:
| 플래그 | 기능 |
|---|---|
--speaker | aiden (기본값); ryan은 다른 네이티브 영어 음성입니다 |
--instruct | 스타일 텍스트, 예: "신나고 빠르게" 또는 "차분하고 진지하게" |
--seed N | 반복 가능한 테이크를 제공합니다 |
--gap S | 결합된 파일에서 줄 사이의 침묵 시간(초) |
--srt F | 결합된 WAV와 동기화된 자막도 작성합니다 (자막 참조) |
--quant | Q8_0 (기본값, 최고) 또는 Q4_K_M (더 작고 약간 덜 부드러움; 먼저 다운로드 필요) |
--check | 발견된 엔진, 모델 및 CUDA 폴더를 보고합니다 |
작동 방식:
- 모든 줄이 하나의 프로세스를 통해 처리되므로 모델이 한 번만 로드됩니다 (3-8초). 줄을 한 번에 하나씩 호출하지 말고 한꺼번에 전달하세요.
- 출력은 24kHz 모노 16비트 WAV입니다.
테이크는 샘플링되므로 실행마다 다릅니다:
- 마음에 드는 클립은 보관하세요. 텍스트와 설정을 키로 하여 줄별로 캐시하세요.
- 줄 길이가 문자당 ~0.07초에서 크게 벗어나면 다시 테이크하세요. 이는 단어가 누락되거나 생성되었음을 의미합니다.
비디오 내레이션의 경우:
- 각 클립의 침묵을 약 50ms 패딩으로 자르고, 자신의 간격으로 타임라인에 줄을 배치하세요.
- 최종 트랙을 음량 정규화하세요:
ffmpeg -af loudnorm=I=-16:TP=-1.5:LRA=11.
자막 (.srt): 모든 내레이션 비디오에 제공하세요
각 줄의 시작과 끝을 이미 알고 있으므로, 받아쓸 필요가 없습니다. 해당 타이밍을 사용하여 자막을 만드세요.
say.py와 함께:--srt narration.srt추가 (-o .wav필요). 자막은 결합된 트랙과 정확히 일치합니다.- 자체 파이프라인에서:
scripts/srt.py의to_srt([(start_s, end_s, text), ...], display=[...])를 호출하세요. 각 음성 줄의 비디오 시간 시작/끝을 전달하세요. 또는 CLI 사용:python srt.py timings.tsv -o video.srt. - 음성 철자 수정. 내레이션 텍스트는 종종 음성에 맞춰 작성됩니다: "D I L", 이름의 음성적 재철자, "runner dot HTML", 숫자를 단어로 표기.
display/--display display.tsv(말한 대로작성된 대로)를 사용하여 다시 매핑하세요. 작성된 형식은 화면에 표시된 것에서 가져오고, 숫자에는 숫자 기호를 사용하세요 ("$232", "83%"). - 결과 확인. 남아 있는 띄어쓰기된 대문자 (
[A-Z] [A-Z])와 " dot "이 있는지 grep으로 확인하세요. - 모듈이 적용하는 규칙:
- 자막당 최대 2줄, 42자
- 문장, 구, 단어 순으로 줄 바꿈
- 짧은 문장은 너무 빠르게 지나가지 않도록 병합
- 시간은 길이에 비례하여 분배
- 비디오와 같은 이름 (
Video Name.srt를Video Name.mp4옆에)으로 지정하여 플레이어가 자동으로 로드하게 하세요. VLC에서는--sub-file=로 파일을 강제할 수 있습니다.
whiteboard-explainer 스킬의 template/narration/build_vo.py는 완전한 작동 파이프라인 예제입니다: 줄별 캐시, 재테이크, 침묵 자르기, 일시 정지 성형, 단어 정렬, 큐 테이블 및 립싱크 봉투.
주의사항
- CUDA DLL이 PATH에 있어야 함 (Windows). CUDA 13은 이를
...\CUDA\v13.x\bin\x64에 유지합니다. 해당 폴더가 PATH에 없으면qwen-tts.exe가 출력 없이 자동 종료됩니다.say.py가 자동으로 추가합니다. --stream-by-line -o -는 스트리밍 WAV 헤더를 작성합니다 (크기 0x7fffffff), 줄당 하나씩.RIFF....WAVEfmt에서 분할하고 각 44바이트 헤더를 버리세요. 크기 필드는 신뢰하지 마세요.- Aiden이 단일 문자와 특수 토큰을 잘못 읽습니다. 무작위 Whisper 감사에서 발견됨:
- "h star"는 "a hap" 또는 "our star", "y t"는 "VT", "y"는 "we", "arXiv"는 "ArcSireFolk"로 출력됨.
- 다음은 잘 작동함: 대문자 "H star" / "under H", "why tee" / "why tilde", "archive", "SMILES check".
- "aitch"는 불규칙적입니다. 이름은 단독으로는 괜찮을 수 있지만 문장 중간에 변형될 수 있습니다: 전체 줄 안에서 테스트하세요.
- 문장 첫머리의 K가 누락될 수 있음 ("Kwenputer" → "When Pooter"): "And" 또는 "So"로 줄을 시작하세요.
- 초기 프롬프트 없이 각 클립을 전사한 후, 스크립트와 비교하여 감사하세요. 프롬프트된 Whisper는 의도된 단어를 "듣고" 오류를 숨깁니다. 도구:
whiteboard-explainer/template/narration/audit_vo.py및tts_try.py.
- 콜론에서의 일시 정지. Qwen은 콜론에서 0.6-0.8초 동안 멈추고 때로는 구 중간에도 멈춥니다. 내레이션에서는 구두점 앞의 침묵으로 각 침묵을 제한하고 (템플릿의 build_vo.py에 있는
shape()) 콜론-단편 줄을 피하세요 ("첫째: ..."). - CPU 폴백: Kokoro 82M (
kokoro-onnx)은 평탄하지만 CPU에서 빠르며, GPU가 사용 중일 때 초안 작업에 적합합니다.
계속해서 더 나은 모델 찾기
로컬 TTS는 빠르게 개선되고 있으며, 현재 선택이 곧 깨질 것입니다. 이를 최종 답이 아닌 현 챔피언으로 취급하세요. 특히 큰 내레이션 작업 전이나 마지막 확인이 약 6주 이상 지났을 때 더 새롭고 더 나은 모델을 찾으세요.
- 스캔. 마지막 확인 이후 출시 또는 업데이트된 오픈 가중치 TTS를 웹에서 검색하세요. 다음을 확인하세요:
- TTS Arena / Artificial Analysis 음성 리더보드
- Hugging Face 트렌딩 text-to-speech 모델
- r/LocalLLaMA
- 아래 엔진의 GitHub 릴리스
- 필터. 다음 조건을 모두 충족하는 경우에만 후보로 유지하세요:
- 로컬에서 무료로 사용 가능 (오픈 가중치, 허용적 또는 개인용 라이선스)
- 사용자의 GPU 메모리와 OS에서 실행 가능
- 필요한 언어를 지원
- 품질 면에서 챔피언을 능가하거나, 동등한 품질이면서 훨씬 빠름
- 시험. 후보로
eval/lines.txt를 생성하세요.scripts/voice_metrics.py(pip install numpy librosa; 챔피언 및 기준 녹음은eval/에 있음)로 챔피언과 점수를 비교하세요:- 피치 표준편차 ≥ ~5 반음, 범위 ≥ ~17 반음이 자연스러운 소리에 필요합니다.
- 속도는 생성 시간당 오디오 시간(초)으로 측정하세요.
- 듣기. 사용자에게 후보와
eval/champion_*.wav(ffplay -nodisp -autoexit file.wav) 사이를 귀로 선택하도록 요청하세요. 메트릭은 후보를 선별할 뿐; 귀가 최종 결정을 내립니다. - 기록. 변경된 사항이 없더라도 아래 "마지막 확인" 줄과
references/benchmarks.md를 업데이트하세요. 챔피언이 변경되면eval/champion_*.wav를 교체하고say.py를 업데이트한 후, 이전 모델을 삭제하기 전에 물어보세요.
마지막 확인: 2026-11-02 (웹 설문 조사 및 로컬 VoxCPM2 Q8 및 Phonon 31m/Miles 시험). Aiden이 두 경우 모두 귀로 선호되었습니다. 아직 로컬에서 시도하지 않음: Phonon 40m, OmniVoice, Breeze TTS 2, Drama 3, Orpheus, Dia, Sesame CSM, Spark-TTS, IndexTTS-2, VibeVoice, Higgs Audio, Kyutai TTS 및 Fish/OpenAudio. 자세한 내용은 references/benchmarks.md에 있습니다.