Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
CHANGED
@@ -86,15 +86,16 @@ if not DATA_DIR.exists():
|
|
86 |
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
87 |
CONFIG = {
|
88 |
"MODELS": {
|
89 |
-
'grok-2': 'grok-latest',
|
90 |
-
'grok-2-imageGen': 'grok-latest',
|
91 |
-
'grok-2-search': 'grok-latest',
|
92 |
"grok-3": "grok-3",
|
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",
|
@@ -121,13 +122,15 @@ CONFIG = {
|
|
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 |
DEFAULT_HEADERS = {
|
132 |
'Accept': '*/*',
|
133 |
'Accept-Language': 'zh-CN,zh;q=0.9',
|
@@ -136,16 +139,15 @@ DEFAULT_HEADERS = {
|
|
136 |
'Connection': 'keep-alive',
|
137 |
'Origin': 'https://grok.com',
|
138 |
'Priority': 'u=1, i',
|
139 |
-
'User-Agent': 'Mozilla/5.0 (
|
140 |
-
'Sec-Ch-Ua': '"
|
141 |
'Sec-Ch-Ua-Mobile': '?0',
|
142 |
-
'Sec-Ch-Ua-Platform': '"
|
143 |
'Sec-Fetch-Dest': 'empty',
|
144 |
'Sec-Fetch-Mode': 'cors',
|
145 |
'Sec-Fetch-Site': 'same-origin',
|
146 |
-
'
|
147 |
-
'x-
|
148 |
-
'Baggage': 'sentry-public_key=b311e0f2690c81f25e2c4cf6d4f7ce1c'
|
149 |
}
|
150 |
|
151 |
class AuthTokenManager:
|
@@ -153,32 +155,49 @@ class AuthTokenManager:
|
|
153 |
self.token_model_map = {}
|
154 |
self.expired_tokens = set()
|
155 |
self.token_status_map = {}
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
}
|
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:
|
@@ -196,47 +215,67 @@ class AuthTokenManager:
|
|
196 |
logger.info("已从配置文件加载令牌状态", "TokenManager")
|
197 |
except Exception as error:
|
198 |
logger.error(f"加载令牌状态失败: {str(error)}", "TokenManager")
|
199 |
-
def add_token(self,
|
200 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
201 |
for model in self.model_config.keys():
|
202 |
if model not in self.token_model_map:
|
203 |
self.token_model_map[model] = []
|
204 |
if sso not in self.token_status_map:
|
205 |
self.token_status_map[sso] = {}
|
206 |
|
207 |
-
existing_token_entry = next((entry for entry in self.token_model_map[model] if entry["token"] ==
|
208 |
|
209 |
if not existing_token_entry:
|
210 |
self.token_model_map[model].append({
|
211 |
-
"token":
|
|
|
212 |
"RequestCount": 0,
|
213 |
"AddedTime": int(time.time() * 1000),
|
214 |
-
"StartCallTime": None
|
|
|
215 |
})
|
216 |
|
217 |
if model not in self.token_status_map[sso]:
|
218 |
self.token_status_map[sso][model] = {
|
219 |
"isValid": True,
|
220 |
"invalidatedTime": None,
|
221 |
-
"totalRequestCount": 0
|
|
|
222 |
}
|
223 |
if not isinitialization:
|
224 |
self.save_token_status()
|
225 |
|
226 |
-
def set_token(self,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
227 |
models = list(self.model_config.keys())
|
228 |
self.token_model_map = {model: [{
|
229 |
-
"token":
|
|
|
230 |
"RequestCount": 0,
|
231 |
"AddedTime": int(time.time() * 1000),
|
232 |
-
"StartCallTime": None
|
|
|
233 |
}] for model in models}
|
234 |
|
235 |
-
sso =
|
236 |
self.token_status_map[sso] = {model: {
|
237 |
"isValid": True,
|
238 |
"invalidatedTime": None,
|
239 |
-
"totalRequestCount": 0
|
|
|
240 |
} for model in models}
|
241 |
|
242 |
def delete_token(self, token):
|
@@ -295,10 +334,15 @@ class AuthTokenManager:
|
|
295 |
return None
|
296 |
|
297 |
token_entry = self.token_model_map[normalized_model][0]
|
|
|
298 |
if is_return:
|
299 |
return token_entry["token"]
|
300 |
|
301 |
if token_entry:
|
|
|
|
|
|
|
|
|
302 |
if token_entry["StartCallTime"] is None:
|
303 |
token_entry["StartCallTime"] = int(time.time() * 1000)
|
304 |
|
@@ -308,18 +352,21 @@ class AuthTokenManager:
|
|
308 |
|
309 |
token_entry["RequestCount"] += 1
|
310 |
|
311 |
-
if token_entry["RequestCount"] >
|
312 |
self.remove_token_from_model(normalized_model, token_entry["token"])
|
313 |
next_token_entry = self.token_model_map[normalized_model][0] if self.token_model_map[normalized_model] else None
|
314 |
return next_token_entry["token"] if next_token_entry else None
|
315 |
|
316 |
sso = token_entry["token"].split("sso=")[1].split(";")[0]
|
|
|
317 |
if sso in self.token_status_map and normalized_model in self.token_status_map[sso]:
|
318 |
if token_entry["RequestCount"] == self.model_config[normalized_model]["RequestFrequency"]:
|
319 |
self.token_status_map[sso][normalized_model]["isValid"] = False
|
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"]
|
@@ -341,7 +388,8 @@ class AuthTokenManager:
|
|
341 |
self.expired_tokens.add((
|
342 |
removed_token_entry["token"],
|
343 |
normalized_model,
|
344 |
-
int(time.time() * 1000)
|
|
|
345 |
))
|
346 |
|
347 |
if not self.token_reset_switch:
|
@@ -358,7 +406,7 @@ class AuthTokenManager:
|
|
358 |
return list(self.expired_tokens)
|
359 |
|
360 |
def normalize_model_name(self, model):
|
361 |
-
if model.startswith('grok-') and
|
362 |
return '-'.join(model.split('-')[:2])
|
363 |
return model
|
364 |
|
@@ -371,8 +419,8 @@ class AuthTokenManager:
|
|
371 |
|
372 |
for model in self.model_config.keys():
|
373 |
model_tokens = self.token_model_map.get(model, [])
|
374 |
-
|
375 |
-
|
376 |
total_used_requests = sum(token_entry.get("RequestCount", 0) for token_entry in model_tokens)
|
377 |
|
378 |
remaining_capacity = (len(model_tokens) * model_request_frequency) - total_used_requests
|
@@ -388,10 +436,13 @@ class AuthTokenManager:
|
|
388 |
def reset_expired_tokens():
|
389 |
now = int(time.time() * 1000)
|
390 |
|
|
|
391 |
tokens_to_remove = set()
|
392 |
for token_info in self.expired_tokens:
|
393 |
-
token, model, expired_time = token_info
|
394 |
-
|
|
|
|
|
395 |
|
396 |
if now - expired_time >= expiration_time:
|
397 |
if not any(entry["token"] == token for entry in self.token_model_map.get(model, [])):
|
@@ -400,9 +451,11 @@ class AuthTokenManager:
|
|
400 |
|
401 |
self.token_model_map[model].append({
|
402 |
"token": token,
|
|
|
403 |
"RequestCount": 0,
|
404 |
"AddedTime": now,
|
405 |
-
"StartCallTime": None
|
|
|
406 |
})
|
407 |
|
408 |
sso = token.split("sso=")[1].split(";")[0]
|
@@ -410,12 +463,13 @@ class AuthTokenManager:
|
|
410 |
self.token_status_map[sso][model]["isValid"] = True
|
411 |
self.token_status_map[sso][model]["invalidatedTime"] = None
|
412 |
self.token_status_map[sso][model]["totalRequestCount"] = 0
|
|
|
413 |
|
414 |
tokens_to_remove.add(token_info)
|
415 |
|
416 |
self.expired_tokens -= tokens_to_remove
|
417 |
|
418 |
-
for model in
|
419 |
if model not in self.token_model_map:
|
420 |
continue
|
421 |
|
@@ -423,13 +477,14 @@ class AuthTokenManager:
|
|
423 |
if not token_entry.get("StartCallTime"):
|
424 |
continue
|
425 |
|
426 |
-
expiration_time =
|
427 |
if now - token_entry["StartCallTime"] >= expiration_time:
|
428 |
sso = token_entry["token"].split("sso=")[1].split(";")[0]
|
429 |
if sso in self.token_status_map and model in self.token_status_map[sso]:
|
430 |
self.token_status_map[sso][model]["isValid"] = True
|
431 |
self.token_status_map[sso][model]["invalidatedTime"] = None
|
432 |
self.token_status_map[sso][model]["totalRequestCount"] = 0
|
|
|
433 |
|
434 |
token_entry["RequestCount"] = 0
|
435 |
token_entry["StartCallTime"] = None
|
@@ -632,14 +687,14 @@ class GrokApiClient:
|
|
632 |
# logger.error(str(error), "Server")
|
633 |
# raise ValueError(error)
|
634 |
def prepare_chat_request(self, request):
|
635 |
-
if ((request["model"] == 'grok-
|
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-
|
643 |
last_message = todo_messages[-1]
|
644 |
if last_message["role"] != 'user':
|
645 |
raise ValueError('此模型最后一条消息必须是用户消息!')
|
@@ -651,7 +706,7 @@ class GrokApiClient:
|
|
651 |
message_length = 0
|
652 |
convert_to_file = False
|
653 |
last_message_content = ''
|
654 |
-
search = request["model"] in ['grok-
|
655 |
deepsearchPreset = ''
|
656 |
if request["model"] == 'grok-3-deepsearch':
|
657 |
deepsearchPreset = 'default'
|
@@ -743,7 +798,7 @@ class GrokApiClient:
|
|
743 |
"imageGenerationCount": 1,
|
744 |
"forceConcise": False,
|
745 |
"toolOverrides": {
|
746 |
-
"imageGen": request["model"] in ['grok-
|
747 |
"webSearch": search,
|
748 |
"xSearch": search,
|
749 |
"xMediaSearch": search,
|
@@ -800,17 +855,14 @@ def process_model_response(response, model):
|
|
800 |
if response.get("cachedImageGenerationResponse") and not CONFIG["IS_IMG_GEN2"]:
|
801 |
result["imageUrl"] = response["cachedImageGenerationResponse"]["imageUrl"]
|
802 |
return result
|
803 |
-
|
804 |
-
if model == 'grok-2':
|
805 |
result["token"] = response.get("token")
|
806 |
-
elif model in ['grok-
|
807 |
if response.get("webSearchResults") and CONFIG["ISSHOW_SEARCH_RESULTS"]:
|
808 |
result["token"] = f"\r\n<think>{Utils.organize_search_results(response['webSearchResults'])}</think>\r\n"
|
809 |
else:
|
810 |
result["token"] = response.get("token")
|
811 |
-
elif model
|
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"]:
|
@@ -838,6 +890,37 @@ def process_model_response(response, model):
|
|
838 |
else:
|
839 |
result["token"] = response.get("token")
|
840 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
841 |
return result
|
842 |
|
843 |
def handle_image_response(image_url):
|
@@ -1022,20 +1105,36 @@ def handle_stream_response(response, model):
|
|
1022 |
|
1023 |
def initialization():
|
1024 |
sso_array = os.environ.get("SSO", "").split(',')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1025 |
logger.info("开始加载令牌", "Server")
|
1026 |
token_manager.load_token_status()
|
1027 |
-
for
|
1028 |
-
if
|
1029 |
-
token_manager.add_token(
|
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(
|
|
|
1034 |
|
1035 |
if CONFIG["API"]["PROXY"]:
|
1036 |
logger.info(f"代理已设置: {CONFIG['API']['PROXY']}", "Server")
|
1037 |
|
1038 |
-
logger.info("初始化完成", "Server")
|
1039 |
|
1040 |
|
1041 |
app = Flask(__name__)
|
@@ -1079,7 +1178,7 @@ def add_manager_token():
|
|
1079 |
sso = request.json.get('sso')
|
1080 |
if not sso:
|
1081 |
return jsonify({"error": "SSO token is required"}), 400
|
1082 |
-
token_manager.add_token(f"sso-rw={sso};sso={sso}")
|
1083 |
return jsonify({"success": True})
|
1084 |
except Exception as e:
|
1085 |
return jsonify({"error": str(e)}), 500
|
@@ -1130,7 +1229,7 @@ def add_token():
|
|
1130 |
|
1131 |
try:
|
1132 |
sso = request.json.get('sso')
|
1133 |
-
token_manager.add_token(f"sso-rw={sso};sso={sso}")
|
1134 |
return jsonify(token_manager.get_token_status_map().get(sso, {})), 200
|
1135 |
except Exception as error:
|
1136 |
logger.error(str(error), "Server")
|
@@ -1202,6 +1301,7 @@ def chat_completions():
|
|
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"]:
|
|
|
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",
|
|
|
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 |
+
|
134 |
DEFAULT_HEADERS = {
|
135 |
'Accept': '*/*',
|
136 |
'Accept-Language': 'zh-CN,zh;q=0.9',
|
|
|
139 |
'Connection': 'keep-alive',
|
140 |
'Origin': 'https://grok.com',
|
141 |
'Priority': 'u=1, i',
|
142 |
+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
|
143 |
+
'Sec-Ch-Ua': '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"',
|
144 |
'Sec-Ch-Ua-Mobile': '?0',
|
145 |
+
'Sec-Ch-Ua-Platform': '"macOS"',
|
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:
|
|
|
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):
|
|
|
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"]
|
|
|
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
|
|
|
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'
|
|
|
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,
|
|
|
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"]:
|
|
|
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):
|
|
|
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__)
|
|
|
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"]:
|