yangtb24 commited on
Commit
01f588e
·
verified ·
1 Parent(s): c506221

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -704
app.py CHANGED
@@ -23,16 +23,11 @@ logging.basicConfig(level=logging.INFO,
23
  API_ENDPOINT = "https://api.deepseek.com/user/balance"
24
  TEST_MODEL_ENDPOINT = "https://api.deepseek.com/v1/chat/completions"
25
  MODELS_ENDPOINT = "https://api.deepseek.com/v1/models"
26
- EMBEDDINGS_ENDPOINT = "https://api.deepseek.com/v1/embeddings"
27
 
28
  app = Flask(__name__)
29
 
30
  text_models = []
31
  free_text_models = []
32
- embedding_models = []
33
- free_embedding_models = []
34
- image_models = []
35
- free_image_models = []
36
 
37
  invalid_keys_global = []
38
  free_keys_global = []
@@ -78,6 +73,7 @@ def get_credit_summary(api_key):
78
  exchange_rate = get_usd_to_cny_rate()
79
  if exchange_rate is not None:
80
  total_balance_cny += usd_balance * exchange_rate
 
81
  else:
82
  logging.warning(f"获取美元兑人民币汇率失败,无法转换美元余额,API Key:{api_key}")
83
  total_balance_cny += usd_balance * 7.2
@@ -731,8 +727,8 @@ def billing_subscription():
731
  "business_address": None
732
  })
733
 
734
- @app.route('/handsome/v1/embeddings', methods=['POST'])
735
- def handsome_embeddings():
736
  if not check_authorization(request):
737
  return jsonify({"error": "Unauthorized"}), 401
738
 
@@ -741,11 +737,13 @@ def handsome_embeddings():
741
  return jsonify({"error": "Invalid request data"}), 400
742
 
743
  model_name = data['model']
 
744
  request_type = determine_request_type(
745
  model_name,
746
- embedding_models,
747
- free_embedding_models
748
  )
 
749
  api_key = select_key(request_type, model_name)
750
 
751
  if not api_key:
@@ -763,706 +761,86 @@ def handsome_embeddings():
763
  "Authorization": f"Bearer {api_key}",
764
  "Content-Type": "application/json"
765
  }
766
-
767
  try:
768
  start_time = time.time()
769
  response = requests.post(
770
- EMBEDDINGS_ENDPOINT,
771
  headers=headers,
772
  json=data,
773
- timeout=120
 
774
  )
775
 
776
  if response.status_code == 429:
777
  return jsonify(response.json()), 429
778
 
779
- response.raise_for_status()
780
- end_time = time.time()
781
- response_json = response.json()
782
- total_time = end_time - start_time
783
-
784
- try:
785
- prompt_tokens = response_json["usage"]["prompt_tokens"]
786
- embedding_data = response_json["data"]
787
- except (KeyError, ValueError, IndexError) as e:
788
- logging.error(
789
- f"解析响应 JSON 失败: {e}, "
790
- f"完整内容: {response_json}"
791
- )
792
- prompt_tokens = 0
793
- embedding_data = []
794
-
795
- logging.info(
796
- f"使用的key: {api_key}, "
797
- f"提示token: {prompt_tokens}, "
798
- f"总共用时: {total_time:.4f}秒, "
799
- f"使用的模型: {model_name}"
800
- )
801
-
802
- with data_lock:
803
- request_timestamps.append(time.time())
804
- token_counts.append(prompt_tokens)
805
-
806
- return jsonify({
807
- "object": "list",
808
- "data": embedding_data,
809
- "model": model_name,
810
- "usage": {
811
- "prompt_tokens": prompt_tokens,
812
- "total_tokens": prompt_tokens
813
- }
814
- })
815
-
816
- except requests.exceptions.RequestException as e:
817
- return jsonify({"error": str(e)}), 500
818
-
819
- @app.route('/handsome/v1/images/generations', methods=['POST'])
820
- def handsome_images_generations():
821
- if not check_authorization(request):
822
- return jsonify({"error": "Unauthorized"}), 401
823
-
824
- data = request.get_json()
825
- if not data or 'model' not in data:
826
- return jsonify({"error": "Invalid request data"}), 400
827
-
828
- model_name = data.get('model')
829
-
830
- request_type = determine_request_type(
831
- model_name,
832
- image_models,
833
- free_image_models
834
- )
835
-
836
- api_key = select_key(request_type, model_name)
837
-
838
- if not api_key:
839
- return jsonify(
840
- {
841
- "error": (
842
- "No available API key for this "
843
- "request type or all keys have "
844
- "reached their limits"
845
- )
846
- }
847
- ), 429
848
-
849
- headers = {
850
- "Authorization": f"Bearer {api_key}",
851
- "Content-Type": "application/json"
852
- }
853
-
854
- response_data = {}
855
-
856
- if "stable-diffusion" in model_name or model_name in ["black-forest-labs/FLUX.1-schnell", "Pro/black-forest-labs/FLUX.1-schnell","black-forest-labs/FLUX.1-dev", "black-forest-labs/FLUX.1-pro"]:
857
- siliconflow_data = {
858
- "model": model_name,
859
- "prompt": data.get("prompt"),
860
-
861
- }
862
-
863
- if model_name == "black-forest-labs/FLUX.1-pro":
864
- siliconflow_data["width"] = data.get("width", 1024)
865
- siliconflow_data["height"] = data.get("height", 768)
866
- siliconflow_data["prompt_upsampling"] = data.get("prompt_upsampling", False)
867
- siliconflow_data["image_prompt"] = data.get("image_prompt")
868
- siliconflow_data["steps"] = data.get("steps", 20)
869
- siliconflow_data["guidance"] = data.get("guidance", 3)
870
- siliconflow_data["safety_tolerance"] = data.get("safety_tolerance", 2)
871
- siliconflow_data["interval"] = data.get("interval", 2)
872
- siliconflow_data["output_format"] = data.get("output_format", "png")
873
- seed = data.get("seed")
874
- if isinstance(seed, int) and 0 < seed < 9999999999:
875
- siliconflow_data["seed"] = seed
876
-
877
- if siliconflow_data["width"] < 256 or siliconflow_data["width"] > 1440 or siliconflow_data["width"] % 32 != 0:
878
- siliconflow_data["width"] = 1024
879
- if siliconflow_data["height"] < 256 or siliconflow_data["height"] > 1440 or siliconflow_data["height"] % 32 != 0:
880
- siliconflow_data["height"] = 768
881
-
882
- if siliconflow_data["steps"] < 1 or siliconflow_data["steps"] > 50:
883
- siliconflow_data["steps"] = 20
884
- if siliconflow_data["guidance"] < 1.5 or siliconflow_data["guidance"] > 5:
885
- siliconflow_data["guidance"] = 3
886
- if siliconflow_data["safety_tolerance"] < 0 or siliconflow_data["safety_tolerance"] > 6:
887
- siliconflow_data["safety_tolerance"] = 2
888
- if siliconflow_data["interval"] < 1 or siliconflow_data["interval"] > 4 :
889
- siliconflow_data["interval"] = 2
890
- else:
891
- siliconflow_data["image_size"] = data.get("image_size", "1024x1024")
892
- siliconflow_data["prompt_enhancement"] = data.get("prompt_enhancement", False)
893
- seed = data.get("seed")
894
- if isinstance(seed, int) and 0 < seed < 9999999999:
895
- siliconflow_data["seed"] = seed
896
-
897
- if model_name not in ["black-forest-labs/FLUX.1-schnell", "Pro/black-forest-labs/FLUX.1-schnell"]:
898
- siliconflow_data["batch_size"] = data.get("n", 1)
899
- siliconflow_data["num_inference_steps"] = data.get("steps", 20)
900
- siliconflow_data["guidance_scale"] = data.get("guidance_scale", 7.5)
901
- siliconflow_data["negative_prompt"] = data.get("negative_prompt")
902
- if siliconflow_data["batch_size"] < 1:
903
- siliconflow_data["batch_size"] = 1
904
- if siliconflow_data["batch_size"] > 4:
905
- siliconflow_data["batch_size"] = 4
906
-
907
- if siliconflow_data["num_inference_steps"] < 1:
908
- siliconflow_data["num_inference_steps"] = 1
909
- if siliconflow_data["num_inference_steps"] > 50:
910
- siliconflow_data["num_inference_steps"] = 50
911
-
912
- if siliconflow_data["guidance_scale"] < 0:
913
- siliconflow_data["guidance_scale"] = 0
914
- if siliconflow_data["guidance_scale"] > 100:
915
- siliconflow_data["guidance_scale"] = 100
916
-
917
- if "image_size" in siliconflow_data and siliconflow_data["image_size"] not in ["1024x1024", "512x1024", "768x512", "768x1024", "1024x576", "576x1024","960x1280", "720x1440", "720x1280"]:
918
- siliconflow_data["image_size"] = "1024x1024"
919
-
920
- try:
921
- start_time = time.time()
922
- response = requests.post(
923
- "https://api.siliconflow.cn/v1/images/generations",
924
- headers=headers,
925
- json=siliconflow_data,
926
- timeout=120
927
- )
928
-
929
- if response.status_code == 429:
930
- return jsonify(response.json()), 429
931
-
932
- response.raise_for_status()
933
- end_time = time.time()
934
- response_json = response.json()
935
- total_time = end_time - start_time
936
-
937
- try:
938
- images = response_json.get("images", [])
939
- openai_images = []
940
- for item in images:
941
- if isinstance(item, dict) and "url" in item:
942
- image_url = item["url"]
943
- print(f"image_url: {image_url}")
944
- if data.get("response_format") == "b64_json":
945
- try:
946
- image_data = requests.get(image_url, stream=True).raw
947
- image = Image.open(image_data)
948
- buffered = io.BytesIO()
949
- image.save(buffered, format="PNG")
950
- img_str = base64.b64encode(buffered.getvalue()).decode()
951
- openai_images.append({"b64_json": img_str})
952
- except Exception as e:
953
- logging.error(f"图片转base64失败: {e}")
954
- openai_images.append({"url": image_url})
955
- else:
956
- openai_images.append({"url": image_url})
957
- else:
958
- logging.error(f"无效的图片数据: {item}")
959
- openai_images.append({"url": item})
960
-
961
-
962
- response_data = {
963
- "created": int(time.time()),
964
- "data": openai_images
965
- }
966
- except (KeyError, ValueError, IndexError) as e:
967
- logging.error(
968
- f"解析响应 JSON 失败: {e}, "
969
- f"完整内容: {response_json}"
970
- )
971
- response_data = {
972
- "created": int(time.time()),
973
- "data": []
974
- }
975
-
976
- logging.info(
977
- f"使用的key: {api_key}, "
978
- f"总共用时: {total_time:.4f}秒, "
979
- f"使用的模型: {model_name}"
980
- )
981
-
982
- with data_lock:
983
- request_timestamps.append(time.time())
984
- token_counts.append(0)
985
-
986
- return jsonify(response_data)
987
-
988
- except requests.exceptions.RequestException as e:
989
- logging.error(f"请求转发异常: {e}")
990
- return jsonify({"error": str(e)}), 500
991
- else:
992
- return jsonify({"error": "Unsupported model"}), 400
993
-
994
- @app.route('/handsome/v1/chat/completions', methods=['POST'])
995
- def handsome_chat_completions():
996
- if not check_authorization(request):
997
- return jsonify({"error": "Unauthorized"}), 401
998
-
999
- data = request.get_json()
1000
- if not data or 'model' not in data:
1001
- return jsonify({"error": "Invalid request data"}), 400
1002
-
1003
- model_name = data['model']
1004
-
1005
- request_type = determine_request_type(
1006
- model_name,
1007
- text_models + image_models,
1008
- free_text_models + free_image_models
1009
- )
1010
-
1011
- api_key = select_key(request_type, model_name)
1012
-
1013
- if not api_key:
1014
- return jsonify(
1015
- {
1016
- "error": (
1017
- "No available API key for this "
1018
- "request type or all keys have "
1019
- "reached their limits"
1020
- )
1021
- }
1022
- ), 429
1023
-
1024
- headers = {
1025
- "Authorization": f"Bearer {api_key}",
1026
- "Content-Type": "application/json"
1027
- }
1028
-
1029
- if model_name in image_models:
1030
- user_content = ""
1031
- messages = data.get("messages", [])
1032
- for message in messages:
1033
- if message["role"] == "user":
1034
- if isinstance(message["content"], str):
1035
- user_content += message["content"] + " "
1036
- elif isinstance(message["content"], list):
1037
- for item in message["content"]:
1038
- if (
1039
- isinstance(item, dict) and
1040
- item.get("type") == "text"
1041
- ):
1042
- user_content += (
1043
- item.get("text", "") +
1044
- " "
1045
- )
1046
- user_content = user_content.strip()
1047
-
1048
- siliconflow_data = {
1049
- "model": model_name,
1050
- "prompt": user_content,
1051
-
1052
- }
1053
- if model_name == "black-forest-labs/FLUX.1-pro":
1054
- siliconflow_data["width"] = data.get("width", 1024)
1055
- siliconflow_data["height"] = data.get("height", 768)
1056
- siliconflow_data["prompt_upsampling"] = data.get("prompt_upsampling", False)
1057
- siliconflow_data["image_prompt"] = data.get("image_prompt")
1058
- siliconflow_data["steps"] = data.get("steps", 20)
1059
- siliconflow_data["guidance"] = data.get("guidance", 3)
1060
- siliconflow_data["safety_tolerance"] = data.get("safety_tolerance", 2)
1061
- siliconflow_data["interval"] = data.get("interval", 2)
1062
- siliconflow_data["output_format"] = data.get("output_format", "png")
1063
- seed = data.get("seed")
1064
- if isinstance(seed, int) and 0 < seed < 9999999999:
1065
- siliconflow_data["seed"] = seed
1066
- if siliconflow_data["width"] < 256 or siliconflow_data["width"] > 1440 or siliconflow_data["width"] % 32 != 0:
1067
- siliconflow_data["width"] = 1024
1068
- if siliconflow_data["height"] < 256 or siliconflow_data["height"] > 1440 or siliconflow_data["height"] % 32 != 0:
1069
- siliconflow_data["height"] = 768
1070
-
1071
- if siliconflow_data["steps"] < 1 or siliconflow_data["steps"] > 50:
1072
- siliconflow_data["steps"] = 20
1073
- if siliconflow_data["guidance"] < 1.5 or siliconflow_data["guidance"] > 5:
1074
- siliconflow_data["guidance"] = 3
1075
- if siliconflow_data["safety_tolerance"] < 0 or siliconflow_data["safety_tolerance"] > 6:
1076
- siliconflow_data["safety_tolerance"] = 2
1077
- if siliconflow_data["interval"] < 1 or siliconflow_data["interval"] > 4 :
1078
- siliconflow_data["interval"] = 2
1079
- else:
1080
- siliconflow_data["image_size"] = "1024x1024"
1081
- siliconflow_data["batch_size"] = 1
1082
- siliconflow_data["num_inference_steps"] = 20
1083
- siliconflow_data["guidance_scale"] = 7.5
1084
- siliconflow_data["prompt_enhancement"] = False
1085
-
1086
- if data.get("size"):
1087
- siliconflow_data["image_size"] = data.get("size")
1088
- if data.get("n"):
1089
- siliconflow_data["batch_size"] = data.get("n")
1090
- if data.get("steps"):
1091
- siliconflow_data["num_inference_steps"] = data.get("steps")
1092
- if data.get("guidance_scale"):
1093
- siliconflow_data["guidance_scale"] = data.get("guidance_scale")
1094
- if data.get("negative_prompt"):
1095
- siliconflow_data["negative_prompt"] = data.get("negative_prompt")
1096
- if data.get("seed"):
1097
- siliconflow_data["seed"] = data.get("seed")
1098
- if data.get("prompt_enhancement"):
1099
- siliconflow_data["prompt_enhancement"] = data.get("prompt_enhancement")
1100
-
1101
- if siliconflow_data["batch_size"] < 1:
1102
- siliconflow_data["batch_size"] = 1
1103
- if siliconflow_data["batch_size"] > 4:
1104
- siliconflow_data["batch_size"] = 4
1105
-
1106
- if siliconflow_data["num_inference_steps"] < 1:
1107
- siliconflow_data["num_inference_steps"] = 1
1108
- if siliconflow_data["num_inference_steps"] > 50:
1109
- siliconflow_data["num_inference_steps"] = 50
1110
-
1111
- if siliconflow_data["guidance_scale"] < 0:
1112
- siliconflow_data["guidance_scale"] = 0
1113
- if siliconflow_data["guidance_scale"] > 100:
1114
- siliconflow_data["guidance_scale"] = 100
1115
-
1116
- if siliconflow_data["image_size"] not in ["1024x1024", "512x1024", "768x512", "768x1024", "1024x576", "576x1024", "960x1280", "720x1440", "720x1280"]:
1117
- siliconflow_data["image_size"] = "1024x1024"
1118
-
1119
- try:
1120
- start_time = time.time()
1121
- response = requests.post(
1122
- "https://api.siliconflow.cn/v1/images/generations",
1123
- headers=headers,
1124
- json=siliconflow_data,
1125
- timeout=120,
1126
- stream=data.get("stream", False)
1127
- )
1128
-
1129
- if response.status_code == 429:
1130
- return jsonify(response.json()), 429
1131
-
1132
- if data.get("stream", False):
1133
- def generate():
1134
- first_chunk_time = None
1135
- full_response_content = ""
1136
- try:
1137
- response.raise_for_status()
1138
- end_time = time.time()
1139
- response_json = response.json()
1140
- total_time = end_time - start_time
1141
-
1142
- images = response_json.get("images", [])
1143
-
1144
- image_url = ""
1145
- if images and isinstance(images[0], dict) and "url" in images[0]:
1146
- image_url = images[0]["url"]
1147
- logging.info(f"Extracted image URL: {image_url}")
1148
- elif images and isinstance(images[0], str):
1149
- image_url = images[0]
1150
- logging.info(f"Extracted image URL: {image_url}")
1151
-
1152
- markdown_image_link = f"![image]({image_url})"
1153
- if image_url:
1154
- chunk_data = {
1155
- "id": f"chatcmpl-{uuid.uuid4()}",
1156
- "object": "chat.completion.chunk",
1157
- "created": int(time.time()),
1158
- "model": model_name,
1159
- "choices": [
1160
- {
1161
- "index": 0,
1162
- "delta": {
1163
- "role": "assistant",
1164
- "content": markdown_image_link
1165
- },
1166
- "finish_reason": None
1167
- }
1168
- ]
1169
- }
1170
- yield f"data: {json.dumps(chunk_data)}\n\n".encode('utf-8')
1171
- full_response_content = markdown_image_link
1172
- else:
1173
- chunk_data = {
1174
- "id": f"chatcmpl-{uuid.uuid4()}",
1175
- "object": "chat.completion.chunk",
1176
- "created": int(time.time()),
1177
- "model": model_name,
1178
- "choices": [
1179
- {
1180
- "index": 0,
1181
- "delta": {
1182
- "role": "assistant",
1183
- "content": "Failed to generate image"
1184
- },
1185
- "finish_reason": None
1186
- }
1187
- ]
1188
- }
1189
- yield f"data: {json.dumps(chunk_data)}\n\n".encode('utf-8')
1190
- full_response_content = "Failed to generate image"
1191
-
1192
- end_chunk_data = {
1193
- "id": f"chatcmpl-{uuid.uuid4()}",
1194
- "object": "chat.completion.chunk",
1195
- "created": int(time.time()),
1196
- "model": model_name,
1197
- "choices": [
1198
- {
1199
- "index": 0,
1200
- "delta": {},
1201
- "finish_reason": "stop"
1202
- }
1203
- ]
1204
- }
1205
- yield f"data: {json.dumps(end_chunk_data)}\n\n".encode('utf-8')
1206
- with data_lock:
1207
- request_timestamps.append(time.time())
1208
- token_counts.append(0)
1209
- except requests.exceptions.RequestException as e:
1210
- logging.error(f"请求转发异常: {e}")
1211
- error_chunk_data = {
1212
- "id": f"chatcmpl-{uuid.uuid4()}",
1213
- "object": "chat.completion.chunk",
1214
- "created": int(time.time()),
1215
- "model": model_name,
1216
- "choices": [
1217
- {
1218
- "index": 0,
1219
- "delta": {
1220
- "role": "assistant",
1221
- "content": f"Error: {str(e)}"
1222
- },
1223
- "finish_reason": None
1224
- }
1225
- ]
1226
- }
1227
- yield f"data: {json.dumps(error_chunk_data)}\n\n".encode('utf-8')
1228
- end_chunk_data = {
1229
- "id": f"chatcmpl-{uuid.uuid4()}",
1230
- "object": "chat.completion.chunk",
1231
- "created": int(time.time()),
1232
- "model": model_name,
1233
- "choices": [
1234
- {
1235
- "index": 0,
1236
- "delta": {},
1237
- "finish_reason": "stop"
1238
- }
1239
- ]
1240
- }
1241
- yield f"data: {json.dumps(end_chunk_data)}\n\n".encode('utf-8')
1242
- logging.info(
1243
- f"使用的key: {api_key}, "
1244
- f"使用的模型: {model_name}"
1245
- )
1246
- yield "data: [DONE]\n\n".encode('utf-8')
1247
- return Response(stream_with_context(generate()), content_type='text/event-stream')
1248
 
1249
- else:
1250
- response.raise_for_status()
1251
  end_time = time.time()
1252
- response_json = response.json()
1253
- total_time = end_time - start_time
1254
-
1255
- try:
1256
- images = response_json.get("images", [])
1257
-
1258
- image_url = ""
1259
- if images and isinstance(images[0], dict) and "url" in images[0]:
1260
- image_url = images[0]["url"]
1261
- logging.info(f"Extracted image URL: {image_url}")
1262
- elif images and isinstance(images[0], str):
1263
- image_url = images[0]
1264
- logging.info(f"Extracted image URL: {image_url}")
1265
-
1266
- markdown_image_link = f"![image]({image_url})"
1267
- response_data = {
1268
- "id": f"chatcmpl-{uuid.uuid4()}",
1269
- "object": "chat.completion",
1270
- "created": int(time.time()),
1271
- "model": model_name,
1272
- "choices": [
1273
- {
1274
- "index": 0,
1275
- "message": {
1276
- "role": "assistant",
1277
- "content": markdown_image_link if image_url else "Failed to generate image",
1278
- },
1279
- "finish_reason": "stop",
1280
- }
1281
- ],
1282
- }
1283
- except (KeyError, ValueError, IndexError) as e:
1284
- logging.error(
1285
- f"解析响应 JSON 失败: {e}, "
1286
- f"完整内容: {response_json}"
1287
- )
1288
- response_data = {
1289
- "id": f"chatcmpl-{uuid.uuid4()}",
1290
- "object": "chat.completion",
1291
- "created": int(time.time()),
1292
- "model": model_name,
1293
- "choices": [
1294
- {
1295
- "index": 0,
1296
- "message": {
1297
- "role": "assistant",
1298
- "content": "Failed to process image data",
1299
- },
1300
- "finish_reason": "stop",
1301
- }
1302
- ],
1303
- }
1304
-
1305
- logging.info(
1306
- f"使用的key: {api_key}, "
1307
- f"总共用时: {total_time:.4f}秒, "
1308
- f"使用的模型: {model_name}"
1309
- )
1310
- with data_lock:
1311
- request_timestamps.append(time.time())
1312
- token_counts.append(0)
1313
- return jsonify(response_data)
1314
-
1315
- except requests.exceptions.RequestException as e:
1316
- logging.error(f"请求转发异常: {e}")
1317
- return jsonify({"error": str(e)}), 500
1318
- else:
1319
- try:
1320
- start_time = time.time()
1321
- response = requests.post(
1322
- TEST_MODEL_ENDPOINT,
1323
- headers=headers,
1324
- json=data,
1325
- stream=data.get("stream", False),
1326
- timeout=60
1327
- )
1328
-
1329
- if response.status_code == 429:
1330
- return jsonify(response.json()), 429
1331
-
1332
- if data.get("stream", False):
1333
- def generate():
1334
- first_chunk_time = None
1335
- full_response_content = ""
1336
- for chunk in response.iter_content(chunk_size=1024):
1337
- if chunk:
1338
- if first_chunk_time is None:
1339
- first_chunk_time = time.time()
1340
- full_response_content += chunk.decode("utf-8")
1341
- yield chunk
1342
-
1343
- end_time = time.time()
1344
- first_token_time = (
1345
- first_chunk_time - start_time
1346
- if first_chunk_time else 0
1347
- )
1348
- total_time = end_time - start_time
1349
-
1350
- prompt_tokens = 0
1351
- completion_tokens = 0
1352
- response_content = ""
1353
- for line in full_response_content.splitlines():
1354
- if line.startswith("data:"):
1355
- line = line[5:].strip()
1356
- if line == "[DONE]":
1357
- continue
1358
- try:
1359
- response_json = json.loads(line)
1360
-
1361
- if (
1362
- "usage" in response_json and
1363
- "completion_tokens" in response_json["usage"]
1364
- ):
1365
- completion_tokens = response_json[
1366
- "usage"
1367
- ]["completion_tokens"]
1368
-
1369
- if (
1370
- "choices" in response_json and
1371
- len(response_json["choices"]) > 0 and
1372
- "delta" in response_json["choices"][0] and
1373
- "content" in response_json[
1374
- "choices"
1375
- ][0]["delta"]
1376
- ):
1377
- response_content += response_json[
1378
- "choices"
1379
- ][0]["delta"]["content"]
1380
-
1381
- if (
1382
- "usage" in response_json and
1383
- "prompt_tokens" in response_json["usage"]
1384
- ):
1385
- prompt_tokens = response_json[
1386
- "usage"
1387
- ]["prompt_tokens"]
1388
-
1389
- except (
1390
- KeyError,
1391
- ValueError,
1392
- IndexError
1393
- ) as e:
1394
- logging.error(
1395
- f"解析流式响应单行 JSON 失败: {e}, "
1396
- f"行内容: {line}"
1397
- )
1398
-
1399
- user_content = ""
1400
- messages = data.get("messages", [])
1401
- for message in messages:
1402
- if message["role"] == "user":
1403
- if isinstance(message["content"], str):
1404
- user_content += message["content"] + " "
1405
- elif isinstance(message["content"], list):
1406
- for item in message["content"]:
1407
- if (
1408
- isinstance(item, dict) and
1409
- item.get("type") == "text"
1410
- ):
1411
- user_content += (
1412
- item.get("text", "") +
1413
- " "
1414
- )
1415
-
1416
- user_content = user_content.strip()
1417
-
1418
- user_content_replaced = user_content.replace(
1419
- '\n', '\\n'
1420
- ).replace('\r', '\\n')
1421
- response_content_replaced = response_content.replace(
1422
- '\n', '\\n'
1423
- ).replace('\r', '\\n')
1424
-
1425
- logging.info(
1426
- f"使用的key: {api_key}, "
1427
- f"提示token: {prompt_tokens}, "
1428
- f"输出token: {completion_tokens}, "
1429
- f"首字用时: {first_token_time:.4f}秒, "
1430
- f"总共用时: {total_time:.4f}秒, "
1431
- f"使用的模型: {model_name}, "
1432
- f"用户的内容: {user_content_replaced}, "
1433
- f"输出的内容: {response_content_replaced}"
1434
- )
1435
-
1436
- with data_lock:
1437
- request_timestamps.append(time.time())
1438
- token_counts.append(prompt_tokens+completion_tokens)
1439
-
1440
- return Response(
1441
- stream_with_context(generate()),
1442
- content_type=response.headers['Content-Type']
1443
  )
1444
- else:
1445
- response.raise_for_status()
1446
- end_time = time.time()
1447
- response_json = response.json()
1448
  total_time = end_time - start_time
1449
 
1450
- try:
1451
- prompt_tokens = response_json["usage"]["prompt_tokens"]
1452
- completion_tokens = response_json[
1453
- "usage"
1454
- ]["completion_tokens"]
1455
- response_content = response_json[
1456
- "choices"
1457
- ][0]["message"]["content"]
1458
- except (KeyError, ValueError, IndexError) as e:
1459
- logging.error(
1460
- f"解析非流式响应 JSON 失败: {e}, "
1461
- f"完整内容: {response_json}"
1462
- )
1463
- prompt_tokens = 0
1464
- completion_tokens = 0
1465
- response_content = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1466
 
1467
  user_content = ""
1468
  messages = data.get("messages", [])
@@ -1477,7 +855,8 @@ def handsome_chat_completions():
1477
  item.get("type") == "text"
1478
  ):
1479
  user_content += (
1480
- item.get("text", "") + " "
 
1481
  )
1482
 
1483
  user_content = user_content.strip()
@@ -1493,24 +872,91 @@ def handsome_chat_completions():
1493
  f"使用的key: {api_key}, "
1494
  f"提示token: {prompt_tokens}, "
1495
  f"输出token: {completion_tokens}, "
1496
- f"首字用时: 0, "
1497
  f"总共用时: {total_time:.4f}秒, "
1498
  f"使用的模型: {model_name}, "
1499
  f"用户的内容: {user_content_replaced}, "
1500
  f"输出的内容: {response_content_replaced}"
1501
  )
 
1502
  with data_lock:
1503
  request_timestamps.append(time.time())
1504
- if "prompt_tokens" in response_json["usage"] and "completion_tokens" in response_json["usage"]:
1505
- token_counts.append(response_json["usage"]["prompt_tokens"] + response_json["usage"]["completion_tokens"])
1506
- else:
1507
- token_counts.append(0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1508
 
1509
- return jsonify(response_json)
1510
 
1511
- except requests.exceptions.RequestException as e:
1512
- logging.error(f"请求转发异常: {e}")
1513
- return jsonify({"error": str(e)}), 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1514
 
1515
  if __name__ == '__main__':
1516
  import json
 
23
  API_ENDPOINT = "https://api.deepseek.com/user/balance"
24
  TEST_MODEL_ENDPOINT = "https://api.deepseek.com/v1/chat/completions"
25
  MODELS_ENDPOINT = "https://api.deepseek.com/v1/models"
 
26
 
27
  app = Flask(__name__)
28
 
29
  text_models = []
30
  free_text_models = []
 
 
 
 
31
 
32
  invalid_keys_global = []
33
  free_keys_global = []
 
73
  exchange_rate = get_usd_to_cny_rate()
74
  if exchange_rate is not None:
75
  total_balance_cny += usd_balance * exchange_rate
76
+ logging.info(f"获取美元兑人民币汇率成功{total_balance_cny}")
77
  else:
78
  logging.warning(f"获取美元兑人民币汇率失败,无法转换美元余额,API Key:{api_key}")
79
  total_balance_cny += usd_balance * 7.2
 
727
  "business_address": None
728
  })
729
 
730
+ @app.route('/handsome/v1/chat/completions', methods=['POST'])
731
+ def handsome_chat_completions():
732
  if not check_authorization(request):
733
  return jsonify({"error": "Unauthorized"}), 401
734
 
 
737
  return jsonify({"error": "Invalid request data"}), 400
738
 
739
  model_name = data['model']
740
+
741
  request_type = determine_request_type(
742
  model_name,
743
+ text_models + image_models,
744
+ free_text_models + free_image_models
745
  )
746
+
747
  api_key = select_key(request_type, model_name)
748
 
749
  if not api_key:
 
761
  "Authorization": f"Bearer {api_key}",
762
  "Content-Type": "application/json"
763
  }
764
+
765
  try:
766
  start_time = time.time()
767
  response = requests.post(
768
+ TEST_MODEL_ENDPOINT,
769
  headers=headers,
770
  json=data,
771
+ stream=data.get("stream", False),
772
+ timeout=60
773
  )
774
 
775
  if response.status_code == 429:
776
  return jsonify(response.json()), 429
777
 
778
+ if data.get("stream", False):
779
+ def generate():
780
+ first_chunk_time = None
781
+ full_response_content = ""
782
+ for chunk in response.iter_content(chunk_size=1024):
783
+ if chunk:
784
+ if first_chunk_time is None:
785
+ first_chunk_time = time.time()
786
+ full_response_content += chunk.decode("utf-8")
787
+ yield chunk
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
788
 
 
 
789
  end_time = time.time()
790
+ first_token_time = (
791
+ first_chunk_time - start_time
792
+ if first_chunk_time else 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
793
  )
 
 
 
 
794
  total_time = end_time - start_time
795
 
796
+ prompt_tokens = 0
797
+ completion_tokens = 0
798
+ response_content = ""
799
+ for line in full_response_content.splitlines():
800
+ if line.startswith("data:"):
801
+ line = line[5:].strip()
802
+ if line == "[DONE]":
803
+ continue
804
+ try:
805
+ response_json = json.loads(line)
806
+
807
+ if (
808
+ "usage" in response_json and
809
+ "completion_tokens" in response_json["usage"]
810
+ ):
811
+ completion_tokens = response_json[
812
+ "usage"
813
+ ]["completion_tokens"]
814
+
815
+ if (
816
+ "choices" in response_json and
817
+ len(response_json["choices"]) > 0 and
818
+ "delta" in response_json["choices"][0] and
819
+ "content" in response_json[
820
+ "choices"
821
+ ][0]["delta"]
822
+ ):
823
+ response_content += response_json[
824
+ "choices"
825
+ ][0]["delta"]["content"]
826
+
827
+ if (
828
+ "usage" in response_json and
829
+ "prompt_tokens" in response_json["usage"]
830
+ ):
831
+ prompt_tokens = response_json[
832
+ "usage"
833
+ ]["prompt_tokens"]
834
+
835
+ except (
836
+ KeyError,
837
+ ValueError,
838
+ IndexError
839
+ ) as e:
840
+ logging.error(
841
+ f"解析流式响应单行 JSON 失败: {e}, "
842
+ f"行内容: {line}"
843
+ )
844
 
845
  user_content = ""
846
  messages = data.get("messages", [])
 
855
  item.get("type") == "text"
856
  ):
857
  user_content += (
858
+ item.get("text", "") +
859
+ " "
860
  )
861
 
862
  user_content = user_content.strip()
 
872
  f"使用的key: {api_key}, "
873
  f"提示token: {prompt_tokens}, "
874
  f"输出token: {completion_tokens}, "
875
+ f"首字用时: {first_token_time:.4f}秒, "
876
  f"总共用时: {total_time:.4f}秒, "
877
  f"使用的模型: {model_name}, "
878
  f"用户的内容: {user_content_replaced}, "
879
  f"输出的内容: {response_content_replaced}"
880
  )
881
+
882
  with data_lock:
883
  request_timestamps.append(time.time())
884
+ token_counts.append(prompt_tokens+completion_tokens)
885
+
886
+ return Response(
887
+ stream_with_context(generate()),
888
+ content_type=response.headers['Content-Type']
889
+ )
890
+ else:
891
+ response.raise_for_status()
892
+ end_time = time.time()
893
+ response_json = response.json()
894
+ total_time = end_time - start_time
895
+
896
+ try:
897
+ prompt_tokens = response_json["usage"]["prompt_tokens"]
898
+ completion_tokens = response_json[
899
+ "usage"
900
+ ]["completion_tokens"]
901
+ response_content = response_json[
902
+ "choices"
903
+ ][0]["message"]["content"]
904
+ except (KeyError, ValueError, IndexError) as e:
905
+ logging.error(
906
+ f"解析非流式响应 JSON 失败: {e}, "
907
+ f"完整内容: {response_json}"
908
+ )
909
+ prompt_tokens = 0
910
+ completion_tokens = 0
911
+ response_content = ""
912
+
913
+ user_content = ""
914
+ messages = data.get("messages", [])
915
+ for message in messages:
916
+ if message["role"] == "user":
917
+ if isinstance(message["content"], str):
918
+ user_content += message["content"] + " "
919
+ elif isinstance(message["content"], list):
920
+ for item in message["content"]:
921
+ if (
922
+ isinstance(item, dict) and
923
+ item.get("type") == "text"
924
+ ):
925
+ user_content += (
926
+ item.get("text", "") + " "
927
+ )
928
 
929
+ user_content = user_content.strip()
930
 
931
+ user_content_replaced = user_content.replace(
932
+ '\n', '\\n'
933
+ ).replace('\r', '\\n')
934
+ response_content_replaced = response_content.replace(
935
+ '\n', '\\n'
936
+ ).replace('\r', '\\n')
937
+
938
+ logging.info(
939
+ f"使用的key: {api_key}, "
940
+ f"提示token: {prompt_tokens}, "
941
+ f"输出token: {completion_tokens}, "
942
+ f"首字用时: 0, "
943
+ f"总共用时: {total_time:.4f}秒, "
944
+ f"使用的模型: {model_name}, "
945
+ f"用户的内容: {user_content_replaced}, "
946
+ f"输出的内容: {response_content_replaced}"
947
+ )
948
+ with data_lock:
949
+ request_timestamps.append(time.time())
950
+ if "prompt_tokens" in response_json["usage"] and "completion_tokens" in response_json["usage"]:
951
+ token_counts.append(response_json["usage"]["prompt_tokens"] + response_json["usage"]["completion_tokens"])
952
+ else:
953
+ token_counts.append(0)
954
+
955
+ return jsonify(response_json)
956
+
957
+ except requests.exceptions.RequestException as e:
958
+ logging.error(f"请求转发异常: {e}")
959
+ return jsonify({"error": str(e)}), 500
960
 
961
  if __name__ == '__main__':
962
  import json