# syntax=docker/dockerfile:1.7

# SAS V3 — Service de pseudonymisation/dépseudonymisation pour documents
# juridiques. Backend NER par défaut : GLiNER2
# (fastino/gliner2-privacy-filter-PII-multi) ; repli : openai/privacy-filter.
# Les deux tournent en CPU. Image base : Debian slim Python 3.11,
# torch CPU only (pas de CUDA) — inchangé par rapport à la V2.2.
FROM python:3.11-slim AS base

# Dépendances système minimales (libgomp pour torch, ca-certificates pour HF Hub)
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        libgomp1 \
        ca-certificates \
        curl \
    && rm -rf /var/lib/apt/lists/*

# Utilisateur non-root pour isoler les permissions
RUN useradd --create-home --uid 1000 sas
WORKDIR /app

# Le cache HuggingFace vit dans /models, monté en volume Docker persistant.
# Si le modèle est pré-téléchargé au build (couche ci-dessous), Docker copie
# le contenu de /models dans le volume nommé à sa première utilisation :
# aucun téléchargement au premier démarrage. Sinon (SKIP_MODEL_DOWNLOAD=1 ou
# réseau coupé au build), le modèle est téléchargé au premier démarrage et
# conservé dans le volume.
ENV HF_HOME=/models \
    TRANSFORMERS_CACHE=/models \
    HF_HUB_DISABLE_TELEMETRY=1 \
    PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1

# Installation des dépendances Python. torch en CPU-only via l'index PyTorch
# dédié, ce qui économise ~2 Go par rapport à la variante CUDA.
COPY requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir \
        --extra-index-url https://download.pytorch.org/whl/cpu \
        -r /app/requirements.txt

# Pré-téléchargement du modèle GLiNER2 au build (~500 Mo). Encapsulé pour
# tolérer l'absence de réseau : `--build-arg SKIP_MODEL_DOWNLOAD=1` saute
# l'étape explicitement, et un échec de téléchargement (réseau coupé,
# HuggingFace indisponible) n'interrompt PAS le build — le modèle sera
# alors récupéré au premier démarrage du service.
ARG SKIP_MODEL_DOWNLOAD=0
RUN if [ "$SKIP_MODEL_DOWNLOAD" = "1" ]; then \
        echo "Pré-téléchargement GLiNER2 sauté (SKIP_MODEL_DOWNLOAD=1)"; \
    else \
        python -c "from gliner2 import GLiNER2; GLiNER2.from_pretrained('fastino/gliner2-privacy-filter-PII-multi')" \
        || echo "AVERTISSEMENT : pré-téléchargement GLiNER2 impossible — le modèle sera téléchargé au premier démarrage."; \
    fi

# Code de l'application (les data/, static/ et /models sont des volumes,
# donc pas copiés dans l'image).
COPY service.py exporters.py pseudonymizer.py ner_backends.py regex_net.py /app/
COPY static/ /app/static/

# Préparation des points de montage
RUN mkdir -p /app/data/mappings /models \
    && chown -R sas:sas /app /models

USER sas

EXPOSE 8082

# Healthcheck : le service expose /health qui renvoie {"status":"ok",…}
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
    CMD curl --fail --silent http://localhost:8082/health || exit 1

# Le service lit SAS_HOST, SAS_PORT, SAS_PUBLIC_BASE, SAS_NER_BACKEND via
# os.environ. SAS_HOST=0.0.0.0 est forcé pour écouter sur toutes les
# interfaces du conteneur (sinon uvicorn n'écoute que sur 127.0.0.1 et le
# port mapping Docker ne fonctionne pas).
# NB : la V2.2 déclarait PUBLIC_BASE alors que le service lisait
# SAS_PUBLIC_BASE — incohérence résorbée ici (SAS_PUBLIC_BASE partout).
ENV SAS_HOST=0.0.0.0 \
    SAS_PORT=8082 \
    SAS_PUBLIC_BASE=http://localhost:8082 \
    SAS_NER_BACKEND=gliner2

CMD ["python", "-u", "service.py"]
