Gemini generateContent
Markdownالصيغة الأصلية لـGoogle Gemini: مخصصة لـGemini CLI وGoogle GenAI SDK وعملاء REST.
الدليل الكامل
https://api.ailoot.ai/v1beta/models/{model}:generateContentcurl "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": "اقترح ثلاثة أسماء لمقهى."}]}
]
}' from google import genai
from google.genai import types
import os
client = genai.Client(
api_key=os.environ["AILOOT_API_KEY"],
http_options=types.HttpOptions(base_url="https://api.ailoot.ai"), # دون /v1beta
)
resp = client.models.generate_content(
model="gemini-3.8-flash",
contents="اقترح ثلاثة أسماء لمقهى.",
)
print(resp.text)import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({
apiKey: process.env.AILOOT_API_KEY,
httpOptions: { baseUrl: "https://api.ailoot.ai" }, // دون /v1beta
});
const resp = await ai.models.generateContent({
model: "gemini-3.8-flash",
contents: "اقترح ثلاثة أسماء لمقهى.",
});
console.log(resp.text);{
"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.
https://api.ailoot.ai/v1beta/models/{model}:streamGenerateContent?alt=ssehttps://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 المدعومة |
|---|---|
| صور مضمّنة inline | image/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.