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=30acreateTaske 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 applicazione | Parti da | Perché |
|---|---|---|
| Script locale o elaborazione occasionale in batch | Polling tramite SDK | Non devi distribuire un ricevitore pubblico |
| Applicazione interattiva per immagini o video | Webhook verificato | Reagisci quando la generazione termina senza tenere un processo in attesa per ogni attività |
| Servizio in produzione | Webhook e verifica di riconciliazione | Un 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.
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:
- Verificare l’evento con l’SDK ufficiale e il corpo originale della richiesta.
- Confermare che l’attività appartenga a un lavoro gestito dalla tua applicazione.
- Salvare l’evento in modo persistente e deduplicarlo prima di confermarne la ricezione.
- 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"}comeinput.json, poi usanpx @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_createperbytedance/seedream-5.0-pro/text-to-image, poispicyapi_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$spicyapidi eseguire lo stesso flusso e fermarsi per la tua approvazione. Lo Skill usa una connessione CLI o MCP configurata.







