HiAPI
Блог

Руководство

Happyhorse API для видео из изображения: рабочие примеры curl и Python (hiapi)

Jun 27, 2026
Happyhorse API для видео из изображения: рабочие примеры curl и Python (hiapi)

Вы хотите превратить статичное изображение в связный короткий видеоролик прямо из своего кода. Модель happyhorse-1.1/image-to-video на hiapi делает именно это: передайте URL изображения и необязательный промпт движения, и через несколько секунд вы получите MP4 в разрешении 720p или 1080p. Это руководство — самый короткий рабочий путь: настоящие тела запросов, настоящие сообщения об ошибках, на curl и Python — чтобы вы могли запуститься сегодня, а не бороться с именами полей.

Что нужно подготовить перед началом

  • Ключ API hiapi. Получите его в консоли hiapi — он выглядит как sk-... и передаётся в заголовке Authorization: Bearer ....
  • Доступный URL изображения (публичный HTTPS). Локальные файлы не подходят; модель сама загружает этот URL.
  • Намерение движения, выраженное текстом (необязательно, но рекомендуется). Чем чётче глаголы, тем лучше эффект движения.

Модель тарифицируется по секундам видео, цены указаны на странице тарифов hiapi; остальной каталог моделей — в hiapi models — загляните в оба места, прежде чем наращивать объёмы.

Минимальный рабочий запрос (curl)

Каждое видео на hiapi проходит через асинхронную конечную точку /v1/tasks: сначала вы отправляете POST-запрос на создание, получаете taskId, а затем либо опрашиваете GET /v1/tasks/{taskId}, либо принимаете обратный вызов по завершении.

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

curl -X POST "https://api.hiapi.ai/v1/tasks" \
  -H "Authorization: Bearer sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-1.1/image-to-video",
    "input": {
      "image_urls": ["https://example.com/your-still.jpg"],
      "prompt": "the cat slowly turns its head toward the camera and blinks",
      "resolution": "1080p",
      "duration": 5
    }
  }'

Успешный ответ выглядит так:

{
  "code": 200,
  "data": { "taskId": "tk-hiapi-01KW3D..." },
  "message": "success"
}

Теперь опрашивайте результат (раз в 5 секунд достаточно — большинство клипов готовы в течение двух минут):

curl "https://api.hiapi.ai/v1/tasks/tk-hiapi-01KW3D..." \
  -H "Authorization: Bearer sk-your-key"

Пока идёт работа, вы получите "status": "handling". По завершении вы получите:

{
  "code": 200,
  "data": {
    "status": "success",
    "model": "happyhorse-1.1/image-to-video",
    "output": [
      {
        "type": "video",
        "url": "https://temp.hiapi.ai/.../01KW....mp4",
        "expireAt": 1783131245
      }
    ],
    "taskId": "tk-hiapi-01KW3D..."
  }
}

Этот url — то, что нужно скачать, и скачать следует сразу, потому что expireAt — это Unix-временная метка, отмечающая, когда временное хранилище удалит файл.

Python: опрос до успеха

Это полный, рабочий скрипт — подставьте свой ключ и URL изображения.

import os
import time
import requests

API = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_KEY"]  # sk-...

def create_video(image_url: str, prompt: str, duration: int = 5,
                 resolution: str = "1080p") -> str:
    """Submit an image-to-video task. Returns the taskId."""
    r = requests.post(
        API,
        headers={"Authorization": f"Bearer {TOKEN}",
                 "Content-Type": "application/json"},
        json={
            "model": "happyhorse-1.1/image-to-video",
            "input": {
                "image_urls": [image_url],          # exactly one URL
                "prompt": prompt,                   # optional
                "resolution": resolution,           # "720p" or "1080p"
                "duration": duration,               # int, 3..15
            },
        },
        timeout=60,
    )
    body = r.json()
    if body.get("code") != 200:
        raise RuntimeError(f"create failed: {body}")
    return body["data"]["taskId"]

def wait_for_video(task_id: str, timeout_s: int = 600,
                   poll_s: int = 5) -> str:
    """Block until the task succeeds, fails, or times out. Returns the MP4 URL."""
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(
            f"{API}/{task_id}",
            headers={"Authorization": f"Bearer {TOKEN}"},
            timeout=30,
        )
        task = r.json().get("data") or {}
        status = task.get("status")
        if status == "success":
            return task["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"task failed: {task.get('error')}")
        time.sleep(poll_s)
    raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")

def download(url: str, path: str) -> None:
    with requests.get(url, stream=True, timeout=120) as r:
        r.raise_for_status()
        with open(path, "wb") as f:
            for chunk in r.iter_content(1 << 16):
                f.write(chunk)

if __name__ == "__main__":
    task_id = create_video(
        image_url="https://example.com/your-still.jpg",
        prompt="the dancer spins once and ends in a pose",
        duration=5,
        resolution="1080p",
    )
    print("submitted:", task_id)
    mp4_url = wait_for_video(task_id)
    download(mp4_url, "out.mp4")
    print("saved out.mp4")

Всё вместе — около 50 строк, и это весь готовый к продакшену интерфейс: без SDK, без очередей в фоне, без протокола стриминга. Запустите через HIAPI_KEY=sk-... python video.py.

Продакшен: обратный вызов вместо опроса

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

Добавьте объект callback на корневом уровне тела запроса (не внутри input):

curl -X POST "https://api.hiapi.ai/v1/tasks" \
  -H "Authorization: Bearer sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-1.1/image-to-video",
    "input": {
      "image_urls": ["https://example.com/still.jpg"],
      "prompt": "slow zoom out from the subject",
      "resolution": "1080p",
      "duration": 6
    },
    "callback": {
      "url": "https://your-app.example.com/webhooks/hiapi",
      "when": "final"
    }
  }'

Когда задача достигает терминального состояния, hiapi отправит POST на ваш URL тот же объект задачи, который вы могли бы получить опросом (status, output[].url, error и т. д.). when: "final" означает, что вы получите обратный вызов только об успехе или неудаче — без шума о прогрессе.

Несколько правил, которые сэкономят реальное время отладки:

  • Сделайте webhook идемпотентным. Один и тот же taskId может прийти дважды (сетевые повторы — это реальность). Перед обработкой проверьте эту задачу в базе данных.
  • Переразместите MP4 внутри обработчика. URL, который выдаёт hiapi, указывает на временное хранилище с полем expireAt; при первом получении сразу перелейте файл в свой bucket, иначе потеряете его.
  • Подтверждайте быстро. Быстро верните 2xx, а тяжёлую работу выполняйте асинхронно. Медленные webhook рискуют повторами.
  • Используйте опрос как подстраховку. Оберните taskId в отложенную задачу и опросите через 10 минут на случай потери webhook. Если вы сталкиваетесь с этим постоянно, посмотрите причины, по которым обратный вызов задачи hiapi может не срабатывать, чтобы узнать типичные причины.

Сообщения об ошибках, которые вы встретите

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

Ситуация HTTP Форма тела ответа
Неверный или отозванный ключ 401 {"error":{"code":"permission_denied","message":"This API key cannot use the selected model...","type":"hiapi_error"}}
Отсутствует обязательное поле 400 {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: image_urls: missing required field \"image_urls\""}
resolution недопустим 400 ... resolution: value must be one of '720p', '1080p'
Длительность вне диапазона 400 ... duration: minimum: got 2, want 3 / duration: maximum: got 30, want 15
Неверная длина image_urls 400 ... image_urls: maxItems: got 2, want 1 (или minItems: got 0, want 1)
Неизвестное поле на корневом уровне или внутри input 400 ... additional properties 'identity_preserving' not allowed
Сама задача завершилась неудачей после отправки 200 (GET задачи) и data.status == "fail" вместе с data.error.{code,message}

Ошибки аутентификации и валидации означают, что повторять не нужно; все остальные случаи (5xx платформы, сетевые таймауты при опросе, временный task fail с кодом, допускающим повтор) подходят для повторных попыток с небольшой задержкой.

Настройка вывода

Реально влияют четыре параметра — всё остальное (seed, aspect_ratio, fps, cfg_scale, negative_prompt) сейчас отклоняется как неизвестные поля. Оставайтесь в этом наборе:

  • image_urls — один HTTPS URL. Соотношение сторон и композиция вывода следуют за этим изображением.
  • prompt — краткое описание движения ("she smiles and tilts her head"). Кинематографичные промпты, движимые глаголами, побеждают списки прилагательных.
  • resolution — "720p" для прототипирования и миниатюр, "1080p" для сдачи.
  • duration — целое число секунд от 3 до 15. Длинные клипы стоят больше времени и денег; выбирайте минимальную длительность, которая рассказывает историю.

Для проектов, которым нужны начальный и конечный кадры, см. happyhorse-1.1 reference-to-video. Для чистого текст-в-видео без исходного изображения есть happyhorse-1.1 text-to-video — второе руководство. Просматривайте остальное в hiapi models catalogue или в разделе рецептов блога.

FAQ

Можно ли передать два изображения, чтобы задать первый и последний кадры? На happyhorse-1.1/image-to-video — нет, image_urls принимает не более одного элемента (maxItems: 1). Если это нужно, используйте happyhorse-1.1/reference-to-video или создайте решение на основе happyhorse-1.1 reference-to-video.

Какое разрешение у MP4, который я фактически получу? Вывод следует соотношению сторон входного изображения и заданному вами флагу resolution. "1080p" даёт более высокий из двух; "720p" быстрее и дешевле для тестов.

Почему мой ключ работает на других моделях, а здесь я получаю 401 permission_denied? Некоторые модели ограничены по ключу. Проверьте страницу модели в консоли hiapi — если happyhorse-1.1/image-to-video нет в вашем списке разрешённых, сгенерируйте новый ключ или обратитесь в поддержку, указав request_id из ошибки.

Есть ли потоковый/SSE-ответ? Нет. Каждая видеомодель использует асинхронный шаблон задач из этой статьи. Выбирайте опрос или обратный вызов в зависимости от того, контролируете ли вы сервер.

Где увидеть фактическую стоимость каждого клипа? На странице тарифов hiapi. Стоимость считается по секундам видео, поэтому переданный вами duration напрямую определяет затраты — держите клипы для разработки и тестов на duration: 3, чтобы экономить бюджет.

URL вывода перестаёт работать через день. Это ожидаемое поведение — URL указывает на временное хранилище, а ответ содержит Unix-временную метку expireAt. Всегда скачивайте MP4 в момент успешного завершения задачи (или транслируйте его через свой CDN).

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

Все статьи →

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

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

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