feat: replace MeloTTS with Coqui XTTS-v2 natural Korean voice
Some checks failed
Release / semantic-release (push) Successful in 30s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m17s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Release / build-linux (push) Has been cancelled
Some checks failed
Release / semantic-release (push) Successful in 30s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m17s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Release / build-linux (push) Has been cancelled
MeloTTS's single Korean speaker sounded non-native ("foreign accent"). Swap it
for Coqui XTTS-v2 with the built-in female studio speaker "Ana Florence"
(language ko), the natural voice used in earlier local runs.
- bridge/xtts_worker.py: new warm HTTP worker (own /opt/xtts venv), same
/synth + /health contract and PCM16 output as the old melo worker
- docker/setup-xtts.sh: builds the venv with cu128 torch (Blackwell) + Coqui
TTS and bakes the XTTS-v2 model offline. Pins transformers>=4.57,<5 (5.x
removed isin_mps_friendly, breaking XTTS) and installs the [codec] extra
(torch>=2.9 needs torchcodec) — both verified by a real host synth
- Dockerfile: replace the melo build layer with the xtts layer
- supervisord.conf: melo-worker -> xtts-worker, env passthrough for
XTTS_DEVICE/SPEAKER/LANGUAGE (always set via compose defaults)
- bridge/server.py: default TTS_ENGINE=xtts, route to the xtts worker, generic
worker-synth helper, neural-only fallback flag (XTTS_FALLBACK_PIPER)
- settings UI: engine dropdown xtts/piper, drop the dead melo_speed field, fix
the supervisorctl restart target to xtts-worker
- compose/.env.example/README: XTTS_* vars, speaker/language knobs, remove melo
- remove bridge/melo_worker.py and docker/setup-melo.sh
- tests: xtts treated as multilingual (not English-only)
Verified on host: coqui-tts loads XTTS-v2 and synthesises Korean as
"Ana Florence" to a 16-bit mono 24kHz WAV.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,7 @@ from typing import Any, Dict
|
||||
FIELDS = [
|
||||
("ollama_chat_model", "LLM 모델", "model"),
|
||||
("whisper_model", "STT(Whisper) 모델", "select:tiny,base,small,medium,large,large-v3"),
|
||||
("tts_engine", "TTS 엔진", "select:melo,piper"),
|
||||
("melo_speed", "TTS 속도 (MeloTTS)", "number:0.5:2.5:0.1"),
|
||||
("tts_engine", "TTS 엔진", "select:xtts,piper"),
|
||||
("output_language", "출력 언어 (비우면 사용자 언어)", "text"),
|
||||
("llm_thinking_enabled", "LLM 사고(thinking) 모드", "bool"),
|
||||
("agentic_max_turns", "에이전트 최대 반복", "number:1:12:1"),
|
||||
@@ -54,9 +53,7 @@ def _current() -> Dict[str, Any]:
|
||||
cfg = _read_config()
|
||||
out: Dict[str, Any] = {}
|
||||
for k in _KEYS:
|
||||
if k == "melo_speed":
|
||||
out[k] = cfg.get("melo_speed", os.environ.get("MELO_SPEED", "1.5"))
|
||||
elif k == "output_language":
|
||||
if k == "output_language":
|
||||
out[k] = cfg.get("output_language", os.environ.get("OUTPUT_LANGUAGE", ""))
|
||||
else:
|
||||
out[k] = cfg.get(k, "")
|
||||
@@ -78,12 +75,7 @@ def _coerce(updates: Dict[str, Any]) -> Dict[str, Any]:
|
||||
for k, v in updates.items():
|
||||
if k not in _KEYS:
|
||||
continue
|
||||
if k == "melo_speed":
|
||||
try:
|
||||
v = float(v)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
elif k == "agentic_max_turns":
|
||||
if k == "agentic_max_turns":
|
||||
try:
|
||||
v = int(v)
|
||||
except (TypeError, ValueError):
|
||||
@@ -114,12 +106,12 @@ def _save(updates: Dict[str, Any]) -> None:
|
||||
|
||||
|
||||
def _apply() -> str:
|
||||
# Restart melo + bridge AFTER this response is sent. Detached (new session)
|
||||
# so the bridge being killed mid-restart doesn't drop the restart itself,
|
||||
# and the HTTP client still receives this response.
|
||||
# Restart the TTS worker + bridge AFTER this response is sent. Detached (new
|
||||
# session) so the bridge being killed mid-restart doesn't drop the restart
|
||||
# itself, and the HTTP client still receives this response.
|
||||
try:
|
||||
subprocess.Popen(
|
||||
["sh", "-c", "sleep 1; supervisorctl restart melo-worker bridge"],
|
||||
["sh", "-c", "sleep 1; supervisorctl restart xtts-worker bridge"],
|
||||
start_new_session=True,
|
||||
)
|
||||
return "1초 후 브리지/TTS 워커가 재시작되어 반영됩니다."
|
||||
|
||||
Reference in New Issue
Block a user