Détecter et bloquer le contenu généré dans Strapi 5 avec OpenAI
Apprenez pas à pas comment intégrer l’API de modération d’OpenAI dans Strapi 5, en utilisant les hooks de cycle de vie ou le middleware guardrails de l’AI‑SDK pour rejeter le contenu toxique avant son enregistrement ou sa publication.
Par l’équipe Revisionary · · 4 min de lecture
Réponse : Dans Strapi 5, vous pouvez vérifier automatiquement chaque morceau de texte (ou image) généré par les utilisateurs avec l’API de modération d’OpenAI et le rejeter dans le flux de contenu en ajoutant un hook de cycle de vie ou en utilisant le middleware guardrails de l’AI‑SDK. Voici un guide complet, prêt pour la production.
Vue d’ensemble
Strapi 5 stocke le contenu sous forme de documents Draft et Published. Avant qu’un Draft ne soit persistant — ou avant qu’un Draft ne passe en Published — vous pouvez exécuter du code personnalisé. Le point de terminaison de modération d’OpenAI (POST /v1/moderations) renvoie un drapeau flagged ainsi que les catégories correspondantes pour le texte soumis. En branchant cet appel aux hooks de cycle de vie de Strapi ou au middleware Guardrails, vous obtenez :
- Rejet en temps réel de tout contenu haineux, harcelant ou illégal.
- Raison détaillée affichée aux éditeurs.
- Historique complet (utilisez le plugin Revisionary pour conserver un historique des décisions de modération).
Prérequis
- Projet Strapi 5 fonctionnant sous Node 18‑24 avec une base de données supportée.
- Clé d’API OpenAI disposant de l’accès au modèle de modération (
omni-moderation-latest). - Optionnel : le plugin payant Revisionary si vous souhaitez conserver un enregistrement versionné de chaque tentative de modération.
1. Installer le plugin OpenAI
Strapi fournit un plugin communautaire officiel qui ajoute un service openAI.
npm install @strapi/plugin-open-ai # or yarn add @strapi/plugin-open-aiAprès l’installation, redémarrez Strapi afin que le plugin soit chargé.
2. Configurer le jeton OpenAI
Créez ou modifiez ./config/plugins.js (ou plugins.ts si vous utilisez TypeScript) et ajoutez le jeton API :
module.exports = ({ env }) => ({
// other plugins …
openAI: {
config: {
apiToken: env('OPENAI_API_KEY'), // défini dans le fichier .env
},
},
});Ajoutez OPENAI_API_KEY=sk-… à votre fichier .env. Le plugin expose alors strapi.plugin('openAI').service('moderation').
3. Choisir votre point d’intégration
Vous avez deux méthodes fiables pour intercepter le contenu :
- Hooks de cycle de vie – exécuter la modération avant que le contenu ne soit sauvegardé ou publié.
- Middleware Guardrails – utiliser le plugin
guardrailsde l’AI‑SDK pour bloquer les requêtes vers tout endpoint IA, pratique lorsque vous exposez une route personnalisée/api/ai/*. Les deux approches sont illustrées ci‑dessous.
3.1 Utiliser les hooks de cycle de vie
Les hooks de cycle de vie se trouvent dans ./src/api/<content-type>/content-types/<content-type>/lifecycles.js.
// src/api/article/content-types/article/lifecycles.js
module.exports = {
async beforeCreate(event) {
await moderate(event);
},
async beforeUpdate(event) {
await moderate(event);
},
};
async function moderate(event) {
const { data } = event.params;
// Ne modérer que les champs contenant du texte utilisateur
const text = `${data.title || ''}\n${data.body || ''}`;
if (!text.trim()) return; // rien à vérifier
const moderation = await strapi
.plugin('openAI')
.service('moderation')
.create({ model: 'omni-moderation-latest', input: text });
if (moderation.results[0].flagged) {
const categories = Object.entries(moderation.results[0].categories)
.filter(([, v]) => v)
.map(([k]) => k)
.join(', ');
throw new Error(
`Content rejected by OpenAI moderation. Categories: ${categories}`
);
}
}Ce qui se passe : lorsqu’un éditeur crée ou met à jour un article, Strapi appelle beforeCreate/beforeUpdate. Le hook envoie le titre et le corps concaténés à OpenAI. Si la réponse est marquée comme flagged, le hook lève une erreur, que Strapi affiche dans l’interface d’administration comme une erreur de validation.
3.2 Utiliser le middleware Guardrails (AI‑SDK)
Installez d’abord le plugin Guardrails de l’AI‑SDK (inclus dans @strapi/plugin-open-ai ou sous forme de plugin séparé selon votre configuration).
npm install @strapi/plugin-ai-sdk # nom hypothétique ; adaptez à votre projetCréez une configuration Guardrails dans config/plugins.ts :
export default ({ env }) => ({
guardrails: {
enabled: true,
maxInputLength: 10000,
blockedMessage: 'Your content violates our policy and was blocked.',
// hook personnalisé défini ci‑dessous
beforeProcess: async ({ text, route, ctx }) => {
const response = await fetch('https://api.openai.com/v1/moderations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${env('OPENAI_API_KEY')}`,
},
body: JSON.stringify({ model: 'omni-moderation-latest', input: text }),
});
const result = await response.json();
const flagged = result.results[0].flagged;
if (flagged) {
const categories = Object.entries(result.results[0].categories)
.filter(([, v]) => v)
.map(([k]) => k)
.join(', ');
return { blocked: true, reason: `OpenAI moderation flagged: ${categories}` };
}
return { blocked: false, sanitized: text };
},
},
});Dorénavant, toute route utilisant l’AI‑SDK (par ex. /api/ai-sdk/chat) exécutera d’abord la fonction beforeProcess. Si le contenu est flagué, le middleware renvoie un 403 avec le blockedMessage.
4. Tester l’intégration
- Test unitaire – moquez la réponse d’OpenAI avec une bibliothèque comme
nocket vérifiez que le hook lève une erreur sur du contenu flagué. - Test manuel – dans l’interface admin de Strapi, essayez de créer un article contenant un discours de haine évident (ex. « I hate all … »). L’erreur doit apparaître immédiatement.
- Test end‑to‑end – appelez l’API publique (
POST /api/articles) avec un payload JSON contenant du texte flagué. La réponse HTTP doit être400 Bad Requestavec le message d’erreur du hook.
5. Considérations en production
- Limites de débit – le forfait gratuit d’OpenAI autorise un nombre limité d’appels de modération par minute. Mettez en cache les résultats récents si vous prévoyez un fort trafic.
- Modération d’images – le point de terminaison accepte également des images (
image_url). Étendez la fonctionmoderatepour parcourir les URL d’images téléchargées et les envoyer dans la même requête (max 20 Mo par image). - Historique d’audit – utilisez le plugin Revisionary pour enregistrer chaque décision de modération. Le journal d’audit du plugin (
/docs/reference/audit) indique qui a tenté d’enregistrer le contenu et pourquoi il a été bloqué. - Gestion des erreurs – ne divulguez pas les messages d’erreur bruts d’OpenAI aux utilisateurs finaux. Transformez‑les en un avis générique « Contenu non autorisé » tout en consignant les raisons détaillées pour les administrateurs.
- Localisation – si votre site est multilingue, appliquez la modération sur le texte de chaque locale. Le panneau de traduction de Revisionary (
/docs/everyday-use/translations) aide à garder les locales synchronisées.
6. Déploiement en production
- Ajoutez
OPENAI_API_KEYen tant que secret dans votre environnement d’hébergement (Vercel, Netlify, Railway, etc.). - Assurez‑vous que les fichiers du plugin sont inclus dans votre image Docker ou votre étape de build.
- Effectuez un test de fumée après le déploiement pour vérifier que la modération bloque toujours le contenu prohibé.
7. Quand choisir les hooks vs les guardrails
| Aspect | Hooks de cycle de vie | Middleware Guardrails |
|---|---|---|
| Portée | Types de contenu spécifiques uniquement | Toutes les routes AI‑SDK, quel que soit le type de contenu |
| Granularité | Possibilité d’inspecter n’importe quel champ, statut, locale | Fonctionne sur le corps brut de la requête avant que Strapi ne le parse |
| Simplicité | Un peu plus de code par type de contenu | Point de configuration centralisé |
| Performance | Un appel supplémentaire par création/mise à jour | Un appel supplémentaire par requête AI |
Choisissez l’approche qui correspond à votre architecture. De nombreuses équipes débutent avec les hooks pour le contenu éditorial, puis ajoutent les guardrails pour les endpoints IA publics.
Conclusion
En installant le plugin officiel OpenAI, en configurant votre clé API et en intégrant l’appel de modération soit via un hook de cycle de vie, soit via le middleware guardrails de l’AI‑SDK, vous disposez d’un filet de sécurité automatisé qui bloque le contenu toxique généré par les utilisateurs avant qu’il n’atteigne votre base de données ou votre API publique. Combinez cela avec l’historique de version et le journal d’audit de Revisionary pour conserver une trace infalsifiable de chaque décision de modération.
Lectures complémentaires
- Référence de l’API de modération OpenAI – https://developers.openai.com/api/reference/resources/moderations/methods/create
- Guide des hooks de cycle de vie Strapi – https://docs.strapi.io/cms/migration/v4-to-v5/breaking-changes/lifecycle-hooks-document-service
- Documentation du middleware Guardrails – https://github.com/PaulBratslavsky/strapi-plugin-ai-sdk/blob/HEAD/docs/guardrails.md
- Bases du développement de plugins Strapi – https://docs.strapi.io/cms/plugins-development/plugin-structure
Sources
L’équipe Revisionary
Les développeurs de Revisionary, un plugin d’historique des versions pour Strapi 5. Nous écrivons sur Strapi, le développement web, l’IA et la sécurité des applications.
Cet article a été rédigé avec l'aide d'une IA.