# ── RAG Spectrum — public Space build file ────────────────────────────────────────── # Generated by scripts/deploy_space.py; do not edit by hand. The source code is # not in this repo: stage 0 pulls it from a private repo with the Space's # HF_TOKEN secret, pinned to one snapshot. The stages after it are the # project's own Dockerfile with every COPY reading from that snapshot. # ───────────────────────────────────────────────────────────────────────────── ARG RAG_SPECTRUM_CODE_REPO=APC15/prism-code ARG RAG_SPECTRUM_REV=844d8425cfbb510da69e660e7f6fe6876f710ae4 # ── Stage 0: private source ── FROM alpine:3.20 AS source ARG RAG_SPECTRUM_CODE_REPO ARG RAG_SPECTRUM_REV RUN apk add --no-cache git # HF's git endpoint takes the token as a Basic-auth password (it rejects # Bearer). A header keeps the token out of the URL and out of /src/.git. RUN --mount=type=secret,id=HF_TOKEN,mode=0444,required=true \ AUTH="$(printf 'hf:%s' "$(cat /run/secrets/HF_TOKEN)" | base64 | tr -d '\n')" \ && git -c "http.extraHeader=Authorization: Basic ${AUTH}" \ clone --quiet --depth 1 "https://huggingface.co/${RAG_SPECTRUM_CODE_REPO}" /src \ && test "$(git -C /src rev-parse HEAD)" = "${RAG_SPECTRUM_REV}" \ || { echo "Could not fetch ${RAG_SPECTRUM_CODE_REPO} at ${RAG_SPECTRUM_REV}: check that the HF_TOKEN secret can read it and that no newer snapshot was pushed after this build file." >&2; exit 1; } RUN rm -rf /src/.git # ── RAG Spectrum — single-container deployment (Hugging Face Spaces) ──────── # Stage 1 builds the React frontend; stage 2 runs FastAPI, which serves the # built frontend as static files (see the SPA fallback at the end of api/main.py). # HF Spaces expects the app on port 7860 and runs the container as uid 1000. # ───────────────────────────────────────────────────────────────────────────── # ── Stage 1: frontend build ── FROM node:20-alpine AS frontend WORKDIR /build COPY --from=source /src/frontend/package*.json ./ RUN npm ci COPY --from=source /src/frontend/ ./ RUN npm run build # ── Stage 2: Python runtime ── FROM python:3.13-slim ENV PYTHONUNBUFFERED=1 PIP_NO_CACHE_DIR=1 # CPU-only torch first — the default PyPI wheel bundles CUDA (~3GB heavier). RUN pip install torch --index-url https://download.pytorch.org/whl/cpu WORKDIR /app COPY --from=source /src/requirements.txt ./requirements.txt COPY --from=source /src/api/requirements.txt ./api-requirements.txt RUN pip install -r requirements.txt -r api-requirements.txt COPY --from=source /src/ . COPY --from=frontend /build/dist ./frontend/dist # HF Spaces runs as uid 1000; give it a home + writable app dir # (SQLite DB in api/db/, model caches, per-job scratch under /tmp). RUN useradd -m -u 1000 user && chown -R user:user /app USER user ENV HOME=/home/user \ HF_HOME=/tmp/hf_cache \ PYTHONPATH=/app WORKDIR /app/api EXPOSE 7860 # --proxy-headers + trusted forwarded IPs so request.client.host resolves to the # real client (HF's router fronts the container). Without this, rate limiting # keys on the proxy IP and every visitor shares one bucket. CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860", \ "--proxy-headers", "--forwarded-allow-ips=*"]