Tutoriale
Generare immagini di prodotto e-commerce con FLUX.1 [schnell] tramite l'API hiapi
Una guida curl + Python pronta all'uso per immagini catalogo su sfondo bianco, scene e varianti, a $0.005 per immagine.
La fotografia per catalogo è la fase più lenta quando si pubblica uno SKU online. Prenotare uno studio, ingaggiare uno stylist, allestire softbox, assumere un ritoccatore: per una tazza da $24 non ha alcun senso. flux-schnell/text-to-image su hiapi ti permette di ottenere immagini prodotto utilizzabili su sfondo bianco pulito, immagini principali in contesto e varianti colore/materiale, a $0.005 per immagine, in circa 30 secondi end-to-end — a questo livello non ragioni più sul costo del singolo scatto, ma inizi a pensare ai prompt e ai batch di prompt.
Questa guida percorre il flusso di lavoro esatto: i quattro tipi di immagine che una pagina di dettaglio prodotto richiede davvero; la struttura del prompt che mantiene il modello su uno sfondo pulito e senza giunture, invece di inventare un tavolo di legno dal nulla; come generare in batch 100 varianti tramite /v1/tasks senza mandare in crash il terminale; e le poche cose che schnell non sa fare, che devi pianificare in anticipo.
Perché il lavoro di catalogo è particolarmente adatto a flux-schnell
Su hiapi ci sono anche modelli a fedeltà più alta (flux-2, flux-1.1-pro, nano-banana-pro), e se si tratta dell'immagine principale di una campagna di brand dovresti usarli. Ma per il catalogo i conti sono diversi:
- Un lancio di 200 SKU, con circa 4 immagini per SKU (sfondo bianco, scena, riferimento proporzioni, dall'alto) = 800 immagini. A $0.005 sono $4. A $0.05 sono $40. A $0.17 sono $136.
schnellcompleta la generazione in 1–4 step di campionamento, quindi end-to-end (coda + generazione + download) nei nostri test richiede circa 30 secondi.flux-2enano-banana-prosono diverse volte più lenti.- Le immagini di catalogo vengono mostrate a 600px di larghezza nella pagina di dettaglio prodotto e a 200px nella griglia. A queste dimensioni il margine di fedeltà dei modelli avanzati non si vede affatto; contano di più l'aderenza al prompt e la plausibilità del rapporto d'aspetto.
Il compromesso è reale: schnell è debole sul testo piccolo e leggibile sulle etichette, è debole sulle persone che tengono in mano il prodotto (per questi casi usa nano-banana-pro), ed è chiaramente debole sui loghi di brand complessi. Per «mostrami il prodotto, su sfondo pulito, in tre colori, vista dall'alto e a tre quarti» — cioè il suo vero lavoro — è eccellente.
La lista delle immagini che devi effettivamente generare
Prima di scrivere qualsiasi prompt, stabilisci di cosa ha bisogno il tuo template di pagina di dettaglio prodotto. Un insieme di partenza utile:
| Tipo di immagine | Rapporto d'aspetto | Uso |
|---|---|---|
| Immagine prodotto su sfondo bianco | 1:1 |
Immagine principale della pagina di dettaglio, miniatura della griglia |
| Scatto in studio a tre quarti | 4:3 |
Seconda immagine della galleria della pagina di dettaglio |
| Immagine di scena / contesto | 3:2 |
Galleria della pagina di dettaglio, annunci social |
| Flat lay dall'alto | 1:1 |
Galleria della pagina di dettaglio, riferimento proporzioni |
| Griglia varianti colore/materiale | 1:1 per variante |
Miniature del selettore colore |
flux-schnell su hiapi supporta 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9, auto. Qualsiasi altro rapporto viene rifiutato alla creazione del task.
Esecuzione singola: generare una singola immagine prodotto con curl
Il minimo indispensabile per verificare che il token funzioni. La mia ultima esecuzione ha impiegato 31 secondi end-to-end:
TOKEN="$HIAPI_API_KEY"
# 1. Crea il task
TASK=$(curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "flux-schnell/text-to-image",
"input": {
"prompt": "Product packshot: matte ceramic coffee mug, soft beige glaze, centered on seamless white cyclorama, soft diffused studio lighting, subtle contact shadow, 50mm photography, no props, ecommerce hero, clean negative space top and bottom",
"aspect_ratio": "1:1"
}
}' | jq -r '.data.taskId')
echo "task: $TASK"
# 2. Polling finché non è completo (success | fail)
while true; do
STATE=$(curl -s "https://api.hiapi.ai/v1/tasks/$TASK" \
-H "Authorization: Bearer $TOKEN")
STATUS=$(echo "$STATE" | jq -r '.data.status')
echo " status=$STATUS"
[ "$STATUS" = "success" ] && break
[ "$STATUS" = "fail" ] && { echo "$STATE" | jq '.data.error'; exit 1; }
sleep 4
done
# 3. Scarica (l'URL di output scade; recuperalo subito)
URL=$(echo "$STATE" | jq -r '.data.output[0].url')
curl -s -o packshot.jpg "$URL"
echo "saved packshot.jpg"
Una particolarità da tenere presente specificamente per flux-schnell: lo schema di input di questo modello accetta aspect_ratio ma rifiuta resolution. Gli altri modelli di immagine su hiapi (ad esempio flux-2, nano-banana-pro) accettano entrambi. Se invii a flux-schnell {"aspect_ratio": "1:1", "resolution": "1K"}, ottieni:
{
"code": 400,
"message": "additional properties not allowed: resolution"
}
Rimuovi resolution. Non ti serve: schnell restituisce in output alle dimensioni predefinite del modello, secondo il rapporto d'aspetto che hai scelto.
In produzione: generazione in batch con Python
Il vero lavoro di catalogo invia molti task, scarica gli output quando sono pronti e riprova i casi falliti. Questo è lo script che abbiamo usato quando facevamo prototipazione per una serie di SKU:
"""Generatore batch di packshot per flux-schnell su hiapi.
Legge un CSV di (sku, prompt, aspect_ratio), invia tutti i job, fa polling in parallelo,
scarica gli output completati in ./out/{sku}.jpg. Costo totale = $0.005 * len(csv).
"""
import csv
import json
import os
import subprocess
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
API = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"]
OUT = Path("./out"); OUT.mkdir(exist_ok=True)
def _post(path, body):
r = subprocess.run(
["curl", "-s", "-X", "POST", path,
"-H", f"Authorization: Bearer {TOKEN}",
"-H", "Content-Type: application/json",
"-d", json.dumps(body)],
capture_output=True, text=True, timeout=60,
)
return json.loads(r.stdout)
def _get(path):
r = subprocess.run(
["curl", "-s", path, "-H", f"Authorization: Bearer {TOKEN}"],
capture_output=True, text=True, timeout=30,
)
return json.loads(r.stdout)
def render(sku: str, prompt: str, ratio: str) -> tuple[str, str]:
"""Submit → poll → download. Restituisce (sku, status). status='ok' oppure 'fail:<reason>'."""
body = {"model": "flux-schnell/text-to-image",
"input": {"prompt": prompt, "aspect_ratio": ratio}}
resp = _post(API, body)
task_id = (resp.get("data") or {}).get("taskId")
if not task_id:
return sku, f"fail:submit:{resp.get('message')}"
deadline = time.time() + 180
while time.time() < deadline:
state = _get(f"{API}/{task_id}")
data = state.get("data") or {}
status = data.get("status")
if status == "success":
url = (data.get("output") or [{}])[0].get("url")
if not url:
return sku, "fail:no-output-url"
subprocess.run(["curl", "-s", "-o", str(OUT / f"{sku}.jpg"), url],
timeout=60, check=True)
return sku, "ok"
if status == "fail":
return sku, f"fail:model:{data.get('error', {}).get('code')}"
time.sleep(4)
return sku, "fail:timeout"
def main():
rows = list(csv.DictReader(open("skus.csv")))
print(f"submitting {len(rows)} renders (cost ${0.005 * len(rows):.3f})")
with ThreadPoolExecutor(max_workers=8) as ex:
futures = {ex.submit(render, r["sku"], r["prompt"], r["aspect_ratio"]): r
for r in rows}
for f in as_completed(futures):
sku, status = f.result()
print(f" {sku}: {status}")
if __name__ == "__main__":
main()
Una riga di skus.csv è così:
sku,prompt,aspect_ratio
mug-beige-01,"Product packshot: matte ceramic mug, beige glaze, seamless white cyclorama, soft studio lighting, subtle contact shadow, 50mm photography, ecommerce hero, clean negative space",1:1
mug-charcoal-01,"Product packshot: matte ceramic mug, charcoal glaze, seamless white cyclorama, soft studio lighting, subtle contact shadow, 50mm photography, ecommerce hero, clean negative space",1:1
Note sul codice di produzione:
ThreadPoolExecutor(max_workers=8)è un livello di parallelismo sicuro perschnell. Andare oltre allunga solo la coda, senza completare più in fretta.- Il timeout di 180 secondi per task è impostato per essere prudente; in realtà ogni task riuscito si completa entro 30–60 secondi. Se scatta il timeout significa che il task è bloccato: le quattro cause sono nella guida hiapi ai task bloccati/timeout.
- Scarichiamo immediatamente dopo
success.output[].urlè un link temporaneo con un timestampexpireAt; non salvarlo nel tuo CMS.
Il template di prompt che ti dà immagini prodotto noiose ma utili
I prompt di catalogo non sono prompt creativi. Vuoi la stessa luce, lo stesso sfondo, la stessa fotocamera ogni volta, cambiando solo il prodotto. Un template:
Product packshot: {MATERIAL} {PRODUCT}, {COLOR} {FINISH},
{COMPOSITION},
{BACKGROUND},
{LIGHTING},
{LENS_NOTE},
ecommerce hero, no props, clean negative space {AREA}
Compilato:
Product packshot: matte ceramic coffee mug, soft beige glaze,
centered single subject filling about 60% of frame,
seamless white cyclorama background,
soft diffused studio lighting from the upper left, subtle contact shadow underneath,
shot on 50mm with shallow depth of field,
ecommerce hero, no props, clean negative space top and bottom
L'ordine conta meno della struttura. Questi elementi migliorano costantemente l'output:
- «seamless white cyclorama» è meglio di «white background»: il primo implica una fondale da studio infinito con illuminazione uniforme, il secondo a volte ti dà una tovaglia.
- «subtle contact shadow underneath» impedisce che il prodotto sembri sospeso.
- «filling about 60% of frame» ancora la composizione; senza,
schnella volte si allontana molto o spinge il prodotto in un angolo. - «no props» impedisce che accanto alla tazza compaiano piatti, foglie o cancelleria superflui.
Per le varianti di scena, sostituisci il blocco sfondo + illuminazione:
... matte ceramic coffee mug, soft beige glaze, single subject filling about 40% of frame,
on a light oak countertop with morning sunlight from a kitchen window,
soft golden-hour rim lighting, gentle defocused background showing a blurred linen curtain,
shot on 35mm at f/2.8, lifestyle photography, no people, no other props
Per il flat lay dall'alto:
... single subject centered, top-down 90-degree angle, ceramic coffee mug, soft beige glaze,
on a light grey paper surface, soft even overhead lighting, soft shadow directly under the rim,
shot on 50mm, flatlay product photography, no props, clean negative space all sides, 1:1
Esegui questi tre prompt sullo stesso SKU e ottieni una galleria di pagina di dettaglio prodotto utilizzabile al costo di $0.015.
Varianti colore/materiale senza rifare lo shooting
schnell eccelle nell'e-commerce proprio per la generazione di varianti. Una volta che un prompt funziona per un colore, puoi produrre in batch gli altri sostituendo le stringhe dei descrittori di colore:
COLORS = [
("beige", "soft beige glaze"),
("charcoal", "deep charcoal matte glaze"),
("sage", "muted sage green glaze"),
("terracotta", "warm terracotta clay glaze"),
("cream", "off-white cream glaze with subtle speckle"),
]
TEMPLATE = (
"Product packshot: matte ceramic coffee mug, {color_desc}, "
"centered single subject filling about 60% of frame, "
"seamless white cyclorama background, soft diffused studio lighting from the upper left, "
"subtle contact shadow underneath, shot on 50mm, ecommerce hero, no props, "
"clean negative space top and bottom"
)
rows = [{"sku": f"mug-{c}-01", "prompt": TEMPLATE.format(color_desc=desc),
"aspect_ratio": "1:1"} for c, desc in COLORS]
Cinque varianti a $0.005 = l'intero selettore colore a $0.025. Il problema: schnell non mantiene perfettamente la forma tra render diversi. Lo spessore del manico, la curva del bordo, le proporzioni variano leggermente tra i colori. Per una pagina prodotto stilizzata va bene. Per varianti identiche al pixel ti serve il condizionamento con immagine di riferimento, cioè flux-1.1-pro con immagine di riferimento o nano-banana-pro, non schnell.
Integrazione nel frontend del tuo negozio
L'output è un file JPG scaricato. Da lì alla pubblicazione nella pagina di dettaglio prodotto il percorso dipende dalla tua piattaforma:
- Shopify:
POST /admin/api/2025-01/products/{id}/images.json, con body{"image": {"attachment": "<base64>"}}. Restituisce un URL CDN ospitato da Shopify. - WooCommerce: carica tramite la libreria media di WP (
POST /wp-json/wp/v2/media), poi aggiorna il prodotto con l'ID media restituito tramiteimages: [{id: ...}]con una PATCH. - Headless / CMS proprio: carica sul tuo object storage (S3, R2, Cloudflare Images) e referenzia l'URL generato nel record del prodotto.
In ogni caso, carica lato server, non lato client, così la tua chiave hiapi non arriva mai al browser.
Calcolo dei costi per la pianificazione
A $0.005 per immagine il budget raramente è il vincolo, ma ragionare per batch aiuta:
| Batch | Numero di immagini | Costo |
|---|---|---|
| Uno SKU, 4 immagini | 4 | $0.02 |
| Lancio di 50 SKU, 4 immagini ciascuno | 200 | $1.00 |
| Aggiornamento catalogo di 200 SKU | 800 | $4.00 |
| Test giornaliero di varianti, 100 al giorno per 30 giorni | 3,000 | $15.00 |
Su hiapi il costo lato token dell'endpoint immagini (il prompt) è gratuito: paghi solo per l'immagine prodotta in output.
Cose che flux-schnell non fa bene
Cose da pianificare prima di investire:
- Testo leggibile sulle etichette. Se la tua immagine prodotto richiede un wordmark di brand chiaramente leggibile, genera prima l'immagine base con
schnell, poi sovrapponi il PNG dell'etichetta reale in un editor di immagini. Chiedere aschnelldi renderizzare «una tazza con la scritta 'OAK ROAST' sopra» produce testo illeggibile in circa l'80% dei casi. - Prodotto tenuto in mano. L'anatomia umana è un punto debole di
schnell. Per le immagini di scena con persone, passa anano-banana-prooflux-1.1-pro. - Prodotto identico al pixel tra varianti. In questo caso usa un modello che supporta le immagini di riferimento.
- Dettagli submillimetrici (gioielli, orologi con lancette visibili, metallo inciso). Questo è il territorio dei modelli avanzati.
Per tutto il resto della pagina di dettaglio prodotto — sfondi, illuminazione, varianti colore, immagini di contesto, atmosfera — flux-schnell è lo strumento giusto, nella fascia di prezzo giusta, con il tempo di turnaround giusto. L'intero ciclo sta in uno script while true: poll; download e in un CSV di SKU, e costa abbastanza poco da poter iterare sui prompt senza riunioni di budget.
Domande frequenti
D: Posso inviare immagini di riferimento a flux-schnell?
R: No. flux-schnell/text-to-image supporta solo text-to-image — il campo input accetta solo prompt e aspect_ratio, nient'altro. Per varianti condizionate da riferimento usa flux-1.1-pro o nano-banana-pro, che su hiapi accettano input immagine.
D: Quali rapporti d'aspetto sono supportati?
R: 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9 e auto. Qualsiasi altro rapporto (ad esempio 5:7, 2:1) viene rifiutato alla creazione del task, con un errore che indica l'insieme supportato.
D: Perché la creazione del task restituisce 400 quando includo resolution?
R: L'input di flux-schnell accetta solo aspect_ratio. Gli altri modelli di immagine su hiapi (ad esempio flux-2, nano-banana-pro) accettano resolution (1K/2K/4K). Per schnell, rimuovilo.
D: Per quanto tempo è valido l'URL di output?
R: Ogni output[].url porta un timestamp expireAt (tipicamente alcune decine di minuti). Appena status diventa success, scarica subito i byte dell'immagine e salvali nel tuo bucket — non fare hotlink dell'URL temporaneo nel tuo database prodotti.
D: Posso eseguire più di 8 task concorrenti?
R: Sì, ma di fatto non finiscono più in fretta — schnell è già veloce end-to-end, e oltre circa 8 in parallelo si accumula solo coda. Per volumi davvero grandi (migliaia), parallelizza su più macchine worker, non con thread in un unico processo.
D: Come ottengo varianti identiche al pixel dello stesso prodotto?
R: Con il solo schnell non è possibile. Genera una volta l'immagine principale, poi esegui le varianti con un modello che supporta le immagini di riferimento (flux-1.1-pro o nano-banana-pro) usando l'immagine principale come riferimento. Il costo sale, ma la coerenza della forma migliora sensibilmente.
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