Ge-AI commited on
Commit
b14ef71
·
verified ·
1 Parent(s): a18c6c7

Upload 4 files

Browse files
Files changed (1) hide show
  1. api.py +55 -21
api.py CHANGED
@@ -47,12 +47,12 @@ def check_private_key():
47
  break
48
 
49
  if not PRIVATE_KEY:
50
- logging.warning("PRIVATE_KEY 未设置,服务将不进行鉴权!")
51
  return None
52
 
53
  if not key_from_header or key_from_header != PRIVATE_KEY:
54
- logging.warning(f"未授权访问: Path={request.path}, IP={request.remote_addr}")
55
- return jsonify({"error": "Unauthorized. Correct 'Authorization: Bearer <PRIVATE_KEY>' or 'X-API-KEY: <PRIVATE_KEY>' header is required."}), 401
56
  return None
57
 
58
  # 密钥管理
@@ -69,7 +69,7 @@ class KeyManager:
69
  def get(self):
70
  with self.lock:
71
  if not self.key_list:
72
- raise ValueError("API key pool is empty.")
73
 
74
  now = time.time()
75
  for _ in range(len(self.key_list)):
@@ -119,7 +119,7 @@ def create_session(apikey, external_user_id=None):
119
  resp.raise_for_status()
120
  return resp.json()["data"]["id"]
121
  except Exception as e:
122
- logging.error(f"创建会话失败: {e}")
123
  raise
124
 
125
  # 处理流式请求
@@ -141,6 +141,7 @@ def handle_stream_request(apikey, session_id, query, endpoint_id, model_name):
141
  with requests.post(url, json=payload, headers=headers, stream=True, timeout=180) as resp:
142
  resp.raise_for_status()
143
  first_chunk = True
 
144
 
145
  for line in resp.iter_lines():
146
  if not line:
@@ -152,6 +153,9 @@ def handle_stream_request(apikey, session_id, query, endpoint_id, model_name):
152
 
153
  data = line[5:].strip()
154
  if data == "[DONE]":
 
 
 
155
  yield "data: [DONE]\n\n"
156
  break
157
 
@@ -161,6 +165,10 @@ def handle_stream_request(apikey, session_id, query, endpoint_id, model_name):
161
  content = event_data.get("answer", "")
162
  if content is None:
163
  continue
 
 
 
 
164
 
165
  delta = {}
166
  if first_chunk:
@@ -177,7 +185,7 @@ def handle_stream_request(apikey, session_id, query, endpoint_id, model_name):
177
  }
178
  yield format_openai_sse_delta(chunk)
179
  except Exception as e:
180
- logging.warning(f"处理流数据出错: {e}")
181
  continue
182
  except Exception as e:
183
  error = {
@@ -189,8 +197,10 @@ def handle_stream_request(apikey, session_id, query, endpoint_id, model_name):
189
  }
190
  yield format_openai_sse_delta(error)
191
  yield "data: [DONE]\n\n"
 
 
192
 
193
- # 处理非流式请求
194
  def handle_non_stream_request(apikey, session_id, query, endpoint_id, model_name):
195
  url = f"{ONDEMAND_API_BASE}/sessions/{session_id}/query"
196
  payload = {
@@ -207,6 +217,10 @@ def handle_non_stream_request(apikey, session_id, query, endpoint_id, model_name
207
  response_data = resp.json()
208
  content = response_data["data"]["answer"]
209
 
 
 
 
 
210
  return jsonify({
211
  "id": f"chatcmpl-{str(uuid.uuid4())[:12]}",
212
  "object": "chat.completion",
@@ -220,7 +234,9 @@ def handle_non_stream_request(apikey, session_id, query, endpoint_id, model_name
220
  "usage": {}
221
  })
222
  except Exception as e:
223
- return jsonify({"error": str(e)}), 500
 
 
224
 
225
  # 路��处理
226
  @app.route("/v1/chat/completions", methods=["POST"])
@@ -228,11 +244,11 @@ def chat_completions():
228
  try:
229
  data = request.json
230
  if not data or "messages" not in data:
231
- return jsonify({"error": "Invalid request format"}), 400
232
 
233
  messages = data["messages"]
234
  if not isinstance(messages, list) or not messages:
235
- return jsonify({"error": "Messages must be a non-empty list"}), 400
236
 
237
  model = data.get("model", "gpt-4o")
238
  endpoint_id = get_endpoint_id(model)
@@ -259,7 +275,7 @@ def chat_completions():
259
  formatted_messages.append(f"<|{role}|>: {content}")
260
 
261
  if not formatted_messages:
262
- return jsonify({"error": "No valid content in messages"}), 400
263
 
264
  # 添加系统提示词
265
  system_prompt = f"<|system|>: {CLAUDE_SYSTEM_PROMPT}\n"
@@ -269,29 +285,47 @@ def chat_completions():
269
  max_retries = 5
270
  retry_count = 0
271
  last_error = None
 
 
272
 
273
  while retry_count < max_retries:
274
  try:
275
  apikey = keymgr.get()
276
  if not apikey:
277
- return jsonify({"error": "No available API keys"}), 503
278
 
279
  session_id = create_session(apikey)
280
 
281
  if is_stream:
282
- return Response(
283
- handle_stream_request(apikey, session_id, query, endpoint_id, model),
284
- content_type='text/event-stream'
285
- )
 
 
 
 
 
 
 
 
286
  else:
287
- return handle_non_stream_request(apikey, session_id, query, endpoint_id, model)
 
 
 
 
 
 
 
 
288
 
289
  except Exception as e:
290
  last_error = str(e)
291
  if isinstance(e, requests.exceptions.RequestException):
292
  keymgr.mark_bad(apikey)
293
 
294
- logging.warning(f"请求失败 (尝试 {retry_count+1}/{max_retries}): {last_error}")
295
  retry_count += 1
296
 
297
  # 如果还有重试次数,继续尝试
@@ -299,10 +333,10 @@ def chat_completions():
299
  continue
300
 
301
  # 超过最大重试次数,返回400错误
302
- return jsonify({"error": "超过重试次数,请试", "details": last_error}), 400
303
 
304
  except Exception as e:
305
- return jsonify({"error": str(e)}), 500
306
 
307
  @app.route("/v1/models", methods=["GET"])
308
  def list_models():
@@ -458,7 +492,7 @@ if __name__ == "__main__":
458
  )
459
 
460
  if not ONDEMAND_APIKEYS:
461
- logging.warning("未设置ONDEMAND_APIKEYS环境变量,服务可能无法正常工作")
462
 
463
  port = int(os.environ.get("PORT", 7860))
464
  app.run(host="0.0.0.0", port=port, debug=False)
 
47
  break
48
 
49
  if not PRIVATE_KEY:
50
+ logging.warning("安全警告:PRIVATE_KEY 未设置服务将不进行鉴权!这可能导致未授权访问!")
51
  return None
52
 
53
  if not key_from_header or key_from_header != PRIVATE_KEY:
54
+ logging.warning(f"未授权访问: 路径={request.path}, IP地址={request.remote_addr}")
55
+ return jsonify({"error": "未授权访问。请提供正确的'Authorization: Bearer <PRIVATE_KEY>''X-API-KEY: <PRIVATE_KEY>'请求头。"}), 401
56
  return None
57
 
58
  # 密钥管理
 
69
  def get(self):
70
  with self.lock:
71
  if not self.key_list:
72
+ raise ValueError("API密钥池为空,无法提供服务。请确保已配置有效的API密钥。")
73
 
74
  now = time.time()
75
  for _ in range(len(self.key_list)):
 
119
  resp.raise_for_status()
120
  return resp.json()["data"]["id"]
121
  except Exception as e:
122
+ logging.error(f"创建会话失败:无法与API服务建立连接,错误详情:{e}")
123
  raise
124
 
125
  # 处理流式请求
 
141
  with requests.post(url, json=payload, headers=headers, stream=True, timeout=180) as resp:
142
  resp.raise_for_status()
143
  first_chunk = True
144
+ has_content = False # 标记是否接收到内容
145
 
146
  for line in resp.iter_lines():
147
  if not line:
 
153
 
154
  data = line[5:].strip()
155
  if data == "[DONE]":
156
+ # 如果没有接收到任何内容,抛出异常
157
+ if not has_content:
158
+ raise ValueError("空回复:未从API接收到任何有效内容,请稍后重试或联系管理员")
159
  yield "data: [DONE]\n\n"
160
  break
161
 
 
165
  content = event_data.get("answer", "")
166
  if content is None:
167
  continue
168
+
169
+ # 如果内容不为空,标记为已接收到内容
170
+ if content.strip():
171
+ has_content = True
172
 
173
  delta = {}
174
  if first_chunk:
 
185
  }
186
  yield format_openai_sse_delta(chunk)
187
  except Exception as e:
188
+ logging.warning(f"处理流式响应数据出错:解析或处理数据时发生异常,详情:{e}")
189
  continue
190
  except Exception as e:
191
  error = {
 
197
  }
198
  yield format_openai_sse_delta(error)
199
  yield "data: [DONE]\n\n"
200
+ # 重新抛出异常,以便上层函数可以捕获并重试
201
+ raise
202
 
203
+ # 处理非流式请求
204
  def handle_non_stream_request(apikey, session_id, query, endpoint_id, model_name):
205
  url = f"{ONDEMAND_API_BASE}/sessions/{session_id}/query"
206
  payload = {
 
217
  response_data = resp.json()
218
  content = response_data["data"]["answer"]
219
 
220
+ # 检查回复是否为空
221
+ if not content or not content.strip():
222
+ raise ValueError("空回复:API返回了空内容,无法提供有效回答,请稍后重试")
223
+
224
  return jsonify({
225
  "id": f"chatcmpl-{str(uuid.uuid4())[:12]}",
226
  "object": "chat.completion",
 
234
  "usage": {}
235
  })
236
  except Exception as e:
237
+ # 不在这里处理错误,而是将异常抛给上层函数处理
238
+ logging.warning(f"非流式请求失败:无法获取完整响应,错误详情:{e}")
239
+ raise
240
 
241
  # 路��处理
242
  @app.route("/v1/chat/completions", methods=["POST"])
 
244
  try:
245
  data = request.json
246
  if not data or "messages" not in data:
247
+ return jsonify({"error": "无效的请求格式:请求体必须包含messages字段"}), 400
248
 
249
  messages = data["messages"]
250
  if not isinstance(messages, list) or not messages:
251
+ return jsonify({"error": "消息格式错误:messages必须是非空列表,且至少包含一条消息"}), 400
252
 
253
  model = data.get("model", "gpt-4o")
254
  endpoint_id = get_endpoint_id(model)
 
275
  formatted_messages.append(f"<|{role}|>: {content}")
276
 
277
  if not formatted_messages:
278
+ return jsonify({"error": "消息内容为空:所有消息均不包含有效内容,请检查消息格式"}), 400
279
 
280
  # 添加系统提示词
281
  system_prompt = f"<|system|>: {CLAUDE_SYSTEM_PROMPT}\n"
 
285
  max_retries = 5
286
  retry_count = 0
287
  last_error = None
288
+ empty_response_retries = 0 # 空回复重试计数
289
+ max_empty_retries = 5 # 最大空回复重试次数
290
 
291
  while retry_count < max_retries:
292
  try:
293
  apikey = keymgr.get()
294
  if not apikey:
295
+ return jsonify({"error": "服务暂时不可用:没有可用的API密钥,请稍后重试或联系管理员"}), 503
296
 
297
  session_id = create_session(apikey)
298
 
299
  if is_stream:
300
+ try:
301
+ return Response(
302
+ handle_stream_request(apikey, session_id, query, endpoint_id, model),
303
+ content_type='text/event-stream'
304
+ )
305
+ except ValueError as ve:
306
+ # 捕获空回复异常
307
+ if "空回复" in str(ve) and empty_response_retries < max_empty_retries:
308
+ empty_response_retries += 1
309
+ logging.warning(f"检测到空回复:API未返回有效内容,正在使用新密钥重试 ({empty_response_retries}/{max_empty_retries})")
310
+ continue # 使用新密钥重试
311
+ raise # 其他ValueError或超过重试次数,重新抛出
312
  else:
313
+ try:
314
+ return handle_non_stream_request(apikey, session_id, query, endpoint_id, model)
315
+ except ValueError as ve:
316
+ # 捕获空回复异常
317
+ if "空回复" in str(ve) and empty_response_retries < max_empty_retries:
318
+ empty_response_retries += 1
319
+ logging.warning(f"检测到空回复:API未返回有效内容,正在使用新密钥重试 ({empty_response_retries}/{max_empty_retries})")
320
+ continue # 使用新密钥重试
321
+ raise # 其他ValueError或超过重试次数,重新抛出
322
 
323
  except Exception as e:
324
  last_error = str(e)
325
  if isinstance(e, requests.exceptions.RequestException):
326
  keymgr.mark_bad(apikey)
327
 
328
+ logging.warning(f"请求处理失败 (尝试 {retry_count+1}/{max_retries}):可能是网络问题或API服务不稳定,错误详情:{last_error}")
329
  retry_count += 1
330
 
331
  # 如果还有重试次数,继续尝试
 
333
  continue
334
 
335
  # 超过最大重试次数,返回400错误
336
+ return jsonify({"error": "请求失败:已超过最大重试次数,请稍后再试", "details": last_error}), 400
337
 
338
  except Exception as e:
339
+ return jsonify({"error": f"服务器内部错误:{str(e)},请联系管理员"}), 500
340
 
341
  @app.route("/v1/models", methods=["GET"])
342
  def list_models():
 
492
  )
493
 
494
  if not ONDEMAND_APIKEYS:
495
+ logging.warning("配置错误:未设置ONDEMAND_APIKEYS环境变量服务无法连接到API提供商,请配置至少一个有效的API密钥")
496
 
497
  port = int(os.environ.get("PORT", 7860))
498
  app.run(host="0.0.0.0", port=port, debug=False)