# latch-voice — Kokoro-82M on CPU + ffmpeg, for Latch's daily mantra. See server.py.
#
# 🔴 Everything the voice needs is fetched HERE, at build time, and the image then runs with
# the network's help refused (HF_HUB_OFFLINE): the weights, the voices and the English G2P
# dictionary are baked in. A request's words never leave the container.
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 HF_HOME=/opt/hf
RUN apt-get update && apt-get install -y --no-install-recommends espeak-ng ffmpeg \
    && rm -rf /var/lib/apt/lists/*
WORKDIR /srv
COPY requirements.txt .
RUN pip install --no-cache-dir --index-url https://download.pytorch.org/whl/cpu torch==2.6.0 \
    && pip install --no-cache-dir -r requirements.txt \
    && python -m spacy download en_core_web_sm
COPY server.py .
# Bake: load both language pipelines and every shipped voice once, so nothing is fetched later.
RUN python -c "import server; [server.speak('Good.', v, 1.0) for v in server.VOICES]" \
    && chmod -R a+rX /opt/hf
ENV HF_HUB_OFFLINE=1
RUN useradd -r -u 1501 -U latchvoice
USER latchvoice
EXPOSE 8000
HEALTHCHECK --interval=60s --timeout=5s --start-period=60s \
  CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=4).status==200 else 1)"
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"]
