التوثيق
API

Gemini generateContent

Markdown

الصيغة الأصلية لـGoogle Gemini: مخصصة لـGemini CLI وGoogle GenAI SDK وعملاء REST.

الدليل الكامل
POSThttps://api.ailoot.ai/v1beta/models/{model}:generateContent
Gemini generateContent
curl "https://api.ailoot.ai/v1beta/models/gemini-3.8-flash:generateContent" \
  -H "x-goog-api-key: $AILOOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [
      {"role": "user", "parts": [{"text": "اقترح ثلاثة أسماء لمقهى."}]}
    ]
  }' 
200 OK
{
  "candidates": [
    {
      "content": {
        "role": "model",
        "parts": [{ "text": "1. «حبوب وبخار» 2. «طحن الصباح» 3. «مقهى الزاوية»" }]
      },
      "finishReason": "STOP"
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 9,
    "candidatesTokenCount": 27,
    "totalTokenCount": 36
  },
  "modelVersion": "gemini-3.8-flash"
}

المصادقة

  • x-goog-api-keyheaderمطلوب

    المفتاح sk-…. يمكن أيضاً استخدام Authorization: Bearer أو x-api-key. وللتوافق مع Google، يُقبل أيضاً ?key= في العنوان، بأدنى أولوية؛ أما ?api_key= فيُرفض بالرمز 400. نوصي باستخدام الترويسة حتى لا يظهر المفتاح في السجلات.

المسار

  • modelstringمطلوب

    معرّف النموذج الذي يدعم صيغة Gemini، مثل gemini-3.8-flash أو gemini-3.1-pro. المجموع 27.

POSThttps://api.ailoot.ai/v1beta/models/{model}:streamGenerateContent?alt=sse
GEThttps://api.ailoot.ai/v1beta/models

جسم الطلب

  • contentsarrayمطلوب

    رسائل تتضمن role (user/model) و parts: text وinlineData/fileData وfunctionCall/functionResponse. تُستخدم المرفقات التي يقبلها النموذج كمدخلات.

  • systemInstructionobjectاختياري

    تعليمات نظام نصية: {"parts": [{"text": "…"}]}.

  • generationConfigobjectاختياري

    generationConfig يقبل temperature, topP, topK, maxOutputTokens, thinkingConfig, responseMimeType (text/plain أو application/json), responseSchema أو responseJsonSchema (كائن JSON)، stopSequences (مصفوفة سلاسل نصية)، candidateCount: 1، وقيمة صحيحة لـ seed، وقيم عددية لـ presencePenalty و frequencyPenalty. تعتمد النطاقات والقدرات المسموح بها على النموذج المحدد؛ للحصول على رد JSON، اختر صيغة مخطط واحدة مدعومة و application/json. في النماذج النصية، تكون responseModalities — فقط ["TEXT"].

  • safetySettingsarrayاختياري

    كائنات تحتوي على الحقول المطلوبة category و threshold، والحقل الاختياري method. يجب أن تكون القيم مدعومة لدى النموذج المحدد.

  • toolsarrayاختياري

    دوال العميل functionDeclarations ينفذها تطبيقك. تقبل النماذج النصية أيضاً {"googleSearch": {}} و {"urlContext": {}}: كلاً منها على حدة أو معاً في مصفوفة tools. لا يمكن الجمع بين Google Search أو URL context وبين functionDeclarations في طلب واحد. لتوليد الصور، تتاح دوال العميل فقط. الأدوات المدمجة الأخرى وexplicit cache غير مدعومة. قد تتطلب Search/URL context حجز رصيد وفق الحد الكامل للإدخال؛ وتُحسب قيم toolUsePromptTokenCount الفعلية بوصفها توكنات إدخال.

  • toolConfigobjectاختياري

    functionCallingConfig: mode (AUTO/ANY/NONE/VALIDATED/MODE_UNSPECIFIED), allowedFunctionNames.

إذا كان النموذج لا يدعم حقلاً أو مرفقاً أو تركيبة أدوات، يُرفض الطلب قبل حجز الرصيد ولا يُخصم شيء. سيأتي رد HTTP 400 مع status INVALID_ARGUMENT والفئة invalid_request (في ErrorInfo.reason — INVALID_REQUEST). كما تعيد أخطاء JSON غير الصالح ومعاملات المسار والفحوص الأخرى الرمز 400؛ اقرأ نص الخطأ وRequest ID. تختلف القدرات بحسب النموذج: تحقق من صِيَغه ومدخلاته في الكتالوج.

PDF والصوت والفيديو والروابط

في نماذج Gemini التي تدعم نوع الإدخال المطلوب، parts[].inlineData يحتوي على mimeType وبيانات base64 غير فارغة؛ ويجب أن يكون PDF ملف PDF حقيقياً. fileData يحتوي على عنوان عام يبدأ بـ httpsضمن fileUri ونوع MIME للملف. يمكن ترك MIME دون تحديد لروابط YouTube. httpوالعناوين الخاصة و gs:// وكائنات Google Files API غير مدعومة، وكذلك الرفع عبر Google Files API. يمكن إضافة videoMetadata: startOffset/endOffset كسلسلة نصية بالثواني (مثل 1.5s) و fps أكبر من 0 ولا يتجاوز 24. يُتحقق من حجم الجسم والسياق والإدخال المسموح وحد الرد بحسب النموذج والصيغة.

الإدخالأنواع MIME المدعومة
صور مضمّنة inlineimage/png, image/jpeg, image/webp
المستنداتapplication/pdf; text/plain, text/html, text/css, text/csv, text/xml, text/rtf, text/markdown, text/javascript, application/x-javascript, text/x-python, application/x-python
الصوتaudio/wav, audio/mp3, audio/mpeg, audio/aiff, audio/aac, audio/ogg, audio/flac
الفيديوvideo/mp4, video/mpeg, video/mov, video/quicktime, video/avi, video/x-flv, video/mpg, video/webm, video/wmv, video/3gpp
import json, os, urllib.request

def generate(model, payload):
    req = urllib.request.Request(
        "https://api.ailoot.ai/v1beta/models/" + model + ":generateContent",
        data=json.dumps(payload).encode(),
        headers={"x-goog-api-key": os.environ["AILOOT_API_KEY"],
                 "Content-Type": "application/json"},
    )
    # إرسال واحد فقط. بعد انتهاء المهلة، تحقّق من Request ID في سجل الاستخدام قبل إعادة المحاولة.
    with urllib.request.urlopen(req, timeout=300) as response:
        print("Request ID:", response.headers.get("X-Request-ID"))
        return json.load(response)

import base64, pathlib, sys

# قدّم ملف PDF أو ملف صوت أو فيديو محليًا حقيقيًا، مع نوع MIME المدعوم له.
path, mime = pathlib.Path(sys.argv[1]), sys.argv[2]
payload = {"contents": [{"role": "user", "parts": [
    {"text": "صِف محتوى الملف بإيجاز."},
    {"inlineData": {"mimeType": mime,
                    "data": base64.b64encode(path.read_bytes()).decode()}},
]}]}
print(generate("gemini-3.8-flash", payload))
# مرفق بديل: {"fileData": {"mimeType": mime, "fileUri": public_https_url}}
# لعنوان URL فعلي على YouTube: {"fileData": {"fileUri": youtube_url}}

Search وURL context

دوال العميل functionDeclarations ينفذها تطبيقك. تقبل النماذج النصية أيضاً {"googleSearch": {}} و {"urlContext": {}}: كلاً منها على حدة أو معاً في مصفوفة tools. لا يمكن الجمع بين Google Search أو URL context وبين functionDeclarations في طلب واحد. لتوليد الصور، تتاح دوال العميل فقط. الأدوات المدمجة الأخرى وexplicit cache غير مدعومة. قد تتطلب Search/URL context حجز رصيد وفق الحد الكامل للإدخال؛ وتُحسب قيم toolUsePromptTokenCount الفعلية بوصفها توكنات إدخال.

{"tools": [{"googleSearch": {}}, {"urlContext": {}}]}

الصور في المخرجات

النموذج الوحيد الذي يمكنه إرجاع صور بصيغة Gemini هو gemini-3.1-flash-image. هذه قدرة مستقلة عن /v1/images/generations: نماذج الصور الأخرى لا تعمل هنا. يقبل هذا النموذج إدخالاً حتى 131072 توكن ورداً حتى 32768 توكن؛ وتُحجز مسبقاً التكلفة الكاملة لأطول رد ممكن.

responseModalities — مجموعة غير فارغة من TEXT/IMAGE دون تكرار. imageConfig.imageSize: 1K/2K/4K; aspectRatio: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 1:4, 4:1, 1:8, 8:1. يقبل هذا النموذج نصاً وصور PNG/JPEG/WebP مضمّنة inline؛ ولا يقبل PDF/audio/video/fileData أو أدوات Search/URL context المدمجة. التوافر والأسعار لمفتاحك موضحة في الكتالوج وفي GET /v1/models.

import json, os, urllib.request

def generate(model, payload):
    req = urllib.request.Request(
        "https://api.ailoot.ai/v1beta/models/" + model + ":generateContent",
        data=json.dumps(payload).encode(),
        headers={"x-goog-api-key": os.environ["AILOOT_API_KEY"],
                 "Content-Type": "application/json"},
    )
    # إرسال واحد فقط. بعد انتهاء المهلة، تحقّق من Request ID في سجل الاستخدام قبل إعادة المحاولة.
    with urllib.request.urlopen(req, timeout=300) as response:
        print("Request ID:", response.headers.get("X-Request-ID"))
        return json.load(response)

import base64, pathlib

reply = generate("gemini-3.1-flash-image", {
    "contents": [{"role": "user", "parts": [{"text": "ألوان مائية: منارة عند الفجر"}]}],
    "generationConfig": {
        "responseModalities": ["TEXT", "IMAGE"],
        "imageConfig": {"aspectRatio": "1:1", "imageSize": "1K"},
    },
})
index = 0
for candidate in reply.get("candidates", []):
    for part in candidate.get("content", {}).get("parts", []):
        if "text" in part:
            print(part["text"])
        blob = part.get("inlineData", {})
        if blob.get("mimeType", "").startswith("image/") and blob.get("data"):
            index += 1
            extension = {"image/png": "png", "image/jpeg": "jpg",
                         "image/webp": "webp"}.get(blob["mimeType"], "bin")
            pathlib.Path(f"gemini-image-v{index}.{extension}").write_bytes(
                base64.b64decode(blob["data"]))
print("All returned images:", index)

دورة function calling الكاملة

ينفذ العميل الدوال. أعد content الأصلي للنموذج بالكامل مع thoughtSignature دون تغيير، ثم functionResponse باستخدام name وid نفسيهما إذا كان id موجوداً في functionCall.

import json, os, urllib.request

def generate(model, payload):
    req = urllib.request.Request(
        "https://api.ailoot.ai/v1beta/models/" + model + ":generateContent",
        data=json.dumps(payload).encode(),
        headers={"x-goog-api-key": os.environ["AILOOT_API_KEY"],
                 "Content-Type": "application/json"},
    )
    # إرسال واحد فقط. بعد انتهاء المهلة، تحقّق من Request ID في سجل الاستخدام قبل إعادة المحاولة.
    with urllib.request.urlopen(req, timeout=300) as response:
        print("Request ID:", response.headers.get("X-Request-ID"))
        return json.load(response)

tools = [{"functionDeclarations": [{
    "name": "multiply", "description": "ضرب عددين",
    "parameters": {"type": "object", "properties": {
        "a": {"type": "number"}, "b": {"type": "number"}},
        "required": ["a", "b"]},
}]}]
contents = [{"role": "user", "parts": [{"text": "اضرب 7 في 8 باستخدام دالة"}]}]
for turn in range(4):  # ضع حدًا لحلقة الأدوات؛ لا تُعد إرسال طلب لم تتضح نتيجته.
    reply = generate("gemini-3.8-flash", {"contents": contents, "tools": tools})
    content = reply["candidates"][0]["content"]
    contents.append(content)  # احتفظ بجميع الأجزاء الأصلية وبـ thoughtSignature دون أي تغيير.
    results = []
    for part in content.get("parts", []):
        call = part.get("functionCall")
        if not call:
            continue
        if call["name"] != "multiply":
            raise ValueError("Unexpected function")
        args = call["args"]
        result = {"name": call["name"], "response": {"value": args["a"] * args["b"]}}
        if "id" in call:
            result["id"] = call["id"]
        results.append({"functionResponse": result})
    if not results:
        print(content)
        break
    contents.append({"role": "user", "parts": results})
else:
    raise RuntimeError("Tool loop limit reached")

الرد

  • candidates[].content.partsarray

    رد النموذج.

  • usageMetadataobject

    promptTokenCount, candidatesTokenCount, totalTokenCount.

هل لديك أسئلة أخرى؟ أرسل Request ID ووصفاً للمشكلة وسنساعدك على فهمها.مراسلة الدعم