Spaces:
Sleeping
Sleeping
| # syntax=docker/dockerfile:1.7 | |
| FROM ghcr.io/astral-sh/uv:0.9-python3.12-bookworm-slim AS builder | |
| WORKDIR /app | |
| # Copy dependency files first for layer caching | |
| COPY pyproject.toml uv.lock .python-version ./ | |
| # Install dependencies only (locked, no project code yet) | |
| RUN uv sync --no-install-project --no-dev | |
| # Copy application code and install the project | |
| COPY app/ app/ | |
| RUN uv sync --no-dev | |
| # --- DB downloader stage --- | |
| FROM python:3.12-slim AS db-downloader | |
| WORKDIR /app/data | |
| # Download a pinned DDInter SQLite DB from the project's release source. | |
| ARG INTERACTION_DB_REPO=SPerekrestova/pillchecker-api | |
| ARG INTERACTION_DB_TAG=ddinter-2026-05-16 | |
| ARG INTERACTION_DB_SHA256=ebdd0640949ca551c0d669ee1161b00e5d868ef067c857852a8afc380e51d4fb | |
| COPY scripts/download_interaction_db.py /tmp/download_interaction_db.py | |
| RUN --mount=type=secret,id=github_token,required=false \ | |
| INTERACTION_DB_REPO="$(printf '%s' "${INTERACTION_DB_REPO}" | tr -d "\r\n")"; \ | |
| INTERACTION_DB_TAG="$(printf '%s' "${INTERACTION_DB_TAG}" | tr -d "\r\n")"; \ | |
| INTERACTION_DB_SHA256="$(printf '%s' "${INTERACTION_DB_SHA256}" | tr -d "\r\n")"; \ | |
| test -n "${INTERACTION_DB_REPO}" || { echo "INTERACTION_DB_REPO build arg is required"; exit 1; }; \ | |
| test -n "${INTERACTION_DB_TAG}" || { echo "INTERACTION_DB_TAG build arg is required"; exit 1; }; \ | |
| if [ -f /run/secrets/github_token ]; then export GITHUB_TOKEN="$(cat /run/secrets/github_token)"; fi; \ | |
| if [ -n "${INTERACTION_DB_SHA256}" ]; then export INTERACTION_DB_SHA256="${INTERACTION_DB_SHA256}"; fi; \ | |
| python /tmp/download_interaction_db.py \ | |
| --repo "${INTERACTION_DB_REPO}" \ | |
| --tag "${INTERACTION_DB_TAG}" \ | |
| --asset ddinter.db \ | |
| --output ddinter.db | |
| # --- Application base stage --- | |
| FROM python:3.12-slim AS app-base | |
| WORKDIR /app | |
| # Copy built virtualenv from builder | |
| COPY --from=builder /app/.venv /app/.venv | |
| # Copy DDInter SQLite DB from downloader stage | |
| COPY --from=db-downloader /app/data /app/data | |
| ENV PATH="/app/.venv/bin:$PATH" | |
| ENV HF_HOME=/app/models | |
| ENV TRANSFORMERS_CACHE=/app/models | |
| ENV INTERACTION_DB_PATH=/app/data/ddinter.db | |
| # Pre-download NER model so the image is self-contained. | |
| # Layer is cached until venv or model ID changes. | |
| # In local dev, docker-compose mounts a volume over /app/models. | |
| RUN python -c "from transformers import pipeline; \ | |
| pipeline('ner', model='OpenMed/OpenMed-NER-PharmaDetect-BioPatient-108M', aggregation_strategy='none'); \ | |
| pipeline('zero-shot-classification', model='MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli')" | |
| # App code comes last — most frequently changing layer | |
| COPY --from=builder /app/app /app/app | |
| COPY scripts/ /app/scripts/ | |
| RUN chmod +x /app/scripts/prod-startup.sh /app/scripts/ci-startup.sh | |
| # Create a non-root user for security | |
| RUN groupadd -r pillchecker && useradd -r -g pillchecker pillchecker && \ | |
| chown -R pillchecker:pillchecker /app | |
| USER pillchecker | |
| # --- Benchmark runner stage --- | |
| FROM app-base AS benchmark-runner | |
| USER root | |
| COPY eval/ /app/eval/ | |
| RUN chown -R pillchecker:pillchecker /app/eval | |
| USER pillchecker | |
| ENTRYPOINT ["python", "-m", "eval.run_benchmark"] | |
| CMD [] | |
| # --- Runtime stage --- | |
| FROM app-base AS runtime | |
| EXPOSE 8000 | |
| ENTRYPOINT ["/app/scripts/prod-startup.sh"] | |
| CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] | |