الأدلة
توليد الصور
ولّد الصور وحرّرها بشكل غير متزامن: أرسل مهمة، واستعلم حتى الاكتمال، ونزّل عناوين URL الموقّعة للمخرجات.
يولّد API الصور من Felo الصور ويحرّرها باستخدام نماذج من كتالوج نماذج Felo. وهو غير متزامن: يعيد طلب الإرسال معرّف مهمة فورًا، وتستطلع المهمة حتى تصل إلى حالة نهائية.
تغطي هذه الصفحة العقد الخاص بالصور. لدورة حياة المهام المشتركة، راجع المهام غير المتزامنة.
قبل أن تبدأ
- مفتاح API. راجع المصادقة.
- نموذج تكون قيمة
model_kindفيهimage_generation. راجع العثور على نموذج صور. - عنوان URL الأساسي
https://openapi.felo.ai.
كيف يختلف عن OpenAI Images API
المسار مشابه لواجهة OpenAI Images API. لكن الاستجابة ليست كذلك:
| OpenAI Images API | Felo Image API | |
|---|---|---|
| استجابة الإرسال | 200 مع بيانات الصورة | 202 مع task_id وstatus: "queued" |
| متى توجد الصورة | في استجابة الإرسال | بعد وصول الاستطلاع إلى succeeded |
| حمولة الصورة | b64_json أو url | url موقّع محدود المدة |
| أخطاء الطلب | خطأ HTTP عند الإرسال | عادةً status: "failed" في المهمة |
لا ترسل openai.images.generate() إلى هذا endpoint. تتوقع SDK مصفوفة data متزامنة ولا يمكنها استطلاع مهمة. استدعِ endpoint عبر HTTP واستطلع المهمة، أو اكتب غلافًا صغيرًا للخطوتين.
إرسال مهمة
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"
}'يعيد الإرسال الناجح HTTP 202:
{
"task_id": "6d1f0c9a-...",
"status": "queued",
"kind": "image",
"outputs": []
}تعني 202 أن المنصة قبلت المهمة. ولا تعني أن الموجّه أو المعاملات أو الصور المرجعية صالحة. يجري استدعاء المنبع بعد الاستجابة، لذا تظهر معظم مشكلات الطلب لاحقًا كمهمة فاشلة. الاستثناء هو توجيه النموذج: يُرفض نموذج الدردشة أو الفيديو عند الإرسال.
استطلع حتى تصبح المهمة نهائية
curl "https://openapi.felo.ai/api/v1/images/generations/${TASK_ID}" \
-H "Authorization: Bearer ${FELO_API_KEY}"| الحالة | المعنى | ما يجب فعله |
|---|---|---|
queued | مقبولة؛ بانتظار البدء | واصل الاستطلاع |
running | النموذج يولّد | واصل الاستطلاع |
succeeded | نهائية؛ تم ملء outputs | نزّل المخرجات |
failed | نهائية؛ اقرأ error.message | أصلح الطلب؛ لا تعده دون تغيير |
interrupted | نهائية؛ تعذّر استرداد النتيجة | أعد إرسال المهمة |
تحافظ حالات فشل المهام على حالة HTTP عند 200. تحقق من status في النص، لا من حالة HTTP وحدها.
ابدأ بفاصل من 2 إلى 5 ثوانٍ ثم تراجع تدريجيًا. تنتهي معظم الصور خلال دقيقة؛ ويستغرق إخراج 4K والتحرير مع صور مرجعية كثيرة وقتًا أطول. عيّن دائمًا مهلة زمنية خاصة بك.
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")قراءة المخرجات وتخزينها
عند نجاح المهمة، يحتوي outputs على إدخال واحد لكل صورة مولّدة:
{
"task_id": "6d1f0c9a-...",
"status": "succeeded",
"kind": "image",
"outputs": [
{
"media_type": "image/png",
"url": "https://openapi.felo.ai/api/v1/media/...?exp=...&sig=..."
}
]
}- يكون
outputsفارغًا حتى تنجح المهمة. urlعنوان URL موقّع. يمكن تنزيله دون مفتاح API، لذا تعامل معه كرابط حامل (bearer).- عنوان URL محدود المدة. معامل الاستعلام
expهو وقت انتهاء صلاحيته. نزّل الملف وخزّنه في حاوية التخزين أو نظام الملفات لديك؛ فالمهمة ليست تخزينًا دائمًا. - إعادة الاستطلاع بعد انتهاء صلاحية عنوان URL تعيد العنوان المنتهي نفسه. ولا تصدر عنوانًا جديدًا.
- لا تتضمن الاستجابة بيانات صورة 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)تحرير صورة
مرّر الصور المرجعية في input_references. يستخدمها النموذج كسياق؛ ويظل الموجّه يصف التغيير.
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"}
}
]
}'كل مرجع هو عنوان URL بنمط HTTP(S) أو عنوان بيانات base64. يُحفظ ترتيب المراجع؛ وأشر إلى الصور بحسب موقعها في الموجّه عندما يكون ذلك مهمًا. تقبل النماذج الحالية ما يصل إلى 14 مرجعًا.
حقول الطلب
| الحقل | مطلوب | الوصف |
|---|---|---|
model | نعم | معرّف النموذج في الكتالوج، مثل gemini-3-pro-image. لا تستخدم معرّف google/... الخاص بالمنبع |
prompt | نعم | نص التعليمات. للتحرير، صف التغيير وما يجب أن يبقى كما هو |
resolution | لا | فئة الإخراج. تقبل النماذج الحالية 1K أو 2K أو 4K |
aspect_ratio | لا | نسبة الإخراج. تعتمد القيم المقبولة على النموذج |
n | لا | عدد الصور. تقبل النماذج الحالية 1 |
input_references | لا | صور مرجعية للتحرير أو التركيب |
نماذج الصور الحالية:
| معرّف النموذج | الدقات | نسب العرض إلى الارتفاع | الصور لكل مهمة | المراجع |
|---|---|---|---|---|
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 | حتى 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 | حتى 14 |
لتثبيت مزوّد، أرسل رأس X-Felo-Channel مع رمز قناة من قائمة channels الخاصة بالنموذج. راجع القنوات وتوجيه المزوّد.
Find an image model (العثور على نموذج صور)
لا يوجد endpoint منفصل لقائمة نماذج الصور. استعلم الكتالوج العام وصفِّ حسب 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} قنوات النموذج والأسعار المنشورة.
supported_parameters في الكتالوج العام قائمة على مستوى البروتوكول. وبالنسبة لنماذج الصور، فهي لا تعدّد حقول الصور أعلاه بشكل موثوق، لذا لا تبنِ طلبك منها. استخدم جدول الحقول في هذا الدليل وأكّد معرّف النموذج من الكتالوج.
التسعير
تُفوتر عملية توليد الصور وفق الأسعار المنشورة للنموذج. يعرض الكتالوج input_image وoutput_image إلى جانب أسعار النص prompt وcompletion. أسعار الصور هي أسعار رموز: تغيّر resolution عدد رموز الصور الناتجة التي تستهلكها الصورة، لذا تكلف صورة 4K أكثر من صورة 1K. وتضيف الصور المرجعية رموز صور إدخال.
لا تتضمن استجابة المهمة كائن usage. راجع Console Billing لمعرفة الرسوم.
المهمة التي تنتهي بحالة failed أو interrupted لا تنتج مخرجات ولا تُفوتر. وعملية إرسال مرفوضة بـ402 لم تنشئ مهمة.
الأخطاء
تستخدم الأخطاء على مستوى endpoint من مسار الصور غلاف أخطاء OpenAI:
{
"error": {
"message": "Model kind does not match this generation endpoint",
"type": "invalid_request_error",
"param": null,
"code": "model_kind_mismatch"
}
}يوجد معرّف الطلب في رأس الاستجابة X-Request-Id. سجّله مع معرّف المهمة.
| HTTP | error.code | المعنى |
|---|---|---|
| 400 | invalid_request_error | model مفقود، أو النص ليس كائن JSON |
| 400 | model_not_configured | معرّف النموذج غير موجود في الكتالوج الممكّن |
| 400 | chat_model_not_allowed | أُرسل نموذج دردشة إلى endpoint الصور |
| 400 | model_kind_mismatch | أُرسل نموذج فيديو أو نموذج آخر غير خاص بالصور |
| 402 | insufficient_balance | أرصدة غير كافية؛ لم تُنشأ مهمة |
| 404 | generation_task_not_found | معرّف المهمة غير معروف أو يخص حسابًا آخر |
| 429 | daily_spend_limit_exceeded | بلغ الحساب حد الإنفاق اليومي |
| 503 | generation_unavailable | التوليد غير متاح مؤقتًا؛ أعد المحاولة لاحقًا |
تُوصف أخطاء المصادقة في الأخطاء والحدود وإعادة المحاولة.