Руководство
Как вызвать veo-3.1-fast/image-to-video через API HiAPI (curl + Python)
Готовый к запуску пример запроса: входное изображение первого кадра, нативный звук, асинхронный опрос и загрузка результата
Что мы создаём в этом руководстве и что нужно подготовить
Это руководство полностью демонстрирует один рабочий сценарий интеграции с HiAPI с использованием veo-3.1-fast/image-to-video: вы отправляете изображение первого кадра и текст промпта, получаете асинхронную задачу, опрашиваете её до завершения, а затем скачиваете сгенерированное видео вместе с нативным звуком.
К концу руководства у вас будет две эквивалентные реализации — команда curl, которую можно запустить в терминале, и клиент на Python, который можно поместить в скрипт или сервис, — обе обращаются к одному и тому же эндпоинту HiAPI.
Требования
Перед началом подготовьте следующее:
- Ключ API HiAPI. Не коммитьте его в систему контроля версий. В примерах ниже он читается из переменной окружения, а не вставляется инлайн.
- Базовый URL HiAPI. Используйте адрес, указанный в вашей панели HiAPI или справочнике API; сохраните его в переменной, чтобы настроить один раз.
- Изображение первого кадра. Публично доступный URL — самый простой вариант ввода. Используйте реальное изображение, на которое у вас есть права, в распространённом формате, например JPEG или PNG.
- HTTP-клиент. Для этой демонстрации достаточно
curl. Для версии на Python вам понадобится толькоrequests— SDK вендора не требуется. - Локальный каталог для хранения скачанного видео.
Настройка окружения
Экспортируйте ключ и базовый URL, чтобы их могли использовать и пример для shell, и пример на Python:
export HIAPI_API_KEY="your-api-key"
export HIAPI_BASE_URL="https://api.hiapi.ai"
export FIRST_FRAME_URL="https://example.com/your-first-frame.jpg"
Точный путь эндпоинта и имена параметров для veo-3.1-fast/image-to-video указаны в справочнике API HiAPI рядом с записью модели — сверяйте канонический список полей там, а не полагайтесь на фрагменты, скопированные из других источников. Это руководство сосредоточено на структуре запроса и рабочем процессе, которые остаются неизменными, даже если детали полей нужно уточнять по документации.
Стоит запомнить один момент: это задачная модель, а не синхронная. Вы не получите видео прямо в ответе на отправку. Вы получите идентификатор задачи, а видео появится позже.
Структура запроса генерации видео из изображения
Прежде чем писать код, полезно понять, что именно вы отправляете и что получаете в ответ. Генерация видео из изображения тяжелее текстовой генерации, поэтому API моделирует её как фоновую задачу.
Вход: промпт и первый кадр
Запрос veo-3.1-fast/image-to-video концептуально состоит из двух частей:
- Текстовый промпт, описывающий движение, поведение камеры и замысел сцены — то, что должно произойти после первого кадра.
- Референсное изображение, задающее первый кадр вывода. В этом и отличие генерации видео из изображения от генерации видео из текста: модель продолжает ваше изображение, а не создаёт вступительный кадр с нуля.
Само название модели говорит о компромиссе: вариант fast настроен на более быстрый оборот задач генерации видео из изображения, что делает его идеальным для итераций и конвейеров, где задержка важнее максимальной точности.
Сгенерированный результат содержит нативный звук, поэтому итоговый файл — это полноценное видео со звуком, а не немой фрагмент, которому нужна отдельная звуковая дорожка.
Жизненный цикл задачи
Поскольку генерация занимает время, взаимодействие делится на три этапа:
- Отправка. Вы отправляете промпт и изображение методом
POSTна эндпоинт модели. Ответ — это лёгкое подтверждение, содержащее идентификатор задачи, а не видео. - Опрос. Используя этот идентификатор, вы многократно выполняете
GETстатуса задачи, пока она не сообщит о завершении (или ошибке). - Получение. После завершения ответ задачи указывает на сгенерированное видео, которое вы скачиваете и сохраняете.
Разделение этих этапов в коде — самое важное структурное решение. Если их смешать, повторы, тайм-ауты и обработка ошибок становятся размытыми.
Как выглядит правильно оформленная отправка
Независимо от точного способа сериализации, планируйте запрос, содержащий следующее:
- Идентификатор модели
veo-3.1-fast/image-to-video. - Текст вашего промпта.
- Ссылку на изображение первого кадра.
- Аутентификацию через ключ API в заголовке запроса.
Всё остальное — необязательные параметры, значения по умолчанию, варианты разрешения вывода — относится к справочнику API HiAPI для этой модели. Прочитайте его один раз, поместите подтверждённые имена полей в константы и не разбрасывайте их по кодовой базе.
Относитесь к ответу на отправку как к квитанции. Запишите его, сохраните ID задачи и переходите к опросу.
Вызов с помощью curl
Давайте отправим задачу. Приведённая ниже команда отправляет JSON-тело с промптом и изображением первого кадра на эндпоинт модели в HiAPI и аутентифицируется ключом из окружения.
curl -sS -X POST "$HIAPI_BASE_URL/v1/videos/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "veo-3.1-fast/image-to-video",
"prompt": "Slow dolly forward through a sunlit forest path, leaves drifting, soft birdsong ambience",
"image": "'"$FIRST_FRAME_URL"'"
}'
Несколько замечаний об этой команде:
- Путь эндпоинта и имя поля
imageследует сверить со справочником API HiAPI дляveo-3.1-fast/image-to-video; если они отличаются, замените на канонические значения. Здесь важна именно структура — модель, промпт, изображение. - Промпт действительно работает. Явно описывайте движение и движение камеры («медленный наезд вперёд», «колышущиеся листья») и упоминайте желаемую звуковую атмосферу, поскольку модель генерирует и изображение, и нативный звук одновременно.
-sSсохраняет вывод тихим, но всё равно показывает ошибки — именно это нужно в демонстрации в терминале.- Изображение передаётся как строка URL. Если вы предпочитаете загружать байты, посмотрите поддерживаемые формы ввода в справочнике, а не угадывайте.
Чтение ответа на отправку
Успешная отправка возвращает компактный объект JSON с идентификатором задачи и статусом — примерно так:
{
"id": "job_abc123",
"status": "queued"
}
Имена полей приведены только для примера; сверяйте их с фактическим ответом. Важно то, что теперь у вас есть ID, который можно использовать для опроса, и статус, который не означает готовое видео.
Захватите этот ID в shell, чтобы упростить последующие шаги:
JOB_ID="job_abc123"
Если вы получили ошибку аутентификации, значит, ваш ключ отсутствует или имеет неверный формат. Ошибка валидации обычно означает, что тело запроса не соответствует документированной схеме — в первую очередь проверьте имена полей и типы. Ответ об ограничении частоты означает, что вы отправляете слишком часто; делайте паузу, а не повторяйте в плотном цикле.
Тот же запрос на Python
Ниже эквивалентная отправка на Python. Она использует только requests, читает конфигурацию из переменных окружения и отделяет этап отправки от опроса, чтобы каждую часть можно было переиспользовать.
import os
import time
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
FIRST_FRAME_URL = os.environ["FIRST_FRAME_URL"]
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
MODEL = "veo-3.1-fast/image-to-video"
def submit_job(prompt: str, image_url: str) -> str:
payload = {
"model": MODEL,
"prompt": prompt,
"image": image_url,
}
resp = requests.post(
f"{BASE_URL}/v1/videos/generations",
headers=HEADERS,
json=payload,
timeout=60,
)
resp.raise_for_status()
data = resp.json()
job_id = data["id"]
print(f"submitted job: {job_id} (status={data.get('status')})")
return job_id
if __name__ == "__main__":
job_id = submit_job(
prompt="Slow dolly forward through a sunlit forest path, "
"leaves drifting, soft birdsong ambience",
image_url=FIRST_FRAME_URL,
)
Почему выбрана такая структура
- Конфигурация в константах. Базовый URL, заголовки, путь эндпоинта и имя модели определяются один раз. Когда справочник API сообщает о других именах полей, вы меняете одну строку.
timeoutявный. Отправка, которая висит вечно, хуже быстрого отказа. Для небольшого JSON-тела шестидесяти секунд более чем достаточно.raise_for_status()быстро выявляет ошибки. При 4xx и 5xx вы получаете исключение, а не молчаливое разбирание тела ошибки как задачи.- Функция возвращает только ID задачи. Вызывающему не нужно знать, как выглядит полезная нагрузка отправки; ему нужен лишь объект для опроса.
Если ваше приложение — это веб-сервис, вызывайте submit_job в обработчике запроса, а возвращённый ID передавайте фоновому рабочему процессу. Не блокируйте HTTP-запрос, пока рендерится видео.
Опрос асинхронной задачи до готовности видео
Теперь задача существует и стоит в очереди. Опрос — это способ узнать, когда она завершится.
Базовый цикл опроса
def poll_job(job_id: str, timeout_s: int = 900, initial_delay: float = 5.0) -> dict:
url = f"{BASE_URL}/v1/videos/generations/{job_id}"
delay = initial_delay
deadline = time.time() + timeout_s
while time.time() < deadline:
resp = requests.get(url, headers=HEADERS, timeout=30)
resp.raise_for_status()
data = resp.json()
status = data.get("status")
print(f"status={status}")
if status == "succeeded":
return data
if status in ("failed", "cancelled"):
raise RuntimeError(f"job {job_id} ended with status={status}: {data}")
time.sleep(delay)
delay = min(delay * 1.5, 30.0) # back off, cap at 30s
raise TimeoutError(f"job {job_id} did not finish within {timeout_s}s")
Почему присутствует каждая часть
- Опрос, а не webhook. Самая простая и надёжная интеграция — это периодический запрос статуса. Webhook лучше при большом масштабе, но требует публичного эндпоинта; опрос работает везде.
- Экспоненциальная задержка с верхним пределом. Ранние опросы дешёвы и часты; поздние интервалы растут. Верхний предел не даёт интервалу выйти из-под контроля на длинных задачах. Начинайте примерно с пяти секунд и постепенно увеличивайте.
- Явные терминальные состояния. Успех — это одно состояние; ошибка и отмена — другие. Всё остальное считайте «продолжать ждать», но никогда не ждите бесконечно.
- Реальный дедлайн по времени. Генерация видео медленнее текстовой. Выберите щедрый общий тайм-аут, соответствующий терпению вашего продукта, и по его истечении завершайтесь с ошибкой, а не зацикливайтесь навсегда.
- Логирование статусов. Печатайте или записывайте каждый переход состояния. Когда что-то идёт не так, это первое, что вам нужно.
Опрос из shell
Для быстрой ручной проверки при отладке достаточно одного вызова curl:
curl -sS "$HIAPI_BASE_URL/v1/videos/generations/$JOB_ID" \
-H "Authorization: Bearer $HIAPI_API_KEY"
Повторяйте его каждые несколько секунд или оберните в небольшой цикл while, пока статус не сменится на терминальный. Сверьте точные имена полей и путей со справочником API HiAPI — жизненный цикл стабилен, но именно детали на проводе являются источником истины.
Как только poll_job вернёт результат, ответ должен содержать ссылку на готовое видео. Именно это вы скачаете дальше.
Скачивание и проверка результата
Задача завершена, и ответ указывает на сгенерированный файл. Скачивание — это обычный HTTP GET, но сделайте две вещи правильно: потоково запишите его на диск и проверьте, что вы получили.
Получение видео
import os
from urllib.parse import urlparse
def download_video(job: dict, out_dir: str = "outputs") -> str:
video_url = job["output"]["url"] # confirm the field path in the API reference
os.makedirs(out_dir, exist_ok=True)
parsed = urlparse(video_url)
ext = os.path.splitext(parsed.path)[1] or ".mp4"
dest = os.path.join(out_dir, f"{job['id']}{ext}")
with requests.get(video_url, stream=True, timeout=120) as r:
r.raise_for_status()
with open(dest, "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 16):
f.write(chunk)
size = os.path.getsize(dest)
if size == 0:
raise IOError(f"downloaded file is empty: {dest}")
print(f"saved {dest} ({size} bytes)")
return dest
Пояснения:
- Потоковая передача по частям. Видеофайлы большие; загружать их в память через
r.contentрасточительно и может привести к сбою на хостах с ограниченными ресурсами. - Сохраняйте расширение, чтобы плееры и нижестоящие инструменты распознавали формат контейнера.
- Именуйте по ID задачи. Это уникально, отслеживаемо и позволяет избежать конфликтов при пакетных запусках.
- Отклоняйте пустые файлы. Скачивание нулевого размера — это неудачное скачивание, даже если код состояния показывает 200.
Если URL видео подписан или имеет ограничение по времени, скачивайте сразу после завершения задачи, а не сохраняйте URL на потом.
Проверка, что это настоящее видео со звуком
То, что файл существует, не означает, что он пригоден. Проверьте его:
- Воспроизведите локально в медиаплеере и подтвердите наличие изображения и звука.
veo-3.1-fast/image-to-videoгенерирует нативный звук, поэтому тихий результат — тревожный сигнал, который стоит расследовать до того, как он дойдёт до пользователей. - Проверьте контейнер с помощью
ffprobe, если у вас установлен ffmpeg:
ffprobe -hide_banner outputs/job_abc123.mp4
В выводе ищите видеопоток и аудиопоток, а также разумную длительность. Это также самый быстрый способ поймать усечённый файл.
- Выполните базовую проверку первого кадра. Он должен быть похож на ваше входное изображение. Если это не так, прежде чем винить модель, заподозрите URL изображения или поле, через которое вы его передавали.
Как только скачивание проверено, сохраните файл в постоянное хранилище и заодно запишите ID задачи. Это сопоставление позволяет в дальнейшем отлаживать, перезапускать и сверять биллинг.
Подводные камни и проверки перед масштабированием
Большинство проблем интеграции с асинхронными видео-API — не проблемы модели. Это проблемы конвейера. Вот что следует проверить в первую очередь.
Ввод изображения
- Действительно ли изображение доступно? URL, работающий в вашем браузере, может требовать аутентификации, блокировать хотлинки или истекать. Предпочитайте стабильные, публично читаемые URL.
- Это поддерживаемый формат? Если в справочнике API не указано иное, придерживайтесь распространённых форматов, таких как JPEG и PNG.
- Правильно ли содержимое? Первый кадр задаёт весь фрагмент. Низкокачественное или нерелевантное изображение даст разочаровывающее видео, которое не исправить никакой настройкой промпта.
Структура запроса
- Имена полей и типы. Проверьте по справочнику API HiAPI для
veo-3.1-fast/image-to-video. Фрагменты, скопированные с других платформ, не сработают — эндпоинт принадлежит HiAPI, а имена полей чувствительны к регистру. - Тип содержимого. Отправляйте
Content-Type: application/jsonи фактическое JSON-тело, а не данные формы. - Идентификатор модели. Используйте полную строку
veo-3.1-fast/image-to-video; усечённые имена возвращают на вид несвязанные ошибки.
Тайм-ауты и повторы
- Отдельные тайм-ауты для каждого этапа. Отправка, запросы опроса и скачивание файла заслуживают собственных. Единый глобальный тайм-аут либо слишком тугой для скачивания, либо слишком свободный для проверок статуса.
- Повторяйте безопасно. Отправку можно повторять при временных сетевых ошибках и ответах 5xx, но только если вы можете определить, была ли задача фактически создана — иначе вы можете дважды списать средства и дважды сгенерировать. Опрос и скачивание идемпотентны и допускают свободные повторы.
- При ограничении частоты делайте паузу. Соблюдайте ответ и замедляйтесь, а не бомбите эндпоинт.
Поведение при опросе
- Никогда не опрашивайте в плотном цикле. Это тратит квоту и выглядит как злоупотребление.
- Всегда имейте условие завершения. Дедлайн, который выбрасывает исключение, лучше задачи, застрявшей в памяти.
- Записывайте время каждого перехода состояния. Оно нужно для вывода задержки.
Эксплуатационная гигиена
- Держите ключи API на стороне сервера. Никогда не отправляйте их в браузер и не встраивайте в мобильные приложения.
- Храните ID задачи вместе с каждым артефактом. Это ваш связующий ключ между логами, файлами и записями использования.
- Проверяйте скачивание перед публикацией. Проверяйте размер и в идеале потоки. Пустой или немой файл, дошедший до пользователей, обходится гораздо дороже, чем неудачное скачивание, которое вы повторите.
- Не предполагайте путь к полю. Расположение
outputв ответе задачи — как раз та деталь, которая может меняться — читайте его из справочника API, а не из руководства, включая это.
Прежде чем создавать тикет по модели, проверьте этот список по порядку. В большинстве случаев исправлением оказывается URL, имя поля или отсутствие паузы.
Вот и весь цикл: отправка с изображением первого кадра и промптом, опрос задачи до завершения, затем скачивание и проверка видео с нативным звуком. Начните со страницы модели veo-3.1-fast/image-to-video на HiAPI, подтвердите актуальные поля запроса, а затем перенесите две функции выше в свой сервис.
Похожие статьи
Все статьи →-
Руководство
Как вызвать 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
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата