Gemini (Google AI)
Google Gemini CLI와 Google AI SDK(@google/genai)가 그대로 연결되는 Gemini native 호환 엔드포인트.
PleumRouter는 Gemini native 포맷(generateContent / streamGenerateContent)을 그대로 노출합니다. Gemini CLI와 Google AI SDK로 하드와이어돈 도구는 OpenAI 호환 base URL로는 붙을 수 없기 때문에, 이 인바운드 경로가 필요합니다. 요청은 내부적으로 표준(OpenAI 호환) 파이프라인으로 변환되어 라우팅·과금·스트리밍 코어를 그대로 재사용하고, 응답은 다시 Gemini 포맷(candidates[] / usageMetadata)으로 직렬화됩니다.
연결하기#
Google AI SDK에서 baseUrl(Python은 HttpOptions(base_url=...))를 루트 https://router.pleum.ai로 설정하세요. SDK가 /v1beta/models/{model}:generateContent를 붙입니다.
from google import genai
client = genai.Client(
api_key="plm_...",
http_options=genai.types.HttpOptions(base_url="https://router.pleum.ai"),
)
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="Hello",
)
print(response.text)import { GoogleGenAI } from "@google/genai";
const client = new GoogleGenAI({
apiKey: "plm_...",
httpOptions: { baseUrl: "https://router.pleum.ai" },
});
const response = await client.models.generateContent({
model: "gemini-2.5-flash",
contents: "Hello",
});
console.log(response.text);Gemini CLI는 GOOGLE_GEMINI_BASE_URL을 루트로, plm_ 키를 GEMINI_API_KEY로 설정하세요.
export GEMINI_API_KEY="plm_..."
export GOOGLE_GEMINI_BASE_URL="https://router.pleum.ai"
gemini/v1beta를 붙이지 마세요. SDK가 다시 /v1beta/...를 붙여 경로가 중복되어 요청이 실패합니다. 반드시 루트 https://router.pleum.ai만 지정하세요.인증은 plm_ API 키를 Gemini 표준 헤더 x-goog-api-key 또는 쿼리 ?key=로 전달합니다. Authorization: Bearer 헤더도 함께 받습니다.
콘텐츠 생성#
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| contents | array | 필수 | {role, parts} 배열. role은 user·model. parts는 text·inline_data 블록 배열입니다. |
| systemInstruction | object | string | 선택 | 시스템 프롬프트. parts의 text만 추출해 system 메시지로 변환합니다. |
| generationConfig | object | 선택 | camelCase와 snake_case 모두 수용. temperature·maxOutputTokens·topP·stopSequences 등. |
| tools | array | 선택 | Gemini 형식의 함수 선언(functionDeclarations). 양방향 변환됩니다. |
| toolConfig | object | 선택 | 함수 호출 모드(functionCallingConfig). |
| safetySettings | array | 선택 | 받지만 upstream으로 전달되지는 않습니다. |
curl https://router.pleum.ai/v1beta/models/gemini-2.5-flash:generateContent \
-H "x-goog-api-key: plm_..." \
-H "content-type: application/json" \
-d '{
"systemInstruction": {"parts": [{"text": "You are a helpful assistant."}]},
"contents": [{"role": "user", "parts": [{"text": "Hello"}]}],
"generationConfig": {"temperature": 0.7, "maxOutputTokens": 1024}
}'응답은 Gemini 스키마를 따릅니다. candidates[].content.parts에 텍스트가 들어가고, 토큰 사용량은 usageMetadata.promptTokenCount / candidatesTokenCount / totalTokenCount로 반환됩니다. 이미지 입력은 inline_data(base64)로 보낼 수 있습니다.
{
"candidates": [
{
"content": {
"parts": [{"text": "Hello! How can I help you?"}],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}
],
"usageMetadata": {
"promptTokenCount": 5,
"candidatesTokenCount": 7,
"totalTokenCount": 12
}
}스트리밍#
:streamGenerateContent는 ?alt=sse 쿼리로 SSE 포맷을 사용합니다. 각 data: 라인은 GenerateContentResponse 형태의 JSON 청크이며 [DONE] 마커는 없습니다.
curl "https://router.pleum.ai/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse" \
-H "x-goog-api-key: plm_..." \
-H "content-type: application/json" \
-d '{
"contents": [{"role": "user", "parts": [{"text": "Hello"}]}]
}'
# Each SSE data: line is a GenerateContentResponse JSON chunk (no [DONE] marker).
# data: {"candidates":[{"content":{"parts":[{"text":"Hello"}],"role":"model"},"index":0}]}
# data: {"candidates":[{"content":{"parts":[{"text":"! How can I help you?"}],"role":"model"},"index":0}],"usageMetadata":{"promptTokenCount":5,"candidatesTokenCount":7,"totalTokenCount":12}}토큰 수 세기#
:countTokens는 generateContent와 같은 본문을 받아 {"totalTokens": <int>}를 반환합니다. 휴리스틱 추정값이며 실제 토크나이저 결과는 아닙니다.
curl https://router.pleum.ai/v1beta/models/gemini-2.5-flash:countTokens \
-H "x-goog-api-key: plm_..." \
-H "content-type: application/json" \
-d '{
"contents": [{"role": "user", "parts": [{"text": "Hello"}]}]
}'
# -> {"totalTokens": 5}모델 목록#
GET /v1beta/models는 Gemini 포맷의 모델 목록을 반환합니다. 같은 공개 가시성 규칙을 GET /v1/models와 공유합니다.
curl https://router.pleum.ai/v1beta/models \
-H "x-goog-api-key: plm_..."
# -> {"models": [{"name": "models/gemini-2.5-flash", "supportedGenerationMethods": [...]}, ...]}X-Cost-Krw(정수)·X-Cost-Usd(소수)로 노출됩니다(Anthropic 엔드포인트와 동일 패턴). 스트리밍은 종료 시점에야 비용이 확정되므로 헤더가 생략됩니다.