Руководство
Как вызвать seedream-4.5/image-to-image через HiAPI API: curl и Python
Полная демонстрация рабочего запроса, включая ввод нескольких референсных изображений, асинхронный опрос и обработку результатов
Что делает этот эндпоинт и когда его выбирать
seedream-4.5/image-to-image преобразует одно или несколько референсных изображений вместе с текстовым промптом в новое изображение. Это часть серии image-to-image на HiAPI: вы предоставляете визуальный контекст, а модель переосмысляет его согласно вашим инструкциям. Именно в этом ключевое отличие от text-to-image — в text-to-image промпт является единственным входом, и модель создаёт всё с нуля.
Выбирайте image-to-image, когда хотите, чтобы визуальный результат оставался привязанным к существующим материалам: рестайлинг существующих ассетов, изменение освещения или фона с сохранением формы и компоновки продукта, итерация композиции без потери субъекта или обеспечение единообразного вида партии результатов за счёт повторного использования одних и тех же референсов.
Выбирайте text-to-image, когда у вас нет референсных материалов и вы просто хотите описать сцену словами.
Этот эндпоинт асинхронный. Вы отправляете задачу, получаете идентификатор, затем опрашиваете, пока задача не перейдёт в терминальное состояние, после чего получаете результат. Планируйте этот жизненный цикл с самого начала; остальная часть руководства строит рабочий запрос, а затем делает его надёжным.
Создание рабочего curl-запроса
Каждый запрос к этому эндпоинту имеет одинаковую базовую структуру. Разберём её поле за полем.
Эндпоинт и метод
Запрос отправляется методом POST на маршрут image-to-image под базовым URL HiAPI с идентификатором модели seedream-4.5/image-to-image. Имя модели — это значение в теле запроса, а не часть пути.
Аутентификация
Передайте ваш API-ключ HiAPI как bearer token в заголовке Authorization. Храните его в переменной окружения, чтобы он не попал в историю shell или систему контроля версий:
export HIAPI_API_KEY="your-key-here"
Минимальное тело запроса
curl -sS -X POST "$HIAPI_BASE_URL/v1/images/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedream-4.5/image-to-image",
"prompt": "restyle this photo as a warm studio portrait",
"image": "https://example.com/reference.jpg"
}'
Разбор по полям:
model— буквальный идентификаторseedream-4.5/image-to-image.prompt— что нужно сделать с референсным изображением. Описывайте процесс преобразования, а не только субъект.image— референсный вход. Для одного изображения это одно значение; несколько референсов рассматриваются в следующем разделе.
Чтение первого ответа
Этот вызов возвращает принятую задачу, а не готовое изображение. Захватите идентификатор задачи из тела ответа и сохраните его; он понадобится при опросе. Не считайте статус класса 200 означающим «изображение готово».
Прежде чем писать клиентский код, запустите этот запрос один раз как есть. Тело запроса, которое падает в curl, упадёт и в Python по той же причине, а отлаживать в shell быстрее.
Перенос запроса в Python
Python-версия сохраняет тело запроса побайтно идентичным, заменяя только транспортный уровень и обработку аутентификации. Именно это разделение и важно: если curl работает, Python должен заработать с первой попытки.
import os
import requests
BASE_URL = os.environ["HIAPI_BASE_URL"]
API_KEY = os.environ["HIAPI_API_KEY"]
payload = {
"model": "seedream-4.5/image-to-image",
"prompt": "restyle this photo as a warm studio portrait",
"image": "https://example.com/reference.jpg",
}
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
resp = requests.post(
f"{BASE_URL}/v1/images/generations",
json=payload,
headers=headers,
timeout=30,
)
resp.raise_for_status()
job = resp.json()
print(job["id"])
Следующие замечания сэкономят время в дальнейшем:
- Стройте тело запроса как Python dict, позволяя
json=выполнить сериализацию. Написанные вручную JSON-строки — источник ошибок с кавычками. - Держите построение аутентификации в одной вспомогательной функции. Если формат заголовка изменится, править нужно в одном месте.
- Всегда передавайте явный
timeoutи в вызове отправки. Зависание сокета на этапе отправки неотличимо от медленной модели. - Сразу сохраняйте возвращённый идентификатор задачи, а не выводите его заново из логов.
Код опроса в последующих разделах использует те же BASE_URL, API_KEY и headers, поэтому разместите их в области модуля или в небольшом клиентском классе.
Передача нескольких референсных изображений
Ввод нескольких референсов — самое частое место ошибок в запросах image-to-image, обычно потому, что модель получает три изображения, а промпт описывает только одно из них.
Явная организация входов
Поместите референсные изображения списком в то же поле image, в нужном вам порядке, и пусть промпт указывает роль каждой позиции:
payload = {
"model": "seedream-4.5/image-to-image",
"prompt": (
"Use the first reference for the subject's pose, "
"the second for the background setting, "
"and the third for color grading. Keep the subject sharp."
),
"image": [
"https://example.com/pose.jpg",
"https://example.com/background.jpg",
"https://example.com/grading.jpg",
],
}
Почему аннотация лучше позиции
Порядок списка — это соглашение, но именно промпт сообщает модели, как интерпретировать этот порядок. Пустой массив с расплывчатым промптом вынуждает модель угадывать, какой референс имеет приоритет при конфликте. Указание роли каждого изображения в промпте превращает неявные предположения о позиции в явные инструкции.
Практические правила:
- Держите число референсов небольшим и каждый — с чёткой целью. Лишние референсы размывают, а не обогащают результат.
- Указывайте разрешение конфликтов: если референс позы и референс фона расходятся в кадрировании, укажите, какой из них главный.
- Используйте стабильные публично доступные URL или эквивалентный механизм загрузки. Референс, возвращающий 404 посреди задачи, приведёт к провалу всего запроса.
Если результат игнорирует какой-то референс, обычное решение — не повторный вызов модели, а более ясное предложение в промпте, указывающее роль этого изображения.
Обработка жизненного цикла асинхронной задачи
Генерация изображений требует времени, поэтому эндпоинт построен на задачах. Рассматривайте жизненный цикл как четыре отдельных шага и пишите код для каждого.
1. Отправка
Отправьте показанный выше POST. Прежде чем делать что-либо ещё, сохраните идентификатор задачи из ответа.
2. Опрос
С теми же заголовками аутентификации выполняйте GET-запросы к маршруту задачи, пока статус не станет терминальным:
import time
def poll_job(job_id, interval=2.0, max_interval=30.0, deadline=300.0):
start = time.monotonic()
while True:
r = requests.get(
f"{BASE_URL}/v1/images/generations/{job_id}",
headers=headers,
timeout=30,
)
r.raise_for_status()
data = r.json()
status = data["status"]
if status in ("succeeded", "failed"):
return data
if time.monotonic() - start > deadline:
raise TimeoutError(f"job {job_id} not finished within {deadline}s")
time.sleep(interval)
interval = min(interval * 2, max_interval)
3. Определение терминального состояния
Цикл завершают только два исхода: успех или неудача. Всё остальное означает продолжать ожидание. Никогда не предполагайте, что результат появится мгновенно, и никогда не задавайте фиксированное число опросов без реального предельного срока.
4. Получение результата
Рассматривается в следующем разделе.
Backoff важен. Плотный цикл sleep(0.1) тратит ваш лимит запросов на проверки статуса. Начав примерно с двух секунд и удваивая до上限, можно сохранить низкую задержку, не перегружая API.
Получение и хранение результата
Когда опрос возвращает успешный статус, ответ содержит ссылку на результат. Возвращается указатель на сгенерированное изображение, не обязательно сами байты.
Осознанная загрузка
data = poll_job(job_id)
url = data["output"][0]["url"] if isinstance(data["output"], list) else data["output"]
with requests.get(url, stream=True, timeout=60) as r:
r.raise_for_status()
with open(f"{job_id}.png", "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
Настраивайте путь по фактической структуре ответа, наблюдаемой у первой реальной задачи, а не предполагайте фиксированную схему.
Правила хранения, предотвращающие переделки
- Называйте файлы по идентификатору задачи. Он уникален, отслеживаем и связывает артефакт с породившим его запросом.
- Загружайте promptly. Ссылки на результаты могут иметь срок действия, поэтому сохраняйте сразу после успешного опроса, а не кэшируйте URL на потом.
- Потоково обрабатывайте большие файлы, а не читайте их целиком в память.
- Записывайте промпт и список референсов вместе с файлом. Когда результат неожиданный, входные данные — это журнал отладки.
Если вам нужны детерминированные повторы, сохранение идентификатора задачи означает, что вы можете повторно опросить или повторно загрузить результат без оплаты второй генерации.
Ошибки, повторы и контроль затрат
Большинство сбоев относятся к одной из трёх категорий, и каждая требует своего подхода.
Клиентские ошибки
Некорректное тело запроса, отсутствие model, недоступный URL референса или неверный ключ. Эти ошибки возвращаются сразу и будут возвращаться при повторе. Исправьте запрос; не повторяйте в цикле. Проверяйте, что URL референсов разрешаются, перед отправкой.
Временные серверные и сетевые ошибки
Таймауты, сбросы соединения, ответы об ограничении частоты. Их стоит повторять с экспоненциальным backoff и jitter, ограничивая небольшим максимальным числом попыток. Повторяйте конкретный шаг — отправку, опрос или загрузку — а не весь конвейер. Повторная отправка после успешной отправки — именно так возникают неожиданные двойные списания.
Ошибки уровня задачи
Задача переходит в терминальное состояние неудачи. Повтор с тем же идентификатором задачи не поможет. Явно решите, повторно ли отправлять с изменённым промптом или набором референсов, и фиксируйте причину сбоя, чтобы отличать ошибки входных данных от временных сбоев.
def with_retries(fn, attempts=4, base=1.0):
for i in range(attempts):
try:
return fn()
except requests.RequestException:
if i == attempts - 1:
raise
time.sleep(base * (2 ** i))
Контроль затрат
Оплата привязана к генерации, поэтому дорогостоящая ошибка — это повторная отправка. Устанавливайте реальный предельный срок для опроса, делайте отправку идемпотентной за счёт сохранения идентификатора задачи перед опросом и ограничивайте параллелизм, чтобы шторм повторов не превратился в десятки оплачиваемых задач. Записывайте каждую отправку и её идентификатор задачи; этот журнал — ваш аудиторский след расходов.
Подключите эти три аспекта к клиенту один раз, и один и тот же код будет обрабатывать запросы с одним и несколькими референсами без изменений.
Похожие статьи
Все статьи →-
Руководство
Как вызвать 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
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата