Gemini generateContent
MarkdownFormat natif de Google Gemini : pour Gemini CLI, le SDK Google GenAI et les clients REST.
Guide complet
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": "Propose trois noms pour un café."}]}
]
}' 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"), # sans /v1beta
)
resp = client.models.generate_content(
model="gemini-3.8-flash",
contents="Propose trois noms pour un café.",
)
print(resp.text)import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({
apiKey: process.env.AILOOT_API_KEY,
httpOptions: { baseUrl: "https://api.ailoot.ai" }, // sans /v1beta
});
const resp = await ai.models.generateContent({
model: "gemini-3.8-flash",
contents: "Propose trois noms pour un café.",
});
console.log(resp.text);{
"candidates": [
{
"content": {
"role": "model",
"parts": [{ "text": "1. « Grain et vapeur » 2. « La mouture du matin » 3. « Le café du coin »" }]
},
"finishReason": "STOP"
}
],
"usageMetadata": {
"promptTokenCount": 9,
"candidatesTokenCount": 27,
"totalTokenCount": 36
},
"modelVersion": "gemini-3.8-flash"
}Authentification
- x-goog-api-keyheaderobligatoire
Clé
sk-…. Conviennent égalementAuthorization: Beareroux-api-key. Pour assurer la compatibilité avec Google, le paramètre?key=est aussi accepté dans l’URL, avec la priorité la plus faible ;?api_key=est rejeté avec le statut 400. Nous recommandons de transmettre la clé dans un en-tête pour qu’elle n’apparaisse pas dans les journaux.
Chemin
- modelstringobligatoire
ID d’un modèle prenant en charge le format Gemini, par exemple
gemini-3.8-flashougemini-3.1-pro. Il y en a 27 au total.
https://api.ailoot.ai/v1beta/models/{model}:streamGenerateContent?alt=ssehttps://api.ailoot.ai/v1beta/modelsCorps de la requête
- contentsarrayobligatoire
Messages avec
role(user/model) etparts: text, inlineData/fileData, functionCall/functionResponse. Les pièces jointes doivent correspondre aux entrées acceptées par le modèle. - systemInstructionobjectfacultatif
Instruction système textuelle :
{"parts": [{"text": "…"}]}. - generationConfigobjectfacultatif
generationConfigacceptetemperature,topP,topK,maxOutputTokens,thinkingConfig,responseMimeType(text/plainouapplication/json),responseSchemaouresponseJsonSchema(objet JSON),stopSequences(tableau de chaînes),candidateCount: 1, le paramètre entierseed, les paramètres numériquespresencePenaltyetfrequencyPenalty. Les plages autorisées et les capacités dépendent du modèle exact ; pour une réponse JSON, choisissez une seule représentation de schéma prise en charge etapplication/json. Pour les modèles textuels,responseModalities— uniquement["TEXT"]. - safetySettingsarrayfacultatif
Objets avec les champs obligatoires
categoryetthreshold, le champ facultatifmethod. Les valeurs doivent être prises en charge par le modèle exact. - toolsarrayfacultatif
Les fonctions déclarées côté client dans
functionDeclarationssont exécutées par votre application. Les modèles textuels acceptent aussi{"googleSearch": {}}et{"urlContext": {}}: séparément ou ensemble dans le tableautools. Ni Google Search ni URL context ne peuvent être combinés avecfunctionDeclarationsdans une même requête. Pour les images en sortie, seules les fonctions clientes sont disponibles. Les autres outils intégrés et le cache explicite (explicit cache) ne sont pas pris en charge. Search/URL context peuvent exiger une réservation correspondant à la limite maximale d’entrée ; les valeurs réellestoolUsePromptTokenCountsont comptées comme tokens d’entrée. - toolConfigobjectfacultatif
functionCallingConfig: mode (AUTO/ANY/NONE/VALIDATED/MODE_UNSPECIFIED), allowedFunctionNames.
Si le modèle ne prend pas en charge un champ, une pièce jointe ou une combinaison d’outils, la requête est rejetée avant la réservation, sans débit. Vous recevrez un statut HTTP 400 avec status INVALID_ARGUMENT et la classe invalid_request (dans ErrorInfo.reason — INVALID_REQUEST). Un JSON incorrect, des erreurs de paramètres de chemin ou d’autres validations renvoient aussi 400; lisez le message d’erreur et le Request ID. Les capacités dépendent du modèle : vérifiez ses formats et les entrées acceptées dans le catalogue.
PDF, audio, vidéo et liens
Pour les modèles Gemini prenant en charge l’entrée concernée, parts[].inlineData contient mimeType et des données base64 non vides ; le PDF doit être un véritable fichier PDF. fileData contient une URL publique https dans fileUri et le type MIME du fichier. Pour YouTube, le MIME peut être omis. http, les adresses privées, gs:// et les objets Google Files API ne sont pas pris en charge, pas plus que l’envoi de fichiers via Google Files API. Pour une vidéo, vous pouvez ajouter videoMetadata : startOffset/endOffset sous forme de chaîne exprimée en secondes (par exemple, 1.5s) et fps supérieur à 0 et inférieur ou égal à 24. La taille du corps, le contexte, l’entrée autorisée et la limite de réponse sont vérifiés selon le modèle et le format.
| Entrée | Types MIME pris en charge |
|---|---|
| Images intégrées (inline) | image/png, image/jpeg, image/webp |
| Documents | 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 | audio/wav, audio/mp3, audio/mpeg, audio/aiff, audio/aac, audio/ogg, audio/flac |
| Vidéo | 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"},
)
# Un seul envoi. En cas de dépassement du délai, vérifiez le Request ID dans votre historique d’utilisation avant de réessayer.
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
# Fournissez un fichier PDF, audio ou vidéo local réel, avec son type MIME pris en charge.
path, mime = pathlib.Path(sys.argv[1]), sys.argv[2]
payload = {"contents": [{"role": "user", "parts": [
{"text": "Décris brièvement le contenu du fichier."},
{"inlineData": {"mimeType": mime,
"data": base64.b64encode(path.read_bytes()).decode()}},
]}]}
print(generate("gemini-3.8-flash", payload))
# Autre pièce jointe : {"fileData": {"mimeType": mime, "fileUri": public_https_url}}
# Pour une URL YouTube réelle : {"fileData": {"fileUri": youtube_url}}Search et URL context
Les fonctions déclarées côté client dans functionDeclarations sont exécutées par votre application. Les modèles textuels acceptent aussi {"googleSearch": {}} et {"urlContext": {}} : séparément ou ensemble dans le tableau tools. Ni Google Search ni URL context ne peuvent être combinés avec functionDeclarations dans une même requête. Pour les images en sortie, seules les fonctions clientes sont disponibles. Les autres outils intégrés et le cache explicite (explicit cache) ne sont pas pris en charge. Search/URL context peuvent exiger une réservation correspondant à la limite maximale d’entrée ; les valeurs réelles toolUsePromptTokenCount sont comptées comme tokens d’entrée.
{"tools": [{"googleSearch": {}}, {"urlContext": {}}]}Images en sortie
Seul le modèle suivant peut produire des images dans une réponse au format Gemini : gemini-3.1-flash-image. Cette capacité est distincte de /v1/images/generations : les autres modèles d’image ne fonctionnent pas ici. Ce modèle accepte jusqu’à 131072 tokens en entrée et 32768 en réponse ; le coût total de la réponse la plus longue est réservé à l’avance.
responseModalities — ensemble non vide de TEXT/IMAGE, sans doublons. 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. Ce modèle accepte du texte et des images inline PNG/JPEG/WebP. PDF/audio/video/fileData et les outils intégrés Search/URL context ne sont pas acceptés ici. La disponibilité et les prix pour votre clé figurent dans le catalogue et dans 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"},
)
# Un seul envoi. En cas de dépassement du délai, vérifiez le Request ID dans votre historique d’utilisation avant de réessayer.
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": "Aquarelle : un phare à l’aube"}]}],
"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)Cycle complet d’appel de fonctions (function calling)
Les fonctions sont exécutées par le client. Renvoyez l’intégralité du content d’origine du modèle, y compris thoughtSignature, sans modification, puis functionResponse avec les mêmes name et id, si cet id figurait dans 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"},
)
# Un seul envoi. En cas de dépassement du délai, vérifiez le Request ID dans votre historique d’utilisation avant de réessayer.
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": "Multiplier deux nombres",
"parameters": {"type": "object", "properties": {
"a": {"type": "number"}, "b": {"type": "number"}},
"required": ["a", "b"]},
}]}]
contents = [{"role": "user", "parts": [{"text": "Multiplie 7 par 8 à l’aide de la fonction"}]}]
for turn in range(4): # Limitez la boucle d’outils ; ne renvoyez pas une requête dont le résultat est incertain.
reply = generate("gemini-3.8-flash", {"contents": contents, "tools": tools})
content = reply["candidates"][0]["content"]
contents.append(content) # Conservez TOUTES (ALL) les parties (parts) d’origine et thoughtSignature sans les modifier.
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")Réponse
- candidates[].content.partsarray
Réponse du modèle.
- usageMetadataobject
promptTokenCount,candidatesTokenCount,totalTokenCount.