유튜브 쇼츠 자동화 시스템을 구축하면서 TTS 엔진 선택이 생각보다 큰 고민이었습니다.
ElevenLabs는 품질이 좋지만 비용이 발생합니다. OpenAI TTS도 마찬가지입니다. 무료로 쓸 수 있으면서 한국어 품질이 괜찮은 걸 찾다가 Edge-TTS를 선택했습니다. Microsoft Edge 브라우저의 음성 합성 기술을 무료로 사용할 수 있는 라이브러리입니다.
실제로 써보니 한국어 품질은 생각보다 훨씬 좋았습니다. 다만 두 가지 문제가 있었습니다. 영문 혼재 시 발음 오류, 그리고 자막 싱크 불일치입니다. 이 글에서는 UGREEN DXP4800PLUS NAS Docker 환경에서 Edge-TTS를 설치하고, 실제로 겪은 문제와 해결 방법을 정리합니다.
왜 Edge-TTS를 선택했는가
TTS 엔진 선택 기준은 세 가지였습니다.
- 무료 또는 저비용
- 한국어 품질
- Python 연동 가능
비교 결과:
| TTS | 비용 | 한국어 품질 |
|---|---|---|
| ElevenLabs | 유료 | 최상 |
| OpenAI TTS | 유료 | 상 |
| Clova | 유료 | 상 |
| Edge-TTS | 무료 | 중상 |
| gTTS | 무료 | 중 |
Edge-TTS는 무료이면서 한국어 품질이 실용적인 수준이었습니다. 특히 ko-KR-SunHiNeural 목소리는 자연스러운 억양으로 쇼츠 자동화에 충분히 사용 가능했습니다.
실제로 생성한 음성을 유튜브 쇼츠 테스트 영상에 적용해 보니 TTS 특유의 기계음이 완전히 사라진 것은 아니었지만, 무료 서비스라는 점을 고려하면 충분히 실사용 가능한 수준이었습니다.
특히 30~40초 길이의 AI 자동화 관련 쇼츠에서는 직접 들어봤을 때 TTS 특유의 느낌이 크게 두드러지지 않았습니다.
NAS Docker 환경에서 Edge-TTS 설치
UGREEN DXP4800PLUS NAS에 SSH로 접속한 후 설치합니다.
python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install edge-tts
설치 확인:
edge-tts --version
# 예: 확인 시점 출력값(설치 환경마다 다를 수 있음)
사용 가능한 한국어 목소리 확인:
edge-tts --list-voices | grep ko-KR
주요 한국어 목소리:
ko-KR-SunHiNeural(여성, 자연스러운 억양)ko-KR-InJoonNeural(남성, 안정적인 톤)
기본 음성 생성
Python에서 사용하는 기본 방법입니다.
import asyncio
import edge_tts
async def generate_tts(text: str, output_path: str):
tts = edge_tts.Communicate(text, "ko-KR-SunHiNeural")
await tts.save(output_path)
asyncio.run(generate_tts("안녕하세요. 테스트입니다.", "/tmp/test.mp3"))
명령줄에서 바로 생성하는 방법:
edge-tts \
--voice "ko-KR-SunHiNeural" \
--text "안녕하세요 테스트입니다" \
--write-media /tmp/test.mp3
실제로 겪은 문제 ① 영문 혼재 시 발음 오류
쇼츠 자동화 대본에는 영문이 자주 섞입니다.
"ChatGPT vs Claude 비교"
"YouTube Data API 쿼터 절약"
"n8n으로 자동화하기"
이걸 그대로 TTS에 넣으면 발음이 어색해집니다.
vs → "브이에스" 또는 "브스"
API → "에이피아이" 또는 이상한 발음
GPT → "지피티" 또는 "그피트"
n8n → 읽지 못함
% → 무시하거나 "퍼센트"
$ → 무시하거나 "달러"
해결 방법: TTS 전처리 규칙 적용
def preprocess_for_tts(text: str) -> str:
replacements = {
"FastAPI": "패스트에이피아이", "ChatGPT": "챗지피티",
"Docker": "도커", "n8n": "엔에잇엔", "NAS": "나스",
"GPT": "지피티", "API": "에이피아이", " vs ": " 대 ",
" VS ": " 대 ", "%": "퍼센트", "$": "달러", "#": "",
}
# 긴 토큰을 먼저 바꿔 FastAPI가 API 규칙에 먼저 걸리지 않게 한다.
for old in sorted(replacements, key=len, reverse=True):
text = text.replace(old, replacements[old])
return text
전처리 후 TTS 생성:
raw_text = "ChatGPT vs Claude 비교, API 쿼터는 10,000유닛"
clean_text = preprocess_for_tts(raw_text)
# "챗지피티 대 Claude 비교, 에이피아이 쿼터는 10,000유닛"
await generate_tts(clean_text, "/tmp/output.mp3")
실제로 겪은 문제 ② 자막 싱크 불일치
문장 길이를 무시하고 자막 시간을 균등 분할하면 실제 발화와 자막이 어긋날 수 있습니다. 현재 edge-tts는 음성 스트림과 함께 WordBoundary·SentenceBoundary 이벤트를 제공하므로, 이 이벤트를 한 번의 스트림에서 받아 자막 타임라인을 만들 수 있습니다.
해결 방법: 공식 --write-subtitles 옵션으로 SRT 생성
edge-tts \
--voice "ko-KR-SunHiNeural" \
--text "안녕하세요 테스트입니다" \
--write-media /tmp/output.mp3 \
--write-subtitles /tmp/output.srt
Python에서는 같은 Communicate 객체의 스트림을 한 번만 소비하면서 오디오 청크는 파일에 쓰고, 경계 이벤트는 SubMaker에 전달합니다.
import asyncio
import edge_tts
async def generate_tts_with_subtitle(text: str, audio_path: str, subtitle_path: str):
communicate = edge_tts.Communicate(text, "ko-KR-SunHiNeural")
submaker = edge_tts.SubMaker()
with open(audio_path, "wb") as audio_file:
async for chunk in communicate.stream():
if chunk["type"] == "audio":
audio_file.write(chunk["data"])
elif chunk["type"] in ("WordBoundary", "SentenceBoundary"):
submaker.feed(chunk)
with open(subtitle_path, "w", encoding="utf-8") as sub_file:
sub_file.write(submaker.get_srt())
asyncio.run(generate_tts_with_subtitle(
"안녕하세요 테스트입니다",
"/tmp/output.mp3",
"/tmp/output.srt",
))
edge-tts 공식 구현도 같은 스트림에서 오디오와 경계 이벤트를 처리한 뒤 SubMaker.get_srt()로 SRT를 저장합니다. 스트림을 모두 소비한 뒤 같은 객체로 다시 save()를 호출하지 않습니다. VTT가 필요하다면 생성된 SRT를 별도 변환 단계에서 바꾸는 편이 안전합니다.
쇼츠 자동화 파이프라인 적용
현재 운영 중인 유튜브 쇼츠 자동화 파이프라인에서 Edge-TTS는 이 위치에 있습니다.
YouTube API 트렌드 수집
↓
AI 언어 모델 대본 생성
↓
TTS 전처리 (발음 오류 수정)
↓
Edge-TTS 음성 생성 + SRT 자막
↓
FFmpeg 영상 합성
↓
drafts 폴더 저장
실제 운영 코드 구조:
async def generate_video(trend_data: dict):
# 1. 대본 전처리
raw_script = trend_data["full_text"]
clean_script = preprocess_for_tts(raw_script)
# 2. TTS + 자막 생성
await generate_tts_with_subtitle(
clean_script,
"/tmp/output.mp3",
"/tmp/output.srt"
)
# 3. FFmpeg 합성
compose_video("/tmp/output.mp3", "/tmp/output.srt")
마무리
Edge-TTS는 무료 TTS 중에서 한국어 품질이 가장 실용적인 수준입니다. 다만 두 가지는 반드시 고려해야 합니다.
첫째, 영문 혼재 시 전처리 규칙이 필요합니다. vs, API, GPT 같은 용어는 미리 한국어로 변환해야 자연스러운 발음이 나옵니다.
둘째, 자막 싱크는 균등 분할 방식이 아니라 --write-subtitles 옵션으로 실제 발화 타이밍 기반으로 생성해야 합니다.
이 두 가지만 해결하면 쇼츠 자동화에 충분히 사용 가능한 품질이 나옵니다.