| # ββ Chatty: Dockerfile for Hugging Face Spaces (Docker SDK) ββ | |
| # Free tier: 2 vCPU, 16 GB RAM, 50 GB ephemeral disk, port 7860. | |
| # Secrets are injected via HF Space settings, not .env files. | |
| FROM python:3.14-slim AS base | |
| # ββ System dependencies ββ | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| ffmpeg \ | |
| espeak-ng \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # ββ uv for fast dependency resolution ββ | |
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv | |
| WORKDIR /app | |
| # ββ Python dependencies (cached layer β only invalidated when lock changes) ββ | |
| COPY pyproject.toml uv.lock ./ | |
| RUN uv sync --no-dev --frozen | |
| # ββ Pre-download the wav2vec2 phoneme model at build time ββ | |
| # This avoids a 5-10s cold-start delay on the first voice request. | |
| # The model is ~1.2 GB and cached in the container image layer. | |
| RUN uv run python -c "\ | |
| from transformers import Wav2Vec2ForCTC, Wav2Vec2Processor; \ | |
| Wav2Vec2Processor.from_pretrained('facebook/wav2vec2-lv-60-espeak-cv-ft'); \ | |
| Wav2Vec2ForCTC.from_pretrained('facebook/wav2vec2-lv-60-espeak-cv-ft'); \ | |
| print('wav2vec2 model cached')" | |
| # ββ Application code ββ | |
| COPY app/ app/ | |
| COPY alembic.ini ./ | |
| # ββ HF Spaces requires port 7860 ββ | |
| ENV PORT=7860 | |
| EXPOSE 7860 | |
| # ββ Writable paths: HF Spaces only allows /tmp for writes ββ | |
| # DATABASE_URL is intentionally NOT hardcoded here: production MUST set it to an | |
| # external Postgres (Neon/Supabase) via HF Space Settings β Variables/Secrets, so | |
| # data survives container restarts. Without it the app falls back to the SQLite | |
| # default in app/core/config.py β fine for local dev, but on HF /tmp is wiped on | |
| # every restart, so a prod Space left on SQLite loses all user data. | |
| ENV AUDIO_DIR="/tmp/media/audio" | |
| ENV AUDIO_STORAGE_BACKEND="local" | |
| # ββ Startup: run migrations then launch uvicorn ββ | |
| CMD ["sh", "-c", "python -c 'import os; print(\"Env keys:\", sorted(os.environ.keys()))' && uv run alembic upgrade head && uv run uvicorn app.main:app --host 0.0.0.0 --port 7860"] | |