HiAPI
Блог

Руководство

Как использовать gpt-image-2/text-to-image через API hiapi: параметры, код и рабочие примеры

Jun 25, 2026
Как использовать gpt-image-2/text-to-image через API hiapi: параметры, код и рабочие примеры

Этот туториал показывает минимальный объём кода, необходимый для генерации изображения с помощью gpt-image-2/text-to-image через единый API задач hiapi, а затем по очереди объясняет каждый параметр и производственные подходы (обратные вызовы, идемпотентность, обработка ошибок), которые следует применять после того, как код заработает.

Предварительные условия

Вам нужен ключ API. Создайте его на странице ключей API в консоли hiapi — ключ начинается с sk-. На странице модели gpt-image-2/text-to-image указана текущая цена за одно изображение; полная детализация приведена на странице цен.

Все вызовы в этом руководстве направляются на единый асинхронный эндпоинт задач:

  • POST https://api.hiapi.ai/v1/tasks — создание задачи генерации
  • GET https://api.hiapi.ai/v1/tasks/{taskId} — опрос статуса задачи

Общая справочная документация платформы находится в документации API hiapi.

Минимальный рабочий пример (curl)

Одна генерация — это двухшаговое взаимодействие: сначала создайте задачу, затем дождитесь её завершения.

# 1. Create the task
curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2/text-to-image",
    "input": {
      "prompt": "a calico cat curled up on a sunlit windowsill, soft focus background",
      "aspect_ratio": "1:1",
      "resolution": "1K"
    }
  }'
# => {"code":200,"data":{"taskId":"tk-hiapi-01KVY...."},"message":"success"}

# 2. Poll until status == "success"
TASK_ID="tk-hiapi-01KVY...."
curl -s "https://api.hiapi.ai/v1/tasks/$TASK_ID" \
  -H "Authorization: Bearer sk-YOUR_KEY"
# => {"code":200,"data":{"status":"success","output":[{"url":"https://..."}], ...}}

URL изображения находится в data.output[0].url. Скачайте его сразу — output[0].expireAt очень короткий, поэтому этот URL предназначен только для получения, а не для постоянного встраивания.

Python: создание + опрос + сохранение на диск

import os
import time
import urllib.request
import requests  # pip install requests

API_BASE = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"]  # sk-...

def create_task(prompt: str, aspect_ratio: str = "1:1", resolution: str = "1K") -> str:
    payload = {
        "model": "gpt-image-2/text-to-image",
        "input": {
            "prompt": prompt,
            "aspect_ratio": aspect_ratio,
            "resolution": resolution,
        },
    }
    r = requests.post(API_BASE, json=payload,
                      headers={"Authorization": f"Bearer {TOKEN}"},
                      timeout=60)
    r.raise_for_status()
    body = r.json()
    if body.get("error"):
        raise RuntimeError(f"create failed: {body['error']}")
    return body["data"]["taskId"]

def wait_task(task_id: str, timeout_s: int = 600, poll_s: int = 5) -> dict:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(f"{API_BASE}/{task_id}",
                         headers={"Authorization": f"Bearer {TOKEN}"},
                         timeout=30)
        r.raise_for_status()
        task = r.json().get("data") or {}
        status = task.get("status")
        if status == "success":
            return task
        if status == "fail":
            raise RuntimeError(f"task failed: {task.get('error')}")
        time.sleep(poll_s)
    raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")

if __name__ == "__main__":
    task_id = create_task(
        "a calico cat curled up on a sunlit windowsill, soft focus background",
        aspect_ratio="3:2",
        resolution="1K",
    )
    task = wait_task(task_id)
    url = task["output"][0]["url"]
    urllib.request.urlretrieve(url, "cat.png")
    print(f"saved cat.png from task {task_id}")

Node.js: тот же процесс с использованием fetch

// Node 18+ has global fetch
const API_BASE = "https://api.hiapi.ai/v1/tasks";
const TOKEN = process.env.HIAPI_API_KEY;

async function createTask(prompt, aspectRatio = "1:1", resolution = "1K") {
  const res = await fetch(API_BASE, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "gpt-image-2/text-to-image",
      input: { prompt, aspect_ratio: aspectRatio, resolution },
    }),
  });
  const body = await res.json();
  if (body.error) throw new Error(`create failed: ${body.error.code} ${body.error.message}`);
  return body.data.taskId;
}

async function waitTask(taskId, { timeoutMs = 600_000, pollMs = 5_000 } = {}) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const res = await fetch(`${API_BASE}/${taskId}`, {
      headers: { "Authorization": `Bearer ${TOKEN}` },
    });
    const task = (await res.json()).data || {};
    if (task.status === "success") return task;
    if (task.status === "fail") throw new Error(`task failed: ${JSON.stringify(task.error)}`);
    await new Promise(r => setTimeout(r, pollMs));
  }
  throw new Error(`task ${taskId} timed out`);
}

(async () => {
  const id = await createTask(
    "a calico cat curled up on a sunlit windowsill, soft focus background",
    "16:9",
    "1K",
  );
  const task = await waitTask(id);
  const url = task.output[0].url;
  const img = await fetch(url).then(r => r.arrayBuffer());
  const { writeFileSync } = await import("node:fs");
  writeFileSync("cat.png", Buffer.from(img));
  console.log(`saved cat.png from task ${id}`);
})();

Справочник по параметрам

Тело запроса всегда содержит два поля верхнего уровня: model (строка, голый идентификатор модели gpt-image-2/text-to-image) и input (объект с параметрами, специфичными для модели).

Поле input Обязательно Тип Описание
prompt Да string Текстовое описание желаемого изображения.
aspect_ratio Да string Одно из значений: 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9 или auto.
resolution Нет string 1K (по умолчанию), 2K или 4K. Размеры в пикселях масштабируются в зависимости от выбранного соотношения сторон.
callback Нет object { "url": "https://yours.example/hook", "when": "final" } — см. следующий раздел.

Успешное создание возвращает {"code":200, "data":{"taskId":"tk-hiapi-..."}, "message":"success"}. GET /v1/tasks/{taskId} возвращает data.status со значением handling, success или fail; при успехе data.output — это массив, первый элемент которого содержит url изображения и временную метку expireAt.

Другие модели изображений hiapi (например, z-image, qwen-image) используют несколько иные поля input — aspect_ratio — это соглашение, принятое в gpt-image-2/text-to-image. При смене модели проверьте страницу модели, чтобы убедиться в точной структуре input.

Производственные подходы

Используйте обратные вызовы вместо опроса

Опрос каждые 5 секунд подходит для прототипа, но для производственного трафика вы хотите, чтобы hiapi сам推送 (направлял) завершённые задачи вам, освобождая worker. Добавьте блок callback в input:

{
  "model": "gpt-image-2/text-to-image",
  "input": {
    "prompt": "an astronaut sketching the moon",
    "aspect_ratio": "3:2",
    "resolution": "1K",
    "callback": {
      "url": "https://your-app.example.com/webhooks/hiapi",
      "when": "final"
    }
  }
}

when: "final" срабатывает один раз, когда задача достигает конечного состояния (success или fail). Полезная нагрузка, которую получает ваш эндпоинт, имеет ту же структуру, что и GET /v1/tasks/{id}, поэтому обработчик может повторно использовать логику разбора при опросе. Сверьте taskId с taskId, сохранённым при создании задачи, чтобы понять, какому запросу принадлежит обратный вызов.

Сделайте операцию создания идемпотентной

Если worker упадёт после POST /v1/tasks, но до сохранения taskId, вы можете сгенерировать одно и то же изображение дважды. Недорогое решение: в момент получения ответа о создании сохранить (your_request_id → taskId) в базе данных в той же транзакции, что и отправка запроса. Если worker повторит попытку, он найдёт существующий taskId и возобновит опрос, а не создаст новую задачу.

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

При ошибке аутентификации hiapi возвращает HTTP 200 со встроенной в тело ответа полезной нагрузкой ошибки:

{"error":{"code":"permission_denied","message":"This API key cannot use the selected model. ...","type":"hiapi_error"}}

Поэтому один лишь код состояния 200 не означает успех. Всегда сначала проверяйте body.error; если он есть, смотрите error.code (permission_denied, invalid_request и т. д.) и error.message. request_id в сообщении — это то, что вы вставляете в тикет поддержки, когда нужна помощь.

Скачивайте сразу и переразмещайте самостоятельно

data.output[0].url — это URL с коротким сроком действия — в ответе содержится expireAt. Не вставляйте URL hiapi напрямую в <img src> вашего продукта; как только задача завершится успешно, сразу скачайте байтовый поток, загрузите его в собственное хранилище (S3, R2, Supabase Storage и т. п.) и отдавайте оттуда.

Задавайте разумные тайм-ауты

Разумные значения по умолчанию: тайм-аут POST-запроса 60 секунд (создание задачи быстрое — вы фактически просто ждёте подтверждения получения API), общий бюджет цикла опроса 10 минут с интервалом опроса 5 секунд. Задачи, занимающие более 10 минут, почти всегда означают, что задача незаметно перешла в состояние fail, поэтому тайм-аут с записью последнего тела ответа задачи в лог полезнее бесконечного ожидания.

Частые вопросы

В чём разница между gpt-image-2 и gpt-image-2/text-to-image?

gpt-image-2 — это семейство моделей; gpt-image-2/text-to-image — это конкретный эндпоинт, который вы вызываете для преобразования текстового запроса в новое изображение. Другие варианты этого семейства предоставляют иную структуру input (например, редактирование изображений принимает референсное изображение). Если сомневаетесь, используйте голый идентификатор модели, который видите на странице модели.

Что делает aspect_ratio: auto?

auto позволяет модели самой определить соотношение сторон на основе запроса. Используйте это, когда у вас нет строгих требований к компоновке; в противном случае фиксируйте соотношение самостоятельно, чтобы последующая обрезка была предсказуемой.

Почему мой запрос возвращает HTTP 200 с permission_denied?

Либо ключ API неверен (опечатка, отозван, отсутствует префикс sk-), либо тарифный план этого ключа не включает gpt-image-2/text-to-image. Откройте консоль ключей API, проверьте строку ключа и посмотрите свой план на странице цен. Всегда проверяйте body.error.code — никогда не полагайтесь только на HTTP-код состояния.

Можно ли сгенерировать несколько изображений за один запрос?

gpt-image-2/text-to-image генерирует одно изображение за задачу — data.output является массивом, но для этой модели его длина всегда равна 1. Чтобы сгенерировать N вариантов, запускайте N задач параллельно и используйте шаблон callback, описанный выше, чтобы не держать N worker'ов занятыми в ожидании.

Как отменить выполняющуюся задачу?

Единый API задач в настоящее время не предоставляет эндпоинта отмены. Самое простое смягчение — позволить клиентскому worker'у отказаться от результата, когда он больше не нужен пользователю, — уже выполненная генерация всё равно будет списана, поэтому правильное место для принудительной отмены — перед вызовом POST /v1/tasks.

Как переключиться на другую модель изображений?

Измените model на новый голый ID (например, z-image/text-to-image) и скорректируйте input в соответствии со структурой этой модели. Структуры моделей не полностью одинаковы — некоторые принимают size, некоторые принимают aspect_ratio, а少数 (некоторые) не принимают resolution. Каталог моделей перечисляет все доступные модели, и на странице каждой модели документированы её поля input.

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

Все статьи →

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

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

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