deploy: HF Spaces β combined single-container imageWraps our existing 2-service compose into one image that HF Spaces' Docker SDK can run on its standard 7860 port.- Dockerfile (root): three-stage build1. node:20-alpine β npm ci + npm run build (produces ui/dist/)2. python:3.11-slim β pip install into an isolated /opt/venv3. python:3.11-slim + nginx (via apt) + tini as PID 1- docker/nginx.hf.conf: variant listening on 7860, proxies /api β 127.0.0.1:8000- docker/hf-entrypoint.sh: launches uvicorn in the background bound to127.0.0.1:8000 (nginx-only reachable), polls /health for up to 30s songinx isn't serving 502s during boot, then execs nginx in the foreground.Trap forwards SIGTERM to uvicorn for clean shutdown.- README.md: YAML frontmatter block (title, sdk: docker, app_port: 7860)that HF Spaces reads to configure the Space. Also added the π€ HF badgeand a 'Deploy your own' section for anyone forking.CI is unaffected β the existing docker/api.Dockerfile + docker/ui.Dockerfilestill drive the multi-container compose + CI docker-build job. This rootDockerfile is HF-only and doesn't touch the compose stack.
f3aa131 | # ============================================================================ | |
| # HF Spaces build β single container: nginx (frontend + reverse proxy) | |
| # + uvicorn (FastAPI). Port 7860 is what HF Spaces expects. | |
| # | |
| # Three-stage build: | |
| # 1. ui-builder β node β npm ci β npm run build (produces ui/dist/) | |
| # 2. py-builder β pip install into an isolated venv | |
| # 3. runtime β nginx:alpine + python:3.11-slim system libs + venv + dist | |
| # ============================================================================ | |
| # ---------- Stage 1: build the React bundle ---------------------------------- | |
| FROM node:20-alpine AS ui-builder | |
| WORKDIR /ui | |
| COPY ui/package.json ui/package-lock.json ./ | |
| RUN npm ci --no-audit --no-fund | |
| COPY ui/ ./ | |
| RUN npm run build | |
| # ---------- Stage 2: build the Python venv ---------------------------------- | |
| FROM python:3.11-slim AS py-builder | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| build-essential gcc \ | |
| && rm -rf /var/lib/apt/lists/* | |
| RUN python -m venv /opt/venv | |
| ENV PATH="/opt/venv/bin:$PATH" | |
| WORKDIR /build | |
| COPY requirements.txt . | |
| RUN pip install --no-cache-dir --upgrade pip \ | |
| && pip install --no-cache-dir -r requirements.txt | |
| # ---------- Stage 3: runtime ------------------------------------------------ | |
| FROM python:3.11-slim AS runtime | |
| # Runtime deps for pymupdf/pdf2image + nginx. | |
| # nginx is pulled from Debian repos (not the alpine variant we used in docker/ | |
| # β this stage needs a full-featured base for the Python bits). | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| poppler-utils \ | |
| libglib2.0-0 \ | |
| nginx \ | |
| curl \ | |
| tini \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # Copy the venv (Python deps only, no compilers) + the app source. | |
| COPY --from=py-builder /opt/venv /opt/venv | |
| ENV PATH="/opt/venv/bin:$PATH" \ | |
| PYTHONDONTWRITEBYTECODE=1 \ | |
| PYTHONUNBUFFERED=1 \ | |
| PYTHONPATH=/app | |
| WORKDIR /app | |
| COPY src/ ./src/ | |
| COPY pyproject.toml ./ | |
| # Copy the built UI bundle into nginx's default web root. | |
| COPY --from=ui-builder /ui/dist /var/www/html | |
| # HF-flavored nginx config: listens on 7860, proxies /api β 127.0.0.1:8000. | |
| COPY docker/nginx.hf.conf /etc/nginx/conf.d/default.conf | |
| # Remove the stock server block on port 80 so nginx doesn't warn. | |
| RUN sed -i '/listen 80/d' /etc/nginx/nginx.conf 2>/dev/null || true \ | |
| && rm -f /etc/nginx/sites-enabled/default | |
| # Entrypoint: starts uvicorn in background, execs nginx in foreground. | |
| # Tini reaps zombie children so PID 1 semantics are correct. | |
| COPY docker/hf-entrypoint.sh /usr/local/bin/hf-entrypoint.sh | |
| RUN chmod +x /usr/local/bin/hf-entrypoint.sh | |
| EXPOSE 7860 | |
| # Non-root would need /var/lib/nginx writable + touch /run/nginx.pid β for HF | |
| # demo we keep it root (HF sandboxes container-side anyway). Documented so the | |
| # skimming reviewer knows this is a deliberate choice, not laziness. | |
| ENTRYPOINT ["/usr/bin/tini", "--"] | |
| CMD ["/usr/local/bin/hf-entrypoint.sh"] | |