返回列表 发布新帖
查看: 35|回复: 0

Gemini2API 服务端实现,Python抛砖引玉版本

发表于 昨天 18:28 | 查看全部 |阅读模式

立刻注册账号,享受更清爽的界面!

您需要 登录 才可以下载或查看,没有账号?注册

×
https://github.com/HanaokaYuzu/Gemini-API
然后花了一点时间做了一个API,可以对接 Cherry Studio
➡️代码
  1. import asyncio
  2. import json
  3. from datetime import datetime, timezone

  4. from fastapi import FastAPI, HTTPException, Request
  5. from fastapi.middleware.cors import CORSMiddleware
  6. from fastapi.responses import JSONResponse
  7. from fastapi.responses import StreamingResponse
  8. from pydantic import BaseModel
  9. from typing import List, Optional
  10. import time
  11. import uuid
  12. import logging

  13. from gemini_webapi import GeminiClient, set_log_level
  14. from gemini_webapi.constants import Model

  15. # Configure logging
  16. logging.basicConfig(level=logging.INFO)
  17. logger = logging.getLogger(__name__)
  18. set_log_level("INFO")

  19. app = FastAPI(title="Gemini API FastAPI Server")

  20. # Add CORS middleware
  21. app.add_middleware(
  22.     CORSMiddleware,
  23.     allow_origins=["*"],
  24.     allow_credentials=True,
  25.     allow_methods=["*"],
  26.     allow_headers=["*"],
  27. )

  28. # Global client
  29. gemini_client = None

  30. # Authentication credentials
  31. SECURE_1PSID = ""
  32. SECURE_1PSIDTS = ""


  33. # Pydantic models for API requests and responses
  34. class Message(BaseModel):
  35.     role: str
  36.     content: str
  37.     name: Optional[str] = None


  38. class ChatCompletionRequest(BaseModel):
  39.     model: str
  40.     messages: List[Message]
  41.     temperature: Optional[float] = 0.7
  42.     top_p: Optional[float] = 1.0
  43.     n: Optional[int] = 1
  44.     stream: Optional[bool] = False
  45.     max_tokens: Optional[int] = None
  46.     presence_penalty: Optional[float] = 0
  47.     frequency_penalty: Optional[float] = 0
  48.     user: Optional[str] = None


  49. class Choice(BaseModel):
  50.     index: int
  51.     message: Message
  52.     finish_reason: str


  53. class Usage(BaseModel):
  54.     prompt_tokens: int
  55.     completion_tokens: int
  56.     total_tokens: int


  57. class ChatCompletionResponse(BaseModel):
  58.     id: str
  59.     object: str = "chat.completion"
  60.     created: int
  61.     model: str
  62.     choices: List[Choice]
  63.     usage: Usage


  64. class ModelData(BaseModel):
  65.     id: str
  66.     object: str = "model"
  67.     created: int
  68.     owned_by: str = "google"


  69. class ModelList(BaseModel):
  70.     object: str = "list"
  71.     data: List[ModelData]


  72. # Simple error handler middleware
  73. @app.middleware("http")
  74. async def error_handling(request: Request, call_next):
  75.     try:
  76.         return await call_next(request)
  77.     except Exception as e:
  78.         logger.error(f"Request failed: {str(e)}")
  79.         return JSONResponse(
  80.             status_code=500,
  81.             content={ "error": { "message": str(e), "type": "internal_server_error" } }
  82.         )


  83. # Get list of available models
  84. @app.get("/v1/models")
  85. async def list_models():
  86.     """返回 gemini_webapi 中声明的模型列表"""
  87.     now = int(datetime.now(tz=timezone.utc).timestamp())
  88.     data = [
  89.         {
  90.             "id": m.model_name,          # 如 "gemini-2.0-flash"
  91.             "object": "model",
  92.             "created": now,
  93.             "owned_by": "google-gemini-web"
  94.         }
  95.         for m in Model
  96.     ]
  97.     print(data)
  98.     return {"object": "list", "data": data}


  99. # Helper to convert between Gemini and OpenAI model names
  100. def map_model_name(openai_model_name: str) -> Model:
  101.     """根据模型名称字符串查找匹配的 Model 枚举值"""
  102.     # 打印所有可用模型以便调试
  103.     all_models = [m.model_name if hasattr(m, "model_name") else str(m) for m in Model]
  104.     logger.info(f"Available models: {all_models}")

  105.     # 首先尝试直接查找匹配的模型名称
  106.     for m in Model:
  107.         model_name = m.model_name if hasattr(m, "model_name") else str(m)
  108.         if openai_model_name.lower() in model_name.lower():
  109.             return m

  110.     # 如果找不到匹配项,使用默认映射
  111.     model_keywords = {
  112.         "gemini-pro": ["pro", "2.0"],
  113.         "gemini-pro-vision": ["vision", "pro"],
  114.         "gemini-flash": ["flash", "2.0"],
  115.         "gemini-1.5-pro": ["1.5", "pro"],
  116.         "gemini-1.5-flash": ["1.5", "flash"],
  117.     }

  118.     # 根据关键词匹配
  119.     keywords = model_keywords.get(openai_model_name, ["pro"])  # 默认使用pro模型

  120.     for m in Model:
  121.         model_name = m.model_name if hasattr(m, "model_name") else str(m)
  122.         if all(kw.lower() in model_name.lower() for kw in keywords):
  123.             return m

  124.     # 如果还是找不到,返回第一个模型
  125.     return next(iter(Model))


  126. # Prepare conversation history from OpenAI messages format
  127. def prepare_conversation(messages: List[Message]) -> str:
  128.     conversation = ""

  129.     for msg in messages:
  130.         if msg.role == "system":
  131.             conversation += f"System: {msg.content}\n\n"
  132.         elif msg.role == "user":
  133.             conversation += f"Human: {msg.content}\n\n"
  134.         elif msg.role == "assistant":
  135.             conversation += f"Assistant: {msg.content}\n\n"

  136.     # Add a final prompt for the assistant to respond to
  137.     conversation += "Assistant: "

  138.     return conversation


  139. # Dependency to get the initialized Gemini client
  140. async def get_gemini_client():
  141.     global gemini_client
  142.     if gemini_client is None:
  143.         try:
  144.             gemini_client = GeminiClient(SECURE_1PSID, SECURE_1PSIDTS)
  145.             await gemini_client.init(timeout=30)
  146.         except Exception as e:
  147.             logger.error(f"Failed to initialize Gemini client: {str(e)}")
  148.             raise HTTPException(
  149.                 status_code=500,
  150.                 detail=f"Failed to initialize Gemini client: {str(e)}"
  151.             )
  152.     return gemini_client


  153. @app.post("/v1/chat/completions")
  154. async def create_chat_completion(request: ChatCompletionRequest):
  155.     try:
  156.         # 确保客户端已初始化
  157.         global gemini_client
  158.         if gemini_client is None:
  159.             gemini_client = GeminiClient(SECURE_1PSID, SECURE_1PSIDTS)
  160.             await gemini_client.init(timeout=30)
  161.             logger.info("Gemini client initialized successfully")

  162.         # 转换消息为对话格式
  163.         conversation = prepare_conversation(request.messages)
  164.         logger.info(f"Prepared conversation: {conversation}")

  165.         # 获取适当的模型
  166.         model = map_model_name(request.model)
  167.         logger.info(f"Using model: {model}")

  168.         # 生成响应
  169.         logger.info("Sending request to Gemini...")
  170.         response = await gemini_client.generate_content(conversation, model=model)

  171.         # 提取文本响应
  172.         reply_text = ""
  173.         if hasattr(response, "text"):
  174.             reply_text = response.text
  175.         else:
  176.             reply_text = str(response)

  177.         logger.info(f"Response: {reply_text}")

  178.         if not reply_text or reply_text.strip() == "":
  179.             logger.warning("Empty response received from Gemini")
  180.             reply_text = "服务器返回了空响应。请检查 Gemini API 凭据是否有效。"

  181.         # 创建响应对象
  182.         completion_id = f"chatcmpl-{uuid.uuid4()}"
  183.         created_time = int(time.time())

  184.         # 检查客户端是否请求流式响应
  185.         if request.stream:
  186.             # 实现流式响应
  187.             async def generate_stream():
  188.                 # 创建 SSE 格式的流式响应
  189.                 # 先发送开始事件
  190.                 data = {
  191.                     "id": completion_id,
  192.                     "object": "chat.completion.chunk",
  193.                     "created": created_time,
  194.                     "model": request.model,
  195.                     "choices": [
  196.                         {
  197.                             "index": 0,
  198.                             "delta": {
  199.                                 "role": "assistant"
  200.                             },
  201.                             "finish_reason": None
  202.                         }
  203.                     ]
  204.                 }
  205.                 yield f"data: {json.dumps(data)}\n\n"

  206.                 # 模拟流式输出 - 将文本按字符分割发送
  207.                 for char in reply_text:
  208.                     data = {
  209.                         "id": completion_id,
  210.                         "object": "chat.completion.chunk",
  211.                         "created": created_time,
  212.                         "model": request.model,
  213.                         "choices": [
  214.                             {
  215.                                 "index": 0,
  216.                                 "delta": {
  217.                                     "content": char
  218.                                 },
  219.                                 "finish_reason": None
  220.                             }
  221.                         ]
  222.                     }
  223.                     yield f"data: {json.dumps(data)}\n\n"
  224.                     # 可选:添加短暂延迟以模拟真实的流式输出
  225.                     await asyncio.sleep(0.01)

  226.                 # 发送结束事件
  227.                 data = {
  228.                     "id": completion_id,
  229.                     "object": "chat.completion.chunk",
  230.                     "created": created_time,
  231.                     "model": request.model,
  232.                     "choices": [
  233.                         {
  234.                             "index": 0,
  235.                             "delta": { },
  236.                             "finish_reason": "stop"
  237.                         }
  238.                     ]
  239.                 }
  240.                 yield f"data: {json.dumps(data)}\n\n"
  241.                 yield "data: [DONE]\n\n"

  242.             return StreamingResponse(
  243.                 generate_stream(),
  244.                 media_type="text/event-stream"
  245.             )
  246.         else:
  247.             # 非流式响应(原来的逻辑)
  248.             result = {
  249.                 "id": completion_id,
  250.                 "object": "chat.completion",
  251.                 "created": created_time,
  252.                 "model": request.model,
  253.                 "choices": [
  254.                     {
  255.                         "index": 0,
  256.                         "message": {
  257.                             "role": "assistant",
  258.                             "content": reply_text
  259.                         },
  260.                         "finish_reason": "stop"
  261.                     }
  262.                 ],
  263.                 "usage": {
  264.                     "prompt_tokens": len(conversation.split()),
  265.                     "completion_tokens": len(reply_text.split()),
  266.                     "total_tokens": len(conversation.split()) + len(reply_text.split())
  267.                 }
  268.             }

  269.             logger.info(f"Returning response: {result}")
  270.             return result

  271.     except Exception as e:
  272.         logger.error(f"Error generating completion: {str(e)}", exc_info=True)
  273.         raise HTTPException(
  274.             status_code=500,
  275.             detail=f"Error generating completion: {str(e)}"
  276.         )


  277. @app.get("/")
  278. async def root():
  279.     return { "status": "online", "message": "Gemini API FastAPI Server is running" }


  280. if __name__ == "__main__":
  281.     import uvicorn

  282.     uvicorn.run("main:app", host="0.0.0.0", port=8000, log_level="info")
复制代码

0. 填入Secure_1PSID 和Secure_1PSIDTS  (登录下 Gemini 去 Application - Cookie 里面找)
  1. Secure_1PSID = "COOKIE VALUE HERE"
  2. Secure_1PSIDTS = "COOKIE VALUE HERE"
复制代码

1.安装一下依赖
  1. uv add fastapi uvicorn gemini-webapi
复制代码

或者pip也可以
  1. pip install fastapi uvicorn gemini-webapi
复制代码

2. 激活一下环境
  1. source venv/bin/activate
复制代码

3. 启动
  1. uvicorn main:app --reload --host 127.0.0.1 --port 8000
复制代码

tips: 没有任何密码,仅作为抛砖引玉
f57a81c002f22d394a9a66a3a5003828.jpg
0ab7c27a09c02f3eaf66c719641b4964.jpg
这个问题一般是 IP 不太行 或者 请求太频繁(后者等待一段时间即可),见issue:https://github.com/HanaokaYuzu/Gemini-API/issues/72
  1. "message": "500 {"detail":"Error generating completion: Failed to initialize client. SECURE_1PSIDTS could get expired frequently,
复制代码

爱生活,爱奶昔~
您需要登录后才可以回帖 登录 | 注册

本版积分规则

  • 关注公众号
  • 添加微信客服
© 2025 Naixi Networks 沪ICP备13020230号-1|沪公网安备 31010702007642号
关灯 在本版发帖
扫一扫添加微信客服
返回顶部
快速回复 返回顶部 返回列表