Руководство
Как использовать kling-3.0-omni/image-to-video через HiAPI API: руководство по curl и Python
Что делает эндпоинт 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 означает исправить запрос. Неудачная задача означает изменить входные данные или повторить — если одно и то же тело запроса не удаётся дважды, прекратите повторять и измените что-нибудь: упростите промпт, выберите более близкие кадры, снизьте разрешение.
Краткий чек-лист диагностики
- HTTP-статус
4xx? Исправьте тело запроса или учётные данные; не опрашивайте. - Отправка успешна, но задача никогда не завершается? Ваш лимит ожидания слишком мал или задача застряла — запишите идентификатор задачи и разбирайтесь, а не зацикливайтесь навсегда.
- Задача завершилась неудачей? Прочитайте подробности ошибки, затем скорректируйте входные данные, а не отправляйте как есть повторно.
- Успех, но видео неверное? Это проблема промпта и выбора кадров, а не API.
Выпуск: производственный чек-лист
Прежде чем показывать пользователям, укрепите те части, которые могут незаметно отказать.
Конфигурация. Храните base URL и API-ключ в переменных окружения или менеджере секретов, никогда в исходном коде. Если чего-то из этого нет, быстро падайте при запуске, а не при первом запросе пользователя.
Таймауты и повторные попытки. Каждому исходящему вызову нужен явный таймаут. Повторяйте отправку только там, где дублирование допустимо, и считайте повторный опрос безопасным — идемпотентным чтением состояния. Ограничьте общее время ожидания и предоставьте вызывающей стороне чёткий таймаут.
Идентификатор задачи — это запись. Сохраняйте идентификатор задачи вместе с отправленным телом запроса: кадры, промпт, разрешение, выбор аудио и метка времени. Когда кто-то через две недели спросит, почему видео выглядит не так, эта строка — весь ответ.
Вывод временный. Считайте возвращённый URL видео временным. Как только задача успешна, скачайте и сохраните его в собственное постоянное хранилище, и запишите место хранения в задаче.
Осознание затрат. Генерация видео оплачивается по выходным данным, поэтому разрешение, длительность и количество генераций — важные рычаги. Итерируйте в низком разрешении, осознанно генерируйте финальную версию и записывайте настройки, чтобы относить расходы к конкретному сценарию, а не обнаруживать их только в счёте.
Наблюдаемость. Выводите строки логов при отправке и при терминальном статусе, включая идентификатор задачи, задержку и статус. Простая метрика успешности по каждой модели скажет вам, когда изменения промпта или настройки параметров начинают приводить к сбоям задач.
Сверяйтесь с документацией, а не с примерами. Перед каждым релизом, затрагивающим аудио, разрешение или входные кадры, подтверждайте имена полей и допустимые значения на справочной странице модели, поскольку эти настройки наиболее вероятно дрейфуют.
С клиентом, циклом опроса и этими мерами предосторожности kling-3.0-omni/image-to-video становится предсказуемым компонентом, а не скриптом, который вы молитесь, чтобы он работал.
Похожие статьи
Все статьи →-
Руководство
Как вызвать hailuo-2.3-fast/image-to-video через HiAPI API: практика с curl и Python
Первый рабочий запрос к быстрому и недорогому уровню генерации видео по изображению — от ID модели до загрузки MP4
-
Руководство
Как вызывать hailuo-2.3/text-to-video через API HiAPI: curl, Python и рабочие примеры запросов
-
Руководство
Использование Kandinsky 6.0 Pro для преобразования текста в видео на HiAPI: руководство по curl и Python
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата