| # Hugging Face Spaces — Docker SDK router image. | |
| # Runs the unified router on port 7860 (HF's required port) as non-root. | |
| FROM python:3.11-slim | |
| # Create a non-root user (HF Spaces requires running as uid 1000). | |
| RUN useradd -m -u 1000 user | |
| WORKDIR /app | |
| # Install dependencies first (better Docker layer caching). | |
| COPY --chown=user requirements.txt ./ | |
| RUN pip install --no-cache-dir -r requirements.txt | |
| # Copy the source tree. models.json is a STUB here — the real config (with | |
| # keys) is fetched at runtime via the MODELS_URL env secret, so no keys ever | |
| # live in the public image. See scripts/deploy_hf.sh. | |
| COPY --chown=user src/ ./src/ | |
| RUN mkdir -p data && echo '{}' > data/models.json | |
| # Copy the dreamy website into static/ so FastAPI serves it at the same origin | |
| # (login.html, dashboard.html, css/, js/, assets/). | |
| COPY --chown=user static/ ./static/ | |
| # Switch to the non-root user for everything that follows. | |
| USER user | |
| # Environment variables for the non-root shell. | |
| ENV HOME=/home/user \ | |
| PATH=/home/user/.local/bin:$PATH \ | |
| PYTHONUNBUFFERED=1 | |
| # HF Spaces expects the app to listen on port 7860. | |
| EXPOSE 7860 | |
| # uvicorn serves src.app:app (module-level `app = create_app()`). | |
| # IMPORTANT: exactly ONE worker. This app is stateful (in-memory OAuth state, | |
| # balance cache, and background payment/tracker coroutines that credit users). | |
| # Multiple workers would split that state, race the same gists, and could | |
| # credit the same ETH deposit twice. cpu-basic handles our scale single-threaded. | |
| CMD ["uvicorn", "src.app:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"] | |