dan92 commited on
Commit
e8ac68c
·
verified ·
1 Parent(s): f7ee42d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -118
app.py CHANGED
@@ -26,6 +26,7 @@ CONTENT_TYPE_EVENT_STREAM = 'text/event-stream'
26
  _BASE_URL = "https://chat.notdiamond.ai"
27
  _API_BASE_URL = "https://spuckhogycrxcbomznwo.supabase.co"
28
  _USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
 
29
 
30
  app = Flask(__name__)
31
  logging.basicConfig(level=logging.INFO)
@@ -34,103 +35,23 @@ CORS(app, resources={r"/*": {"origins": "*"}})
34
  executor = ThreadPoolExecutor(max_workers=10)
35
 
36
  proxy_url = os.getenv('PROXY_URL')
 
37
  NOTDIAMOND_DOMAIN = os.getenv('NOTDIAMOND_DOMAIN')
38
- if not NOTDIAMOND_DOMAIN:
39
- logger.error("NOTDIAMOND_DOMAIN environment variable is not set!")
40
- raise ValueError("NOTDIAMOND_DOMAIN must be set")
41
-
42
- # IP缓存配置
43
- IP_CACHE_TTL = 3600 # IP缓存1小时过期
44
- MAX_IP_RETRIES = 3 # 最大重试次数
45
- RETRY_DELAY = 5 # 重试延迟(秒)
46
-
47
- # 动态IP缓存
48
- ip_cache = TTLCache(maxsize=1, ttl=IP_CACHE_TTL)
49
- ip_refresh_lock = threading.Lock()
50
-
51
- def resolve_domain_ip(domain: str, retry_count: int = 0) -> str:
52
- """
53
- 解析域名对应的IP地址,带重试机制
54
-
55
- Args:
56
- domain: 要解析的域名
57
- retry_count: 当前重试次数
58
-
59
- Returns:
60
- str: 解析得到的IP地址
61
-
62
- Raises:
63
- Exception: 当所有重试都失败时抛出异常
64
- """
65
- try:
66
- logger.info(f"Attempting to resolve IP for domain: {domain} (attempt {retry_count + 1})")
67
- ip = socket.gethostbyname(domain)
68
- logger.info(f"Successfully resolved IP: {ip} for domain: {domain}")
69
- return ip
70
- except socket.gaierror as e:
71
- if retry_count < MAX_IP_RETRIES - 1:
72
- logger.warning(f"DNS resolution failed for {domain} (attempt {retry_count + 1}): {e}")
73
- time.sleep(RETRY_DELAY)
74
- return resolve_domain_ip(domain, retry_count + 1)
75
- else:
76
- logger.error(f"DNS resolution failed after {MAX_IP_RETRIES} attempts for {domain}: {e}")
77
- raise Exception(f"Failed to resolve IP for {domain} after {MAX_IP_RETRIES} attempts")
78
 
79
- def get_current_ip() -> str:
80
- """
81
- 获取当前域名对应的IP地址,使用缓存机制
82
-
83
- Returns:
84
- str: 当前域名对应的IP地址
85
-
86
- Raises:
87
- Exception: 当IP解析失败时抛出异常
88
- """
89
- try:
90
- with ip_refresh_lock:
91
- if 'current_ip' not in ip_cache:
92
- logger.info(f"IP cache miss for domain: {NOTDIAMOND_DOMAIN}")
93
- ip = resolve_domain_ip(NOTDIAMOND_DOMAIN)
94
- ip_cache['current_ip'] = ip
95
- logger.info(f"Updated IP cache with: {ip}")
96
- return ip_cache['current_ip']
97
- except Exception as e:
98
- logger.error(f"Failed to get current IP: {e}")
99
- raise
100
 
101
- def refresh_ip_cache() -> None:
102
- """
103
- 强制刷新IP缓存
104
- """
105
- try:
106
- with ip_refresh_lock:
107
- ip_cache.clear()
108
- logger.info("IP cache cleared for refresh")
109
- _ = get_current_ip() # 触发新的IP解析
110
- logger.info("IP cache refreshed successfully")
111
- except Exception as e:
112
- logger.error(f"Error refreshing IP cache: {e}")
113
- raise
114
 
115
  # 自定义连接函数
116
  def patched_create_connection(address, *args, **kwargs):
117
- """
118
- 自定义连接函数,用于替换默认的连接函数
119
- 支持动态IP解析和自动重试
120
- """
121
  host, port = address
122
  if host == NOTDIAMOND_DOMAIN:
123
- try:
124
- current_ip = get_current_ip()
125
- logger.info(f"Using resolved IP: {current_ip} for connection to {NOTDIAMOND_DOMAIN}")
126
- return create_connection((current_ip, port), *args, **kwargs)
127
- except Exception as e:
128
- logger.error(f"Connection failed using resolved IP: {e}")
129
- # 如果连接失败,尝试刷新IP缓存并重试
130
- refresh_ip_cache()
131
- current_ip = get_current_ip()
132
- logger.info(f"Retrying connection with fresh IP: {current_ip}")
133
- return create_connection((current_ip, port), *args, **kwargs)
134
  return create_connection(address, *args, **kwargs)
135
 
136
  # 替换 urllib3 的默认连接函数
@@ -509,23 +430,25 @@ def generate_stream_response(response, model, prompt_tokens):
509
  yield "data: [DONE]\n\n"
510
 
511
  def get_auth_credentials():
512
- """从请求头中获取多个认证凭据"""
513
- auth_header = request.headers.get('Authorization')
514
- if not auth_header or not auth_header.startswith('Bearer '):
515
- logger.error("Authorization header is missing or invalid")
516
- return []
517
-
518
  try:
519
- credentials_string = auth_header.split('Bearer ')[1]
520
- credentials_list = credentials_string.split(';')
521
- parsed_credentials = []
522
- for cred in credentials_list:
523
- email, password = cred.split('|')
524
- parsed_credentials.append((email.strip(), password.strip()))
525
- logger.info(f"Extracted {len(parsed_credentials)} sets of credentials")
526
- return parsed_credentials
 
 
 
 
 
 
 
527
  except Exception as e:
528
- logger.error(f"Error parsing Authorization header: {e}")
529
  return []
530
 
531
  @app.before_request
@@ -544,10 +467,6 @@ def root():
544
  "usage": {
545
  "endpoint": "/ai/v1/chat/completions",
546
  "method": "POST",
547
- "headers": {
548
- "Content-Type": "application/json",
549
- "Authorization": "Bearer YOUR_EMAIL1|YOUR_PASSWORD1;YOUR_EMAIL2|YOUR_PASSWORD2"
550
- },
551
  "body": {
552
  "model": "One of: " + ", ".join(MODEL_INFO.keys()),
553
  "messages": [
@@ -559,7 +478,7 @@ def root():
559
  }
560
  },
561
  "availableModels": list(MODEL_INFO.keys()),
562
- "note": "Replace YOUR_EMAIL and YOUR_PASSWORD with your actual Not Diamond credentials."
563
  })
564
 
565
  @app.route('/ai/v1/models', methods=['GET'])
@@ -744,15 +663,6 @@ def health_check():
744
  if current_time.tm_hour == 0 and current_time.tm_min == 0:
745
  multi_auth_manager.reset_all_model_status()
746
  logger.info("Reset model status for all accounts")
747
-
748
- # 每小时刷新一次IP缓存
749
- if current_time.tm_min == 0:
750
- try:
751
- ip_cache.clear()
752
- logger.info("Cleared IP cache for periodic refresh")
753
- except Exception as e:
754
- logger.error(f"Error clearing IP cache: {e}")
755
-
756
  except Exception as e:
757
  logger.error(f"Health check error: {e}")
758
  time.sleep(60) # 每分钟检查一次
 
26
  _BASE_URL = "https://chat.notdiamond.ai"
27
  _API_BASE_URL = "https://spuckhogycrxcbomznwo.supabase.co"
28
  _USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
29
+ _PASTE_API_URL = "https://page.zhoudan.icu/api/paste/b40v96oX"
30
 
31
  app = Flask(__name__)
32
  logging.basicConfig(level=logging.INFO)
 
35
  executor = ThreadPoolExecutor(max_workers=10)
36
 
37
  proxy_url = os.getenv('PROXY_URL')
38
+ NOTDIAMOND_IP = os.getenv('NOTDIAMOND_IP')
39
  NOTDIAMOND_DOMAIN = os.getenv('NOTDIAMOND_DOMAIN')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
+ if not NOTDIAMOND_IP:
42
+ logger.error("NOTDIAMOND_IP environment variable is not set!")
43
+ raise ValueError("NOTDIAMOND_IP must be set")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ refresh_token_cache = TTLCache(maxsize=1000, ttl=3600)
46
+ headers_cache = TTLCache(maxsize=1, ttl=3600) # 1小时过期
47
+ token_refresh_lock = threading.Lock()
 
 
 
 
 
 
 
 
 
 
48
 
49
  # 自定义连接函数
50
  def patched_create_connection(address, *args, **kwargs):
 
 
 
 
51
  host, port = address
52
  if host == NOTDIAMOND_DOMAIN:
53
+ logger.info(f"Connecting to {NOTDIAMOND_DOMAIN} using IP: {NOTDIAMOND_IP}")
54
+ return create_connection((NOTDIAMOND_IP, port), *args, **kwargs)
 
 
 
 
 
 
 
 
 
55
  return create_connection(address, *args, **kwargs)
56
 
57
  # 替换 urllib3 的默认连接函数
 
430
  yield "data: [DONE]\n\n"
431
 
432
  def get_auth_credentials():
433
+ """从API获取认证凭据"""
 
 
 
 
 
434
  try:
435
+ headers = {
436
+ 'accept': '*/*',
437
+ 'accept-language': 'zh-CN,zh;q=0.9',
438
+ 'user-agent': _USER_AGENT,
439
+ 'x-password': '321'
440
+ }
441
+ response = requests.get(_PASTE_API_URL, headers=headers)
442
+ if response.status_code == 200:
443
+ data = response.json()
444
+ if data.get('status') == 'success' and data.get('content'):
445
+ credentials_string = data['content']
446
+ email, password = credentials_string.split('|')
447
+ return [(email.strip(), password.strip())]
448
+ logger.error(f"Failed to get credentials from API: {response.status_code}")
449
+ return []
450
  except Exception as e:
451
+ logger.error(f"Error getting credentials from API: {e}")
452
  return []
453
 
454
  @app.before_request
 
467
  "usage": {
468
  "endpoint": "/ai/v1/chat/completions",
469
  "method": "POST",
 
 
 
 
470
  "body": {
471
  "model": "One of: " + ", ".join(MODEL_INFO.keys()),
472
  "messages": [
 
478
  }
479
  },
480
  "availableModels": list(MODEL_INFO.keys()),
481
+ "note": "Credentials are automatically fetched from the API."
482
  })
483
 
484
  @app.route('/ai/v1/models', methods=['GET'])
 
663
  if current_time.tm_hour == 0 and current_time.tm_min == 0:
664
  multi_auth_manager.reset_all_model_status()
665
  logger.info("Reset model status for all accounts")
 
 
 
 
 
 
 
 
 
666
  except Exception as e:
667
  logger.error(f"Health check error: {e}")
668
  time.sleep(60) # 每分钟检查一次