HiAPI
Блог

Руководство

Как вызывать flux-1-kontext-max в HiAPI: руководство по curl и Python

Полный цикл рабочего запроса: ввод, асинхронный опрос и скачивание результата

Oct 31, 2026
hiapi.ai 博客封面图:深咖啡底色上交织的燕麦色与黄铜色宽织带,呈扁平编织图解式几何图案。

Как выглядит запрос к flux-1-kontext-max

Прежде чем писать код, полезно понять форму взаимодействия. Вызов редактирования изображения для flux-1-kontext-max в HiAPI — это не простой запрос/ответ, возвращающий картинку в том же HTTP-вызове. Это двухэтапная задача:

  1. Отправка — вы POST-ите JSON-полезную нагрузку, описывающую входное изображение и желаемое редактирование. API принимает задачу и возвращает идентификатор задачи.
  2. Опрос — вы GET-ите статус задачи по этому идентификатору, пока она не сообщит о завершении, а затем читаете URL результата из ответа.

Эта схема выбрана потому, что редактирование изображений требует больших вычислений. Держать одно HTTP-соединение открытым на протяжении всего рендеринга хрупко; дескриптор задачи позволяет отключаться, повторять попытки и возвращаться позже.

Сама полезная нагрузка концептуально делится на три части:

  • Селектор модели — поле, указывающее flux-1-kontext-max как модель для запуска.
  • Вход — обычно изображение (URL или base64-полезная нагрузка, в зависимости от документированной схемы) плюс текстовая инструкция, описывающая редактирование.
  • Необязательные параметры управления — параметры, настраивающие поведение генерации, например соотношение сторон или seed, если они описаны в документации модели.

Всё остальное — заголовки аутентификации, эндпоинт отправки, эндпоинт статуса — совпадает с конвейером, который вы используете в каждой задаче HiAPI. Как только вы усвоите этот трёхшаговый ритм (отправка → опрос → скачивание), версии на curl и Python станут взаимозаменяемыми, и вы сможете переключаться между ними без повторного изучения процесса.

Предварительные требования и аутентификация

Прежде чем первый запрос завершится успешно, нужно подготовить несколько вещей.

Что вам понадобится

  • Аккаунт HiAPI и API key, созданный в панели управления.
  • Базовый URL API HiAPI, как указано в документации платформы.
  • Исходное изображение, доступное API — чаще всего публичный HTTPS URL. Если ваше изображение приватное, загрузите его туда, откуда API сможет его получить, или передайте его inline, если схема модели поддерживает ввод base64.
  • curl для упражнений в shell и Python 3 с библиотекой requests для упражнений в коде.

Аутентификация

HiAPI аутентифицирует запросы, отправляя ваш API key в заголовке авторизации. Соглашение — bearer token:

Authorization: Bearer $HIAPI_API_KEY

И каждый JSON-запрос должен объявлять свой тип содержимого:

Content-Type: application/json

Держите ключ подальше от исходного кода

Храните ключ в переменной окружения, а не вставляйте его в скрипт:

export HIAPI_API_KEY="your_key_here"

В Python читайте его через os.environ["HIAPI_API_KEY"]. В curl ссылайтесь на него как $HIAPI_API_KEY. Эта одна привычка предотвращает самую распространённую причину утечки учётных данных — ключ попадает в репозиторий, а затем под давлением его приходится ротировать.

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

Отправка запроса с помощью curl

Ниже приведён вызов отправки. Замените URL изображения и инструкцию редактирования на свои.

curl -X POST "$HIAPI_BASE_URL/jobs" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-1-kontext-max",
    "input": {
      "image": "https://example.com/input.jpg",
      "prompt": "Replace the sky with a dramatic sunset, keep the buildings unchanged"
    }
  }'

Что делает каждая часть

  • -X POST — отправка является операцией создания, поэтому используется POST.
  • Эндпоинт — эндпоинт jobs принимает новые задачи. Базовый URL берётся из вашего окружения, поэтому команда переносима между средами.
  • Authorization — ваш bearer token, считываемый из переменной окружения, а не inline.
  • Content-Type: application/json — обязателен; без него сервер может отклонить или неправильно разобрать тело запроса.
  • -d — JSON-полезная нагрузка. model выбирает flux-1-kontext-max, input.image указывает на исходное изображение, input.prompt описывает редактирование.

Чтение ответа

Успешная отправка возвращает JSON-тело, содержащее идентификатор задачи — обычно такое поле, как id или job_id — и статус, указывающий, что задача поставлена в очередь или обрабатывается. Сохраните этот идентификатор; опрос зависит от него.

curl -s -X POST "$HIAPI_BASE_URL/jobs" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json | python -m json.tool

Передача вывода через python -m json.tool красиво форматирует ответ, делая ID задачи легко обнаружимым. Размещение тела запроса в payload.json позволяет команде оставаться читаемой по мере роста промпта.

На этом этапе вы отправили задачу, но ещё не получили изображение. Изображение возвращается только после опроса.

Тот же запрос на Python

Версия на Python несёт ту же логику и предлагает более удобную эргономику для всего, что вы планируете сохранять надолго.

import os
import requests

BASE_URL = os.environ["HIAPI_BASE_URL"]
API_KEY = os.environ["HIAPI_API_KEY"]

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

payload = {
    "model": "flux-1-kontext-max",
    "input": {
        "image": "https://example.com/input.jpg",
        "prompt": "Replace the sky with a dramatic sunset, keep the buildings unchanged",
    },
}

response = requests.post(
    f"{BASE_URL}/jobs",
    headers=headers,
    json=payload,
    timeout=30,
)
response.raise_for_status()
job = response.json()
print("job id:", job["id"])

Почему это зеркально повторяет вызов curl

Параметр json=payload сериализует словарь и задаёт тип содержимого за вас — отправляются те же байты, что и в curl. timeout=30 ограничивает запрос отправки, так что зависшее соединение громко завершается ошибкой, а не сковывает ваш процесс. raise_for_status() превращает 4xx или 5xx в исключение, которое вы можете перехватить, а не молча возвращает документ ошибки.

Важные небольшие различия

  • Словарь вместо строки — вы строите полезную нагрузку как объект Python, что упрощает вычисление промптов или подстановку переменных.
  • Обработка исключений — оберните вызов в try/except requests.HTTPError, чтобы записать тело ответа; полезные нагрузки ошибок обычно объясняют, что не так со входными данными.
  • Не нужно экранирование shell — длинные промпты с кавычками больше не требуют экранирования, что устраняет целый класс ошибок.

ID задачи, возвращённый здесь, напрямую переходит в шаг опроса ниже. Задача ничуть не меняется от того, что она отправлена из Python, а не из curl.

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

Отправка возвращается быстро; рендеринг — нет. Вы ждёте, опрашивая эндпоинт статуса по ID задачи.

Цикл опроса

import time

def wait_for_job(job_id, headers, interval=3, max_attempts=100):
    url = f"{BASE_URL}/jobs/{job_id}"
    for attempt in range(max_attempts):
        r = requests.get(url, headers=headers, timeout=30)
        r.raise_for_status()
        data = r.json()
        status = data.get("status")
        if status == "succeeded" or status == "completed":
            return data
        if status == "failed" or status == "error":
            raise RuntimeError(f"Job failed: {data}")
        time.sleep(interval)
    raise TimeoutError(f"Job {job_id} did not finish in time")

Интерпретация статусов задачи

Ожидайте небольшой словарь: состояние queued/pending до начала работы, состояние processing/running во время рендеринга моделью и терминальное состояние — успех или неудача. Некоторые API используют немного другое написание; проверяйте фактический ответ и сопоставляйте эти строки, не предполагайте. Ключевое правило: считайте задачу завершённой только тогда, когда статус является терминальным успешным и присутствует URL результата. Ответ 200 от эндпоинта статуса не означает, что изображение готово.

Этикет опроса

  • Делайте интервалы между запросами. Для задач с изображениями достаточно нескольких секунд между опросами. Опрос каждые 100 мс тратит лимиты скорости без всякой пользы.
  • Ограничивайте время ожидания. max_attempts ограничивает цикл, так что зависшая задача заставляет ваш код завершиться ошибкой, а не висеть вечно.
  • Отступайте при 429. Если вы достигли лимита скорости, поспите дольше перед повторной попыткой, а не долбите.
  • Предпочитайте webhook, если он доступен. Если в документации платформы описан механизм обратного вызова, он полностью устраняет опрос и лучше масштабируется.

Для тестирования в shell быстрый цикл работает так же:

JOB_ID="your_job_id"
while true; do
  BODY=$(curl -s "$HIAPI_BASE_URL/jobs/$JOB_ID" -H "Authorization: Bearer $HIAPI_API_KEY")
  echo "$BODY"
  echo "$BODY" | grep -q '"succeeded"' && break
  sleep 3
done

Как только вы выйдете из цикла, терминальный ответ содержит ссылку на результат. Это следующий шаг.

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

Ответ завершённой задачи указывает на отрендеренное изображение, обычно это URL (иногда список). Получите его вторым запросом и запишите байты на диск.

import pathlib

def download_output(job_data, path="edit.png"):
    out = job_data.get("output")
    if isinstance(out, list):
        out = out[0]
    url = out["url"] if isinstance(out, dict) else out

    r = requests.get(url, timeout=60)
    r.raise_for_status()
    pathlib.Path(path).write_bytes(r.content)
    return path

На что обратить внимание

  • Не жёстко кодируйте форму. Поле вывода различается от модели к модели — иногда это строковый URL, иногда объект с ключом url, иногда список. Проверяйте реальный ответ и нормализуйте его перед скачиванием.
  • URL результата может истечь. Относитесь к URL как к короткоживущему: скачивайте сразу или немедленно копируйте в собственное хранилище. Не храните URL как постоянную запись изображения.
  • Проверяйте байты. Убедитесь, что Content-Type начинается с image/, а размер файла разумен; страница ошибки, сохранённая как .png, — это тихий сбой.
  • Повторяйте при временных ошибках скачивания. Оберните GET в повтор с небольшим отступом — подписанные URL иногда возвращают 403 из-за дрейфа часов, а сеть тоже дрожит.

Для быстрой ручной проверки достаточно curl:

curl -L -o edit.png "$OUTPUT_URL"

Флаг -L следует за перенаправлениями, которые часто используются для результатов на CDN. После того как файл сохранён на диск, откройте его и убедитесь, что редактирование действительно соответствует промпту — это ваша сквозная проверка, и в конвейерах, где изображение приходится перегенерировать при сбое, стоит автоматизировать визуальную проверку или проверку хеша.

Распространённые точки отказа и исправления

Большинство сбоев при первой интеграции происходит одним из нескольких способов.

Аутентификация и заголовки

  • 401/403 — ключ неверный, истёк или содержит лишние пробелы. Повторно экспортируйте переменную окружения и убедитесь, что форма заголовка совпадает с документацией.
  • Отсутствует Content-Type — отправка JSON без этого заголовка может вызвать запутанную ошибку 4xx. Включите его или используйте json= в Python.

Проблемы с вводом

  • Изображение недоступно — API получает ваше изображение на стороне сервера. URL localhost или ссылки, требующие аутентификации, не сработают. Используйте публичный HTTPS URL или inline base64, если это поддерживается.
  • Промпт игнорируется или отклоняется — расплывчатые инструкции дают расплывчатые результаты. Описывайте, что изменить и что сохранить, как в примере с закатом. Очень длинные промпты могут быть усечены.
  • Неподдерживаемые параметры — передача полей, которые не принимает модель, может вызвать ошибку валидации. Начните с минимальной полезной нагрузки, затем добавляйте документированные параметры управления по одному.

Ошибки асинхронной обработки

  • Чтение изображения из ответа на отправку — вызов отправки возвращает дескриптор задачи, а не пиксели. Сначала опрашивайте.
  • Считать любой 200 завершением — эндпоинт статуса также возвращает 200 для задач, которые ещё выполняются. Проверяйте поле статуса и наличие URL результата.
  • Опрос слишком частый или бесконечный — добавьте интервал и верхний предел, иначе вы исчерпаете лимиты скорости и подвесите свой worker.

Проблемы со скачиванием

  • Сохранение HTML как изображения — всегда проверяйте тип содержимого и размер.
  • URL результата истёк — скачивайте сразу после завершения; не ставьте URL в очередь на потом.

Структурные ошибки

  • Несовпадение ID задач — если вы отправляете несколько задач, помечайте каждый ID собственным ID запроса, чтобы результаты опроса не перепутались.
  • Нет таймаутов — у каждого запроса должен быть таймаут. Без него зависший вызов может затормозить целый пакет.

Превращение упражнения в переиспользуемую вспомогательную функцию

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

def edit_image(image_url, prompt, model="flux-1-kontext-max",
               headers=None, poll_interval=3, max_attempts=100):
    payload = {"model": model,
               "input": {"image": image_url, "prompt": prompt}}
    r = requests.post(f"{BASE_URL}/jobs", headers=headers,
                      json=payload, timeout=30)
    r.raise_for_status()
    job_id = r.json()["id"]

    data = wait_for_job(job_id, headers,
                        interval=poll_interval,
                        max_attempts=max_attempts)
    return download_output(data, path=f"{job_id}.png")

Что делает её готовой к продакшену

  • Единая точка входа. Вызывающий передаёт изображение и промпт, получает путь к файлу или исключение. Детали рабочего процесса остаются скрытыми.
  • Явные сбои. Каждый запрос выбрасывает исключение при HTTP-ошибке, опросчик выбрасывает при неудаче задачи или таймауте, так что ваша очередь или вызывающий код может повторить попытку.
  • Настраиваемые тайминги. poll_interval и max_attempts являются параметрами, поэтому вы можете ослабить их для более тяжёлых редактирований, не трогая логику.
  • Предсказуемое именование результатов. Использование ID задачи в качестве имени файла упрощает сопоставление файлов с логами.

Куда двигаться дальше

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

Страница flux-1-kontext-max в документации HiAPI — это справочник по принимаемым полям и текущим параметрам. Держите вспомогательную функцию минимальной, позволяйте документации управлять схемой, и одна и та же функция охватит как исследовательские скрипты, так и реальные конвейеры.

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

Все статьи →

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

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

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