pillchecker-staging / Dockerfile
SPerva's picture
Sync Space from GitHub b7a9985013bfc37ac1e672554593d6ca8490dd0d
82e4c31 verified
# 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"]