Référence de l’API IA.
DXPR Builder expose trois routes IA. Le navigateur les appelle, et les contrôleurs transmettent la requête via le module AI de Drupal au fournisseur DXPR (ai_provider_dxpr), pour que la clé API ne parvienne jamais au navigateur. Les routes sont définies dans dxpr_builder.routing.yml ; le comportement ci-dessous vient de src/Controller/AiChatController.php et src/Controller/AiImageController.php.

Conditions d’accès (les trois routes)
| Exigence | Source |
|---|---|
Méthode HTTP POST |
methods: [POST] dans la route |
Permission edit with dxpr builder |
_permission |
| Utilisateur facturable (place de licence valide) | _dxpr_builder_billable_user, vérifié par DxprBuilderBillableUserAccessCheck |
Jeton CSRF dans le paramètre token de la requête |
_csrf_token: 'TRUE' |
| Cookie de session Drupal connecté | Les vérifications d’accès Drupal tournent par utilisateur |
Le jeton est le jeton CSRF de route de Drupal pour le chemin de la route. DXPR Builder le génère côté serveur et l’intègre dans drupalSettings.dxprBuilder.aiAgent comme endpointUrl, imageEndpointUrl et imageEditEndpointUrl (voir DxprBuilderFormatter). Lisez l’une de ces valeurs depuis une page où l’éditeur est chargé pour obtenir une URL fonctionnelle. Une vérification d’accès ratée renvoie la réponse 403 standard de Drupal.
Les contrôleurs instancient toujours le fournisseur dxpr ; le fournisseur défini sous /admin/config/ai/settings n’est pas utilisé.
Chat
POST /dxpr_builder/ajax/ai/chat?token=...
Utilisé par les commandes de texte, la création de pages et les suggestions de prompt. Le contrôleur lit un corps JSON et appelle $provider->chat().
Corps de la requête
| Champ | Type | Requis | Notes |
|---|---|---|---|
messages |
tableau de {role, content} |
oui | role vaut system, user ou assistant |
model |
chaîne | non | Défaut : kavya-m1. Doit figurer dans la liste Allowed models du fournisseur |
stream |
booléen | non | Défaut : true |
prediction |
objet | non | Transmis tel quel, par exemple {"type":"content","content":"<p>...</p>"} |
providers |
chaîne | non | Identifiants de fournisseurs séparés par des virgules, par exemple openai,mistral |
allowed_html_tags |
chaîne | non | Transmis tel quel ; le builder envoie Bootstrap 5 HTML |
allowed_html_classes |
chaîne | non | Transmis tel quel ; le builder envoie Bootstrap 5 Classes |
web_search |
booléen | non | Seul false est transmis |
response_format |
objet | non | Transmis tel quel ; un objet json_schema par exemple |
Le contrôleur ajoute toujours jsonrpc: false à la configuration du fournisseur. Avant l’appel, il fusionne les domaines de AI Output Filtering > Allowed domains dans le filtre de noms d’hôte du module AI pour la durée de la requête (* fait passer le filtre en confiance totale).
Réponse
En continu (stream vrai, le défaut) : 200, Content-Type: text/event-stream. Chaque événement est data: {json} suivi d’une ligne vide, et le flux se termine par data: [DONE].
data: {"choices":[{"delta":{"content":"Hello"}}],"id":"...","model":"kavya-m1","usage":{...}}
data: [DONE]
id, object, created, model, original_model et usage sont copiés depuis le morceau brut du fournisseur quand ils sont présents.
Non continu (stream faux) : 200, application/json :
{"choices":[{"message":{"role":"assistant","content":"..."}}]}
Erreurs
| Statut | Corps |
|---|---|
400 |
Texte brut Invalid request: messages required |
403 |
{"error":{"code":"model_not_allowed","message":"The selected model is not allowed. Please refresh the page to update your model options."}} quand ai_provider_dxpr est installé et que model n’est pas dans sa liste Allowed models |
500 |
{"error":{"message":"The request could not be completed."}} (détails dans le canal de log dxpr_builder) |
Exemple
const url = drupalSettings.dxprBuilder.aiAgent.endpointUrl;
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "kavya-m1",
stream: false,
messages: [
{ role: "system", content: "You are a copywriter." },
{ role: "user", content: "Shorten: <p>Our team ...</p>" }
]
})
});
const data = await res.json();
console.log(data.choices[0].message.content);
Génération d’images
POST /dxpr_builder/ajax/ai/image?token=...
Appelle $provider->textToImage().
Corps de la requête
| Champ | Type | Requis | Notes |
|---|---|---|---|
prompt |
chaîne | oui | Description textuelle de l’image |
model |
chaîne | non | Défaut : kavya-image |
size |
chaîne | non | Le builder envoie 1024x1024, 1536x1024 ou 1024x1536 ; omis pour Auto |
quality |
chaîne | non | Transmis au fournisseur sans changement |
background |
chaîne | non | Transmis au fournisseur sans changement |
Réponse
200, application/json. Seule la première image est renvoyée, encodée en base64. Le fournisseur DXPR demande une sortie webp.
{"data":[{"b64_json":"UklGRi..."}]}
Erreurs
| Statut | Corps |
|---|---|
400 |
{"error":{"message":"Invalid request: prompt required"}} |
500 |
{"error":{"message":"No image was generated"}} |
500 |
{"error":{"message":"Image generation failed. Please try again."}} |
Exemple
curl -X POST "https://example.com/dxpr_builder/ajax/ai/image?token=TOKEN" \
-H "Content-Type: application/json" \
-H "Cookie: SESSxxx=..." \
-d '{"prompt":"Flat illustration of a rocket","size":"1536x1024"}'
Modification d’images
POST /dxpr_builder/ajax/ai/image/edit?token=...
Appelle $provider->imageToImage() avec l’image téléversée et le prompt.
Corps de la requête
| Champ | Type | Requis | Notes |
|---|---|---|---|
prompt |
chaîne | oui | Instruction de modification |
image |
chaîne | oui | Données d’image Base64 sans préfixe data: ; décodage strict |
mimeType |
chaîne | non | Défaut : image/png ; le sous-type devient l’extension du fichier |
model |
chaîne | non | Défaut : kavya-image |
size, quality, background |
chaîne | non | Comme pour la génération d’images |
Réponse
Même forme que la génération d’images : {"data":[{"b64_json":"..."}]}.
Erreurs
| Statut | Corps |
|---|---|
400 |
{"error":{"message":"Invalid request: prompt and image required"}} |
400 |
{"error":{"message":"Invalid image data: base64 decode failed"}} |
500 |
{"error":{"message":"No image was generated"}} |
500 |
{"error":{"message":"Image editing failed. Please try again."}} |
Exemple
const url = drupalSettings.dxprBuilder.aiAgent.imageEditEndpointUrl;
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
prompt: "Remove the background",
image: base64String,
mimeType: "image/jpeg"
})
});
const { data } = await res.json();
Stocker une image générée
Les routes ne renvoient que les octets de l’image. Le builder convertit b64_json en fichier webp et le téléverse vers POST /dxpr_builder/ajax/file_upload (drupalSettings.dxprBuilder.fileUploadUrl, champ de formulaire upload[]), qui répond avec l’url et le fid du fichier. Le prompt devient le nom du fichier (80 premiers caractères) et l’attribut alt.