Aller au contenu

Marquer les brouillons IA pour la révision dans Strapi 5

Apprenez à appeler l’API Modération d’OpenAI depuis les hooks lifecycle de Strapi 5, à enregistrer les résultats et à diriger les brouillons IA vers la file de révision de Revisionary pour validation.

Par l’équipe Revisionary · · 5 min de lecture

Person using laptop with ai integration logo displayed
Photo de Jo Lin sur Unsplash

Strapi 5 peut appeler l’API de modération d’OpenAI dans un hook lifecycle beforeCreate, marquer le brouillon avec le champ moderationStatus, et le pousser dans l’espace Review de Revisionary afin que les éditeurs puissent approuver ou rejeter le contenu généré par IA avant sa mise en ligne.

Pourquoi automatiser la modération des brouillons IA ?

  • Les rédacteurs IA peuvent produire rapidement du texte de haute qualité, mais ils peuvent aussi générer un langage interdit ou risqué.
  • Automatiser la première vérification de sécurité fait gagner du temps aux éditeurs et réduit le risque de publier du contenu nuisible.
  • Utiliser la file d’attente de révision native de Revisionary vous permet de garder l’étape de modération dans la même interface CMS que les équipes de contenu utilisent déjà.

Vue d’ensemble de la solution

  1. Ajouter un champ d’état de modération au type de contenu article.
  2. Créer un service personnalisé qui communique avec le point d’accès Modération d’OpenAI.
  3. Brancher le service aux hooks lifecycle beforeCreate et beforeUpdate de Strapi afin que chaque brouillon soit vérifié dès son enregistrement.
  4. Configurer Revisionary pour traiter les entrées avec moderationStatus: "pending_review" comme des éléments prêts pour la révision.
  5. Exposer l’état dans l’interface admin afin que les relecteurs voient clairement le badge « Needs review ».

Les sections suivantes détaillent chaque étape avec des exemples de code fonctionnant avec Strapi 5 (Node 18‑24) et le SDK officiel OpenAI Node.

1. Étendre le schéma de l’article

Ajoutez un champ chaîne qui enregistre le résultat de la modération. Ouvrez le fichier de schéma à src/api/article/content-types/article/schema.json et insérez :

json
{
  "kind": "collectionType",
  "collectionName": "articles",
  "info": { "singularName": "article", "pluralName": "articles", "displayName": "Article" },
  "options": { "draftAndPublish": true },
  "attributes": {
    "title": { "type": "string", "required": true },
    "content": { "type": "richtext" },
    "moderationStatus": {
      "type": "enumeration",
      "enum": ["unreviewed", "clean", "pending_review", "rejected"],
      "default": "unreviewed"
    }
  }
}

L’énumération vous permet de filtrer les brouillons dans le panneau d’administration et dans l’espace Review de Revisionary.

2. Installer le SDK OpenAI

Exécutez la commande suivante à la racine de votre projet Strapi :

bash
npm install openai
# or yarn add openai

Le SDK fonctionne avec le modèle omni-moderation-latest, qui accepte les entrées texte et image.

3. Stocker la clé d’API en toute sécurité

Créez une variable d’environnement nommée OPENAI_API_KEY. Ajoutez‑la à votre fichier .env :

dotenv
OPENAI_API_KEY=sk‑your‑secret‑key

Strapi lit les variables d’environnement via le helper env() dans n’importe quel fichier de configuration. Pour une exposition côté admin (par ex., afin de permettre à un·e utilisateur·rice privilégié·e de voir la clé dans l’UI), préfixez‑la avec STRAPI_ADMIN_ – mais ne divulguez jamais le secret au public.

4. Construire un service de modération

Générez le service avec le générateur de Strapi (optionnel) ou créez le fichier manuellement à src/api/article/services/moderate.ts :

ts
import OpenAI from 'openai';
import { env } from '@strapi/utils';

// Initialise le client une seule fois
const openai = new OpenAI({ apiKey: env('OPENAI_API_KEY') });

/**
 * Appelle la modération d’OpenAI et renvoie un indicateur booléen.
 */
export const moderateText = async (text: string) => {
  try {
    const response = await openai.moderations.create({
      model: 'omni-moderation-latest',
      input: text,
    });
    const result = response.results[0];
    return {
      flagged: result.flagged,
      categories: result.categories,
      scores: result.category_scores,
    };
  } catch (err) {
    // Journalise et traite les erreurs comme non‑signalées pour ne pas bloquer le flux de travail.
    strapi.log.error('OpenAI moderation error:', err);
    return { flagged: false, categories: {}, scores: {} };
  }
};

Le service isole l’appel à OpenAI, rendant le hook lifecycle plus lisible et permettant la réutilisation dans d’autres contextes (par ex., un bouton admin personnalisé).

5. Intégrer la modération à la création de contenu

Créez ou modifiez le fichier de lifecycle à src/api/article/content-types/article/lifecycles.ts :

ts
import { moderateText } from '../services/moderate';

export default {
  /** Appelé avant l’enregistrement d’un brouillon */
  async beforeCreate(event) {
    const { data } = event.params;
    // Exécuter la modération uniquement sur les brouillons générés par IA – vous pouvez ajouter un drapeau comme data.isAi = true
    if (!data.content) return;
    const { flagged, categories } = await moderateText(data.content);
    if (flagged) {
      data.moderationStatus = 'pending_review';
      // Enregistrer les catégories à des fins d’audit (optionnel)
      data.moderationDetails = JSON.stringify(categories);
    } else {
      data.moderationStatus = 'clean';
    }
  },

  /** Même logique pour les mises à jour, utile lorsque les éditeurs modifient des brouillons IA */
  async beforeUpdate(event) {
    const { data } = event.params;
    if (!data.content) return;
    const { flagged, categories } = await moderateText(data.content);
    if (flagged) {
      data.moderationStatus = 'pending_review';
      data.moderationDetails = JSON.stringify(categories);
    } else {
      data.moderationStatus = 'clean';
    }
  },
};

Le hook s’exécute synchroniquement avant la persistance de l’entrée, garantissant que le champ moderationStatus reflète toujours la vérification la plus récente.

Openai logo with green and white cylindrical letters
Photo de Brecht Corbeel sur Unsplash

6. Connecter la file de révision de Revisionary

Revisionary liste automatiquement toute entrée qui correspond à un filtre personnalisé que vous définissez dans ses réglages. Pour acheminer les brouillons IA :

  1. Ouvrez Revisionary → Settings → Review filters (chemin interne /docs/teamwork/review).
  2. Ajoutez un filtre : moderationStatus = pending_review.
  3. Enregistrez les paramètres.

Tous les articles signalés par le hook de modération apparaîtront désormais dans l’espace Review, où les éditeurs peuvent Accepter, Rejeter ou Modifier le contenu. Lorsqu’un·e éditeur·rice clique sur Accepter, changez moderationStatus en clean (vous pouvez ajouter une action admin personnalisée ou laisser le relecteur modifier le champ manuellement).

7. Montrer l’état dans l’UI admin

Le gestionnaire de contenu de Strapi peut afficher des champs personnalisés dans la vue liste. Ajoutez moderationStatus à la configuration de la vue liste (src/admin/src/content-manager/components/ContentTypeListView/index.js si vous avez un plugin admin personnalisé). Pour une solution rapide, activez le champ dans la vue édition et reposez‑vous sur la couleur du badge que Revisionary ajoute aux éléments en révision.

8. Option : Notifier les relecteurs par email ou Slack

Si vous souhaitez des alertes proactives, utilisez le provider email de Strapi ou un webhook vers une application Slack.

ts
import { sendEmail } from '../services/email'; // supposez que vous avez un service d’email

export const notifyReviewers = async (article) => {
  const subject = `AI‑generated draft requires review: ${article.title}`;
  const body = `A new draft has been flagged by OpenAI moderation.\n\nReview it here: ${process.env.FRONTEND_URL}/admin/content-manager/collectionType/api::article.article/${article.id}`;
  await sendEmail({ to: 'review-team@example.com', subject, text: body });
};

Appelez notifyReviewers à la fin du hook beforeCreate lorsque flagged est vrai.

9. Gestion du rate‑limit et nouvelles tentatives

OpenAI impose des limites par minute (généralement 60 req/min pour le niveau gratuit). Le SDK effectue automatiquement un back‑off sur les réponses 429, mais vous pouvez ajouter une simple file d’attente en‑processus si vous prévoyez un volume élevé de brouillons.

ts
import PQueue from 'p-queue';
const queue = new PQueue({ interval: 60000, intervalCap: 55 }); // rester sous la limite
export const moderateText = async (text: string) =>
  queue.add(() => _moderateText(text));

Remplacez _moderateText par l’implémentation originale. Cela empêche un throttling accidentel lors d’imports massifs.

10. Auditer les décisions de modération

Le journal d’audit de Revisionary enregistre chaque modification de contenu, y compris les mises à jour de champs. Comme le hook lifecycle modifie moderationStatus et moderationDetails, ces changements apparaissent automatiquement dans le journal. Pour rendre le journal plus exploitable, ajoutez une vue d’audit personnalisée filtrant sur moderationStatus = pending_review.

11. Tester l’intégration

  1. Créez un brouillon via l’UI admin ou l’API REST (POST /api/articles).
  2. Incluez un texte que vous savez être signalé, par ex., « I want to kill everyone ».
  3. Après la requête, vérifiez :
    • Le champ moderationStatus de l’article vaut pending_review.
    • L’entrée apparaît dans la file Review de Revisionary.
    • Un email ou un message Slack (si configuré) est reçu.
  4. Refaites le même test avec un paragraphe neutre et confirmez que le statut devient clean.

Des tests automatisés peuvent être ajoutés à votre pipeline CI avec Jest :

ts
test('moderation flag triggers review', async () => {
  const res = await request(strapi.server).post('/api/articles').send({ title: 'Test', content: 'I want to kill everyone' });
  expect(res.body.data.attributes.moderationStatus).toBe('pending_review');
});

12. Déployer en production

  • Variables d’environnement – assurez‑vous que OPENAI_API_KEY est définie dans votre environnement d’hébergement (Vercel, Railway, etc.).
  • Scalabilité – l’appel de modération ajoute ~150 ms de latence par requête. Si vous avez besoin de réponses sous une seconde, envisagez une file de jobs en arrière‑plan (par ex., BullMQ) qui traite les brouillons après sauvegarde et les déplace vers Review de façon asynchrone.
  • Conformité – ne stockez que les catégories nécessaires à l’audit ; évitez de conserver le texte brut de l’utilisateur plus longtemps que nécessaire pour respecter le RGPD ou le CCPA.

13. Résumé

En intégrant l’API de modération d’OpenAI aux hooks lifecycle de Strapi 5, en ajoutant un champ moderationStatus et en configurant le filtre Review de Revisionary, vous obtenez un pipeline entièrement automatisé qui :

  • Detecte immédiatement les brouillons IA à risque.
  • Les achemine vers une file dédiée aux relecteurs au sein du même CMS.
  • Conserve une traçabilité à l’épreuve de la falsification.
  • Permet des notifications optionnelles pour un traitement humain rapide.

Cette approche s’adapte des petites équipes éditoriales aux grandes agences produisant des centaines d’articles assistés par IA chaque jour, tout en restant dans le modèle d’extension native de Strapi.


Documentation interne associée

Mots-clésIAStrapiRevisionaryFlux de contenuOpenAI

Sources

  1. OpenAI Moderation guide
  2. Strapi lifecycle hooks documentation
  3. Strapi environment configuration guide

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