vantage / Dockerfile
sourabh gupta
add: Docker deployment for HF Spaces demo
3da409a
Raw
History Blame Contribute Delete
3.05 kB
# syntax=docker/dockerfile:1
# ──────────────────────────────────────────────────────────────────────────────
# Vantage β€” single-container demo image.
# β€’ Stage 1 (web): build the React/Vite frontend β†’ static dist/
# β€’ Stage 2 (app): FastAPI + agent + baked ML models, serves API *and* the dist
# Listens on 7860 (Hugging Face Spaces' expected port; override with $PORT).
# Secrets (Qdrant/Neo4j/OpenAI/Langfuse) are injected as env vars at run time β€”
# never baked in. See .env.example for the variable names.
# ──────────────────────────────────────────────────────────────────────────────
# ── Stage 1: build the frontend ───────────────────────────────────────────────
FROM node:20-slim AS web
WORKDIR /web
COPY apps/web/package.json apps/web/package-lock.json ./
RUN npm ci
COPY apps/web/ ./
RUN npm run build # β†’ /web/dist
# ── Stage 2: python API + models + static frontend ───────────────────────────
FROM python:3.11-slim AS app
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
HF_HOME=/models \
PORT=7860
WORKDIR /app
# curl is used by the container HEALTHCHECK below.
RUN apt-get update && apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*
# CPU-only torch first β€” avoids pulling the multi-GB CUDA build that
# sentence-transformers would otherwise drag in.
RUN pip install --index-url https://download.pytorch.org/whl/cpu torch==2.12.0
# Pinned runtime deps (matches the working py311 env), then the local package
# with --no-deps so its version ranges can't bump anything we just pinned.
COPY requirements.docker.txt ./
RUN pip install -r requirements.docker.txt
COPY packages/ ./packages/
RUN pip install --no-deps -e ./packages/vantage_core
# Bake the ML models into the image so runtime stays fully offline
# (the adapters open them with local_files_only=True).
RUN python - <<'PY'
from sentence_transformers import SentenceTransformer, CrossEncoder
from fastembed import SparseTextEmbedding
SentenceTransformer("all-MiniLM-L6-v2")
CrossEncoder("cross-encoder/ms-marco-MiniLM-L-6-v2")
list(SparseTextEmbedding("Qdrant/bm25").embed(["warmup"]))
print("models baked")
PY
# Application code + built frontend.
COPY apps/ ./apps/
COPY --from=web /web/dist ./apps/web/dist
EXPOSE 7860
HEALTHCHECK --interval=30s --timeout=5s --start-period=120s --retries=3 \
CMD curl -fsS "http://localhost:${PORT}/api/health" || exit 1
# shell form so ${PORT} expands (HF/Railway/Render set their own PORT).
CMD uvicorn apps.api.main:app --host 0.0.0.0 --port ${PORT}