Создайте изображение, утвердите его, затем анимируйте в короткий клип. Эти шаги повторяют наш тест синей кружки в октябре 2026 года. В руководстве используются изображение Z-Image за 0,010 $ и пять секунд MiniMax H3 в 768p за 0,185 $: 0,195 $ за одну попытку на каждом этапе, с выключенным расширением промпта для изображения. Сначала попробуйте ту же сцену в Playground; когда входные данные будут работать, используйте пример Python или поручите вызовы агенту.
Желаемый результат конкретен: кружка правильной формы на верстаке, пар уходит вправо, камера медленно приближается и в конце останавливается. Разворачивать модель или настраивать сервер GPU не нужно.
Попробуйте весь пример в Playground
Создайте аккаунт и пополните баланс, затем подтвердите электронную почту. Playground обрабатывает запрос; ключ API нужен только для кода и инструментов агента ниже.
1. Создайте начальное изображение
Откройте Z-Image: текст в изображение и используйте Playground. Вставьте этот промпт:
Photograph of a handmade blue ceramic mug of tea on a worn wooden workbench in a pottery studio, a thin curl of steam rising from the mug. Soft window light from the left, shallow depth of field, shelves of pots softly out of focus behind. The mug sits left of centre with empty bench to its right. Natural colours, no text, no logos.
Выберите 16:9, PNG, seed 42 и выключите расширение промпта. Проверьте указанную цену и нажмите Run model. Базовое изображение стоит 0,010 $; расширение увеличит цену до 0,016 $. При сравнении изменений промпта оставляйте seed 42 неизменным.
Откройте результат, прежде чем продолжать. Проверьте:
- Объект: одна кружка, одна ручка и правильная геометрия керамики.
- Возможность движения: видимый пар и пространство справа для его смещения.
- Композиция: кружка находится левее центра; полки остаются спокойным фоном.
- Лишние детали: нет случайных надписей, логотипов или дополнительных чашек.
Скачайте утверждённый PNG как image.png. Если кружка неверна, измените одно предложение и создайте новое изображение, прежде чем тратить деньги на видео. Каждое новое базовое изображение добавляет 0,010 $.
2. Анимируйте утверждённое изображение
Откройте MiniMax H3: изображение в видео, добавьте image.png в Input image и вставьте в Prompt:
Steam rises from the mug and drifts to the right. The camera pushes in slowly toward the mug, then holds. The mug, bench and shelves stay where they are. Quiet room, a faint ceramic clink.
Задайте Duration 5 секунд и Resolution 768p; проверьте цену и нажмите Run model. Этот клип стоит 0,185 $; выбор 2k обойдётся в 0,290 $.
Промпт разделяет движение пара, движение камеры и звук. Он просит оставить кружку на месте, а не описывает её заново. Если кружка перемещается по верстаку, упростите указание для камеры вместо добавления новых действий объекта. Медленный наезд приближает камеру; это не просьба двигать кружку.
3. Проверьте клип и выберите следующий дубль
Воспроизведите весь результат со звуком. Проверьте, что кружка не скользит и не меняет форму, камера приближается и останавливается, нет нежелательной склейки, а звук подходит тихой мастерской. Ожидаемый результат — MP4 примерно на пять секунд со звуковой дорожкой; сама возможность воспроизведения файла ещё не делает кадр пригодным.
Если изображение верно, но движение нет, сохраните утверждённое начальное изображение и измените промпт движения. Если начальное изображение неверно, сначала замените его. У H3 нет seed: генерация в 2k даёт новый дубль, движения в котором могут отличаться от понравившейся версии 768p.
Что получилось в тесте синей кружки
Изображение стоило 0,010 $ и пришло как PNG 1280 × 720. Запрос пятисекундного видео стоил 0,125 $ (в 480p, который больше не предлагается; тот же клип в 768p стоит 0,185 $) и вернул MP4 832 × 480 со звуковой дорожкой. Итого — 0,135 $; в 768p было бы 0,195 $.
Кружка оставалась на верстаке, пар двигался вверх и вправо, а наезд камеры был едва заметным. На изображении кружка располагалась лишь немного левее центра, а ближе к концу пар терял чёткость возле полки. Для более крупного предметного плана точнее задайте положение кружки в промпте изображения до анимации.
Почему эти две модели подходят для первой попытки
Z-Image даёт недорогое изображение для выбора объекта и композиции. H3 принимает это изображение и генерирует движение и звуковую дорожку. Входные данные различаются:
| Z-Image: текст в изображение | H3: изображение в видео | |
|---|---|---|
| ID модели | alibaba/z-image-turbo/text-to-image | minimax/h3/image-to-video |
| Обязательный ввод | prompt (от 1 до 1 000 символов) | prompt (до 7 000) и image_url |
| Используемые настройки | aspect_ratio (1:1, 4:3, 3:4, 16:9 или 9:16), output_format (только png), seed, enable_prompt_expansion | duration_seconds (от 4 до 15), resolution (768p или 2k) |
| Не поддерживается | любой другой формат вывода | seed и aspect_ratio: форму задаёт начальное изображение |
| Возвращает | один PNG | один MP4 со сгенерированной звуковой дорожкой |
| Цена | 0,010 $ за изображение | 0,037 $ за секунду в 768p |
Используйте начальное изображение PNG, JPEG, WebP или GIF: каждая сторона от 256 до 5 760 пикселей, соотношение сторон от 2:5 до 5:2, размер файла менее 30 MB. Загруженный PNG — самый простой вариант. Публичная ссылка должна возвращать само изображение; страница общего доступа облачного диска не является изображением на входе.
Выполните тот же пример из Python
Используйте Python 3.11 или новее, установите официальный пакет через python -m pip install spicyapi и обеспечьте доступ к утилите file. Задайте SPICY_API_KEY в своём терминале, сохраните код как blue-mug.py и выполните python blue-mug.py. Он запрашивает согласие на обоих платных этапах и делает паузу для проверки изображения. При возобновлении сохраняйте созданную папку запуска; выбирайте новый RUN_NAME только для намеренно новой попытки. Контракт API и параметры SDK описаны в документации SDK Python.
import hashlib
import json
import os
from pathlib import Path
import subprocess
import tempfile
import time
import urllib.request
import uuid
from spicyapi import SpicyClient, output_assets
# Change RUN_NAME for a deliberately new pair of paid generations.
folder = Path(os.getenv("RUN_NAME", "blue-mug-1"))
folder.mkdir(exist_ok=True, mode=0o700)
state_file = folder / "state.json"
state = json.loads(state_file.read_text()) if state_file.exists() else {}
identity = hashlib.sha256(os.environ["SPICY_API_KEY"].encode()).hexdigest()
if state.get("identity", identity) != identity:
raise RuntimeError("This saved run belongs to a different API key.")
state["identity"] = identity
client = SpicyClient()
def save() -> None:
temp = state_file.with_suffix(".tmp")
temp.write_text(json.dumps(state, indent=2))
temp.chmod(0o600)
temp.replace(state_file)
def run(stage: str, model: str, inputs: dict) -> dict:
request = {"model": model, "input": inputs}
if stage not in state:
state[stage] = {"request": request, "key": str(uuid.uuid4())}
saved = state[stage]
if saved["request"] != request:
raise RuntimeError("Input changed: choose a new RUN_NAME, not a new retry key.")
save() # The same request and key survive a lost create response.
if not saved.get("taskId"):
if "first_sent" in saved and time.time() - saved["first_sent"] >= 23 * 3600:
raise RuntimeError("Unknown acceptance: reconcile task history before retrying.")
if "quote" not in saved:
quote = client.quote_task(model=model, input_data=inputs)
if input(f"{stage}: quoted ${quote['estimatedCost']}. Create? [y/N] ") != "y":
raise SystemExit("No task created for this stage.")
saved["quote"] = quote
saved.setdefault("first_sent", time.time())
save()
quote = saved["quote"]
task = client.create_task(model=model, input_data=inputs,
idempotency_key=saved["key"],
quote_id=quote["quoteId"],
expected_cost=quote["estimatedCost"])
saved["taskId"] = task["taskId"]
save()
task_id = saved["taskId"]
print(stage, "task:", task_id)
deadline = time.monotonic() + 1200
while time.monotonic() < deadline:
task = client.get_task(task_id)
if task["state"] in {"failed", "canceled", "expired"}:
raise RuntimeError(f"{task_id}: {task.get('errorCode')} {task.get('errorMessage')}")
if task["state"] == "succeeded":
assets = output_assets(task)
if not assets or assets[0].get("unavailable"):
raise RuntimeError(f"{task_id}: no retrievable output; keep the task ID.")
asset = assets[0]
if not asset.get("pending") and asset.get("url"):
print("Charge:", task.get("cost"), "settled:", task.get("settled"))
return asset
time.sleep(5)
raise TimeoutError(f"Resume {task_id} by rerunning this file; do not start another task.")
def download(asset: dict, destination: Path, mime: str) -> None:
temporary = None
try:
request = urllib.request.Request(asset["url"], headers={"User-Agent": "SpicyAPI-Blog-Example/1.0"})
with urllib.request.urlopen(request, timeout=300) as response:
if response.status != 200 or response.headers.get_content_type() != mime:
raise RuntimeError("Unexpected download status or content type.")
with tempfile.NamedTemporaryFile(dir=folder, delete=False) as handle:
temporary = Path(handle.name)
while chunk := response.read(1024 * 1024):
handle.write(chunk)
size = temporary.stat().st_size
expected = int(asset.get("bytes") or 0)
detected = subprocess.check_output(["file", "-b", "--mime-type", str(temporary)], text=True).strip()
if not size or (expected and size != expected) or detected != mime:
raise RuntimeError("Incomplete or incorrectly formatted download.")
temporary.replace(destination) # An interrupted transfer leaves the old file alone.
finally:
if temporary is not None:
temporary.unlink(missing_ok=True)
image_input = {
"prompt": (
'Photograph of a handmade blue ceramic mug of tea on a worn wooden workbench '
'in a pottery studio, a thin curl of steam rising from the mug. Soft window '
'light from the left, shallow depth of field, shelves of pots softly out of '
'focus behind. The mug sits left of centre with empty bench to its right. '
'Natural colours, no text, no logos.'
),
"aspect_ratio": "16:9",
"output_format": "png",
"seed": 42,
"enable_prompt_expansion": False,
}
image_asset = run("image", "alibaba/z-image-turbo/text-to-image", image_input)
download(image_asset, folder / "image.png", "image/png")
if input(f"Open {folder / 'image.png'}. Is the mug/frame approved? [y/N] ") != "y":
raise SystemExit("Stopped before video generation.")
if not state.get("image_uri"):
state["image_uri"] = client.upload_file(str(folder / "image.png"))["uri"]
save()
video_input = {"image_url": state["image_uri"], "prompt": 'Steam rises from the mug and drifts to the right. The camera pushes in slowly toward the mug, then holds. The mug, bench and shelves stay where they are. Quiet room, a faint ceramic clink.',
"duration_seconds": 5, "resolution": "768p"}
video_asset = run("video", "minimax/h3/image-to-video", video_input)
download(video_asset, folder / "video.mp4", "video/mp4")
print("Play", folder / "video.mp4", "with sound and review it before using it.")Храните ключ API на своём сервере или контролируемом компьютере, никогда на публичной веб-странице или в мобильном приложении. Перед интеграцией другой модели проверяйте текущую доступность и допустимые входные данные на страницах моделей выше.
Поручите вызовы агенту, если так удобнее
Используйте Agent, если хотите поручить ему подготовку входных данных и получение результата, а цену и творческие решения утверждать самостоятельно. Лично проверьте начальное изображение до разрешения генерации видео.
- CLI: сохраните тот же входной объект как
input.jsonи используйтеnpx @spicyapi/cli tasks create --model alibaba/z-image-turbo/text-to-image --input-file input.json --wait. CLI подтверждает цену; сохраните возвращённый ID задачи для восстановления. Для клипа загрузите утверждённое изображение черезnpx @spicyapi/cli files upload image.png, затем создайтеminimax/h3/image-to-videoтем же способом, используя возвращённый URIspicy://какimage_url. - MCP: попросите помощника использовать
spicyapi_task_createдляalibaba/z-image-turbo/text-to-image, затемspicyapi_task_wait; для клипа добавьтеspicyapi_upload_fileдля утверждённогоimage.png, затемspicyapi_task_createсminimax/h3/image-to-video, 5 секундами, 768p и промптом движения выше. Сервер MCP запрашивает подтверждение цены до создания. - Skill: установите через
npx skills add spicyapi-ai/spicy-skill, затем попросите$spicyapiвыполнить тот же процесс и остановиться для вашего согласия. Skill использует настроенное соединение CLI или MCP.
Планируйте бюджет на попытки, а не только финальный клип
Оценки приведены в долларах США. Перед генерацией подтвердите текущую цену.
| Запрос | Примерная цена |
|---|---|
| Одно изображение Z-Image, PNG 16:9 | 0,010 $ |
| То же изображение с расширением промпта | 0,016 $ |
| H3, 4 s в 768p | 0,148 $ |
H3, 5 s в 768p (по умолчанию, если resolution не указан) | 0,185 $ |
| H3, 5 s в 2k | 0,290 $ |
| H3, 10 s в 768p | 0,370 $ |
| H3, 15 s в 2k | 0,870 $ |
- Длительность и разрешение: H3 стоит 0,037 $ или 0,058 $ за секунду в 768p или 2k.
- Неподдерживаемые сочетания: клип на 4 секунды в 2k отклоняется с ошибкой
40004. - Два черновика: одно изображение и два пятисекундных видео 768p стоят 0,380 $.
- Черновик и дубль для передачи: одно изображение, пятисекундная проверка в 768p и один пятисекундный дубль 2k стоят 0,010 $ + 0,185 $ + 0,290 $ = 0,485 $ с повторным использованием утверждённого изображения.
Деньги резервируются при принятии задачи и окончательно списываются по её завершении. Неудачные и просроченные задачи обычно освобождают резерв; некоторые отказы по содержимому оплачиваются согласно заявленной политике модели. При проверке списания смотрите фактический cost и статус settled задачи.
Исправляйте проблему на нужном этапе
| Симптом | Что изменить |
|---|---|
| У кружки две ручки или случайный текст | Исправьте промпт изображения и утвердите новое начальное изображение до генерации видео |
| Кружка движется, хотя вы хотели движение камеры | Сохраните изображение; запросите одно движение камеры и явно укажите, что кружка неподвижна |
| Видео хорошо в 768p, но новый дубль 2k отличается | Считайте его новым кадром и проверьте движение до принятия |
| Ссылка на изображение не работает | Загрузите файл или используйте прямой доступный URL изображения вместо страницы общего доступа |
Аккаунт возвращает 401 или 40310 | Проверьте ключ или завершите подтверждение электронной почты |
40301 / 40302 / 40303 | Проверьте разрешения модели, список разрешённых IP ключа или региональную доступность |
40201 / 40202 | Проверьте доступный баланс или лимит расходов аккаунта/ключа; сохраняйте запрос при сверке неудачной отправки |
Запрос отклоняет seed, aspect_ratio или output_format | Проверьте входные данные выбранной задачи; не копируйте поля Z-Image в H3 |
40004 | Измените несовместимое сочетание: 4 секунды в 2k |
40901 или конфликт идемпотентности | Получите новую оценку цены: если ID задачи не сохранён, удалите запись этого этапа в state.json и запустите снова. Если предыдущая попытка могла быть принята, проверьте список задач до создания чего-либо ещё; см. справочник ошибок |
429 или ошибка соединения | Сохраните папку запуска и ID задачи; не начинайте ещё одну платную попытку только ради восстановления результата |
Задача сообщает content_rejected или timeout | Прочитайте ошибку и списание, затем сознательно выберите изменённый промпт, другое исходное изображение или более короткий кадр |
| Генерация успешна, но результат ещё не готов | Возобновите ту же сохранённую задачу; не генерируйте другой клип ради скачивания |
Сохраните первый рабочий процесс небольшим
Когда кадр удаётся, выберите длительность и разрешение для передачи, затем создайте и проверьте этот дубль. Необязательное конечное изображение может направлять завершение через last_image_url H3; оно не гарантирует точный последний кадр или движение между кадрами.
Для приложения сохраняйте оба ID задач и храните утверждённые файлы в собственном хранилище. Сравнение опроса и Webhooks поможет выбрать получение результатов, хранение медиа — сохранить файлы, а пакетная генерация пригодится для множества кадров. Первый рубеж тот же: утверждённое изображение и клип, который действительно следует задуманному кадру.







