# SIOP V2 — image du service IA (siop2-ai, ADR-004). # Contexte de build : apps/ai (le service est autonome, pas de dépendance au # monorepo). Étage 1 : uv sync + téléchargement du modèle ONNX AU BUILD # (ADR-004 §1 — jamais au démarrage) ; étage 2 : runtime minimal non-root. # Ce service n'est JAMAIS exposé publiquement : seul siop2-api le contacte, # porteur du secret AI_SERVICE_TOKEN (ADR-004 §4). FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim AS builder WORKDIR /app ENV UV_LINK_MODE=copy \ FASTEMBED_CACHE_PATH=/opt/fastembed # Manifestes d'abord (cache de couche), puis le code. L'installation du projet # reste éditable (.pth → /app/src) : src est donc copié dans l'image finale. COPY pyproject.toml uv.lock ./ RUN uv sync --frozen --no-install-project --no-dev \ --extra embeddings --extra generation COPY src src RUN uv sync --frozen --no-dev \ --extra embeddings --extra generation # Le modèle d'embeddings est EMBARQUÉ dans l'image : pas de téléchargement au # boot (démarrage prévisible, marche sans accès à Hugging Face en production). RUN uv run python -c "from siop_ai.embeddings import EmbeddeurLocal; EmbeddeurLocal()" FROM python:3.11-slim-bookworm WORKDIR /app ENV PATH=/app/.venv/bin:$PATH \ FASTEMBED_CACHE_PATH=/opt/fastembed RUN useradd --system --create-home siop COPY --from=builder --chown=siop:siop /app/.venv /app/.venv COPY --from=builder --chown=siop:siop /app/src /app/src COPY --from=builder --chown=siop:siop /opt/fastembed /opt/fastembed USER siop EXPOSE 8000 HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \ CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8000/healthz', timeout=4).status==200 else 1)" CMD ["uvicorn", "siop_ai.app:app", "--host", "0.0.0.0", "--port", "8000"]