Ir al contenido principal

createTask, ¿y ahora qué? Sondeo o Webhooks para tareas de generación asíncronas

Los modelos de imagen y vídeo devuelven una taskId. Elige sondeo o Webhooks y retoma la tarea tras un timeout sin pagar dos veces.

Autor
SpicyAPI Engineering
Publicado
Lectura
8 min de lectura
Actualizado
Una ruta sinuosa con puntos de control circulares junto a un camino dorado directo hacia una esfera luminosa.

Has llamado a createTask y has recibido una taskId en lugar de una imagen. Ahora necesitas obtener el resultado sin mantener una conexión abierta durante minutos, pagar dos veces tras un timeout ni perder la tarea cuando se reinicie tu proceso.

La versión breve:

  • Modelos de imagen rápidos en un script: añade ?wait=30 a createTask y, a menudo, podrás prescindir del sondeo.
  • Scripts, desarrollo local, sin servidor público: consulta la tarea con un bucle limitado como el del ejemplo siguiente.
  • Cualquier trabajo que haga esperar al usuario, vídeo o grandes volúmenes: utiliza callBackUrl, verifica la firma, confirma la recepción rápidamente y procesa los eventos desde una cola.
  • Producción: combina ambos métodos. El callback es la vía rápida; una revisión periódica del estado recupera los callbacks que nunca llegan.

En la API directa, ?wait=<seconds> (hasta 60) mantiene abierto createTask hasta que termine la tarea. Es adecuado para modelos de imagen que acaban en segundos, pero no para vídeo. callBackUrl (con B mayúscula) es la dirección HTTPS pública que recibe el resultado, y recordInfo es la llamada de estado que encapsula get_task en el SDK. La referencia de tareas explica las tres opciones.

Pruébalo primero en Playground

Abre el Playground de seedream-5-0-pro. Escribe un Prompt breve, establece Resolution en 1k, pulsa Run model y consulta el resultado en Output; History muestra las ejecuciones anteriores. El sondeo y los Webhooks automatizan para tu aplicación la espera que ves; no crean una segunda imagen.

Elige cómo recibir el resultado

Tu aplicaciónEmpieza conMotivo
Script local o lotes ocasionalesSondeo mediante el SDKNo necesitas desplegar un receptor público
Aplicación interactiva de imagen o vídeoWebhook verificadoReacciona cuando termina la generación sin mantener un proceso en espera por tarea
Servicio en producciónWebhook más revisión de conciliaciónUn callback perdido no deja desatendida una tarea aceptada

Elige sondeo cuando haya pocas tareas o tu equipo no pueda recibir llamadas HTTPS públicas. Elige Webhooks cuando los usuarios esperen en una aplicación interactiva o las tareas de vídeo largas vayan a ocupar los procesos de trabajo.

Para tareas con imágenes de entrada, el flujo de carga del SDK ejecuta /files/{fileId}/commit y devuelve una URI spicy://; consulta la documentación de medios.

Ejecuta una tarea con el SDK

Instala spicyapi, configura SPICY_API_KEY y ejecuta el ejemplo. Conserva map-image.json para retomar la misma tarea tras una interrupción. Si quieres una imagen deliberadamente distinta, usa un nombre de ejecución nuevo. El Python SDK proporciona los métodos de la API; la referencia de tareas cubre el ciclo de vida completo.

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"])

Interpreta correctamente la respuesta

Una tarea siempre está en uno de estos estados: queued, running, succeeded, failed o expired. Solo los dos primeros indican que sigue en curso. Por eso, termina el bucle cuando el estado no sea queued ni running, en vez de esperar únicamente a succeeded; de lo contrario, consultarás indefinidamente una tarea fallida (los registros antiguos también pueden mostrar canceled, un estado de solo lectura). El enlace al resultado está en output.assets[0].url. Si llamas a la API directa, lee la tarea del objeto data del contenedor de respuesta, no de la raíz. Una tarea aceptada no se puede cancelar, y solo se cobra succeeded; failed y expired normalmente liberan el importe retenido.

Qué significa un timeout para tu aplicación

HTTP 202 significa que se ha aceptado una tarea, no que haya terminado la generación. Un timeout local detiene la espera; no cancela la tarea aceptada. Conserva su ID y retómala en lugar de comprar otra generación. El plazo devuelto por la tarea marca el límite de recuperación, no una predicción del tiempo de renderizado.

  • Se perdió la respuesta al envío: conserva la solicitud y su clave para que la recuperación pueda encontrar la tarea original.
  • La generación falló: muestra el error del modelo y deja que el usuario decida expresamente si quiere otro intento.
  • La generación terminó, pero el archivo está pendiente: sigue esperando en esa tarea; la imagen o el vídeo aún se está preparando para su entrega.

Una solicitud nueva recibe una clave de idempotencia nueva. Al recuperar la misma solicitud, mantén la clave y la entrada sin cambios. La referencia de idempotencia describe el plazo de 24 horas para repetir una solicitud.

Usa Webhooks como vía rápida

Envía los eventos de finalización al backend de tu aplicación y después actualiza la interfaz por tu canal habitual de notificaciones. Un callback no es un mensaje directo al navegador del usuario.

El receptor debe hacer cuatro cosas:

  1. Verificar el evento con el SDK oficial y el cuerpo original de la solicitud.
  2. Confirmar que la tarea corresponde a un trabajo de tu aplicación.
  3. Guardar el evento de forma persistente y deduplicarlo antes de confirmar su recepción.
  4. Encolar por separado la copia del resultado y la actualización de la aplicación, sin incluirlas en la respuesta HTTP.

Elígelo cuando: ya tengas un backend y quieras recibir avisos de finalización rápidamente. Busca otra opción cuando: sea un script local breve sin receptor público; el sondeo es más sencillo.

Comprueba por separado la finalización de la tarea y la entrega del archivo. Un evento bien formado puede describir una tarea fallida, mientras que una tarea completada puede requerir gestionar los archivos antes de que tu aplicación la marque como lista. La documentación de Webhooks recoge las condiciones de verificación y entrega.

Mantén una revisión de conciliación

Guarda el ID de cada tarea aceptada. Revisa periódicamente las tareas que tu aplicación no haya resuelto, sobre todo después de un despliegue, una caída de red o un cambio del secreto de firma. Pasa el resultado recuperado por el mismo manejador de finalización idempotente que usa un Webhook, para que la galería no reciba el mismo archivo dos veces.

Mantén los cobros sin resolver en el registro hasta que termine la liquidación. Si pierdes los registros locales, el historial de tareas de la clave actual permite recuperar los ID; la integración en producción explica esta vía.

Copia los resultados antes de que caduquen

Los enlaces a resultados listos son temporales. Copia los archivos a un almacenamiento que controles, con una cabecera User-Agent en la solicitud y un nombre de archivo que coincida con el formato devuelto. Un fallo de descarga es motivo para recuperar el resultado existente, no para volver a generarlo.

Consulta los plazos en retención y entrega de medios y el flujo de copia en almacenamiento duradero.

La decisión

Empieza con sondeo mediante el SDK para un script pequeño. Añade Webhooks verificados cuando tengas un servicio interactivo y conserva la revisión periódica para recuperar tareas. El ID guardado conecta las tres vías: recogen una única generación en lugar de enviar tareas de sustitución.

Para ejecutar más trabajos a la vez, añade un despacho de lotes limitado. Para tu primer par de imagen y vídeo, utiliza la guía de inicio.

Deja que un Agent gestione la llamada

Utiliza un Agent si quieres que prepare las entradas y devuelva el resultado mientras tú apruebas el precio y las decisiones creativas.

  • CLI: guarda {"prompt": "a folded paper map on a wooden table, overhead", "resolution": "1k", "output_format": "png"} como input.json y utiliza npx @spicyapi/cli tasks create --model bytedance/seedream-5.0-pro/text-to-image --input-file input.json --wait. La CLI pide confirmar el precio; conserva el ID de tarea devuelto para la recuperación.
  • MCP: pide a tu asistente que use spicyapi_task_create para bytedance/seedream-5.0-pro/text-to-image y, después, spicyapi_task_wait. El MCP server solicita confirmar el precio antes de crear la tarea.
  • Skill: instala con npx skills add spicyapi-ai/spicy-skill y pide a $spicyapi que ejecute el mismo flujo y se detenga para solicitar tu aprobación. El Skill usa una conexión CLI o MCP configurada.

También en English · 日本語 · 한국어 · Deutsch · Français · Português (Brasil) · Русский · Italiano · Polski

Pruébalo tú mismo

Pagas solo lo que ejecutas: sin planes ni suscripciones.

Hecho con MiniMax H3 · ByteDance Seedance 2.0 Fast