Gemini generateContent
MarkdownĐịnh dạng gốc của Google Gemini: dành cho Gemini CLI, Google GenAI SDK và ứng dụng REST.
Hướng dẫn đầy đủ
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": "Nghĩ ra ba tên cho một quán cà phê."}]}
]
}' 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"), # không có /v1beta
)
resp = client.models.generate_content(
model="gemini-3.8-flash",
contents="Nghĩ ra ba tên cho một quán cà phê.",
)
print(resp.text)import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({
apiKey: process.env.AILOOT_API_KEY,
httpOptions: { baseUrl: "https://api.ailoot.ai" }, // không có /v1beta
});
const resp = await ai.models.generateContent({
model: "gemini-3.8-flash",
contents: "Nghĩ ra ba tên cho một quán cà phê.",
});
console.log(resp.text);{
"candidates": [
{
"content": {
"role": "model",
"parts": [{ "text": "1. «Hạt và Hơi nước» 2. «Xay buổi sáng» 3. «Quán cà phê góc phố»" }]
},
"finishReason": "STOP"
}
],
"usageMetadata": {
"promptTokenCount": 9,
"candidatesTokenCount": 27,
"totalTokenCount": 36
},
"modelVersion": "gemini-3.8-flash"
}Xác thực
- x-goog-api-keyheaderbắt buộc
Khóa
sk-…. Cũng có thể dùngAuthorization: Bearerhoặcx-api-key. Để tương thích với Google, cũng chấp nhận?key=trong địa chỉ — với mức ưu tiên thấp nhất;?api_key=bị từ chối với mã 400. Nên dùng header để khóa không xuất hiện trong log.
Đường dẫn
- modelstringbắt buộc
ID mô hình hỗ trợ định dạng Gemini, ví dụ
gemini-3.8-flashhoặcgemini-3.1-pro. Tổng cộng 27.
https://api.ailoot.ai/v1beta/models/{model}:streamGenerateContent?alt=ssehttps://api.ailoot.ai/v1beta/modelsPhần thân yêu cầu
- contentsarraybắt buộc
Tin nhắn có
role(user/model) vàparts: text, inlineData/fileData, functionCall/functionResponse. Tệp đính kèm phải thuộc loại đầu vào mà mô hình hỗ trợ. - systemInstructionobjectkhông bắt buộc
Chỉ dẫn hệ thống dạng văn bản:
{"parts": [{"text": "…"}]}. - generationConfigobjectkhông bắt buộc
generationConfigchấp nhậntemperature,topP,topK,maxOutputTokens,thinkingConfig,responseMimeType(text/plainhoặcapplication/json),responseSchemahoặcresponseJsonSchema(đối tượng JSON),stopSequences(mảng chuỗi),candidateCount: 1, tham số số nguyênseed, các tham số sốpresencePenaltyvàfrequencyPenalty. Phạm vi giá trị và khả năng hỗ trợ phụ thuộc vào mô hình cụ thể; để nhận phản hồi JSON, hãy chọn một dạng lược đồ được hỗ trợ vàapplication/json. Với các mô hình văn bản,responseModalities— chỉ["TEXT"]. - safetySettingsarraykhông bắt buộc
Các đối tượng có các trường bắt buộc
categoryvàthreshold, trường không bắt buộcmethod. Các giá trị phải được mô hình cụ thể hỗ trợ. - toolsarraykhông bắt buộc
Các hàm phía máy khách
functionDeclarationsđược ứng dụng của bạn thực thi. Với các mô hình văn bản, cũng chấp nhận{"googleSearch": {}}và{"urlContext": {}}: riêng lẻ hoặc cùng nhau trong mảngtools. Không được kết hợp Google Search hay URL context vớifunctionDeclarationstrong cùng một yêu cầu. Đối với ảnh đầu ra, chỉ hỗ trợ các hàm phía máy khách. Các công cụ tích hợp khác và explicit cache không được hỗ trợ. Search/URL context có thể yêu cầu giữ tiền theo toàn bộ giới hạn đầu vào; sốtoolUsePromptTokenCountthực tế được tính là token đầu vào. - toolConfigobjectkhông bắt buộc
functionCallingConfig: mode (AUTO/ANY/NONE/VALIDATED/MODE_UNSPECIFIED), allowedFunctionNames.
Nếu mô hình không hỗ trợ trường, tệp đính kèm hoặc tổ hợp công cụ, yêu cầu sẽ bị từ chối trước khi giữ tiền — không có khoản nào bị khấu trừ. Phản hồi HTTP 400 có status INVALID_ARGUMENT và lớp invalid_request (trong ErrorInfo.reason — INVALID_REQUEST). JSON không hợp lệ, lỗi tham số đường dẫn và các lỗi kiểm tra khác cũng trả về 400; hãy đọc thông báo lỗi và Request ID. Khả năng hỗ trợ phụ thuộc vào mô hình: kiểm tra định dạng và đầu vào của mô hình trong danh mục.
PDF, âm thanh, video và liên kết
Với các mô hình Gemini hỗ trợ loại đầu vào tương ứng, parts[].inlineData chứa mimeType và dữ liệu base64 không rỗng; PDF phải là tệp PDF thực. fileData chứa địa chỉ công khai dùng https trong fileUri và MIME của loại tệp. Với YouTube, có thể không chỉ định MIME. http, địa chỉ riêng tư, gs:// và các đối tượng Google Files API không được hỗ trợ; tải lên qua Google Files API cũng không được hỗ trợ. Với video, có thể thêm videoMetadata: startOffset/endOffset dưới dạng chuỗi tính bằng giây (ví dụ, 1.5s) và fps lớn hơn 0 và không quá 24. Kích thước phần thân, ngữ cảnh, đầu vào được phép và giới hạn phản hồi được kiểm tra theo mô hình và định dạng.
| Đầu vào | Các MIME được hỗ trợ |
|---|---|
| Ảnh inline | image/png, image/jpeg, image/webp |
| Tài liệu | 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 |
| Âm thanh | 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"},
)
# Chỉ gửi một lần. Nếu hết thời gian chờ, hãy kiểm tra Request ID trong lịch sử sử dụng trước khi thử lại.
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
# Cung cấp một tệp PDF, âm thanh hoặc video có thật trên máy cùng loại MIME được hỗ trợ của tệp đó.
path, mime = pathlib.Path(sys.argv[1]), sys.argv[2]
payload = {"contents": [{"role": "user", "parts": [
{"text": "Mô tả ngắn gọn nội dung tệp."},
{"inlineData": {"mimeType": mime,
"data": base64.b64encode(path.read_bytes()).decode()}},
]}]}
print(generate("gemini-3.8-flash", payload))
# Cách đính kèm khác: {"fileData": {"mimeType": mime, "fileUri": public_https_url}}
# Với URL YouTube có thật: {"fileData": {"fileUri": youtube_url}}Search và URL context
Các hàm phía máy khách functionDeclarations được ứng dụng của bạn thực thi. Với các mô hình văn bản, cũng chấp nhận {"googleSearch": {}} và {"urlContext": {}}: riêng lẻ hoặc cùng nhau trong mảng tools. Không được kết hợp Google Search hay URL context với functionDeclarations trong cùng một yêu cầu. Đối với ảnh đầu ra, chỉ hỗ trợ các hàm phía máy khách. Các công cụ tích hợp khác và explicit cache không được hỗ trợ. Search/URL context có thể yêu cầu giữ tiền theo toàn bộ giới hạn đầu vào; số toolUsePromptTokenCount thực tế được tính là token đầu vào.
{"tools": [{"googleSearch": {}}, {"urlContext": {}}]}Ảnh đầu ra
Chỉ mô hình sau có thể trả về ảnh trong phản hồi định dạng Gemini: gemini-3.1-flash-image. Đây là khả năng riêng biệt so với /v1/images/generations: các mô hình tạo ảnh khác không hoạt động ở đây. Mô hình này hỗ trợ đầu vào tối đa 131072 token, phản hồi tối đa 32768; toàn bộ chi phí của phản hồi dài nhất được giữ trước.
responseModalities — tập hợp TEXT/IMAGE không rỗng, không có phần tử trùng lặp. 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. Đầu vào của mô hình này là văn bản và ảnh inline PNG/JPEG/WebP; PDF/audio/video/fileData và Search/URL context tích hợp không được chấp nhận ở đây. Khả năng truy cập và giá dành cho khóa của bạn có trong danh mục và trong 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"},
)
# Chỉ gửi một lần. Nếu hết thời gian chờ, hãy kiểm tra Request ID trong lịch sử sử dụng trước khi thử lại.
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": "Tranh màu nước: ngọn hải đăng lúc bình minh"}]}],
"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)Chu trình gọi hàm đầy đủ
Ứng dụng máy khách thực thi các hàm. Gửi lại toàn bộ content gốc của mô hình cùng thoughtSignature mà không thay đổi, sau đó gửi functionResponse với cùng name và id nếu id có trong 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"},
)
# Chỉ gửi một lần. Nếu hết thời gian chờ, hãy kiểm tra Request ID trong lịch sử sử dụng trước khi thử lại.
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": "Nhân hai số",
"parameters": {"type": "object", "properties": {
"a": {"type": "number"}, "b": {"type": "number"}},
"required": ["a", "b"]},
}]}]
contents = [{"role": "user", "parts": [{"text": "Nhân 7 với 8 bằng hàm"}]}]
for turn in range(4): # Giới hạn số vòng gọi công cụ; không gửi lại yêu cầu khi chưa rõ kết quả.
reply = generate("gemini-3.8-flash", {"contents": contents, "tools": tools})
content = reply["candidates"][0]["content"]
contents.append(content) # Giữ nguyên TẤT CẢ các phần gốc và 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")Phản hồi
- candidates[].content.partsarray
Phản hồi của mô hình.
- usageMetadataobject
promptTokenCount,candidatesTokenCount,totalTokenCount.