Pro API: генерация и ретушь изображений
Одно изображение стоит 1 кредит, независимо от режима. Генерация по промпту и ретушь загруженного тобой изображения выполняются через один и тот же маршрут.
POST /images/quote принимает то же тело запроса и возвращает цену, ничего не создавая, всегда
{ "cost": 1, ... } в этом случае. Это сделано для симметрии с видео, где цена может варьироваться.
Отправить изображение
POST /images
{ "prompt": "portrait of a woman in a rainy street at night, neon reflections, cinematic",
"width": 832, "height": 1216 }| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
prompt | string | обязательное | Описание сцены. Английский язык даёт наиболее точные результаты. |
width, height | int | 1024 x 1024 | Размер в пикселях. Удачные форматы: 1024 x 1024 (квадрат), 832 x 1216 (портрет), 1216 x 832 (альбомный). |
mode | string | generation | edit, img2img или inpaint, см. ниже. Отсутствие поля означает генерацию по промпту. |
image_b64 | string | Исходное изображение в base64 (PNG или JPEG), обязательно для всех трёх режимов ретуши. Не более 12 МБ после декодирования. | |
mask_b64 | string | Маска в base64: обязательна для inpaint, необязательна для edit. Закрась области для ретуши красным цветом, размер совпадает с исходным изображением. | |
lora | string | Обученный персонаж в аккаунте: name, возвращаемый GET /loras. Добавь его trigger в промпт. | |
lora2, lora2_strength | string, number | Второй персонаж и его сила (от 0 до 1, по умолчанию 1) для сцены с двумя персонажами. | |
count | int | 1 | Количество изображений для рендера в одном запросе, от 1 до 8. Каждое получает свой уникальный сид; при указании seed они используют seed, seed+1, seed+2... Это соответствует селектору Изображений за генерацию в приложении. |
seed | int | случайный | Сид рендера, от 0 до 4294967295. Одинаковый seed, промпт и настройки дают одинаковый результат с очень незначительными отличиями при смене видеокарты. Сохранение seed при изменении промпта позволяет получить вариацию с сохранением композиции. |
steps | int | движок | Оставь пустым. Движок сам знает своё значение. |
Ответ:
{ "jobId": "test-79634842-4586-46d4-ad52-d9ea236ae00d", "seed": 178078967, "cost": 1 }seed возвращается в ответе, указал ты его сам или он был выбран случайно: сохрани его, чтобы
снова сгенерировать то же изображение или создать его вариацию.
Запрос нескольких изображений сразу
При count больше 1 один запрос запускает несколько рендеров, каждый со своим сидом, и ответ
содержит их список:
{ "count": 4, "requested": 4, "cost_total": 4,
"jobs": [ { "jobId": "...", "seed": 178078967, "cost": 1 }, { "jobId": "...", "seed": 903412, "cost": 1 } ],
"errors": [],
"jobId": "...", "seed": 178078967, "cost": 1 }Обрати внимание на два момента.
jobId, seed и cost первого рендера продублированы на верхнем уровне. Это сделано для
обратной совместимости с клиентами, написанными до поддержки пакетной обработки, а не потому что
первый запрос важнее. Опрашивай каждую запись в jobs, а не только её.
И сравнивай count с requested. Отказ в середине процесса из-за нехватки кредитов или
превышения дневного лимита ключа остановит пакет на текущем месте: requested это то, что ты
запросил, count это то, что реально запустилось, а errors объясняет причину остановки.
Клиент, предполагающий равенство этих значений, незаметно теряет рендеры.
POST /images/quote тоже принимает count и рассчитывает стоимость всего пакета. У видео нет count:
один запрос, один клип.
Три режима ретуши
Все три работают на одном движке редактирования с поддержкой инструкций, который сохраняет
внешний вид исходного изображения. При передаче исходного изображения width и height читаются
из самого изображения и не требуют явной передачи.
mode | Входные данные | Что делает движок |
|---|---|---|
edit | image_b64 + prompt (+ необязательный mask_b64) | Применяет инструкцию ко всему изображению ("добавить солнцезащитные очки", "сделать снег"). С маской изменение сосредотачивается внутри красной области. |
inpaint | image_b64 + mask_b64 + prompt | Регенерирует только красную область маски согласно инструкции. Остальное воссоздаётся пиксель за пикселем. |
img2img | image_b64 + prompt | Переработка всего изображения по промпту с сохранением его композиции и стиля: вариация. |
В режиме edit сервер сам выбирает лучший способ правки, как приложение:
- с маской: он читает инструкцию и выбирает между заменой содержимого области (другой предмет, другая одежда, лицо: область перерисовывается по тому, что должно в ней появиться) и изменением того, что в ней есть (цвет, материал, свет). С
loraперсонажа область всегда перерисовывается, включая лицо; - без маски, с
loraперсонажа ("replace the woman with kara..."): сервер находит человека на фото и перерисовывает его в персонажа; если никого не найдено, инструкция применяется ко всему изображению, как раньше.
Цена одна во всех случаях (1 кредит за изображение). Выбор виден в результате, а не в ответе.
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\"}"Создание изображения с персонажами, предметами и локацией
Добавь объект multiref в POST /images, и сервер соберёт твоих персонажей (Персонажи), твои предметы и животных и локацию (Объекты) вместе на одном изображении, каждого узнаваемым, как на экране "Создать изображение" в приложении. Вызывай каждого по @Имя в промпте, на английском.
{ "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 }Поле multiref | Что делает |
|---|---|
characters[].character_id, name | Персонаж из GET /characters; name: слово, которое пишется после @ (буквы, цифры, _). |
characters[].view | Ракурс его character sheet, который его представляет, от 1 до 5 (по умолчанию 1, бюст анфас). |
characters[].sheet_id | Необязательно: используемый character sheet (по умолчанию самый последний). |
characters[].lora | Необязательно: его LoRA для изображений, имя из списка image в GET /loras. Тогда персонажа передаёт его LoRA, а не его ракурс. |
characters[].strength | Сила LoRA, от 0 до 1,5 (по умолчанию 1). |
characters[].lora_pass | Доля изображения, перерисовываемая его проходом LoRA, от 0,3 до 0,9 (по умолчанию 0,55); полезно при нескольких объектах. |
characters[].description | Необязательно, на английском: одежда, возраст... |
subjects[] | Предметы и животные из /subjects: subject_id, name (по умолчанию первое слово его названия), description, image (какое из его изображений, по умолчанию 1). |
location | Локация из /subjects (subject_id, name) или разовый фон: background_b64 и background_description. |
count | 1 или 2: изображения рендерятся одно за другим. |
- Не более 4 объектов (персонажи, предметы и животные). Без LoRA, только по изображениям: не более 4 референсов, включая локацию. Сервер выбирает метод по референсам и размещает каждый в порядке
characters, затемsubjects, слева направо. @Имя, не соответствующее ни одному референсу, отклоняется (unknown_mention); референс, отсутствующий в промпте, всё равно передаётся.- Цена: один проход стоит как одно изображение (1 кредит). Простое изображение: 1 проход; несколько персонажей, переданных через LoRA: 1 плюс один проход на каждую LoRA (не более 4); только по изображениям: один проход на каждый референс после первого; смешанный вариант: и то и другое. Итог (проходы x
count) резервируется при отправке и списывается один раз, при финальном изображении: ошибка или отмена ничего не стоят.POST /images/quoteс тем же телом запроса даёт точную цену, метод и его проходы, ничего не запуская. - Ответ
202:{ "jobId": "mri_...", "seed", "cost", "method", "passes", "billed_passes" }(приcount2:jobsиcost_total). Опрос статуса, загрузка и отмена идут через обычные маршруты ниже; во время рендераprogressпоказывает текущий проход ("2/3"). Создание изображения занимает от 1 до 3 минут. - Финальное изображение доступно 1 час, и 10 минут после первой загрузки. Неудавшийся проход даёт
status: "failed"сreason: "render_failed"; отмена:reason: "cancelled". - Ошибки:
invalid_count,invalid_view,invalid_lora_pass,invalid_subject_image,invalid_size,character_not_ready, а также ошибки Multi-Ref (unknown_character,unknown_subject,unknown_lora,unknown_mention,multiref_too_many_references,invalid_strength...). См. Лимиты и ошибки.
Опрос статуса
GET /images/{jobId}
| Ответ | Значение |
|---|---|
{ "status": "pending", "phase": "IN_QUEUE" } | В очереди |
{ "status": "pending", "phase": "IN_PROGRESS" } | Рендерится |
{ "status": "completed", "cost": 1, "file_url": "/pro/v1/images/{jobId}/file", ... } | Готово, файл доступен |
{ "status": "failed", "detail": "..." } | Ошибка, ничего не списывается |
Опрашивай каждые 3 секунды, не чаще: очередь общая.
Загрузка
GET /images/{jobId}/file
Сам PNG-файл в теле ответа (Content-Type: image/png). Доступен сразу после получения статуса
completed, и вернёт 404 media_unavailable после удаления рендера. Загружай сразу, файлы не архивируются.
Отмена
POST /images/{jobId}/cancel
Отменяет рендер в очереди или выполняющийся. Возвращает { "ok": true }. Ничего не списывается, и
зарезервированная стоимость возвращается обратно в дневной лимит ключа.