HiAPI
Блог

Руководство

Как вызвать flux-2-klein-4b/text-to-image через HiAPI API: curl, Python и рабочий запрос

Практическое руководство по подключению экономичного уровня генерации изображений к вашему пайплайну

Oct 31, 2026
平面玻璃风格封面图:数层半透明玻璃斜向叠压,把浅灰底场折射成冷蓝色带,构图安静克制。

Почему flux-2-klein-4b/text-to-image подходит для задач, чувствительных к стоимости

Не каждому пайплайну изображений нужна самая тяжёлая модель в каталоге. Значительная часть трафика в продакшене повторяема: товарные изображения, превью вариантов, миниатюры для листингов, социальные карточки, созданные по одному шаблону. Для этих сценариев flux-2-klein-4b/text-to-image задуман как намеренно более лёгкий уровень: вы обмениваете немного максимальной точности на пропускную способность и предсказуемость, и при плановой генерации тысяч материалов партиями это обычно правильный компромисс.

Два типа задач выигрывают больше всего:

  • Изображения товаров для электронной коммерции. Обычно у вас есть чистое базовое описание («матовая керамическая кружка, 350 мл, тёплый серый, на бесшовном белом фоне»), и вам нужно создать множество вариантов рендеринга, покрывающих цвета, ракурсы и композицию. Согласованность важнее художественной выразительности.
  • Пакетная генерация для внутренних или длиннохвостых интерфейсов. Баннеры категорий, креативы для A/B-тестов, заглушки для черновых листингов — здесь предельное улучшение качества не оправдывает более высокую стоимость запуска.

Выбирайте более тяжёлый уровень, когда вы создаёте ключевые визуальные образы, тонкие текстуры и когда сама композиция является продуктом. Выбирайте flux-2-klein-4b/text-to-image, когда решение определяется объёмом генерации, задержкой и стоимостью одного изображения. Оставшаяся часть руководства использует этот уровень от начала до конца: структура запроса, вызов через curl, функция-помощник на Python, стратегия соотношений сторон и жизненный цикл асинхронных задач.

Подготовка перед отправкой запроса

Перед первым вызовом нужно определить три вещи.

1. API-ключ от HiAPI

Создайте ключ в консоли HiAPI. Каждый описанный здесь запрос аутентифицируется этим ключом, и ключ — единственные учётные данные, которые вам нужны: отдельной регистрации для каждой модели нет.

2. Держите ключ вне системы контроля версий

Относитесь к ключу как к любому другому секрету. Один из проверенных подходов:

export HIAPI_API_KEY="your-key-here"

Затем читайте его из окружения в shell и Python. Никогда не коммитьте его, а если вы используете загрузчик dotfile, добавьте .env в .gitignore. Если ключ утёк, смените его в консоли, а не пытайтесь вычистить историю.

3. Подтвердите идентификатор модели

Строка идентификатора используется как есть в теле запроса, а в некоторых конфигурациях — и в URL:

flux-2-klein-4b/text-to-image

Копируйте точно: и 4b, и суффикс /text-to-image являются частью имени. Опечатка здесь — самая частая причина ошибок 404 или «unknown model». Как только в окружении есть ключ и подтверждён идентификатор, можно собирать полезную нагрузку.

Из чего состоит запрос flux-2-klein-4b/text-to-image

Запросы генерации изображений из текста в HiAPI намеренно минималистичны. Вы передаёте идентификатор модели и набор параметров генерации; в ответ возвращается либо результат, либо идентификатор задачи — в зависимости от того, как настроена конечная точка этой модели.

Самые важные поля

  • model — точный идентификатор, flux-2-klein-4b/text-to-image.
  • prompt — строка, описывающая изображение. Это поле сильнее всего влияет на качество результата; сосредоточьте усилия здесь, прежде чем менять что-либо ещё.
  • Размер или соотношение сторон — как вы задаёте кадрирование результата. Предпочитайте задание соотношения сторон, а не жёстко закодированные пары пикселей, потому что это остаётся стабильным, даже если поведение базового разрешения изменится.

Как выглядит ответ

Ответ бывает двух видов, и ваш клиент должен обрабатывать оба:

  1. Синхронная нагрузка — ответ напрямую содержит расположение сгенерированного изображения (URL).
  2. Асинхронная нагрузка задачи — ответ содержит идентификатор задачи и статус (pending, processing, succeeded, failed — типичные статусы). Затем вы опрашиваете конечную точку статуса с этим идентификатором, пока она не достигнет терминального состояния, а нагрузка не будет содержать расположение результата.

Не изобретайте параметры, которые не можете проверить. Если поле не входит в документированный запрос этой модели, не включайте его: неизвестные поля — вторая по частоте причина запутанных ошибок 400. Начните с model, prompt и соотношения сторон, получите рабочее изображение, затем добавляйте необязательные параметры по одному и проверяйте результат после каждого изменения.

Ваш первый рабочий вызов curl

Ниже — полный запрос, который можно вставить в терминал. Он предполагает, что HIAPI_API_KEY экспортирован, как описано выше.

curl -sS -X POST "https://api.hiapi.ai/v1/images/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-2-klein-4b/text-to-image",
    "prompt": "Studio product photo of a matte ceramic mug, warm grey, soft diffused light, seamless white background, centered composition",
    "aspect_ratio": "1:1"
  }'

Пропустите его через форматировщик JSON (| jq .), чтобы прочитать ответ. Вы увидите либо прямой URL изображения, либо объект задачи с id и status.

Интерпретация результата

  • Если вы получили URL изображения, откройте его в браузере. Это подтверждает, что ключ, идентификатор модели и промпт работают корректно.
  • Если вы получили объект задачи, запишите id — его вы будете опрашивать в последующих разделах.

Диагностика типичных сбоев

  • 401 / 403 — ключ отсутствует, имеет неверный формат или не передан через заголовок Authorization: Bearer. Проверьте, что переменная окружения действительно экспортирована в shell, где выполняется curl.
  • 404 или «unknown model» — неверный идентификатор. Он должен быть точно flux-2-klein-4b/text-to-image.
  • 400 с сообщением валидации — обычно отсутствует prompt, указано неподдерживаемое имя параметра или соотношение сторон не из допустимого набора. Сократите нагрузку до трёх основных полей и повторите попытку.
  • 429 — вы отправляете запросы быстрее, чем позволяет ваш уровень. Добавьте задержку с экспоненциальным ростом, а не повторяйте в плотном цикле.

Когда curl работает, у вас есть заведомо рабочий запрос, с которым можно сверять версию на Python, если что-то пойдёт не так.

Перенос того же запроса в Python

Версия на Python — тонкая обёртка вокруг той же нагрузки. Оформите её как функцию, чтобы остальная часть пайплайна могла вызывать её без дублирования HTTP-логики.

import os
import time
import requests

API_BASE = "https://api.hiapi.ai/v1"
MODEL = "flux-2-klein-4b/text-to-image"

def generate_image(prompt: str, aspect_ratio: str = "1:1") -> dict:
    """Submit a text-to-image job and return the parsed response."""
    api_key = os.environ["HIAPI_API_KEY"]
    payload = {
        "model": MODEL,
        "prompt": prompt,
        "aspect_ratio": aspect_ratio,
    }
    response = requests.post(
        f"{API_BASE}/images/generations",
        headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        },
        json=payload,
        timeout=60,
    )
    if response.status_code >= 400:
        # Surface the server's message rather than a bare status code.
        raise RuntimeError(f"HiAPI error {response.status_code}: {response.text}")
    return response.json()

Несколько привычек, которые сразу приносят плоды:

  • Читайте ключ из окружения внутри функции, а не при импорте, чтобы один и тот же модуль работал в notebook, скриптах и плановых задачах.
  • Явно проверяйте код состояния и включайте тело ответа в исключение. Сообщения валидации HiAPI скажут, какое поле неверно; голый raise_for_status() это скрывает.
  • Задавайте тайм-аут. Без тайм-аута зависшее соединение может бесконечно подвешивать рабочий процесс.
  • Держите нагрузку как dict, чтобы вы могли её логировать, сравнивать и расширять необязательными параметрами без переписывания форматирования строк.

Теперь минимальный драйвер:

result = generate_image(
    "Studio product photo of a matte ceramic mug, warm grey, "
    "soft diffused light, seamless white background, centered composition"
)
print(result)

Выбор соотношений сторон, выдерживающих проверку продакшеном

Соотношение сторон — параметр, который чаще всего вызывает переделки позже, потому что нижестоящие системы предполагают определённое кадрирование. Решайте для каждого интерфейса, а не для каждого запроса.

Практическое соответствие

  • Квадрат (1:1) — листинги маркетплейсов, сетки товаров, аватары и места для миниатюр. Это безопасное значение по умолчанию для электронной коммерции, потому что большинство плиток товаров квадратные, а обрезка выглядит плохо.
  • Портрет (3:4 или 4:5) — места в социальных лентах и товарные изображения в стиле лукбука. Даёт пространство для вертикальных товаров, таких как бутылки и одежда, без добавления чёрных полос.
  • Альбом (16:9) — баннеры, полосы ключевых визуалов, заголовки писем, миниатюры видео.

Почему стоит закреплять соотношение выше по потоку

Если соотношение выбирается на этапе рендеринга кодом, который случайно вызывает API, вы получите каталог, где половина плиток квадратные, а половина — портретные, и вам придётся заплатить за повторную генерацию, чтобы это исправить. Вместо этого закодируйте соотношение в своей модели контента — поле surface или placement, которое детерминированно отображается в соотношение, — и генерируйте из этого поля. Используйте 1:1 для мест, где обрезка допустима; для мест с фиксированной вёрсткой используйте соотношение, которое требует вёрстка.

Та же дисциплина применима и к промптам: включайте указания по кадрированию («центрированная композиция», «полный товар в кадре», «пустое место слева для текста») в шаблон промпта, а не в одноразовые строки для каждого вызова. Шаблоны заставляют тысячу сгенерированных изображений выглядеть так, будто они вышли из одного пайплайна, а именно это и нужно товарному каталогу.

Одно замечание: не каждая модель принимает каждое соотношение. Отправьте выбранное соотношение один раз, убедитесь в успехе и только затем раскатывайте на всю партию.

Опрос асинхронных задач до завершения

Когда flux-2-klein-4b/text-to-image возвращает идентификатор задачи, а не изображение, рассматривайте это как машину состояний. Поток такой: отправить → получить ID задачи → опрашивать статус → терминальное состояние → прочитать результат.

def wait_for_job(job_id: str, timeout_s: int = 300, interval_s: int = 2) -> dict:
    api_key = os.environ["HIAPI_API_KEY"]
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        response = requests.get(
            f"{API_BASE}/jobs/{job_id}",
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=30,
        )
        response.raise_for_status()
        job = response.json()
        status = job.get("status")
        if status == "succeeded":
            return job
        if status == "failed":
            raise RuntimeError(f"Job {job_id} failed: {job.get('error')}")
        time.sleep(interval_s)
    raise TimeoutError(f"Job {job_id} did not finish in {timeout_s}s")

Обработка каждого состояния

  • pending / processing — продолжайте ждать. Начните с короткого интервала и рассмотрите мягкую задержку с ростом (например, увеличивайте паузу до верхнего предела), чтобы не забрасывать конечную точку статуса запросами во время длинных очередей.
  • succeeded — нагрузка теперь содержит расположение результата. Немедленно прекратите опрос.
  • failed — не повторяйте слепо. Запишите сообщение об ошибке; если проблема в промпте или параметрах, повторная отправка того же запроса приведёт к тому же сбою.

Знайте, когда остановиться

Всегда ограничивайте цикл дедлайном по настенным часам. Рабочий процесс, который опрашивает вечно, — это утёкший процесс. При тайм-ауте раскройте ID задачи для ручной проверки: если задача позже завершится успешно, вы всё ещё сможете получить результат. Для партий запускайте несколько задач параллельно и опрашивайте их вместе, а не сериализуйте отправку и ожидание для каждого изображения.

Скачивание и хранение результатов

Сгенерированные изображения появляются в задаче или ответе генерации в виде доступного для получения расположения. Загружайте его на стороне сервера и сохраняйте самостоятельно — не встраивайте возвращённый URL напрямую в страницы товаров, потому что это артефакт доставки, а не ваш слой хранения.

def download_image(url: str, path: str) -> str:
    response = requests.get(url, timeout=120)
    response.raise_for_status()
    with open(path, "wb") as f:
        f.write(response.content)
    return path

Используйте предсказуемую схему именования

Путь вроде images/{surface}/{sku}/{variant}-{ratio}.png даёт вам три вещи: материалы естественно группируются по продукту, интерфейс говорит, какое кадрирование было запрошено, а соотношение в имени файла делает случайные дубликаты очевидными. Если вы перегенерируете вариант того же SKU, включите в имя файла короткий хэш промпта: так повторный запуск не перезапишет молча предыдущую попытку, которую вы, возможно, захотите сравнить.

Замыкание цикла

Записывайте ID задачи вместе с сохранённым файлом — в манифесте, строке базы данных или сопутствующем файле. Когда нижестоящая система сообщает о плохом изображении, именно ID задачи позволяет вам получить исходный промпт и параметры. В сочетании с именами файлов, основанными на содержимом, это даёт вам воспроизводимый аудиторский след от сохранённого материала обратно к точному запросу, который его произвёл.

Когда отправка, опрос и скачивание соединены вместе, flux-2-klein-4b/text-to-image становится обычным шагом в вашем пайплайне: поставьте работу в очередь, опрашивайте с дедлайном, сохраняйте под стабильным именем. С этого момента масштабирование — вопрос параллелизма и шаблонов, а не нового кода.

Похожие статьи

Все статьи →

Начните работать с постоянными артефактами ИИ

Получите API-ключ и вызывайте модели изображений, видео и аудио через один API на основе tasks.

Читать документацию API