dan92 commited on
Commit
8ab6014
·
verified ·
1 Parent(s): 246ea36

Upload 6 files

Browse files
Files changed (4) hide show
  1. Dockerfile +26 -0
  2. README.md +3 -0
  3. app.py +85 -197
  4. requirements.txt +0 -1
Dockerfile ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ # 设置工作目录
4
+ WORKDIR /app
5
+
6
+ # 复制依赖文件
7
+ COPY requirements.txt .
8
+
9
+ # 安装 gunicorn 和其他依赖
10
+ RUN pip install --upgrade pip && \
11
+ pip install --no-cache-dir -r requirements.txt gunicorn
12
+
13
+ # 复制应用程序文件
14
+ COPY app.py .
15
+ COPY register_bot.py .
16
+
17
+ # 设置环境变量
18
+ ENV FLASK_APP=app.py
19
+ ENV FLASK_ENV=production
20
+ ENV PYTHONUNBUFFERED=1
21
+
22
+ # 暴露端口
23
+ EXPOSE 3000
24
+
25
+ # 使用 gunicorn 作为生产级 WSGI 服务器
26
+ CMD ["gunicorn", "--bind", "0.0.0.0:3000", "--workers", "4", "app:app"]
README.md CHANGED
@@ -9,3 +9,6 @@ license: apache-2.0
9
  app_port: 3000
10
  ---
11
 
 
 
 
 
9
  app_port: 3000
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
13
+
14
+ [email protected]|password123
app.py CHANGED
@@ -23,7 +23,6 @@ from datetime import datetime, timedelta
23
 
24
  # 新增导入
25
  import register_bot
26
- from proxy_pool import ProxyPool
27
 
28
  # Constants
29
  CHAT_COMPLETION_CHUNK = 'chat.completion.chunk'
@@ -129,28 +128,16 @@ 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
  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,7 +148,6 @@ class AuthManager:
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,39 +155,10 @@ class AuthManager:
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,55 +177,29 @@ class AuthManager:
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,6 +284,16 @@ class AuthManager:
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,9 +323,7 @@ class MultiAuthManager:
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,13 +337,12 @@ class MultiAuthManager:
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():
@@ -840,16 +778,11 @@ def build_payload(request_data, model_id):
840
 
841
  return payload
842
 
843
- # 在全局变量部分添加
844
- proxy_pool = ProxyPool()
845
-
846
- # 修改 make_request 函数
847
  def make_request(payload, auth_manager, model_id):
848
  """发送请求并处理可能的认证刷新和模型特定错误。"""
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
 
@@ -874,6 +807,7 @@ def make_request(payload, auth_manager, model_id):
874
  if not auth_manager:
875
  break
876
 
 
877
  if auth_manager._email in tried_accounts:
878
  continue
879
 
@@ -881,137 +815,91 @@ def make_request(payload, auth_manager, model_id):
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):
945
  logger.info("所有现有账号都已尝试,开始注册新账号")
946
  successful_accounts = register_bot.register_and_verify(5)
947
  if successful_accounts:
948
  credentials = [(account['email'], account['password']) for account in successful_accounts]
949
  multi_auth_manager = MultiAuthManager(credentials)
 
950
  return make_request(payload, None, model_id)
951
 
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__":
 
23
 
24
  # 新增导入
25
  import register_bot
 
26
 
27
  # Constants
28
  CHAT_COMPLETION_CHUNK = 'chat.completion.chunk'
 
128
  self._session: requests.Session = create_custom_session()
129
  self._logger: logging.Logger = logging.getLogger(__name__)
130
  self.model_status = {model: True for model in MODEL_INFO.keys()}
131
+ # 添加新的属性来跟踪认证请求
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
 
137
  def _should_attempt_auth(self) -> bool:
138
  """检查是否应该尝试认证请求"""
139
  current_time = time.time()
140
 
 
 
 
 
 
 
 
 
 
 
141
  # 检查是否在退避期内
142
  if current_time - self._last_auth_attempt < self._backoff_delay:
143
  return False
 
148
  self._auth_window_start = current_time
149
  self._auth_attempts = 0
150
  self._backoff_delay = AUTH_RETRY_DELAY
 
151
 
152
  # 检查请求数量
153
  if self._auth_attempts >= AUTH_MAX_REQUESTS:
 
155
 
156
  return True
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  def login(self) -> bool:
159
+ """改进的登录方法,包含速率限制和退避机制"""
160
  if not self._should_attempt_auth():
161
+ logger.warning(f"Rate limit reached for {self._email}, waiting {self._backoff_delay}s")
162
  return False
163
 
164
  try:
 
177
 
178
  if response.status_code == 429:
179
  self._backoff_delay *= AUTH_BACKOFF_FACTOR
 
 
180
  logger.warning(f"Rate limit hit, increasing backoff to {self._backoff_delay}s")
181
  return False
182
 
183
+ response.raise_for_status()
 
 
 
 
 
 
 
184
  self._user_info = response.json()
185
  self._refresh_token = self._user_info.get('refresh_token', '')
186
  self._access_token = self._user_info.get('access_token', '')
187
  self._token_expiry = time.time() + self._user_info.get('expires_in', 3600)
188
 
189
+ # 重置退避延迟
 
190
  self._backoff_delay = AUTH_RETRY_DELAY
191
  self._log_values()
192
  return True
193
 
194
  except requests.RequestException as e:
195
  logger.error(f"\033[91m登录请求错误: {e}\033[0m")
 
 
196
  self._backoff_delay *= AUTH_BACKOFF_FACTOR
197
  return False
198
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  def refresh_user_token(self) -> bool:
 
200
  url = f"{_API_BASE_URL}/auth/v1/token?grant_type=refresh_token"
201
  headers = self._get_headers(with_content_type=True)
202
  data = {"refresh_token": self._refresh_token}
 
203
  try:
204
  response = self._make_request('POST', url, headers=headers, json=data)
205
  self._user_info = response.json()
 
284
  headers['Authorization'] = f'Bearer {self._access_token}'
285
  return headers
286
 
287
+ def _make_request(self, method: str, url: str, **kwargs) -> requests.Response:
288
+ """发送HTTP请求并处理异常。"""
289
+ try:
290
+ response = self._session.request(method, url, **kwargs)
291
+ response.raise_for_status()
292
+ return response
293
+ except requests.RequestException as e:
294
+ self._logger.error(f"请求错误 ({method} {url}): {e}")
295
+ raise
296
+
297
  def is_model_available(self, model):
298
  return self.model_status.get(model, True)
299
 
 
323
  start_index = self.current_index
324
  for _ in range(len(self.auth_managers)):
325
  auth_manager = self.auth_managers[self.current_index]
326
+ if auth_manager.is_model_available(model) and auth_manager._should_attempt_auth():
 
 
327
  return auth_manager
328
  self.current_index = (self.current_index + 1) % len(self.auth_managers)
329
  if self.current_index == start_index:
 
337
  return auth_manager
338
  return None
339
 
340
+ def reset_all_model_status(self):
 
341
  for auth_manager in self.auth_managers:
342
+ auth_manager.reset_model_status()
343
 
344
  def require_auth(func: Callable) -> Callable:
345
+ """装饰器,确保在调用API之前有有效的token。"""
346
  @wraps(func)
347
  def wrapper(self, *args, **kwargs):
348
  if not self.ensure_valid_token():
 
778
 
779
  return payload
780
 
 
 
 
 
781
  def make_request(payload, auth_manager, model_id):
782
  """发送请求并处理可能的认证刷新和模型特定错误。"""
783
  global multi_auth_manager
784
  max_retries = 3
785
  retry_delay = 1
 
786
 
787
  logger.info(f"尝试发送请求,模型:{model_id}")
788
 
 
807
  if not auth_manager:
808
  break
809
 
810
+ # 如果这个账号已经尝试过,继续下一个
811
  if auth_manager._email in tried_accounts:
812
  continue
813
 
 
815
  logger.info(f"尝试使用账号 {auth_manager._email}")
816
 
817
  for attempt in range(max_retries):
818
+ try:
819
+ url = get_notdiamond_url()
820
+ headers = get_notdiamond_headers(auth_manager)
821
+ response = executor.submit(
822
+ requests.post,
823
+ url,
824
+ headers=headers,
825
+ json=payload,
826
+ stream=True
827
+ ).result()
828
+
829
+ if response.status_code == 200 and response.headers.get('Content-Type') == 'text/event-stream':
830
+ logger.info(f"请求成功,使用账号 {auth_manager._email}")
831
+ return response
832
+
833
+ headers_cache.clear()
834
+
835
+ if response.status_code == 401: # Unauthorized
836
+ logger.info(f"Token expired for account {auth_manager._email}, attempting refresh")
837
+ if auth_manager.ensure_valid_token():
838
  continue
839
+
840
+ if response.status_code == 403: # Forbidden, 模型使用限制
841
+ logger.warning(f"Model {model_id} usage limit reached for account {auth_manager._email}")
842
+ auth_manager.set_model_unavailable(model_id)
843
+ break # 跳出重试循环,尝试下一个账号
844
+
845
+ logger.error(f"Request failed with status {response.status_code} for account {auth_manager._email}")
846
+
847
+ except Exception as e:
848
+ logger.error(f"Request attempt {attempt + 1} failed for account {auth_manager._email}: {e}")
849
+ if attempt < max_retries - 1:
850
+ time.sleep(retry_delay)
851
+ continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
852
 
853
+ # 所有账号都尝试过且失败后,才进行注册
854
  if len(tried_accounts) == len(multi_auth_manager.auth_managers):
855
  logger.info("所有现有账号都已尝试,开始注册新账号")
856
  successful_accounts = register_bot.register_and_verify(5)
857
  if successful_accounts:
858
  credentials = [(account['email'], account['password']) for account in successful_accounts]
859
  multi_auth_manager = MultiAuthManager(credentials)
860
+ # 使用新注册的账号重试请求
861
  return make_request(payload, None, model_id)
862
 
863
  raise Exception("所有账号均不可用,且注册新账号失败")
864
 
865
  def health_check():
866
+ """改进的健康检查函数"""
867
+ last_check_time = {} # 用于跟踪每个账号的最后检查时间
 
 
868
 
869
+ while True:
870
+ try:
871
+ if multi_auth_manager:
872
+ current_time = time.time()
873
+
874
+ for auth_manager in multi_auth_manager.auth_managers:
875
+ email = auth_manager._email
876
 
877
+ # 检查是否需要进行健康检查
878
+ if email not in last_check_time or \
879
+ current_time - last_check_time[email] >= AUTH_CHECK_INTERVAL:
880
 
881
+ if not auth_manager._should_attempt_auth():
882
+ logger.info(f"Skipping health check for {email} due to rate limiting")
883
+ continue
884
 
885
+ if not auth_manager.ensure_valid_token():
886
+ logger.warning(f"Auth token validation failed during health check for {email}")
887
+ auth_manager.clear_auth()
888
+ else:
889
+ logger.info(f"Health check passed for {email}")
890
 
891
+ last_check_time[email] = current_time
892
+
893
+ # 每天重置所有账号的模型使用状态
894
+ current_time_local = time.localtime()
895
+ if current_time_local.tm_hour == 0 and current_time_local.tm_min == 0:
896
+ multi_auth_manager.reset_all_model_status()
897
+ logger.info("Reset model status for all accounts")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
898
 
899
+ except Exception as e:
900
+ logger.error(f"Health check error: {e}")
901
 
902
+ sleep(60) # 主循环每分钟运行一次
 
 
 
 
 
 
 
 
 
 
 
903
 
904
  # 为了兼容 Flask CLI 和 Gunicorn,修改启动逻辑
905
  if __name__ != "__main__":
requirements.txt CHANGED
@@ -8,4 +8,3 @@ urllib3==1.26.9
8
  beautifulsoup4==4.11.1
9
  Pillow==9.2.0
10
  lxml==4.9.1
11
- requests[socks]
 
8
  beautifulsoup4==4.11.1
9
  Pillow==9.2.0
10
  lxml==4.9.1