yxmiler commited on
Commit
7061687
·
verified ·
1 Parent(s): de817c4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -38
app.py CHANGED
@@ -7,18 +7,13 @@ 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):
24
  logger.remove()
@@ -85,8 +80,10 @@ class Logger:
85
  self.logger.bind(**caller_info).info(f"请求: {request.method} {request.path}", "Request")
86
 
87
  logger = Logger(level="INFO")
 
88
 
89
-
 
90
  CONFIG = {
91
  "MODELS": {
92
  'grok-2': 'grok-latest',
@@ -96,37 +93,39 @@ CONFIG = {
96
  "grok-3-search": "grok-3",
97
  "grok-3-imageGen": "grok-3",
98
  "grok-3-deepsearch": "grok-3",
 
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
 
@@ -146,7 +145,7 @@ DEFAULT_HEADERS = {
146
  'Sec-Fetch-Mode': 'cors',
147
  'Sec-Fetch-Site': 'same-origin',
148
  'Baggage': 'sentry-public_key=b311e0f2690c81f25e2c4cf6d4f7ce1c',
149
- 'x-statsig-id': "ZTpUeXBlRXJyb3I6IENhbm5vdCByZWFkIHByb3BlcnRpZXMgb2YgdW5kZWZpbmVkIChyZWFkaW5nICdjaGlsZE5vZGVzJyk="
150
  }
151
 
152
  class AuthTokenManager:
@@ -168,6 +167,10 @@ class AuthTokenManager:
168
  "RequestFrequency": 10,
169
  "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
170
  },
 
 
 
 
171
  "grok-3-reasoning": {
172
  "RequestFrequency": 10,
173
  "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
@@ -175,8 +178,25 @@ class AuthTokenManager:
175
  }
176
  self.token_reset_switch = False
177
  self.token_reset_timer = None
178
-
179
- def add_token(self, token):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  sso = token.split("sso=")[1].split(";")[0]
181
  for model in self.model_config.keys():
182
  if model not in self.token_model_map:
@@ -200,6 +220,8 @@ class AuthTokenManager:
200
  "invalidatedTime": None,
201
  "totalRequestCount": 0
202
  }
 
 
203
 
204
  def set_token(self, token):
205
  models = list(self.model_config.keys())
@@ -225,6 +247,8 @@ class AuthTokenManager:
225
 
226
  if sso in self.token_status_map:
227
  del self.token_status_map[sso]
 
 
228
 
229
  logger.info(f"令牌已成功移除: {token}", "TokenManager")
230
  return True
@@ -296,6 +320,8 @@ class AuthTokenManager:
296
  self.token_status_map[sso][normalized_model]["invalidatedTime"] = int(time.time() * 1000)
297
  self.token_status_map[sso][normalized_model]["totalRequestCount"] += 1
298
 
 
 
299
  return token_entry["token"]
300
 
301
  return None
@@ -526,7 +552,6 @@ class GrokApiClient:
526
  },
527
  json=upload_data,
528
  impersonate="chrome133a",
529
- verify=False,
530
  **proxy_options
531
  )
532
 
@@ -572,7 +597,6 @@ class GrokApiClient:
572
  },
573
  json=upload_data,
574
  impersonate="chrome133a",
575
- verify=False,
576
  **proxy_options
577
  )
578
 
@@ -587,13 +611,33 @@ class GrokApiClient:
587
  except Exception as error:
588
  logger.error(str(error), "Server")
589
  return ''
590
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
  def prepare_chat_request(self, request):
592
  if ((request["model"] == 'grok-2-imageGen' or request["model"] == 'grok-3-imageGen') and
593
  not CONFIG["API"]["PICGO_KEY"] and not CONFIG["API"]["TUMY_KEY"] and
594
  request.get("stream", False)):
595
  raise ValueError("该模型流式输出需要配置PICGO或者TUMY图床密钥!")
596
 
 
597
  todo_messages = request["messages"]
598
  if request["model"] in ['grok-2-imageGen', 'grok-3-imageGen', 'grok-3-deepsearch']:
599
  last_message = todo_messages[-1]
@@ -608,6 +652,11 @@ class GrokApiClient:
608
  convert_to_file = False
609
  last_message_content = ''
610
  search = request["model"] in ['grok-2-search', 'grok-3-search']
 
 
 
 
 
611
 
612
  # 移除<think>标签及其内容和base64图片
613
  def remove_think_tags(text):
@@ -631,7 +680,6 @@ class GrokApiClient:
631
  elif content["type"] == 'text':
632
  return remove_think_tags(content["text"])
633
  return remove_think_tags(self.process_message_content(content))
634
-
635
  for current in todo_messages:
636
  role = 'assistant' if current["role"] == 'assistant' else 'user'
637
  is_last_message = current == todo_messages[-1]
@@ -703,11 +751,11 @@ class GrokApiClient:
703
  "xPostAnalyze": search
704
  },
705
  "enableSideBySide": True,
706
- "isPreset": False,
707
  "sendFinalMetadata": True,
708
- "customInstructions": "",
709
- "deepsearchPreset": "default" if request["model"] == 'grok-3-deepsearch' else "",
710
- "isReasoning": request["model"] == 'grok-3-reasoning'
 
711
  }
712
 
713
  class MessageProcessor:
@@ -762,7 +810,7 @@ def process_model_response(response, model):
762
  result["token"] = response.get("token")
763
  elif model == 'grok-3':
764
  result["token"] = response.get("token")
765
- elif model == 'grok-3-deepsearch':
766
  if response.get("messageStepId") and not CONFIG["SHOW_THINKING"]:
767
  return result
768
  if response.get("messageStepId") and not CONFIG["IS_THINKING"]:
@@ -772,7 +820,11 @@ def process_model_response(response, model):
772
  result["token"] = "</think>" + response.get("token", "")
773
  CONFIG["IS_THINKING"] = False
774
  elif (response.get("messageStepId") and CONFIG["IS_THINKING"] and response.get("messageTag") == "assistant") or response.get("messageTag") == "final":
775
- result["token"] = response.get("token")
 
 
 
 
776
  elif model == 'grok-3-reasoning':
777
  if response.get("isThinking") and not CONFIG["SHOW_THINKING"]:
778
  return result
@@ -936,6 +988,7 @@ def handle_stream_response(response, model):
936
  continue
937
  try:
938
  line_json = json.loads(chunk.decode("utf-8").strip())
 
939
  if line_json.get("error"):
940
  logger.error(json.dumps(line_json, indent=2), "Server")
941
  yield json.dumps({"error": "RateLimitError"}) + "\n\n"
@@ -968,11 +1021,13 @@ def handle_stream_response(response, model):
968
  return generate()
969
 
970
  def initialization():
971
- sso_array = os.getenv("SSO", "").split(',')
972
  logger.info("开始加载令牌", "Server")
 
973
  for sso in sso_array:
974
  if sso:
975
- token_manager.add_token(f"sso-rw={sso};sso={sso}")
 
976
 
977
  logger.info(f"成功加载令牌: {json.dumps(token_manager.get_all_tokens(), indent=2)}", "Server")
978
  logger.info(f"令牌加载完成,共加载: {len(token_manager.get_all_tokens())}个令牌", "Server")
@@ -985,7 +1040,7 @@ logger.info("初始化完成", "Server")
985
 
986
  app = Flask(__name__)
987
  app.wsgi_app = ProxyFix(app.wsgi_app)
988
- app.secret_key = os.getenv('FLASK_SECRET_KEY') or secrets.token_hex(16)
989
  app.json.sort_keys = False
990
 
991
  @app.route('/manager/login', methods=['GET', 'POST'])
@@ -1147,7 +1202,7 @@ def chat_completions():
1147
  retry_count = 0
1148
  grok_client = GrokApiClient(model)
1149
  request_payload = grok_client.prepare_chat_request(data)
1150
-
1151
 
1152
  while retry_count < CONFIG["RETRY"]["MAX_ATTEMPTS"]:
1153
  retry_count += 1
@@ -1174,9 +1229,8 @@ def chat_completions():
1174
  **DEFAULT_HEADERS,
1175
  "Cookie":CONFIG["SERVER"]['COOKIE']
1176
  },
1177
- json=request_payload,
1178
  impersonate="chrome133a",
1179
- verify=False,
1180
  stream=True,
1181
  **proxy_options)
1182
  logger.info(CONFIG["SERVER"]['COOKIE'],"Server")
@@ -1206,6 +1260,9 @@ def chat_completions():
1206
  token_manager.reduce_token_request_count(model,1)#重置去除当前因为错误未成功请求的次数,确保不会因为错误未成功请求的次数导致次数上限
1207
  if token_manager.get_token_count_for_model(model) == 0:
1208
  raise ValueError(f"{model} 次数已达上限,请切换其他模型或者重新对话")
 
 
 
1209
  raise ValueError(f"IP暂时被封无法破盾,请稍后重试或者更换ip")
1210
  elif response.status_code == 429:
1211
  response_status_code = 429
 
7
  import inspect
8
  import secrets
9
  from loguru import logger
10
+ from pathlib import Path
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
  class Logger:
18
  def __init__(self, level="INFO", colorize=True, format=None):
19
  logger.remove()
 
80
  self.logger.bind(**caller_info).info(f"请求: {request.method} {request.path}", "Request")
81
 
82
  logger = Logger(level="INFO")
83
+ DATA_DIR = Path("/data")
84
 
85
+ if not DATA_DIR.exists():
86
+ DATA_DIR.mkdir(parents=True, exist_ok=True)
87
  CONFIG = {
88
  "MODELS": {
89
  'grok-2': 'grok-latest',
 
93
  "grok-3-search": "grok-3",
94
  "grok-3-imageGen": "grok-3",
95
  "grok-3-deepsearch": "grok-3",
96
+ "grok-3-deepersearch": "grok-3",
97
  "grok-3-reasoning": "grok-3"
98
  },
99
  "API": {
100
+ "IS_TEMP_CONVERSATION": os.environ.get("IS_TEMP_CONVERSATION", "true").lower() == "true",
101
+ "IS_CUSTOM_SSO": os.environ.get("IS_CUSTOM_SSO", "false").lower() == "true",
102
  "BASE_URL": "https://grok.com",
103
+ "API_KEY": os.environ.get("API_KEY", "sk-123456"),
104
  "SIGNATURE_COOKIE": None,
105
+ "PICGO_KEY": os.environ.get("PICGO_KEY") or None,
106
+ "TUMY_KEY": os.environ.get("TUMY_KEY") or None,
107
  "RETRY_TIME": 1000,
108
+ "PROXY": os.environ.get("PROXY") or None
109
  },
110
  "ADMIN": {
111
+ "MANAGER_SWITCH": os.environ.get("MANAGER_SWITCH") or None,
112
+ "PASSWORD": os.environ.get("ADMINPASSWORD") or None
113
  },
114
  "SERVER": {
115
  "COOKIE": None,
116
+ "CF_CLEARANCE":os.environ.get("CF_CLEARANCE") or None,
117
+ "PORT": int(os.environ.get("PORT", 5200))
118
  },
119
  "RETRY": {
120
  "RETRYSWITCH": False,
121
  "MAX_ATTEMPTS": 2
122
  },
123
+ "TOKEN_STATUS_FILE": str(DATA_DIR / "token_status.json"),
124
+ "SHOW_THINKING": os.environ.get("SHOW_THINKING") == "true",
125
  "IS_THINKING": False,
126
  "IS_IMG_GEN": False,
127
  "IS_IMG_GEN2": False,
128
+ "ISSHOW_SEARCH_RESULTS": os.environ.get("ISSHOW_SEARCH_RESULTS", "true").lower() == "true"
129
  }
130
 
131
 
 
145
  'Sec-Fetch-Mode': 'cors',
146
  'Sec-Fetch-Site': 'same-origin',
147
  'Baggage': 'sentry-public_key=b311e0f2690c81f25e2c4cf6d4f7ce1c',
148
+ 'x-statsig-id': 'ZTpUeXBlRXJyb3I6IENhbm5vdCByZWFkIHByb3BlcnRpZXMgb2YgdW5kZWZpbmVkIChyZWFkaW5nICdjaGlsZE5vZGVzJyk='# 暂用固定x-statsig-id,失效再看
149
  }
150
 
151
  class AuthTokenManager:
 
167
  "RequestFrequency": 10,
168
  "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
169
  },
170
+ "grok-3-deepersearch": {
171
+ "RequestFrequency": 3,
172
+ "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
173
+ },
174
  "grok-3-reasoning": {
175
  "RequestFrequency": 10,
176
  "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
 
178
  }
179
  self.token_reset_switch = False
180
  self.token_reset_timer = None
181
+ self.load_token_status() # 加载令牌状态
182
+ def save_token_status(self):
183
+ try:
184
+ with open(CONFIG["TOKEN_STATUS_FILE"], 'w', encoding='utf-8') as f:
185
+ json.dump(self.token_status_map, f, indent=2, ensure_ascii=False)
186
+ logger.info("令牌状态已保存到配置文件", "TokenManager")
187
+ except Exception as error:
188
+ logger.error(f"保存令牌状态失败: {str(error)}", "TokenManager")
189
+
190
+ def load_token_status(self):
191
+ try:
192
+ token_status_file = Path(CONFIG["TOKEN_STATUS_FILE"])
193
+ if token_status_file.exists():
194
+ with open(token_status_file, 'r', encoding='utf-8') as f:
195
+ self.token_status_map = json.load(f)
196
+ logger.info("已从配置文件加载令牌状态", "TokenManager")
197
+ except Exception as error:
198
+ logger.error(f"加载令牌状态失败: {str(error)}", "TokenManager")
199
+ def add_token(self, token,isinitialization=False):
200
  sso = token.split("sso=")[1].split(";")[0]
201
  for model in self.model_config.keys():
202
  if model not in self.token_model_map:
 
220
  "invalidatedTime": None,
221
  "totalRequestCount": 0
222
  }
223
+ if not isinitialization:
224
+ self.save_token_status()
225
 
226
  def set_token(self, token):
227
  models = list(self.model_config.keys())
 
247
 
248
  if sso in self.token_status_map:
249
  del self.token_status_map[sso]
250
+
251
+ self.save_token_status()
252
 
253
  logger.info(f"令牌已成功移除: {token}", "TokenManager")
254
  return True
 
320
  self.token_status_map[sso][normalized_model]["invalidatedTime"] = int(time.time() * 1000)
321
  self.token_status_map[sso][normalized_model]["totalRequestCount"] += 1
322
 
323
+ self.save_token_status()
324
+
325
  return token_entry["token"]
326
 
327
  return None
 
552
  },
553
  json=upload_data,
554
  impersonate="chrome133a",
 
555
  **proxy_options
556
  )
557
 
 
597
  },
598
  json=upload_data,
599
  impersonate="chrome133a",
 
600
  **proxy_options
601
  )
602
 
 
611
  except Exception as error:
612
  logger.error(str(error), "Server")
613
  return ''
614
+ # def convert_system_messages(self, messages):
615
+ # try:
616
+ # system_prompt = []
617
+ # i = 0
618
+ # while i < len(messages):
619
+ # if messages[i].get('role') != 'system':
620
+ # break
621
+
622
+ # system_prompt.append(self.process_message_content(messages[i].get('content')))
623
+ # i += 1
624
+
625
+ # messages = messages[i:]
626
+ # system_prompt = '\n'.join(system_prompt)
627
+
628
+ # if not messages:
629
+ # raise ValueError("没有找到用户或者AI消息")
630
+ # return {"system_prompt":system_prompt,"messages":messages}
631
+ # except Exception as error:
632
+ # logger.error(str(error), "Server")
633
+ # raise ValueError(error)
634
  def prepare_chat_request(self, request):
635
  if ((request["model"] == 'grok-2-imageGen' or request["model"] == 'grok-3-imageGen') and
636
  not CONFIG["API"]["PICGO_KEY"] and not CONFIG["API"]["TUMY_KEY"] and
637
  request.get("stream", False)):
638
  raise ValueError("该模型流式输出需要配置PICGO或者TUMY图床密钥!")
639
 
640
+ # system_message, todo_messages = self.convert_system_messages(request["messages"]).values()
641
  todo_messages = request["messages"]
642
  if request["model"] in ['grok-2-imageGen', 'grok-3-imageGen', 'grok-3-deepsearch']:
643
  last_message = todo_messages[-1]
 
652
  convert_to_file = False
653
  last_message_content = ''
654
  search = request["model"] in ['grok-2-search', 'grok-3-search']
655
+ deepsearchPreset = ''
656
+ if request["model"] == 'grok-3-deepsearch':
657
+ deepsearchPreset = 'default'
658
+ elif request["model"] == 'grok-3-deepersearch':
659
+ deepsearchPreset = 'deeper'
660
 
661
  # 移除<think>标签及其内容和base64图片
662
  def remove_think_tags(text):
 
680
  elif content["type"] == 'text':
681
  return remove_think_tags(content["text"])
682
  return remove_think_tags(self.process_message_content(content))
 
683
  for current in todo_messages:
684
  role = 'assistant' if current["role"] == 'assistant' else 'user'
685
  is_last_message = current == todo_messages[-1]
 
751
  "xPostAnalyze": search
752
  },
753
  "enableSideBySide": True,
 
754
  "sendFinalMetadata": True,
755
+ "customPersonality": "",
756
+ "deepsearchPreset": deepsearchPreset,
757
+ "isReasoning": request["model"] == 'grok-3-reasoning',
758
+ "disableTextFollowUps": True
759
  }
760
 
761
  class MessageProcessor:
 
810
  result["token"] = response.get("token")
811
  elif model == 'grok-3':
812
  result["token"] = response.get("token")
813
+ elif model in ['grok-3-deepsearch', 'grok-3-deepersearch']:
814
  if response.get("messageStepId") and not CONFIG["SHOW_THINKING"]:
815
  return result
816
  if response.get("messageStepId") and not CONFIG["IS_THINKING"]:
 
820
  result["token"] = "</think>" + response.get("token", "")
821
  CONFIG["IS_THINKING"] = False
822
  elif (response.get("messageStepId") and CONFIG["IS_THINKING"] and response.get("messageTag") == "assistant") or response.get("messageTag") == "final":
823
+ result["token"] = response.get("token","")
824
+ elif (CONFIG["IS_THINKING"] and response.get("token","").get("action","") == "webSearch"):
825
+ result["token"] = response.get("token","").get("action_input","").get("query","")
826
+ elif (CONFIG["IS_THINKING"] and response.get("webSearchResults")):
827
+ result["token"] = Utils.organize_search_results(response['webSearchResults'])
828
  elif model == 'grok-3-reasoning':
829
  if response.get("isThinking") and not CONFIG["SHOW_THINKING"]:
830
  return result
 
988
  continue
989
  try:
990
  line_json = json.loads(chunk.decode("utf-8").strip())
991
+ print(line_json)
992
  if line_json.get("error"):
993
  logger.error(json.dumps(line_json, indent=2), "Server")
994
  yield json.dumps({"error": "RateLimitError"}) + "\n\n"
 
1021
  return generate()
1022
 
1023
  def initialization():
1024
+ sso_array = os.environ.get("SSO", "").split(',')
1025
  logger.info("开始加载令牌", "Server")
1026
+ token_manager.load_token_status()
1027
  for sso in sso_array:
1028
  if sso:
1029
+ token_manager.add_token(f"sso-rw={sso};sso={sso}",True)
1030
+ token_manager.save_token_status()
1031
 
1032
  logger.info(f"成功加载令牌: {json.dumps(token_manager.get_all_tokens(), indent=2)}", "Server")
1033
  logger.info(f"令牌加载完成,共加载: {len(token_manager.get_all_tokens())}个令牌", "Server")
 
1040
 
1041
  app = Flask(__name__)
1042
  app.wsgi_app = ProxyFix(app.wsgi_app)
1043
+ app.secret_key = os.environ.get('FLASK_SECRET_KEY') or secrets.token_hex(16)
1044
  app.json.sort_keys = False
1045
 
1046
  @app.route('/manager/login', methods=['GET', 'POST'])
 
1202
  retry_count = 0
1203
  grok_client = GrokApiClient(model)
1204
  request_payload = grok_client.prepare_chat_request(data)
1205
+ logger.info(json.dumps(request_payload,indent=2))
1206
 
1207
  while retry_count < CONFIG["RETRY"]["MAX_ATTEMPTS"]:
1208
  retry_count += 1
 
1229
  **DEFAULT_HEADERS,
1230
  "Cookie":CONFIG["SERVER"]['COOKIE']
1231
  },
1232
+ data=json.dumps(request_payload),
1233
  impersonate="chrome133a",
 
1234
  stream=True,
1235
  **proxy_options)
1236
  logger.info(CONFIG["SERVER"]['COOKIE'],"Server")
 
1260
  token_manager.reduce_token_request_count(model,1)#重置去除当前因为错误未成功请求的次数,确保不会因为错误未成功请求的次数导致次数上限
1261
  if token_manager.get_token_count_for_model(model) == 0:
1262
  raise ValueError(f"{model} 次数已达上限,请切换其他模型或者重新对话")
1263
+ print("状态码:", response.status_code)
1264
+ print("响应头:", response.headers)
1265
+ print("响应内容:", response.text)
1266
  raise ValueError(f"IP暂时被封无法破盾,请稍后重试或者更换ip")
1267
  elif response.status_code == 429:
1268
  response_status_code = 429