HiAPI
Блог

Руководство

Как использовать kling-3.0-omni/image-to-video через HiAPI API: руководство по curl и Python

Nov 3, 2026
扁平液状色块交叠的抽象封面图,墨色底上点缀青瓷绿与石板灰,用于该教程文章。

Что делает эндпоинт image-to-video

Генерация видео — это не синхронный вызов. В HiAPI kling-3.0-omni/image-to-video следует схеме сначала отправка, потом опрос: вы отправляете HTTP-запрос с описанием задачи, API принимает запрос и возвращает идентификатор задачи, затем вы опрашиваете эту задачу, пока генерация видео не завершится.

У такой двухэтапной структуры есть веские причины. Рендеринг видео из статичного изображения требует времени — намного больше, чем типичный HTTP-запрос должен оставаться открытым. Если бы эндпоинт блокировался до готовности файла, вы бы при каждом вызове получали таймауты шлюза и обрывы соединения. Возвращая дескриптор задачи немедленно, API позволяет вашему коду самому решать, сколько ждать, как часто проверять и что делать при ошибке.

Типичная задача состоит из трёх логических частей:

  • Входные медиа — изображение (или набор изображений), задающее точку привязки для сцены.
  • Настройки генерации — текст промпта, параметры движения, выбор аудио и разрешения.
  • Жизненный цикл — ответ на отправку с идентификатором задачи, затем проверки статуса, которые в итоге дают URL готового видео или причину сбоя.

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

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

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

Построение рабочего запроса curl

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

Вызов отправки имеет предсказуемую структуру. Вы аутентифицируетесь с помощью ключа HiAPI API в заголовке Authorization, объявляете Content-Type: application/json и отправляете JSON-тело. Концептуально тело выглядит так:

{
  "model": "kling-3.0-omni/image-to-video",
  "input": {
    "image": "https://your-cdn.example.com/frame-first.jpg",
    "prompt": "Медленный наезд камеры, пока утренний свет пересекает комнату"
  }
}

Структура важнее буквальных значений: идентификатор модели, объект input, несущий ссылку на исходное изображение и промпт, и место для параметров генерации. Прежде чем жёстко прописывать каждый ключ, сверьтесь с текущей документацией.

Эквивалентный вызов curl следует распространённой схеме:

curl -sS -X POST "$HIAPI_BASE_URL/v1/video/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json

Хранение тела запроса в request.json, а не встроенно, сильно упрощает итерации — вы редактируете файл, а не запись в истории оболочки.

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

Успешная отправка намеренно невзрачна. Ожидайте идентификатор задачи и статус, означающий «принято, но не завершено». Разберите его, выведите и сохраните:

curl -sS -X POST "$HIAPI_BASE_URL/v1/video/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json | tee submit.json

Сначала проверьте HTTP-код состояния. 4xx означает, что сам запрос отклонён — неверный ключ, некорректный JSON, неподдерживаемые параметры, недопустимый URL изображения. 2xx означает, что задача попала в систему, и с этого момента полезный сигнал исходит от статуса задачи, а не от HTTP-кода состояния.

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

Работа с входами первого и последнего кадра

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

Только первый кадр

Когда вы предоставляете одно изображение, рассматривайте его как начальный кадр. Промпт затем описывает, что должно произойти начиная с этого кадра: движение камеры, действия субъекта, изменения освещения, темп. Поскольку модель должна создать всё после первого кадра, промпты, описывающие траекторию, работают лучше, чем промпты, описывающие статичную сцену. «Остаётся неподвижным и выглядит красиво» не даёт модели ничего для анимации; «она поворачивается к окну, и свет тоже теплеет» задаёт направление.

Добавление последнего кадра

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

Три практических замечания:

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

В коде рассматривайте кадры как небольшой набор именованных входов, а не как свободную коллекцию URL:

inputs = {"image": first_frame_url}
if last_frame_url:
    inputs["last_frame"] = last_frame_url

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

Наконец, размещайте кадры там, где они надёжно доступны. URL, истекающий в середине задачи, приводит к сбою после отправки, и ошибка выглядит как сбой генерации, а не как проблема ресурса.

Настройка аудио и выходного разрешения

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

Аудио

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

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

Разрешение

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

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

  • Проверяйте перед отправкой. Если модель не поддерживает переданное вами разрешение, вы хотите получить чёткий отказ на этапе отправки, а не запутанный сбой уровня задачи через несколько минут.
  • Храните настройки вместе с задачей. Когда вы сравниваете несколько результатов, вам нужно знать, с каким разрешением и выбором аудио был получен каждый.
  • Не предполагайте паритет между кадрами. Задача с двумя кадрами и большим исходным изображением может вести себя иначе, чем задача с одним кадром; тестируйте оба пути.

Где это должно находиться в коде

Сгруппируйте параметры генерации в отдельный объект, чтобы намерение было очевидным и можно было заменить значения по умолчанию в одном месте:

options = {
    "resolution": "1080p",   # подтвердите поддерживаемые значения в документации модели
    "audio": True,
}

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

Опрос завершения в Python

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

Минимальная структура клиента

import os, time, requests

BASE = os.environ["HIAPI_BASE_URL"]
KEY = os.environ["HIAPI_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}

def submit(payload: dict) -> str:
    r = requests.post(f"{BASE}/v1/video/generations",
                      headers=HEADERS, json=payload, timeout=30)
    r.raise_for_status()
    return r.json()["id"]

def wait(task_id: str, interval: float = 5.0, max_wait: float = 600.0) -> dict:
    deadline = time.monotonic() + max_wait
    while time.monotonic() < deadline:
        r = requests.get(f"{BASE}/v1/video/generations/{task_id}",
                         headers=HEADERS, timeout=30)
        r.raise_for_status()
        job = r.json()
        if job["status"] in ("succeeded", "failed"):
            return job
        time.sleep(interval)
    raise TimeoutError(f"task {task_id} not finished in {max_wait}s")

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

  • Явные таймауты для каждого HTTP-вызова. Зависший запрос хуже неудавшегося.
  • Максимальное время ожидания. Неограниченный цикл превращает застрявшую задачу в застрявший сервис.
  • Проверка терминальных состояний. Останавливайтесь только тогда, когда статус действительно окончательный; всё остальное считайте продолжающимся, включая статусы, которых вы не знаете.
  • Возврат всего объекта задачи. Вызывающей стороне обычно нужны URL вывода и любые подробности ошибки, а не просто булево значение.

Ритм опроса

Для видеозадач пять секунд — разумное значение по умолчанию. Опрос каждые 200 мс расходует квоту без всякой пользы, поскольку рендеринг в любом случае занимает несколько минут. Если вы отправляете много задач, поместите цикл опроса в worker, а не в обработчик запросов, и немного увеличьте интервал для долго выполняющихся задач.

Соединяем всё вместе

payload = {
    "model": "kling-3.0-omni/image-to-video",
    "input": {"image": first_frame_url, "prompt": prompt},
    "options": options,
}

job = wait(submit(payload))
if job["status"] == "failed":
    raise RuntimeError(job.get("error") or "generation failed")
print(job["output"]["url"])

Поскольку submit возвращает обычную строку, а wait возвращает dict, вы можете тестировать каждую половину независимо: имитировать ответ на отправку, чтобы протестировать логику опроса, и отдельно вызывать submit, чтобы проверить тело запроса на живом API.

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

Сбои сосредоточены на трёх уровнях, и определение уровня — это большая часть диагностики.

Уровень 1: отказ при отправке

Они появляются как ответы 4xx до того, как существует какая-либо задача. Частые причины:

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

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

Уровень 2: транспортные проблемы

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

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

Уровень 3: сбои уровня задачи

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

В коде чётко различайте их, потому что меры исправления разные. 4xx означает исправить запрос. Неудачная задача означает изменить входные данные или повторить — если одно и то же тело запроса не удаётся дважды, прекратите повторять и измените что-нибудь: упростите промпт, выберите более близкие кадры, снизьте разрешение.

Краткий чек-лист диагностики

  1. HTTP-статус 4xx? Исправьте тело запроса или учётные данные; не опрашивайте.
  2. Отправка успешна, но задача никогда не завершается? Ваш лимит ожидания слишком мал или задача застряла — запишите идентификатор задачи и разбирайтесь, а не зацикливайтесь навсегда.
  3. Задача завершилась неудачей? Прочитайте подробности ошибки, затем скорректируйте входные данные, а не отправляйте как есть повторно.
  4. Успех, но видео неверное? Это проблема промпта и выбора кадров, а не API.

Выпуск: производственный чек-лист

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

Конфигурация. Храните base URL и API-ключ в переменных окружения или менеджере секретов, никогда в исходном коде. Если чего-то из этого нет, быстро падайте при запуске, а не при первом запросе пользователя.

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

Идентификатор задачи — это запись. Сохраняйте идентификатор задачи вместе с отправленным телом запроса: кадры, промпт, разрешение, выбор аудио и метка времени. Когда кто-то через две недели спросит, почему видео выглядит не так, эта строка — весь ответ.

Вывод временный. Считайте возвращённый URL видео временным. Как только задача успешна, скачайте и сохраните его в собственное постоянное хранилище, и запишите место хранения в задаче.

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

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

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

С клиентом, циклом опроса и этими мерами предосторожности kling-3.0-omni/image-to-video становится предсказуемым компонентом, а не скриптом, который вы молитесь, чтобы он работал.

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

Все статьи →

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

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

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