Vai al contenuto principale

La tua API AI restituisce una chiave risorsa. Ora conserva i media nel tempo

I risultati restano circa 14 giorni, i riferimenti 1 giorno. Scopri le scadenze e copia i file nel tuo archivio tramite un callback.

Autore
SpicyAPI Engineering
Pubblicato
Lettura
13 min di lettura
Aggiornato
Una mano sposta una scheda fotografica luminosa da una base temporanea con clessidra a un vano disco accanto a un monitor di montaggio

Una generazione riuscita può comunque diventare un’immagine non disponibile nel tuo prodotto se salvi l’URL temporaneo di consegna invece di copiare il file. I link firmati scadono in pochi minuti; il risultato dell’API viene conservato per circa due settimane.

Un’API multimediale ti consegna lo stesso file con diverse identità: un riferimento di input, una chiave del risultato generato e un URL firmato che consente di recuperare i byte per qualche minuto. Ognuno scade secondo il proprio termine e nessuno è un indirizzo permanente. Questa guida indica le finestre esatte di SpicyAPI, poi mostra come copiare i risultati utili in uno spazio di archiviazione che controlli. I controlli di conservazione possono abbreviare queste finestre.

Prova prima nel Playground

Apri la pagina Z-Image da testo a immagine e accedi:

  1. Scrivi una breve scena in Prompt e scegli un Aspect ratio.
  2. Premi Run model. Il risultato compare sotto Output.
  3. Scarica l’immagine e salvala in uno spazio che controlli.
  4. Riapri il file salvato in seguito. Si apre senza la pagina né il suo link temporaneo al risultato: il resto della guida automatizza proprio questo in produzione.

Punti chiave

  • Copia al completamento, in un processo di lavoro. Tieni i download pesanti fuori dalla richiesta di callback.
  • Mantieni privati i link firmati. Chi ne possiede uno ottiene accesso temporaneo al file.
  • Esponi il tuo ID risorsa e il tuo URL di consegna. Un record di attività può sopravvivere ai suoi media.

Cosa scade e quando

ElementoDurataCosa succede alla scadenza
Ticket di caricamento (uploadUrl)Circa 20 minuti; PUT e conferma devono terminare entrambi entro questo intervalloUna risposta di ticket scaduto richiede un nuovo ticket; una conferma occupata può anche restituire 409
Riferimento confermato (spicy://f/fil_...)1 giorno dalla conferma, fino a expiresAt nella relativa rispostaURI rifiutato per nuove attività e nuovi tentativi
Link del risultato (output.assets[].url)Circa 20 minuti, mai oltre la scadenza del media stessoL’archiviazione risponde 403; rileggi l’attività per un link nuovo
Immagine, video o audio generatoCirca 14 giorni dal completamento (meno se lo imposti così)Eliminato; nessun link può essere emesso (410 da download-url)
Testo del prompt e percorsi dei file del risultato nell’attività30 giorniinput e output vengono svuotati; il record dell’attività rimane
Record dell’attività (ID, modello, stato, costo, timestamp)Conservato a tempo indeterminatoAncora consultabile, senza contenuto

I media dei cortometraggi creati in un progetto Spicy Studio hanno una propria finestra più lunga, di circa 60 giorni; le generazioni con API, SDK e Playground usano il limite di 14 giorni indicato sopra. Puoi anche ridurre la conservazione delle generazioni per richiesta o per account, come spiega l’articolo sui controlli di conservazione. Puoi solo abbreviare questi limiti, mai allungarli.

I 14 giorni decorrono dal completamento, non dall’invio. Prima che l’attività finisca, il timestamp è provvisorio e viene ricalcolato al completamento.

«Circa» è intenzionale. La pulizia dell’archiviazione segue una regola del ciclo di vita e può avvenire fino a un giorno dopo la scadenza, ma questo ritardo non ti dà tempo aggiuntivo: quando la finestra si chiude, non viene più emesso alcun link di download.

Un file, quattro rappresentazioni

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

SDK, CLI e Playground eseguono i passaggi di caricamento per te, quindi raramente devi scriverli a mano. Ogni rappresentazione ha una funzione. Il ticket autorizza una scrittura diretta entro la sua validità; la conferma fissa i byte accettati. L’URI spicy:// permette a un’attività di riferirsi per un giorno a un input confermato e limitato all’account. Il key di output identifica un risultato generato. L’url autorizza temporaneamente una lettura. Il tuo ID risorsa è l’unica identità duratura che il prodotto dovrebbe esporre.

Caricare il riferimento su SpicyAPI è gratuito; paghi l’attività di generazione che lo usa. Aggiornare un link a un output esistente non crea un altro addebito di generazione. Se il risultato è perso e scegli di generarlo di nuovo, la nuova attività avrà il proprio costo del modello. Prevedi separatamente archiviazione, richieste e trasferimenti del tuo bucket permanente secondo il piano del fornitore di archiviazione.

Input: carica e pianifica la scadenza di 1 giorno

Conserva l’immagine, il video o l’audio di riferimento originale nel tuo spazio di archiviazione. Carica un input locale tramite SDK, CLI o Playground e riutilizza l’URI confermato finché è valido. Ricaricalo quando ti serve dopo la scadenza; l’URI temporaneo non è il tuo archivio.

Tre modi per fornire un input a un modello:

  • Indirizzo HTTPS pubblico. Funziona dove il campo del modello accetta un URL, purché restituisca il file stesso. Un link a un disco cloud, un album o un social restituisce una pagina web e l’attività fallisce con invalid_asset; scarica il file e caricalo invece.
  • Piccola immagine incorporata. JPEG, PNG, WebP o GIF come URI di dati base64, fino a 1 MiB ciascuna.
  • Caricamento. Per file locali. Immagini (JPEG, PNG, WebP, GIF) fino a 10 MiB; audio e video WAV, MP3, WebM, MP4 o MOV fino a 90 MiB e 600 secondi. Un modello può accettare meno, quindi controlla il limite del campo sulla sua pagina. Nel TypeScript SDK, await client.uploadFile("./reference.png") restituisce l’URI spicy:// come file.uri.

Non esporre mai la chiave SpicyAPI nel browser; fai emettere i ticket di caricamento al tuo server. La documentazione dei media descrive l’integrazione nel browser e tutti i limiti.

Output: come si presenta un risultato completato

Un’attività completata e un file recuperabile sono stati diversi:

  • Pronto: copia il file nel tuo spazio di archiviazione e registra ID dell’attività, formato e dimensione.
  • In attesa: mantieni la stessa attività e controlla di nuovo; non acquistare un’altra generazione per ottenere il file.
  • Non disponibile: la copia della piattaforma non c’è più e aspettare non la farà tornare. Usa la tua copia salvata; altrimenti genera di nuovo, con la normale fatturazione. Solo un errore iniziale di archiviazione senza file consegnati non viene addebitato.

I link temporanei danno accesso a chi li possiede. Tienili fuori da pagine pubbliche e sistemi di analisi; ottieni un link aggiornato quando il processo di copia è pronto.

Il limite della conservazione

Un record di attività, una chiave di output o un link di download aggiornato non conserva i byte. Copiali prima della scadenza del media.

Quando la finestra si chiude, recordInfo riporta contentState: "expired", e input e output vengono svuotati al più tardi dopo 30 giorni. Se hai distrutto tu il contenuto dell’attività, lo stato è purged. Lo stato dell’attività expired è diverso: significa che la generazione ha superato il tempo limite e non ha prodotto nulla. Non mostrarli entrambi con la stessa etichetta nell’interfaccia: uno richiede un nuovo tentativo, l’altro non si recupera riprovando.

Imposta la scadenza della copia ben prima del limite. Copia al primo evento di successo, poi esegui un processo di riconciliazione che elenchi le attività riuscite senza risorsa permanente e avvisi mentre ai risultati restano ancora giorni. Il giorno 14 è un margine di recupero, non una pianificazione. Se un’impostazione dell’account o della richiesta riduce la conservazione, outputsExpireAt può essere molto prima di 14 giorni: basa gli avvisi su quel campo, mai su una costante. Un’impostazione dell’account può anche agire retroattivamente: accorciare il periodo del testo del prompt elimina i risultati delle attività già concluse prima del outputsExpireAt assegnato. Scarica ciò che vuoi conservare prima di cambiare le impostazioni dell’account e aspettati che la riconciliazione segnali quelle attività come perse, anziché come errori della pipeline.

Una pipeline di callback che regge nuovi tentativi e video pesanti

In un’applicazione, verifica l’evento di completamento, salvalo e accoda la copia prima di rispondere. Rendi la copia idempotente, così un evento ripetuto non crea un altro elemento nella galleria. Segnala i risultati non copiati prima della loro scadenza accettata.

Questo processo autonomo salva i file di un’attività esistente in una directory locale privata. Installa spicyapi, imposta SPICY_API_KEY, TASK_ID e facoltativamente ARCHIVE_DIR, poi eseguilo. Non crea alcuna generazione. Memorizza la directory su uno spazio persistente e includila nel piano di backup; un disco temporaneo del server non è un archivio duraturo.

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)

Per la consegna da uno spazio di archiviazione a oggetti, trasferisci in streaming verso un oggetto provvisorio privato ed esponilo solo dopo un trasferimento completo. La documentazione dei media e dei webhook descrive l’aggiornamento dei risultati e gli eventi autenticati. Mantieni il polling come percorso di riconciliazione per i callback mancati.

La tua risorsa permanente deve nascondere il percorso di generazione

Una volta copiato, l’oggetto servito dal tuo prodotto ha la propria identità:

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

Mantieni privato il bucket e distribuisci tramite il tuo CDN, un endpoint multimediale autenticato o i tuoi link di breve durata. Non riutilizzare un URL firmato SpicyAPI come URL pubblico. Così link temporanei e dettagli di archiviazione non finiscono in HTML, log ed esportazioni, puoi cambiare regole di accesso o domini senza riscrivere la cronologia delle attività e cancellare una risorsa utente agendo sul tuo record. Conserva privatamente la provenienza: ID dell’attività sorgente, chiave originale della risorsa, tipo di contenuto, dimensione, ora della copia e chiave di destinazione.

Errori e azioni di recupero

ErroreCosa osserviRecupero corretto
Ticket scaduto prima della fine del caricamento o file non confermato usato in un’attivitàCaricamento o conferma rifiutati, oppure la creazione dell’attività rifiuta il riferimentoRichiedi un nuovo ticket e ricarica; un 409/429 per conferma occupata richiede invece di riprovare la stessa conferma
URI spicy:// salvato usato il giorno seguente400 alla creazione o nuovo tentativo fallitoRicarica l’originale; tieni gli originali nel tuo spazio di archiviazione
Callback consegnato due volteDue processi avviano la stessa copiaDeduplica per request_id e per ID attività più indice risorsa nella coda e nella destinazione
Endpoint di callback lentoArrivano nuovi tentativi durante un downloadSalva, accoda e restituisci 2xx prima di spostare i media
Link al risultato scaduto in codaIl recupero dalla sorgente restituisce 403Rileggi l’attività per una nuova url e riprova lo streaming
La risorsa mostra pending: truekey e url sono vuotiAspetta qualche secondo e interroga di nuovo
La risorsa mostra unavailable: true o download-url restituisce 410Scaduta, eliminata o archiviazione fallitaUsa la copia privata verificata; se non c’è, informa l’utente e genera di nuovo con una nuova attività addebitata
Copia completata ma scrittura nel database fallitaOggetto privato presente, nessuna riga di risorsa prontaVerifica la destinazione esistente e riprova la scrittura dei metadati; non cancellare mai una copia valida né rigenerare
Il database indica pronto ma l’oggetto mancaPagina non funzionante o 404 dal CDNRiconcilia le righe del database con il bucket prima di segnare come pronto
URL firmato nei logEsposta una capacità temporanea di letturaOscura stringhe di query e corpi delle risposte; i link scadono in circa 20 minuti ma non sono revocabili
Video pesante caricato in memoriaIl processo si riavvia o esaurisce la memoriaUsa streaming con concorrenza limitata e gestione della contropressione

Lista per il lancio in produzione

  • Recupera prima della scadenza: segnala le copie mancanti usando la scadenza accettata di ogni attività.
  • Rendi esplicita la proprietà: servi risorse private solo al proprietario e raccogli i risultati prima di ruotare le chiavi API.
  • Elimina in tutti i tuoi sistemi: includi bucket, cache di consegna e backup nella politica di cancellazione.

Domande frequenti

Posso salvare l’URL restituito in output.assets[].url?

Solo per la copia stessa. Salva il tuo record della risorsa e ottieni un link nuovo quando devi spostare i byte.

Mi serve ancora download-url?

Solo per aggiornare un link tramite taskId e key nella finestra di conservazione; le risorse pronte hanno già url ed expiresAt.

No. Un link nuovo rinnova solo l’accesso in lettura; l’oggetto viene comunque eliminato a retention.outputsExpireAt.

Posso passare un URL pubblico di immagine al modello invece di caricarla?

Sì, se lo schema del modello consente un URL in quel campo, purché l’indirizzo restituisca il file stesso e rimanga raggiungibile durante l’attività. Usa il caricamento per file locali, input più grandi o contenuti non ospitati pubblicamente.

Mi serve la stessa immagine di riferimento la prossima settimana. Cosa faccio?

Ricaricala dalla tua copia quando ti serve la prossima settimana. Un riferimento confermato funziona solo per 1 giorno, ma può servire più attività mentre è valido, salvo eliminazione anticipata.

Devo copiare il risultato nella richiesta di callback?

No. Un trasferimento pesante nella richiesta supera il timeout del callback di 15 secondi e provoca consegne duplicate; un processo in coda può riprovare in sicurezza.

E se non voglio conservare affatto un risultato?

Non copiarlo e lascialo scadere, oppure riduci la conservazione o distruggi il contenuto di un’attività su richiesta. Questi controlli sono descritti in Caricamento, conservazione e consegna dei media AI e nella documentazione di conservazione. Distruggere il contenuto non cambia mai quanto ti è stato addebitato.

Lascia che un Agent gestisca la chiamata

Usa un Agent per recuperare un output esistente invece di crearlo di nuovo.

  • CLI: npx @spicyapi/cli tasks get "$TASK_ID" recupera l’attività. Vedi la guida CLI.
  • MCP: chiedi a spicyapi_task_get l’output attuale e salva il file restituito. Vedi la guida MCP.
  • Skill: installa npx skills add spicyapi-ai/spicy-skill, poi chiedi a $spicyapi di archiviare il risultato dell’attività nella directory scelta. Vedi la guida Skill.

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