yangtb24 commited on
Commit
c31239d
1 Parent(s): 756c521

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +147 -30
app.py CHANGED
@@ -4,7 +4,7 @@ import logging
4
  import requests
5
  import json
6
  import random
7
- import uuid
8
  import concurrent.futures
9
  from datetime import datetime, timedelta
10
  from apscheduler.schedulers.background import BackgroundScheduler
@@ -16,11 +16,14 @@ logging.basicConfig(level=logging.INFO,
16
  API_ENDPOINT = "https://api.siliconflow.cn/v1/user/info"
17
  TEST_MODEL_ENDPOINT = "https://api.siliconflow.cn/v1/chat/completions"
18
  MODELS_ENDPOINT = "https://api.siliconflow.cn/v1/models"
 
19
 
20
  app = Flask(__name__)
21
 
22
  all_models = []
23
  free_models = []
 
 
24
 
25
  invalid_keys_global = []
26
  free_keys_global = []
@@ -74,7 +77,7 @@ def test_model_availability(api_key, model_name):
74
  "stream": False
75
  },
76
  timeout=10)
77
- if response.status_code == 429 or response.status_code == 200 :
78
  return True
79
  else:
80
  return False
@@ -86,13 +89,16 @@ def refresh_models():
86
  """
87
  刷新模型列表和免费模型列表。
88
  """
89
- global all_models, free_models
90
 
91
- all_models = get_all_models(FREE_MODEL_TEST_KEY)
 
92
  free_models = []
 
93
 
94
  with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
95
- future_to_model = {executor.submit(test_model_availability, FREE_MODEL_TEST_KEY, model): model for model in all_models}
 
96
  for future in concurrent.futures.as_completed(future_to_model):
97
  model = future_to_model[future]
98
  try:
@@ -102,8 +108,47 @@ def refresh_models():
102
  except Exception as exc:
103
  logging.error(f"模型 {model} 测试生成异常: {exc}")
104
 
105
- logging.info(f"所有模型列表:{all_models}")
106
- logging.info(f"免费模型列表:{free_models}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  def load_keys():
109
  """
@@ -171,7 +216,7 @@ def process_key(key, test_model):
171
  else:
172
  return "unverified"
173
 
174
- def get_all_models(api_key):
175
  """
176
  获取所有模型列表。
177
  """
@@ -180,11 +225,12 @@ def get_all_models(api_key):
180
  "Content-Type": "application/json"
181
  }
182
  try:
183
- response = requests.get(MODELS_ENDPOINT, headers=headers, params={"sub_type": "chat"})
184
  response.raise_for_status()
185
  data = response.json()
186
  if isinstance(data, dict) and 'data' in data and isinstance(data['data'], list):
187
- return [model.get("id") for model in data["data"] if isinstance(model, dict) and "id" in model]
 
188
  else:
189
  logging.error("获取模型列表失败:响应数据格式不正确")
190
  return []
@@ -195,13 +241,13 @@ def get_all_models(api_key):
195
  logging.error(f"解析模型列表失败,API Key:{api_key},错误信息:{e}")
196
  return []
197
 
198
- def determine_request_type(model_name):
199
  """
200
  根据用户请求的模型判断请求类型。
201
  """
202
- if model_name in free_models:
203
  return "free"
204
- elif model_name in all_models:
205
  return "paid"
206
  else:
207
  return "unknown"
@@ -225,7 +271,7 @@ def select_key(request_type, model_name):
225
  for _ in range(len(available_keys)):
226
  key = available_keys[current_index % len(available_keys)]
227
  current_index += 1
228
-
229
  if key_is_valid(key, request_type):
230
  model_key_indices[model_name] = current_index
231
  return key
@@ -241,13 +287,13 @@ def key_is_valid(key, request_type):
241
  """
242
  if request_type == "invalid":
243
  return False
244
-
245
  credit_summary = get_credit_summary(key)
246
  if credit_summary is None:
247
  return False
248
-
249
  total_balance = credit_summary.get("total_balance", 0)
250
-
251
  if request_type == "free":
252
  return True
253
  elif request_type == "paid" or request_type == "unverified":
@@ -299,13 +345,16 @@ def check_tokens():
299
  credit_summary = get_credit_summary(token)
300
  balance = credit_summary.get("total_balance", 0) if credit_summary else 0
301
  if key_type == "invalid":
302
- results.append({"token": token, "type": "无效 KEY", "balance": balance, "message": "无法获取额度信息"})
 
303
  elif key_type == "free":
304
  results.append({"token": token, "type": "免费 KEY", "balance": balance, "message": "额度不足"})
305
  elif key_type == "unverified":
306
- results.append({"token": token, "type": "未实名 KEY", "balance": balance, "message": "无法使用指定模型"})
 
307
  elif key_type == "valid":
308
- results.append({"token": token, "type": "有效 KEY", "balance": balance, "message": "可以使用指定模型"})
 
309
  except Exception as exc:
310
  logging.error(f"处理 Token {token} 生成异常: {exc}")
311
 
@@ -321,11 +370,12 @@ def handsome_chat_completions():
321
  return jsonify({"error": "Invalid request data"}), 400
322
 
323
  model_name = data['model']
324
- request_type = determine_request_type(model_name)
325
  api_key = select_key(request_type, model_name)
326
 
327
  if not api_key:
328
- return jsonify({"error": "No available API key for this request type or all keys have reached their limits"}), 429
 
329
 
330
  headers = {
331
  "Authorization": f"Bearer {api_key}",
@@ -374,7 +424,9 @@ def handsome_chat_completions():
374
  if "usage" in response_json and "completion_tokens" in response_json["usage"]:
375
  completion_tokens = response_json["usage"]["completion_tokens"]
376
 
377
- if "choices" in response_json and len(response_json["choices"]) > 0 and "delta" in response_json["choices"][0] and "content" in response_json["choices"][0]["delta"]:
 
 
378
  response_content += response_json["choices"][0]["delta"]["content"]
379
 
380
  if "usage" in response_json and "prompt_tokens" in response_json["usage"]:
@@ -393,15 +445,16 @@ def handsome_chat_completions():
393
  for item in message["content"]:
394
  if isinstance(item, dict) and item.get("type") == "text":
395
  user_content += item.get("text", "") + " "
396
-
397
  user_content = user_content.strip()
398
-
399
  user_content_replaced = user_content.replace('\n', '\\n').replace('\r', '\\n')
400
  response_content_replaced = response_content.replace('\n', '\\n').replace('\r', '\\n')
401
-
402
  logging.info(
403
  f"使用的key: {api_key}, 提示token: {prompt_tokens}, 输出token: {completion_tokens}, 首字用时: {first_token_time:.4f}秒, 总共用时: {total_time:.4f}秒, 使用的模型: {model_name}, 用户的内容: {user_content_replaced}, 输出的内容: {response_content_replaced}"
404
  )
 
405
  return Response(stream_with_context(generate()), content_type=response.headers['Content-Type'])
406
  else:
407
  response.raise_for_status()
@@ -429,12 +482,12 @@ def handsome_chat_completions():
429
  for item in message["content"]:
430
  if isinstance(item, dict) and item.get("type") == "text":
431
  user_content += item.get("text", "") + " "
432
-
433
  user_content = user_content.strip()
434
-
435
  user_content_replaced = user_content.replace('\n', '\\n').replace('\r', '\\n')
436
  response_content_replaced = response_content.replace('\n', '\\n').replace('\r', '\\n')
437
-
438
  logging.info(
439
  f"使用的key: {api_key}, 提示token: {prompt_tokens}, 输出token: {completion_tokens}, 首字用时: 0, 总共用时: {total_time:.4f}秒, 使用的模型: {model_name}, 用户的内容: {user_content_replaced}, 输出的内容: {response_content_replaced}"
440
  )
@@ -552,6 +605,70 @@ def billing_subscription():
552
  "business_address": None
553
  })
554
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
555
  if __name__ == '__main__':
556
  import json
557
  logging.info(f"环境变量:{os.environ}")
@@ -569,4 +686,4 @@ if __name__ == '__main__':
569
  refresh_models()
570
  logging.info("首次刷新模型列表已手动触发执行")
571
 
572
- app.run(debug=False, host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))
 
4
  import requests
5
  import json
6
  import random
7
+ import uuid
8
  import concurrent.futures
9
  from datetime import datetime, timedelta
10
  from apscheduler.schedulers.background import BackgroundScheduler
 
16
  API_ENDPOINT = "https://api.siliconflow.cn/v1/user/info"
17
  TEST_MODEL_ENDPOINT = "https://api.siliconflow.cn/v1/chat/completions"
18
  MODELS_ENDPOINT = "https://api.siliconflow.cn/v1/models"
19
+ EMBEDDINGS_ENDPOINT = "https://api.siliconflow.cn/v1/embeddings"
20
 
21
  app = Flask(__name__)
22
 
23
  all_models = []
24
  free_models = []
25
+ embedding_models = []
26
+ free_embedding_models = []
27
 
28
  invalid_keys_global = []
29
  free_keys_global = []
 
77
  "stream": False
78
  },
79
  timeout=10)
80
+ if response.status_code == 429 or response.status_code == 200:
81
  return True
82
  else:
83
  return False
 
89
  """
90
  刷新模型列表和免费模型列表。
91
  """
92
+ global all_models, free_models, embedding_models, free_embedding_models
93
 
94
+ all_models = get_all_models(FREE_MODEL_TEST_KEY, "chat")
95
+ embedding_models = get_all_models(FREE_MODEL_TEST_KEY, "embedding")
96
  free_models = []
97
+ free_embedding_models = []
98
 
99
  with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
100
+ future_to_model = {executor.submit(test_model_availability, FREE_MODEL_TEST_KEY, model): model for model in
101
+ all_models}
102
  for future in concurrent.futures.as_completed(future_to_model):
103
  model = future_to_model[future]
104
  try:
 
108
  except Exception as exc:
109
  logging.error(f"模型 {model} 测试生成异常: {exc}")
110
 
111
+ with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
112
+ future_to_model = {
113
+ executor.submit(test_embedding_model_availability, FREE_MODEL_TEST_KEY, model): model for model in
114
+ embedding_models}
115
+ for future in concurrent.futures.as_completed(future_to_model):
116
+ model = future_to_model[future]
117
+ try:
118
+ is_free = future.result()
119
+ if is_free:
120
+ free_embedding_models.append(model)
121
+ except Exception as exc:
122
+ logging.error(f"模型 {model} 测试生成异常: {exc}")
123
+
124
+ logging.info(f"所有文本模型列表:{all_models}")
125
+ logging.info(f"免费文本模型列表:{free_models}")
126
+ logging.info(f"所有向量模型列表:{embedding_models}")
127
+ logging.info(f"免费向量模型列表:{free_embedding_models}")
128
+
129
+ def test_embedding_model_availability(api_key, model_name):
130
+ """
131
+ 测试指定的向量模型是否可用。
132
+ """
133
+ headers = {
134
+ "Authorization": f"Bearer {api_key}",
135
+ "Content-Type": "application/json"
136
+ }
137
+ try:
138
+ response = requests.post(EMBEDDINGS_ENDPOINT,
139
+ headers=headers,
140
+ json={
141
+ "model": model_name,
142
+ "input": ["hi"],
143
+ },
144
+ timeout=10)
145
+ if response.status_code == 429 or response.status_code == 200:
146
+ return True
147
+ else:
148
+ return False
149
+ except requests.exceptions.RequestException as e:
150
+ logging.error(f"测试向量模型 {model_name} 可用性失败,API Key:{api_key},错误信息:{e}")
151
+ return False
152
 
153
  def load_keys():
154
  """
 
216
  else:
217
  return "unverified"
218
 
219
+ def get_all_models(api_key, sub_type):
220
  """
221
  获取所有模型列表。
222
  """
 
225
  "Content-Type": "application/json"
226
  }
227
  try:
228
+ response = requests.get(MODELS_ENDPOINT, headers=headers, params={"sub_type": sub_type})
229
  response.raise_for_status()
230
  data = response.json()
231
  if isinstance(data, dict) and 'data' in data and isinstance(data['data'], list):
232
+ return [model.get("id") for model in data["data"] if
233
+ isinstance(model, dict) and "id" in model]
234
  else:
235
  logging.error("获取模型列表失败:响应数据格式不正确")
236
  return []
 
241
  logging.error(f"解析模型列表失败,API Key:{api_key},错误信息:{e}")
242
  return []
243
 
244
+ def determine_request_type(model_name, model_list, free_model_list):
245
  """
246
  根据用户请求的模型判断请求类型。
247
  """
248
+ if model_name in free_model_list:
249
  return "free"
250
+ elif model_name in model_list:
251
  return "paid"
252
  else:
253
  return "unknown"
 
271
  for _ in range(len(available_keys)):
272
  key = available_keys[current_index % len(available_keys)]
273
  current_index += 1
274
+
275
  if key_is_valid(key, request_type):
276
  model_key_indices[model_name] = current_index
277
  return key
 
287
  """
288
  if request_type == "invalid":
289
  return False
290
+
291
  credit_summary = get_credit_summary(key)
292
  if credit_summary is None:
293
  return False
294
+
295
  total_balance = credit_summary.get("total_balance", 0)
296
+
297
  if request_type == "free":
298
  return True
299
  elif request_type == "paid" or request_type == "unverified":
 
345
  credit_summary = get_credit_summary(token)
346
  balance = credit_summary.get("total_balance", 0) if credit_summary else 0
347
  if key_type == "invalid":
348
+ results.append(
349
+ {"token": token, "type": "无效 KEY", "balance": balance, "message": "无法获取额度信息"})
350
  elif key_type == "free":
351
  results.append({"token": token, "type": "免费 KEY", "balance": balance, "message": "额度不足"})
352
  elif key_type == "unverified":
353
+ results.append(
354
+ {"token": token, "type": "未实名 KEY", "balance": balance, "message": "无法使用指定模型"})
355
  elif key_type == "valid":
356
+ results.append(
357
+ {"token": token, "type": "有效 KEY", "balance": balance, "message": "可以使用指定模型"})
358
  except Exception as exc:
359
  logging.error(f"处理 Token {token} 生成异常: {exc}")
360
 
 
370
  return jsonify({"error": "Invalid request data"}), 400
371
 
372
  model_name = data['model']
373
+ request_type = determine_request_type(model_name, all_models, free_models)
374
  api_key = select_key(request_type, model_name)
375
 
376
  if not api_key:
377
+ return jsonify(
378
+ {"error": "No available API key for this request type or all keys have reached their limits"}), 429
379
 
380
  headers = {
381
  "Authorization": f"Bearer {api_key}",
 
424
  if "usage" in response_json and "completion_tokens" in response_json["usage"]:
425
  completion_tokens = response_json["usage"]["completion_tokens"]
426
 
427
+ if "choices" in response_json and len(response_json["choices"]) > 0 and "delta" in \
428
+ response_json["choices"][0] and "content" in response_json["choices"][0][
429
+ "delta"]:
430
  response_content += response_json["choices"][0]["delta"]["content"]
431
 
432
  if "usage" in response_json and "prompt_tokens" in response_json["usage"]:
 
445
  for item in message["content"]:
446
  if isinstance(item, dict) and item.get("type") == "text":
447
  user_content += item.get("text", "") + " "
448
+
449
  user_content = user_content.strip()
450
+
451
  user_content_replaced = user_content.replace('\n', '\\n').replace('\r', '\\n')
452
  response_content_replaced = response_content.replace('\n', '\\n').replace('\r', '\\n')
453
+
454
  logging.info(
455
  f"使用的key: {api_key}, 提示token: {prompt_tokens}, 输出token: {completion_tokens}, 首字用时: {first_token_time:.4f}秒, 总共用时: {total_time:.4f}秒, 使用的模型: {model_name}, 用户的内容: {user_content_replaced}, 输出的内容: {response_content_replaced}"
456
  )
457
+
458
  return Response(stream_with_context(generate()), content_type=response.headers['Content-Type'])
459
  else:
460
  response.raise_for_status()
 
482
  for item in message["content"]:
483
  if isinstance(item, dict) and item.get("type") == "text":
484
  user_content += item.get("text", "") + " "
485
+
486
  user_content = user_content.strip()
487
+
488
  user_content_replaced = user_content.replace('\n', '\\n').replace('\r', '\\n')
489
  response_content_replaced = response_content.replace('\n', '\\n').replace('\r', '\\n')
490
+
491
  logging.info(
492
  f"使用的key: {api_key}, 提示token: {prompt_tokens}, 输出token: {completion_tokens}, 首字用时: 0, 总共用时: {total_time:.4f}秒, 使用的模型: {model_name}, 用户的内容: {user_content_replaced}, 输出的内容: {response_content_replaced}"
493
  )
 
605
  "business_address": None
606
  })
607
 
608
+ @app.route('/handsome/v1/embeddings', methods=['POST'])
609
+ def handsome_embeddings():
610
+ if not check_authorization(request):
611
+ return jsonify({"error": "Unauthorized"}), 401
612
+
613
+ data = request.get_json()
614
+ if not data or 'model' not in data:
615
+ return jsonify({"error": "Invalid request data"}), 400
616
+
617
+ model_name = data['model']
618
+ request_type = determine_request_type(model_name, embedding_models, free_embedding_models)
619
+ api_key = select_key(request_type, model_name)
620
+
621
+ if not api_key:
622
+ return jsonify(
623
+ {"error": "No available API key for this request type or all keys have reached their limits"}), 429
624
+
625
+ headers = {
626
+ "Authorization": f"Bearer {api_key}",
627
+ "Content-Type": "application/json"
628
+ }
629
+
630
+ try:
631
+ start_time = time.time()
632
+ response = requests.post(
633
+ EMBEDDINGS_ENDPOINT,
634
+ headers=headers,
635
+ json=data,
636
+ timeout=60
637
+ )
638
+
639
+ if response.status_code == 429:
640
+ return jsonify(response.json()), 429
641
+
642
+ response.raise_for_status()
643
+ end_time = time.time()
644
+ response_json = response.json()
645
+ total_time = end_time - start_time
646
+
647
+ try:
648
+ prompt_tokens = response_json["usage"]["prompt_tokens"]
649
+ embedding_data = response_json["data"]
650
+ except (KeyError, ValueError, IndexError) as e:
651
+ logging.error(f"解析响应 JSON 失败: {e}, 完整内容: {response_json}")
652
+ prompt_tokens = 0
653
+ embedding_data = []
654
+
655
+ logging.info(
656
+ f"使用的key: {api_key}, 提示token: {prompt_tokens}, 总共用时: {total_time:.4f}秒, 使用的模型: {model_name}"
657
+ )
658
+
659
+ return jsonify({
660
+ "object": "list",
661
+ "data": embedding_data,
662
+ "model": model_name,
663
+ "usage": {
664
+ "prompt_tokens": prompt_tokens,
665
+ "total_tokens": prompt_tokens
666
+ }
667
+ })
668
+
669
+ except requests.exceptions.RequestException as e:
670
+ return jsonify({"error": str(e)}), 500
671
+
672
  if __name__ == '__main__':
673
  import json
674
  logging.info(f"环境变量:{os.environ}")
 
686
  refresh_models()
687
  logging.info("首次刷新模型列表已手动触发执行")
688
 
689
+ app.run(debug=False, host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))