Modération et sécurité du contenu visuel
Modération et sécurité du contenu visuel
Déployer la génération d’images en production implique des responsabilités légales et éthiques. Cette leçon couvre les outils de modération d’OpenAI, les bonnes pratiques de filtrage, et les stratégies pour protéger votre application et vos utilisateurs.
Le système de modération intégré
GPT Image refuse automatiquement de générer certains contenus (violence, contenu sexuel explicite, etc.). Quand un prompt est refusé, l’API renvoie une erreur spécifique :
from openai import OpenAI, BadRequestError
client = OpenAI()
def generer_avec_moderation(prompt: str, output: str) -> dict:
"""Génère une image en gérant les refus de modération."""
try:
response = client.images.generate(
model="gpt-image-1",
prompt=prompt,
size="1024x1024",
quality="medium",
response_format="b64_json"
)
import base64
data = base64.b64decode(response.data[0].b64_json)
with open(output, "wb") as f:
f.write(data)
return {"status": "ok", "path": output}
except BadRequestError as e:
if "safety" in str(e).lower() or "content_policy" in str(e).lower():
return {
"status": "refuse",
"raison": "Contenu refusé par la politique de sécurité",
"details": str(e)
}
raise
resultat = generer_avec_moderation(
"Un chaton jouant avec une pelote de laine",
"chaton.png"
)
print(resultat)
Pré-filtrage des prompts utilisateur
Avant d’envoyer un prompt à GPT Image, filtrez-le avec l’API de modération d’OpenAI :
from openai import OpenAI
client = OpenAI()
def verifier_prompt(prompt: str) -> dict:
"""Vérifie un prompt avec l'API de modération avant génération."""
moderation = client.moderations.create(
model="omni-moderation-latest",
input=prompt
)
result = moderation.results[0]
if result.flagged:
categories_flagged = [
cat for cat, flagged in result.categories.__dict__.items()
if flagged
]
return {
"autorise": False,
"categories": categories_flagged,
"message": "Ce prompt a été signalé par le système de modération."
}
return {"autorise": True}
def generer_image_securisee(prompt: str, output: str):
"""Pipeline complet : modération + génération."""
# Étape 1 : pré-filtrage
check = verifier_prompt(prompt)
if not check["autorise"]:
print(f"Prompt refusé : {check['message']}")
print(f"Catégories : {check['categories']}")
return None
# Étape 2 : génération
print("Prompt validé, génération en cours...")
return generer_avec_moderation(prompt, output)
# Test avec un prompt inoffensif
generer_image_securisee(
"Un paysage de montagne avec un lac cristallin",
"montagne.png"
)
Modération des images générées
Vérifiez aussi les images après génération, car le modèle peut parfois produire du contenu inattendu :
from openai import OpenAI
import base64
client = OpenAI()
def moderer_image_generee(image_path: str) -> dict:
"""Analyse une image générée pour détecter du contenu problématique."""
with open(image_path, "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
moderation = client.moderations.create(
model="omni-moderation-latest",
input=[
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{image_b64}"
}
}
]
)
result = moderation.results[0]
if result.flagged:
categories_flagged = [
cat for cat, flagged in result.categories.__dict__.items()
if flagged
]
return {
"safe": False,
"categories": categories_flagged
}
return {"safe": True}
def pipeline_securise(prompt: str, output: str):
"""Pipeline complet : modération prompt + génération + modération image."""
# 1. Vérifier le prompt
check_prompt = verifier_prompt(prompt)
if not check_prompt["autorise"]:
return {"status": "prompt_refuse", "details": check_prompt}
# 2. Générer l'image
response = client.images.generate(
model="gpt-image-1",
prompt=prompt,
size="1024x1024",
quality="medium",
response_format="b64_json"
)
data = base64.b64decode(response.data[0].b64_json)
with open(output, "wb") as f:
f.write(data)
# 3. Vérifier l'image générée
check_image = moderer_image_generee(output)
if not check_image["safe"]:
import os
os.remove(output)
return {
"status": "image_supprimee",
"raison": "L'image générée a été signalée",
"categories": check_image["categories"]
}
return {"status": "ok", "path": output}
Gestion des prompts utilisateurs (UGC)
Quand vos utilisateurs fournissent les prompts, ajoutez des couches de protection supplémentaires :
from openai import OpenAI
import re
client = OpenAI()
class ModerateurPrompt:
"""Filtre multicouche pour les prompts utilisateur."""
def __init__(self):
self.mots_interdits = [] # À remplir selon votre politique
self.prefixe_securite = (
"Image sûre et appropriée pour tout public. "
"Pas de contenu violent, sexuel ou discriminatoire. "
)
def nettoyer(self, prompt: str) -> str:
"""Nettoie et normalise un prompt utilisateur."""
# Supprimer les injections potentielles
prompt = prompt.strip()
# Limiter la longueur
prompt = prompt[:500]
# Supprimer les caractères de contrôle
prompt = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', prompt)
return prompt
def verifier_mots(self, prompt: str) -> bool:
"""Vérifie l'absence de mots interdits."""
prompt_lower = prompt.lower()
for mot in self.mots_interdits:
if mot in prompt_lower:
return False
return True
def securiser(self, prompt: str) -> str:
"""Ajoute un préfixe de sécurité au prompt."""
return f"{self.prefixe_securite}{prompt}"
def pipeline(self, prompt_brut: str) -> dict:
"""Pipeline complet de modération d'un prompt utilisateur."""
# Étape 1 : nettoyage
prompt = self.nettoyer(prompt_brut)
# Étape 2 : vérification locale
if not self.verifier_mots(prompt):
return {"autorise": False, "raison": "Mot interdit détecté"}
# Étape 3 : modération API
check = verifier_prompt(prompt)
if not check["autorise"]:
return {"autorise": False, "raison": check["message"]}
# Étape 4 : ajout du préfixe de sécurité
prompt_final = self.securiser(prompt)
return {"autorise": True, "prompt": prompt_final}
moderateur = ModerateurPrompt()
# Simuler un prompt utilisateur
resultat = moderateur.pipeline("Un chat tigré dormant sur un coussin rouge")
if resultat["autorise"]:
print(f"Prompt sécurisé : {resultat['prompt']}")
else:
print(f"Refusé : {resultat['raison']}")
Logging et audit
En production, conservez un journal de toutes les générations pour audit :
import json
import os
from datetime import datetime
class AuditLogger:
"""Journal d'audit pour les générations d'images."""
def __init__(self, log_file: str = "audit_images.jsonl"):
self.log_file = log_file
def enregistrer(
self,
prompt: str,
user_id: str,
resultat: str,
image_path: str = None,
raison_refus: str = None
):
"""Enregistre une entrée d'audit."""
entry = {
"timestamp": datetime.now().isoformat(),
"user_id": user_id,
"prompt": prompt[:200],
"resultat": resultat, # "ok", "prompt_refuse", "image_supprimee"
"image_path": image_path,
"raison_refus": raison_refus,
}
with open(self.log_file, "a") as f:
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
def rapport(self, derniers_n: int = 100):
"""Génère un rapport des dernières générations."""
if not os.path.exists(self.log_file):
print("Aucun log trouvé.")
return
entries = []
with open(self.log_file, "r") as f:
for line in f:
entries.append(json.loads(line))
recent = entries[-derniers_n:]
total = len(recent)
ok = sum(1 for e in recent if e["resultat"] == "ok")
refuses = sum(1 for e in recent if e["resultat"] != "ok")
print(f"Rapport des {total} dernières générations :")
print(f" Acceptées : {ok} ({100*ok/total:.1f}%)")
print(f" Refusées : {refuses} ({100*refuses/total:.1f}%)")
if refuses > 0:
print(f"\nDétail des refus :")
for e in recent:
if e["resultat"] != "ok":
print(f" [{e['timestamp'][:10]}] {e['user_id']} : {e['raison_refus']}")
logger = AuditLogger()
logger.rapport()
Respect du droit d’auteur et des marques
GPT Image peut générer des images ressemblant à des styles artistiques ou des marques existantes. En production, protégez-vous :
# Bonnes pratiques à intégrer dans votre politique d'usage
REGLES_PRODUCTION = """
1. Ne pas demander d'imiter le style d'un artiste vivant nommément
2. Ne pas reproduire de logos ou marques déposées
3. Ne pas générer de visages de personnes réelles
4. Ajouter une mention "Image générée par IA" quand c'est requis
5. Conserver les logs de génération pendant 12 mois minimum
6. Permettre aux utilisateurs de signaler du contenu problématique
"""
def avertissement_usage():
"""Affiche les règles d'usage en production."""
print("=" * 60)
print("RÈGLES DE PRODUCTION — Génération d'images IA")
print("=" * 60)
print(REGLES_PRODUCTION)
Configuration RGPD et conformité
Pour les entreprises européennes, respectez le RGPD :
class ConfigConformite:
"""Configuration de conformité pour la génération d'images."""
def __init__(self):
self.retention_logs_jours = 365
self.retention_images_jours = 90
self.mention_ia_obligatoire = True
self.consentement_requis = True
def verifier_consentement(self, user_id: str) -> bool:
"""Vérifie que l'utilisateur a consenti à la génération IA."""
# À implémenter avec votre système de gestion des consentements
return True
def ajouter_metadata_ia(self, image_path: str):
"""Ajoute des métadonnées indiquant la génération par IA."""
from PIL import Image
from PIL.PngImagePlugin import PngInfo
img = Image.open(image_path)
metadata = PngInfo()
metadata.add_text("AI-Generated", "true")
metadata.add_text("Generator", "GPT Image via OpenAI API")
metadata.add_text("Date", datetime.now().isoformat())
img.save(image_path, pnginfo=metadata)
print(f"Métadonnées IA ajoutées : {image_path}")
Checklist de mise en production
Avant de déployer votre système de génération d’images :
- Modération : pré-filtrage des prompts + post-vérification des images
- Logging : journal complet de toutes les générations avec prompts et résultats
- Rate limiting : limiter le nombre de générations par utilisateur
- Consentement : informer les utilisateurs que les images sont générées par IA
- Métadonnées : marquer les images générées (EXIF ou métadonnées PNG)
- Droit à l’effacement : pouvoir supprimer les données d’un utilisateur sur demande
- Signalement : permettre aux utilisateurs de signaler du contenu problématique
- Backup : sauvegarder les logs d’audit indépendamment des images
Exercice pratique
Créez un service complet de génération d’images qui intègre : le pré-filtrage des prompts (modération API + liste de mots), le préfixe de sécurité, la post-vérification des images, le logging d’audit, et l’ajout de métadonnées IA sur chaque image. Testez-le avec 5 prompts variés (dont au moins un qui devrait être refusé).