Spaces:
Sleeping
Sleeping
| # ProbabilityRAG β Hugging Face Spaces (Docker SDK, free CPU basic: 2 vCPU / 16 GB). | |
| # Two stages: build the React bundle, then a CPU-only Python image that bakes the vector | |
| # index + model weights so cold start is model-load only (no indexing at boot). | |
| # ---------- Stage 1: build the frontend ---------- | |
| FROM node:22-alpine AS web | |
| WORKDIR /web | |
| # Copy manifests first so `npm ci` is cached until deps actually change. | |
| COPY web/package.json web/package-lock.json ./ | |
| RUN npm ci | |
| COPY web/ ./ | |
| RUN npm run build # -> /web/dist | |
| # ---------- Stage 2: Python runtime ---------- | |
| FROM python:3.12-slim AS app | |
| # HF hub caches model weights here; a stable path lets the BGE-M3 + reranker downloads that | |
| # happen at build time bake into the image (cold start = load from disk, no network fetch). | |
| ENV HF_HOME=/opt/hf \ | |
| KMP_DUPLICATE_LIB_OK=TRUE \ | |
| HF_HUB_DISABLE_SYMLINKS_WARNING=1 \ | |
| PROBRAG_PUBLIC=1 \ | |
| PROBRAG_MODELS=glm-flash \ | |
| PYTHONUNBUFFERED=1 | |
| WORKDIR /app | |
| # curl is only needed to fetch the source PDF below; drop the apt lists to keep the layer small. | |
| RUN apt-get update && apt-get install -y --no-install-recommends curl \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # CPU torch FIRST, from PyTorch's CPU wheel index β requirements.txt pins torch==2.11.0+cu128 | |
| # (a local-GPU build) which does NOT exist on PyPI and would never resolve on a CPU host. | |
| # Then install everything else EXCEPT the torch line (grep it out) so pip doesn't try to | |
| # "correct" our CPU torch back to the CUDA pin. | |
| COPY requirements.txt ./ | |
| RUN pip install --no-cache-dir torch==2.11.0 --index-url https://download.pytorch.org/whl/cpu \ | |
| && grep -v '^torch' requirements.txt > /tmp/req-nocuda.txt \ | |
| && pip install --no-cache-dir -r /tmp/req-nocuda.txt | |
| # Only what the index build needs β app/ is copied AFTER the build steps below, so pure | |
| # server-code changes reuse the cached PDF + index layers (~2 min rebuild instead of ~20). | |
| COPY src/ ./src/ | |
| COPY scripts/ ./scripts/ | |
| COPY data/chunks/ ./data/chunks/ | |
| # Grinstead & Snell "Introduction to Probability" β GFDL-licensed, legally redistributable. | |
| # Hosted by Dartmouth; verified to return %PDF (see DEPLOY.md attribution). The /pdf citation | |
| # viewer needs it, so a failed download must fail the build loudly (-f -> non-zero on 4xx/5xx). | |
| ARG PDF_URL=https://math.dartmouth.edu/~prob/prob/prob.pdf | |
| RUN mkdir -p data/raw \ | |
| && curl -fSL "$PDF_URL" -o data/raw/grinstead_snell.pdf \ | |
| && head -c 4 data/raw/grinstead_snell.pdf | grep -q '%PDF' # sanity: it's really a PDF | |
| # Build the vector index AT BUILD TIME. This downloads BGE-M3 + bge-reranker weights into | |
| # HF_HOME and writes qdrant_storage/, so the running container never indexes or fetches models. | |
| RUN python scripts/embed_store.py --build | |
| # Server code + built frontend land after the heavy layers (see COPY note above). | |
| COPY app/ ./app/ | |
| COPY --from=web /web/dist ./web/dist | |
| # HF Spaces routes traffic to the container's app_port (7860). ZAI_API_KEY is injected as a | |
| # Space secret at runtime β deliberately NOT baked into the image. | |
| EXPOSE 7860 | |
| CMD ["uvicorn", "app.server:app", "--host", "0.0.0.0", "--port", "7860"] | |