API Pro : générer et retoucher des images

Une image coûte 1 crédit, quel que soit le mode. La génération à partir d'un prompt et la retouche d'une image que tu fournis passent toutes les deux par la même route.

POST /images/quote prend le même corps et renvoie le prix sans rien créer, toujours { "cost": 1, ... } ici. Il existe par symétrie avec les vidéos, où le prix varie.

Soumettre une image

POST /images

json
{ "prompt": "portrait of a woman in a rainy street at night, neon reflections, cinematic",
  "width": 832, "height": 1216 }
ChampTypeDéfautCe que ça fait
promptstringrequiredLa scène. L'anglais donne les résultats les plus précis.
width, heightint1024 x 1024Taille en pixels. Bonnes proportions : 1024 x 1024 (carré), 832 x 1216 (portrait), 1216 x 832 (paysage).
modestringgenerationedit, img2img ou inpaint, voir ci-dessous. Absent signifie générer depuis le prompt.
image_b64stringImage source en base64 (PNG ou JPEG), requise par les trois modes de retouche. 12 Mo décodés au maximum.
mask_b64stringMasque en base64 : requis par inpaint, facultatif pour edit. Peins en rouge les zones à retoucher, à la taille de l'image source.
lorastringUn personnage entraîné sur le compte : le name renvoyé par GET /loras. Mets son trigger dans le prompt.
lora2, lora2_strengthstring, numberUn second personnage et sa force (0 à 1, défaut 1) pour une scène à deux.
countint1Nombre d'images à générer depuis cette requête, de 1 à 8. Chacune reçoit sa propre graine aléatoire ; avec seed, elles prennent seed, seed+1, seed+2... C'est le sélecteur Images par génération de l'app.
seedintau hasardGraine du rendu, de 0 à 4294967295. Même seed, même prompt et mêmes réglages : le même rendu, à de très légers écarts près si la carte graphique change. Garder la seed et retoucher le prompt décline le rendu en gardant sa composition.
stepsintengineLaisse vide. Le moteur connaît sa propre valeur.

La réponse :

json
{ "jobId": "test-79634842-4586-46d4-ad52-d9ea236ae00d", "seed": 178078967, "cost": 1 }

La graine (seed) est renvoyée dans la réponse, qu'elle ait été donnée ou tirée au hasard : garde-la pour refaire la même image, ou pour la décliner.

Demander plusieurs images à la fois

Avec count supérieur à 1, une seule requête lance plusieurs rendus, chacun avec sa propre graine, et la réponse les liste tous :

json
{ "count": 4, "requested": 4, "cost_total": 4,
  "jobs": [ { "jobId": "...", "seed": 178078967, "cost": 1 }, { "jobId": "...", "seed": 903412, "cost": 1 } ],
  "errors": [],
  "jobId": "...", "seed": 178078967, "cost": 1 }

Deux points à lire attentivement.

Le jobId, le seed et le cost du premier rendu sont répétés au niveau supérieur. C'est là pour que les clients écrits avant les batchs continuent de fonctionner sans modification, pas parce que le premier compte davantage. Interroge chaque entrée de jobs, pas seulement celle-là.

Et compare count avec requested. Un refus en cours de route, faute de crédits ou parce que la clé a atteint son plafond journalier, arrête le batch là où il en est : requested est ce que tu as demandé, count est ce qui a réellement démarré, et errors explique pourquoi ça s'est arrêté. Un client qui suppose que les deux sont égaux perd des rendus en silence.

POST /images/quote accepte aussi count et calcule le prix du batch entier. Les vidéos n'ont pas de count : une requête, un clip.

Les trois modes de retouche

Les trois fonctionnent sur le même moteur d'édition piloté par instructions, qui préserve l'apparence de l'image source. Quand tu fournis une image source, width et height sont lus depuis l'image elle-même et n'ont pas besoin d'être envoyés.

modeEntréesCe que le moteur fait
editimage_b64 + prompt (+ mask_b64 facultatif)Applique l'instruction à l'image entière ("add sunglasses", "make it snow"). Avec un masque, la modification se concentre dans la zone rouge.
inpaintimage_b64 + mask_b64 + promptRégénère uniquement la zone rouge du masque en suivant l'instruction. Le reste est recomposé pixel pour pixel.
img2imgimage_b64 + promptRetravaille l'image entière en suivant le prompt tout en conservant sa composition et son aspect : une variation.

En edit, le serveur choisit seul la meilleure façon de traiter la retouche, comme l'application :

  • avec un masque : il lit la consigne et choisit entre remplacer le contenu de la zone (un autre objet, un autre vêtement, un visage : la zone est redessinée d'après ce qui doit y apparaître) et modifier ce qui s'y trouve (couleur, matière, lumière). Avec un lora de personnage, la zone est toujours redessinée, son visage compris ;
  • sans masque, avec un lora de personnage (« replace the woman with kara... ») : le serveur trouve la personne de la photo et la redessine avec le personnage ; sans personne trouvée, la consigne s'applique à toute l'image, comme avant.

Même prix dans tous les cas (1 crédit par image). Le choix se voit au résultat, pas dans la réponse.

bash
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\"}"

Créer une image avec des personnages, des objets et un lieu

Ajoute l'objet multiref à POST /images : le serveur fait jouer tes personnages (Personnages), tes objets et animaux et un lieu (Sujets) dans une seule image, chacun reconnaissable, comme l'écran « Créer une image » de l'application. Désigne chacun par @Nom dans le prompt, en anglais.

json
{ "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 }
Champ de multirefCe que ça fait
characters[].character_id, nameUn personnage de GET /characters ; name est le mot écrit après @ (lettres, chiffres, _).
characters[].viewLa vue de sa sheet qui le représente, 1 à 5 (1, le buste de face, par défaut).
characters[].sheet_idFacultatif : la sheet à utiliser (la plus récente par défaut).
characters[].loraFacultatif : son LoRA d'image, un nom de la liste image de GET /loras. Le personnage est alors joué par son LoRA, pas par sa vue.
characters[].strengthForce du LoRA, 0 à 1,5 (1 par défaut).
characters[].lora_passPart de l'image repeinte par sa passe LoRA, 0,3 à 0,9 (0,55 par défaut) ; utile avec plusieurs sujets.
characters[].descriptionFacultatif, en anglais : tenue, âge...
subjects[]Objets et animaux de /subjects : subject_id, name (par défaut le premier mot de son nom), description, image (laquelle de ses images, 1 par défaut).
locationUn lieu de /subjects (subject_id, name), ou un décor ponctuel : background_b64 et background_description.
count1 ou 2 : les images sont rendues l'une après l'autre.
  • 4 sujets au plus (personnages, objets et animaux). Sans LoRA, par images seules : 4 références au plus, lieu compris. Le serveur choisit la méthode d'après les références, et place chacune dans l'ordre de characters puis de subjects, de gauche à droite.
  • Un @Nom qui ne désigne aucune référence est refusé (unknown_mention) ; une référence absente du prompt part quand même.
  • Prix : une passe coûte le prix d'une image (1 crédit). Une image simple = 1 passe ; plusieurs personnages joués par un LoRA = 1 + une passe par LoRA (4 au plus) ; par images seules, une passe par référence au-delà de la première ; un mélange, les deux. Le total (passes x count) est réservé à la soumission et débité une seule fois, à l'image finale : un échec ou une annulation ne coûte rien. POST /images/quote avec le même corps donne le prix exact, la méthode et ses passes, sans rien lancer.
  • Réponse 202 : { "jobId": "mri_...", "seed", "cost", "method", "passes", "billed_passes" } (avec count 2 : jobs et cost_total). Suivi, téléchargement et annulation passent par les routes habituelles ci-dessous ; pendant le rendu, progress dit la passe en cours ("2/3"). Une image prend 1 à 3 minutes.
  • L'image finale reste disponible 1 heure, et 10 minutes après son premier téléchargement. Une passe ratée rend status: "failed" avec reason: "render_failed" ; une annulation, reason: "cancelled".
  • Erreurs : invalid_count, invalid_view, invalid_lora_pass, invalid_subject_image, invalid_size, character_not_ready, plus celles du Multi-Ref (unknown_character, unknown_subject, unknown_lora, unknown_mention, multiref_too_many_references, invalid_strength...). Voir Limites et erreurs.

Polling

GET /images/{jobId}

RéponseSignification
{ "status": "pending", "phase": "IN_QUEUE" }En file d'attente
{ "status": "pending", "phase": "IN_PROGRESS" }En cours de rendu
{ "status": "completed", "cost": 1, "file_url": "/pro/v1/images/{jobId}/file", ... }Terminé, fichier prêt
{ "status": "failed", "detail": "..." }Échoué, et rien n'est débité

Interroge toutes les 3 secondes, pas plus vite : la file est partagée.

Téléchargement

GET /images/{jobId}/file

Le PNG lui-même, comme corps de la réponse (Content-Type: image/png). Disponible dès que le statut est completed, et 404 media_unavailable une fois le rendu supprimé. Télécharge-le immédiatement, il n'est pas archivé.

Annulation

POST /images/{jobId}/cancel

Annule un rendu en file d'attente ou en cours. Renvoie { "ok": true }. Rien n'est débité, et le coût réservé sur le plafond journalier de la clé est restitué.

Windows · Mac · Cloud ou local

Génère en privé. Ce soir.

Télécharge tendre.AI gratuitement et génère sans limites, en privé, sur ton propre GPU.

OS Windows 10/11GPU NVIDIA 8 Go+VRAM 12 Go recommandésDisque 20 Go

Mac : puce Apple (M1 ou plus récent), macOS 13 minimum. Les Mac Intel ne sont pas pris en charge.

Sur Mac, la génération d'images en local demande un M4 avec 24 Go de mémoire, ou un M2 ou M3 Pro, Max ou Ultra avec 24 Go. En dessous, tout fonctionne en ligne avec les crédits. La retouche et la vidéo se font en ligne sur Mac pour l'instant.

Tout sur tendre.AI pour Mac

Pas de GPU NVIDIA ? Démarre à 100 % dans le cloud : 5 images et 1 vidéo gratuites chaque jour. Une carte NVIDIA (8 Go+) débloque la génération locale illimitée.