# ── 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"]