# Inflect v2 family (owensong/Inflect-Micro-v2, owensong/Inflect-Nano-v2) — a shared image, since
# the two models ship one codebase and one public API.
#
# Separate from inflect-nano/ on purpose: that image serves Inflect-Nano-**v1**, a different
# architecture (an `inflect_nano/` package with split acoustic + vocoder checkpoints, and a
# numba/inflect text frontend). v2 is VITS under `runtime/` with a single `model.pth` and a
# phonemizer/espeak-ng frontend, so the two share no dependencies worth merging.
FROM nvidia/cuda:12.9.0-runtime-ubuntu24.04

ENV DEBIAN_FRONTEND=noninteractive

# System deps. espeak-ng is REQUIRED, not optional, and specifically the distro package:
# the model's own frontend (`_configure_espeak`) looks for /usr/lib/x86_64-linux-gnu/libespeak-ng.so.1
# first and only falls back to the pip `espeakng-loader`, whose own comment warns that it
# "extracts a temporary shared object, which can exhaust mmap resources when phonemizer repeatedly
# creates backends over a large corpus" — which is exactly what a 1000-2000 sample eval does.
# libsndfile1/ffmpeg cover audio I/O; git is needed for pip VCS installs.
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3 \
    python3-pip \
    python3-dev \
    espeak-ng \
    ffmpeg \
    git \
    libsndfile1 \
    && rm -rf /var/lib/apt/lists/*

# Set Python alias (Ubuntu 24.04 ships Python 3.12)
RUN ln -sf /usr/bin/python3 /usr/bin/python

# Allow pip to install packages system-wide in the container (PEP 668)
ENV PIP_BREAK_SYSTEM_PACKAGES=1

WORKDIR /app

# Upgrade pip so it prefers prebuilt manylinux wheels. --ignore-installed is required on
# Ubuntu 24.04: the Debian-installed pip has no RECORD file and cannot be uninstalled.
RUN pip install --no-cache-dir --upgrade --ignore-installed pip setuptools wheel

# PyTorch (cu128 wheels for CUDA 12.8+/12.9 compat). The model requires torch>=2.6; no torchaudio,
# as its audio I/O is soundfile only.
RUN pip install --no-cache-dir \
    torch==2.8.0 \
    --index-url https://download.pytorch.org/whl/cu128

# The model's own runtime requirements (from owensong/Inflect-Micro-v2/requirements.txt), minus
# torch which is pinned above. espeakng-loader stays installed as the fallback path for hosts
# without the distro library, even though the apt espeak-ng above is what will actually be used.
RUN pip install --no-cache-dir \
    "huggingface-hub>=0.36" \
    "numpy>=1.26,<3" \
    "scipy>=1.13" \
    "soundfile>=0.13" \
    "phonemizer>=3.3" \
    "espeakng-loader>=0.2.4" \
    "num2words>=0.5.14" \
    "Unidecode>=1.3.8"

# datasets + tqdm for the eval loop. datasets is pinned <4.0 for consistency with the other
# backends and to avoid pulling torchcodec: this model never reads the `prompt_audio` column
# (run_eval.py drops it), so no audio decoding happens either way.
RUN pip install --no-cache-dir "datasets<4.0" tqdm

# Fail the build rather than an 8-hour job if the espeak wiring is broken. This exercises the
# real code path: it resolves the library the way the model's frontend does, then phonemizes.
RUN python -c "\
import os, ctypes, phonemizer;\
lib='/usr/lib/x86_64-linux-gnu/libespeak-ng.so.1';\
assert os.path.isfile(lib), 'distro libespeak-ng missing — the frontend would fall back to the mmap-leaky loader';\
os.environ['PHONEMIZER_ESPEAK_LIBRARY']=lib;\
ctypes.CDLL(lib);\
from phonemizer.backend import EspeakBackend;\
out=EspeakBackend('en-us').phonemize(['hello world']);\
assert out and out[0].strip(), out;\
print('espeak-ng + phonemizer OK:', out)"

# NOTE: the weights are deliberately NOT baked in. The model repo carries the inference code
# *and* the checkpoint, and it is only ~40 MB, so run_eval.py snapshot_downloads whichever
# Inflect v2 model it is pointed at — which is what lets one image serve both Micro-v2 and
# Nano-v2 without rebuilding.

# Copy the full repository
COPY . /app

# Default entrypoint
ENTRYPOINT ["bash"]

# Keep-alive CMD so the Space runtime stays healthy. HF Jobs and `docker run`
# override this with their own command (e.g. run_eval.sh).
EXPOSE 7860
CMD ["-c", "python3 -m http.server 7860"]
