ltxlong commited on
Commit
0fc4728
·
verified ·
1 Parent(s): 2a0a433

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +252 -94
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,48 +80,54 @@ 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',
93
- 'grok-2-imageGen': 'grok-latest',
94
- 'grok-2-search': 'grok-latest',
95
  "grok-3": "grok-3",
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
 
@@ -145,7 +146,8 @@ DEFAULT_HEADERS = {
145
  'Sec-Fetch-Dest': 'empty',
146
  'Sec-Fetch-Mode': 'cors',
147
  'Sec-Fetch-Site': 'same-origin',
148
- 'Baggage': 'sentry-public_key=b311e0f2690c81f25e2c4cf6d4f7ce1c'
 
149
  }
150
 
151
  class AuthTokenManager:
@@ -153,67 +155,127 @@ class AuthTokenManager:
153
  self.token_model_map = {}
154
  self.expired_tokens = set()
155
  self.token_status_map = {}
156
-
157
- self.model_config = {
158
- "grok-2": {
159
- "RequestFrequency": 30,
160
- "ExpirationTime": 1 * 60 * 60 * 1000 # 1小时
161
- },
162
- "grok-3": {
163
- "RequestFrequency": 20,
164
- "ExpirationTime": 2 * 60 * 60 * 1000 # 2小时
165
- },
166
- "grok-3-deepsearch": {
167
- "RequestFrequency": 10,
168
- "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
169
- },
170
- "grok-3-reasoning": {
171
- "RequestFrequency": 10,
172
- "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
 
 
 
 
173
  }
174
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  self.token_reset_switch = False
176
  self.token_reset_timer = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
- def add_token(self, token):
179
- sso = token.split("sso=")[1].split(";")[0]
180
  for model in self.model_config.keys():
181
  if model not in self.token_model_map:
182
  self.token_model_map[model] = []
183
  if sso not in self.token_status_map:
184
  self.token_status_map[sso] = {}
185
 
186
- existing_token_entry = next((entry for entry in self.token_model_map[model] if entry["token"] == token), None)
187
 
188
  if not existing_token_entry:
189
  self.token_model_map[model].append({
190
- "token": token,
 
191
  "RequestCount": 0,
192
  "AddedTime": int(time.time() * 1000),
193
- "StartCallTime": None
 
194
  })
195
 
196
  if model not in self.token_status_map[sso]:
197
  self.token_status_map[sso][model] = {
198
  "isValid": True,
199
  "invalidatedTime": None,
200
- "totalRequestCount": 0
 
201
  }
 
 
 
 
 
 
 
 
 
 
202
 
203
- def set_token(self, token):
204
  models = list(self.model_config.keys())
205
  self.token_model_map = {model: [{
206
- "token": token,
 
207
  "RequestCount": 0,
208
  "AddedTime": int(time.time() * 1000),
209
- "StartCallTime": None
 
210
  }] for model in models}
211
 
212
- sso = token.split("sso=")[1].split(";")[0]
213
  self.token_status_map[sso] = {model: {
214
  "isValid": True,
215
  "invalidatedTime": None,
216
- "totalRequestCount": 0
 
217
  } for model in models}
218
 
219
  def delete_token(self, token):
@@ -224,6 +286,8 @@ class AuthTokenManager:
224
 
225
  if sso in self.token_status_map:
226
  del self.token_status_map[sso]
 
 
227
 
228
  logger.info(f"令牌已成功移除: {token}", "TokenManager")
229
  return True
@@ -270,10 +334,15 @@ class AuthTokenManager:
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:
278
  token_entry["StartCallTime"] = int(time.time() * 1000)
279
 
@@ -283,18 +352,23 @@ class AuthTokenManager:
283
 
284
  token_entry["RequestCount"] += 1
285
 
286
- if token_entry["RequestCount"] > self.model_config[normalized_model]["RequestFrequency"]:
287
  self.remove_token_from_model(normalized_model, token_entry["token"])
288
  next_token_entry = self.token_model_map[normalized_model][0] if self.token_model_map[normalized_model] else None
289
  return next_token_entry["token"] if next_token_entry else None
290
 
291
  sso = token_entry["token"].split("sso=")[1].split(";")[0]
 
292
  if sso in self.token_status_map and normalized_model in self.token_status_map[sso]:
293
  if token_entry["RequestCount"] == self.model_config[normalized_model]["RequestFrequency"]:
294
  self.token_status_map[sso][normalized_model]["isValid"] = False
295
  self.token_status_map[sso][normalized_model]["invalidatedTime"] = int(time.time() * 1000)
296
  self.token_status_map[sso][normalized_model]["totalRequestCount"] += 1
297
 
 
 
 
 
298
  return token_entry["token"]
299
 
300
  return None
@@ -314,7 +388,8 @@ class AuthTokenManager:
314
  self.expired_tokens.add((
315
  removed_token_entry["token"],
316
  normalized_model,
317
- int(time.time() * 1000)
 
318
  ))
319
 
320
  if not self.token_reset_switch:
@@ -331,7 +406,7 @@ class AuthTokenManager:
331
  return list(self.expired_tokens)
332
 
333
  def normalize_model_name(self, model):
334
- if model.startswith('grok-') and 'deepsearch' not in model and 'reasoning' not in model:
335
  return '-'.join(model.split('-')[:2])
336
  return model
337
 
@@ -344,8 +419,8 @@ class AuthTokenManager:
344
 
345
  for model in self.model_config.keys():
346
  model_tokens = self.token_model_map.get(model, [])
347
- model_request_frequency = self.model_config[model]["RequestFrequency"]
348
-
349
  total_used_requests = sum(token_entry.get("RequestCount", 0) for token_entry in model_tokens)
350
 
351
  remaining_capacity = (len(model_tokens) * model_request_frequency) - total_used_requests
@@ -361,10 +436,13 @@ class AuthTokenManager:
361
  def reset_expired_tokens():
362
  now = int(time.time() * 1000)
363
 
 
364
  tokens_to_remove = set()
365
  for token_info in self.expired_tokens:
366
- token, model, expired_time = token_info
367
- expiration_time = self.model_config[model]["ExpirationTime"]
 
 
368
 
369
  if now - expired_time >= expiration_time:
370
  if not any(entry["token"] == token for entry in self.token_model_map.get(model, [])):
@@ -373,9 +451,11 @@ class AuthTokenManager:
373
 
374
  self.token_model_map[model].append({
375
  "token": token,
 
376
  "RequestCount": 0,
377
  "AddedTime": now,
378
- "StartCallTime": None
 
379
  })
380
 
381
  sso = token.split("sso=")[1].split(";")[0]
@@ -383,12 +463,13 @@ class AuthTokenManager:
383
  self.token_status_map[sso][model]["isValid"] = True
384
  self.token_status_map[sso][model]["invalidatedTime"] = None
385
  self.token_status_map[sso][model]["totalRequestCount"] = 0
 
386
 
387
  tokens_to_remove.add(token_info)
388
 
389
  self.expired_tokens -= tokens_to_remove
390
 
391
- for model in self.model_config.keys():
392
  if model not in self.token_model_map:
393
  continue
394
 
@@ -396,13 +477,14 @@ class AuthTokenManager:
396
  if not token_entry.get("StartCallTime"):
397
  continue
398
 
399
- expiration_time = self.model_config[model]["ExpirationTime"]
400
  if now - token_entry["StartCallTime"] >= expiration_time:
401
  sso = token_entry["token"].split("sso=")[1].split(";")[0]
402
  if sso in self.token_status_map and model in self.token_status_map[sso]:
403
  self.token_status_map[sso][model]["isValid"] = True
404
  self.token_status_map[sso][model]["invalidatedTime"] = None
405
  self.token_status_map[sso][model]["totalRequestCount"] = 0
 
406
 
407
  token_entry["RequestCount"] = 0
408
  token_entry["StartCallTime"] = None
@@ -525,7 +607,6 @@ class GrokApiClient:
525
  },
526
  json=upload_data,
527
  impersonate="chrome133a",
528
- verify=False,
529
  **proxy_options
530
  )
531
 
@@ -571,7 +652,6 @@ class GrokApiClient:
571
  },
572
  json=upload_data,
573
  impersonate="chrome133a",
574
- verify=False,
575
  **proxy_options
576
  )
577
 
@@ -586,15 +666,35 @@ class GrokApiClient:
586
  except Exception as error:
587
  logger.error(str(error), "Server")
588
  return ''
589
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
590
  def prepare_chat_request(self, request):
591
- if ((request["model"] == 'grok-2-imageGen' or request["model"] == 'grok-3-imageGen') and
592
  not CONFIG["API"]["PICGO_KEY"] and not CONFIG["API"]["TUMY_KEY"] and
593
  request.get("stream", False)):
594
  raise ValueError("该模型流式输出需要配置PICGO或者TUMY图床密钥!")
595
 
 
596
  todo_messages = request["messages"]
597
- if request["model"] in ['grok-2-imageGen', 'grok-3-imageGen', 'grok-3-deepsearch']:
598
  last_message = todo_messages[-1]
599
  if last_message["role"] != 'user':
600
  raise ValueError('此模型最后一条消息必须是用户消息!')
@@ -606,7 +706,12 @@ class GrokApiClient:
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图片
612
  def remove_think_tags(text):
@@ -630,7 +735,6 @@ class GrokApiClient:
630
  elif content["type"] == 'text':
631
  return remove_think_tags(content["text"])
632
  return remove_think_tags(self.process_message_content(content))
633
-
634
  for current in todo_messages:
635
  role = 'assistant' if current["role"] == 'assistant' else 'user'
636
  is_last_message = current == todo_messages[-1]
@@ -694,7 +798,7 @@ class GrokApiClient:
694
  "imageGenerationCount": 1,
695
  "forceConcise": False,
696
  "toolOverrides": {
697
- "imageGen": request["model"] in ['grok-2-imageGen', 'grok-3-imageGen'],
698
  "webSearch": search,
699
  "xSearch": search,
700
  "xMediaSearch": search,
@@ -702,11 +806,11 @@ class GrokApiClient:
702
  "xPostAnalyze": search
703
  },
704
  "enableSideBySide": True,
705
- "isPreset": False,
706
  "sendFinalMetadata": True,
707
- "customInstructions": "",
708
- "deepsearchPreset": "default" if request["model"] == 'grok-3-deepsearch' else "",
709
- "isReasoning": request["model"] == 'grok-3-reasoning'
 
710
  }
711
 
712
  class MessageProcessor:
@@ -751,17 +855,14 @@ def process_model_response(response, model):
751
  if response.get("cachedImageGenerationResponse") and not CONFIG["IS_IMG_GEN2"]:
752
  result["imageUrl"] = response["cachedImageGenerationResponse"]["imageUrl"]
753
  return result
754
-
755
- if model == 'grok-2':
756
  result["token"] = response.get("token")
757
- elif model in ['grok-2-search', 'grok-3-search']:
758
  if response.get("webSearchResults") and CONFIG["ISSHOW_SEARCH_RESULTS"]:
759
  result["token"] = f"\r\n<think>{Utils.organize_search_results(response['webSearchResults'])}</think>\r\n"
760
  else:
761
  result["token"] = response.get("token")
762
- elif model == 'grok-3':
763
- result["token"] = response.get("token")
764
- elif model == 'grok-3-deepsearch':
765
  if response.get("messageStepId") and not CONFIG["SHOW_THINKING"]:
766
  return result
767
  if response.get("messageStepId") and not CONFIG["IS_THINKING"]:
@@ -771,7 +872,11 @@ def process_model_response(response, model):
771
  result["token"] = "</think>" + response.get("token", "")
772
  CONFIG["IS_THINKING"] = False
773
  elif (response.get("messageStepId") and CONFIG["IS_THINKING"] and response.get("messageTag") == "assistant") or response.get("messageTag") == "final":
774
- result["token"] = response.get("token")
 
 
 
 
775
  elif model == 'grok-3-reasoning':
776
  if response.get("isThinking") and not CONFIG["SHOW_THINKING"]:
777
  return result
@@ -785,6 +890,37 @@ def process_model_response(response, model):
785
  else:
786
  result["token"] = response.get("token")
787
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
788
  return result
789
 
790
  def handle_image_response(image_url):
@@ -935,6 +1071,7 @@ def handle_stream_response(response, model):
935
  continue
936
  try:
937
  line_json = json.loads(chunk.decode("utf-8").strip())
 
938
  if line_json.get("error"):
939
  logger.error(json.dumps(line_json, indent=2), "Server")
940
  yield json.dumps({"error": "RateLimitError"}) + "\n\n"
@@ -967,24 +1104,42 @@ def handle_stream_response(response, model):
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:
974
- token_manager.add_token(f"sso-rw={sso};sso={sso}")
 
 
975
 
976
  logger.info(f"成功加载令牌: {json.dumps(token_manager.get_all_tokens(), indent=2)}", "Server")
977
- logger.info(f"令牌加载完成,共加载: {len(token_manager.get_all_tokens())}个令牌", "Server")
 
978
 
979
  if CONFIG["API"]["PROXY"]:
980
  logger.info(f"代理已设置: {CONFIG['API']['PROXY']}", "Server")
981
 
982
- logger.info("初始化完成", "Server")
983
 
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'])
@@ -1023,7 +1178,7 @@ def add_manager_token():
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
@@ -1074,7 +1229,7 @@ def add_token():
1074
 
1075
  try:
1076
  sso = request.json.get('sso')
1077
- token_manager.add_token(f"sso-rw={sso};sso={sso}")
1078
  return jsonify(token_manager.get_token_status_map().get(sso, {})), 200
1079
  except Exception as error:
1080
  logger.error(str(error), "Server")
@@ -1146,7 +1301,8 @@ def chat_completions():
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
@@ -1173,9 +1329,8 @@ def chat_completions():
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")
@@ -1205,6 +1360,9 @@ def chat_completions():
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
 
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-3": "grok-3",
90
  "grok-3-search": "grok-3",
91
  "grok-3-imageGen": "grok-3",
92
  "grok-3-deepsearch": "grok-3",
93
+ "grok-3-deepersearch": "grok-3",
94
+ "grok-3-reasoning": "grok-3",
95
+ 'grok-4': 'grok-4',
96
+ 'grok-4-reasoning': 'grok-4',
97
+ 'grok-4-imageGen': 'grok-4',
98
+ 'grok-4-deepsearch': 'grok-4'
99
  },
100
  "API": {
101
+ "IS_TEMP_CONVERSATION": os.environ.get("IS_TEMP_CONVERSATION", "true").lower() == "true",
102
+ "IS_CUSTOM_SSO": os.environ.get("IS_CUSTOM_SSO", "false").lower() == "true",
103
  "BASE_URL": "https://grok.com",
104
+ "API_KEY": os.environ.get("API_KEY", "sk-123456"),
105
  "SIGNATURE_COOKIE": None,
106
+ "PICGO_KEY": os.environ.get("PICGO_KEY") or None,
107
+ "TUMY_KEY": os.environ.get("TUMY_KEY") or None,
108
  "RETRY_TIME": 1000,
109
+ "PROXY": os.environ.get("PROXY") or None
110
  },
111
  "ADMIN": {
112
+ "MANAGER_SWITCH": os.environ.get("MANAGER_SWITCH") or None,
113
+ "PASSWORD": os.environ.get("ADMINPASSWORD") or None
114
  },
115
  "SERVER": {
116
  "COOKIE": None,
117
+ "CF_CLEARANCE":os.environ.get("CF_CLEARANCE") or None,
118
+ "PORT": int(os.environ.get("PORT", 5200))
119
  },
120
  "RETRY": {
121
  "RETRYSWITCH": False,
122
  "MAX_ATTEMPTS": 2
123
  },
124
+ "TOKEN_STATUS_FILE": str(DATA_DIR / "token_status.json"),
125
+ "SHOW_THINKING": os.environ.get("SHOW_THINKING").lower() == "true",
126
  "IS_THINKING": False,
127
  "IS_IMG_GEN": False,
128
  "IS_IMG_GEN2": False,
129
+ "ISSHOW_SEARCH_RESULTS": os.environ.get("ISSHOW_SEARCH_RESULTS", "true").lower() == "true",
130
+ "IS_SUPER_GROK": os.environ.get("IS_SUPER_GROK", "false").lower() == "true"
131
  }
132
 
133
 
 
146
  'Sec-Fetch-Dest': 'empty',
147
  'Sec-Fetch-Mode': 'cors',
148
  'Sec-Fetch-Site': 'same-origin',
149
+ 'Baggage': 'sentry-public_key=b311e0f2690c81f25e2c4cf6d4f7ce1c',
150
+ 'x-statsig-id': 'ZTpUeXBlRXJyb3I6IENhbm5vdCByZWFkIHByb3BlcnRpZXMgb2YgdW5kZWZpbmVkIChyZWFkaW5nICdjaGlsZE5vZGVzJyk='
151
  }
152
 
153
  class AuthTokenManager:
 
155
  self.token_model_map = {}
156
  self.expired_tokens = set()
157
  self.token_status_map = {}
158
+ self.model_super_config = {
159
+ "grok-3": {
160
+ "RequestFrequency": 100,
161
+ "ExpirationTime": 3 * 60 * 60 * 1000 # 3小时
162
+ },
163
+ "grok-3-deepsearch": {
164
+ "RequestFrequency": 30,
165
+ "ExpirationTime": 24 * 60 * 60 * 1000 # 3小��
166
+ },
167
+ "grok-3-deepersearch": {
168
+ "RequestFrequency": 10,
169
+ "ExpirationTime": 3 * 60 * 60 * 1000 # 23小时
170
+ },
171
+ "grok-3-reasoning": {
172
+ "RequestFrequency": 30,
173
+ "ExpirationTime": 3 * 60 * 60 * 1000 # 3小时
174
+ },
175
+ "grok-4": {
176
+ "RequestFrequency": 20,
177
+ "ExpirationTime": 3 * 60 * 60 * 1000 # 3小时
178
+ }
179
  }
180
+ self.model_normal_config = {
181
+ "grok-3": {
182
+ "RequestFrequency": 20,
183
+ "ExpirationTime": 3 * 60 * 60 * 1000 # 3小时
184
+ },
185
+ "grok-3-deepsearch": {
186
+ "RequestFrequency": 10,
187
+ "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
188
+ },
189
+ "grok-3-deepersearch": {
190
+ "RequestFrequency": 3,
191
+ "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
192
+ },
193
+ "grok-3-reasoning": {
194
+ "RequestFrequency": 8,
195
+ "ExpirationTime": 24 * 60 * 60 * 1000 # 24小时
196
+ }
197
+ }
198
+ self.model_config = self.model_normal_config
199
  self.token_reset_switch = False
200
  self.token_reset_timer = None
201
+ def save_token_status(self):
202
+ try:
203
+ with open(CONFIG["TOKEN_STATUS_FILE"], 'w', encoding='utf-8') as f:
204
+ json.dump(self.token_status_map, f, indent=2, ensure_ascii=False)
205
+ logger.info("令牌状态已保存到配置文件", "TokenManager")
206
+ except Exception as error:
207
+ logger.error(f"保存令牌状态失败: {str(error)}", "TokenManager")
208
+
209
+ def load_token_status(self):
210
+ try:
211
+ token_status_file = Path(CONFIG["TOKEN_STATUS_FILE"])
212
+ if token_status_file.exists():
213
+ with open(token_status_file, 'r', encoding='utf-8') as f:
214
+ self.token_status_map = json.load(f)
215
+ logger.info("已从配置文件加载令牌状态", "TokenManager")
216
+ except Exception as error:
217
+ logger.error(f"加载令牌状态失败: {str(error)}", "TokenManager")
218
+ def add_token(self, tokens, isinitialization=False):
219
+ tokenType = tokens.get("type")
220
+ tokenSso = tokens.get("token")
221
+ if tokenType == "normal":
222
+ self.model_config = self.model_normal_config
223
+ else:
224
+ self.model_config = self.model_super_config
225
+ sso = tokenSso.split("sso=")[1].split(";")[0]
226
 
 
 
227
  for model in self.model_config.keys():
228
  if model not in self.token_model_map:
229
  self.token_model_map[model] = []
230
  if sso not in self.token_status_map:
231
  self.token_status_map[sso] = {}
232
 
233
+ existing_token_entry = next((entry for entry in self.token_model_map[model] if entry["token"] == tokenSso), None)
234
 
235
  if not existing_token_entry:
236
  self.token_model_map[model].append({
237
+ "token": tokenSso,
238
+ "MaxRequestCount": self.model_config[model]["RequestFrequency"],
239
  "RequestCount": 0,
240
  "AddedTime": int(time.time() * 1000),
241
+ "StartCallTime": None,
242
+ "type": tokenType
243
  })
244
 
245
  if model not in self.token_status_map[sso]:
246
  self.token_status_map[sso][model] = {
247
  "isValid": True,
248
  "invalidatedTime": None,
249
+ "totalRequestCount": 0,
250
+ "isSuper":tokenType == "super"
251
  }
252
+ if not isinitialization:
253
+ self.save_token_status()
254
+
255
+ def set_token(self, tokens):
256
+ tokenType = tokens.get("type")
257
+ tokenSso = tokens.get("token")
258
+ if tokenType == "normal":
259
+ self.model_config = self.model_normal_config
260
+ else:
261
+ self.model_config = self.model_super_config
262
 
 
263
  models = list(self.model_config.keys())
264
  self.token_model_map = {model: [{
265
+ "token": tokenSso,
266
+ "MaxRequestCount": self.model_config[model]["RequestFrequency"],
267
  "RequestCount": 0,
268
  "AddedTime": int(time.time() * 1000),
269
+ "StartCallTime": None,
270
+ "type": tokenType
271
  }] for model in models}
272
 
273
+ sso = tokenSso.split("sso=")[1].split(";")[0]
274
  self.token_status_map[sso] = {model: {
275
  "isValid": True,
276
  "invalidatedTime": None,
277
+ "totalRequestCount": 0,
278
+ "isSuper":tokenType == "super"
279
  } for model in models}
280
 
281
  def delete_token(self, token):
 
286
 
287
  if sso in self.token_status_map:
288
  del self.token_status_map[sso]
289
+
290
+ self.save_token_status()
291
 
292
  logger.info(f"令牌已成功移除: {token}", "TokenManager")
293
  return True
 
334
  return None
335
 
336
  token_entry = self.token_model_map[normalized_model][0]
337
+ logger.info(f"token_entry: {token_entry}", "TokenManager")
338
  if is_return:
339
  return token_entry["token"]
340
 
341
  if token_entry:
342
+ if token_entry["type"] == "super":
343
+ self.model_config = self.model_super_config
344
+ else:
345
+ self.model_config = self.model_normal_config
346
  if token_entry["StartCallTime"] is None:
347
  token_entry["StartCallTime"] = int(time.time() * 1000)
348
 
 
352
 
353
  token_entry["RequestCount"] += 1
354
 
355
+ if token_entry["RequestCount"] > token_entry["MaxRequestCount"]:
356
  self.remove_token_from_model(normalized_model, token_entry["token"])
357
  next_token_entry = self.token_model_map[normalized_model][0] if self.token_model_map[normalized_model] else None
358
  return next_token_entry["token"] if next_token_entry else None
359
 
360
  sso = token_entry["token"].split("sso=")[1].split(";")[0]
361
+
362
  if sso in self.token_status_map and normalized_model in self.token_status_map[sso]:
363
  if token_entry["RequestCount"] == self.model_config[normalized_model]["RequestFrequency"]:
364
  self.token_status_map[sso][normalized_model]["isValid"] = False
365
  self.token_status_map[sso][normalized_model]["invalidatedTime"] = int(time.time() * 1000)
366
  self.token_status_map[sso][normalized_model]["totalRequestCount"] += 1
367
 
368
+
369
+
370
+ self.save_token_status()
371
+
372
  return token_entry["token"]
373
 
374
  return None
 
388
  self.expired_tokens.add((
389
  removed_token_entry["token"],
390
  normalized_model,
391
+ int(time.time() * 1000),
392
+ removed_token_entry["type"]
393
  ))
394
 
395
  if not self.token_reset_switch:
 
406
  return list(self.expired_tokens)
407
 
408
  def normalize_model_name(self, model):
409
+ if model.startswith('grok-') and not any(keyword in model for keyword in ['deepsearch','deepersearch','reasoning']):
410
  return '-'.join(model.split('-')[:2])
411
  return model
412
 
 
419
 
420
  for model in self.model_config.keys():
421
  model_tokens = self.token_model_map.get(model, [])
422
+
423
+ model_request_frequency = sum(token_entry.get("MaxRequestCount", 0) for token_entry in model_tokens)
424
  total_used_requests = sum(token_entry.get("RequestCount", 0) for token_entry in model_tokens)
425
 
426
  remaining_capacity = (len(model_tokens) * model_request_frequency) - total_used_requests
 
436
  def reset_expired_tokens():
437
  now = int(time.time() * 1000)
438
 
439
+ model_config = self.model_normal_config
440
  tokens_to_remove = set()
441
  for token_info in self.expired_tokens:
442
+ token, model, expired_time ,type = token_info
443
+ if type == "super":
444
+ model_config = self.model_super_config
445
+ expiration_time = model_config[model]["ExpirationTime"]
446
 
447
  if now - expired_time >= expiration_time:
448
  if not any(entry["token"] == token for entry in self.token_model_map.get(model, [])):
 
451
 
452
  self.token_model_map[model].append({
453
  "token": token,
454
+ "MaxRequestCount": model_config[model]["RequestFrequency"],
455
  "RequestCount": 0,
456
  "AddedTime": now,
457
+ "StartCallTime": None,
458
+ "type": type
459
  })
460
 
461
  sso = token.split("sso=")[1].split(";")[0]
 
463
  self.token_status_map[sso][model]["isValid"] = True
464
  self.token_status_map[sso][model]["invalidatedTime"] = None
465
  self.token_status_map[sso][model]["totalRequestCount"] = 0
466
+ self.token_status_map[sso][model]["isSuper"] = type == "super"
467
 
468
  tokens_to_remove.add(token_info)
469
 
470
  self.expired_tokens -= tokens_to_remove
471
 
472
+ for model in model_config.keys():
473
  if model not in self.token_model_map:
474
  continue
475
 
 
477
  if not token_entry.get("StartCallTime"):
478
  continue
479
 
480
+ expiration_time = model_config[model]["ExpirationTime"]
481
  if now - token_entry["StartCallTime"] >= expiration_time:
482
  sso = token_entry["token"].split("sso=")[1].split(";")[0]
483
  if sso in self.token_status_map and model in self.token_status_map[sso]:
484
  self.token_status_map[sso][model]["isValid"] = True
485
  self.token_status_map[sso][model]["invalidatedTime"] = None
486
  self.token_status_map[sso][model]["totalRequestCount"] = 0
487
+ self.token_status_map[sso][model]["isSuper"] = token_entry["type"] == "super"
488
 
489
  token_entry["RequestCount"] = 0
490
  token_entry["StartCallTime"] = None
 
607
  },
608
  json=upload_data,
609
  impersonate="chrome133a",
 
610
  **proxy_options
611
  )
612
 
 
652
  },
653
  json=upload_data,
654
  impersonate="chrome133a",
 
655
  **proxy_options
656
  )
657
 
 
666
  except Exception as error:
667
  logger.error(str(error), "Server")
668
  return ''
669
+ # def convert_system_messages(self, messages):
670
+ # try:
671
+ # system_prompt = []
672
+ # i = 0
673
+ # while i < len(messages):
674
+ # if messages[i].get('role') != 'system':
675
+ # break
676
+
677
+ # system_prompt.append(self.process_message_content(messages[i].get('content')))
678
+ # i += 1
679
+
680
+ # messages = messages[i:]
681
+ # system_prompt = '\n'.join(system_prompt)
682
+
683
+ # if not messages:
684
+ # raise ValueError("没有找到用户或者AI消息")
685
+ # return {"system_prompt":system_prompt,"messages":messages}
686
+ # except Exception as error:
687
+ # logger.error(str(error), "Server")
688
+ # raise ValueError(error)
689
  def prepare_chat_request(self, request):
690
+ if ((request["model"] == 'grok-4-imageGen' or request["model"] == 'grok-3-imageGen') and
691
  not CONFIG["API"]["PICGO_KEY"] and not CONFIG["API"]["TUMY_KEY"] and
692
  request.get("stream", False)):
693
  raise ValueError("该模型流式输出需要配置PICGO或者TUMY图床密钥!")
694
 
695
+ # system_message, todo_messages = self.convert_system_messages(request["messages"]).values()
696
  todo_messages = request["messages"]
697
+ if request["model"] in ['grok-4-imageGen', 'grok-3-imageGen', 'grok-3-deepsearch']:
698
  last_message = todo_messages[-1]
699
  if last_message["role"] != 'user':
700
  raise ValueError('此模型最后一条消息必须是用户消息!')
 
706
  message_length = 0
707
  convert_to_file = False
708
  last_message_content = ''
709
+ search = request["model"] in ['grok-4-deepsearch', 'grok-3-search']
710
+ deepsearchPreset = ''
711
+ if request["model"] == 'grok-3-deepsearch':
712
+ deepsearchPreset = 'default'
713
+ elif request["model"] == 'grok-3-deepersearch':
714
+ deepsearchPreset = 'deeper'
715
 
716
  # 移除<think>标签及其内容和base64图片
717
  def remove_think_tags(text):
 
735
  elif content["type"] == 'text':
736
  return remove_think_tags(content["text"])
737
  return remove_think_tags(self.process_message_content(content))
 
738
  for current in todo_messages:
739
  role = 'assistant' if current["role"] == 'assistant' else 'user'
740
  is_last_message = current == todo_messages[-1]
 
798
  "imageGenerationCount": 1,
799
  "forceConcise": False,
800
  "toolOverrides": {
801
+ "imageGen": request["model"] in ['grok-4-imageGen', 'grok-3-imageGen'],
802
  "webSearch": search,
803
  "xSearch": search,
804
  "xMediaSearch": search,
 
806
  "xPostAnalyze": search
807
  },
808
  "enableSideBySide": True,
 
809
  "sendFinalMetadata": True,
810
+ "customPersonality": "",
811
+ "deepsearchPreset": deepsearchPreset,
812
+ "isReasoning": request["model"] == 'grok-3-reasoning',
813
+ "disableTextFollowUps": True
814
  }
815
 
816
  class MessageProcessor:
 
855
  if response.get("cachedImageGenerationResponse") and not CONFIG["IS_IMG_GEN2"]:
856
  result["imageUrl"] = response["cachedImageGenerationResponse"]["imageUrl"]
857
  return result
858
+ if model == 'grok-3':
 
859
  result["token"] = response.get("token")
860
+ elif model in ['grok-3-search']:
861
  if response.get("webSearchResults") and CONFIG["ISSHOW_SEARCH_RESULTS"]:
862
  result["token"] = f"\r\n<think>{Utils.organize_search_results(response['webSearchResults'])}</think>\r\n"
863
  else:
864
  result["token"] = response.get("token")
865
+ elif model in ['grok-3-deepsearch', 'grok-3-deepersearch','grok-4-deepsearch']:
 
 
866
  if response.get("messageStepId") and not CONFIG["SHOW_THINKING"]:
867
  return result
868
  if response.get("messageStepId") and not CONFIG["IS_THINKING"]:
 
872
  result["token"] = "</think>" + response.get("token", "")
873
  CONFIG["IS_THINKING"] = False
874
  elif (response.get("messageStepId") and CONFIG["IS_THINKING"] and response.get("messageTag") == "assistant") or response.get("messageTag") == "final":
875
+ result["token"] = response.get("token","")
876
+ elif (CONFIG["IS_THINKING"] and response.get("token","").get("action","") == "webSearch"):
877
+ result["token"] = response.get("token","").get("action_input","").get("query","")
878
+ elif (CONFIG["IS_THINKING"] and response.get("webSearchResults")):
879
+ result["token"] = Utils.organize_search_results(response['webSearchResults'])
880
  elif model == 'grok-3-reasoning':
881
  if response.get("isThinking") and not CONFIG["SHOW_THINKING"]:
882
  return result
 
890
  else:
891
  result["token"] = response.get("token")
892
 
893
+ elif model == 'grok-4':
894
+ if response.get("isThinking"):
895
+ return result
896
+ result["token"] = response.get("token")
897
+ elif model == 'grok-4-reasoning':
898
+ if response.get("isThinking") and not CONFIG["SHOW_THINKING"]:
899
+ return result
900
+ if response.get("isThinking") and not CONFIG["IS_THINKING"] and response.get("messageTag") == "assistant":
901
+ result["token"] = "<think>" + response.get("token", "")
902
+ CONFIG["IS_THINKING"] = True
903
+ elif not response.get("isThinking") and CONFIG["IS_THINKING"] and response.get("messageTag") == "final":
904
+ result["token"] = "</think>" + response.get("token", "")
905
+ CONFIG["IS_THINKING"] = False
906
+ else:
907
+ result["token"] = response.get("token")
908
+ elif model in ['grok-4-deepsearch']:
909
+ if response.get("messageStepId") and not CONFIG["SHOW_THINKING"]:
910
+ return result
911
+ if response.get("messageStepId") and not CONFIG["IS_THINKING"] and response.get("messageTag") == "assistant":
912
+ result["token"] = "<think>" + response.get("token", "")
913
+ CONFIG["IS_THINKING"] = True
914
+ elif not response.get("messageStepId") and CONFIG["IS_THINKING"] and response.get("messageTag") == "final":
915
+ result["token"] = "</think>" + response.get("token", "")
916
+ CONFIG["IS_THINKING"] = False
917
+ elif (response.get("messageStepId") and CONFIG["IS_THINKING"] and response.get("messageTag") == "assistant") or response.get("messageTag") == "final":
918
+ result["token"] = response.get("token","")
919
+ elif (CONFIG["IS_THINKING"] and response.get("token","").get("action","") == "webSearch"):
920
+ result["token"] = response.get("token","").get("action_input","").get("query","")
921
+ elif (CONFIG["IS_THINKING"] and response.get("webSearchResults")):
922
+ result["token"] = Utils.organize_search_results(response['webSearchResults'])
923
+
924
  return result
925
 
926
  def handle_image_response(image_url):
 
1071
  continue
1072
  try:
1073
  line_json = json.loads(chunk.decode("utf-8").strip())
1074
+ print(line_json)
1075
  if line_json.get("error"):
1076
  logger.error(json.dumps(line_json, indent=2), "Server")
1077
  yield json.dumps({"error": "RateLimitError"}) + "\n\n"
 
1104
  return generate()
1105
 
1106
  def initialization():
1107
+ sso_array = os.environ.get("SSO", "").split(',')
1108
+ sso_array_super = os.environ.get("SSO_SUPER", "").split(',')
1109
+
1110
+ combined_dict = []
1111
+ for value in sso_array_super:
1112
+ combined_dict.append({
1113
+ "token": f"sso-rw={value};sso={value}",
1114
+ "type": "super"
1115
+ })
1116
+ for value in sso_array:
1117
+ combined_dict.append({
1118
+ "token": f"sso-rw={value};sso={value}",
1119
+ "type": "normal"
1120
+ })
1121
+
1122
+
1123
  logger.info("开始加载令牌", "Server")
1124
+ token_manager.load_token_status()
1125
+ for tokens in combined_dict:
1126
+ if tokens:
1127
+ token_manager.add_token(tokens,True)
1128
+ token_manager.save_token_status()
1129
 
1130
  logger.info(f"成功加载令牌: {json.dumps(token_manager.get_all_tokens(), indent=2)}", "Server")
1131
+ logger.info(f"令牌加载完成,共加载: {len(sso_array)+len(sso_array_super)}个令牌", "Server")
1132
+ logger.info(f"其中共加载: {len(sso_array_super)}个super会员令牌", "Server")
1133
 
1134
  if CONFIG["API"]["PROXY"]:
1135
  logger.info(f"代理已设置: {CONFIG['API']['PROXY']}", "Server")
1136
 
1137
+ logger.info("初始化完成", "Server")
1138
 
1139
 
1140
  app = Flask(__name__)
1141
  app.wsgi_app = ProxyFix(app.wsgi_app)
1142
+ app.secret_key = os.environ.get('FLASK_SECRET_KEY') or secrets.token_hex(16)
1143
  app.json.sort_keys = False
1144
 
1145
  @app.route('/manager/login', methods=['GET', 'POST'])
 
1178
  sso = request.json.get('sso')
1179
  if not sso:
1180
  return jsonify({"error": "SSO token is required"}), 400
1181
+ token_manager.add_token({"token":f"sso-rw={sso};sso={sso}","type":"normal"})
1182
  return jsonify({"success": True})
1183
  except Exception as e:
1184
  return jsonify({"error": str(e)}), 500
 
1229
 
1230
  try:
1231
  sso = request.json.get('sso')
1232
+ token_manager.add_token({"token":f"sso-rw={sso};sso={sso}","type":"normal"})
1233
  return jsonify(token_manager.get_token_status_map().get(sso, {})), 200
1234
  except Exception as error:
1235
  logger.error(str(error), "Server")
 
1301
  retry_count = 0
1302
  grok_client = GrokApiClient(model)
1303
  request_payload = grok_client.prepare_chat_request(data)
1304
+
1305
+ logger.info(json.dumps(request_payload,indent=2))
1306
 
1307
  while retry_count < CONFIG["RETRY"]["MAX_ATTEMPTS"]:
1308
  retry_count += 1
 
1329
  **DEFAULT_HEADERS,
1330
  "Cookie":CONFIG["SERVER"]['COOKIE']
1331
  },
1332
+ data=json.dumps(request_payload),
1333
  impersonate="chrome133a",
 
1334
  stream=True,
1335
  **proxy_options)
1336
  logger.info(CONFIG["SERVER"]['COOKIE'],"Server")
 
1360
  token_manager.reduce_token_request_count(model,1)#重置去除当前因为错误未成功请求的次数,确保不会因为错误未成功请求的次数导致次数上限
1361
  if token_manager.get_token_count_for_model(model) == 0:
1362
  raise ValueError(f"{model} 次数已达上限,请切换其他模型或者重新对话")
1363
+ print("状态码:", response.status_code)
1364
+ print("响应头:", response.headers)
1365
+ print("响应内容:", response.text)
1366
  raise ValueError(f"IP暂时被封无法破盾,请稍后重试或者更换ip")
1367
  elif response.status_code == 429:
1368
  response_status_code = 429