Aller au contenu

Boutons

Les boutons d'IA de l'admin, AiActions et AiResults, qui les voit, leur formulaire, les modes fill et choose, les propositions gardées à côté d'un contenu et la limite d'appels.

Un bouton d'IA vit dans l'écran d'un autre module : l'éditeur d'un post, la fenêtre d'un média. Le module IA fournit le composant, l'écran le place et décide de ce que devient la réponse. Rien n'est enregistré : la réponse remplit les champs, et la personne relit avant d'enregistrer.

Cette page sert à qui écrit un écran d'admin, dans un module ou dans le projet. Les deux composants se lisent par l'intégration ai, sans importer @fraza/module-ai : sans le module, getIntegration('ai') rend null et l'écran n'affiche rien.

Placer un bouton

'use client';
import { getIntegration } from '@fraza/core/integrations';

export function SummaryButton({ request, onSummary }) {
  const AiActions = getIntegration('ai')?.AiActions;
  if (!AiActions) return null;
  return (
    <AiActions
      target="site.request"
      context={() => ({ requestId: request.id })}
      onApply={(values) => onSummary(values.summary)}
    />
  );
}
PropriétéRequiseRôle
targetouiL'écran, tel que les prompts le nomment dans leur target.
scopenonUn objet qui choisit le schéma de sortie, transmis à output(scope). {} par défaut. Changer le scope relit la liste des boutons.
contextnonUn objet, ou une fonction appelée au clic, pour envoyer le contenu tel qu'il est à ce moment. Transmis à build().
onApplyouiReçoit la réponse vérifiée. Met les valeurs dans les champs de l'écran, sans enregistrer.
disablednonDésactive le bouton, pendant un enregistrement par exemple.

Le composant demande au serveur les prompts de cet écran que ce compte peut lancer. Un seul : un bouton à son libellé. Plusieurs : un menu « IA ». Aucun : rien n'est rendu, ni bouton ni message.

Tout prompt qui vise l'écran y apparaît. Un prompt du projet déclaré avec target: 'posts.post' s'ajoute au menu de l'éditeur de Posts. Sa réponse passe alors par le onApply de Posts, qui ne lit que les clés qu'il connaît : un tel prompt reprend leur forme.

Qui voit un bouton

Un prompt apparaît sur l'écran quand toutes ces conditions tiennent :

  1. Le module est activé, et le compte a ai.use.
  2. Le prompt a un target égal à celui de l'écran, et le projet ne l'a pas désactivé.
  3. Le compte a la permission propre au prompt, s'il en a une.
  4. Son output donne un schéma pour ce scope. Une fonction qui rend null dit que le prompt ne s'applique pas ici, une fonction qui lève retire aussi le bouton.

Le bouton n'apparaît pas tant que le fournisseur n'est pas configuré : chaque clic échouerait. La page IA nomme alors la variable en cause.

Seul un prompt à target se lance depuis le navigateur. Un prompt sans écran ne s'appelle que depuis le code du serveur : il peut lire ce qu'un compte de l'admin ne doit pas atteindre, et la route POST /ai/run le refuse comme un prompt inconnu.

Le formulaire d'un bouton

Un prompt qui déclare un input ouvre un court formulaire avant l'appel. Les champs viennent du schéma, dans son ordre :

SchémaChamp
string avec enumUne liste.
string avec maxLength de 120 au plusUne ligne.
string plus longue, ou sans maxLengthPlusieurs lignes.
number, integerUn nombre, la virgule acceptée comme séparateur.
booleanUne case à cocher.

Le libellé est le title du champ, sinon sa clé, et l'aide sa description. Un champ est requis sauf si son type admet null ; un champ laissé vide part alors à null. Une case à cocher n'est jamais requise. Le formulaire vérifie les champs requis, les entiers et maxLength, puis le serveur vérifie de nouveau tout le schéma : une saisie hors schéma rend invalid_input.

input: {
  type: 'object',
  properties: {
    subject: { type: 'string', maxLength: 200, title: 'Sujet' },
    details: { type: ['string', 'null'], maxLength: 2000, title: 'Détails', description: 'Facultatif.' },
  },
  required: ['subject', 'details'],
},

Le formulaire ne sait dessiner que des champs simples, au premier niveau : textes, nombres et cases à cocher. Un input qui imbrique un objet ou une liste est refusé à la déclaration.

Deux modes

fill remplit les champs : la réponse va tout droit à onApply, et un message rappelle de relire avant d'enregistrer. C'est le mode de Posts, qui reçoit un titre, un contenu et des termes.

choose propose des choix. Chaque propriété de la réponse qui est une liste de textes devient un groupe, et la personne en prend un par groupe, ou aucun. onApply reçoit un objet aux mêmes clés, avec le texte choisi à la place de chaque liste, ou null pour un groupe laissé vide. Les autres propriétés passent telles quelles.

// Réponse du modèle
{ filenames: ['chat-roux', 'chat-sur-canape', 'chat-endormi'], altTexts: ['…', '…', '…'] }
// Ce que reçoit onApply
{ filenames: 'chat-sur-canape', altTexts: null }

Le titre d'un groupe est le title de la propriété, sinon sa description, sinon sa clé. La première proposition de chaque groupe est cochée à l'ouverture. C'est le mode de Médias : trois noms de fichier et trois textes alternatifs, pour en garder un de chaque.

Les propositions gardées

Une tâche en arrière-plan n'a personne à qui montrer sa réponse. Elle la range avec saveResult() à côté du contenu qu'elle concerne, voir Tâches. L'écran de ce contenu l'affiche avec AiResults :

const AiResults = getIntegration('ai')?.AiResults;

{AiResults && (
  <AiResults
    target="medias.media"
    id={media.id}
    labels={{ altText: 'Texte alternatif' }}
    onApply={(data) => setAltText(data.altText)}
  />
)}
PropriétéRequiseRôle
targetouiLe type de contenu, comme dans saveResult.
idouiL'identifiant du contenu.
labelsnonLe nom affiché de chaque clé de la réponse. Une clé sans nom s'affiche telle quelle.
onApplynonReçoit (data, result) au clic sur « Utiliser ». Sans lui, seul « Ignorer » est offert.

Chaque proposition s'affiche dans une carte marquée « Proposé par l'IA », la plus récente en tête. « Utiliser » passe la réponse à l'écran, qui la met dans ses champs sans enregistrer, puis la marque comme utilisée. « Ignorer » la marque seulement. Une proposition marquée ne s'affiche plus, jusqu'à ce que la tâche en range une nouvelle pour le même contenu et le même prompt. Rien n'est rendu sans proposition, ni pour un compte sans ai.use.

Limite d'appels

Chaque appel coûte des jetons. POST /ai/run, et le bouton « Tester » de la page IA, comptent sur leur propre préréglage, ai_run : 10 tentatives par fenêtre de 10 minutes, blocage de 10 minutes. Comme tout préréglage d'une route connectée, il est compté sur le compte et triplé pour une session vérifiée, soit 30 appels par compte et par fenêtre, les deux routes ensemble. Une personne qui clique reste loin en dessous, une boucle ne fait pas grimper la facture. Voir Rate limit.

Notes

  • Les composants se lisent par getIntegration('ai') dans un fichier 'use client'. Le core fusionne sous ce nom les composants publiés par @fraza/module-ai/admin et les fonctions serveur. Voir Intégrations entre modules.
  • La route passe le signal de la requête à l'appel : une requête interrompue arrête l'attente du fournisseur, et l'historique note cancelled.
  • Un message d'erreur s'affiche dans une notification, en français, tel que le module le rend. Voir API.

Sur cette page