Руководство
Как использовать flux-2-klein-9b/image-to-image через API hiapi: curl, Python и рабочий запрос
Этот учебный материал показывает, как вызвать режим image-to-image модели flux-2-klein-9b через единый API задач hiapi: точную структуру запроса, рабочие команды curl, Python-скрипт, который можно сразу вставить в бэкенд, и одну особенность схемы, на которую вы наткнётесь, если переходите с других моделей на платформе.
После прочтения у вас будет скрипт, который принимает URL одного референсного изображения и промпт редактирования, а возвращает URL готового изображения для скачивания.
Что вам понадобится
- Аккаунт hiapi и API key. Его можно получить в консоли hiapi.
- Ровно одно референсное изображение, размещённое по публичному HTTPS-URL. В отличие от некоторых image-to-image моделей на платформе, которые принимают несколько референсных изображений, массив
image_urlsу flux-2-klein-9b ограничен одним элементом — подробности ниже. - Текстовый промпт, описывающий редактирование или преобразование.
Все запросы отправляются на единый эндпоинт задач, ключ передаётся в заголовке Authorization:
POST https://api.hiapi.ai/v1/tasks
Authorization: Bearer sk-<your-key>
Content-Type: application/json
Структура запроса (и одно поле, на котором легко ошибиться)
Идентификатор модели — flux-2-klein-9b/image-to-image — передавайте его как есть, точно так, как он указан в /v1/models. Его схема input строгая:
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
prompt |
string | Да | Инструкция для редактирования. |
image_urls |
string[] | Да | Ровно один URL референсного изображения — minItems и maxItems равны 1. |
aspect_ratio |
string | Нет | Одно из значений: 1:1, 4:3, 3:4, 16:9, 9:16. |
seed |
integer | Нет | Зафиксируйте его, чтобы воспроизводить результат. |
output_format |
string | Нет | Одно из значений: jpeg, png, webp. |
Прежде чем писать код, стоит узнать две вещи:
image_urlsпринимает только один URL, а не диапазон.Если вы построили общий код отправки вокруг модели, принимающей 1–14 референсных изображений, отправка двух URL здесь будет отклонена —maxItems: got 2, want 1. Эта модель выполняет редактирование по одному изображению, а не слияние нескольких референсов.- Лишние поля отклоняются, а не игнорируются.
resolution,size,n,strength,image_sizeиnum_images— все они распространены в других моделях изображений на платформе — здесь возвращают400 INVALID_REQUEST: additional properties '<field>' not allowed. Не переиспользуйте payload другой модели, не проверив схему этой модели.
Минимальный рабочий пример: curl
Создайте задачу:
curl -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "flux-2-klein-9b/image-to-image",
"input": {
"prompt": "Change the jacket to charcoal grey leather, keep the pose and background unchanged",
"image_urls": ["https://your-cdn.example.com/subject.png"],
"aspect_ratio": "3:4",
"output_format": "png"
}
}'
После успешной отправки в data возвращается id задачи:
{"code": 200, "data": {"taskId": "tk-hiapi-..."}}
Опрашивайте результат:
curl https://api.hiapi.ai/v1/tasks/tk-hiapi-... \
-H "Authorization: Bearer sk-<your-key>"
Во время выполнения data.status последовательно проходит queued → handling → archiving. По завершении он переключается на "success", а изображение появляется в data.output:
{
"code": 200,
"data": {
"status": "success",
"output": [{"url": "https://.../result.png", "expireAt": "..."}]
}
}
URL вывода живёт недолго (обратите внимание на expireAt). Скачайте байты сразу и сохраните их у себя — никогда не используйте горячие ссылки и не сохраняйте исходный URL.
Python для продакшена: отправка, опрос, скачивание
import time
import requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
API_KEY = "sk-<your-key>"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
def edit_image(prompt: str, image_url: str,
aspect_ratio: str = "1:1", output_format: str = "png") -> bytes:
# 1. Создать задачу — image_urls этой модели принимает ровно один URL
resp = requests.post(API_BASE, headers=HEADERS, json={
"model": "flux-2-klein-9b/image-to-image",
"input": {
"prompt": prompt,
"image_urls": [image_url],
"aspect_ratio": aspect_ratio,
"output_format": output_format,
},
}, timeout=60)
body = resp.json()
if resp.status_code != 200 or not (body.get("data") or {}).get("taskId"):
raise RuntimeError(f"create failed [{resp.status_code}]: {body}")
task_id = body["data"]["taskId"]
# 2. Опрашивать до терминального состояния
deadline = time.time() + 600
while time.time() < deadline:
task = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS,
timeout=30).json().get("data") or {}
if task.get("status") == "success":
outputs = task.get("output") or []
if not outputs or not outputs[0].get("url"):
raise RuntimeError(f"task {task_id} succeeded but returned no output URL")
# 3. Скачать сразу — URL истекает
img = requests.get(outputs[0]["url"], timeout=120)
img.raise_for_status()
return img.content
if task.get("status") == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')} {err.get('message')}")
time.sleep(5)
raise TimeoutError(f"task {task_id} still running after 600s")
if __name__ == "__main__":
png = edit_image(
"Change the jacket to charcoal grey leather, keep the pose and background unchanged",
"https://your-cdn.example.com/subject.png",
aspect_ratio="3:4",
)
with open("edited.png", "wb") as f:
f.write(png)
print(f"saved edited.png ({len(png)} bytes)")
Воспроизводимое редактирование с помощью seed
Передайте целое число seed, и модель будет использовать его в этой генерации — это полезно, когда вы хотите оставить всё остальное неизменным и провести A/B-тестирование формулировки промпта:
{
"model": "flux-2-klein-9b/image-to-image",
"input": {
"prompt": "Change the jacket to charcoal grey leather, keep the pose and background unchanged",
"image_urls": ["https://your-cdn.example.com/subject.png"],
"seed": 42
}
}
Если его опустить, модель будет выбирать seed случайно при каждом вызове — именно это и нужно для обычного продакшен-трафика: когда вам нужны разные варианты результата, меняйте промпт, а не seed.
Callback вместо опроса
Для скриптов и очередей воркеров опрос подходит. Для веб-бэкенда зарегистрируйте callback при создании задачи, чтобы hiapi отправлял вам терминальное состояние — объект callback находится на верхнем уровне запроса, рядом с model:
{
"model": "flux-2-klein-9b/image-to-image",
"input": { "...": "..." },
"callback": {
"url": "https://your-app.example.com/hooks/hiapi",
"when": "final"
}
}
С "when": "final" вы получите ровно один POST, когда задача достигнет состояния успеха или ошибки. У обработчика два правила:
- Сделайте его идемпотентным.Стройте логику обработки по ключу task id, чтобы повторно доставленный webhook не обрабатывался дважды. Сохраняйте task id при отправке и рассматривайте callback как «пойди и заверши», а не как единственный источник истины.
- Сохраняйте путь сверки.Если в момент срабатывания callback ваш эндпоинт недоступен, периодический обход неразрешённых id и GET
/v1/tasks/<id>позволит поймать всё пропущенное.
Если ваш callback, похоже, так и не приходит, пройдитесь по материалу почему ваш callback задачи hiapi не срабатывает — там в порядке вероятности разобраны типичные причины сбоев.
Обработка ошибок: три ключевых сценария сбоя
При создании возвращается 401 permission_denied — ваш ключ не может использовать эту модель. Тело ответа выглядит так:
{"error": {"code": "permission_denied", "message": "...", "request_id": "...", "type": "hiapi_error"}}
Если вы с этим столкнулись, проверьте материал недействительный API key или посмотрите права ключа на модели в консоли.
При создании возвращается 400 INVALID_REQUEST — ваш input не соответствует схеме этой модели. Сообщение прямо указывает на нарушающее поле (например, <root>: additional properties 'resolution' not allowed или image_urls: maxItems: got 2, want 1). Это постоянные ошибки — повторная отправка того же payload будет всегда терпеть неудачу; исправьте поле и отправьте заново.
Задача возвращает status: "fail" — создание прошло успешно, но генерация не удалась (референсный URL, который бэкенд не может получить, политика контента, ёмкость вышестоящего сервиса). Поля задачи error.code и error.message скажут, что именно. В отличие от 400, некоторые из них временные, и стоит один раз повторить с экспоненциальной задержкой.
Также полезно знать: GET по несуществующему или истёкшему id задачи возвращает 404 task not found — при сверке это следует считать терминальным состоянием, а не «всё ещё ожидает».
Куда двигаться дальше
- Страница модели flux-2-klein-9b/image-to-image — песочница и цена за изображение.
- Цены hiapi — актуальные тарифы для всех моделей изображений.
- Учебный материал по seedream-5.0-lite image-to-image — тот же API задач, но схема принимает до 14 референсных изображений вместо 1; хороший пример того, почему payload нельзя переносить между моделями.
- Документация hiapi по API асинхронных задач — полный справочник по созданию, опросу и callback.
- Документация hiapi по аутентификации — настройка API key и формат заголовков.
Частые вопросы
Могу ли я передать несколько референсных изображений в flux-2-klein-9b image-to-image?
Нет. У image_urls и minItems, и maxItems равны 1 — ровно один URL, ни больше ни меньше. Если вам нужно слияние нескольких референсов, посмотрите модели, схема которых допускает более широкий диапазон, например seedream-5.0-lite.
Почему я получаю «additional properties 'resolution' not allowed»?
Схема input API задач зависит от модели. flux-2-klein-9b/image-to-image вообще не принимает поля resolution или size — размер вывода следует за входным изображением и aspect_ratio. Удалите любые поля размера, перенесённые из payload другой модели.
Могу ли я отправить референсное изображение в base64, а не по URL?
Схема этой модели принимает image_urls — массив URL. Разместите изображение по доступному HTTPS-URL (подойдёт любой CDN, объектное хранилище или pre-signed URL) и передайте этот URL.
Что на самом деле контролирует seed?
Одинаковые seed, prompt и референсное изображение воспроизводят одинаковый результат генерации — это полезно для контролируемых A/B-тестов промптов. В обычном трафике опускайте его, чтобы каждый вызов получал свой случайный seed.
Тот же код подходит для flux-2-klein-9b text-to-image?
Эндпоинт и процесс те же, но у text-to-image своя схема input (без image_urls). Замените id модели на flux-2-klein-9b/text-to-image и уберите референсное изображение — затем проверьте тестовым вызовом, поскольку обязательные поля различаются по режимам.
Сколько стоит каждое изображение? Цена рассчитывается по использованию за каждую генерацию. Смотрите актуальные тарифы на странице цен.
Похожие статьи
Все статьи →-
Руководство
Как вызвать hailuo-2.3-fast/image-to-video через HiAPI API: практика с curl и Python
Первый рабочий запрос к быстрому и недорогому уровню генерации видео по изображению — от ID модели до загрузки MP4
-
Руководство
Как вызывать hailuo-2.3/text-to-video через API HiAPI: curl, Python и рабочие примеры запросов
-
Руководство
Использование Kandinsky 6.0 Pro для преобразования текста в видео на HiAPI: руководство по curl и Python
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата