#!/usr/bin/env bash # ============================================================================ # Install a dedicated MeloTTS (Korean voice) venv at /opt/melo. # # Why a SEPARATE venv (not the brain-bridge /opt/venv): # - MeloTTS pins old deps (transformers 4.27.4 / tokenizers 0.13.3 / fugashi) # whose binary wheels exist only for cp311, so we use python3.11 here even # though the image's default interpreter is 3.12. # - It isolates the heavy torch/transformers stack from the slim bridge env, # which pins numpy<2 for faster-whisper. # # torch is the CUDA (cu128) build so MeloTTS runs on the GPU alongside Ollama + # Whisper. CPU synth serialised under concurrent load (whisper STT + bot) and # blew TTS up to 7-8s per reply; on the GPU a sentence synthesises in ~0.3s. # cu128 is the Blackwell (sm_120) wheel verified on this host's RTX 5050. # The worker selects the device via MELO_DEVICE=cuda (compose). # ============================================================================ set -euxo pipefail export DEBIAN_FRONTEND=noninteractive apt-get update # Build deps for fugashi / mecab-python3 + a system MeCab dict, plus python3.11. apt-get install -y --no-install-recommends \ software-properties-common build-essential pkg-config swig \ libmecab-dev mecab mecab-ipadic-utf8 add-apt-repository -y ppa:deadsnakes/ppa apt-get update apt-get install -y --no-install-recommends python3.11 python3.11-venv python3.11-dev rm -rf /var/lib/apt/lists/* python3.11 -m venv /opt/melo /opt/melo/bin/pip install --no-cache-dir --upgrade pip wheel setuptools # CUDA (cu128) torch first, so MeloTTS's unpinned `torch` dep is already # satisfied with the GPU build. Pinned to the Blackwell-verified versions # (2.11.0+cu128) for reproducible rebuilds. /opt/melo/bin/pip install --no-cache-dir torch==2.11.0+cu128 torchaudio==2.11.0+cu128 \ --index-url https://download.pytorch.org/whl/cu128 # MeloTTS from GitHub. The PyPI sdist is broken (its setup.py reads a # requirements.txt that is not shipped in the sdist), so install from the repo. # Pinned to a commit (not refs/heads/main) so rebuilds are reproducible. /opt/melo/bin/pip install --no-cache-dir \ "https://github.com/myshell-ai/MeloTTS/archive/209145371cff8fc3bd60d7be902ea69cbdb7965a.tar.gz" # Korean g2p backend. MeloTTS otherwise tries to pip-install this on the first # Korean request, which fails in a network-isolated container at runtime. /opt/melo/bin/pip install --no-cache-dir python-mecab-ko python-mecab-ko-dic # Remove the full `unidic` package (its dictionary is never downloaded, only a # stub) so mecab-python3 falls back to the bundled `unidic_lite` dict. Without # this, importing melo's Japanese module fails with a missing-mecabrc error. /opt/melo/bin/pip uninstall -y unidic || true # Pre-cache every model asset MeloTTS pulls at runtime, so the worker starts # offline and the first Discord turn pays no download cost. Importing melo.api # fetches the Japanese (tohoku-nlp/bert-base-japanese-v3) and Korean # (kykim/bert-kor-base) BERT tokenizers plus nltk g2p data; loading the KR voice # downloads the OpenVoice KR config+checkpoint, and a real synth pulls the # Korean BERT weights. All of these go through huggingface_hub. # # CRITICAL: at runtime docker-compose mounts the `whisper_cache` named volume # over /root/.cache/huggingface (for faster-whisper). That volume would SHADOW # anything baked into the default HF cache, so we pin the melo worker to a # DEDICATED, non-volume cache dir (/opt/melo-cache) here AND in supervisord, and # warm it once. nltk_data (/root/nltk_data) is not volume-mounted so it stays. export HF_HOME=/opt/melo-cache mkdir -p "$HF_HOME" MELO_LANGUAGE=KR HF_HOME=/opt/melo-cache /opt/melo/bin/python - <<'PY' import tempfile from melo.api import TTS model = TTS(language="KR", device="cpu") out = tempfile.mktemp(suffix=".wav") model.tts_to_file("초기화 워밍업입니다.", model.hps.data.spk2id["KR"], out, speed=1.5) print("[setup-melo] warm-up KR synth OK ->", out) PY echo "[setup-melo] MeloTTS venv ready at /opt/melo"