xidu commited on
Commit
0806587
·
1 Parent(s): ace75a8

feat: Deploy final version with latest google-genai SDK

Browse files
Files changed (2) hide show
  1. app.py +38 -39
  2. requirements.txt +1 -1
app.py CHANGED
@@ -5,13 +5,14 @@ import asyncio
5
  import os
6
  import random
7
  from contextlib import asynccontextmanager
 
8
 
9
  import uvicorn
10
  from fastapi import FastAPI, Request, HTTPException
11
  from fastapi.responses import StreamingResponse, JSONResponse
12
  from fastapi.middleware.cors import CORSMiddleware
13
- from google import genai
14
- from google.genai import types
15
 
16
  # 配置日志
17
  logging.basicConfig(
@@ -21,6 +22,7 @@ logging.basicConfig(
21
  )
22
  logger = logging.getLogger(__name__)
23
 
 
24
  # !!! 重要:管理您的 API 密钥 !!!
25
  # 为了安全,强烈建议您通过 Hugging Face Space 的 "Settings" -> "Secrets"
26
  # 来设置您的 API 密钥。例如,创建一个名为 "GOOGLE_API_KEYS" 的 Secret,
@@ -31,8 +33,8 @@ logger = logging.getLogger(__name__)
31
 
32
  # 为了方便首次测试,您可以先临时使用下面的列表:
33
  API_KEYS = [
34
- "YOUR_GOOGLE_API_KEY_1", # 请替换成您的第一个有效密钥
35
- "YOUR_GOOGLE_API_KEY_2", # 请替换成您的第二个有效密钥
36
  ]
37
 
38
 
@@ -47,7 +49,7 @@ def get_model_name(requested_model: str) -> str:
47
  return requested_model
48
  return "gemini-1.5-flash-latest"
49
 
50
- def convert_messages_to_gemini_format(messages):
51
  gemini_messages = []
52
  system_instruction = None
53
  for message in messages:
@@ -64,29 +66,34 @@ def convert_messages_to_gemini_format(messages):
64
 
65
  def handle_error_response(error):
66
  error_str = str(error).lower()
 
 
67
  if "prompt_feedback" in error_str:
68
  return "请求因安全或内容策略被拒绝。", "content_filter"
69
- elif "api_key_invalid" in error_str:
70
- return "提供的 API 密钥无效。", "invalid_request_error"
71
  return f"发生未知错误: {error}", "stop"
72
 
73
  def get_api_key():
74
- if not API_KEYS or all(key.startswith("YOUR_")):
75
  raise ValueError("API 密钥列表为空或未配置。请在 app.py 中设置它们或使用 Space Secrets。")
76
  return random.choice(API_KEYS)
77
 
78
-
79
  @asynccontextmanager
80
  async def lifespan(app: FastAPI):
81
  logger.info("应用启动...")
82
- if not API_KEYS or all(key.startswith("YOUR_")):
83
- logger.warning("警告:未检测到有效的 Google API 密钥。应用可能会在处理请求时失败。")
84
- else:
85
- logger.info(f"已加载 {len(API_KEYS)} 个 API 密钥。")
 
 
 
 
 
86
  yield
87
  logger.info("应用关闭。")
88
 
89
- app = FastAPI(lifespan=lifespan, title="Gemini API Proxy", version="1.4.0")
 
90
 
91
  app.add_middleware(
92
  CORSMiddleware,
@@ -96,13 +103,14 @@ app.add_middleware(
96
  allow_headers=["*"],
97
  )
98
 
 
99
  SAFETY_SETTINGS = [
100
- types.SafetySetting(category=cat, threshold=types.HarmBlockThreshold.BLOCK_NONE)
101
  for cat in [
102
- types.HarmCategory.HARM_CATEGORY_HARASSMENT,
103
- types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
104
- types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
105
- types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
106
  ]
107
  ]
108
 
@@ -118,10 +126,8 @@ async def stream_generator(model_name: str, gemini_messages, generation_config):
118
  ):
119
  if chunk.text:
120
  data = {
121
- "id": f"chatcmpl-{int(time.time())}",
122
- "object": "chat.completion.chunk",
123
- "created": int(time.time()),
124
- "model": model_name,
125
  "choices": [{"delta": {"content": chunk.text}}],
126
  }
127
  yield f"data: {json.dumps(data, ensure_ascii=False)}\n\n"
@@ -130,20 +136,16 @@ async def stream_generator(model_name: str, gemini_messages, generation_config):
130
  logger.error(f"流式响应生成时出错: {e}")
131
  error_message, finish_reason = handle_error_response(e)
132
  error_data = {
133
- "id": f"chatcmpl-{int(time.time())}",
134
- "object": "chat.completion.chunk",
135
- "created": int(time.time()),
136
- "model": model_name,
137
  "choices": [{"delta": {"content": error_message}, "finish_reason": finish_reason}],
138
  }
139
  yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n"
140
 
141
  finally:
142
  final_data = {
143
- "id": f"chatcmpl-{int(time.time())}",
144
- "object": "chat.completion.chunk",
145
- "created": int(time.time()),
146
- "model": model_name,
147
  "choices": [{"delta": {}, "finish_reason": "stop"}],
148
  }
149
  yield f"data: {json.dumps(final_data, ensure_ascii=False)}\n\n"
@@ -157,10 +159,10 @@ async def chat_completions(request: Request):
157
  messages = body.get("messages", [])
158
  gemini_messages, system_instruction = convert_messages_to_gemini_format(messages)
159
 
160
- generation_config = types.GenerationConfig(
161
  temperature=body.get("temperature", 0.7),
162
  top_p=body.get("top_p", 1.0),
163
- max_output_tokens=body.get("max_tokens", 2048),
164
  )
165
 
166
  if system_instruction:
@@ -181,14 +183,11 @@ async def chat_completions(request: Request):
181
  contents=gemini_messages,
182
  generation_config=generation_config
183
  )
184
-
185
  return {
186
- "id": f"chatcmpl-{int(time.time())}",
187
- "object": "chat.completion",
188
- "created": int(time.time()),
189
- "model": model_name,
190
  "choices": [{"message": {"role": "assistant", "content": response.text}, "finish_reason": "stop"}],
191
- "usage": {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0} # Usage info not easily available
192
  }
193
  except Exception as e:
194
  logger.error(f"非流式响应生成时出错: {e}")
 
5
  import os
6
  import random
7
  from contextlib import asynccontextmanager
8
+ from typing import List
9
 
10
  import uvicorn
11
  from fastapi import FastAPI, Request, HTTPException
12
  from fastapi.responses import StreamingResponse, JSONResponse
13
  from fastapi.middleware.cors import CORSMiddleware
14
+ # 正确的导入方式
15
+ import google.generativeai as genai
16
 
17
  # 配置日志
18
  logging.basicConfig(
 
22
  )
23
  logger = logging.getLogger(__name__)
24
 
25
+
26
  # !!! 重要:管理您的 API 密钥 !!!
27
  # 为了安全,强烈建议您通过 Hugging Face Space 的 "Settings" -> "Secrets"
28
  # 来设置您的 API 密钥。例如,创建一个名为 "GOOGLE_API_KEYS" 的 Secret,
 
33
 
34
  # 为了方便首次测试,您可以先临时使用下面的列表:
35
  API_KEYS = [
36
+ "AIzaSyCJGYHjn3m41mYpft9j3G9-RXWkDAcAsPs", # 请替换成您的第一个有效密钥
37
+ "AIzaSyCoDA9F9bsCXJx9p1CQqdKpeSO4n31DPt0", # 请替换成您的第二个有效密钥
38
  ]
39
 
40
 
 
49
  return requested_model
50
  return "gemini-1.5-flash-latest"
51
 
52
+ def convert_messages_to_gemini_format(messages: List[dict]):
53
  gemini_messages = []
54
  system_instruction = None
55
  for message in messages:
 
66
 
67
  def handle_error_response(error):
68
  error_str = str(error).lower()
69
+ if "api_key_invalid" in error_str:
70
+ return "提供的 API 密钥无效。", "invalid_request_error"
71
  if "prompt_feedback" in error_str:
72
  return "请求因安全或内容策略被拒绝。", "content_filter"
 
 
73
  return f"发生未知错误: {error}", "stop"
74
 
75
  def get_api_key():
76
+ if not API_KEYS or all("YOUR_GOOGLE_API_KEY" in key for key in API_KEYS):
77
  raise ValueError("API 密钥列表为空或未配置。请在 app.py 中设置它们或使用 Space Secrets。")
78
  return random.choice(API_KEYS)
79
 
 
80
  @asynccontextmanager
81
  async def lifespan(app: FastAPI):
82
  logger.info("应用启动...")
83
+ try:
84
+ if not API_KEYS or all("YOUR_GOOGLE_API_KEY" in key for key in API_KEYS):
85
+ logger.warning("警告:未检测到有效的 Google API 密钥。应用可能会在处理请求时失败。")
86
+ else:
87
+ # 启动时用一个密钥测试配置是否正确
88
+ genai.configure(api_key=API_KEYS[0])
89
+ logger.info(f"已加载 {len(API_KEYS)} 个 API 密钥,并成功配置。")
90
+ except Exception as e:
91
+ logger.error(f"Gemini 配置失败: {e}")
92
  yield
93
  logger.info("应用关闭。")
94
 
95
+
96
+ app = FastAPI(lifespan=lifespan, title="Gemini API Proxy", version="1.5.0")
97
 
98
  app.add_middleware(
99
  CORSMiddleware,
 
103
  allow_headers=["*"],
104
  )
105
 
106
+ # 使用 genai.types 来访问类型定义
107
  SAFETY_SETTINGS = [
108
+ genai.types.SafetySetting(category=cat, threshold=genai.types.HarmBlockThreshold.BLOCK_NONE)
109
  for cat in [
110
+ genai.types.HarmCategory.HARM_CATEGORY_HARASSMENT,
111
+ genai.types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
112
+ genai.types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
113
+ genai.types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
114
  ]
115
  ]
116
 
 
126
  ):
127
  if chunk.text:
128
  data = {
129
+ "id": f"chatcmpl-{int(time.time())}", "object": "chat.completion.chunk",
130
+ "created": int(time.time()), "model": model_name,
 
 
131
  "choices": [{"delta": {"content": chunk.text}}],
132
  }
133
  yield f"data: {json.dumps(data, ensure_ascii=False)}\n\n"
 
136
  logger.error(f"流式响应生成时出错: {e}")
137
  error_message, finish_reason = handle_error_response(e)
138
  error_data = {
139
+ "id": f"chatcmpl-{int(time.time())}", "object": "chat.completion.chunk",
140
+ "created": int(time.time()), "model": model_name,
 
 
141
  "choices": [{"delta": {"content": error_message}, "finish_reason": finish_reason}],
142
  }
143
  yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n"
144
 
145
  finally:
146
  final_data = {
147
+ "id": f"chatcmpl-{int(time.time())}", "object": "chat.completion.chunk",
148
+ "created": int(time.time()), "model": model_name,
 
 
149
  "choices": [{"delta": {}, "finish_reason": "stop"}],
150
  }
151
  yield f"data: {json.dumps(final_data, ensure_ascii=False)}\n\n"
 
159
  messages = body.get("messages", [])
160
  gemini_messages, system_instruction = convert_messages_to_gemini_format(messages)
161
 
162
+ generation_config = genai.types.GenerationConfig(
163
  temperature=body.get("temperature", 0.7),
164
  top_p=body.get("top_p", 1.0),
165
+ max_output_tokens=body.get("max_tokens", 8192),
166
  )
167
 
168
  if system_instruction:
 
183
  contents=gemini_messages,
184
  generation_config=generation_config
185
  )
 
186
  return {
187
+ "id": f"chatcmpl-{int(time.time())}", "object": "chat.completion",
188
+ "created": int(time.time()), "model": model_name,
 
 
189
  "choices": [{"message": {"role": "assistant", "content": response.text}, "finish_reason": "stop"}],
190
+ "usage": {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
191
  }
192
  except Exception as e:
193
  logger.error(f"非流式响应生成时出错: {e}")
requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
  fastapi
2
  uvicorn
3
- google-generativeai
4
  loguru
5
  httpx
 
1
  fastapi
2
  uvicorn
3
+ google-genai==1.20.0
4
  loguru
5
  httpx