Vai al contenuto principale

createTask, e poi? Polling o Webhook per le attività di generazione asincrone

I modelli restituiscono una taskId. Scegli polling o Webhook e riprendi dopo un timeout senza pagare due volte la stessa generazione.

Autore
SpicyAPI Engineering
Pubblicato
Lettura
8 min di lettura
Aggiornato
Un percorso tortuoso con punti di controllo circolari accanto a una via dorata diretta verso una sfera luminosa.

Hai chiamato createTask e ricevuto una taskId invece di un’immagine. Ora ti serve il risultato senza tenere aperta una connessione per minuti, pagare due volte dopo un timeout o perdere l’attività quando il processo si riavvia.

In breve:

  • Modelli di immagine veloci in uno script: aggiungi ?wait=30 a createTask e spesso puoi evitare del tutto il polling.
  • Script, sviluppo locale, nessun server pubblico: interroga l’attività con un ciclo limitato come quello qui sotto.
  • Qualsiasi attività attesa da un utente, video o grandi volumi: usa callBackUrl, verifica la firma, conferma rapidamente la ricezione e gestisci gli eventi da una coda.
  • Produzione: usa entrambi. Il callback è la via rapida; una verifica periodica degli stati recupera i callback che non arrivano mai.

Nell’API diretta, ?wait=<seconds> (fino a 60) tiene aperto createTask finché l’attività non termina. È adatto ai modelli di immagine che finiscono in pochi secondi, ma non ai video. callBackUrl (con B maiuscola) è l’indirizzo HTTPS pubblico che riceve il risultato, mentre recordInfo è la chiamata di stato incapsulata da get_task nell’SDK. La documentazione di riferimento delle attività descrive tutti e tre.

Prova prima nel Playground

Apri il Playground di seedream-5-0-pro. Inserisci un Prompt breve, imposta Resolution su 1k, premi Run model e leggi il risultato in Output; History elenca le esecuzioni precedenti. Il polling e i Webhook automatizzano per la tua applicazione l’attesa che vedi; non creano una seconda immagine.

Scegli come ottenere il risultato

La tua applicazioneParti daPerché
Script locale o elaborazione occasionale in batchPolling tramite SDKNon devi distribuire un ricevitore pubblico
Applicazione interattiva per immagini o videoWebhook verificatoReagisci quando la generazione termina senza tenere un processo in attesa per ogni attività
Servizio in produzioneWebhook e verifica di riconciliazioneUn callback perso non lascia senza seguito un’attività accettata

Scegli il polling quando le attività sono poche o il tuo computer non può ricevere chiamate HTTPS pubbliche. Scegli i Webhook quando gli utenti attendono in un’applicazione interattiva o lunghe attività video terrebbero occupati i processi di lavoro.

Per le attività con immagini in ingresso, il flusso di caricamento dell’SDK esegue /files/{fileId}/commit e restituisce un URI spicy://; consulta la documentazione dei media.

Esegui un’attività con l’SDK

Installa spicyapi, imposta SPICY_API_KEY ed esegui l’esempio. Conserva map-image.json per riprendere la stessa attività dopo un’interruzione. Per un’immagine volutamente diversa, usa un nuovo nome di esecuzione. Il Python SDK fornisce i metodi dell’API; la documentazione di riferimento delle attività copre l’intero ciclo di vita.

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

Leggi correttamente la risposta

Un’attività si trova sempre in uno di questi stati: queued, running, succeeded, failed o expired. Solo i primi due indicano che è ancora in corso. Termina quindi il ciclo quando lo stato non è né queued né running, invece di aspettare solo succeeded, altrimenti continuerai a interrogare all’infinito un’attività fallita (i record più vecchi possono mostrare anche lo stato di sola lettura canceled). Il link al risultato si trova in output.assets[0].url. Se chiami l’API diretta, leggi l’attività dall’oggetto data dell’involucro della risposta, non dalla radice. Un’attività accettata non può essere annullata e solo succeeded viene addebitato; failed ed expired normalmente liberano l’importo trattenuto.

Cosa significa un timeout per la tua applicazione

HTTP 202 significa che un’attività è stata accettata, non che la generazione è terminata. Un timeout locale interrompe l’attesa; non annulla l’attività accettata. Conserva il suo ID e riprendila invece di acquistare un’altra generazione. La scadenza restituita dall’attività delimita il periodo di recupero, non prevede il tempo di rendering.

  • Risposta all’invio persa: conserva la richiesta e la sua chiave per permettere al recupero di trovare l’attività originale.
  • Generazione fallita: mostra l’errore del modello e lascia che l’utente scelga consapevolmente un altro tentativo.
  • Generazione riuscita, file in attesa: continua ad aspettare quella stessa attività; l’immagine o il video è ancora in preparazione per la consegna.

Una nuova richiesta riceve una nuova chiave di idempotenza. Per recuperare la stessa richiesta, mantieni invariati chiave e input. La documentazione di riferimento dell’idempotenza descrive la finestra di 24 ore per ripetere la richiesta.

Usa i Webhook per la via rapida

Invia gli eventi di completamento al backend della tua applicazione, poi aggiorna l’interfaccia tramite il tuo abituale canale di notifica. Un callback non è un messaggio diretto al browser dell’utente.

Il ricevitore deve fare quattro cose:

  1. Verificare l’evento con l’SDK ufficiale e il corpo originale della richiesta.
  2. Confermare che l’attività appartenga a un lavoro gestito dalla tua applicazione.
  3. Salvare l’evento in modo persistente e deduplicarlo prima di confermarne la ricezione.
  4. Accodare la copia dell’output e l’aggiornamento dell’applicazione separatamente dalla risposta HTTP.

Sceglilo quando: hai già un backend e vuoi aggiornamenti tempestivi sul completamento. Valuta un’altra soluzione quando: si tratta di un breve script locale senza ricevitore pubblico; il polling è più semplice.

Verifica separatamente il completamento dell’attività e la consegna dei media. Un evento ben formato può descrivere un’attività fallita, mentre un’attività riuscita può richiedere la gestione dei file prima che la tua applicazione la indichi come pronta. La documentazione dei Webhook contiene le regole di verifica e consegna.

Mantieni una verifica di riconciliazione

Salva l’ID di ogni attività accettata. Ricontrolla periodicamente le attività non ancora risolte dalla tua applicazione, soprattutto dopo una distribuzione, un’interruzione di rete o una rotazione del segreto di firma. Fai passare un risultato recuperato dallo stesso gestore di completamento idempotente usato per un Webhook, così la galleria non riceverà due volte lo stesso file.

Mantieni nel registro gli addebiti non risolti finché la liquidazione non termina. Se perdi i record locali, la cronologia delle attività della chiave attuale permette di recuperare gli ID; l’integrazione in produzione descrive questo percorso.

Copia i risultati prima che scadano

I link agli output pronti sono temporanei. Copia i file in uno spazio di archiviazione che controlli, usando un header di richiesta User-Agent e un nome di file corrispondente al formato restituito. Un download fallito è un motivo per recuperare il risultato esistente, non per rigenerarlo.

Consulta conservazione e consegna dei media per le scadenze e archiviazione duratura per il flusso di copia.

La decisione

Parti dal polling tramite SDK per uno script piccolo. Aggiungi Webhook verificati quando hai un servizio interattivo e mantieni la verifica periodica per il recupero. L’ID salvato collega tutti e tre i percorsi: raccolgono una sola generazione invece di inviare attività sostitutive.

Per più lavori simultanei, aggiungi un invio di batch con limiti. Per la tua prima coppia immagine-video, usa la guida introduttiva.

Lascia che un Agent gestisca la chiamata

Usa un Agent se vuoi che prepari gli input e restituisca il risultato mentre tu approvi il prezzo e le scelte creative.

  • CLI: salva {"prompt": "a folded paper map on a wooden table, overhead", "resolution": "1k", "output_format": "png"} come input.json, poi usa npx @spicyapi/cli tasks create --model bytedance/seedream-5.0-pro/text-to-image --input-file input.json --wait. La CLI richiede la conferma del prezzo; conserva l’ID restituito per il recupero.
  • MCP: chiedi al tuo assistente di usare spicyapi_task_create per bytedance/seedream-5.0-pro/text-to-image, poi spicyapi_task_wait. Il MCP server chiede conferma del prezzo prima della creazione.
  • Skill: installa con npx skills add spicyapi-ai/spicy-skill, poi chiedi a $spicyapi di eseguire lo stesso flusso e fermarsi per la tua approvazione. Lo Skill usa una connessione CLI o MCP configurata.

Anche in English · 日本語 · 한국어 · Deutsch · Français · Español · Português (Brasil) · Русский · Polski

Provalo tu stesso

Paghi solo quello che esegui: nessun piano, nessun abbonamento.

Creato con MiniMax H3 · ByteDance Seedance 2.0 Fast