tanbushi commited on
Commit
df1a318
·
1 Parent(s): e10a2a3

Sun Jun 8 12:53:28 CST 2025

Browse files
0-git-all.sh ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ git checkout dev
2
+ git add .
3
+ git commit -m "$(date)"
4
+ git push
5
+ git checkout main
6
+ git merge dev
7
+ git checkout dev
1-git-commit-dev.sh ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ git checkout dev
2
+ git add .
3
+ git commit -m "$(date)"
git-push-dev.sh → 2-git-push-dev.sh RENAMED
File without changes
git-merge.sh → 3-git-commit-merge copy.sh RENAMED
@@ -1,3 +1,6 @@
 
 
 
1
  git checkout main
2
  git merge dev
3
  git checkout dev
 
1
+ git checkout dev
2
+ git add .
3
+ git commit -m "$(date)"
4
  git checkout main
5
  git merge dev
6
  git checkout dev
app.py CHANGED
@@ -4,8 +4,7 @@ import httpx
4
  import logging
5
  import os, json
6
  import re # 用于URL路径处理
7
- from pprint import pprint
8
- from key_selector import KeySelector
9
 
10
  def get_target_url(url: str) -> str:
11
  """将url参数变了转换为合法的目标url;from http/ or https/ to http:// or https://"""
@@ -20,9 +19,7 @@ logging.basicConfig(level=logging.INFO)
20
  logger = logging.getLogger("uvicorn.error")
21
 
22
  # 从环境变量获取配置
23
- # UPSTREAM_HOST = os.getenv("UPSTREAM_HOST", "http://127.0.0.1") # 必须包含端口号
24
- # AUTH_TOKEN = os.getenv("AUTH_TOKEN", "YIG8ANC8q2QxFV_Gf8qwkPdBj2EpsqGqlfc3qvSdg7ksVkZcokOUtQn43XGK0NK3UUdBlIkYzNWefco_Wu4RcKnB0kpNgtZ2nTeqNum0i3fTUEhEcWSlJtT8FQgRK7bi") # 安全认证令牌
25
- X_Goog_Api_Key = os.getenv("X_Goog_Api_Key", "")
26
 
27
  @app.get("/")
28
  async def read_root():
@@ -32,40 +29,24 @@ async def read_root():
32
  async def proxy(request: Request, path: str):
33
  # 添加流式请求判断逻辑
34
  is_streaming = ":streamGenerateContent" in path.lower()
35
- print(f"path: {path}")
36
- # path = "https/generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent"
37
- # target_url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent"
38
  target_url = get_target_url(path)
39
- # target_url = f"{target_url}?key={X_Goog_Api_Key}"
40
- print(f"target_url: {target_url}")
41
  method = request.method
42
  headers = {k: v for k, v in request.headers.items()
43
  # if k.lower() not in ["host", "connection", "Postman-Token", "content-length"]}
44
  if k.lower() not in ["host", "content-length"]}
45
 
46
  key_selector = KeySelector()
47
- # print('apikey',key_selector.get_api_key()['key_value'])
48
-
49
- headers["X-Goog-Api-Key"] = key_selector.get_api_key()['key_value']
50
- # print(key_selector.api_key_info.key_value)
51
- # headers["host"] = "generativelanguage.googleapis.com"
52
 
53
  try:
54
  # 关键修复:禁用KeepAlive防止连接冲突
55
  transport = httpx.AsyncHTTPTransport(retries=3, http1=True)
56
-
57
  async with httpx.AsyncClient(
58
  transport=transport,
59
  timeout=httpx.Timeout(300.0, connect=30.0)
60
  ) as client:
61
  # 处理请求体
62
  req_content = await request.body()
63
- print(f"Request headers: {headers}")
64
- # print(f"req_content: {req_content}")
65
- # req_content_str = req_content.decode('utf-8') # 假设内容是 UTF-8 编码
66
- # print(f"req_content_str: {req_content_str}")
67
- print(f'target_url: {target_url}')
68
- print(f'method: {method}')
69
  # 发送请求到上游服务
70
  response = await client.request(
71
  method=method,
@@ -74,7 +55,6 @@ async def proxy(request: Request, path: str):
74
  content=req_content,
75
  follow_redirects=True # 自动处理重定向
76
  )
77
-
78
  if is_streaming:
79
  # 流式响应处理
80
  async def stream_generator():
@@ -88,7 +68,6 @@ async def proxy(request: Request, path: str):
88
  # 移除冲突头部
89
  headers = dict(response.headers)
90
  headers.pop("Content-Length", None)
91
-
92
  return StreamingResponse(
93
  content=stream_generator(),
94
  status_code=response.status_code,
@@ -96,16 +75,12 @@ async def proxy(request: Request, path: str):
96
  media_type="application/x-ndjson" # Gemini流式格式
97
  )
98
  else:
99
-
100
- print(f"response.status_code: {response.status_code}")
101
- print(f"response.text: {response.text}")
102
  # 解析 JSON 字符串
103
  try:
104
  data = json.loads(response.text)
105
  # 格式化输出 JSON 数据
106
  formatted_json = json.dumps(data, ensure_ascii=False, indent=4)
107
- print('formatted_json')
108
- print(formatted_json)
109
  # return formatted_json
110
  return Response(
111
  content=formatted_json,
@@ -113,23 +88,6 @@ async def proxy(request: Request, path: str):
113
  )
114
  except json.JSONDecodeError as e:
115
  print(f"Error decoding JSON: {e}")
116
-
117
-
118
- # # 详细记录错误响应
119
- # if response.status_code >= 400:
120
- # error_detail = response.text[:1000] # 增加错误详情长度
121
- # logger.error(f"Upstream error {response.status_code}: {error_detail}")
122
- # # 可选:记录完整响应到文件
123
- # # with open("error.log", "a") as f:
124
- # # f.write(f"\n--- {target_url} ---\n{response.text}\n")
125
-
126
- # # 流式传输响应
127
- # return StreamingResponse(
128
- # content=response.aiter_bytes(),
129
- # status_code=response.status_code,
130
- # headers=dict(response.headers)
131
- # )
132
-
133
  except httpx.ConnectError as e:
134
  logger.error(f"Connection failed to {target_url}: {e}")
135
  raise HTTPException(502, f"无法连接到上游服务: {target_url}") # Modified error message
@@ -137,15 +95,11 @@ async def proxy(request: Request, path: str):
137
  logger.error(f"Timeout: {e}")
138
  raise HTTPException(504, "上游服务响应超时")
139
  except httpx.HTTPError as e: # 捕获所有HTTP异常
140
- print('111111111111111111111')
141
-
142
  try:
143
  # 安全地获取异常信息
144
  error_type = type(e).__name__
145
-
146
  # 尝试获取状态码(如果存在)
147
  status_code = getattr(e, 'response', None) and e.response.status_code
148
-
149
  # 安全地获取错误详情
150
  error_detail = ""
151
  try:
@@ -154,7 +108,6 @@ async def proxy(request: Request, path: str):
154
  error_detail = e.response.text[:500] # 只取前500个字符
155
  except Exception as ex:
156
  error_detail = f"无法获取错误详情: {type(ex).__name__}"
157
-
158
  # 安全地记录日志
159
  logger.error(
160
  "HTTP代理错误 | "
@@ -163,13 +116,10 @@ async def proxy(request: Request, path: str):
163
  f"目标URL: {target_url} | "
164
  f"详情: {error_detail[:200]}" # 日志中只记录前200字符
165
  )
166
-
167
  # 打印到控制台以便调试
168
- print(f"111111111111111111111 - HTTP代理错误: {error_type}")
169
  print(f"目标URL: {target_url}")
170
  print(f"状态码: {status_code or 'N/A'}")
171
  print(f"错误详情: {error_detail[:500]}")
172
-
173
  except Exception as ex:
174
  # 如果记录日志本身出错,使用最安全的方式记录
175
  logger.error(f"记录HTTP错误时发生异常: {type(ex).__name__}")
@@ -180,12 +130,6 @@ async def proxy(request: Request, path: str):
180
  status_code=502,
181
  detail=f"网关服务错误: {error_type} (上游状态: {status_code or '未知'})"
182
  )
183
-
184
-
185
- print('111111111111111111111')
186
- # logger.error(f"HTTP error: {str(e)}")
187
-
188
- raise HTTPException(502, f"网关错误: {str(e)}")
189
  except Exception as e:
190
  logger.exception("Unexpected proxy error")
191
  raise HTTPException(500, f"内部服务器错误: {str(e)}")
 
4
  import logging
5
  import os, json
6
  import re # 用于URL路径处理
7
+ from key_selector import KeySelector # 自动选择key
 
8
 
9
  def get_target_url(url: str) -> str:
10
  """将url参数变了转换为合法的目标url;from http/ or https/ to http:// or https://"""
 
19
  logger = logging.getLogger("uvicorn.error")
20
 
21
  # 从环境变量获取配置
22
+ # X_Goog_Api_Key = os.getenv("X_Goog_Api_Key", "")
 
 
23
 
24
  @app.get("/")
25
  async def read_root():
 
29
  async def proxy(request: Request, path: str):
30
  # 添加流式请求判断逻辑
31
  is_streaming = ":streamGenerateContent" in path.lower()
 
 
 
32
  target_url = get_target_url(path)
 
 
33
  method = request.method
34
  headers = {k: v for k, v in request.headers.items()
35
  # if k.lower() not in ["host", "connection", "Postman-Token", "content-length"]}
36
  if k.lower() not in ["host", "content-length"]}
37
 
38
  key_selector = KeySelector()
39
+ headers["X-Goog-Api-Key"] = key_selector.get_api_key()['key_value'] # 从数据库获取API密钥
 
 
 
 
40
 
41
  try:
42
  # 关键修复:禁用KeepAlive防止连接冲突
43
  transport = httpx.AsyncHTTPTransport(retries=3, http1=True)
 
44
  async with httpx.AsyncClient(
45
  transport=transport,
46
  timeout=httpx.Timeout(300.0, connect=30.0)
47
  ) as client:
48
  # 处理请求体
49
  req_content = await request.body()
 
 
 
 
 
 
50
  # 发送请求到上游服务
51
  response = await client.request(
52
  method=method,
 
55
  content=req_content,
56
  follow_redirects=True # 自动处理重定向
57
  )
 
58
  if is_streaming:
59
  # 流式响应处理
60
  async def stream_generator():
 
68
  # 移除冲突头部
69
  headers = dict(response.headers)
70
  headers.pop("Content-Length", None)
 
71
  return StreamingResponse(
72
  content=stream_generator(),
73
  status_code=response.status_code,
 
75
  media_type="application/x-ndjson" # Gemini流式格式
76
  )
77
  else:
78
+ # 非流式响应处理
 
 
79
  # 解析 JSON 字符串
80
  try:
81
  data = json.loads(response.text)
82
  # 格式化输出 JSON 数据
83
  formatted_json = json.dumps(data, ensure_ascii=False, indent=4)
 
 
84
  # return formatted_json
85
  return Response(
86
  content=formatted_json,
 
88
  )
89
  except json.JSONDecodeError as e:
90
  print(f"Error decoding JSON: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  except httpx.ConnectError as e:
92
  logger.error(f"Connection failed to {target_url}: {e}")
93
  raise HTTPException(502, f"无法连接到上游服务: {target_url}") # Modified error message
 
95
  logger.error(f"Timeout: {e}")
96
  raise HTTPException(504, "上游服务响应超时")
97
  except httpx.HTTPError as e: # 捕获所有HTTP异常
 
 
98
  try:
99
  # 安全地获取异常信息
100
  error_type = type(e).__name__
 
101
  # 尝试获取状态码(如果存在)
102
  status_code = getattr(e, 'response', None) and e.response.status_code
 
103
  # 安全地获取错误详情
104
  error_detail = ""
105
  try:
 
108
  error_detail = e.response.text[:500] # 只取前500个字符
109
  except Exception as ex:
110
  error_detail = f"无法获取错误详情: {type(ex).__name__}"
 
111
  # 安全地记录日志
112
  logger.error(
113
  "HTTP代理错误 | "
 
116
  f"目标URL: {target_url} | "
117
  f"详情: {error_detail[:200]}" # 日志中只记录前200字符
118
  )
 
119
  # 打印到控制台以便调试
 
120
  print(f"目标URL: {target_url}")
121
  print(f"状态码: {status_code or 'N/A'}")
122
  print(f"错误详情: {error_detail[:500]}")
 
123
  except Exception as ex:
124
  # 如果记录日志本身出错,使用最安全的方式记录
125
  logger.error(f"记录HTTP错误时发生异常: {type(ex).__name__}")
 
130
  status_code=502,
131
  detail=f"网关服务错误: {error_type} (上游状态: {status_code or '未知'})"
132
  )
 
 
 
 
 
 
133
  except Exception as e:
134
  logger.exception("Unexpected proxy error")
135
  raise HTTPException(500, f"内部服务器错误: {str(e)}")