prxyasd commited on
Commit
ca7d586
Β·
verified Β·
1 Parent(s): ee6b440

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -62
app.py CHANGED
@@ -36,8 +36,6 @@ from api_usage import (
36
  # ─────────────────────────────────────────
37
  def get_key_oai_info(key: str) -> Dict[str, Any]:
38
  session = requests.Session()
39
- # raw_status_codeλŠ” HTTP 응닡 μ½”λ“œ λ˜λŠ” μœ μ‚¬ν•œ μƒνƒœ ν‘œμ‹œμž
40
- # org_data_or_errorλŠ” 성곡 μ‹œ 데이터, μ‹€νŒ¨ μ‹œ μ—λŸ¬ 정보 λ“±
41
  raw_status_code, org_data_or_error = check_key_availability(session, key)
42
 
43
  info_dict = {
@@ -85,8 +83,6 @@ def get_key_oai_info(key: str) -> Dict[str, Any]:
85
  info_dict["quota"] = current_quota_message
86
  if "insufficient_quota" not in current_quota_message.lower(): # 상세 λ©”μ‹œμ§€μ— insufficient_quotaκ°€ μ—†λ‹€λ©΄ μƒνƒœ λ©”μ‹œμ§€μ— μΆ”κ°€
87
  info_dict["status_message"] += f" Error: {current_quota_message}"
88
- # μ—¬κΈ°μ„œ λ°˜ν™˜ν•˜λ©΄ μ•„λž˜ ꡬ독 정보 확인을 κ±΄λ„ˆλ›°μ§€λ§Œ, has_sufficient_quotaκ°€ 이미 Falseμž„
89
- # return info_dict # ν•„μš”μ— 따라 주석 ν•΄μ œν•˜μ—¬ 더 λΉ λ₯Έ λ°˜ν™˜ κ°€λŠ₯
90
  else: # 기타 μ—λŸ¬
91
  info_dict["status_message"] = f"Key check failed (status: {raw_status_code})."
92
  if isinstance(org_data_or_error, dict) and "error" in org_data_or_error:
@@ -97,10 +93,11 @@ def get_key_oai_info(key: str) -> Dict[str, Any]:
97
  return info_dict
98
 
99
  if not info_dict["key_availability"]:
100
- return info_dict # ν‚€κ°€ μœ νš¨ν•˜μ§€ μ•ŠμœΌλ©΄ 더 이상 μ§„ν–‰ μ•ˆ 함
 
 
101
 
102
- # org_data_for_subscription이 μ€€λΉ„λ˜μ§€ μ•Šμ€ 경우 (예: 초기 200μ΄μ—ˆμ§€λ§Œ org_dataκ°€ λΆ€μ μ ˆ)
103
- if not org_data_for_subscription:
104
  status_me, orgs_me_data = get_orgs_me(session, key)
105
  if status_me == 200:
106
  org_data_for_subscription = orgs_me_data
@@ -110,6 +107,12 @@ def get_key_oai_info(key: str) -> Dict[str, Any]:
110
  info_dict["has_sufficient_quota"] = False
111
  return info_dict
112
 
 
 
 
 
 
 
113
  subscription_info = get_subscription(key, session, org_data_for_subscription)
114
  if subscription_info:
115
  info_dict.update(
@@ -122,7 +125,7 @@ def get_key_oai_info(key: str) -> Dict[str, Any]:
122
  "models": subscription_info.get("models", ""),
123
  "requests_per_minute": subscription_info.get("rpm", ""),
124
  "tokens_per_minute": subscription_info.get("tpm", ""),
125
- "quota": subscription_info.get("quota", info_dict["quota"]),
126
  "all_models": subscription_info.get("all_models", ""),
127
  }
128
  )
@@ -140,20 +143,32 @@ def get_key_oai_info(key: str) -> Dict[str, Any]:
140
  ("billing" in err_msg and "issue" in err_msg):
141
  info_dict["has_sufficient_quota"] = False
142
  new_quota_message = f"Insufficient: {error_info.get('message', err_type)}"
143
- info_dict["quota"] = new_quota_message # μΏΌν„° ν•„λ“œμ— λͺ…μ‹œμ  λ©”μ‹œμ§€
144
- info_dict["status_message"] = (info_dict["status_message"] + f" Quota/Billing issue: {error_info.get('message', err_type)}").strip()
 
 
 
145
 
146
- # 계정 λΉ„ν™œμ„±ν™” λ“± 확인
147
  if "account_deactivated" in str(subscription_info).lower() or \
148
  "payment_failed" in str(subscription_info).lower():
149
  info_dict["has_sufficient_quota"] = False
150
- if "Account issue" not in info_dict["status_message"]: # 쀑볡 λ©”μ‹œμ§€ λ°©μ§€
151
- info_dict["status_message"] = (info_dict["status_message"] + " Account issue (e.g., deactivated, payment failed).").strip()
 
 
152
  else:
153
- info_dict["status_message"] = (info_dict["status_message"] + " Failed to retrieve full subscription details.").strip()
154
- info_dict["has_sufficient_quota"] = False
155
- # ꡬ독 정보 μ—†μœΌλ©΄ key_availability도 False둜 κ°„μ£Όν•  수 있음.
156
- # info_dict["key_availability"] = False # 주석 μ²˜λ¦¬ν•˜μ—¬ ν‚€ μžμ²΄λŠ” μœ νš¨ν•  수 μžˆμŒμ„ 남김
 
 
 
 
 
 
 
 
157
 
158
  return info_dict
159
 
@@ -448,40 +463,28 @@ def not_supported(key: str) -> Dict[str, Any]:
448
  # 단일 ν‚€ 비동기 처리 (μ—…λ°μ΄νŠΈλ¨)
449
  # ─────────────────────────────────────────
450
  async def process_single_key(key: str, rate_limit: bool, claude_model: str) -> Dict[str, Any]:
451
- """μ£Όμ–΄μ§„ key ν•˜λ‚˜λ₯Ό 뢄석해 정보 dict λ°˜ν™˜. Gemini ν‚€μ˜ μž‘λ™ μ—¬λΆ€ ν”Œλž˜κ·Έ 포함."""
452
  _key = key.strip()
453
 
454
  if not _key:
455
  return {"key": "", "key_type": "Empty", "key_availability": False}
456
 
457
- # OpenRouter
458
  if re.match(re.compile(r"sk-or-v1-[a-z0-9]{64}"), _key):
459
  result = get_key_openrouter_info(_key)
460
  return {"key": _key, **result}
461
-
462
- # Anthropic Claude
463
  if re.match(re.compile(r"sk-ant-api03-[a-zA-Z0-9\-_]{93}AA"), _key) or \
464
  (_key.startswith("sk-ant-") and len(_key) == 93) or \
465
  (len(_key) == 89 and re.match(re.compile(r"sk-[a-zA-Z0-9]{86}"), _key)):
466
  result = await get_key_ant_info(_key, rate_limit, claude_model)
467
  return {"key": _key, **result}
468
-
469
- # Stability
470
  if re.match(re.compile(r"sk-[a-zA-Z0-9]{48}"), _key) and len(_key) == 51 and "T3BlbkFJ" not in _key:
471
  result = get_key_stability_info(_key)
472
  return {"key": _key, **result}
473
-
474
- # Deepseek
475
  if re.match(re.compile(r"sk-[a-f0-9]{32}"), _key):
476
  result = get_key_deepseek_info(_key)
477
  return {"key": _key, **result}
478
-
479
- # OpenAI (λ‹€λ₯Έ sk- νŒ¨ν„΄λ³΄λ‹€ 뒀에 와야 함)
480
  if _key.startswith("sk-"):
481
- result = get_key_oai_info(_key) # μˆ˜μ •λœ ν•¨μˆ˜ 호좜
482
  return {"key": _key, **result}
483
-
484
- # Google Gemini 처리
485
  if _key.startswith("AIzaSy"):
486
  gemini_info = get_key_gemini_info(_key)
487
  is_working = gemini_info.get("key_availability") and gemini_info.get("status") == "Working"
@@ -491,23 +494,15 @@ async def process_single_key(key: str, rate_limit: bool, claude_model: str) -> D
491
  "is_gemini_working": is_working
492
  }
493
  return result
494
-
495
- # NovelAI
496
  if _key.startswith("pst-"):
497
  result = get_key_nai_info(_key)
498
  return {"key": _key, **result}
499
-
500
- # Replicate
501
  if (_key.startswith("r8_") and len(_key) == 40) or (_key.islower() and len(_key) == 40):
502
  result = get_key_replicate_info(_key)
503
  return {"key": _key, **result}
504
-
505
- # xAI
506
  if _key.startswith("xai-"):
507
  result = get_key_xai_info(_key)
508
  return {"key": _key, **result}
509
-
510
- # Azure endpoint: "name:key"
511
  if len(_key.split(":")) == 2:
512
  name, potential_key = _key.split(":", 1)
513
  if re.fullmatch(r'[a-fA-F0-9]{32}', potential_key) and "openai.azure.com" not in name:
@@ -515,48 +510,32 @@ async def process_single_key(key: str, rate_limit: bool, claude_model: str) -> D
515
  api_key = potential_key
516
  result = get_key_azure_info(endpoint, api_key)
517
  return {"key": _key, **result}
518
-
519
- # Azure endpoint: "https://xxx.openai.azure.com;key"
520
  if ";" in _key and "openai.azure.com" in _key.split(";")[0]:
521
  endpoint, api_key = _key.split(";", 1)
522
  result = get_key_azure_info(endpoint, api_key)
523
  return {"key": _key, **result}
524
-
525
- # AWS
526
  if _key.startswith("AKIA") and len(_key.split(":")[0]) == 20 and _key.split(":")[0].isalnum() and _key.split(":")[0].isupper() and len(_key.split(':')) == 2:
527
  result = await get_key_aws_info(_key)
528
  return {"key": _key, **result}
529
-
530
- # ElevenLabs
531
  if re.fullmatch(r"[a-f0-9]{32}", _key) or re.fullmatch(r"sk_[a-f0-9]{48}", _key):
532
  result = get_key_elevenlabs_info(_key)
533
  return {"key": _key, **result}
534
-
535
- # Mistral
536
  if re.fullmatch(r"[a-zA-Z0-9]{32}", _key) and not _key.startswith('sk-'):
537
  result = get_key_mistral_info(_key)
538
  return {"key": _key, **result}
539
-
540
- # Groq
541
  if re.match(re.compile(r"gsk_[a-zA-Z0-9]{20}WGdyb3FY[a-zA-Z0-9]{24}"), _key):
542
  result = get_key_groq_info(_key)
543
  return {"key": _key, **result}
544
-
545
- # GCP - refresh token
546
  if re.match(re.compile(r"[\w\-]+:[\w\-@\.]+:.+:.+"), _key):
547
  parts = _key.split(':')
548
  if len(parts) >= 4:
549
  result = await get_key_gcp_info(_key, 0)
550
  return {"key": _key, **result}
551
-
552
- # GCP - service account
553
  if re.match(re.compile(r"[\w\-]+:[\w\-@\.]+:.+\\n"), _key):
554
  parts = _key.split(':')
555
  if len(parts) >= 3:
556
  result = await get_key_gcp_info(_key, 1)
557
  return {"key": _key, **result}
558
-
559
- # Not supported
560
  result = not_supported(_key)
561
  return {"key": _key, **result}
562
 
@@ -565,10 +544,6 @@ async def process_single_key(key: str, rate_limit: bool, claude_model: str) -> D
565
  # μ—¬λŸ¬ key 비동기 처리 ν•¨μˆ˜ (μ—…λ°μ΄νŠΈλ¨)
566
  # ─────────────────────────────────────────
567
  async def sort_keys(text: str, rate_limit: bool, claude_model: str) -> Tuple[List[Dict[str, Any]], str, str, str]:
568
- """
569
- ν…μŠ€νŠΈ λ°•μŠ€μ— μž…λ ₯된 μ—¬λŸ¬ ν‚€λ₯Ό 쀄 λ‹¨μœ„λ‘œ λΆ„μ„ν•˜κ³ ,
570
- 전체 결과와 μž‘λ™ν•˜λŠ” OAI, Anthropic, Gemini ν‚€ λͺ©λ‘μ„ 각각 λ°˜ν™˜ν•©λ‹ˆλ‹€.
571
- """
572
  keys = [k.strip() for k in text.splitlines() if k.strip()]
573
  if not keys:
574
  return [], "", "", ""
@@ -587,15 +562,12 @@ async def sort_keys(text: str, rate_limit: bool, claude_model: str) -> Tuple[Lis
587
 
588
  key_type = result.get("key_type")
589
 
590
- # Gemini ν‚€ 필터링
591
  if result.get("is_gemini_working"):
592
  working_gemini_keys.append(key_value)
593
- # OpenAI ν‚€ 필터링 (μˆ˜μ •λ¨: has_sufficient_quota 확인)
594
  elif key_type == "OpenAI" and \
595
  result.get("key_availability") is True and \
596
- result.get("has_sufficient_quota") is True: # 이 ν•„λ“œκ°€ Trueμ—¬μ•Ό 함
597
  working_oai_keys.append(key_value)
598
- # Anthropic ν‚€ 필터링
599
  elif key_type == "Anthropic Claude" and result.get("key_availability") is True:
600
  working_anthropic_keys.append(key_value)
601
 
 
36
  # ─────────────────────────────────────────
37
  def get_key_oai_info(key: str) -> Dict[str, Any]:
38
  session = requests.Session()
 
 
39
  raw_status_code, org_data_or_error = check_key_availability(session, key)
40
 
41
  info_dict = {
 
83
  info_dict["quota"] = current_quota_message
84
  if "insufficient_quota" not in current_quota_message.lower(): # 상세 λ©”μ‹œμ§€μ— insufficient_quotaκ°€ μ—†λ‹€λ©΄ μƒνƒœ λ©”μ‹œμ§€μ— μΆ”κ°€
85
  info_dict["status_message"] += f" Error: {current_quota_message}"
 
 
86
  else: # 기타 μ—λŸ¬
87
  info_dict["status_message"] = f"Key check failed (status: {raw_status_code})."
88
  if isinstance(org_data_or_error, dict) and "error" in org_data_or_error:
 
93
  return info_dict
94
 
95
  if not info_dict["key_availability"]:
96
+ # 429κ°€ μ•„λ‹Œ λ‹€λ₯Έ 이유둜 key_availabilityκ°€ Falseλ©΄ λ°˜ν™˜
97
+ if raw_status_code != 429:
98
+ return info_dict
99
 
100
+ if not org_data_for_subscription and info_dict["key_availability"]:
 
101
  status_me, orgs_me_data = get_orgs_me(session, key)
102
  if status_me == 200:
103
  org_data_for_subscription = orgs_me_data
 
107
  info_dict["has_sufficient_quota"] = False
108
  return info_dict
109
 
110
+ if not org_data_for_subscription and info_dict["key_availability"]:
111
+ info_dict["status_message"] = (info_dict["status_message"] + " Organization data for subscription is missing.").strip()
112
+ info_dict["key_availability"] = False
113
+ info_dict["has_sufficient_quota"] = False
114
+ return info_dict
115
+
116
  subscription_info = get_subscription(key, session, org_data_for_subscription)
117
  if subscription_info:
118
  info_dict.update(
 
125
  "models": subscription_info.get("models", ""),
126
  "requests_per_minute": subscription_info.get("rpm", ""),
127
  "tokens_per_minute": subscription_info.get("tpm", ""),
128
+ "quota": subscription_info.get("quota") if subscription_info.get("quota") is not None else info_dict.get("quota", ""),
129
  "all_models": subscription_info.get("all_models", ""),
130
  }
131
  )
 
143
  ("billing" in err_msg and "issue" in err_msg):
144
  info_dict["has_sufficient_quota"] = False
145
  new_quota_message = f"Insufficient: {error_info.get('message', err_type)}"
146
+ info_dict["quota"] = new_quota_message
147
+ current_status_msg = info_dict["status_message"]
148
+ additional_msg = f" Quota/Billing issue from error object: {error_info.get('message', err_type)}"
149
+ if additional_msg.strip() not in current_status_msg :
150
+ info_dict["status_message"] = (current_status_msg + additional_msg).strip()
151
 
 
152
  if "account_deactivated" in str(subscription_info).lower() or \
153
  "payment_failed" in str(subscription_info).lower():
154
  info_dict["has_sufficient_quota"] = False
155
+ current_status_msg = info_dict["status_message"]
156
+ additional_msg = " Account issue (e.g., deactivated, payment failed) from subscription info."
157
+ if additional_msg.strip() not in current_status_msg:
158
+ info_dict["status_message"] = (current_status_msg + additional_msg).strip()
159
  else:
160
+ if info_dict["key_availability"]:
161
+ info_dict["status_message"] = (info_dict["status_message"] + " Failed to retrieve full subscription details.").strip()
162
+ info_dict["has_sufficient_quota"] = False
163
+
164
+ if info_dict.get("has_sufficient_quota") is True:
165
+ current_quota_field_value = info_dict.get("quota")
166
+ if current_quota_field_value:
167
+ if "insufficient_quota" in str(current_quota_field_value).lower():
168
+ info_dict["has_sufficient_quota"] = False
169
+ insufficient_msg = "Insufficient quota indicated in 'quota' field."
170
+ if insufficient_msg not in info_dict["status_message"]:
171
+ info_dict["status_message"] = (info_dict["status_message"] + f" {insufficient_msg}").strip()
172
 
173
  return info_dict
174
 
 
463
  # 단일 ν‚€ 비동기 처리 (μ—…λ°μ΄νŠΈλ¨)
464
  # ─────────────────────────────────────────
465
  async def process_single_key(key: str, rate_limit: bool, claude_model: str) -> Dict[str, Any]:
 
466
  _key = key.strip()
467
 
468
  if not _key:
469
  return {"key": "", "key_type": "Empty", "key_availability": False}
470
 
 
471
  if re.match(re.compile(r"sk-or-v1-[a-z0-9]{64}"), _key):
472
  result = get_key_openrouter_info(_key)
473
  return {"key": _key, **result}
 
 
474
  if re.match(re.compile(r"sk-ant-api03-[a-zA-Z0-9\-_]{93}AA"), _key) or \
475
  (_key.startswith("sk-ant-") and len(_key) == 93) or \
476
  (len(_key) == 89 and re.match(re.compile(r"sk-[a-zA-Z0-9]{86}"), _key)):
477
  result = await get_key_ant_info(_key, rate_limit, claude_model)
478
  return {"key": _key, **result}
 
 
479
  if re.match(re.compile(r"sk-[a-zA-Z0-9]{48}"), _key) and len(_key) == 51 and "T3BlbkFJ" not in _key:
480
  result = get_key_stability_info(_key)
481
  return {"key": _key, **result}
 
 
482
  if re.match(re.compile(r"sk-[a-f0-9]{32}"), _key):
483
  result = get_key_deepseek_info(_key)
484
  return {"key": _key, **result}
 
 
485
  if _key.startswith("sk-"):
486
+ result = get_key_oai_info(_key)
487
  return {"key": _key, **result}
 
 
488
  if _key.startswith("AIzaSy"):
489
  gemini_info = get_key_gemini_info(_key)
490
  is_working = gemini_info.get("key_availability") and gemini_info.get("status") == "Working"
 
494
  "is_gemini_working": is_working
495
  }
496
  return result
 
 
497
  if _key.startswith("pst-"):
498
  result = get_key_nai_info(_key)
499
  return {"key": _key, **result}
 
 
500
  if (_key.startswith("r8_") and len(_key) == 40) or (_key.islower() and len(_key) == 40):
501
  result = get_key_replicate_info(_key)
502
  return {"key": _key, **result}
 
 
503
  if _key.startswith("xai-"):
504
  result = get_key_xai_info(_key)
505
  return {"key": _key, **result}
 
 
506
  if len(_key.split(":")) == 2:
507
  name, potential_key = _key.split(":", 1)
508
  if re.fullmatch(r'[a-fA-F0-9]{32}', potential_key) and "openai.azure.com" not in name:
 
510
  api_key = potential_key
511
  result = get_key_azure_info(endpoint, api_key)
512
  return {"key": _key, **result}
 
 
513
  if ";" in _key and "openai.azure.com" in _key.split(";")[0]:
514
  endpoint, api_key = _key.split(";", 1)
515
  result = get_key_azure_info(endpoint, api_key)
516
  return {"key": _key, **result}
 
 
517
  if _key.startswith("AKIA") and len(_key.split(":")[0]) == 20 and _key.split(":")[0].isalnum() and _key.split(":")[0].isupper() and len(_key.split(':')) == 2:
518
  result = await get_key_aws_info(_key)
519
  return {"key": _key, **result}
 
 
520
  if re.fullmatch(r"[a-f0-9]{32}", _key) or re.fullmatch(r"sk_[a-f0-9]{48}", _key):
521
  result = get_key_elevenlabs_info(_key)
522
  return {"key": _key, **result}
 
 
523
  if re.fullmatch(r"[a-zA-Z0-9]{32}", _key) and not _key.startswith('sk-'):
524
  result = get_key_mistral_info(_key)
525
  return {"key": _key, **result}
 
 
526
  if re.match(re.compile(r"gsk_[a-zA-Z0-9]{20}WGdyb3FY[a-zA-Z0-9]{24}"), _key):
527
  result = get_key_groq_info(_key)
528
  return {"key": _key, **result}
 
 
529
  if re.match(re.compile(r"[\w\-]+:[\w\-@\.]+:.+:.+"), _key):
530
  parts = _key.split(':')
531
  if len(parts) >= 4:
532
  result = await get_key_gcp_info(_key, 0)
533
  return {"key": _key, **result}
 
 
534
  if re.match(re.compile(r"[\w\-]+:[\w\-@\.]+:.+\\n"), _key):
535
  parts = _key.split(':')
536
  if len(parts) >= 3:
537
  result = await get_key_gcp_info(_key, 1)
538
  return {"key": _key, **result}
 
 
539
  result = not_supported(_key)
540
  return {"key": _key, **result}
541
 
 
544
  # μ—¬λŸ¬ key 비동기 처리 ν•¨μˆ˜ (μ—…λ°μ΄νŠΈλ¨)
545
  # ─────────────────────────────────────────
546
  async def sort_keys(text: str, rate_limit: bool, claude_model: str) -> Tuple[List[Dict[str, Any]], str, str, str]:
 
 
 
 
547
  keys = [k.strip() for k in text.splitlines() if k.strip()]
548
  if not keys:
549
  return [], "", "", ""
 
562
 
563
  key_type = result.get("key_type")
564
 
 
565
  if result.get("is_gemini_working"):
566
  working_gemini_keys.append(key_value)
 
567
  elif key_type == "OpenAI" and \
568
  result.get("key_availability") is True and \
569
+ result.get("has_sufficient_quota") is True:
570
  working_oai_keys.append(key_value)
 
571
  elif key_type == "Anthropic Claude" and result.get("key_availability") is True:
572
  working_anthropic_keys.append(key_value)
573