Felo API PlatformFelo API Platform

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

Perbedaannya dengan OpenAI Images API

Path-nya mirip dengan Images API milik OpenAI. Responsnya tidak:

OpenAI Images APIFelo Image API
Respons pengiriman200 dengan data gambar202 dengan task_id, status: "queued"
Kapan gambar tersediaDalam respons pengirimanSetelah polling mencapai succeeded
Payload gambarb64_json atau urlurl bertanda tangan yang dibatasi waktu
Error permintaanError HTTP saat pengirimanBiasanya 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}"
StatusArtiYang harus dilakukan
queuedDiterima; menunggu dimulaiLanjutkan polling
runningModel sedang menghasilkanLanjutkan polling
succeededTerminal; outputs terisiUnduh output
failedTerminal; baca error.messagePerbaiki permintaan; jangan mencoba ulang tanpa perubahan
interruptedTerminal; hasil tidak dapat dipulihkanKirim 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=..."
    }
  ]
}
  • outputs kosong hingga tugas berhasil.
  • url adalah URL bertanda tangan. URL ini dapat diunduh tanpa kunci API, jadi perlakukan sebagai tautan bearer.
  • URL dibatasi waktu. Parameter kueri exp adalah 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

FieldWajibDeskripsi
modelYaID model katalog, misalnya gemini-3-pro-image. Jangan gunakan ID upstream google/...
promptYaInstruksi teks. Untuk pengeditan, jelaskan perubahan dan apa yang harus tetap sama
resolutionTidakTingkat output. Model saat ini menerima 1K, 2K, atau 4K
aspect_ratioTidakRasio output. Nilai yang diterima bergantung pada model
nTidakJumlah gambar. Model saat ini menerima 1
input_referencesTidakGambar referensi untuk pengeditan atau komposisi

Model gambar saat ini:

ID ModelResolusiRasio aspekGambar per tugasReferensi
gemini-3-pro-image1K, 2K, 4K1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:91Hingga 14
gemini-nano-banana-2.11K, 2K, 4K1: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:91Hingga 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.

HTTPerror.codeArti
400invalid_request_errormodel hilang, atau body bukan objek JSON
400model_not_configuredID model tidak ada di katalog yang diaktifkan
400chat_model_not_allowedModel chat dikirim ke endpoint gambar
400model_kind_mismatchModel video atau model non-gambar lain dikirim
402insufficient_balanceKredit tidak mencukupi; tidak ada tugas yang dibuat
404generation_task_not_foundID tugas tidak dikenal atau milik akun lain
429daily_spend_limit_exceededBatas pengeluaran harian akun tercapai
503generation_unavailableGenerasi sementara tidak tersedia; coba lagi nanti

Error autentikasi dijelaskan di Error, Batas, dan Percobaan Ulang.

Terkait