Gemini generateContent
MarkdownHet native Google Gemini-formaat: voor Gemini CLI, Google GenAI SDK en REST-clients.
Volledige gids
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": "Bedenk drie namen voor een koffiebar."}]}
]
}' 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"), # zonder /v1beta
)
resp = client.models.generate_content(
model="gemini-3.8-flash",
contents="Bedenk drie namen voor een koffiebar.",
)
print(resp.text)import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({
apiKey: process.env.AILOOT_API_KEY,
httpOptions: { baseUrl: "https://api.ailoot.ai" }, // zonder /v1beta
});
const resp = await ai.models.generateContent({
model: "gemini-3.8-flash",
contents: "Bedenk drie namen voor een koffiebar.",
});
console.log(resp.text);{
"candidates": [
{
"content": {
"role": "model",
"parts": [{ "text": "1. «Boon en stoom» 2. «De ochtendmaling» 3. «Koffiehuis op de hoek»" }]
},
"finishReason": "STOP"
}
],
"usageMetadata": {
"promptTokenCount": 9,
"candidatesTokenCount": 27,
"totalTokenCount": 36
},
"modelVersion": "gemini-3.8-flash"
}Authenticatie
- x-goog-api-keyheaderverplicht
Sleutel
sk-…. Ook deze headers werken:Authorization: Bearerofx-api-key. Voor compatibiliteit met Google wordt ook?key=in het adres geaccepteerd — met de laagste prioriteit;?api_key=wordt afgewezen met 400. We raden een header aan: zo komt de sleutel niet in de logs terecht.
Pad
- modelstringverplicht
Model-ID met het Gemini-formaat, bijvoorbeeld
gemini-3.8-flashofgemini-3.1-pro. In totaal 27.
https://api.ailoot.ai/v1beta/models/{model}:streamGenerateContent?alt=ssehttps://api.ailoot.ai/v1beta/modelsVerzoekbody
- contentsarrayverplicht
Berichten met
role(user/model) enparts: text, inlineData/fileData, functionCall/functionResponse. Alleen bijlagen die het model als invoer ondersteunt. - systemInstructionobjectoptioneel
Systeeminstructie in tekstvorm:
{"parts": [{"text": "…"}]}. - generationConfigobjectoptioneel
generationConfigaccepteerttemperature,topP,topK,maxOutputTokens,thinkingConfig,responseMimeType(text/plainofapplication/json),responseSchemaofresponseJsonSchema(JSON-object),stopSequences(array van strings),candidateCount: 1, een geheel getal voorseed, numerieke waarden voorpresencePenaltyenfrequencyPenalty. Toegestane bereiken en mogelijkheden hangen af van het specifieke model; kies voor een JSON-antwoord één ondersteunde schemavorm enapplication/json. Bij tekstmodellen isresponseModalitiesuitsluitend["TEXT"]. - safetySettingsarrayoptioneel
Objecten met verplichte
categoryenthreshold, optionelemethod. Het specifieke model moet deze waarden ondersteunen. - toolsarrayoptioneel
Clientfuncties in
functionDeclarationsworden uitgevoerd door je applicatie. Bij tekstmodellen worden ook{"googleSearch": {}}en{"urlContext": {}}geaccepteerd: afzonderlijk of samen in de arraytools. Noch Google Search noch URL context kan worden gecombineerd metfunctionDeclarationsin hetzelfde verzoek. Voor afbeeldingen als output zijn alleen clientfuncties beschikbaar. Andere ingebouwde tools en explicit cache worden niet ondersteund. Search/URL context kunnen een reservering vereisen op basis van de volledige invoerlimiet; de daadwerkelijketoolUsePromptTokenCountworden als invoertokens geteld. - toolConfigobjectoptioneel
functionCallingConfig: mode (AUTO/ANY/NONE/VALIDATED/MODE_UNSPECIFIED), allowedFunctionNames.
Als het model een veld, bijlage of combinatie van tools niet ondersteunt, wordt het verzoek vóór de reservering afgewezen — er wordt niets afgeschreven. Je ontvangt HTTP 400 met status INVALID_ARGUMENT en de klasse invalid_request (in ErrorInfo.reason — INVALID_REQUEST). Ongeldige JSON, fouten in padparameters en andere controles geven ook 400 terug; lees de foutmelding en de Request ID. De mogelijkheden hangen af van het model: controleer de formaten en invoertypen in de catalogus.
PDF, audio, video en links
Voor Gemini-modellen die dit invoertype ondersteunen, geldt: parts[].inlineData bevat mimeType en niet-lege base64-data; een PDF moet een echt PDF-bestand zijn. fileData bevat een openbaar https-adres in fileUri en het MIME-type van het bestand. Voor YouTube mag je het MIME-type weglaten. http, niet-openbare adressen, gs:// en Google Files API-objecten worden niet ondersteund; uploaden via Google Files API ook niet. Bij video kun je videoMetadata: startOffset/endOffset toevoegen als string in seconden (bijvoorbeeld 1.5s) en fps moet groter dan 0 en maximaal 24 zijn. De bodygrootte, context, toegestane invoer en antwoordlimiet worden per model en formaat gecontroleerd.
| Invoer | Ondersteunde MIME-typen |
|---|---|
| Inline-afbeeldingen | image/png, image/jpeg, image/webp |
| Documenten | 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 |
| Video | 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"},
)
# Eén keer versturen. Controleer na een time-out de Request ID in je gebruiksgeschiedenis voordat je opnieuw probeert.
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
# Geef een echt lokaal PDF-, audio- of videobestand op, met het ondersteunde MIME-type.
path, mime = pathlib.Path(sys.argv[1]), sys.argv[2]
payload = {"contents": [{"role": "user", "parts": [
{"text": "Beschrijf kort de inhoud van het bestand."},
{"inlineData": {"mimeType": mime,
"data": base64.b64encode(path.read_bytes()).decode()}},
]}]}
print(generate("gemini-3.8-flash", payload))
# Alternatieve bijlage: {"fileData": {"mimeType": mime, "fileUri": public_https_url}}
# Voor een echte YouTube-URL: {"fileData": {"fileUri": youtube_url}}Search en URL context
Clientfuncties in functionDeclarations worden uitgevoerd door je applicatie. Bij tekstmodellen worden ook {"googleSearch": {}} en {"urlContext": {}} geaccepteerd: afzonderlijk of samen in de array tools. Noch Google Search noch URL context kan worden gecombineerd met functionDeclarations in hetzelfde verzoek. Voor afbeeldingen als output zijn alleen clientfuncties beschikbaar. Andere ingebouwde tools en explicit cache worden niet ondersteund. Search/URL context kunnen een reservering vereisen op basis van de volledige invoerlimiet; de daadwerkelijke toolUsePromptTokenCount worden als invoertokens geteld.
{"tools": [{"googleSearch": {}}, {"urlContext": {}}]}Afbeeldingen als output
Afbeeldingen in antwoorden in het Gemini-formaat worden alleen ondersteund door gemini-3.1-flash-image. Dit staat los van /v1/images/generations: andere afbeeldingsmodellen werken hier niet. Dit model accepteert maximaal 131072 invoertokens en 32768 antwoordtokens; de volledige kosten van het langst mogelijke antwoord worden vooraf gereserveerd.
responseModalities — een niet-lege verzameling TEXT/IMAGE zonder duplicaten. 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. Dit model accepteert tekst en inline PNG/JPEG/WebP als invoer; PDF/audio/video/fileData en ingebouwde Search/URL context worden hier niet geaccepteerd. Beschikbaarheid en prijzen voor jouw sleutel vind je in de catalogus en in 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"},
)
# Eén keer versturen. Controleer na een time-out de Request ID in je gebruiksgeschiedenis voordat je opnieuw probeert.
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": "Aquarel: een vuurtoren bij zonsopgang"}]}],
"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)De volledige function calling-cyclus
De client voert de functies uit. Geef de volledige oorspronkelijke content van het model met thoughtSignature ongewijzigd terug, daarna functionResponse met dezelfde name en dezelfde id, als die id in functionCall aanwezig was.
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"},
)
# Eén keer versturen. Controleer na een time-out de Request ID in je gebruiksgeschiedenis voordat je opnieuw probeert.
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": "Twee getallen vermenigvuldigen",
"parameters": {"type": "object", "properties": {
"a": {"type": "number"}, "b": {"type": "number"}},
"required": ["a", "b"]},
}]}]
contents = [{"role": "user", "parts": [{"text": "Vermenigvuldig 7 met 8 met behulp van de functie"}]}]
for turn in range(4): # Beperk de toollus; verstuur een verzoek met een onduidelijk resultaat niet opnieuw.
reply = generate("gemini-3.8-flash", {"contents": contents, "tools": tools})
content = reply["candidates"][0]["content"]
contents.append(content) # Bewaar ALLE (ALL) oorspronkelijke onderdelen (parts) en thoughtSignature ongewijzigd.
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")Antwoord
- candidates[].content.partsarray
Antwoord van het model.
- usageMetadataobject
promptTokenCount,candidatesTokenCount,totalTokenCount.