fix(melo-test): strip standalone Hangul jamo before synthesis
MeloTTS-Korean's symbol vocab only includes precomposed Hangul syllables. Bare Hangul Compatibility Jamo characters (ㅋㅋㅋ, ㅠㅠ, ㅎㅎ) and Hangul Jamo block code points blow up in `cleaned_text_to_sequence` with `KeyError: 'ㅋ'` (or similar). Pre-clean the request text in `/tts` to drop those code point ranges before handing the string to the model, collapsing the leftover whitespace. If sanitization yields an empty string, return 400 with an explanation instead of a 500 stack trace. Also document the limitation in the README troubleshooting section.
This commit is contained in:
@@ -114,6 +114,11 @@ Content-Type: application/json
|
||||
한국어 발음이 깨짐
|
||||
→ 입력에 영문/이모지가 섞이면 운율이 어색해질 수 있음. 디스코드 봇 통합 단계에서 `TTSClient.textReplace` 같은 사전 치환을 그대로 활용.
|
||||
|
||||
`KeyError: 'ㅋ'` (또는 'ㅠ', 'ㅎ' 등)
|
||||
→ MeloTTS-Korean 의 symbol vocab 은 완성형 음절(가, 나, ...)만 포함하므로 'ㅋㅋㅋ', 'ㅠㅠ' 같은 한글 자모(Hangul Compatibility Jamo) 가 단독으로 들어오면 합성 단계에서 죽음.
|
||||
`server.py` 가 요청 직전에 단독 자모를 자동으로 제거하므로 최신 코드(`git pull`) 받으면 해결.
|
||||
봇 통합 단계에서도 어댑터에서 같은 sanitize 를 적용할 것.
|
||||
|
||||
`RuntimeError: Failed initializing MeCab` / `no such file or directory: ...\unidic\dicdir\mecabrc`
|
||||
→ `unidic` 사전 데이터 미다운로드. 가상환경 활성화 상태에서 `python -m unidic download` 실행 후 재시작.
|
||||
한국어만 써도 MeloTTS 가 임포트 시점에 일본어 모듈을 강제 로딩하기 때문에 이 단계는 필수.
|
||||
|
||||
@@ -8,6 +8,7 @@ GET / -> index.html (테스트 UI)
|
||||
"""
|
||||
import os
|
||||
import io
|
||||
import re
|
||||
import time
|
||||
import tempfile
|
||||
import logging
|
||||
@@ -62,16 +63,38 @@ class TTSReq(BaseModel):
|
||||
speed: float = 1.0
|
||||
|
||||
|
||||
# MeloTTS-Korean 의 symbol vocab 은 완성형 음절(가, 나, ...)만 포함한다.
|
||||
# 'ㅋㅋㅋ', 'ㅠㅠ', 'ㅎㅎ' 같이 한글 자모(Hangul Compatibility Jamo /
|
||||
# Hangul Jamo) 가 단독으로 들어오면 cleaned_text_to_sequence 에서
|
||||
# KeyError 로 죽는다. 합성 전에 미리 제거한다.
|
||||
_STANDALONE_JAMO_RE = re.compile(r"[\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF]+")
|
||||
|
||||
|
||||
def _sanitize_for_melo(text: str) -> str:
|
||||
# 단독 자모를 공백으로 치환한 뒤 연속 공백을 하나로 정리.
|
||||
cleaned = _STANDALONE_JAMO_RE.sub(" ", text)
|
||||
return re.sub(r"\s+", " ", cleaned).strip()
|
||||
|
||||
|
||||
@app.post("/tts")
|
||||
def tts(req: TTSReq):
|
||||
model = state.get("model")
|
||||
if model is None:
|
||||
raise HTTPException(503, "model not ready")
|
||||
text = (req.text or "").strip()
|
||||
if not text:
|
||||
raw = (req.text or "").strip()
|
||||
if not raw:
|
||||
raise HTTPException(400, "empty text")
|
||||
if len(text) > 500:
|
||||
if len(raw) > 500:
|
||||
raise HTTPException(400, "too long (<=500)")
|
||||
text = _sanitize_for_melo(raw)
|
||||
if not text:
|
||||
raise HTTPException(
|
||||
400,
|
||||
"text contains only standalone Hangul jamo (e.g. ㅋㅋㅋ); "
|
||||
"MeloTTS-Korean cannot synthesize these.",
|
||||
)
|
||||
if text != raw:
|
||||
log.info("sanitized standalone jamo: %r -> %r", raw[:60], text[:60])
|
||||
|
||||
speed = max(0.5, min(2.0, float(req.speed or 1.0)))
|
||||
fd, out_path = tempfile.mkstemp(suffix=".wav")
|
||||
|
||||
Reference in New Issue
Block a user