Guide
Generazione di immagini
Genera e modifica immagini in modo asincrono: invia un'attività, monitora il completamento e scarica gli URL di output firmati.
L'API per le immagini di Felo genera e modifica immagini con i modelli del catalogo Felo. È asincrona: la richiesta di invio restituisce subito un ID attività e interroghi l'attività finché non raggiunge uno stato terminale.
Questa pagina descrive il contratto specifico delle immagini. Per il ciclo di vita condiviso delle attività, vedi Attività asincrone.
Prima di iniziare
- Una chiave API. Vedi Autenticazione.
- Un modello il cui
model_kindèimage_generation. Vedi Trovare un modello di immagine. - L'URL di base
https://openapi.felo.ai.
Come si differenzia dalla OpenAI Images API
Il percorso è simile a quello della Images API di OpenAI. La risposta no:
| OpenAI Images API | Felo Image API | |
|---|---|---|
| Risposta di invio | 200 con i dati dell'immagine | 202 con task_id, status: "queued" |
| Quando l'immagine esiste | Nella risposta di invio | Dopo che il polling raggiunge succeeded |
| Payload dell'immagine | b64_json o url | Un url firmato con scadenza |
| Errori della richiesta | Errore HTTP all'invio | Di solito status: "failed" sull'attività |
Non inviare openai.images.generate() a questo endpoint. L'SDK si aspetta un array data sincrono e non può interrogare un'attività. Chiama l'endpoint via HTTP e interroga l'attività, oppure scrivi un piccolo wrapper per entrambi i passaggi.
Inviare un'attività
curl -X POST "https://openapi.felo.ai/api/v1/images/generations" \
-H "Authorization: Bearer ${FELO_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-pro-image",
"prompt": "A studio product photo of a ceramic coffee cup on warm linen, soft morning light",
"resolution": "2K",
"aspect_ratio": "4:3"
}'Un invio riuscito restituisce HTTP 202:
{
"task_id": "6d1f0c9a-...",
"status": "queued",
"kind": "image",
"outputs": []
}202 significa che la piattaforma ha accettato l'attività. Non significa che il prompt, i parametri o le immagini di riferimento siano validi. La chiamata upstream avviene dopo la risposta, quindi la maggior parte dei problemi della richiesta compare più tardi come attività non riuscita. L'eccezione è il routing dei modelli: un modello di chat o video viene rifiutato all'invio.
Interrogare finché l'attività è terminale
curl "https://openapi.felo.ai/api/v1/images/generations/${TASK_ID}" \
-H "Authorization: Bearer ${FELO_API_KEY}"| Stato | Significato | Cosa fare |
|---|---|---|
queued | Accettata; in attesa di avvio | Continua a interrogare |
running | Il modello sta generando | Continua a interrogare |
succeeded | Terminale; outputs è popolato | Scarica gli output |
failed | Terminale; leggi error.message | Correggi la richiesta; non riprovare senza modifiche |
interrupted | Terminale; il risultato non è stato recuperabile | Invia di nuovo l'attività |
Gli errori delle attività mantengono lo stato HTTP a 200. Controlla status nel corpo, non solo lo stato HTTP.
Parti da un intervallo di 2–5 secondi e aumentalo. La maggior parte delle immagini termina entro un minuto; l'output 4K e le modifiche con molte immagini di riferimento richiedono più tempo. Imposta sempre una scadenza tua.
import os
import time
import requests
BASE = "https://openapi.felo.ai"
HEADERS = {"Authorization": f"Bearer {os.environ['FELO_API_KEY']}"}
def generate_image(prompt: str, **params) -> list[dict]:
response = requests.post(
f"{BASE}/api/v1/images/generations",
headers=HEADERS,
json={"model": "gemini-3-pro-image", "prompt": prompt, **params},
timeout=30,
)
response.raise_for_status()
task = response.json()
deadline = time.monotonic() + 300
delay = 2.0
while time.monotonic() < deadline:
time.sleep(delay)
delay = min(delay * 1.5, 10.0)
poll = requests.get(
f"{BASE}/api/v1/images/generations/{task['task_id']}",
headers=HEADERS,
timeout=30,
)
poll.raise_for_status()
task = poll.json()
if task["status"] == "succeeded":
return task["outputs"]
if task["status"] in {"failed", "interrupted"}:
message = task.get("error", {}).get("message", task["status"])
raise RuntimeError(message)
raise TimeoutError(f"image task {task['task_id']} did not finish")Leggere e conservare gli output
Quando l'attività riesce, outputs contiene una voce per ogni immagine generata:
{
"task_id": "6d1f0c9a-...",
"status": "succeeded",
"kind": "image",
"outputs": [
{
"media_type": "image/png",
"url": "https://openapi.felo.ai/api/v1/media/...?exp=...&sig=..."
}
]
}outputsè vuoto finché l'attività non riesce.urlè un URL firmato. Si scarica senza chiave API, quindi trattalo come un link bearer.- L'URL ha una scadenza. Il parametro di query
expè il suo momento di scadenza. Scarica il file e conservalo nel tuo bucket o filesystem; l'attività non è un archivio permanente. - Se interroghi di nuovo dopo la scadenza dell'URL, ottieni lo stesso URL scaduto. Non ne viene emesso uno nuovo.
- La risposta non include dati immagine in base64.
for index, output in enumerate(outputs):
image = requests.get(output["url"], timeout=60)
image.raise_for_status()
with open(f"image-{index}.png", "wb") as file:
file.write(image.content)Modificare un'immagine
Passa le immagini di riferimento in input_references. Il modello le usa come contesto; il prompt descrive comunque la modifica.
curl -X POST "https://openapi.felo.ai/api/v1/images/generations" \
-H "Authorization: Bearer ${FELO_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-pro-image",
"prompt": "Keep the product and framing. Replace the background with a sunlit marble countertop.",
"resolution": "2K",
"aspect_ratio": "4:3",
"input_references": [
{
"type": "image_url",
"image_url": {"url": "https://example.com/product.png"}
}
]
}'Ogni riferimento è un URL HTTP(S) o un URL di dati base64. L'ordine dei riferimenti viene conservato; quando conta, fai riferimento alle immagini per posizione nel prompt. I modelli attuali accettano fino a 14 riferimenti.
Campi della richiesta
| Campo | Obbligatorio | Descrizione |
|---|---|---|
model | Sì | ID del modello nel catalogo, per esempio gemini-3-pro-image. Non usare l'ID upstream google/... |
prompt | Sì | Istruzione testuale. Per una modifica, descrivi il cambiamento e cosa deve restare uguale |
resolution | No | Livello di output. I modelli attuali accettano 1K, 2K o 4K |
aspect_ratio | No | Rapporto d'aspetto dell'output. I valori accettati dipendono dal modello |
n | No | Numero di immagini. I modelli attuali accettano 1 |
input_references | No | Immagini di riferimento per modifiche o composizioni |
Modelli di immagine attuali:
| ID modello | Risoluzioni | Rapporti d'aspetto | Immagini per attività | Riferimenti |
|---|---|---|---|---|
gemini-3-pro-image | 1K, 2K, 4K | 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9 | 1 | Fino a 14 |
gemini-nano-banana-2.1 | 1K, 2K, 4K | 1:1, 1:4, 1:8, 2:3, 3:2, 3:4, 4:1, 4:3, 4:5, 5:4, 8:1, 9:16, 16:9, 21:9 | 1 | Fino a 14 |
Per vincolare un fornitore, invia l'header X-Felo-Channel con un codice canale dall'elenco channels del modello. Vedi Canali e routing dei provider.
Trovare un modello di immagine
Non esiste un endpoint separato per l'elenco dei modelli di immagine. Interroga il catalogo generale e filtra per model_kind:
curl "https://openapi.felo.ai/api/v1/models" \
-H "Authorization: Bearer ${FELO_API_KEY}" \
| jq '.data[] | select(.model_kind == "image_generation") | {id, name}'GET /api/v1/models/{model_id} restituisce i canali del modello e le tariffe pubblicate.
supported_parameters nel catalogo generale è un elenco a livello di protocollo. Per i modelli di immagine non enumera in modo affidabile i campi immagine sopra, quindi non costruire la richiesta partendo da lì. Usa la tabella dei campi in questa guida e conferma l'ID del modello dal catalogo.
Prezzi
La generazione di immagini viene fatturata secondo le tariffe pubblicate del modello. Il catalogo espone input_image e output_image accanto alle tariffe di testo prompt e completion. Le tariffe immagine sono tariffe per token: resolution cambia quanti token immagine di output consuma un'immagine, quindi un'immagine 4K costa più di una 1K. Le immagini di riferimento aggiungono token immagine di input.
La risposta dell'attività non include un oggetto usage. Controlla l'addebito in Console Billing.
Un'attività che termina failed o interrupted non produce output e non viene fatturata. Un invio rifiutato con 402 non ha creato alcuna attività.
Errori
Gli errori a livello di endpoint della route immagini usano la struttura di errore OpenAI:
{
"error": {
"message": "Model kind does not match this generation endpoint",
"type": "invalid_request_error",
"param": null,
"code": "model_kind_mismatch"
}
}Il request ID si trova nell'header di risposta X-Request-Id. Registralo insieme all'ID dell'attività.
| HTTP | error.code | Significato |
|---|---|---|
| 400 | invalid_request_error | model manca oppure il corpo non è un oggetto JSON |
| 400 | model_not_configured | L'ID del modello non è nel catalogo abilitato |
| 400 | chat_model_not_allowed | È stato inviato un modello di chat all'endpoint immagini |
| 400 | model_kind_mismatch | È stato inviato un modello video o un altro modello non di immagine |
| 402 | insufficient_balance | Crediti insufficienti; nessuna attività è stata creata |
| 404 | generation_task_not_found | L'ID dell'attività è sconosciuto o appartiene a un altro account |
| 429 | daily_spend_limit_exceeded | È stato raggiunto il limite di spesa giornaliero dell'account |
| 503 | generation_unavailable | La generazione è temporaneamente non disponibile; riprova più tardi |
Gli errori di autenticazione sono descritti in Errori, limiti e retry.