Przejdź do treści głównej

createTask — i co dalej? Odpytywanie czy Webhook dla asynchronicznych zadań generowania

Modele zwracają taskId. Wybierz odpytywanie lub Webhook i wznów zadanie po przekroczeniu czasu oczekiwania bez podwójnej opłaty.

Autor
SpicyAPI Engineering
Opublikowano
Czas czytania
7 min czytania
Zaktualizowano
Kręta ścieżka z okrągłymi punktami kontrolnymi obok prostej złotej drogi prowadzącej do świecącej kuli.

Wywołujesz createTask i otrzymujesz taskId zamiast obrazu. Teraz potrzebujesz wyniku bez utrzymywania otwartego połączenia przez kilka minut, płacenia dwa razy po przekroczeniu czasu oczekiwania ani utraty zadania po ponownym uruchomieniu procesu.

W skrócie:

  • Szybkie modele obrazu w skrypcie: dodaj ?wait=30 do createTask, a często całkowicie pominiesz odpytywanie.
  • Skrypty, praca lokalna, brak publicznego serwera: odpytuj zadanie w pętli z ograniczoną liczbą iteracji, tak jak w przykładzie poniżej.
  • Wszystko, na co czeka użytkownik, wideo lub duża liczba zadań: użyj callBackUrl, sprawdź podpis, szybko potwierdź odbiór i przetwarzaj zdarzenia z kolejki.
  • Produkcja: połącz obie metody. Callback jest szybką ścieżką, a okresowa kontrola stanów wychwytuje przypadki, w których callback nie dociera.

Przy bezpośrednim wywołaniu API ?wait=<seconds> (do 60) utrzymuje createTask otwarte do zakończenia zadania. Nadaje się to do modeli obrazu kończących pracę w kilka sekund, ale nie do wideo. callBackUrl (z wielkim B) to publiczny adres HTTPS odbierający wynik, a recordInfo to wywołanie stanu opakowane przez get_task w SDK. Dokumentacja zadań opisuje wszystkie trzy elementy.

Najpierw wypróbuj w Playground

Otwórz Playground seedream-5-0-pro. Wpisz krótki Prompt, ustaw Resolution na 1k, naciśnij Run model i odczytaj wynik w Output; History pokazuje wcześniejsze uruchomienia. Odpytywanie i Webhook automatyzują w aplikacji widoczne tu oczekiwanie; nie tworzą drugiego obrazu.

Wybierz sposób odbierania wyniku

Twoja aplikacjaZacznij odDlaczego
Lokalny skrypt lub sporadyczne przetwarzanie wsadoweOdpytywanie przez SDKNie musisz wdrażać publicznego odbiornika
Interaktywna aplikacja do obrazów lub wideoZweryfikowany WebhookReagujesz na koniec generowania bez utrzymywania osobnego oczekującego procesu dla każdego zadania
Usługa produkcyjnaWebhook i okresowe uzgadnianie stanuPominięty callback nie pozostawia przyjętego zadania bez obsługi

Wybierz odpytywanie, gdy zadań jest mało lub Twój komputer nie może odbierać publicznych wywołań HTTPS. Wybierz Webhook, gdy użytkownicy czekają w interaktywnej aplikacji lub długie zadania wideo blokowałyby procesy robocze.

Dla zadań z obrazem wejściowym proces przesyłania w SDK wykonuje /files/{fileId}/commit i zwraca URI spicy://; zobacz dokumentację mediów.

Uruchom jedno zadanie przez SDK

Zainstaluj spicyapi, ustaw SPICY_API_KEY i uruchom przykład. Zachowaj map-image.json, aby po przerwaniu wznowić to samo zadanie. Jeśli celowo chcesz inny obraz, użyj nowej nazwy uruchomienia. Python SDK udostępnia metody API, a dokumentacja zadań obejmuje cały cykl życia.

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

Poprawnie odczytaj odpowiedź

Zadanie zawsze ma jeden z następujących stanów: queued, running, succeeded, failed lub expired. Tylko pierwsze dwa oznaczają, że nadal jest w toku. Zakończ więc pętlę, gdy stan nie jest ani queued, ani running, zamiast czekać wyłącznie na succeeded; w przeciwnym razie nieudane zadanie będzie odpytywane bez końca (starsze rekordy mogą też zawierać stan tylko do odczytu canceled). Link do wyniku znajduje się w output.assets[0].url. Przy bezpośrednim wywołaniu API odczytaj zadanie z obiektu data w opakowaniu odpowiedzi, a nie z jej korzenia. Przyjętego zadania nie można anulować. Opłata jest naliczana wyłącznie za succeeded; failed i expired zwykle zwalniają zablokowaną kwotę.

Co przekroczenie czasu oczekiwania oznacza dla aplikacji

HTTP 202 oznacza przyjęcie zadania, a nie zakończenie generowania. Lokalny limit czasu przerywa oczekiwanie, ale nie anuluje przyjętego zadania. Zachowaj jego ID i wznów je zamiast kupować kolejne generowanie. Termin zwrócony dla zadania wyznacza granicę odzyskiwania, a nie przewiduje czasu renderowania.

  • Utracona odpowiedź na wysłanie: zachowaj żądanie i jego klucz, aby podczas odzyskiwania znaleźć pierwotne zadanie.
  • Generowanie nie powiodło się: pokaż błąd modelu i pozwól użytkownikowi świadomie wybrać kolejną próbę.
  • Generowanie zakończone, plik wciąż oczekuje: nadal czekaj na to samo zadanie; obraz lub wideo jest jeszcze przygotowywany do udostępnienia.

Nowe żądanie otrzymuje nowy klucz idempotencji. Przy odzyskiwaniu tego samego żądania klucz i dane wejściowe pozostają bez zmian. Dokumentacja idempotencji opisuje 24-godzinne okno ponawiania żądania.

Użyj Webhook jako szybkiej ścieżki

Wysyłaj zdarzenia zakończenia do backendu aplikacji, a następnie aktualizuj interfejs użytkownika zwykłym kanałem powiadomień. Callback nie jest bezpośrednią wiadomością do przeglądarki użytkownika.

Odbiornik powinien wykonać cztery czynności:

  1. Zweryfikować zdarzenie oficjalnym SDK i surową treścią żądania.
  2. Potwierdzić, że zadanie należy do pracy obsługiwanej przez Twoją aplikację.
  3. Trwale zapisać zdarzenie i usunąć duplikaty przed potwierdzeniem odbioru.
  4. Umieścić kopiowanie wyniku i aktualizację aplikacji w kolejce, niezależnie od odpowiedzi HTTP.

Wybierz tę metodę, gdy: masz już backend i chcesz szybko otrzymywać informacje o zakończeniu. Poszukaj innej metody, gdy: to krótki lokalny skrypt bez publicznego odbiornika; odpytywanie jest prostsze.

Osobno sprawdzaj zakończenie zadania i dostarczenie mediów. Poprawnie sformowane zdarzenie może opisywać nieudane zadanie, a udane zadanie może wymagać obsługi plików, zanim aplikacja uzna wynik za gotowy. Dokumentacja Webhook zawiera zasady weryfikacji i dostarczania.

Zachowaj okresowe uzgadnianie stanu

Zapisuj ID każdego przyjętego zadania. Okresowo wracaj do zadań, których aplikacja jeszcze nie rozstrzygnęła, szczególnie po wdrożeniu, awarii sieci lub zmianie sekretu podpisywania. Przekazuj odzyskany wynik do tego samego idempotentnego mechanizmu obsługi zakończenia co Webhook, aby galeria nie otrzymała tego samego pliku dwa razy.

Zachowaj nierozstrzygnięte opłaty w dzienniku aż do zakończenia rozliczenia. Jeśli utracisz lokalne zapisy, historia zadań dla bieżącego klucza pozwala odzyskać ID; integracja produkcyjna opisuje tę ścieżkę.

Skopiuj wyniki przed ich wygaśnięciem

Linki do gotowych wyników są tymczasowe. Kopiuj pliki do pamięci, którą kontrolujesz, z nagłówkiem żądania User-Agent i nazwą pliku zgodną ze zwróconym formatem. Nieudane pobieranie jest powodem do odzyskania istniejącego wyniku, a nie ponownego generowania.

Terminy znajdziesz w artykule o przechowywaniu i dostarczaniu mediów, a proces kopiowania w artykule o trwałym przechowywaniu.

Decyzja

Dla małego skryptu zacznij od odpytywania przez SDK. Dodaj zweryfikowany Webhook, gdy masz usługę interaktywną, i utrzymuj okresowe kontrole na potrzeby odzyskiwania. Zapisane ID zadania łączy wszystkie trzy ścieżki: odbierają wynik jednego generowania zamiast wysyłać zadania zastępcze.

Aby wykonywać więcej prac jednocześnie, dodaj wysyłanie partii z ograniczeniami. Dla pierwszej pary obraz–wideo użyj przewodnika na start.

Powierz wywołanie Agentowi

Użyj Agenta, jeśli ma przygotować dane wejściowe i zwrócić wynik, a Ty chcesz zatwierdzać cenę i wybory twórcze.

  • CLI: zapisz {"prompt": "a folded paper map on a wooden table, overhead", "resolution": "1k", "output_format": "png"} jako input.json, a następnie użyj npx @spicyapi/cli tasks create --model bytedance/seedream-5.0-pro/text-to-image --input-file input.json --wait. CLI prosi o potwierdzenie ceny; zachowaj zwrócone ID zadania do odzyskiwania.
  • MCP: poproś asystenta o użycie spicyapi_task_create dla bytedance/seedream-5.0-pro/text-to-image, a następnie spicyapi_task_wait. MCP server prosi o potwierdzenie ceny przed utworzeniem zadania.
  • Skill: zainstaluj przez npx skills add spicyapi-ai/spicy-skill, a potem poproś $spicyapi o wykonanie tego samego procesu i zatrzymanie się na Twoje zatwierdzenie. Skill korzysta ze skonfigurowanego połączenia CLI lub MCP.

Także w językach English · 日本語 · 한국어 · Deutsch · Français · Español · Português (Brasil) · Русский · Italiano

Wypróbuj samodzielnie

Płacisz tylko za to, co uruchomisz — bez planów i subskrypcji.

Zrobione w MiniMax H3 · ByteDance Seedance 2.0 Fast