File size: 3,325 Bytes
1dae4ec
 
767b90c
 
0e01b3e
767b90c
 
 
 
4f2020d
767b90c
 
 
 
 
 
 
 
 
c30608d
767b90c
c30608d
82e4c31
 
 
c30608d
1dae4ec
57538e0
 
 
c30608d
 
1dae4ec
f747de2
c30608d
 
 
 
 
767b90c
8f9e9fa
 
767b90c
0e01b3e
767b90c
4f2020d
0e01b3e
767b90c
c30608d
 
4f2020d
0e01b3e
 
 
c30608d
767b90c
4f2020d
0e01b3e
 
767b90c
 
 
 
0e01b3e
 
 
 
 
767b90c
0e01b3e
 
 
767b90c
0e01b3e
767b90c
8f9e9fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0e01b3e
8046672
0e01b3e
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# 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"]