HiAPI
Блог

Руководство

Как использовать API hailuo 2.3 для генерации видео из изображения: curl, Python и один рабочий пример запроса

Jul 11, 2026
Как использовать API hailuo 2.3 для генерации видео из изображения: curl, Python и один рабочий пример запроса

Краткое содержание

  • Что это: рабочий рецепт использования hailuo-2.3/image-to-video API на hiapi — превращение статичного изображения в короткий видеоклип: создание задачи, опрос задачи, скачивание .mp4.
  • Эндпоинт: POST https://api.hiapi.ai/v1/tasks, в теле запроса указывается "model": "hailuo-2.3/image-to-video", затем опрос через GET /v1/tasks/<taskId>, пока задача не перейдёт в терминальное состояние.
  • Два обязательных входных поля: prompt и image_url — один публичный URL, указывающий на ваш первый кадр (не массив).
  • duration — это строка, а не число: "6" или "10". Передача целого числа 6 будет отклонена с ошибкой 400.
  • Схема строгая. Нет параметров motion_strength, camera_movement или resolution — при их передаче будет ошибка 400. Движение полностью управляется через prompt.

Что вы создаёте и что нужно подготовить

У вас есть статичное изображение — фотография продукта, рендер персонажа, снимок — и вы хотите, чтобы hailuo-2.3 оживил его, создав видеоклип, который начинается именно с этого кадра. hailuo-2.3 славится физически правдоподобным движением (ткани, волосы, биомеханика тела), поэтому отлично подходит для оживления статичных изображений.

Вам понадобятся две вещи:

  1. API-ключ hiapi. Создайте его в панели управления. Ключ имеет вид sk-... и передаётся в заголовке Authorization: Bearer.
  2. Публично доступный URL изображения первого кадра. API загружает изображение из image_url, поэтому оно должно быть доступно без аутентификации — подходят ссылки S3/R2/CDN; пути localhost или истёкшие подписанные URL не подходят.

Как и каждая генеративная модель на hiapi, эта модель использует асинхронный интерфейс задач: вы отправляете POST задачи, сразу получаете taskId, а затем получаете результат через опрос или callback. Для видео нет синхронного эндпоинта — рендеринг клипа занимает время и превышает типичный таймаут HTTP.

Схема запроса

Полная входная схема hailuo-2.3/image-to-video — проверено на работающем API:

Поле Тип Обязательно Описание
prompt string ✅ Описывает движение, а не сцену — сцена берётся из вашего изображения.
image_url string ✅ Один публичный URL — первый кадр. В единственном числе — не image_urls.
duration string Необязательно "6" или "10" (секунды). Обязательно строка.
prompt_optimizer boolean Необязательно Позволяет платформе расширить ваш prompt перед генерацией.

Схема строгая: всё, чего нет в этой таблице, будет отклонено. Отправив motion_strength, camera_movement или resolution, вы получите в ответ:

{
  "code": 400,
  "error_code": "INVALID_REQUEST",
  "message": "invalid input: <root>: additional properties 'resolution', 'camera_movement', 'motion_strength' not allowed"
}

Стоит запомнить два следствия:

  • Нет регулятора движения. Физика движения в hailuo-2.3 управляется только prompt — см. раздел о написании промптов ниже.
  • На этом эндпоинте нет управления разрешением или соотношением сторон. Не создавайте UI для параметров, на которые API вернёт 400.

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

Создание задачи:

curl -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-<your-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hailuo-2.3/image-to-video",
    "input": {
      "prompt": "The woman turns toward the camera and smiles; wind gently moves her hair; slow cinematic push-in",
      "image_url": "https://your-cdn.example.com/first-frame.jpg",
      "duration": "6",
      "prompt_optimizer": true
    }
  }'

Ответ (фрагмент) содержит id задачи в data.taskId:

{ "data": { "taskId": "..." } }

Опрос задачи:

curl -s https://api.hiapi.ai/v1/tasks/<taskId> \
  -H "Authorization: Bearer sk-<your-key>"

Пока клип рендерится, data.status сообщает нетерминальный статус. Когда он меняется на "success", URL видео находится в data.output[0].url; если "fail" — причина указана в data.error.code и data.error.message.

Скачивайте файл сразу после успешного завершения задачи. Выходной URL подписан и имеет срок действия (expireAt) — сохраняйте байты в собственное хранилище и никогда не используйте горячие ссылки на URL задачи.

Минимальный рабочий пример: Python

Полный скрипт того же процесса — создание, опрос, скачивание:

import time
import requests

API_BASE = "https://api.hiapi.ai/v1/tasks"
API_KEY = "sk-<your-key>"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}


def create_task() -> str:
    payload = {
        "model": "hailuo-2.3/image-to-video",
        "input": {
            "prompt": (
                "The cat stretches, hops off the windowsill, and walks toward "
                "the camera; soft afternoon light, subtle handheld camera sway"
            ),
            "image_url": "https://your-cdn.example.com/first-frame.jpg",
            "duration": "6",          # string, not int: "6" or "10"
            "prompt_optimizer": True,
        },
    }
    r = requests.post(API_BASE, json=payload, headers=HEADERS, timeout=30)
    task_id = (r.json().get("data") or {}).get("taskId")
    if not task_id:
        raise RuntimeError(f"create failed ({r.status_code}): {r.text[:300]}")
    return task_id


def wait_task(task_id: str, timeout_s: int = 900, poll_s: int = 10) -> dict:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS, timeout=30)
        task = r.json().get("data") or {}
        status = task.get("status")
        if status == "success":
            return task
        if status == "fail":
            err = task.get("error") or {}
            raise RuntimeError(f"task failed: {err.get('code')}: {err.get('message')}")
        time.sleep(poll_s)
    raise TimeoutError(f"task {task_id} not finished after {timeout_s}s")


def main() -> None:
    task_id = create_task()
    print("task created:", task_id)
    task = wait_task(task_id)
    url = task["output"][0]["url"]
    # The URL is signed and expires -- download immediately, store the bytes yourself.
    video = requests.get(url, timeout=120).content
    with open("hailuo-output.mp4", "wb") as f:
        f.write(video)
    print("saved hailuo-output.mp4")


if __name__ == "__main__":
    main()

Видеозадачи выполняются заметно дольше, чем задачи с изображениями, поэтому скрипт опрашивает каждые 10 секунд и устанавливает щедрый лимит в 15 минут. Не опрашивайте чаще, чем примерно раз в 5 секунд — это не ускорит рендеринг.

Написание промптов, управляющих движением

Поскольку параметров движения нет, prompt — ваш единственный руль, и для hailuo-2.3 этого достаточно. Три практических правила:

  • Описывайте движение, а не внешний вид. Модель уже видит ваше изображение. "a beautiful woman in a red dress" тратит prompt впустую; "she turns her head slowly to the left as the camera pushes in" использует его правильно.
  • Описывайте движение камеры простым языком. "slow push-in", "orbit right", "handheld sway", "static camera" — всё это следует писать в тексте prompt, а не в (несуществующем) поле camera_movement.
  • Если сомневаетесь, пусть поможет prompt_optimizer. При "prompt_optimizer": true платформа расширяет короткий prompt перед генерацией — хорошее значение по умолчанию для коротких входных данных. Отключайте его, когда хотите строго следовать тщательно продуманной формулировке.

Замечания для продакшена

Предпочитайте callback вместо опроса. При создании задачи укажите callback, и hiapi отправит POST с результатом терминального состояния на ваш эндпоинт, так что вам не нужно держать открытый цикл:

{
  "model": "hailuo-2.3/image-to-video",
  "input": { "...": "..." },
  "callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}

"when": "final" срабатывает только один раз в терминальном состоянии. Опрос подходит для скриптов и notebook; callback — правильная форма для сервера: рендеринг видео достаточно долгий, и worker, блокирующийся на опросе, — это реальные затраты.

Явно обрабатывайте следующие ошибки:

  • 401 с "code": "permission_denied" — проблема с ключом или у ключа нет прав на использование этой модели. Сообщение содержит request_id, который можно передать в поддержку.
  • 400 INVALID_REQUEST — нарушение схемы. Сообщение точное, например duration: got number, want string или image_url: missing required field "image_url". Логируйте его дословно.
  • 402 при создании задачи — недостаточно средств. Учтите, что видео стоит дороже за задачу, чем изображения, поэтому ключ, который всё ещё успешно выполняет задачи с изображениями, может начать терпеть неудачу при создании видео. Пополните баланс или проверьте использование в панели управления.
  • Задача перешла в "fail" — сбой на стороне генерации; проверьте data.error. В частности, частая причина для видео из изображения: image_url не удаётся загрузить (приватный bucket, истёкший подписанный URL).

Обеспечьте идемпотентность при повторных попытках. Если ваш процесс умирает между созданием и скачиванием, наивный перезапуск создаст (и оплатит) второй рендеринг. Сохраняйте taskId в постоянном хранилище сразу после возврата из create_task, а при перезапуске продолжайте опрос вместо повторного создания.

Связанные материалы

Часто задаваемые вопросы

Какие длительности поддерживает hailuo-2.3 для видео из изображения? Две: "6" и "10" секунд, передаются строкой. Любое другое значение — или запись того же значения числом — вернёт 400 INVALID_REQUEST.

Почему "duration": 6 не работает, а "duration": "6" работает? Схема определяет duration как строковый enum. API явно сообщает: duration: got number, want string. Это самая распространённая ошибка 400 на этом эндпоинте.

Можно ли задать выходное разрешение или соотношение сторон? Нет. Эндпоинт не предоставляет поля resolution или aspect_ratio, отправка любого из них даёт 400 — схема отклоняет неизвестные свойства, а не игнорирует их.

Как управлять движением камеры или интенсивностью движения? Через prompt. Параметров camera_movement или motion_strength нет — пишите указания по камере и движению простым языком ("slow push-in", "she walks toward the camera").

Можно ли передать несколько референсных изображений? Нет — image_url — это одна строка, первый кадр. Это отличается от некоторых других моделей на hiapi, принимающих массив image_urls; схема определяется для каждой модели, поэтому обязательно проверяйте страницу модели.

Какие форматы изображений поддерживаются для первого кадра? Стандартные веб-форматы (JPEG/PNG), предоставляемые по публично доступному URL. Если платформа не может загрузить этот URL, задача завершится сбоем после создания — поэтому проверьте доступность ссылки до отправки.

Чем это отличается от hailuo-2.3/text-to-video? Видео из текста изобретает сцену исключительно по вашему prompt; видео из изображения закрепляет первый кадр на вашем изображении и начинает анимацию с него. Жизненный цикл задачи идентичен — различается только входная схема (здесь image_url обязателен, а в видео из текста поля изображения нет вовсе).

Сколько это стоит? Видео оплачивается по количеству выходных секунд, ставки меняются — смотрите страницу модели hailuo-2.3/image-to-video и страницу цен для актуальных цифр.

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

Все статьи →

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

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

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