Tutoriale
Come chiamare l'API Imagen 4 tramite HiAPI: esempi con curl e Python
Cosa offre l'endpoint Imagen 4
Se hai già un prompt e vuoi ottenere un'immagine senza registrare un account di fatturazione, senza configurare una coda e senza creare un bucket presso un provider che non hai mai usato, il modello Google-Imagen4 su HiAPI è un punto di partenza ragionevole. Basta inviare un prompt testuale a un singolo endpoint HTTP, autenticarsi con una chiave API e ricevere un riferimento all'immagine generata (o un task da interrogare a intervalli). Tutto il resto — hosting del modello, capacità, retry lato provider — è astratto.
Le chiamate text-to-image tramite questo endpoint coprono tre cose che ti interessano davvero nell'uso pratico:
- Dal prompt all'immagine. Il prompt è l'input principale. A seconda di come configuri la richiesta, il modello restituisce una o più immagini.
- Controllo della forma dell'output. Puoi specificare il rapporto d'aspetto al momento della richiesta (quadrato, orizzontale, verticale) invece di ritagliare dopo. Questo è più importante di quanto sembri: ritagliare un'immagine già generata elimina la composizione che il modello aveva pianificato.
- Esecuzione asincrona. Le generazioni più lunghe vengono gestite come task. Invii, interroghi lo stato, poi recuperi il risultato. Le chiamate brevi possono restituire rapidamente, ma dovresti scrivere il client come se ogni chiamata fosse asincrona, perché è il flusso che regge il traffico di produzione.
Il resto di questo tutorial costruisce la stessa richiesta in tre modi: una chiamata curl grezza da incollare nel terminale, un client Python equivalente, e poi le parti che ti servono per gestire rapporto d'aspetto, polling, persistenza e gestione degli errori. Se vuoi generare un'immagine con una singola riga di shell, va bene. Se ti serve un controllo granulare su maschere di inpainting o su un ciclo di training, potrebbe non essere adatto.
Due prerequisiti prima di iniziare: hai una chiave API HiAPI e il tuo ambiente di esecuzione può effettuare richieste HTTPS in uscita. Nient'altro è richiesto — l'installazione di SDK non è obbligatoria, anche se gli esempi Python qui sotto usano requests.
La tua prima richiesta con curl
Il modo più rapido per verificare che la chiave funzioni è una chiamata curl. L'endpoint accetta un corpo JSON, quindi ti servono due header: Content-Type per il corpo, Authorization per la chiave. Leggi la chiave da una variabile d'ambiente invece di incollarla direttamente nel comando, così non rimane nella cronologia della shell.
export HIAPI_API_KEY="your-key-here"
curl -sS -X POST "https://api.hiapi.ai/v1/images/generations" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-d '{
"model": "google-imagen-4",
"prompt": "a weathered lighthouse on a basalt cliff, morning fog, wide shot",
"n": 1,
"aspect_ratio": "16:9"
}'
Alcuni punti da notare in questo corpo:
modelseleziona Google-Imagen4. Scrivilo esplicitamente anche se il servizio ha un valore predefinito — rende il tuo codice leggibile anche tra un anno.promptè l'unico input creativo obbligatorio. Scrivilo come descriveresti un'inquadratura a un fotografo: soggetto, ambiente, luce, composizione.ncontrolla quante immagini vuoi. Inizia con una mentre metti a punto la struttura della risposta; aumenta quando ti fidi della tua pipeline.aspect_ratioè spiegato in dettaglio più avanti. Ometterlo fa ricadere sul valore predefinito del servizio.
Una risposta riuscita restituisce un oggetto JSON. La parte che ti interessa è la lista di voci immagine; ogni voce porta un riferimento scaricabile o un URL che puoi passare al frontend. Se hai richiesto più immagini, ricevi più voci, nell'ordine della richiesta. Se la generazione richiede abbastanza tempo da essere accodata, la risposta ti dà invece un identificatore e uno stato da interrogare — questo flusso è descritto nella sezione dedicata qui sotto.
Se ricevi un 4xx, controlla prima i due header: il prefisso Bearer mancante o uno spazio finale nella chiave sono le cause più comuni dei fallimenti alla prima chiamata. Durante il debug usa -i per vedere la riga di stato e il corpo della risposta di errore.
La stessa richiesta in Python
In uno script, incapsula la chiamata in una piccola funzione, così il resto del codice non deve mai toccare l'HTTP grezzo. La funzione dovrebbe accettare il prompt e parametri opzionali, costruire il corpo, inviare la richiesta e restituire il JSON analizzato.
import os
import requests
HIAPI_BASE = "https://api.hiapi.ai/v1"
def generate_image(prompt: str, aspect_ratio: str = "1:1", n: int = 1) -> dict:
response = requests.post(
f"{HIAPI_BASE}/images/generations",
headers={
"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
"Content-Type": "application/json",
},
json={
"model": "google-imagen-4",
"prompt": prompt,
"n": n,
"aspect_ratio": aspect_ratio,
},
timeout=120,
)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
result = generate_image(
"a weathered lighthouse on a basalt cliff, morning fog, wide shot",
aspect_ratio="16:9",
)
print(result)
Quando adatti questo codice, ci sono tre scelte di design che vale la pena mantenere:
Timeout esplicito.requests non ha un timeout predefinito, il che significa che una connessione bloccata può sospendere un worker a tempo indefinito. Scegli un valore superiore al tempo di generazione più lento che prevedi e fallo fallire esplicitamente.
Chiama raise_for_status() prima di analizzare.Le risposte di errore non condividono sempre lo stesso schema di quelle riuscite. Controlla prima lo stato HTTP, poi tocca il corpo.
Funzioni piccole e parametrizzate.Quando aggiungi polling e download, questa funzione resta l'unico punto di ingresso per l'invio, con la logica del ciclo di vita accanto, non aggrovigliata al suo interno.
Il risultato analizzato contiene le stesse informazioni dell'output di curl. Per le risposte sincrone, itera sulle voci immagine ed estrai gli URL. Per le risposte asincrone, estrai l'identificatore del task e passalo alla funzione di polling. Il tuo codice dovrebbe diramarsi in base alla forma ricevuta, non presumere che ce ne sia una sola.
Controllare rapporto d'aspetto e output
Il rapporto d'aspetto è il parametro che regoli più spesso, e vale la pena impostarlo correttamente invece di ritagliare dopo. Se richiedi un'immagine quadrata e ne ritagli una fascia 16:9, perdi la parte superiore e inferiore che il modello aveva composto intenzionalmente. Richiedere 16:9 in anticipo permette al modello di pianificare l'inquadratura per quel formato.
Passalo nel corpo insieme al prompt:
result = generate_image(
"a sprawling night market, neon signs, steam from food stalls",
aspect_ratio="16:9",
n=2,
)
I rapporti orizzontali vanno per banner hero, miniature di card larghe e fotografia di prodotto; i rapporti verticali per card mobile-first, poster e ritratti; quelli quadrati per avatar e post social con ritaglio imprevedibile. Decidi in base a dove finirà l'immagine, non in base a come appare isolata.
Quando cambi il rapporto, ciò che cambia nella risposta sono le dimensioni in pixel delle immagini restituite. Il numero di voci, l'ordine e il flusso di download restano invariati, quindi il codice a valle non deve diramarsi in base al rapporto. Se la tua UI riserva spazio prima del caricamento dell'immagine, leggi le dimensioni dalla risposta e impostale sull'elemento, invece di codificarle a mano.
Altri due controlli dell'output che vale la pena conoscere:
- Numero di immagini (
n).Più immagini per richiesta significano più scelta, ma anche più token spesi su un prompt che potrebbe essere sbagliato. Mentre iteri sulla formulazione del prompt, richiedi una sola immagine; passa al batch quando il prompt è stabile. - Formulazione del prompt per l'inquadratura.Il rapporto decide il formato; il prompt decide la composizione all'interno del formato. Parole come "wide shot", "close-up" e "centered" hanno effetto reale insieme al parametro del rapporto.
La fatturazione di questo endpoint segue la generazione delle immagini stessa — controlla il pannello prezzi sul sito per le tariffe attuali e non codificare nulla di fisso nel tuo modello di costo.
Gestire task asincroni e polling
Quando la generazione richiede abbastanza tempo da essere accodata, l'endpoint restituisce prima che l'immagine esista. Ricevi un handle di task, e il tuo compito è controllarlo fino a uno stato terminale. Scrivi questo flusso anche se oggi le chiamate tornano veloci — capacità, complessità del prompt e numero di immagini influenzano la latenza, e un client costruito per uno scenario sincrono si rompe alla prima richiesta lenta.
Il ciclo di vita si articola in tre passi:
- Invio.Invia la richiesta di generazione come al solito. Se la risposta è un task, estrai il suo identificatore.
- Polling.Chiama l'endpoint di stato del task con quell'identificatore a intervalli fissi.
- Recupero.Quando lo stato segnala successo, leggi il riferimento all'immagine dal payload del risultato.
import time
def wait_for_job(job_id: str, interval: float = 2.0, max_attempts: int = 60) -> dict:
for attempt in range(max_attempts):
response = requests.get(
f"{HIAPI_BASE}/images/jobs/{job_id}",
headers={"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
payload = response.json()
status = payload.get("status")
if status == "succeeded":
return payload
if status in {"failed", "cancelled"}:
raise RuntimeError(f"job {job_id} ended with status {status}")
time.sleep(interval)
raise TimeoutError(f"job {job_id} did not finish in time")
I dettagli chiave che rendono questo codice sicuro in produzione:
- Limita i tentativi, non un ciclo infinito.Un task che non finirà mai dovrebbe manifestarsi come un errore di timeout su cui puoi allertare, non come un worker sospeso per sempre.
max_attemptsmoltiplicato perintervalè il tuo budget di tempo effettivo — impostalo in base al tempo di generazione più lento realistico. - Backoff sotto carico.Un intervallo fisso di due secondi va bene per l'uso interattivo. Per carichi batch, aumenta progressivamente il backoff o aggiungi jitter, così i retry di molti worker non si sincronizzano nello stesso secondo.
- Distingui fallimento e sconosciuto.Solo
failedecancelledsono fallimenti terminali. Tratta qualsiasi altro stato non riuscito come "ancora in elaborazione" e interroga di nuovo; aggiungere un ramo che lancia un errore immediato per stati non riconosciuti ti si ritorcerà contro quando il servizio ne introdurrà di nuovi. - Riprova l'invio in caso di errori di rete, non il polling.Se la chiamata di invio stessa va in timeout, un retry può produrre task duplicati. Se l'API supporta chiavi di idempotenza, assegna una chiave di idempotenza a ogni invio; altrimenti deduplica dalla tua parte con un hash del prompt più un timestamp.
Quando un task segnala successo, smetti di interrogarlo. Persistere il risultato e conservare l'handle del task per l'audit costa meno che continuare a chiedere uno stato che già conosci.
Download e archiviazione delle immagini
La risposta di generazione ti dà riferimenti, non i byte delle immagini. Nella maggior parte dei casi ogni voce immagine porta un URL che puoi recuperare con una normale richiesta GET. Tratta quell'URL come un indirizzo temporaneo: scarica subito, verifica e salva i byte dove hai il controllo reale.
import pathlib
import uuid
def download_images(payload: dict, out_dir: str = "images") -> list[pathlib.Path]:
target = pathlib.Path(out_dir)
target.mkdir(parents=True, exist_ok=True)
saved = []
for entry in payload.get("data", []):
url = entry["url"]
resp = requests.get(url, timeout=60)
resp.raise_for_status()
content_type = resp.headers.get("Content-Type", "")
if not content_type.startswith("image/"):
raise ValueError(f"unexpected content type: {content_type}")
path = target / f"{uuid.uuid4().hex}.png"
path.write_bytes(resp.content)
saved.append(path)
return saved
Prima di considerare un task completato, fai alcuni controlli:
- Content type e dimensione.In alcuni ambienti, un redirect a una pagina di errore restituisce 200 e HTML. Prima di scrivere nello storage permanente, verifica che
Content-Typeinizi conimage/e che la dimensione del corpo non sia trascurabile. - Nomi.Genera un nuovo nome per ogni download, invece di derivarlo dal prompt. I prompt si ripetono, confliggono e contengono caratteri rifiutati dal filesystem.
- Archivia il prompt insieme al file.Salva prompt, parametri e identificatore del task nel tuo database o in un file di metadati sidecar. Sei mesi dopo, l'immagine da sola non può dirti quale richiesta l'ha prodotta.
- Sposta nello storage permanente, non copiare.Scrivi prima in una posizione temporanea, verifica, poi sposta nel tuo bucket o nello storage supportato da CDN. Un file scritto a metà nello storage permanente è peggio di un task fallito.
Se la tua pipeline produce molte immagini, separa il passaggio di download da quello di generazione. La generazione è la parte costosa e soggetta a rate limit; il retry del download costa poco e non dovrebbe mai farti rigenerare.
Errori comuni e checklist di debug
La maggior parte dei fallimenti del primo giorno rientra in poche categorie. Controllale in questo ordine — ogni controllo è più veloce del successivo.
Errori di autenticazione (401, 403)
Chiave sbagliata, mancante o malformata. Verifica che il valore dell'header sia esattamente Bearer più la chiave, senza newline da incollamenti, e conferma che la variabile d'ambiente sia effettivamente esportata nella shell o nel processo che esegue il codice. Le chiavi ruotate nella dashboard invalidano immediatamente le vecchie — se un altro servizio ha appena iniziato a fallire, chiedi se qualcuno ha ruotato la chiave.
Parametri rifiutati (400, 422)
Il corpo non corrisponde allo schema. Cause comuni: identificatore model digitato male, stringa aspect_ratio in un formato non accettato dall'endpoint, o n fuori dall'intervallo supportato. Stampa il corpo della risposta di errore — di solito indica il campo problematico. Confronta il tuo JSON con l'esempio curl funzionante, facendo un diff campo per campo.
Timeout
Due timeout diversi si confondono facilmente. Un timeout del client significa che la tua chiamata HTTP ha rinunciato; il task potrebbe essere ancora in esecuzione. Un task che non raggiunge mai uno stato terminale significa che il budget di polling è troppo piccolo o che la richiesta è davvero fallita. Imposta il timeout del client più alto del tempo di generazione più lento che prevedi, e il budget di polling ancora più alto. Quando scatta un timeout del client durante l'invio, un retry cieco può duplicare il lavoro — controlla se esiste già un task prima di reinviare.
Download che sembrano riusciti ma non lo sono
Uno stato 200 con corpo HTML, o un file da zero byte, di solito significa che l'URL dell'immagine è scaduto o che il recupero è avvenuto senza i permessi di accesso corretti. Scarica subito dopo il successo del task e verifica content type e dimensione come descritto sopra.
Rate limit (429)
Fai backoff e riprova, invece di stringere il ciclo. Il backoff esponenziale con jitter è la risposta standard; limita i retry ed esponi i fallimenti persistenti al tuo monitoraggio.
Un'abitudine di debug che vale la pena coltivare
Registra quattro cose per ogni richiesta: identificatore del modello, corpo completo della richiesta senza la chiave, identificatore del task (o stato della risposta per le chiamate sincrone) e durata. Quando qualcosa va storto in produzione, questi quattro campi di solito bastano a capire in meno di un minuto se il problema è nel client, nei parametri o nella coda.
Inizia con la chiamata curl, ottieni una prima immagine, poi sposta la logica in un client Python e aggiungi polling e persistenza intorno. Questo percorso mantiene ogni fallimento limitato e attribuibile.
Articoli correlati
Vedi tutti gli articoli →-
Tutoriale
Come chiamare hailuo-2.3-fast/image-to-video tramite l'API HiAPI: pratica con curl e Python
La prima richiesta funzionante per il livello image-to-video veloce ed economico — dall'ID del modello al download di un MP4
-
Tutoriale
Come chiamare hailuo-2.3/text-to-video tramite l'API HiAPI: curl, Python ed esempi di richiesta eseguibili
-
Tutoriale
Utilizzare Kandinsky 6.0 Pro su HiAPI per la generazione di video da testo: tutorial con curl e Python
Dimostrazione pratica guidata dalla richiesta: costruire la chiamata da prompt a clip video, inviare la richiesta, monitorare lo stato di completamento e scaricare il risultato