API Pro: generar y retocar imágenes
Una imagen cuesta 1 crédito, sea cual sea el modo. La generación desde un prompt y el retoque de una imagen que tú aportes pasan por la misma ruta.
POST /images/quote acepta el mismo cuerpo y devuelve el precio sin crear nada, siempre
{ "cost": 1, ... } en este caso. Existe por simetría con los vídeos, donde el precio sí varía.
Enviar una imagen
POST /images
{ "prompt": "portrait of a woman in a rainy street at night, neon reflections, cinematic",
"width": 832, "height": 1216 }| Campo | Tipo | Por defecto | Qué hace |
|---|---|---|---|
prompt | string | requerido | La escena. En inglés se obtienen los resultados más precisos. |
width, height | int | 1024 x 1024 | Tamaño en píxeles. Proporciones recomendadas: 1024 x 1024 (cuadrado), 832 x 1216 (retrato), 1216 x 832 (paisaje). |
mode | string | generation | edit, img2img o inpaint, ver más abajo. Si se omite, genera desde el prompt. |
image_b64 | string | Imagen fuente en base64 (PNG o JPEG), requerida por los tres modos de retoque. 12 MB decodificados como máximo. | |
mask_b64 | string | Máscara en base64: requerida por inpaint, opcional para edit. Pinta en rojo las zonas que quieres retocar, al tamaño de la imagen fuente. | |
lora | string | Un personaje entrenado en la cuenta: el name devuelto por GET /loras. Incluye su trigger en el prompt. | |
lora2, lora2_strength | string, number | Un segundo personaje y su intensidad (0 a 1, por defecto 1) para una escena con dos personas. | |
count | int | 1 | Cuántas imágenes renderizar con esta solicitud, de 1 a 8. Cada una recibe su propia semilla; con seed, toman seed, seed+1, seed+2... Es el selector Imágenes por generación de la app. |
seed | int | aleatorio | Semilla del render, de 0 a 4294967295. Misma seed, mismo prompt y mismos ajustes: el mismo render, con diferencias muy leves si cambia la tarjeta gráfica. Mantener la seed y ajustar el prompt da una variación que conserva la composición. |
steps | int | motor | Déjalo vacío. El motor conoce su propio valor. |
La respuesta:
{ "jobId": "test-79634842-4586-46d4-ad52-d9ea236ae00d", "seed": 178078967, "cost": 1 }La seed se devuelve en la respuesta, tanto si la indicaste tú como si se generó aleatoriamente: guárdala para
renderizar la misma imagen de nuevo o una variación de ella.
Pedir varias a la vez
Con count mayor que 1, una sola solicitud inicia varios renders, cada uno con su propia semilla, y
la respuesta los lista:
{ "count": 4, "requested": 4, "cost_total": 4,
"jobs": [ { "jobId": "...", "seed": 178078967, "cost": 1 }, { "jobId": "...", "seed": 903412, "cost": 1 } ],
"errors": [],
"jobId": "...", "seed": 178078967, "cost": 1 }Dos cosas que conviene leer con atención.
El jobId, la seed y el cost del primer render se repiten en el nivel superior. Esto existe
para que los clientes escritos antes de que existieran los lotes sigan funcionando sin cambios, no porque el primero
importe más. Sondea cada entrada de jobs, no solo esa.
Y compara count con requested. Un rechazo a mitad del proceso, por falta de créditos o
porque la clave alcanzó su límite diario, detiene el lote donde está: requested es lo que pediste,
count es lo que realmente se inició, y errors explica por qué se detuvo. Un cliente que asume
que ambos son iguales pierde renders en silencio.
POST /images/quote también acepta count y calcula el precio de todo el lote. Los vídeos no tienen count:
una solicitud, un clip.
Los tres modos de retoque
Los tres funcionan sobre el mismo motor de edición basado en instrucciones, que preserva el aspecto de la
imagen fuente. Cuando aportas una imagen fuente, width y height se leen de la propia imagen
y no es necesario enviarlos.
mode | Entradas | Qué hace el motor |
|---|---|---|
edit | image_b64 + prompt (+ mask_b64 opcional) | Aplica la instrucción a toda la imagen ("añadir gafas de sol", "hacer que nieve"). Con una máscara, el cambio se concentra dentro del área roja. |
inpaint | image_b64 + mask_b64 + prompt | Regenera solo el área roja de la máscara siguiendo la instrucción. El resto se recompone píxel a píxel. |
img2img | image_b64 + prompt | Rework de toda la imagen siguiendo el prompt manteniendo su composición y aspecto: una variación. |
En edit, el servidor elige solo la mejor forma de tratar el retoque, como la app:
- con máscara: lee la instrucción y elige entre reemplazar el contenido de la zona (otro objeto, otra prenda, una cara: la zona se redibuja según lo que debe aparecer en ella) y modificar lo que hay (color, material, luz). Con un
lorade personaje, la zona siempre se redibuja, cara incluida; - sin máscara, con un
lorade personaje ("replace the woman with kara..."): el servidor encuentra a la persona de la foto y la redibuja con el personaje; si no encuentra a nadie, la instrucción se aplica a toda la imagen, como antes.
Mismo precio en todos los casos (1 crédito por imagen). La elección se ve en el resultado, no en la respuesta.
IMG=$(base64 -w0 photo.png)
curl -s $B/images -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d "{\"mode\":\"edit\",\"prompt\":\"add a red scarf, keep everything else identical\",\"image_b64\":\"$IMG\"}"Crear una imagen con personajes, objetos y un decorado
Añade un objeto multiref a POST /images y el servidor hace actuar a tus personajes (Personajes), tus objetos y animales y un decorado (Sujetos) juntos en una sola imagen, cada uno reconocible, como la pantalla «Crear una imagen» de la app. Llama a cada uno por @Nombre en el prompt, en inglés.
{ "prompt": "@Mia hands a cup of coffee to @Tom on a sunny terrace, both smiling",
"multiref": {
"characters": [
{ "character_id": "chr_8f3a...", "name": "Mia", "view": 1 },
{ "character_id": "chr_21bc...", "name": "Tom", "lora": "tom_v1", "strength": 1.0, "lora_pass": 0.55 }
],
"subjects": [ { "subject_id": "sub_...", "name": "Mug" } ],
"location": { "subject_id": "sub_...", "name": "Terrace" }
},
"width": 1344, "height": 768, "seed": 42, "count": 1 }Campo de multiref | Qué hace |
|---|---|
characters[].character_id, name | Un personaje de GET /characters; name es la palabra que se escribe tras @ (letras, dígitos, _). |
characters[].view | La vista de su sheet que lo representa, de 1 a 5 (1, el busto de frente, por defecto). |
characters[].sheet_id | Opcional: la sheet que se usa (la más reciente por defecto). |
characters[].lora | Opcional: su LoRA de imagen, un nombre de la lista image de GET /loras. El personaje lo interpreta entonces su LoRA, no su vista. |
characters[].strength | Intensidad del LoRA, de 0 a 1,5 (1 por defecto). |
characters[].lora_pass | Parte de la imagen que repinta su pasada de LoRA, de 0,3 a 0,9 (0,55 por defecto); útil con varios sujetos. |
characters[].description | Opcional, en inglés: outfit, edad... |
subjects[] | Objetos y animales de /subjects: subject_id, name (por defecto, la primera palabra de su nombre), description, image (cuál de sus imágenes, 1 por defecto). |
location | Un decorado de /subjects (subject_id, name), o un decorado puntual: background_b64 y background_description. |
count | 1 o 2: las imágenes se renderizan una tras otra. |
- 4 sujetos como máximo (personajes, objetos y animales). Sin LoRA, solo a partir de imágenes: 4 referencias como máximo, decorado incluido. El servidor elige el método según las referencias, y coloca cada una en el orden de
charactersy luego desubjects, de izquierda a derecha. - Un
@Nombreque no coincide con ninguna referencia se rechaza (unknown_mention); una referencia ausente del prompt se envía de todos modos. - Precio: una pasada cuesta el precio de una imagen (1 crédito). Una imagen simple es 1 pasada; varios personajes interpretados por un LoRA, 1 más una pasada por LoRA (4 como máximo); solo a partir de imágenes, una pasada por referencia más allá de la primera; una mezcla, ambas cosas. El total (pasadas x
count) se reserva al enviar y se descuenta una sola vez, con la imagen final: un fallo o una cancelación no cuesta nada.POST /images/quotecon el mismo cuerpo da el precio exacto, el método y sus pasadas, sin iniciar nada. - Respuesta
202:{ "jobId": "mri_...", "seed", "cost", "method", "passes", "billed_passes" }(concount2:jobsycost_total). El sondeo, la descarga y la cancelación usan las rutas habituales de más abajo; durante el render,progressindica la pasada en curso ("2/3"). Una imagen tarda de 1 a 3 minutos. - La imagen final sigue disponible 1 hora, y 10 minutos después de su primera descarga. Una pasada fallida da
status: "failed"conreason: "render_failed"; una cancelación,reason: "cancelled". - Errores:
invalid_count,invalid_view,invalid_lora_pass,invalid_subject_image,invalid_size,character_not_ready, más los de Multi-Ref (unknown_character,unknown_subject,unknown_lora,unknown_mention,multiref_too_many_references,invalid_strength...). Ver Límites y errores.
Sondeo
GET /images/{jobId}
| Respuesta | Significado |
|---|---|
{ "status": "pending", "phase": "IN_QUEUE" } | En cola |
{ "status": "pending", "phase": "IN_PROGRESS" } | Renderizando |
{ "status": "completed", "cost": 1, "file_url": "/pro/v1/images/{jobId}/file", ... } | Completado, archivo listo |
{ "status": "failed", "detail": "..." } | Fallido, y no se cobra nada |
Sondea cada 3 segundos, no más rápido: la cola es compartida.
Descarga
GET /images/{jobId}/file
El PNG en sí, como cuerpo de la respuesta (Content-Type: image/png). Disponible en cuanto el
estado sea completed, y 404 media_unavailable una vez que el render haya desaparecido. Descárgalo
de inmediato, no se archiva.
Cancelar
POST /images/{jobId}/cancel
Cancela un render en cola o en ejecución. Responde { "ok": true }. No se cobra nada, y el coste
reservado contra el límite diario de la clave se devuelve.