Перейти к основному контенту

createTask — что дальше? Опрос или Webhook для асинхронных задач генерации

Модели возвращают taskId. Выберите опрос или Webhook и возобновляйте задачу после тайм-аута без повторной оплаты генерации.

Автор
SpicyAPI Engineering
Опубликовано
Время чтения
7 мин чтения
Обновлено
Извилистый путь с круглыми контрольными точками рядом с прямой золотистой дорожкой к светящейся сфере.

Вы вызвали createTask и получили taskId вместо изображения. Теперь нужно забрать результат, не удерживая соединение открытым несколько минут, не заплатив дважды после тайм-аута и не потеряв задачу при перезапуске процесса.

Кратко:

  • Быстрые модели изображений в скрипте: добавьте ?wait=30 к createTask, и часто опрос вообще не понадобится.
  • Скрипты, локальная разработка, нет публичного сервера: опрашивайте задачу в ограниченном цикле, как в примере ниже.
  • Любая задача, результата которой ждёт пользователь, видео или большой объём: используйте callBackUrl, проверяйте подпись, быстро подтверждайте получение и обрабатывайте события через очередь.
  • Продакшен: совмещайте оба способа. Обратный вызов — быстрый путь, а периодическая проверка состояния подхватывает случаи, когда он так и не пришёл.

При прямом обращении к API ?wait=<seconds> (до 60) удерживает вызов createTask открытым до завершения задачи. Это подходит моделям изображений, которые справляются за секунды, но не видео. callBackUrl (с заглавной B) — публичный HTTPS-адрес для получения результата, а recordInfo — вызов проверки состояния, который оборачивает метод get_task в SDK. Все три описаны в справочнике задач.

Сначала попробуйте в Playground

Откройте Playground seedream-5-0-pro. Введите короткий Prompt, установите Resolution в 1k, нажмите Run model и посмотрите результат в Output; History показывает предыдущие запуски. Опрос и Webhook автоматизируют для приложения именно то ожидание, которое вы видите; они не создают второе изображение.

Выберите способ получения результата

Ваше приложениеС чего начатьПочему
Локальный скрипт или редкая пакетная обработкаОпрос через SDKНе нужно развёртывать публичный обработчик
Интерактивное приложение для изображений или видеоПроверенный WebhookРеагируете на завершение генерации, не удерживая отдельный ожидающий процесс для каждой задачи
Производственный сервисWebhook и периодическая сверкаПропущенный обратный вызов не оставляет принятую задачу без дальнейшей обработки

Выбирайте опрос, если задач немного или ваш компьютер не может принимать публичные HTTPS-вызовы. Выбирайте Webhook, если пользователи ждут результата в интерактивном приложении или длительные видеозадачи займут рабочие процессы.

Для задач с изображением на входе процесс загрузки SDK выполняет /files/{fileId}/commit и возвращает URI spicy://; см. документацию по медиа.

Запустите одну задачу через SDK

Установите spicyapi, задайте SPICY_API_KEY и запустите пример. Сохраните map-image.json, чтобы возобновить ту же задачу после прерывания. Если намеренно хотите другое изображение, используйте новое имя запуска. Python SDK предоставляет методы API; справочник задач охватывает полный жизненный цикл.

python
import json
import os
import time
import uuid
from pathlib import Path
from spicyapi import SpicyClient, output_assets

client = SpicyClient()

def run(model, inputs, name):
    path = Path(name + ".json")
    request = {"model": model, "input": inputs}
    saved = json.loads(path.read_text()) if path.exists() else {"request": request, "key": str(uuid.uuid4())}
    if saved["request"] != request:
        raise ValueError("Changed input needs a new run name; preserve the old attempt.")
    def save():
        temporary = path.with_suffix(".tmp")
        temporary.write_text(json.dumps(saved))
        temporary.chmod(0o600)
        temporary.replace(path)
    if not saved.get("taskId"):
        if time.time() - saved.get("sentAt", time.time()) >= 23 * 3600:
            raise RuntimeError("Reconcile the saved attempt before submitting again.")
        if "quote" not in saved:
            saved["quote"] = client.quote_task(model=model, input_data=inputs)
            if input(f"Maximum ${saved['quote']['maxCharge']}. Create? [y/N] ") != "y":
                raise SystemExit("Stopped without creating this task.")
        saved.setdefault("sentAt", 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()
    print("Task:", saved["taskId"])
    for _ in range(360):
        task = client.get_task(saved["taskId"])
        if task["state"] not in {"queued", "running"} and task["state"] != "succeeded":
            raise RuntimeError(str(task.get("errorMessage", task["state"])))
        if task["state"] == "succeeded":
            assets = output_assets(task)
            if assets and assets[0].get("unavailable"):
                raise RuntimeError("Output unavailable; keep the task ID for reconciliation.")
            if assets and assets[0].get("url") and not assets[0].get("pending"):
                return assets[0]
        time.sleep(5)
    raise TimeoutError("Rerun the same saved attempt to resume; no new task is needed.")

asset = run("bytedance/seedream-5.0-pro/text-to-image", {
    "prompt": "a folded paper map on a wooden table, overhead", "resolution": "1k", "output_format": "png"
}, "map-image")
print(asset["url"])

Правильно прочитайте ответ

Задача всегда находится в одном из состояний: queued, running, succeeded, failed или expired. Только первые два означают, что работа ещё продолжается. Поэтому завершайте цикл, когда состояние уже не queued и не running, вместо ожидания только succeeded, иначе неудачная задача будет опрашиваться бесконечно (в старых записях также может встречаться доступное только для чтения состояние canceled). Ссылка на результат находится в output.assets[0].url. При прямом вызове API читайте задачу из объекта data в оболочке ответа, а не из корня ответа. Принятую задачу отменить нельзя, а плата списывается только за succeeded; при failed и expired зарезервированная сумма обычно освобождается.

Что тайм-аут означает для приложения

HTTP 202 означает, что задача принята, а не что генерация завершена. Локальный тайм-аут прекращает ожидание, но не отменяет принятую задачу. Сохраните её ID и возобновите её вместо покупки ещё одной генерации. Возвращённый срок задачи задаёт границу восстановления, а не прогнозирует время рендеринга.

  • Ответ на отправку потерян: сохраните запрос и его ключ, чтобы при восстановлении можно было найти исходную задачу.
  • Генерация не удалась: покажите ошибку модели и дайте пользователю осознанно выбрать ещё одну попытку.
  • Генерация успешна, файл ещё не готов: продолжайте ждать по той же задаче; изображение или видео ещё готовится к выдаче.

Новый запрос получает новый ключ идемпотентности. При восстановлении того же запроса сохраняйте ключ и входные данные без изменений. Справочник идемпотентности описывает 24-часовое окно повторного запроса.

Используйте Webhook для быстрого получения результата

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

Обработчик должен выполнить четыре действия:

  1. Проверить событие официальным SDK, используя исходное тело запроса.
  2. Убедиться, что задача относится к работе, которой управляет ваше приложение.
  3. Надёжно сохранить событие и устранить дубликаты до подтверждения получения.
  4. Поставить копирование результата и обновление приложения в очередь отдельно от HTTP-ответа.

Выбирайте этот способ, если: у вас уже есть бэкенд и нужны своевременные уведомления о завершении. Рассмотрите другой вариант, если: это короткий локальный скрипт без публичного обработчика; опрос проще.

Проверяйте завершение задачи и доставку медиа отдельно. Корректно сформированное событие может описывать неудачную задачу, а успешная задача может требовать обработки файлов, прежде чем приложение сообщит о готовности. Документация Webhook содержит правила проверки и доставки.

Сохраняйте периодическую сверку

Записывайте ID каждой принятой задачи. Периодически возвращайтесь к задачам, которые приложение ещё не разрешило, особенно после развёртывания, сбоя сети или смены секрета подписи. Пропускайте восстановленный результат через тот же идемпотентный обработчик завершения, что и Webhook, чтобы галерея не получила один файл дважды.

Храните незавершённые расчёты по оплате в журнале до окончания взаиморасчётов. Если локальные записи потеряны, история задач текущего ключа позволяет восстановить ID; этот путь описан в интеграции для продакшена.

Копируйте результаты до истечения срока

Ссылки на готовые результаты временные. Копируйте файлы в подконтрольное вам хранилище, с заголовком запроса User-Agent и именем файла, соответствующим возвращённому формату. Ошибка скачивания — повод восстановить существующий результат, а не генерировать его заново.

Сроки описаны в статье о хранении и доставке медиа, а процесс копирования — в статье о долговременном хранилище.

Решение

Для небольшого скрипта начните с опроса через SDK. Добавьте проверенные Webhook, когда появится интерактивный сервис, и сохраните периодическую сверку для восстановления. Сохранённый ID задачи объединяет все три пути: они получают результат одной генерации вместо отправки заменяющих задач.

Для большего числа одновременных работ добавьте ограниченную отправку пакетов. Для первой пары «изображение — видео» используйте руководство для начала работы.

Поручите вызов Agent

Используйте Agent, если хотите поручить ему подготовку входных данных и получение результата, а цену и творческие решения утверждать самостоятельно.

  • CLI: сохраните {"prompt": "a folded paper map on a wooden table, overhead", "resolution": "1k", "output_format": "png"} как input.json, затем используйте npx @spicyapi/cli tasks create --model bytedance/seedream-5.0-pro/text-to-image --input-file input.json --wait. CLI запрашивает подтверждение цены; сохраните возвращённый ID задачи для восстановления.
  • MCP: попросите помощника использовать spicyapi_task_create для bytedance/seedream-5.0-pro/text-to-image, затем spicyapi_task_wait. MCP server запрашивает подтверждение цены до создания задачи.
  • Skill: установите через npx skills add spicyapi-ai/spicy-skill, затем попросите $spicyapi выполнить тот же процесс и остановиться для вашего одобрения. Skill использует настроенное подключение CLI или MCP.

Другие языки English · 日本語 · 한국어 · Deutsch · Français · Español · Português (Brasil) · Italiano · Polski