Руководство
Как вызывать Imagen 4 API через HiAPI: примеры на curl и Python
Что даёт вам эндпоинт Imagen 4
Если у вас уже есть промпт и вы хотите получить изображение, не регистрируя платёжный аккаунт, не поднимая очередь и не создавая бакет у провайдера, которым вы никогда не пользовались, то модель Google-Imagen4 на HiAPI — разумная отправная точка. Вы отправляете текстовый промпт на единственный HTTP-эндпоинт, проходите аутентификацию одним API-ключом и получаете ссылку на сгенерированное изображение (или задачу, статус которой можно опрашивать). Всё остальное — хостинг модели, ёмкость, повторы на стороне провайдера — скрыто за абстракцией.
Вызовы генерации изображений по тексту через этот эндпоинт покрывают три вещи, которые реально важны на практике:
- От промпта к изображению. Промпт — основной вход. В зависимости от того, как вы настроите запрос, модель вернёт одно или несколько изображений.
- Управление формой вывода. Соотношение сторон (квадратное, горизонтальное, вертикальное) задаётся при запросе, а не обрезкой постфактум. Это важнее, чем кажется: обрезка готового изображения уничтожает композицию, которую модель уже спланировала.
- Асинхронное выполнение. Долгие генерации обрабатываются как задачи. Вы отправляете запрос, опрашиваете статус и забираете результат. Короткие вызовы могут возвращаться быстро, но клиент стоит писать так, будто каждый вызов асинхронный, — именно такой поток выдерживает продакшн-нагрузку.
Остальная часть руководства строит один и тот же запрос тремя способами: сырой вызов curl, который можно вставить прямо в терминал, эквивалентный клиент на Python, а затем все части, которые нужны при работе с соотношением сторон, опросом, сохранением и обработкой ошибок. Если вы хотите генерировать изображение одной командой в оболочке — это подойдёт. Если нужен тонкий контроль над масками inpainting или циклом обучения — возможно, нет.
Перед началом два условия: у вас есть API-ключ HiAPI, а среда, где выполняется код, может делать исходящие HTTPS-запросы. Больше ничего не требуется — установка SDK не обязательна, хотя в примере на Python ниже используется requests.
Первый запрос через curl
Самый быстрый способ убедиться, что ключ работает, — один вызов curl. Эндпоинт принимает JSON в теле запроса, поэтому нужны два заголовка: Content-Type для тела и Authorization для ключа. Читайте ключ из переменной окружения, а не вставляйте его прямо в команду, чтобы он не остался в истории вашей оболочки.
export HIAPI_API_KEY="your-key-here"
curl -sS -X POST "https://api.hiapi.ai/v1/images/generations" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-d '{
"model": "google-imagen-4",
"prompt": "a weathered lighthouse on a basalt cliff, morning fog, wide shot",
"n": 1,
"aspect_ratio": "16:9"
}'
В этом теле запроса есть несколько моментов, на которые стоит обратить внимание:
modelвыбирает Google-Imagen4. Указывайте его явно, даже если у сервиса есть значение по умолчанию, — так ваш код останется читаемым и через год.prompt— единственный обязательный творческий вход. Пишите его так, как описали бы кадр фотографу: субъект, окружение, свет, кадрирование.nзадаёт число изображений. На этапе настройки структуры ответа начните с одного; увеличивайте, когда начнёте доверять своему конвейеру.aspect_ratioподробно разбирается ниже. Если его опустить, будет использовано значение по умолчанию сервиса.
Успешный ответ возвращает JSON-объект. Вас интересует список записей изображений; каждая запись содержит ссылку для скачивания или URL, который можно передать во фронтенд. Если вы запросили несколько изображений, придёт несколько записей в порядке запроса. Если генерация идёт достаточно долго и попадает в очередь, ответ даст вам идентификатор и статус, который можно опрашивать, — этот процесс описан в отдельном разделе ниже.
При получении 4xx сначала проверьте два заголовка: отсутствие префикса Bearer или пробельные символы в конце ключа — причина большинства провалов при первом вызове. При отладке используйте -i, чтобы увидеть строку статуса и тело ответа с ошибкой.
Тот же запрос на Python
В скрипте оберните вызов в небольшую функцию, чтобы остальной код никогда не касался сырого HTTP. Функция должна принимать промпт и необязательные параметры, собирать тело запроса, отправлять его и возвращать разобранный JSON.
import os
import requests
HIAPI_BASE = "https://api.hiapi.ai/v1"
def generate_image(prompt: str, aspect_ratio: str = "1:1", n: int = 1) -> dict:
response = requests.post(
f"{HIAPI_BASE}/images/generations",
headers={
"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
"Content-Type": "application/json",
},
json={
"model": "google-imagen-4",
"prompt": prompt,
"n": n,
"aspect_ratio": aspect_ratio,
},
timeout=120,
)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
result = generate_image(
"a weathered lighthouse on a basalt cliff, morning fog, wide shot",
aspect_ratio="16:9",
)
print(result)
При адаптации этого кода стоит сохранить три проектных решения:
Явный тайм-аут. У requests нет тайм-аута по умолчанию, а значит, зависшее соединение может подвесить воркер на неопределённый срок. Выберите значение выше самой долгой ожидаемой генерации и дайте ему явно завершаться с ошибкой.
Вызов raise_for_status() до разбора. Ответы с ошибкой не всегда имеют ту же схему, что и успешные. Сначала проверьте HTTP-статус, потом трогайте тело ответа.
Маленькая параметризованная функция. Когда вы добавите опрос и скачивание, эта функция останется единственной точкой входа для отправки, а логика жизненного цикла будет рядом с ней, а не запутана внутри.
Разобранный результат содержит ту же информацию, что и вывод curl. Для синхронного ответа переберите записи изображений и достаньте URL. Для асинхронного достаньте идентификатор задачи и передайте его в функцию опроса. Ваш код должен ветвиться по полученной форме, а не предполагать, что она всегда одна.
Управление соотношением сторон и выводом
Соотношение сторон — параметр, который вы правите чаще всего, и его стоит задавать правильно, а не обрезать потом. Если запросить квадратное изображение и вырезать из него полосу 16:9, вы потеряете верх и низ, которые модель намеренно скомпоновала. Запрос 16:9 заранее позволяет модели спланировать кадр под этот формат.
Передайте его в теле запроса вместе с промптом:
result = generate_image(
"a sprawling night market, neon signs, steam from food stalls",
aspect_ratio="16:9",
n=2,
)
Горизонтальные пропорции — для hero-баннеров, миниатюр широких карточек и продуктовой съёмки; вертикальные — для мобильных карточек, постеров и портретов персонажей; квадратные — для аватаров и постов в соцсетях, где обрезка непредсказуема. Решайте по тому, куда изображение в итоге попадёт, а не по тому, как оно выглядит изолированно.
Что меняется в ответе при смене пропорций: пиксельные размеры возвращаемых изображений. Количество записей, порядок и процесс скачивания остаются прежними, поэтому нижележащему коду не нужно ветвиться по пропорциям. Если ваш UI резервирует место до загрузки изображения, читайте размеры из ответа и задавайте их элементу, а не жёстко кодируйте.
Ещё два регулятора вывода, о которых стоит знать:
- Количество изображений (
n). Больше изображений на запрос — больше выбора, но и больше токенов на промпт, который может быть ошибочным. При итерациях по формулировке промпта запрашивайте одно изображение; запрашивайте пачкой, когда промпт стабилизируется. - Формулировки промпта для кадрирования. Пропорции задают формат; промпт задаёт композицию внутри формата. Слова вроде «wide shot», «close-up» и «centered» работают вместе с параметром пропорций.
Биллинг этого эндпоинта следует за самой генерацией изображения — смотрите актуальные тарифы на панели цен на сайте и не зашивайте ничего в свою модель затрат.
Работа с асинхронными задачами и опросом
Когда генерация идёт достаточно долго и попадает в очередь, эндпоинт возвращает управление до того, как изображение существует. Вы получаете дескриптор задачи, и ваша работа — проверять его, пока он не достигнет терминального состояния. Пишите этот процесс, даже если сегодня вызовы возвращаются быстро: ёмкость, сложность промпта и количество изображений влияют на задержку, а клиент, рассчитанный на синхронный сценарий, упадёт при первом медленном запросе.
Жизненный цикл состоит из трёх шагов:
- Отправка. Отправьте запрос на генерацию как обычно. Если ответ — задача, извлеките её идентификатор.
- Опрос. С фиксированным интервалом вызывайте эндпоинт статуса задачи с этим идентификатором.
- Получение. Как только статус сообщит об успехе, прочитайте ссылки на изображения из полезной нагрузки результата.
import time
def wait_for_job(job_id: str, interval: float = 2.0, max_attempts: int = 60) -> dict:
for attempt in range(max_attempts):
response = requests.get(
f"{HIAPI_BASE}/images/jobs/{job_id}",
headers={"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
payload = response.json()
status = payload.get("status")
if status == "succeeded":
return payload
if status in {"failed", "cancelled"}:
raise RuntimeError(f"job {job_id} ended with status {status}")
time.sleep(interval)
raise TimeoutError(f"job {job_id} did not finish in time")
Ключевые детали, которые делают этот код безопасным в продакшене:
- Ограничивайте попытки, а не зацикливайтесь бесконечно. Задача, которая никогда не завершится, должна проявляться как ошибка тайм-аута, по которой можно сработать алерту, а не как вечно висящий воркер.
max_attemptsумноженное наinterval— ваш реальный бюджет времени; задавайте его исходя из самой долгой реальной генерации. - Экспоненциальная задержка под нагрузкой. Фиксированный двухсекундный интервал нормален для интерактивного использования. Для пакетных нагрузок используйте постепенную задержку или джиттер, чтобы повторы множества воркеров не синхронизировались в одну и ту же секунду.
- Различайте сбой и неизвестность. Только
failedиcancelled— это терминальные сбои. Любой другой не-success статус считайте «всё ещё в обработке» и опрашивайте снова; ветка с немедленным исключением для нераспознанного статуса сломается, когда сервис добавит новый статус. - Повторяйте отправку при сетевых ошибках, а не опрос. Если сам вызов отправки завершился тайм-аутом, повтор может создать дублирующую задачу. Если API поддерживает идемпотентные ключи, давайте каждой отправке идемпотентный ключ; иначе дедуплицируйте на своей стороне по хешу промпта плюс временной метке.
Как только задача сообщает об успехе, прекращайте опрос. Сохранить результат и оставить дескриптор задачи для аудита дешевле, чем продолжать спрашивать о статусе, который вы уже знаете.
Скачивание и хранение изображений
Ответ генерации даёт вам ссылки, а не байты изображений. В большинстве случаев каждая запись изображения содержит URL, который можно получить обычным GET-запросом. Относитесь к этому URL как к временному адресу: скачивайте вовремя, проверяйте и сохраняйте байты туда, что реально контролируете.
import pathlib
import uuid
def download_images(payload: dict, out_dir: str = "images") -> list[pathlib.Path]:
target = pathlib.Path(out_dir)
target.mkdir(parents=True, exist_ok=True)
saved = []
for entry in payload.get("data", []):
url = entry["url"]
resp = requests.get(url, timeout=60)
resp.raise_for_status()
content_type = resp.headers.get("Content-Type", "")
if not content_type.startswith("image/"):
raise ValueError(f"unexpected content type: {content_type}")
path = target / f"{uuid.uuid4().hex}.png"
path.write_bytes(resp.content)
saved.append(path)
return saved
Прежде чем считать задачу завершённой, сделайте несколько проверок:
- Тип контента и размер. В некоторых окружениях редирект на страницу ошибки возвращает 200 и HTML. До записи в постоянное хранилище убедитесь, что
Content-Typeначинается сimage/, а размер тела ответа не ничтожен. - Именование. Генерируйте новое имя для каждого скачивания, а не выводите его из промпта. Промпты повторяются, конфликтуют и содержат символы, которые не принимает файловая система.
- Храните промпт вместе с файлом. Сохраняйте промпт, параметры и идентификатор задачи в своей базе данных или в сопутствующем файле метаданных. Через полгода по одному изображению нельзя понять, какой запрос его породил.
- Переносите в постоянное хранилище, а не копируйте. Сначала пишите во временное место, после проверки переносите в свой бакет или хранилище за CDN. Наполовину записанный файл в постоянном хранилище хуже, чем провалившаяся задача.
Если ваш конвейер порождает много изображений, разделите шаг скачивания и шаг генерации. Генерация — дорогая часть с ограничением частоты; повтор скачивания дешёв и никогда не должен приводить к повторной генерации.
Типичные ошибки и чек-лист отладки
Большинство провалов в первый день попадает в несколько категорий. Проверяйте их в таком порядке — каждая проверка быстрее следующей.
Ошибки аутентификации (401, 403)
Ключ неверен, отсутствует или имеет неверный формат. Убедитесь, что в значении заголовка ровно Bearer плюс ключ, без символов перевода строки от вставки, и что переменная окружения действительно экспортирована в оболочке или процессе, выполняющем код. Ключ, ротированный в панели управления, немедленно делает старый недействительным — если другой сервис только что начал падать, спросите, не ротировал ли кто-то ключ.
Параметр отклонён (400, 422)
Тело запроса не соответствует схеме. Частые причины: опечатка в идентификаторе model, формат строки aspect_ratio, который эндпоинт не принимает, или n вне поддерживаемого диапазона. Напечатайте тело ответа с ошибкой — обычно оно указывает проблемное поле. Сравните ваш JSON с рабочим примером curl, поле за полем.
Тайм-ауты
Легко спутать два разных тайм-аута. Тайм-аут клиента означает, что ваш HTTP-вызов сдался; задача при этом может всё ещё выполняться. Задача, которая никогда не достигает терминального состояния, означает слишком маленький бюджет опроса или то, что запрос действительно провалился. Задайте тайм-аут клиента выше самой долгой ожидаемой генерации, а бюджет опроса — ещё выше. Когда тайм-аут клиента срабатывает во время отправки, слепой повтор может дублировать работу — проверьте, нет ли уже задачи, прежде чем отправлять снова.
Скачивания, которые выглядят успешными, но таковыми не являются
Статус 200 с HTML-телом или файл нулевого размера обычно означает, что URL изображения истёк или что его получают без нужных прав доступа. Скачивайте сразу после успеха задачи и, как описано выше, проверяйте тип контента и размер.
Ограничение частоты (429)
Отступите и повторите, а не затягивайте цикл. Стандартный ответ — экспоненциальная задержка с джиттером; ограничьте число повторов и выведите устойчивые сбои в мониторинг.
Одна привычка отладки, которую стоит завести
Логируйте для каждого запроса четыре вещи: идентификатор модели, полное тело запроса без ключа, идентификатор задачи (или статус ответа для синхронного вызова) и затраченное время. Когда в продакшене что-то ломается, эти четыре поля обычно позволяют меньше чем за минуту понять, проблема в вашем клиенте, в ваших параметрах или в очереди.
Начните с вызова curl, получите одно изображение, затем перенесите логику в клиент на Python и добавьте вокруг него опрос и сохранение. Такой путь держит каждый сбой в узких рамках и позволяет его атрибутировать.
Похожие статьи
Все статьи →-
Руководство
Как вызвать 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
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата