iseehf commited on
Commit
4da989d
·
verified ·
1 Parent(s): 976862e

Upload 2 files

Browse files
Files changed (2) hide show
  1. Dockerfile +1 -1
  2. app.py +261 -65
Dockerfile CHANGED
@@ -2,7 +2,7 @@ FROM python:3.10-slim
2
 
3
  WORKDIR /app
4
 
5
- RUN pip install --no-cache-dir flask requests curl_cffi werkzeug loguru
6
 
7
  COPY . .
8
 
 
2
 
3
  WORKDIR /app
4
 
5
+ RUN pip install --no-cache-dir flask requests curl_cffi werkzeug loguru dotenv
6
 
7
  COPY . .
8
 
app.py CHANGED
@@ -5,13 +5,19 @@ import time
5
  import base64
6
  import sys
7
  import inspect
 
8
  from loguru import logger
 
9
 
10
  import requests
11
- from flask import Flask, request, Response, jsonify, stream_with_context
12
  from curl_cffi import requests as curl_requests
13
  from werkzeug.middleware.proxy_fix import ProxyFix
14
 
 
 
 
 
15
 
16
  class Logger:
17
  def __init__(self, level="INFO", colorize=True, format=None):
@@ -93,27 +99,34 @@ CONFIG = {
93
  "grok-3-reasoning": "grok-3"
94
  },
95
  "API": {
96
- "IS_TEMP_CONVERSATION": os.environ.get("IS_TEMP_CONVERSATION", "true").lower() == "true",
97
- "IS_CUSTOM_SSO": os.environ.get("IS_CUSTOM_SSO", "false").lower() == "true",
98
- "BASE_URL": "https://shadowfetch.guaq.workers.dev/image/https://grok.com",
99
- "API_KEY": os.environ.get("API_KEY", "sk-123456"),
100
  "SIGNATURE_COOKIE": None,
101
- "PICGO_KEY": os.environ.get("PICGO_KEY") or None,
102
- "TUMY_KEY": os.environ.get("TUMY_KEY") or None,
103
  "RETRY_TIME": 1000,
104
- "PROXY": os.environ.get("PROXY") or None
 
 
 
 
105
  },
106
  "SERVER": {
107
- "PORT": int(os.environ.get("PORT", 5200))
 
 
108
  },
109
  "RETRY": {
 
110
  "MAX_ATTEMPTS": 2
111
  },
112
- "SHOW_THINKING": os.environ.get("SHOW_THINKING") == "true",
113
  "IS_THINKING": False,
114
  "IS_IMG_GEN": False,
115
  "IS_IMG_GEN2": False,
116
- "ISSHOW_SEARCH_RESULTS": os.environ.get("ISSHOW_SEARCH_RESULTS", "true").lower() == "true"
117
  }
118
 
119
 
@@ -217,14 +230,48 @@ class AuthTokenManager:
217
  except Exception as error:
218
  logger.error(f"令牌删除失败: {str(error)}")
219
  return False
220
-
221
- def get_next_token_for_model(self, model_id):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  normalized_model = self.normalize_model_name(model_id)
223
 
224
  if normalized_model not in self.token_model_map or not self.token_model_map[normalized_model]:
225
  return None
226
 
227
  token_entry = self.token_model_map[normalized_model][0]
 
 
228
 
229
  if token_entry:
230
  if token_entry["StartCallTime"] is None:
@@ -377,6 +424,14 @@ class AuthTokenManager:
377
  for entry in model_tokens:
378
  all_tokens.add(entry["token"])
379
  return list(all_tokens)
 
 
 
 
 
 
 
 
380
 
381
  def get_token_status_map(self):
382
  return self.token_status_map
@@ -401,8 +456,8 @@ class Utils:
401
  return '\n\n'.join(formatted_results)
402
 
403
  @staticmethod
404
- def create_auth_headers(model):
405
- return token_manager.get_next_token_for_model(model)
406
 
407
  @staticmethod
408
  def get_proxy_options():
@@ -411,12 +466,17 @@ class Utils:
411
 
412
  if proxy:
413
  logger.info(f"使用代理: {proxy}", "Server")
414
- proxy_options["proxies"] = {"https": proxy, "http": proxy}
415
-
416
  if proxy.startswith("socks5://"):
417
- proxy_options["proxies"] = {"https": proxy, "http": proxy}
418
- proxy_options["proxy_type"] = "socks5"
419
-
 
 
 
 
 
 
420
  return proxy_options
421
 
422
  class GrokApiClient:
@@ -445,7 +505,41 @@ class GrokApiClient:
445
  "mimeType": mime_type,
446
  "fileName": file_name
447
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
 
 
 
 
449
  def upload_base64_image(self, base64_data, url):
450
  try:
451
  if 'data:image' in base64_data:
@@ -473,10 +567,11 @@ class GrokApiClient:
473
  url,
474
  headers={
475
  **DEFAULT_HEADERS,
476
- "Cookie": CONFIG["API"]["SIGNATURE_COOKIE"]
477
  },
478
  json=upload_data,
479
  impersonate="chrome133a",
 
480
  **proxy_options
481
  )
482
 
@@ -504,11 +599,13 @@ class GrokApiClient:
504
  if last_message["role"] != 'user':
505
  raise ValueError('此模型最后一条消息必须是用户消息!')
506
  todo_messages = [last_message]
507
-
508
  file_attachments = []
509
  messages = ''
510
  last_role = None
511
  last_content = ''
 
 
 
512
  search = request["model"] in ['grok-2-search', 'grok-3-search']
513
 
514
  # 移除<think>标签及其内容和base64图片
@@ -558,7 +655,9 @@ class GrokApiClient:
558
 
559
 
560
  text_content = process_content(current.get("content", ""))
561
-
 
 
562
  if text_content or (is_last_message and file_attachments):
563
  if role == last_role and text_content:
564
  last_content += '\n' + text_content
@@ -567,9 +666,22 @@ class GrokApiClient:
567
  messages += f"{role.upper()}: {text_content or '[图片]'}\n"
568
  last_content = text_content
569
  last_role = role
570
-
 
 
 
 
 
 
 
 
 
 
 
 
 
571
  return {
572
- "temporary": CONFIG["API"]["IS_TEMP_CONVERSATION"],
573
  "modelName": self.model_id,
574
  "message": messages.strip(),
575
  "fileAttachments": file_attachments[:4],
@@ -684,12 +796,12 @@ def handle_image_response(image_url):
684
  try:
685
  proxy_options = Utils.get_proxy_options()
686
  image_base64_response = curl_requests.get(
687
- f"https://shadowfetch.guaq.workers.dev/image/https://assets.grok.com/{image_url}",
688
  headers={
689
  **DEFAULT_HEADERS,
690
- "Cookie": CONFIG["API"]["SIGNATURE_COOKIE"]
691
  },
692
- impersonate="chrome120",
693
  **proxy_options
694
  )
695
 
@@ -855,7 +967,7 @@ def handle_stream_response(response, model):
855
  return generate()
856
 
857
  def initialization():
858
- sso_array = os.environ.get("SSO", "").split(',')
859
  logger.info("开始加载令牌", "Server")
860
  for sso in sso_array:
861
  if sso:
@@ -872,11 +984,76 @@ logger.info("初始化完成", "Server")
872
 
873
  app = Flask(__name__)
874
  app.wsgi_app = ProxyFix(app.wsgi_app)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
875
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
876
 
877
- @app.before_request
878
- def log_request_info():
879
- logger.info(f"{request.method} {request.path}", "Request")
880
 
881
  @app.route('/get/tokens', methods=['GET'])
882
  def get_tokens():
@@ -885,7 +1062,6 @@ def get_tokens():
885
  return jsonify({"error": '自定义的SSO令牌模式无法获取轮询sso令牌状态'}), 403
886
  elif auth_token != CONFIG["API"]["API_KEY"]:
887
  return jsonify({"error": 'Unauthorized'}), 401
888
-
889
  return jsonify(token_manager.get_token_status_map())
890
 
891
  @app.route('/add/token', methods=['POST'])
@@ -903,7 +1079,20 @@ def add_token():
903
  except Exception as error:
904
  logger.error(str(error), "Server")
905
  return jsonify({"error": '添加sso令牌失败'}), 500
906
-
 
 
 
 
 
 
 
 
 
 
 
 
 
907
  @app.route('/delete/token', methods=['POST'])
908
  def delete_token():
909
  auth_token = request.headers.get('Authorization', '').replace('Bearer ', '')
@@ -937,6 +1126,7 @@ def get_models():
937
 
938
  @app.route('/v1/chat/completions', methods=['POST'])
939
  def chat_completions():
 
940
  try:
941
  auth_token = request.headers.get('Authorization',
942
  '').replace('Bearer ', '')
@@ -956,63 +1146,69 @@ def chat_completions():
956
  retry_count = 0
957
  grok_client = GrokApiClient(model)
958
  request_payload = grok_client.prepare_chat_request(data)
 
959
 
960
  while retry_count < CONFIG["RETRY"]["MAX_ATTEMPTS"]:
961
  retry_count += 1
962
- CONFIG["API"]["SIGNATURE_COOKIE"] = Utils.create_auth_headers(
963
- model)
964
 
965
  if not CONFIG["API"]["SIGNATURE_COOKIE"]:
966
  raise ValueError('该模型无可用令牌')
967
 
968
  logger.info(
969
- f"当前令牌: {json.dumps(CONFIG['API']['SIGNATURE_COOKIE'], indent=2)}",
970
- "Server")
971
  logger.info(
972
- f"当前可用模型的全部可用数量: {json.dumps(token_manager.get_remaining_token_request_capacity(), indent=2)}",
973
- "Server")
974
-
 
 
 
 
975
  try:
976
  proxy_options = Utils.get_proxy_options()
977
  response = curl_requests.post(
978
  f"{CONFIG['API']['BASE_URL']}/rest/app-chat/conversations/new",
979
  headers={
980
- **DEFAULT_HEADERS, "Cookie":
981
- CONFIG["API"]["SIGNATURE_COOKIE"]
982
  },
983
- data=json.dumps(request_payload),
984
  impersonate="chrome133a",
 
985
  stream=True,
986
  **proxy_options)
 
987
  if response.status_code == 200:
 
988
  logger.info("请求成功", "Server")
989
- logger.info(
990
- f"当前{model}剩余可用令牌数: {token_manager.get_token_count_for_model(model)}",
991
- "Server")
992
 
993
  try:
994
  if stream:
995
  return Response(stream_with_context(
996
- handle_stream_response(response, model)),
997
- content_type='text/event-stream')
998
  else:
999
- content = handle_non_stream_response(
1000
- response, model)
1001
  return jsonify(
1002
- MessageProcessor.create_chat_response(
1003
- content, model))
1004
 
1005
  except Exception as error:
1006
  logger.error(str(error), "Server")
1007
  if CONFIG["API"]["IS_CUSTOM_SSO"]:
1008
  raise ValueError(f"自定义SSO令牌当前模型{model}的请求次数已失效")
1009
-
1010
- token_manager.remove_token_from_model(
1011
- model, CONFIG["API"]["SIGNATURE_COOKIE"])
1012
  if token_manager.get_token_count_for_model(model) == 0:
1013
  raise ValueError(f"{model} 次数已达上限,请切换其他模型或者重新对话")
1014
-
 
 
 
 
 
1015
  elif response.status_code == 429:
 
 
1016
  if CONFIG["API"]["IS_CUSTOM_SSO"]:
1017
  raise ValueError(f"自定义SSO令牌当前模型{model}的请求次数已失效")
1018
 
@@ -1025,10 +1221,8 @@ def chat_completions():
1025
  if CONFIG["API"]["IS_CUSTOM_SSO"]:
1026
  raise ValueError(f"自定义SSO令牌当前模型{model}的请求次数已失效")
1027
 
1028
- logger.error(f"令牌异常错误状态!status: {response.status_code}",
1029
- "Server")
1030
- token_manager.remove_token_from_model(
1031
- model, CONFIG["API"]["SIGNATURE_COOKIE"])
1032
  logger.info(
1033
  f"当前{model}剩余可用令牌数: {token_manager.get_token_count_for_model(model)}",
1034
  "Server")
@@ -1038,8 +1232,10 @@ def chat_completions():
1038
  if CONFIG["API"]["IS_CUSTOM_SSO"]:
1039
  raise
1040
  continue
1041
-
1042
- raise ValueError('当前模型所有令牌都已耗尽')
 
 
1043
 
1044
  except Exception as error:
1045
  logger.error(str(error), "ChatAPI")
@@ -1047,7 +1243,7 @@ def chat_completions():
1047
  {"error": {
1048
  "message": str(error),
1049
  "type": "server_error"
1050
- }}), 500
1051
 
1052
  @app.route('/', defaults={'path': ''})
1053
  @app.route('/<path:path>')
@@ -1062,4 +1258,4 @@ if __name__ == '__main__':
1062
  host='0.0.0.0',
1063
  port=CONFIG["SERVER"]["PORT"],
1064
  debug=False
1065
- )
 
5
  import base64
6
  import sys
7
  import inspect
8
+ import secrets
9
  from loguru import logger
10
+ from dotenv import load_dotenv
11
 
12
  import requests
13
+ from flask import Flask, request, Response, jsonify, stream_with_context, render_template, redirect, session
14
  from curl_cffi import requests as curl_requests
15
  from werkzeug.middleware.proxy_fix import ProxyFix
16
 
17
+ current_dir = os.path.dirname(os.path.abspath(__file__))
18
+ env_path = os.path.join(current_dir, '.env')
19
+
20
+ load_dotenv(env_path)
21
 
22
  class Logger:
23
  def __init__(self, level="INFO", colorize=True, format=None):
 
99
  "grok-3-reasoning": "grok-3"
100
  },
101
  "API": {
102
+ "IS_TEMP_CONVERSATION": os.getenv("IS_TEMP_CONVERSATION", "true").lower() == "true",
103
+ "IS_CUSTOM_SSO": os.getenv("IS_CUSTOM_SSO", "false").lower() == "true",
104
+ "BASE_URL": "https://grok.com",
105
+ "API_KEY": os.getenv("API_KEY", "sk-123456"),
106
  "SIGNATURE_COOKIE": None,
107
+ "PICGO_KEY": os.getenv("PICGO_KEY") or None,
108
+ "TUMY_KEY": os.getenv("TUMY_KEY") or None,
109
  "RETRY_TIME": 1000,
110
+ "PROXY": os.getenv("PROXY") or None
111
+ },
112
+ "ADMIN": {
113
+ "MANAGER_SWITCH": os.getenv("MANAGER_SWITCH") or None,
114
+ "PASSWORD": os.getenv("ADMINPASSWORD") or None
115
  },
116
  "SERVER": {
117
+ "COOKIE": None,
118
+ "CF_CLEARANCE":os.getenv("CF_CLEARANCE") or None,
119
+ "PORT": int(os.getenv("PORT", 5200))
120
  },
121
  "RETRY": {
122
+ "RETRYSWITCH": False,
123
  "MAX_ATTEMPTS": 2
124
  },
125
+ "SHOW_THINKING": os.getenv("SHOW_THINKING") == "true",
126
  "IS_THINKING": False,
127
  "IS_IMG_GEN": False,
128
  "IS_IMG_GEN2": False,
129
+ "ISSHOW_SEARCH_RESULTS": os.getenv("ISSHOW_SEARCH_RESULTS", "true").lower() == "true"
130
  }
131
 
132
 
 
230
  except Exception as error:
231
  logger.error(f"令牌删除失败: {str(error)}")
232
  return False
233
+ def reduce_token_request_count(self, model_id, count):
234
+ try:
235
+ normalized_model = self.normalize_model_name(model_id)
236
+
237
+ if normalized_model not in self.token_model_map:
238
+ logger.error(f"模型 {normalized_model} 不存在", "TokenManager")
239
+ return False
240
+
241
+ if not self.token_model_map[normalized_model]:
242
+ logger.error(f"模型 {normalized_model} 没有可用的token", "TokenManager")
243
+ return False
244
+
245
+ token_entry = self.token_model_map[normalized_model][0]
246
+
247
+ # 确保RequestCount不会小于0
248
+ new_count = max(0, token_entry["RequestCount"] - count)
249
+ reduction = token_entry["RequestCount"] - new_count
250
+
251
+ token_entry["RequestCount"] = new_count
252
+
253
+ # 更新token状态
254
+ if token_entry["token"]:
255
+ sso = token_entry["token"].split("sso=")[1].split(";")[0]
256
+ if sso in self.token_status_map and normalized_model in self.token_status_map[sso]:
257
+ self.token_status_map[sso][normalized_model]["totalRequestCount"] = max(
258
+ 0,
259
+ self.token_status_map[sso][normalized_model]["totalRequestCount"] - reduction
260
+ )
261
+ return True
262
+
263
+ except Exception as error:
264
+ logger.error(f"重置校对token请求次数时发生错误: {str(error)}", "TokenManager")
265
+ return False
266
+ def get_next_token_for_model(self, model_id, is_return=False):
267
  normalized_model = self.normalize_model_name(model_id)
268
 
269
  if normalized_model not in self.token_model_map or not self.token_model_map[normalized_model]:
270
  return None
271
 
272
  token_entry = self.token_model_map[normalized_model][0]
273
+ if is_return:
274
+ return token_entry["token"]
275
 
276
  if token_entry:
277
  if token_entry["StartCallTime"] is None:
 
424
  for entry in model_tokens:
425
  all_tokens.add(entry["token"])
426
  return list(all_tokens)
427
+ def get_current_token(self, model_id):
428
+ normalized_model = self.normalize_model_name(model_id)
429
+
430
+ if normalized_model not in self.token_model_map or not self.token_model_map[normalized_model]:
431
+ return None
432
+
433
+ token_entry = self.token_model_map[normalized_model][0]
434
+ return token_entry["token"]
435
 
436
  def get_token_status_map(self):
437
  return self.token_status_map
 
456
  return '\n\n'.join(formatted_results)
457
 
458
  @staticmethod
459
+ def create_auth_headers(model, is_return=False):
460
+ return token_manager.get_next_token_for_model(model, is_return)
461
 
462
  @staticmethod
463
  def get_proxy_options():
 
466
 
467
  if proxy:
468
  logger.info(f"使用代理: {proxy}", "Server")
469
+
 
470
  if proxy.startswith("socks5://"):
471
+ proxy_options["proxy"] = proxy
472
+
473
+ if '@' in proxy:
474
+ auth_part = proxy.split('@')[0].split('://')[1]
475
+ if ':' in auth_part:
476
+ username, password = auth_part.split(':')
477
+ proxy_options["proxy_auth"] = (username, password)
478
+ else:
479
+ proxy_options["proxies"] = {"https": proxy, "http": proxy}
480
  return proxy_options
481
 
482
  class GrokApiClient:
 
505
  "mimeType": mime_type,
506
  "fileName": file_name
507
  }
508
+ def upload_base64_file(self, message, model):
509
+ try:
510
+ message_base64 = base64.b64encode(message.encode('utf-8')).decode('utf-8')
511
+ upload_data = {
512
+ "fileName": "message.txt",
513
+ "fileMimeType": "text/plain",
514
+ "content": message_base64
515
+ }
516
+
517
+ logger.info("发送文字文件请求", "Server")
518
+ cookie = f"{Utils.create_auth_headers(model, True)};{CONFIG['SERVER']['CF_CLEARANCE']}"
519
+ proxy_options = Utils.get_proxy_options()
520
+ response = curl_requests.post(
521
+ "https://grok.com/rest/app-chat/upload-file",
522
+ headers={
523
+ **DEFAULT_HEADERS,
524
+ "Cookie":cookie
525
+ },
526
+ json=upload_data,
527
+ impersonate="chrome133a",
528
+ verify=False,
529
+ **proxy_options
530
+ )
531
+
532
+ if response.status_code != 200:
533
+ logger.error(f"上传文件失败,状态码:{response.status_code}", "Server")
534
+ raise Exception(f"上传文件失败,状态码:{response.status_code}")
535
+
536
+ result = response.json()
537
+ logger.info(f"上传文件成功: {result}", "Server")
538
+ return result.get("fileMetadataId", "")
539
 
540
+ except Exception as error:
541
+ logger.error(str(error), "Server")
542
+ raise Exception(f"上传文件失败,状态码:{response.status_code}")
543
  def upload_base64_image(self, base64_data, url):
544
  try:
545
  if 'data:image' in base64_data:
 
567
  url,
568
  headers={
569
  **DEFAULT_HEADERS,
570
+ "Cookie":CONFIG["SERVER"]['COOKIE']
571
  },
572
  json=upload_data,
573
  impersonate="chrome133a",
574
+ verify=False,
575
  **proxy_options
576
  )
577
 
 
599
  if last_message["role"] != 'user':
600
  raise ValueError('此模型最后一条消息必须是用户消息!')
601
  todo_messages = [last_message]
 
602
  file_attachments = []
603
  messages = ''
604
  last_role = None
605
  last_content = ''
606
+ message_length = 0
607
+ convert_to_file = False
608
+ last_message_content = ''
609
  search = request["model"] in ['grok-2-search', 'grok-3-search']
610
 
611
  # 移除<think>标签及其内容和base64图片
 
655
 
656
 
657
  text_content = process_content(current.get("content", ""))
658
+ if is_last_message and convert_to_file:
659
+ last_message_content = f"{role.upper()}: {text_content or '[图片]'}\n"
660
+ continue
661
  if text_content or (is_last_message and file_attachments):
662
  if role == last_role and text_content:
663
  last_content += '\n' + text_content
 
666
  messages += f"{role.upper()}: {text_content or '[图片]'}\n"
667
  last_content = text_content
668
  last_role = role
669
+ message_length += len(messages)
670
+ if message_length >= 40000:
671
+ convert_to_file = True
672
+
673
+ if convert_to_file:
674
+ file_id = self.upload_base64_file(messages, request["model"])
675
+ if file_id:
676
+ file_attachments.insert(0, file_id)
677
+ messages = last_message_content.strip()
678
+ if messages.strip() == '':
679
+ if convert_to_file:
680
+ messages = '基于txt文件内容进行回复:'
681
+ else:
682
+ raise ValueError('消息内容为空!')
683
  return {
684
+ "temporary": CONFIG["API"].get("IS_TEMP_CONVERSATION", False),
685
  "modelName": self.model_id,
686
  "message": messages.strip(),
687
  "fileAttachments": file_attachments[:4],
 
796
  try:
797
  proxy_options = Utils.get_proxy_options()
798
  image_base64_response = curl_requests.get(
799
+ f"https://assets.grok.com/{image_url}",
800
  headers={
801
  **DEFAULT_HEADERS,
802
+ "Cookie":CONFIG["SERVER"]['COOKIE']
803
  },
804
+ impersonate="chrome133a",
805
  **proxy_options
806
  )
807
 
 
967
  return generate()
968
 
969
  def initialization():
970
+ sso_array = os.getenv("SSO", "").split(',')
971
  logger.info("开始加载令牌", "Server")
972
  for sso in sso_array:
973
  if sso:
 
984
 
985
  app = Flask(__name__)
986
  app.wsgi_app = ProxyFix(app.wsgi_app)
987
+ app.secret_key = os.getenv('FLASK_SECRET_KEY') or secrets.token_hex(16)
988
+ app.json.sort_keys = False
989
+
990
+ @app.route('/manager/login', methods=['GET', 'POST'])
991
+ def manager_login():
992
+ if CONFIG["ADMIN"]["MANAGER_SWITCH"]:
993
+ if request.method == 'POST':
994
+ password = request.form.get('password')
995
+ if password == CONFIG["ADMIN"]["PASSWORD"]:
996
+ session['is_logged_in'] = True
997
+ return redirect('/manager')
998
+ return render_template('login.html', error=True)
999
+ return render_template('login.html', error=False)
1000
+ else:
1001
+ return redirect('/')
1002
+
1003
+ def check_auth():
1004
+ return session.get('is_logged_in', False)
1005
+
1006
+ @app.route('/manager')
1007
+ def manager():
1008
+ if not check_auth():
1009
+ return redirect('/manager/login')
1010
+ return render_template('manager.html')
1011
+
1012
+ @app.route('/manager/api/get')
1013
+ def get_manager_tokens():
1014
+ if not check_auth():
1015
+ return jsonify({"error": "Unauthorized"}), 401
1016
+ return jsonify(token_manager.get_token_status_map())
1017
 
1018
+ @app.route('/manager/api/add', methods=['POST'])
1019
+ def add_manager_token():
1020
+ if not check_auth():
1021
+ return jsonify({"error": "Unauthorized"}), 401
1022
+ try:
1023
+ sso = request.json.get('sso')
1024
+ if not sso:
1025
+ return jsonify({"error": "SSO token is required"}), 400
1026
+ token_manager.add_token(f"sso-rw={sso};sso={sso}")
1027
+ return jsonify({"success": True})
1028
+ except Exception as e:
1029
+ return jsonify({"error": str(e)}), 500
1030
+
1031
+ @app.route('/manager/api/delete', methods=['POST'])
1032
+ def delete_manager_token():
1033
+ if not check_auth():
1034
+ return jsonify({"error": "Unauthorized"}), 401
1035
+ try:
1036
+ sso = request.json.get('sso')
1037
+ if not sso:
1038
+ return jsonify({"error": "SSO token is required"}), 400
1039
+ token_manager.delete_token(f"sso-rw={sso};sso={sso}")
1040
+ return jsonify({"success": True})
1041
+ except Exception as e:
1042
+ return jsonify({"error": str(e)}), 500
1043
+
1044
+ @app.route('/manager/api/cf_clearance', methods=['POST'])
1045
+ def setCf_Manager_clearance():
1046
+ if not check_auth():
1047
+ return jsonify({"error": "Unauthorized"}), 401
1048
+ try:
1049
+ cf_clearance = request.json.get('cf_clearance')
1050
+ if not cf_clearance:
1051
+ return jsonify({"error": "cf_clearance is required"}), 400
1052
+ CONFIG["SERVER"]['CF_CLEARANCE'] = cf_clearance
1053
+ return jsonify({"success": True})
1054
+ except Exception as e:
1055
+ return jsonify({"error": str(e)}), 500
1056
 
 
 
 
1057
 
1058
  @app.route('/get/tokens', methods=['GET'])
1059
  def get_tokens():
 
1062
  return jsonify({"error": '自定义的SSO令牌模式无法获取轮询sso令牌状态'}), 403
1063
  elif auth_token != CONFIG["API"]["API_KEY"]:
1064
  return jsonify({"error": 'Unauthorized'}), 401
 
1065
  return jsonify(token_manager.get_token_status_map())
1066
 
1067
  @app.route('/add/token', methods=['POST'])
 
1079
  except Exception as error:
1080
  logger.error(str(error), "Server")
1081
  return jsonify({"error": '添加sso令牌失败'}), 500
1082
+
1083
+ @app.route('/set/cf_clearance', methods=['POST'])
1084
+ def setCf_clearance():
1085
+ auth_token = request.headers.get('Authorization', '').replace('Bearer ', '')
1086
+ if auth_token != CONFIG["API"]["API_KEY"]:
1087
+ return jsonify({"error": 'Unauthorized'}), 401
1088
+ try:
1089
+ cf_clearance = request.json.get('cf_clearance')
1090
+ CONFIG["SERVER"]['CF_CLEARANCE'] = cf_clearance
1091
+ return jsonify({"message": '设置cf_clearance成功'}), 200
1092
+ except Exception as error:
1093
+ logger.error(str(error), "Server")
1094
+ return jsonify({"error": '设置cf_clearance失败'}), 500
1095
+
1096
  @app.route('/delete/token', methods=['POST'])
1097
  def delete_token():
1098
  auth_token = request.headers.get('Authorization', '').replace('Bearer ', '')
 
1126
 
1127
  @app.route('/v1/chat/completions', methods=['POST'])
1128
  def chat_completions():
1129
+ response_status_code = 500
1130
  try:
1131
  auth_token = request.headers.get('Authorization',
1132
  '').replace('Bearer ', '')
 
1146
  retry_count = 0
1147
  grok_client = GrokApiClient(model)
1148
  request_payload = grok_client.prepare_chat_request(data)
1149
+
1150
 
1151
  while retry_count < CONFIG["RETRY"]["MAX_ATTEMPTS"]:
1152
  retry_count += 1
1153
+ CONFIG["API"]["SIGNATURE_COOKIE"] = Utils.create_auth_headers(model)
 
1154
 
1155
  if not CONFIG["API"]["SIGNATURE_COOKIE"]:
1156
  raise ValueError('该模型无可用令牌')
1157
 
1158
  logger.info(
1159
+ f"当前令牌: {json.dumps(CONFIG['API']['SIGNATURE_COOKIE'], indent=2)}","Server")
 
1160
  logger.info(
1161
+ f"当前可用模型的全部可用数量: {json.dumps(token_manager.get_remaining_token_request_capacity(), indent=2)}","Server")
1162
+
1163
+ if CONFIG['SERVER']['CF_CLEARANCE']:
1164
+ CONFIG["SERVER"]['COOKIE'] = f"{CONFIG['API']['SIGNATURE_COOKIE']};{CONFIG['SERVER']['CF_CLEARANCE']}"
1165
+ else:
1166
+ CONFIG["SERVER"]['COOKIE'] = CONFIG['API']['SIGNATURE_COOKIE']
1167
+ logger.info(json.dumps(request_payload,indent=2),"Server")
1168
  try:
1169
  proxy_options = Utils.get_proxy_options()
1170
  response = curl_requests.post(
1171
  f"{CONFIG['API']['BASE_URL']}/rest/app-chat/conversations/new",
1172
  headers={
1173
+ **DEFAULT_HEADERS,
1174
+ "Cookie":CONFIG["SERVER"]['COOKIE']
1175
  },
1176
+ json=request_payload,
1177
  impersonate="chrome133a",
1178
+ verify=False,
1179
  stream=True,
1180
  **proxy_options)
1181
+ logger.info(CONFIG["SERVER"]['COOKIE'],"Server")
1182
  if response.status_code == 200:
1183
+ response_status_code = 200
1184
  logger.info("请求成功", "Server")
1185
+ logger.info(f"当前{model}剩余可用令牌数: {token_manager.get_token_count_for_model(model)}","Server")
 
 
1186
 
1187
  try:
1188
  if stream:
1189
  return Response(stream_with_context(
1190
+ handle_stream_response(response, model)),content_type='text/event-stream')
 
1191
  else:
1192
+ content = handle_non_stream_response(response, model)
 
1193
  return jsonify(
1194
+ MessageProcessor.create_chat_response(content, model))
 
1195
 
1196
  except Exception as error:
1197
  logger.error(str(error), "Server")
1198
  if CONFIG["API"]["IS_CUSTOM_SSO"]:
1199
  raise ValueError(f"自定义SSO令牌当前模型{model}的请求次数已失效")
1200
+ token_manager.remove_token_from_model(model, CONFIG["API"]["SIGNATURE_COOKIE"])
 
 
1201
  if token_manager.get_token_count_for_model(model) == 0:
1202
  raise ValueError(f"{model} 次数已达上限,请切换其他模型或者重新对话")
1203
+ elif response.status_code == 403:
1204
+ response_status_code = 403
1205
+ token_manager.reduce_token_request_count(model,1)#重置去除当前因为错误未成功请求的次数,确保不会因为错误未成功请求的次数导致次数上限
1206
+ if token_manager.get_token_count_for_model(model) == 0:
1207
+ raise ValueError(f"{model} 次数已达上限,请切换其他模型或者重新对话")
1208
+ raise ValueError(f"IP暂时被封无法破盾,请稍后重试或者更换ip")
1209
  elif response.status_code == 429:
1210
+ response_status_code = 429
1211
+ token_manager.reduce_token_request_count(model,1)
1212
  if CONFIG["API"]["IS_CUSTOM_SSO"]:
1213
  raise ValueError(f"自定义SSO令牌当前模型{model}的请求次数已失效")
1214
 
 
1221
  if CONFIG["API"]["IS_CUSTOM_SSO"]:
1222
  raise ValueError(f"自定义SSO令牌当前模型{model}的请求次数已失效")
1223
 
1224
+ logger.error(f"令牌异常错误状态!status: {response.status_code}","Server")
1225
+ token_manager.remove_token_from_model(model, CONFIG["API"]["SIGNATURE_COOKIE"])
 
 
1226
  logger.info(
1227
  f"当前{model}剩余可用令牌数: {token_manager.get_token_count_for_model(model)}",
1228
  "Server")
 
1232
  if CONFIG["API"]["IS_CUSTOM_SSO"]:
1233
  raise
1234
  continue
1235
+ if response_status_code == 403:
1236
+ raise ValueError('IP暂时被封无法破盾,请稍后重试或者更换ip')
1237
+ elif response_status_code == 500:
1238
+ raise ValueError('当前模型所有令牌暂无可用,请稍后重试')
1239
 
1240
  except Exception as error:
1241
  logger.error(str(error), "ChatAPI")
 
1243
  {"error": {
1244
  "message": str(error),
1245
  "type": "server_error"
1246
+ }}), response_status_code
1247
 
1248
  @app.route('/', defaults={'path': ''})
1249
  @app.route('/<path:path>')
 
1258
  host='0.0.0.0',
1259
  port=CONFIG["SERVER"]["PORT"],
1260
  debug=False
1261
+ )