Referencia de la API de IA.
DXPR Builder expone tres rutas de IA. El navegador
las llama, y los controladores pasan la petición
por el módulo Drupal AI hasta el proveedor de DXPR
(ai_provider_dxpr), así que la clave de API nunca llega
al navegador. Las rutas se definen en
dxpr_builder.routing.yml; el comportamiento de abajo viene
de src/Controller/AiChatController.php y
src/Controller/AiImageController.php.

Requisitos de acceso (las tres rutas)
| Requisito | Origen |
|---|---|
Método HTTP POST |
methods: [POST] en la ruta |
Permiso edit with dxpr builder |
_permission |
| Persona facturable (licencia válida) | _dxpr_builder_billable_user, comprobado por DxprBuilderBillableUserAccessCheck |
Parámetro de consulta token con el token CSRF |
_csrf_token: 'TRUE' |
| Cookie de sesión Drupal con sesión iniciada | Las comprobaciones de acceso de Drupal se ejecutan por persona |
El token es el token CSRF de ruta de Drupal para la
ruta. DXPR Builder lo genera en el servidor
y lo incrusta en drupalSettings.dxprBuilder.aiAgent
como endpointUrl, imageEndpointUrl e
imageEditEndpointUrl (consulta
DxprBuilderFormatter). Lee uno de esos valores
en una página donde el editor está cargado para obtener una
URL válida. Una comprobación de acceso fallida devuelve la
respuesta 403 estándar de Drupal.
Los controladores siempre instancian el proveedor dxpr;
el proveedor fijado en
/admin/config/ai/settings no se usa.
Chat
POST /dxpr_builder/ajax/ai/chat?token=...
Usado por comandos de texto, creación de páginas y sugerencias
de prompts. El controlador lee un cuerpo JSON y
llama a $provider->chat().
Cuerpo de la petición
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
messages |
array de {role, content} |
sí | role es system, user o assistant |
model |
string | no | Predeterminado: kavya-m1. Debe estar en la lista Allowed models del proveedor |
stream |
boolean | no | Predeterminado: true |
prediction |
object | no | Se pasa tal cual, por ejemplo {"type":"content","content":"<p>...</p>"} |
providers |
string | no | ID de proveedor separados por comas, por ejemplo openai,mistral |
allowed_html_tags |
string | no | Se pasa tal cual; el constructor envía Bootstrap 5 HTML |
allowed_html_classes |
string | no | Se pasa tal cual; el constructor envía Bootstrap 5 Classes |
web_search |
boolean | no | Solo false se reenvía |
response_format |
object | no | Se pasa tal cual, por ejemplo un json_schema en forma de objeto |
El controlador siempre añade jsonrpc: false a la
configuración del proveedor. Antes de la llamada fusiona
los dominios de AI Output Filtering > Allowed
domains en el filtro de nombres de host del módulo de IA durante
la petición (* cambia el
filtro a confianza total).
Respuesta
En streaming (stream true, el valor predeterminado):
200, Content-Type: text/event-stream. Cada
evento es data: {json} seguido de una línea en blanco,
y el flujo termina con data: [DONE].
data: {"choices":[{"delta":{"content":"Hello"}}],"id":"...","model":"kavya-m1","usage":{...}}
data: [DONE]
id, object, created, model,
original_model y usage se copian del
fragmento crudo del proveedor cuando existen.
Sin streaming (stream false): 200,
application/json:
{"choices":[{"message":{"role":"assistant","content":"..."}}]}
Errores
| Estado | Cuerpo |
|---|---|
400 |
Texto simple 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."}} cuando ai_provider_dxpr está instalado y model no está en su lista Allowed models |
500 |
{"error":{"message":"The request could not be completed."}} (detalles en el canal de registro dxpr_builder) |
Ejemplo
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);
Generación de imágenes
POST /dxpr_builder/ajax/ai/image?token=...
Llama a $provider->textToImage().
Cuerpo de la petición
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
prompt |
string | sí | Descripción en texto de la imagen |
model |
string | no | Predeterminado: kavya-image |
size |
string | no | El constructor envía 1024x1024, 1536x1024 o 1024x1536; omitido para Auto |
quality |
string | no | Se pasa al proveedor sin cambios |
background |
string | no | Se pasa al proveedor sin cambios |
Respuesta
200, application/json. Solo se devuelve la primera imagen,
codificada en base64. El proveedor de DXPR
pide salida webp.
{"data":[{"b64_json":"UklGRi..."}]}
Errores
| Estado | Cuerpo |
|---|---|
400 |
{"error":{"message":"Invalid request: prompt required"}} |
500 |
{"error":{"message":"No image was generated"}} |
500 |
{"error":{"message":"Image generation failed. Please try again."}} |
Ejemplo
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"}'
Edición de imágenes
POST /dxpr_builder/ajax/ai/image/edit?token=...
Llama a $provider->imageToImage() con la
imagen subida y el prompt.
Cuerpo de la petición
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
prompt |
string | sí | Instrucción de edición |
image |
string | sí | Datos de imagen en Base64 sin prefijo data:; decodificación estricta |
mimeType |
string | no | Predeterminado: image/png; el subtipo pasa a ser la extensión del archivo |
model |
string | no | Predeterminado: kavya-image |
size, quality, background |
string | no | Como en la generación de imágenes |
Respuesta
Misma forma que la generación de imágenes:
{"data":[{"b64_json":"..."}]}.
Errores
| Estado | Cuerpo |
|---|---|
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."}} |
Ejemplo
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();
Guardar una imagen generada
Las rutas solo devuelven bytes de imagen. El constructor
convierte b64_json a un archivo webp y lo sube
a POST /dxpr_builder/ajax/file_upload
(drupalSettings.dxprBuilder.fileUploadUrl, campo de
formulario upload[]), que responde con la
url y el fid del archivo. El prompt pasa a ser el nombre del archivo
(primeros 80 caracteres) y el atributo alt.