| # PawTrace β single-service image for the READ-ONLY demo (Hugging Face Spaces / any Docker host). | |
| # Builds the React frontend, then runs the FastAPI API which also serves that frontend (one origin, | |
| # no CORS). Bundles the fine-tuned PyTorch re-ID model (best.pt) + the HF breed classifier + the | |
| # 1,000-dog demo database, and runs with DEMO_MODE=true so every write is blocked server-side. | |
| # Needs ~1 GB RAM with both models loaded β fine on a Spaces CPU-basic (16 GB) box. | |
| # ---- Stage 1: build the React frontend -> /web/dist ---- | |
| FROM node:20-slim AS frontend | |
| WORKDIR /web | |
| COPY frontend/package.json frontend/package-lock.json ./ | |
| RUN npm ci | |
| COPY frontend/ ./ | |
| RUN npm run build | |
| # ---- Stage 2: Python API (serves the built frontend) ---- | |
| FROM python:3.12-slim AS app | |
| ENV PYTHONUNBUFFERED=1 \ | |
| PIP_NO_CACHE_DIR=1 | |
| WORKDIR /app | |
| # Base runtime deps (FastAPI, SQLAlchemy, Pillow, numpy, ...). | |
| COPY backend/requirements-base.txt ./requirements-base.txt | |
| RUN pip install --upgrade pip && pip install -r requirements-base.txt | |
| # ---- REAL MATCHING (EMBEDDER=reid + BREED_CLASSIFIER=hf) ---------------------------------------- | |
| # PyTorch (CPU build) + transformers power the real re-ID embedder and breed classifier. | |
| RUN pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu \ | |
| && pip install "transformers>=4.40" "safetensors>=0.4" | |
| # Pre-download the model into the image (into HF_HOME) so the first live match doesn't stall on a | |
| # runtime download. This is a big, stable layer β kept cached across code changes below. | |
| ENV HF_HOME=/app/hf_cache | |
| RUN python -c "from transformers import AutoImageProcessor, AutoModel, AutoModelForImageClassification as M; \ | |
| k='jhoppanne/Dogs-Breed-Image-Classification-V1'; AutoImageProcessor.from_pretrained(k); \ | |
| M.from_pretrained(k); AutoModel.from_pretrained(k)" | |
| # ------------------------------------------------------------------------------------------------ | |
| # Backend source (includes backend/demo_data/ β the shipped snapshot). | |
| COPY backend/ ./ | |
| # Fine-tuned re-ID model weights (git-LFS in the Space repo) -> loaded when EMBEDDER=reid. | |
| COPY best.pt /app/best.pt | |
| # Geo centroid CSV lives at the repo root; copy it in and point the app at it. | |
| COPY data/zip_centroids.csv /app/geo/zip_centroids.csv | |
| ENV ZIP_CENTROID_FILE=/app/geo/zip_centroids.csv | |
| # Built frontend from stage 1 (the API serves this at "/"). | |
| COPY --from=frontend /web/dist ./frontend_dist | |
| # Bake the 1,000-dog demo snapshot (SQLite DB + processed photos) into the image's data dir, then | |
| # drop the source copy. DEMO_MODE blocks all writes, so the DB never changes; a redeploy just | |
| # reloads this same read-only snapshot. | |
| RUN mkdir -p /app/data \ | |
| && cp /app/demo_data/app.db /app/data/app.db \ | |
| && cp -r /app/demo_data/media /app/data/media \ | |
| && rm -rf /app/demo_data | |
| ENV DATABASE_URL=sqlite:////app/data/app.db \ | |
| MEDIA_DIR=/app/data/media \ | |
| EMBEDDER=reid \ | |
| REID_MODEL_PATH=/app/best.pt \ | |
| REID_MODEL_VERSION=v4 \ | |
| BREED_CLASSIFIER=hf \ | |
| BREED_TOP_K=10 \ | |
| DEMO_MODE=true \ | |
| HF_HUB_OFFLINE=1 \ | |
| TRANSFORMERS_OFFLINE=1 | |
| # HF_HUB_OFFLINE/TRANSFORMERS_OFFLINE: use the model baked into HF_HOME above; never call | |
| # huggingface.co at runtime (faster cold start, no external dependency during a demo). | |
| # HF Spaces routes to the port declared as `app_port` in README.md (7860). Bind there; ${PORT} keeps | |
| # it portable to hosts that inject a port (Render, etc.). | |
| EXPOSE 7860 | |
| CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-7860}"] | |