Aller au contenu

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

black laptop computer turned on on table
Photo de James Harrison sur Unsplash

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).
A cell phone with a shield logo on it
Photo de appshunter.io sur Unsplash

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.

bash
npm install @strapi/plugin-open-ai   # or yarn add @strapi/plugin-open-ai

Aprè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 :

js
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 :

  1. Hooks de cycle de vie – exécuter la modération avant que le contenu ne soit sauvegardé ou publié.
  2. Middleware Guardrails – utiliser le plugin guardrails de 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.

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).

bash
npm install @strapi/plugin-ai-sdk   # nom hypothétique ; adaptez à votre projet

Créez une configuration Guardrails dans config/plugins.ts :

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

  1. Test unitaire – moquez la réponse d’OpenAI avec une bibliothèque comme nock et vérifiez que le hook lève une erreur sur du contenu flagué.
  2. 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.
  3. Test end‑to‑end – appelez l’API publique (POST /api/articles) avec un payload JSON contenant du texte flagué. La réponse HTTP doit être 400 Bad Request avec 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 fonction moderate pour 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

  1. Ajoutez OPENAI_API_KEY en tant que secret dans votre environnement d’hébergement (Vercel, Netlify, Railway, etc.).
  2. Assurez‑vous que les fichiers du plugin sont inclus dans votre image Docker ou votre étape de build.
  3. 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

AspectHooks de cycle de vieMiddleware Guardrails
PortéeTypes de contenu spécifiques uniquementToutes les routes AI‑SDK, quel que soit le type de contenu
GranularitéPossibilité d’inspecter n’importe quel champ, statut, localeFonctionne sur le corps brut de la requête avant que Strapi ne le parse
SimplicitéUn peu plus de code par type de contenuPoint de configuration centralisé
PerformanceUn appel supplémentaire par création/mise à jourUn 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.

Close-up of server cooling fans in a vibrant data center
Photo de Winston Chen sur Unsplash

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

Mots-clésStrapiOpenAIModérationHooks de cycle de vieGuardrailsSécurité du contenu

Sources

  1. OpenAI Moderation API reference
  2. OpenAI Moderation guide
  3. Strapi OpenAI plugin repository
  4. Strapi lifecycle hooks documentation
  5. Guardrails middleware documentation for Strapi AI‑SDK
  6. Strapi plugin development – plugin structure

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.

Tous les articles

IA

RAG versionné avec Strapi et Revisionary

Apprenez à créer un pipeline RAG qui interroge le contenu de Strapi tout en respectant l’historique des versions, grâce à Revisionary pour des réponses à jour et traçables.

· 5 min de lecture