| # TalkToDoc production image. | |
| # Built to be interchangeable across hosts: Hugging Face Spaces, Render | |
| # (Docker deploy), Fly.io, Cloud Run, or any other platform that runs a | |
| # standard Docker image. Nothing here is tied to one specific host. | |
| # Configuration comes entirely from environment variables set by | |
| # whichever platform runs it (PORT, DATABASE_URL, OPENAI_API_KEY, | |
| # SECRET_KEY, ENVIRONMENT). | |
| FROM python:3.11-slim | |
| # Whisper needs ffmpeg to read audio files, this installs it at the | |
| # system level since it can't come from pip. build-essential is needed | |
| # because some packages in requirements.txt compile C extensions during | |
| # install, and the slim base image has no compiler by default. | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| build-essential \ | |
| ffmpeg \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # Run as a non-root user, standard practice and specifically expected by | |
| # Hugging Face Spaces' Docker SDK. | |
| RUN useradd -m -u 1000 user | |
| USER user | |
| ENV PATH="/home/user/.local/bin:$PATH" | |
| WORKDIR /home/user/app | |
| COPY --chown=user requirements.txt . | |
| RUN pip install --no-cache-dir --upgrade -r requirements.txt | |
| # YarnGPT downloads its WavTokenizer checkpoint itself on first import, | |
| # using a bare requests.get() call with no error checking. If that | |
| # download hiccups at runtime (inside the running container, on the | |
| # app's first request), it silently saves a corrupted or partial file | |
| # and the app fails later with a confusing, unrelated error. | |
| # | |
| # This downloads the exact same two files ahead of time, at build time, | |
| # using huggingface_hub's properly tested download function instead. If | |
| # this fails, the build fails clearly, right here, instead of the app | |
| # failing mysteriously after it's already live. YarnGPT's own downloader | |
| # checks whether the file already exists before downloading, so it will | |
| # find these already in place and skip straight past its own fragile | |
| # download step. | |
| RUN python - <<'PY' | |
| from huggingface_hub import hf_hub_download | |
| import os | |
| target = "/home/user/.yarngpt/models" | |
| os.makedirs(target, exist_ok=True) | |
| hf_hub_download( | |
| repo_id="novateur/WavTokenizer-large-speech-75token", | |
| filename="wavtokenizer_large_speech_320_24k.ckpt", | |
| revision="c5512c1bd34afef082035923e4bae245f3da9e5f", | |
| local_dir=target, | |
| ) | |
| hf_hub_download( | |
| repo_id="novateur/WavTokenizer-medium-speech-75token", | |
| filename="wavtokenizer_mediumdata_frame75_3s_nq1_code4096_dim512_kmeans200_attn.yaml", | |
| local_dir=target, | |
| ) | |
| print("WavTokenizer files downloaded.") | |
| PY | |
| COPY --chown=user . . | |
| ENV ENVIRONMENT=production | |
| # 7860 is Hugging Face Spaces' default port. Other platforms (like | |
| # Render) set $PORT themselves, and this falls back to that automatically. | |
| EXPOSE 7860 | |
| CMD gunicorn app:app --bind 0.0.0.0:${PORT:-7860} --timeout 120 --workers 1 | |