Aller au contenu principal

Conformité RGPD et protection des données

IA et données personnelles : un cadre strict

Le RGPD (Règlement Général sur la Protection des Données) s’applique pleinement aux applications d’IA qui traitent des données de résidents européens. La modération de contenu elle-même génère des données qui tombent sous le scope du RGPD. Vous devez comprendre vos obligations pour éviter des sanctions pouvant atteindre 4% du chiffre d’affaires mondial.

La catégorie PII dans Mistral Moderation

La catégorie pii (Personally Identifiable Information) du classifieur Mistral détecte les demandes ou divulgations d’informations personnelles :

  • Noms et adresses
  • Numéros de sécurité sociale
  • Numéros de carte bancaire
  • Adresses email et téléphones
  • Données de santé
  • Données biométriques
from mistralai import Mistral
import os
import re

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

def detecter_pii(texte: str) -> dict:
    """Détecte les données personnelles dans un texte."""
    # Couche 1 : Classifieur Mistral
    response = client.classifiers.moderate(
        model="mistral-moderation-2603",
        inputs=[texte]
    )
    pii_score = response.results[0].category_scores.get("pii", 0)

    # Couche 2 : Regex pour les patterns courants
    patterns_pii = {
        "email": r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
        "telephone_fr": r"(?:0|\+33)[1-9](?:\d{2}){4}",
        "secu_sociale": r"\d{13,15}",
        "carte_bancaire": r"\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}",
        "iban": r"FR\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{3}"
    }

    pii_detectees = {}
    for nom, pattern in patterns_pii.items():
        matches = re.findall(pattern, texte)
        if matches:
            pii_detectees[nom] = len(matches)

    return {
        "score_classifieur": round(pii_score, 3),
        "pii_regex": pii_detectees,
        "contient_pii": pii_score > 0.2 or len(pii_detectees) > 0
    }

Anonymisation avant traitement

Quand votre application doit traiter des données contenant potentiellement des PII, anonymisez-les avant de les envoyer au modèle :

def anonymiser_texte(texte: str) -> tuple:
    """Anonymise un texte et conserve un mapping de restauration."""
    mapping = {}
    texte_anonyme = texte

    # Anonymiser les emails
    emails = re.findall(
        r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
        texte
    )
    for i, email in enumerate(set(emails)):
        placeholder = f"[EMAIL_{i+1}]"
        mapping[placeholder] = email
        texte_anonyme = texte_anonyme.replace(email, placeholder)

    # Anonymiser les téléphones
    telephones = re.findall(
        r"(?:0|\+33)[1-9](?:[\s.-]?\d{2}){4}",
        texte
    )
    for i, tel in enumerate(set(telephones)):
        placeholder = f"[TEL_{i+1}]"
        mapping[placeholder] = tel
        texte_anonyme = texte_anonyme.replace(tel, placeholder)

    # Anonymiser les noms (si détectés par NER en amont)
    # Ajoutez votre propre logique NER ici

    return texte_anonyme, mapping

def restaurer_texte(texte_anonyme: str, mapping: dict) -> str:
    """Restaure les données anonymisées après traitement."""
    texte_restaure = texte_anonyme
    for placeholder, valeur in mapping.items():
        texte_restaure = texte_restaure.replace(placeholder, valeur)
    return texte_restaure

# Utilisation dans le pipeline
texte_original = "Contactez [email protected] au 06 12 34 56 78"
texte_anonyme, mapping = anonymiser_texte(texte_original)
# → "Contactez [EMAIL_1] au [TEL_1]"

# Envoyer au modèle le texte anonymisé
response = client.chat.complete(
    model="mistral-large-latest",
    messages=[{"role": "user", "content": texte_anonyme}]
)

Logs de modération conformes RGPD

Les logs de modération contiennent potentiellement des données personnelles. Vous devez les gérer conformément au RGPD :

import hashlib
from datetime import datetime

class LogModerationRGPD:
    """Logger de modération conforme RGPD."""

    def __init__(self, retention_jours: int = 90):
        self.retention_jours = retention_jours

    def _pseudonymiser(self, user_id: str) -> str:
        """Pseudonymise un identifiant utilisateur."""
        salt = os.environ.get("PII_SALT", "default_salt")
        return hashlib.sha256(
            f"{user_id}{salt}".encode()
        ).hexdigest()[:16]

    def log_moderation(self, user_id: str, scores: dict,
                       decision: str, texte: str = None) -> dict:
        """Enregistre une décision de modération."""
        entry = {
            "timestamp": datetime.utcnow().isoformat(),
            "user_hash": self._pseudonymiser(user_id),
            "scores": scores,
            "decision": decision,
            # Ne PAS stocker le texte complet par défaut
            "texte_longueur": len(texte) if texte else 0,
            "retention_jusqu_a": (
                datetime.utcnow().isoformat()  # + retention
            )
        }

        # Stocker le texte uniquement si bloqué (pour audit)
        if decision == "blocked" and texte:
            entry["texte_tronque"] = texte[:200]

        return entry

    def purger_anciens_logs(self, logs: list) -> list:
        """Purge les logs au-delà de la durée de rétention."""
        cutoff = datetime.utcnow()  # - timedelta(days=retention)
        return [
            log for log in logs
            if log.get("retention_jusqu_a", "") > cutoff.isoformat()
        ]

Audit trail pour la conformité

Le RGPD et l’AI Act exigent une traçabilité des décisions automatisées. Implémentez un audit trail :

class AuditTrail:
    """Audit trail pour les décisions de modération."""

    def __init__(self, storage_path: str):
        self.storage_path = storage_path

    def enregistrer_decision(self, data: dict) -> str:
        """Enregistre une décision avec un identifiant unique."""
        import uuid

        audit_id = str(uuid.uuid4())
        entry = {
            "audit_id": audit_id,
            "timestamp": datetime.utcnow().isoformat(),
            "type_decision": data.get("decision"),
            "modele_moderation": "mistral-moderation-2603",
            "scores": data.get("scores"),
            "seuils_appliques": data.get("seuils"),
            "politique_version": data.get("politique_version"),
            "action_prise": data.get("action"),
            "base_legale": "interet_legitime",
            "responsable": "systeme_automatise"
        }

        # Écrire dans le fichier d'audit
        import json
        with open(self.storage_path, "a") as f:
            f.write(json.dumps(entry, ensure_ascii=False) + "\n")

        return audit_id

Checklist RGPD pour votre application IA

Voici les points à vérifier pour assurer la conformité de votre système de modération :

Base légale

  • Intérêt légitime documenté pour la modération de contenu
  • Information des utilisateurs sur le traitement automatisé
  • Possibilité de contester une décision automatisée

Minimisation des données

  • Ne stocker que les données strictement nécessaires
  • Anonymiser ou pseudonymiser les identifiants utilisateur
  • Tronquer les textes dans les logs de modération
  • Ne pas conserver les textes acceptés (uniquement les scores)

Durée de conservation

  • Définir une durée de rétention pour chaque type de donnée
  • Logs de modération : 90 jours maximum (sauf obligation légale)
  • Audit trail : selon la réglementation sectorielle
  • Purge automatique programmée

Droits des utilisateurs

  • Droit d’accès aux décisions de modération les concernant
  • Droit de rectification si la décision est contestée
  • Droit à l’explication de la décision automatisée

Points clés à retenir

  • Le RGPD s’applique pleinement à vos systèmes de modération IA
  • Utilisez la catégorie pii de Mistral ET des regex pour détecter les données personnelles
  • Anonymisez les textes avant de les envoyer au modèle quand possible
  • Pseudonymisez les identifiants utilisateur dans les logs
  • Implémentez un audit trail pour la traçabilité des décisions
  • Définissez une durée de rétention et purgez automatiquement les logs