Panduan
Pembuatan gambar
Buat dan edit gambar secara asinkron: kirim tugas, pantau hingga selesai, dan unduh URL keluaran bertanda tangan.
API gambar Felo menghasilkan dan mengedit gambar dengan model dari katalog model Felo. API ini asinkron: permintaan pengiriman langsung mengembalikan ID tugas, dan Anda melakukan polling tugas hingga mencapai status terminal.
Halaman ini membahas kontrak khusus gambar. Untuk siklus hidup tugas bersama, lihat Tugas Asinkron.
Sebelum Anda Memulai
- Kunci API. Lihat Autentikasi.
- Model yang
model_kind-nyaimage_generation. Lihat Menemukan model gambar. - Base URL
https://openapi.felo.ai.
Perbedaannya dengan OpenAI Images API
Path-nya mirip dengan Images API milik OpenAI. Responsnya tidak:
| OpenAI Images API | Felo Image API | |
|---|---|---|
| Respons pengiriman | 200 dengan data gambar | 202 dengan task_id, status: "queued" |
| Kapan gambar tersedia | Dalam respons pengiriman | Setelah polling mencapai succeeded |
| Payload gambar | b64_json atau url | url bertanda tangan yang dibatasi waktu |
| Error permintaan | Error HTTP saat pengiriman | Biasanya status: "failed" pada tugas |
Jangan mengirim openai.images.generate() ke endpoint ini. SDK mengharapkan array data yang sinkron dan tidak dapat melakukan polling tugas. Panggil endpoint melalui HTTP dan lakukan polling tugas, atau tulis wrapper kecil untuk kedua langkah tersebut.
Mengirim Tugas
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"
}'Pengiriman yang berhasil mengembalikan HTTP 202:
{
"task_id": "6d1f0c9a-...",
"status": "queued",
"kind": "image",
"outputs": []
}202 berarti platform menerima tugas. Ini tidak berarti prompt, parameter, atau gambar referensi valid. Panggilan upstream berjalan setelah respons, sehingga sebagian besar masalah permintaan muncul kemudian sebagai tugas gagal. Pengecualiannya adalah routing model: model chat atau video ditolak saat pengiriman.
Polling hingga Tugas Mencapai Status Terminal
curl "https://openapi.felo.ai/api/v1/images/generations/${TASK_ID}" \
-H "Authorization: Bearer ${FELO_API_KEY}"| Status | Arti | Yang harus dilakukan |
|---|---|---|
queued | Diterima; menunggu dimulai | Lanjutkan polling |
running | Model sedang menghasilkan | Lanjutkan polling |
succeeded | Terminal; outputs terisi | Unduh output |
failed | Terminal; baca error.message | Perbaiki permintaan; jangan mencoba ulang tanpa perubahan |
interrupted | Terminal; hasil tidak dapat dipulihkan | Kirim ulang tugas |
Kegagalan tugas mempertahankan status HTTP pada 200. Periksa status di dalam body, bukan hanya status HTTP.
Mulai dengan interval 2–5 detik lalu lakukan backoff. Sebagian besar gambar selesai dalam satu menit; output 4K dan pengeditan dengan banyak gambar referensi memerlukan waktu lebih lama. Selalu tetapkan batas waktu Anda sendiri.
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")Membaca dan Menyimpan Output
Saat tugas berhasil, outputs berisi satu entri per gambar yang dihasilkan:
{
"task_id": "6d1f0c9a-...",
"status": "succeeded",
"kind": "image",
"outputs": [
{
"media_type": "image/png",
"url": "https://openapi.felo.ai/api/v1/media/...?exp=...&sig=..."
}
]
}outputskosong hingga tugas berhasil.urladalah URL bertanda tangan. URL ini dapat diunduh tanpa kunci API, jadi perlakukan sebagai tautan bearer.- URL dibatasi waktu. Parameter kueri
expadalah waktu kedaluwarsanya. Unduh file dan simpan di bucket atau sistem file Anda sendiri; tugas bukan penyimpanan permanen. - Polling lagi setelah URL kedaluwarsa mengembalikan URL kedaluwarsa yang sama. URL baru tidak diterbitkan.
- Respons tidak menyertakan data gambar 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)Mengedit Gambar
Berikan gambar referensi di input_references. Model menggunakannya sebagai konteks; prompt tetap menjelaskan perubahan.
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"}
}
]
}'Setiap referensi berupa URL HTTP(S) atau URL data base64. Urutan referensi dipertahankan; rujuk gambar berdasarkan posisinya di prompt bila itu penting. Model saat ini menerima hingga 14 referensi.
Field Permintaan
| Field | Wajib | Deskripsi |
|---|---|---|
model | Ya | ID model katalog, misalnya gemini-3-pro-image. Jangan gunakan ID upstream google/... |
prompt | Ya | Instruksi teks. Untuk pengeditan, jelaskan perubahan dan apa yang harus tetap sama |
resolution | Tidak | Tingkat output. Model saat ini menerima 1K, 2K, atau 4K |
aspect_ratio | Tidak | Rasio output. Nilai yang diterima bergantung pada model |
n | Tidak | Jumlah gambar. Model saat ini menerima 1 |
input_references | Tidak | Gambar referensi untuk pengeditan atau komposisi |
Model gambar saat ini:
| ID Model | Resolusi | Rasio aspek | Gambar per tugas | Referensi |
|---|---|---|---|---|
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 | Hingga 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 | Hingga 14 |
Untuk menyematkan penyedia, kirim header X-Felo-Channel dengan kode kanal dari daftar channels model. Lihat Kanal dan Routing Penyedia.
Menemukan Model Gambar
Tidak ada endpoint daftar model gambar terpisah. Kueri katalog umum dan filter berdasarkan 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} mengembalikan kanal model dan tarif yang dipublikasikan.
supported_parameters di katalog umum adalah daftar tingkat protokol. Untuk model gambar, daftar ini tidak secara andal menyebutkan field gambar di atas, jadi jangan membangun permintaan Anda darinya. Gunakan tabel field dalam panduan ini dan konfirmasi ID model dari katalog.
Harga
Generasi gambar ditagih berdasarkan tarif model yang dipublikasikan. Katalog mengekspos input_image dan output_image bersama tarif teks prompt dan completion. Tarif gambar adalah tarif token: resolution mengubah berapa banyak token gambar output yang dikonsumsi sebuah gambar, sehingga gambar 4K lebih mahal daripada gambar 1K. Gambar referensi menambahkan token gambar input.
Respons tugas tidak menyertakan objek usage. Periksa Console Billing untuk biaya yang dikenakan.
Tugas yang berakhir failed atau interrupted tidak menghasilkan output dan tidak ditagih. Pengiriman yang ditolak dengan 402 tidak membuat tugas.
Error
Error tingkat endpoint dari rute gambar menggunakan envelope error OpenAI:
{
"error": {
"message": "Model kind does not match this generation endpoint",
"type": "invalid_request_error",
"param": null,
"code": "model_kind_mismatch"
}
}ID permintaan berada di header respons X-Request-Id. Catat ID tersebut bersama ID tugas.
| HTTP | error.code | Arti |
|---|---|---|
| 400 | invalid_request_error | model hilang, atau body bukan objek JSON |
| 400 | model_not_configured | ID model tidak ada di katalog yang diaktifkan |
| 400 | chat_model_not_allowed | Model chat dikirim ke endpoint gambar |
| 400 | model_kind_mismatch | Model video atau model non-gambar lain dikirim |
| 402 | insufficient_balance | Kredit tidak mencukupi; tidak ada tugas yang dibuat |
| 404 | generation_task_not_found | ID tugas tidak dikenal atau milik akun lain |
| 429 | daily_spend_limit_exceeded | Batas pengeluaran harian akun tercapai |
| 503 | generation_unavailable | Generasi sementara tidak tersedia; coba lagi nanti |
Error autentikasi dijelaskan di Error, Batas, dan Percobaan Ulang.