Spaces:
Paused
Paused
Upload 2 files
Browse files
app.py
CHANGED
|
@@ -129,16 +129,28 @@ class AuthManager:
|
|
| 129 |
self._session: requests.Session = create_custom_session()
|
| 130 |
self._logger: logging.Logger = logging.getLogger(__name__)
|
| 131 |
self.model_status = {model: True for model in MODEL_INFO.keys()}
|
| 132 |
-
# 添加新的属性来跟踪认证请求
|
| 133 |
self._last_auth_attempt = 0
|
| 134 |
self._auth_attempts = 0
|
| 135 |
self._auth_window_start = time.time()
|
| 136 |
self._backoff_delay = AUTH_RETRY_DELAY
|
|
|
|
|
|
|
|
|
|
| 137 |
|
| 138 |
def _should_attempt_auth(self) -> bool:
|
| 139 |
"""检查是否应该尝试认证请求"""
|
| 140 |
current_time = time.time()
|
| 141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
# 检查是否在退避期内
|
| 143 |
if current_time - self._last_auth_attempt < self._backoff_delay:
|
| 144 |
return False
|
|
@@ -149,6 +161,7 @@ class AuthManager:
|
|
| 149 |
self._auth_window_start = current_time
|
| 150 |
self._auth_attempts = 0
|
| 151 |
self._backoff_delay = AUTH_RETRY_DELAY
|
|
|
|
| 152 |
|
| 153 |
# 检查请求数量
|
| 154 |
if self._auth_attempts >= AUTH_MAX_REQUESTS:
|
|
@@ -156,10 +169,39 @@ class AuthManager:
|
|
| 156 |
|
| 157 |
return True
|
| 158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
def login(self) -> bool:
|
| 160 |
-
"""改进的登录方法,
|
| 161 |
if not self._should_attempt_auth():
|
| 162 |
-
logger.warning(f"Rate limit reached for {self._email}, waiting {self._backoff_delay}s")
|
| 163 |
return False
|
| 164 |
|
| 165 |
try:
|
|
@@ -178,29 +220,55 @@ class AuthManager:
|
|
| 178 |
|
| 179 |
if response.status_code == 429:
|
| 180 |
self._backoff_delay *= AUTH_BACKOFF_FACTOR
|
|
|
|
|
|
|
| 181 |
logger.warning(f"Rate limit hit, increasing backoff to {self._backoff_delay}s")
|
| 182 |
return False
|
| 183 |
|
| 184 |
-
response.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
self._user_info = response.json()
|
| 186 |
self._refresh_token = self._user_info.get('refresh_token', '')
|
| 187 |
self._access_token = self._user_info.get('access_token', '')
|
| 188 |
self._token_expiry = time.time() + self._user_info.get('expires_in', 3600)
|
| 189 |
|
| 190 |
-
# 重置
|
|
|
|
| 191 |
self._backoff_delay = AUTH_RETRY_DELAY
|
| 192 |
self._log_values()
|
| 193 |
return True
|
| 194 |
|
| 195 |
except requests.RequestException as e:
|
| 196 |
logger.error(f"\033[91m登录请求错误: {e}\033[0m")
|
|
|
|
|
|
|
| 197 |
self._backoff_delay *= AUTH_BACKOFF_FACTOR
|
| 198 |
return False
|
| 199 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
def refresh_user_token(self) -> bool:
|
|
|
|
| 201 |
url = f"{_API_BASE_URL}/auth/v1/token?grant_type=refresh_token"
|
| 202 |
headers = self._get_headers(with_content_type=True)
|
| 203 |
data = {"refresh_token": self._refresh_token}
|
|
|
|
| 204 |
try:
|
| 205 |
response = self._make_request('POST', url, headers=headers, json=data)
|
| 206 |
self._user_info = response.json()
|
|
@@ -285,16 +353,6 @@ class AuthManager:
|
|
| 285 |
headers['Authorization'] = f'Bearer {self._access_token}'
|
| 286 |
return headers
|
| 287 |
|
| 288 |
-
def _make_request(self, method: str, url: str, **kwargs) -> requests.Response:
|
| 289 |
-
"""发送HTTP请求并处理异常。"""
|
| 290 |
-
try:
|
| 291 |
-
response = self._session.request(method, url, **kwargs)
|
| 292 |
-
response.raise_for_status()
|
| 293 |
-
return response
|
| 294 |
-
except requests.RequestException as e:
|
| 295 |
-
self._logger.error(f"请求错误 ({method} {url}): {e}")
|
| 296 |
-
raise
|
| 297 |
-
|
| 298 |
def is_model_available(self, model):
|
| 299 |
return self.model_status.get(model, True)
|
| 300 |
|
|
@@ -324,7 +382,9 @@ class MultiAuthManager:
|
|
| 324 |
start_index = self.current_index
|
| 325 |
for _ in range(len(self.auth_managers)):
|
| 326 |
auth_manager = self.auth_managers[self.current_index]
|
| 327 |
-
if auth_manager.
|
|
|
|
|
|
|
| 328 |
return auth_manager
|
| 329 |
self.current_index = (self.current_index + 1) % len(self.auth_managers)
|
| 330 |
if self.current_index == start_index:
|
|
@@ -338,12 +398,13 @@ class MultiAuthManager:
|
|
| 338 |
return auth_manager
|
| 339 |
return None
|
| 340 |
|
| 341 |
-
def
|
|
|
|
| 342 |
for auth_manager in self.auth_managers:
|
| 343 |
-
auth_manager.
|
| 344 |
|
| 345 |
def require_auth(func: Callable) -> Callable:
|
| 346 |
-
"""
|
| 347 |
@wraps(func)
|
| 348 |
def wrapper(self, *args, **kwargs):
|
| 349 |
if not self.ensure_valid_token():
|
|
@@ -788,6 +849,7 @@ def make_request(payload, auth_manager, model_id):
|
|
| 788 |
global multi_auth_manager
|
| 789 |
max_retries = 3
|
| 790 |
retry_delay = 1
|
|
|
|
| 791 |
|
| 792 |
logger.info(f"尝试发送请求,模型:{model_id}")
|
| 793 |
|
|
@@ -819,53 +881,64 @@ def make_request(payload, auth_manager, model_id):
|
|
| 819 |
logger.info(f"尝试使用账号 {auth_manager._email}")
|
| 820 |
|
| 821 |
for attempt in range(max_retries):
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
-
|
| 828 |
-
|
| 829 |
-
|
| 830 |
-
|
| 831 |
-
|
| 832 |
-
headers=headers,
|
| 833 |
-
json=payload,
|
| 834 |
-
stream=True,
|
| 835 |
-
proxies=proxy if proxy else None,
|
| 836 |
-
timeout=30 # 添加超时设置
|
| 837 |
-
).result()
|
| 838 |
-
|
| 839 |
-
if response.status_code == 200 and response.headers.get('Content-Type') == 'text/event-stream':
|
| 840 |
-
logger.info(f"请求成功,使用账号 {auth_manager._email}")
|
| 841 |
-
return response
|
| 842 |
-
|
| 843 |
-
# 如果请求失败且使用了代理,移除该代理
|
| 844 |
-
if proxy:
|
| 845 |
-
proxy_pool.remove_proxy(proxy)
|
| 846 |
-
|
| 847 |
-
headers_cache.clear()
|
| 848 |
-
|
| 849 |
-
if response.status_code == 401:
|
| 850 |
-
logger.info(f"Token expired for account {auth_manager._email}, attempting refresh")
|
| 851 |
-
if auth_manager.ensure_valid_token():
|
| 852 |
continue
|
| 853 |
-
|
| 854 |
-
|
| 855 |
-
|
| 856 |
-
|
| 857 |
-
|
| 858 |
-
|
| 859 |
-
|
| 860 |
-
|
| 861 |
-
|
| 862 |
-
|
| 863 |
-
|
| 864 |
-
|
| 865 |
-
|
| 866 |
-
|
| 867 |
-
|
| 868 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 869 |
|
| 870 |
# 所有账号都尝试过且失败后,尝试注册新账号
|
| 871 |
if len(tried_accounts) == len(multi_auth_manager.auth_managers):
|
|
@@ -879,43 +952,66 @@ def make_request(payload, auth_manager, model_id):
|
|
| 879 |
raise Exception("所有账号均不可用,且注册新账号失败")
|
| 880 |
|
| 881 |
def health_check():
|
| 882 |
-
"""改进的健康检查函数"""
|
| 883 |
-
last_check_time = {}
|
|
|
|
|
|
|
| 884 |
|
| 885 |
-
|
| 886 |
-
|
| 887 |
-
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
email = auth_manager._email
|
| 892 |
|
| 893 |
-
|
| 894 |
-
|
| 895 |
-
current_time - last_check_time[email] >= AUTH_CHECK_INTERVAL:
|
| 896 |
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
|
| 904 |
-
else:
|
| 905 |
-
logger.info(f"Health check passed for {email}")
|
| 906 |
|
| 907 |
-
|
| 908 |
-
|
| 909 |
-
|
| 910 |
-
|
| 911 |
-
if current_time_local.tm_hour == 0 and current_time_local.tm_min == 0:
|
| 912 |
-
multi_auth_manager.reset_all_model_status()
|
| 913 |
-
logger.info("Reset model status for all accounts")
|
| 914 |
|
| 915 |
-
|
| 916 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 917 |
|
| 918 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 919 |
|
| 920 |
# 为了兼容 Flask CLI 和 Gunicorn,修改启动逻辑
|
| 921 |
if __name__ != "__main__":
|
|
|
|
| 129 |
self._session: requests.Session = create_custom_session()
|
| 130 |
self._logger: logging.Logger = logging.getLogger(__name__)
|
| 131 |
self.model_status = {model: True for model in MODEL_INFO.keys()}
|
|
|
|
| 132 |
self._last_auth_attempt = 0
|
| 133 |
self._auth_attempts = 0
|
| 134 |
self._auth_window_start = time.time()
|
| 135 |
self._backoff_delay = AUTH_RETRY_DELAY
|
| 136 |
+
self._failed_attempts = 0 # 添加失败尝试计数
|
| 137 |
+
self._last_failure_time = 0 # 添加最后失败时间
|
| 138 |
+
self._is_valid = True # 添加账号有效性标志
|
| 139 |
|
| 140 |
def _should_attempt_auth(self) -> bool:
|
| 141 |
"""检查是否应该尝试认证请求"""
|
| 142 |
current_time = time.time()
|
| 143 |
|
| 144 |
+
# 如果账号已被标记为无效,直接返回False
|
| 145 |
+
if not self._is_valid:
|
| 146 |
+
return False
|
| 147 |
+
|
| 148 |
+
# 如果连续失败次数过多,标记账号为无效
|
| 149 |
+
if self._failed_attempts >= 5:
|
| 150 |
+
self._is_valid = False
|
| 151 |
+
self._logger.warning(f"Account {self._email} marked as invalid due to too many failures")
|
| 152 |
+
return False
|
| 153 |
+
|
| 154 |
# 检查是否在退避期内
|
| 155 |
if current_time - self._last_auth_attempt < self._backoff_delay:
|
| 156 |
return False
|
|
|
|
| 161 |
self._auth_window_start = current_time
|
| 162 |
self._auth_attempts = 0
|
| 163 |
self._backoff_delay = AUTH_RETRY_DELAY
|
| 164 |
+
self._failed_attempts = 0 # 重置失败计数
|
| 165 |
|
| 166 |
# 检查请求数量
|
| 167 |
if self._auth_attempts >= AUTH_MAX_REQUESTS:
|
|
|
|
| 169 |
|
| 170 |
return True
|
| 171 |
|
| 172 |
+
def _make_request(self, method: str, url: str, **kwargs) -> requests.Response:
|
| 173 |
+
"""改进的请求方法,支持代理"""
|
| 174 |
+
global proxy_pool
|
| 175 |
+
max_retries = 3
|
| 176 |
+
|
| 177 |
+
for attempt in range(max_retries):
|
| 178 |
+
try:
|
| 179 |
+
# 获取代理
|
| 180 |
+
proxy = proxy_pool.get_proxy() if proxy_pool else None
|
| 181 |
+
|
| 182 |
+
if proxy:
|
| 183 |
+
kwargs['proxies'] = proxy
|
| 184 |
+
kwargs['timeout'] = 10 # 使用代理时设置较短的超时
|
| 185 |
+
|
| 186 |
+
response = self._session.request(method, url, **kwargs)
|
| 187 |
+
response.raise_for_status()
|
| 188 |
+
return response
|
| 189 |
+
|
| 190 |
+
except requests.RequestException as e:
|
| 191 |
+
if proxy:
|
| 192 |
+
proxy_pool.remove_proxy(proxy)
|
| 193 |
+
|
| 194 |
+
if attempt == max_retries - 1:
|
| 195 |
+
self._logger.error(f"请求错误 ({method} {url}): {e}")
|
| 196 |
+
raise
|
| 197 |
+
|
| 198 |
+
time.sleep(1) # 短暂等待后重试
|
| 199 |
+
|
| 200 |
+
raise requests.RequestException("Max retries exceeded")
|
| 201 |
+
|
| 202 |
def login(self) -> bool:
|
| 203 |
+
"""改进的登录方法,使用代理"""
|
| 204 |
if not self._should_attempt_auth():
|
|
|
|
| 205 |
return False
|
| 206 |
|
| 207 |
try:
|
|
|
|
| 220 |
|
| 221 |
if response.status_code == 429:
|
| 222 |
self._backoff_delay *= AUTH_BACKOFF_FACTOR
|
| 223 |
+
self._failed_attempts += 1
|
| 224 |
+
self._last_failure_time = time.time()
|
| 225 |
logger.warning(f"Rate limit hit, increasing backoff to {self._backoff_delay}s")
|
| 226 |
return False
|
| 227 |
|
| 228 |
+
if response.status_code == 400:
|
| 229 |
+
self._failed_attempts += 1
|
| 230 |
+
self._last_failure_time = time.time()
|
| 231 |
+
if self._failed_attempts >= 5:
|
| 232 |
+
self._is_valid = False
|
| 233 |
+
logger.error(f"Account {self._email} marked as invalid due to authentication failures")
|
| 234 |
+
return False
|
| 235 |
+
|
| 236 |
self._user_info = response.json()
|
| 237 |
self._refresh_token = self._user_info.get('refresh_token', '')
|
| 238 |
self._access_token = self._user_info.get('access_token', '')
|
| 239 |
self._token_expiry = time.time() + self._user_info.get('expires_in', 3600)
|
| 240 |
|
| 241 |
+
# 重置失败相关计数
|
| 242 |
+
self._failed_attempts = 0
|
| 243 |
self._backoff_delay = AUTH_RETRY_DELAY
|
| 244 |
self._log_values()
|
| 245 |
return True
|
| 246 |
|
| 247 |
except requests.RequestException as e:
|
| 248 |
logger.error(f"\033[91m登录请求错误: {e}\033[0m")
|
| 249 |
+
self._failed_attempts += 1
|
| 250 |
+
self._last_failure_time = time.time()
|
| 251 |
self._backoff_delay *= AUTH_BACKOFF_FACTOR
|
| 252 |
return False
|
| 253 |
|
| 254 |
+
def is_valid(self) -> bool:
|
| 255 |
+
"""检查账号是否有效"""
|
| 256 |
+
return self._is_valid
|
| 257 |
+
|
| 258 |
+
def reset_status(self) -> None:
|
| 259 |
+
"""重置账号状态"""
|
| 260 |
+
self._is_valid = True
|
| 261 |
+
self._failed_attempts = 0
|
| 262 |
+
self._backoff_delay = AUTH_RETRY_DELAY
|
| 263 |
+
self._auth_attempts = 0
|
| 264 |
+
self._auth_window_start = time.time()
|
| 265 |
+
|
| 266 |
def refresh_user_token(self) -> bool:
|
| 267 |
+
"""改进的令牌刷新方法,使用代理"""
|
| 268 |
url = f"{_API_BASE_URL}/auth/v1/token?grant_type=refresh_token"
|
| 269 |
headers = self._get_headers(with_content_type=True)
|
| 270 |
data = {"refresh_token": self._refresh_token}
|
| 271 |
+
|
| 272 |
try:
|
| 273 |
response = self._make_request('POST', url, headers=headers, json=data)
|
| 274 |
self._user_info = response.json()
|
|
|
|
| 353 |
headers['Authorization'] = f'Bearer {self._access_token}'
|
| 354 |
return headers
|
| 355 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 356 |
def is_model_available(self, model):
|
| 357 |
return self.model_status.get(model, True)
|
| 358 |
|
|
|
|
| 382 |
start_index = self.current_index
|
| 383 |
for _ in range(len(self.auth_managers)):
|
| 384 |
auth_manager = self.auth_managers[self.current_index]
|
| 385 |
+
if (auth_manager.is_valid() and
|
| 386 |
+
auth_manager.is_model_available(model) and
|
| 387 |
+
auth_manager._should_attempt_auth()):
|
| 388 |
return auth_manager
|
| 389 |
self.current_index = (self.current_index + 1) % len(self.auth_managers)
|
| 390 |
if self.current_index == start_index:
|
|
|
|
| 398 |
return auth_manager
|
| 399 |
return None
|
| 400 |
|
| 401 |
+
def reset_all_accounts(self):
|
| 402 |
+
"""重置所有账号状态"""
|
| 403 |
for auth_manager in self.auth_managers:
|
| 404 |
+
auth_manager.reset_status()
|
| 405 |
|
| 406 |
def require_auth(func: Callable) -> Callable:
|
| 407 |
+
"""饰器,确保在调用API之前有有效的token。"""
|
| 408 |
@wraps(func)
|
| 409 |
def wrapper(self, *args, **kwargs):
|
| 410 |
if not self.ensure_valid_token():
|
|
|
|
| 849 |
global multi_auth_manager
|
| 850 |
max_retries = 3
|
| 851 |
retry_delay = 1
|
| 852 |
+
proxy_retries = 2 # 每个账号最多尝试2次代理
|
| 853 |
|
| 854 |
logger.info(f"尝试发送请求,模型:{model_id}")
|
| 855 |
|
|
|
|
| 881 |
logger.info(f"尝试使用账号 {auth_manager._email}")
|
| 882 |
|
| 883 |
for attempt in range(max_retries):
|
| 884 |
+
for proxy_attempt in range(proxy_retries):
|
| 885 |
+
try:
|
| 886 |
+
url = get_notdiamond_url()
|
| 887 |
+
headers = get_notdiamond_headers(auth_manager)
|
| 888 |
+
|
| 889 |
+
# 获取代理
|
| 890 |
+
proxy = proxy_pool.get_proxy()
|
| 891 |
+
if not proxy and proxy_attempt == 0:
|
| 892 |
+
# 如果第一次获取代理失败,等待一下再试
|
| 893 |
+
time.sleep(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 894 |
continue
|
| 895 |
+
|
| 896 |
+
response = executor.submit(
|
| 897 |
+
requests.post,
|
| 898 |
+
url,
|
| 899 |
+
headers=headers,
|
| 900 |
+
json=payload,
|
| 901 |
+
stream=True,
|
| 902 |
+
proxies=proxy if proxy else None,
|
| 903 |
+
timeout=30
|
| 904 |
+
).result()
|
| 905 |
+
|
| 906 |
+
if response.status_code == 200 and response.headers.get('Content-Type') == 'text/event-stream':
|
| 907 |
+
logger.info(f"请求成功,使用账号 {auth_manager._email}")
|
| 908 |
+
return response
|
| 909 |
+
|
| 910 |
+
# 如果请求失败且使用了代理,移除该代理
|
| 911 |
+
if proxy:
|
| 912 |
+
proxy_pool.remove_proxy(proxy)
|
| 913 |
+
if proxy_attempt < proxy_retries - 1:
|
| 914 |
+
# 如果还有代理重试机会,继续下一次尝试
|
| 915 |
+
continue
|
| 916 |
+
|
| 917 |
+
headers_cache.clear()
|
| 918 |
+
|
| 919 |
+
if response.status_code == 401:
|
| 920 |
+
logger.info(f"Token expired for account {auth_manager._email}, attempting refresh")
|
| 921 |
+
if auth_manager.ensure_valid_token():
|
| 922 |
+
break # 跳出代理重试循环,使用新token重试
|
| 923 |
+
|
| 924 |
+
if response.status_code == 403:
|
| 925 |
+
logger.warning(f"Model {model_id} usage limit reached for account {auth_manager._email}")
|
| 926 |
+
auth_manager.set_model_unavailable(model_id)
|
| 927 |
+
break # 跳出代理重试循环,尝试下一个账号
|
| 928 |
+
|
| 929 |
+
logger.error(f"Request failed with status {response.status_code} for account {auth_manager._email}")
|
| 930 |
+
break # 跳出代理重试循环
|
| 931 |
+
|
| 932 |
+
except Exception as e:
|
| 933 |
+
logger.error(f"Request attempt {attempt + 1} failed for account {auth_manager._email}: {e}")
|
| 934 |
+
if proxy:
|
| 935 |
+
proxy_pool.remove_proxy(proxy)
|
| 936 |
+
if proxy_attempt < proxy_retries - 1:
|
| 937 |
+
continue
|
| 938 |
+
break # 跳出代理重试循环
|
| 939 |
+
|
| 940 |
+
if attempt < max_retries - 1:
|
| 941 |
+
time.sleep(retry_delay)
|
| 942 |
|
| 943 |
# 所有账号都尝试过且失败后,尝试注册新账号
|
| 944 |
if len(tried_accounts) == len(multi_auth_manager.auth_managers):
|
|
|
|
| 952 |
raise Exception("所有账号均不可用,且注册新账号失败")
|
| 953 |
|
| 954 |
def health_check():
|
| 955 |
+
"""改进的健康检查函数,使用线程池控制并发"""
|
| 956 |
+
last_check_time = {}
|
| 957 |
+
check_interval = 60 # 每个账号的检查间隔(秒)
|
| 958 |
+
max_concurrent_checks = 3 # 最大并发检查数量
|
| 959 |
|
| 960 |
+
with ThreadPoolExecutor(max_workers=max_concurrent_checks) as executor:
|
| 961 |
+
while True:
|
| 962 |
+
try:
|
| 963 |
+
if multi_auth_manager:
|
| 964 |
+
current_time = time.time()
|
| 965 |
+
check_futures = []
|
|
|
|
| 966 |
|
| 967 |
+
for auth_manager in multi_auth_manager.auth_managers:
|
| 968 |
+
email = auth_manager._email
|
|
|
|
| 969 |
|
| 970 |
+
# 检查是否需要进行健康检查
|
| 971 |
+
if email not in last_check_time or \
|
| 972 |
+
current_time - last_check_time[email] >= check_interval:
|
| 973 |
|
| 974 |
+
if not auth_manager._should_attempt_auth():
|
| 975 |
+
logger.info(f"Skipping health check for {email} due to rate limiting")
|
| 976 |
+
continue
|
|
|
|
|
|
|
| 977 |
|
| 978 |
+
# 提交健康检查任务
|
| 979 |
+
future = executor.submit(perform_health_check, auth_manager)
|
| 980 |
+
check_futures.append((email, future))
|
| 981 |
+
last_check_time[email] = current_time
|
|
|
|
|
|
|
|
|
|
| 982 |
|
| 983 |
+
# 等待所有检查完成
|
| 984 |
+
for email, future in check_futures:
|
| 985 |
+
try:
|
| 986 |
+
result = future.result(timeout=30)
|
| 987 |
+
if result:
|
| 988 |
+
logger.info(f"Health check passed for {email}")
|
| 989 |
+
else:
|
| 990 |
+
logger.warning(f"Health check failed for {email}")
|
| 991 |
+
except Exception as e:
|
| 992 |
+
logger.error(f"Health check error for {email}: {e}")
|
| 993 |
+
|
| 994 |
+
# 每天重置所有账号的模型使用状态
|
| 995 |
+
current_time_local = time.localtime()
|
| 996 |
+
if current_time_local.tm_hour == 0 and current_time_local.tm_min == 0:
|
| 997 |
+
multi_auth_manager.reset_all_accounts()
|
| 998 |
+
logger.info("Reset model status for all accounts")
|
| 999 |
+
|
| 1000 |
+
except Exception as e:
|
| 1001 |
+
logger.error(f"Health check error: {e}")
|
| 1002 |
|
| 1003 |
+
time.sleep(10) # 主循环每10秒运行一次
|
| 1004 |
+
|
| 1005 |
+
def perform_health_check(auth_manager):
|
| 1006 |
+
"""执行单个账号的健康检查"""
|
| 1007 |
+
try:
|
| 1008 |
+
if auth_manager.ensure_valid_token():
|
| 1009 |
+
return True
|
| 1010 |
+
auth_manager.clear_auth()
|
| 1011 |
+
return False
|
| 1012 |
+
except Exception as e:
|
| 1013 |
+
logger.error(f"Health check error for {auth_manager._email}: {e}")
|
| 1014 |
+
return False
|
| 1015 |
|
| 1016 |
# 为了兼容 Flask CLI 和 Gunicorn,修改启动逻辑
|
| 1017 |
if __name__ != "__main__":
|