Zum Hauptinhalt springen

Ihre KI-API liefert einen Asset-Schlüssel. So speichern Sie die Medien dauerhaft

Ergebnisse bleiben etwa 14 Tage, hochgeladene Referenzen 1 Tag. Erfahren Sie, was wann abläuft und wie Sie Dateien per Callback dauerhaft sichern.

Autor
SpicyAPI Engineering
Erschienen
Lesedauer
12 Min. Lesezeit
Aktualisiert
Eine Hand schiebt eine leuchtende Fotokarte aus einer temporären Station mit Sanduhr in einen Laufwerksschacht neben einem Schnittmonitor

Auch eine erfolgreiche Generierung kann in Ihrem Produkt zu einem defekten Bild führen, wenn Sie die temporäre Auslieferungs-URL speichern, statt die Datei zu kopieren. Signierte Links laufen nach Minuten ab; die zugrunde liegende API-Ausgabe bleibt etwa zwei Wochen gespeichert.

Eine Medien-API liefert dieselbe Datei unter mehreren Identitäten: als Eingabereferenz, als Schlüssel der generierten Ausgabe und als signierte URL, über die sich die Bytes einige Minuten lang abrufen lassen. Für jede gilt eine eigene Ablaufzeit, und keine ist eine dauerhafte Adresse. Dieser Leitfaden nennt die genauen Zeitfenster bei SpicyAPI und zeigt, wie Sie wertvolle Ergebnisse in Ihren eigenen Speicher kopieren. Die Aufbewahrungseinstellungen können diese Zeitfenster verkürzen.

Zuerst im Playground ausprobieren

Öffnen Sie die Z-Image-Seite für Text-zu-Bild und melden Sie sich an:

  1. Geben Sie eine kurze Szene in Prompt ein und wählen Sie ein Aspect ratio.
  2. Klicken Sie auf Run model. Das Ergebnis erscheint unter Output.
  3. Laden Sie das Bild herunter und speichern Sie es an einem Ort, den Sie kontrollieren.
  4. Öffnen Sie die gespeicherte Datei später erneut. Sie lässt sich ohne die Seite oder deren temporären Ergebnislink öffnen. Genau das automatisiert der weitere Leitfaden für den Produktivbetrieb.

Das Wichtigste

  • Bei Abschluss in einem Worker kopieren. Große Downloads gehören nicht in die Callback-Anfrage.
  • Signierte Links privat halten. Wer einen besitzt, erhält vorübergehend Zugriff auf die Datei.
  • Eigene Asset-ID und Auslieferungs-URL bereitstellen. Ein Task-Datensatz kann seine Medien überleben.

Was wann abläuft

WasGültigkeitsdauerWas am Ende geschieht
Upload-Ticket (uploadUrl)Etwa 20 Minuten; PUT und Commit müssen beide innerhalb dieses Zeitfensters abgeschlossen seinBei einer Antwort wegen eines abgelaufenen Tickets ist ein neues Ticket nötig; ein ausgelasteter Commit kann auch 409 zurückgeben
Bestätigte Referenz (spicy://f/fil_...)1 Tag ab Commit, bis zum expiresAt aus der Commit-AntwortURI wird für neue Tasks und Wiederholungen abgelehnt
Ergebnislink (output.assets[].url)Etwa 20 Minuten, nie über die Ablaufzeit der Medien hinausSpeicher antwortet mit 403; lesen Sie den Task erneut, um einen neuen Link zu erhalten
Generiertes Bild, Video oder AudioEtwa 14 Tage ab Abschluss (kürzer, wenn Sie es so einstellen)Gelöscht; kein Link mehr ausstellbar (410 von download-url)
Prompt-Text und Ergebnisdateipfade im Task30 Tageinput und output werden geleert; der Task-Datensatz bleibt
Task-Datensatz (ID, Modell, Status, Kosten, Zeitstempel)Unbefristet gespeichertWeiter abfragbar, jedoch ohne Inhalt

Kurzfilmmedien, die innerhalb eines Spicy Studio-Projekts entstehen, haben ein eigenes längeres Zeitfenster von etwa 60 Tagen; für Generierungen über API, SDK und Playground gilt die oben genannte Obergrenze von 14 Tagen. Die Aufbewahrung generierter Medien lässt sich auch pro Anfrage oder Konto verkürzen, wie im Artikel zu den Aufbewahrungseinstellungen beschrieben. Sie können diese Obergrenzen nur verkürzen, nie verlängern.

Die 14 Tage beginnen mit dem Abschluss, nicht mit der Einreichung. Vor dem Abschluss ist der Zeitstempel vorläufig und wird beim Abschluss neu gesetzt.

„Etwa“ ist bewusst gewählt. Die Speicherbereinigung erfolgt über eine Lebenszyklusregel und kann bis zu einen Tag hinter dem Stichtag liegen. Diese Verzögerung gibt Ihnen aber keine zusätzliche Zeit: Sobald das Zeitfenster schließt, wird kein Downloadlink mehr ausgestellt.

Eine Datei, vier Darstellungen

text
local reference image
  │
  ├─ POST /api/v1/common/upload-url       → upload ticket (about 20 min)
  ├─ PUT to the returned uploadUrl         → temporary object
  ├─ POST /api/v1/files/{fileId}/commit    → spicy://f/fil_...  (usable 1 day)
  ├─ POST /api/v1/jobs/createTask          → task
  └─ terminal callback or recordInfo
       └─ output.assets[]                  → key + url + expiresAt (about 20 min)
            └─ stream bytes to your storage → your asset ID and delivery URL

SDKs, CLI und Playground übernehmen die Upload-Schritte, sodass Sie sie selten selbst implementieren müssen. Jede Darstellung erfüllt eine Aufgabe. Das Ticket erlaubt innerhalb seiner Gültigkeit einen direkten Schreibzugriff; der Commit fixiert die akzeptierten Bytes. Die spicy://-URI erlaubt einem Task, einen Tag lang auf eine bestätigte, kontogebundene Eingabe zu verweisen. Der Ausgabe-key identifiziert ein generiertes Ergebnis. Die url erlaubt vorübergehend einen Lesezugriff. Ihre eigene Asset-ID ist die einzige langlebige Identität, die Ihr Produkt bereitstellen sollte.

Der Upload der Referenz zu SpicyAPI ist kostenlos; Sie bezahlen den Generierungs-Task, der sie verwendet. Das Aktualisieren eines Links zu einer vorhandenen Ausgabe verursacht keine weitere Generierungsgebühr. Ist die Ausgabe verloren und entscheiden Sie sich für eine neue Generierung, fallen für diesen neuen Task eigene Modellkosten an. Planen Sie Speicher, Anfragen und Datentransfer Ihres dauerhaften Buckets separat nach dem Tarif Ihres Speicheranbieters ein.

Eingaben: hochladen und den Ablauf nach 1 Tag einplanen

Bewahren Sie das ursprüngliche Referenzbild, -video oder -audio in Ihrem eigenen Speicher auf. Laden Sie eine lokale Eingabe über SDK, CLI oder Playground hoch und verwenden Sie ihre bestätigte URI erneut, solange sie gültig ist. Laden Sie sie nach Ablauf bei Bedarf erneut hoch; die temporäre URI ist kein Archiv.

Drei Möglichkeiten, einem Modell eine Eingabe zu übergeben:

  • Öffentliche HTTPS-Adresse. Funktioniert dort, wo das Modellfeld eine URL akzeptiert, sofern diese die Datei selbst zurückgibt. Ein Cloud-Drive-, Album- oder Social-Media-Link liefert eine Webseite, und der Task schlägt mit invalid_asset fehl; laden Sie stattdessen die Datei herunter und anschließend hoch.
  • Kleines eingebettetes Bild. JPEG, PNG, WebP oder GIF als base64-Daten-URI, jeweils bis zu 1 MiB.
  • Upload. Für lokale Dateien. Bilder (JPEG, PNG, WebP, GIF) bis zu 10 MiB; Audio und Video in WAV, MP3, WebM, MP4 oder MOV bis zu 90 MiB und 600 Sekunden. Ein Modell kann niedrigere Grenzen haben; prüfen Sie daher das Feldlimit auf seiner Seite. Im TypeScript SDK gibt await client.uploadFile("./reference.png") die spicy://-URI als file.uri zurück.

Stellen Sie den SpicyAPI-Schlüssel niemals im Browser bereit; lassen Sie Ihren Server Upload-Tickets ausstellen. Die Mediendokumentation erläutert die Browserintegration und sämtliche Grenzen.

Ausgaben: So sieht ein fertiges Ergebnis aus

Ein abgeschlossener Task und eine abrufbare Datei sind unterschiedliche Zustände:

  • Bereit: Kopieren Sie die Datei in Ihren Speicher und erfassen Sie Task-ID, Format und Größe.
  • Ausstehend: Behalten Sie denselben Task und prüfen Sie erneut; kaufen Sie keine weitere Generierung, um die Datei zu erhalten.
  • Nicht verfügbar: Die Plattformkopie ist verschwunden, und Warten bringt sie nicht zurück. Verwenden Sie Ihre gespeicherte Kopie; andernfalls generieren Sie erneut, was regulär berechnet wird. Nur ein anfänglicher Speicherfehler ohne ausgelieferte Dateien bleibt unberechnet.

Temporäre Links erlauben ihrem Besitzer Zugriff. Halten Sie sie aus öffentlichen Seiten und Analysesystemen heraus; holen Sie einen aktuellen Link, wenn der Kopier-Worker bereit ist.

Die Grenze der Aufbewahrung

Ein Task-Datensatz, Ausgabeschlüssel oder aktualisierter Downloadlink bewahrt die Bytes nicht auf. Kopieren Sie sie vor der Medien-Ablaufzeit.

Nach Ablauf des Zeitfensters meldet recordInfo den Wert contentState: "expired"; input und output werden spätestens nach 30 Tagen geleert. Wenn Sie den Task-Inhalt selbst vernichtet haben, lautet der Zustand purged. Der Task-Zustand expired bedeutet etwas anderes: Die Generierung hat ihr Zeitlimit überschritten und nichts erzeugt. Zeigen Sie beides in Ihrer Oberfläche nicht mit derselben Bezeichnung an, denn ein Fall erfordert eine Wiederholung, während der andere dadurch nicht wiederhergestellt werden kann.

Setzen Sie die Kopierfrist deutlich vor den Stichtag. Kopieren Sie beim ersten Erfolgsereignis und führen Sie zusätzlich einen Abgleichjob aus, der erfolgreiche Tasks ohne dauerhaftes Asset auflistet und Alarm schlägt, solange dem Ergebnis noch Tage bleiben. Tag 14 ist eine Reserve zur Wiederherstellung, kein Zeitplan. Verkürzen Konto- oder Anfrageeinstellungen die Aufbewahrung, kann outputsExpireAt deutlich früher als nach 14 Tagen liegen. Richten Sie Alarme daher nach diesem Feld aus, niemals nach einer Konstante. Eine Kontoeinstellung kann auch rückwirkend wirken: Eine Verkürzung der Frist für Prompt-Text löscht die Ergebnisse bereits abgeschlossener Tasks früher als ihr ursprünglich angegebenes outputsExpireAt. Laden Sie alles, was Sie behalten möchten, vor dem Ändern der Kontoeinstellungen herunter und rechnen Sie damit, dass der Abgleichjob solche Tasks als verloren meldet, statt als Pipelinefehler.

Eine Callback-Pipeline für Wiederholungen und große Videos

In einer Anwendung prüfen Sie das Abschlussereignis, speichern es dauerhaft und stellen den Kopierauftrag vor der Antwort in eine Warteschlange. Gestalten Sie das Kopieren idempotent, damit ein wiederholtes Ereignis keinen weiteren Galerieeintrag erzeugt. Warnen Sie vor unkopierten Ergebnissen, bevor ihre zugesagte Ablaufzeit erreicht ist.

Dieser eigenständige Worker speichert die Dateien eines vorhandenen Tasks in einem privaten lokalen Verzeichnis. Installieren Sie spicyapi, setzen Sie SPICY_API_KEY, TASK_ID und optional ARCHIVE_DIR, und führen Sie ihn aus. Er erzeugt keine Generierung. Legen Sie das Verzeichnis auf dauerhaftem Speicher ab und beziehen Sie es in Ihre Sicherungsplanung ein; eine kurzlebige Serverfestplatte ist kein dauerhaftes Archiv.

python
import hashlib
import json
import os
from pathlib import Path
import tempfile
import urllib.request
from spicyapi import SpicyClient, output_assets

client = SpicyClient()
task_id = os.environ["TASK_ID"]
root = Path(os.environ.get("ARCHIVE_DIR", "media-archive"))
root.mkdir(parents=True, exist_ok=True, mode=0o700)
task = client.get_task(task_id)
if task["state"] != "succeeded":
    raise RuntimeError("Resume the existing task before archiving it.")
for index, asset in enumerate(output_assets(task)):
    if asset.get("pending") or asset.get("unavailable") or not asset.get("url"):
        raise RuntimeError("Asset is not ready; retain the task ID.")
    request = urllib.request.Request(asset["url"], headers={"User-Agent": "SpicyAPI-Blog-Example/1.0"})
    temporary = None
    try:
        with urllib.request.urlopen(request, timeout=300) as response:
            mime = response.headers.get_content_type()
            suffix = {"image/png": ".png", "image/jpeg": ".jpg", "image/webp": ".webp",
                      "video/mp4": ".mp4", "video/webm": ".webm", "audio/mpeg": ".mp3", "audio/wav": ".wav"}.get(mime)
            if response.status != 200 or suffix is None:
                raise RuntimeError("Unexpected response format; do not guess an extension.")
            digest, size = hashlib.sha256(), 0
            with tempfile.NamedTemporaryFile(dir=root, delete=False) as output:
                temporary = Path(output.name)
                while chunk := response.read(1024 * 1024):
                    output.write(chunk)
                    digest.update(chunk)
                    size += len(chunk)
        if not size or (asset.get("bytes") and size != int(asset["bytes"])):
            raise RuntimeError("Empty or incomplete transfer.")
        filename = root / (digest.hexdigest() + suffix)
        temporary.replace(filename)
        record = {"taskId": task_id, "index": index, "file": filename.name,
                  "mime": mime, "bytes": size, "sha256": digest.hexdigest()}
        (root / (digest.hexdigest() + ".json")).write_text(json.dumps(record, indent=2))
        print(filename)
    finally:
        if temporary is not None:
            temporary.unlink(missing_ok=True)

Für die Auslieferung aus einem Objektspeicher streamen Sie in ein privates Zwischenobjekt und geben es erst nach vollständiger Übertragung frei. Die Medien- und Webhook-Dokumentation erklären die Aktualisierung von Ergebnissen und authentifizierte Ereignisse. Behalten Sie Polling als Abgleichpfad für verpasste Callbacks bei.

Ihr dauerhaftes Asset sollte den Generierungsweg verbergen

Nach dem Kopieren hat das Objekt, das Ihr Produkt ausliefert, seine eigene Identität:

text
asset_01k...                     database identity
generated/job_.../....mp4        private storage key
https://media.example.com/a/...  controlled delivery URL

Halten Sie den Bucket privat und liefern Sie über Ihr eigenes CDN, einen authentifizierten Medienendpunkt oder eigene kurzlebige Links aus. Verwenden Sie eine signierte SpicyAPI-URL nicht als öffentliche URL. So bleiben temporäre Links und Speicherdetails aus HTML, Protokollen und Exporten heraus. Sie können Zugriffsregeln oder Domains ändern, ohne den Task-Verlauf neu zu schreiben, und ein Nutzer-Asset über Ihren eigenen Datensatz löschen. Bewahren Sie die Herkunft privat auf: ursprüngliche Task-ID, ursprünglicher Asset-Schlüssel, Inhaltstyp, Größe, Kopierzeitpunkt und Zielschlüssel.

Fehlerfälle und die richtige Wiederherstellung

FehlerfallBeobachtungRichtige Wiederherstellung
Upload-Ticket vor Abschluss abgelaufen oder unbestätigte Datei in einem Task verwendetUpload oder Commit wird abgelehnt, oder die Task-Erstellung verweigert die ReferenzNeues Ticket anfordern und erneut hochladen; bei 409/429 wegen eines ausgelasteten Commits hingegen denselben Commit wiederholen
Gespeicherte spicy://-URI am nächsten Tag verwendet400 bei der Task-Erstellung oder fehlgeschlagene WiederholungOriginal erneut hochladen; Originale im eigenen Speicher aufbewahren
Callback zweimal zugestelltZwei Worker starten denselben KopiervorgangNach request_id sowie nach Task-ID plus Asset-Index in Warteschlange und Ziel deduplizieren
Callback-Endpunkt ist langsamWiederholungen treffen während eines Downloads einSpeichern, einreihen und 2xx zurückgeben, bevor Medien übertragen werden
Ergebnislink läuft in der Warteschlange abAbruf der Quelle liefert 403Task erneut lesen, um eine neue url zu erhalten, und Streaming wiederholen
Asset zeigt pending: truekey und url sind leerEinige Sekunden warten und erneut abfragen
Asset zeigt unavailable: true oder download-url liefert 410Abgelaufen, gelöscht oder Speicherung fehlgeschlagenVerifizierte private Kopie verwenden; fehlt diese, Nutzer informieren und als neuen, kostenpflichtigen Task erneut generieren
Kopie fertig, aber Datenbankschreibvorgang fehlgeschlagenPrivates Objekt vorhanden, kein bereiter Asset-DatensatzVorhandenes Ziel verifizieren und Metadaten erneut schreiben; niemals eine gültige Kopie löschen oder neu generieren
Datenbank meldet bereit, aber Objekt fehltDefekte Seite oder 404 vom CDNDatenbankzeilen mit dem Bucket abgleichen, bevor „bereit“ gesetzt wird
Signierte URL steht in ProtokollenTemporäre Leseberechtigung offengelegtAbfragezeichenfolgen und Antwortinhalte schwärzen; Links laufen nach etwa 20 Minuten ab, können aber nicht widerrufen werden
Großes Video im Arbeitsspeicher gepuffertWorker startet neu oder läuft aus dem SpeicherMit begrenzter Parallelität und Rückstaukontrolle streamen

Checkliste für den Produktionsstart

  • Vor Ablauf wiederherstellen: Fehlende Kopien anhand der zugesagten Frist jedes Tasks überwachen.
  • Eigentum eindeutig halten: Private Assets nur an ihren Eigentümer ausliefern und Ergebnisse vor dem Rotieren der API-Schlüssel sichern.
  • Systemübergreifend löschen: Bucket, Auslieferungscache und Sicherungen in die Löschrichtlinie einbeziehen.

Häufige Fragen

Kann ich die in output.assets[].url zurückgegebene URL speichern?

Nur für den Kopiervorgang selbst. Speichern Sie Ihren eigenen Asset-Datensatz und holen Sie einen neuen Link, wenn Sie Bytes übertragen müssen.

Brauche ich weiterhin download-url?

Nur zum Aktualisieren eines Links anhand von taskId und key innerhalb des Aufbewahrungsfensters; bereite Assets enthalten bereits url und expiresAt.

Verlängert eine Linkaktualisierung die Aufbewahrungsdauer der Medien?

Nein. Ein neuer Link erneuert nur den Lesezugriff; das Objekt wird weiterhin zu retention.outputsExpireAt gelöscht.

Kann ich einem Modell statt eines Uploads eine öffentliche Bild-URL übergeben?

Ja, wenn das Modell-Schema in diesem Feld eine URL erlaubt, die Adresse die Datei selbst liefert und während der Task-Ausführung erreichbar bleibt. Nutzen Sie den Upload-Ablauf für lokale Dateien, größere Eingaben oder Inhalte ohne öffentliches Hosting.

Ich brauche nächste Woche dasselbe Referenzbild. Was soll ich tun?

Laden Sie es nächste Woche bei Bedarf erneut aus Ihrer eigenen Kopie hoch. Eine bestätigte Referenz gilt nur 1 Tag, kann aber während ihrer Gültigkeit mehrere Tasks bedienen, sofern sie nicht vorher gelöscht wird.

Soll ich das Ergebnis innerhalb der Callback-Anfrage kopieren?

Nein. Eine große Übertragung innerhalb der Anfrage überschreitet das Callback-Zeitlimit von 15 Sekunden und löst doppelte Zustellungen aus; ein Worker in der Warteschlange kann sicher wiederholen.

Was, wenn ich ein Ergebnis überhaupt nicht behalten möchte?

Dann kopieren Sie es nicht und lassen es ablaufen, oder verkürzen Sie die Aufbewahrung beziehungsweise vernichten den Task-Inhalt bei Bedarf. Diese Einstellungen werden in Uploads, Aufbewahrung und Auslieferung von KI-Medien und der Aufbewahrungsdokumentation beschrieben. Das Vernichten von Inhalten verändert niemals den berechneten Betrag.

Lassen Sie einen Agenten den Aufruf übernehmen

Verwenden Sie einen Agenten, um eine vorhandene Ausgabe wiederherzustellen, statt sie erneut zu erzeugen.

  • CLI: npx @spicyapi/cli tasks get "$TASK_ID" ruft den Task ab. Siehe CLI-Anleitung.
  • MCP: Fordern Sie über spicyapi_task_get die aktuelle Ausgabe an und speichern Sie die zurückgegebene Datei. Siehe MCP-Anleitung.
  • Skill: Installieren Sie npx skills add spicyapi-ai/spicy-skill und bitten Sie anschließend $spicyapi, das Ergebnis dieses Tasks im gewählten Verzeichnis zu archivieren. Siehe Skill-Anleitung.

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

Selbst ausprobieren

Sie zahlen nur für das, was Sie ausführen – ohne Tarif, ohne Abo.

Erstellt mit MiniMax H3 · ByteDance Seedance 2.0 Fast