Руководство
Как вызывать happyhorse-1.1/image-to-video в API hiapi: руководство по curl и Python
Что делает этот эндпоинт и когда его использовать
happyhorse-1.1/image-to-video превращает одно статическое изображение в короткое видео. Вы отправляете на этот эндпоинт изображение первого кадра, и модель генерирует анимацию, начиная с этого кадра. Практический смысл здесь в непрерывности: субъект, композиция и внешний вид из исходного изображения переносятся в сгенерированный фрагмент. Это и есть то, что мы здесь называем сохранением идентичности — модель не создаёт новую сцену с нуля только по текстовому промпту, а продолжает сцену, которую вы уже создали с помощью изображения.
Поэтому этот эндпоинт отлично подходит, когда визуальная идентичность важнее импровизации:
- У вас уже есть референсный статичный кадр — портрет, фотография продукта, концепт-арт персонажа — и вы хотите сгенерировать движение, верное этому кадру.
- Вы создаёте короткие ролики в конвейере, где все остальные материалы сначала проектируются в виде изображений.
- Вам нужны анимированные раскадровки или превью движения для кадров сториборда.
Он менее подходит, когда вы хотите, чтобы модель свободно переосмыслила сцену с нуля, или когда нет статичного кадра, чтобы закрепить результат. В таких случаях рабочий процесс с приоритетом изображения обычно означает: сначала сгенерировать опорное изображение, а затем передать этот результат этому эндпоинту.
Сам вызов асинхронный: вы отправляете задачу и затем опрашиваете её до готовности видео. Остальная часть руководства проведёт вас через этот жизненный цикл от начала до конца.
Перед отправкой запроса
Перед первым вызовом нужно подготовить две вещи.
API-ключ
Все вызовы выполняются через платформу hiapi, API-ключ прикрепляется как bearer-учётные данные. Храните ключ в переменной окружения, а не в системе контроля версий, чтобы один и тот же код работал и при локальной разработке, и в CI:
export HIAPI_API_KEY="your_key_here"
В Python читайте его во время выполнения через os.environ["HIAPI_API_KEY"]. Никогда не логируйте необработанное значение заголовка.
Ссылка на изображение первого кадра
Эндпоинту нужно стартовое изображение. Заранее решите, как его передавать — как URL, который платформа может загрузить, или как загруженный/закодированный в base64 материал, в зависимости от того, что поддерживают ваш аккаунт и документация эндпоинта. Важно, чтобы эта ссылка была стабильной и доступной в момент отправки. Если задача может встать в очередь, подписанный URL, истекающий через пять минут, — плохой выбор.
Также полезно до вызова знать ожидаемое соотношение сторон и длительность вывода, поскольку первый кадр обычно их ограничивает. Принятое заранее решение избавит от повторной отправки позже.
Когда ключ экспортирован, а ссылка на изображение определена, можно отправлять.
Формирование входных данных первого кадра
Первый кадр — это якорь для всего, что модель генерирует после него. На практике относитесь к нему как к контракту идентичности: всё, что чётко видно на этом изображении — лица, одежда, логотипы, цветовая схема, угол камеры — это то, на что модель должна опираться. Если какая-то деталь на статичном кадре размыта или скрыта, вывод тоже будет размытым.
Независимо от конкретных параметров модели, применимы следующие принципы подготовки:
- Выбирайте чёткие, хорошо освещённые кадры. Артефакты сжатия и сильный шум уменьшают то, что модель может сохранить. Резкое, равномерно освещённое изображение — лучший якорь, чем драматичное, но размытое.
- Помещайте субъект туда, где должно начинаться движение. Обрезка и компоновка на статичном кадре выгоднее, чем надежда на то, что модель перекадрирует.
- Соблюдайте соотношение сторон ожидаемого вывода. Если итоговое видео горизонтальное, подготовьте горизонтальное опорное изображение; последующее заполнение не вернёт потерянную композицию.
- Избегайте противоречивых подсказок. Статичный кадр, который читается в одном смысле, но подразумевает действие за кадром, даёт модели нестабильную отправную точку.
Не предполагайте наличие параметров модели, не описанных в документации эндпоинта. Самый надёжный подход — позволить самому изображению нести замысел, а поля запроса использовать только для того, что они явно покрывают.
Рабочий запрос через curl
Для отправки задачи нужен всего один POST. Структура такова: аутентифицированный запрос к эндпоинту, тело JSON содержит идентификатор модели и входное изображение.
curl -sS -X POST "https://api.hiapi.ai/v1/video/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "happyhorse-1.1/image-to-video",
"input": {
"image": "https://your-bucket.example.com/first-frame.jpg"
}
}'
По шагам:
- Эндпоинт. Цель POST — маршрут генерации видео в API hiapi. Если вы пишете скрипты для нескольких окружений, вынесите его в переменную.
- Заголовок аутентификации.
Authorization: Bearer $HIAPI_API_KEY— оболочка подставит переменную окружения, экспортированную ранее. - Тип содержимого.
application/json, поскольку тело — JSON. - Тело запроса.
modelвыбираетhappyhorse-1.1/image-to-video;input.image— ссылка на ваш первый кадр. Сверьтесь со справочной документацией эндпоинта, чтобы узнать точное имя поля изображения и структуру, принимаемые в вашем аккаунте.
Успешный ответ — это не само видео, а дескриптор задачи. Ожидайте получить идентификатор и поле статуса, обычно что-то вроде queued или processing. Запишите этот ID; он понадобится на следующем шаге для опроса. Сначала выполните команду один раз и выведите ответ, чтобы увидеть его структуру до того, как начнёте писать скрипт.
Тот же запрос на Python
Версия на Python — это прямой перенос, а не новая интеграция. Тот же маршрут, те же заголовки, то же тело JSON.
import os
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
URL = "https://api.hiapi.ai/v1/video/generations"
payload = {
"model": "happyhorse-1.1/image-to-video",
"input": {
"image": "https://your-bucket.example.com/first-frame.jpg"
},
}
resp = requests.post(
URL,
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json=payload,
timeout=60,
)
resp.raise_for_status()
job = resp.json()
print(job)
Пояснения к соответствию:
requestsсjson=payloadсериализует словарь так же, как строка-dв curl — если используетеjson=, не задавайтеContent-Typeвручную; библиотека справится сама. Явный заголовок выше безвреден, но избыточен.raise_for_status()превращает сбой на уровне HTTP в исключение как можно раньше — до того, как вы начнёте опрашивать несуществующую задачу.timeout— лишь клиентская защита для вызова отправки. Генерация выполняется на сервере и им не ограничена.
Храните payload в переменной и переиспользуйте её. При последующей смене модели или изображения вы должны редактировать один словарь, а не две параллельные реализации.
Работа с асинхронными задачами и опрос
Генерация видео из изображения занимает больше времени, чем цикл запрос/ответ. Поэтому API сразу возвращает ссылку на задачу и ожидает, что вы позже её проверите. Жизненный цикл таков: отправка, получение ID, опрос статуса, получение результата.
Извлеките ID задачи из ответа на отправку — имя поля зависит от документированной схемы ответа этого эндпоинта, поэтому прочитайте её один раз и захардкодьте поиск по ключу, а не значение:
job_id = job["id"] # check the endpoint docs for the exact field
Затем опрашивайте с интервалом:
import time
poll_url = f"https://api.hiapi.ai/v1/video/generations/{job_id}"
while True:
status = requests.get(
poll_url,
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
).json()
if status["status"] == "succeeded":
break
if status["status"] == "failed":
raise RuntimeError(status)
time.sleep(5)
Правила разумного опроса:
- Опрашивайте с фиксированным интервалом, а не в плотном цикле. Для задач такого масштаба нескольких секунд между проверками достаточно; бомбардировка эндпоинта увеличивает нагрузку, но не ускоряет появление результата.
- Ограничьте общее время ожидания.
while Trueбез верхней границы — это зависание, которое рано или поздно случится. Отслеживайте прошедшее время и громко падайте после разумного бюджета. - Обрабатывайте оба терминальных состояния. И успех, и неудача — это ответы. Считайте неизвестные строки статуса нетерминальными, но логируйте их, чтобы заметить изменения в паттернах.
- Не опрашивайте одну задачу из нескольких параллельных worker'ов. Один опросчик на задачу или координация через очередь.
Как только статус стал терминальным, переходите к скачиванию результата.
Скачивание и хранение вывода
Готовое видео предоставляется как материал в ответе завершённой задачи — обычно это URL, иногда с временем истечения. Первый шаг после успешного опроса — получить эту ссылку и скопировать байты в хранилище, которое вы контролируете.
video_url = status["output"]["video_url"] # inspect the real response shape
with requests.get(video_url, stream=True, timeout=120) as r:
r.raise_for_status()
with open(f"out/{job_id}.mp4", "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 20):
f.write(chunk)
Рекомендации по хранению, применимые к любому конвейеру:
- Копируйте долговременные артефакты, а не ссылайтесь на них. Подписанный или ограниченный по времени URL — это транспорт, а не хранилище. Сохраните файл, затем в базе данных храните свой собственный ключ объекта вместе с ID задачи.
- Обрабатывайте большие файлы потоково.
iter_contentдержит память стабильной; загрузка всего видео в переменную привязывает лимит памяти к размеру материала. - Записывайте происхождение. Сохраняйте
job_id, ссылку на входное изображение и идентификатор модели вместе с материалом. Когда понадобится воспроизвести фрагмент, эта запись и будет рецептом. - Проверяйте HTTP-статус перед записью. Частичная запись из-за ошибочного ответа хуже чистого сбоя, потому что выглядит как действительный файл.
Как только файл оказался на диске или в объектном хранилище, конвейер замыкается, и можно переходить к следующему кадру.
Ошибки и подводные камни, на которые стоит обратить внимание
Большинство сбоев этого эндпоинта предсказуемы. Краткий чек-лист:
- Некорректный или недоступный ввод первого кадра. Самая частая причина отказа в отправке. Проверьте, разрешается ли URL изображения из публичной сети, принимает ли эндпоинт этот формат и правильно ли вложено поле изображения в payload. Воспроизведите вызов через curl, чтобы отличить проблему аутентификации от проблемы payload.
- Опрос до существования задачи. Чтение ID из неверного поля или опрос маршрута, не соответствующего ответу на отправку, даёт 404, который выглядит как сбой задачи. Выведите ответ на отправку один раз и зафиксируйте поиск по ключу на его основе.
- Неограниченное ожидание. Отсутствие тайм-аута означает, что зависшая задача навсегда подвесит worker. Задайте бюджет, падайте и оповещайте.
- Потеря ссылки на материал. Генерация успешна, но URL использован один раз и больше не скопирован. Сохраняйте байты при получении и держите собственный ключ; не полагайтесь на возвращённую ссылку как на долговременное хранилище.
- Утечка учётных данных. Вставка ключа в notebook и случайная фиксация — повторяющаяся проблема. Загружайте из окружения, при сомнениях — ротируйте.
- Предположение о недокументированных параметрах эндпоинта. Если нужного параметра нет в списке, значит, его не существует. Выражайте замысел только через изображение первого кадра и документированные поля.
Разберитесь с этим, и асинхронный процесс станет банальным — именно этого вы и хотите в производственном конвейере. Что касается специфичных для эндпоинта имён полей и допустимых значений, держите справочную документацию эндпоинта открытой во время разработки.
Похожие статьи
Все статьи →-
Руководство
Как вызвать 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
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата