prxyasd commited on
Commit
f9bdbd9
Β·
verified Β·
1 Parent(s): 16fadcf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +235 -144
app.py CHANGED
@@ -1,17 +1,18 @@
1
-
2
-
3
  import asyncio
4
  import gradio as gr
5
  import requests
6
  import re
 
7
 
 
 
8
  from api_usage import (
9
  get_subscription,
10
  check_key_availability,
11
  get_orgs_me,
12
  check_key_ant_availability,
13
  check_ant_rate_limit,
14
- check_key_gemini_availability,
15
  check_key_azure_availability,
16
  get_azure_status,
17
  get_azure_deploy,
@@ -31,9 +32,9 @@ from api_usage import (
31
  )
32
 
33
  # ─────────────────────────────────────────
34
- # Key-specific helper functions (원본 μœ μ§€)
35
  # ─────────────────────────────────────────
36
- def get_key_oai_info(key):
37
  session = requests.Session()
38
  status, org_data = check_key_availability(session, key)
39
 
@@ -61,25 +62,25 @@ def get_key_oai_info(key):
61
  org_data = orgs_me
62
 
63
  subscription_info = get_subscription(key, session, org_data)
64
-
65
- info_dict.update(
66
- {
67
- "gpt4_availability": subscription_info["has_gpt4"],
68
- "gpt4_32k_availability": subscription_info["has_gpt4_32k"],
69
- "default_org": subscription_info["default_org"],
70
- "org_description": subscription_info["org_description"],
71
- "organization": subscription_info["organization"],
72
- "models": subscription_info["models"],
73
- "requests_per_minute": subscription_info["rpm"],
74
- "tokens_per_minute": subscription_info["tpm"],
75
- "quota": subscription_info["quota"],
76
- "all_models": subscription_info["all_models"],
77
- }
78
- )
79
  return info_dict
80
 
81
 
82
- async def get_key_ant_info(key, rate_limit, claude_model):
83
  key_avai = await check_key_ant_availability(key, claude_model)
84
  info_dict = {
85
  "key_type": "Anthropic Claude",
@@ -111,18 +112,20 @@ async def get_key_ant_info(key, rate_limit, claude_model):
111
  return info_dict
112
 
113
 
114
- def get_key_gemini_info(key):
115
- key_avai = check_key_gemini_availability(key)
 
 
116
  info_dict = {
117
- "key": key,
118
  "key_availability": key_avai[0],
119
  "status": key_avai[1],
120
- #"models": key_avai[2],
121
  }
122
  return info_dict
123
 
124
 
125
- def get_key_azure_info(endpoint, api_key):
126
  key_avai = check_key_azure_availability(endpoint, api_key)
127
  info_dict = {
128
  "key_type": "Microsoft Azure OpenAI",
@@ -137,18 +140,20 @@ def get_key_azure_info(endpoint, api_key):
137
  }
138
  if key_avai[0]:
139
  azure_deploy = get_azure_deploy(endpoint, api_key)
140
- status = get_azure_status(endpoint, api_key, azure_deploy)
141
- info_dict["gpt35_availability"] = status[1]
142
- info_dict["gpt4_availability"] = status[2]
143
- info_dict["gpt4_32k_availability"] = status[3]
144
- info_dict["dall_e_3_availability"] = status[4]
145
- info_dict["moderation_status"] = status[0]
 
 
146
  info_dict["models"] = key_avai[1]
147
- info_dict["deployments"] = azure_deploy
148
  return info_dict
149
 
150
 
151
- def get_key_mistral_info(key):
152
  key_avai = check_key_mistral_availability(key)
153
  info_dict = {
154
  "key_type": "Mistral AI",
@@ -159,14 +164,15 @@ def get_key_mistral_info(key):
159
  }
160
  if key_avai:
161
  quota_info = check_mistral_quota(key)
162
- info_dict["has_quota"] = quota_info[0]
163
- if quota_info[1]:
164
- info_dict["limits"] = quota_info[1]
 
165
  info_dict["models"] = key_avai
166
  return info_dict
167
 
168
 
169
- def get_key_replicate_info(key):
170
  key_avai = check_key_replicate_availability(key)
171
  info_dict = {
172
  "key_type": "Replicate",
@@ -176,15 +182,15 @@ def get_key_replicate_info(key):
176
  "has_quota": "",
177
  "hardware_available": "",
178
  }
179
- if key_avai[0]:
180
- info_dict["account_name"] = key_avai[1]["username"]
181
- info_dict["type"] = key_avai[1]["type"]
182
  info_dict["has_quota"] = key_avai[2]
183
  info_dict["hardware_available"] = key_avai[3]
184
  return info_dict
185
 
186
 
187
- async def get_key_aws_info(key):
188
  key_avai = await check_key_aws_availability(key)
189
  info_dict = {
190
  "key_type": "Amazon AWS Claude",
@@ -198,7 +204,7 @@ async def get_key_aws_info(key):
198
  "aws_bedrock_full_access": "",
199
  "enabled_region": "",
200
  "models_usage": "",
201
- "cost_and_usage": key_avai[1],
202
  }
203
  if key_avai[0]:
204
  info_dict["username"] = key_avai[1]
@@ -214,7 +220,7 @@ async def get_key_aws_info(key):
214
  return info_dict
215
 
216
 
217
- def get_key_openrouter_info(key):
218
  key_avai = check_key_or_availability(key)
219
  info_dict = {
220
  "key_type": "OpenRouter",
@@ -229,25 +235,41 @@ def get_key_openrouter_info(key):
229
  "sonnet_per_request_tokens_limit": "",
230
  "opus_per_request_tokens_limit": "",
231
  }
232
- if key_avai[0]:
233
  models_info = check_key_or_limits(key)
234
- info_dict["is_free_tier"] = key_avai[1]["is_free_tier"]
235
- info_dict["limit"] = key_avai[1]["limit"]
236
- info_dict["limit_remaining"] = key_avai[1]["limit_remaining"]
237
- info_dict["usage"] = f"${format(key_avai[1]['usage'], '.4f')}"
238
- info_dict["balance"] = (
239
- f"${format(models_info[0], '.4f')}" if models_info[0] else f"${key_avai[2]/60} (estimated)"
240
- )
241
- info_dict["rate_limit_per_minite"] = key_avai[2]
242
- info_dict["4_turbo_per_request_tokens_limit"] = models_info[1]["openai/gpt-4o"]
243
- info_dict["sonnet_per_request_tokens_limit"] = models_info[1]["anthropic/claude-3.5-sonnet:beta"]
244
- info_dict["opus_per_request_tokens_limit"] = models_info[1]["anthropic/claude-3-opus:beta"]
245
- else:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  info_dict["usage"] = key_avai[1]
247
  return info_dict
248
 
249
 
250
- async def get_key_gcp_info(key, type):
251
  key_avai = await check_gcp_anthropic(key, type)
252
  info_dict = {
253
  "key_type": "Vertex AI (GCP)",
@@ -257,12 +279,12 @@ async def get_key_gcp_info(key, type):
257
  }
258
  if key_avai[0]:
259
  info_dict["enabled_region"] = key_avai[2]
260
- else:
261
  info_dict["status"] = key_avai[1]
262
  return info_dict
263
 
264
 
265
- def get_key_groq_info(key):
266
  key_avai = check_groq_status(key)
267
  info_dict = {
268
  "key_type": "Groq",
@@ -272,7 +294,7 @@ def get_key_groq_info(key):
272
  return info_dict
273
 
274
 
275
- def get_key_nai_info(key):
276
  key_avai = check_nai_status(key)
277
  info_dict = {
278
  "key_type": "NovelAI",
@@ -282,18 +304,18 @@ def get_key_nai_info(key):
282
  return info_dict
283
 
284
 
285
- def get_key_elevenlabs_info(key):
286
  key_avai = check_elevenlabs_status(key)
287
  info_dict = {
288
  "key_type": "ElevenLabs",
289
  "key_availability": key_avai[0],
290
- "user_info": key_avai[1],
291
- "voices_info": key_avai[2],
292
  }
293
  return info_dict
294
 
295
 
296
- def get_key_xai_info(key):
297
  key_avai = check_xai_status(key)
298
  info_dict = {
299
  "key_type": "xAI Grok",
@@ -302,12 +324,12 @@ def get_key_xai_info(key):
302
  "models": "",
303
  }
304
  if key_avai[0]:
305
- info_dict["key_status"] = key_avai[1]
306
- info_dict["models"] = key_avai[2]
307
  return info_dict
308
 
309
 
310
- def get_key_stability_info(key):
311
  key_avai = check_stability_status(key)
312
  info_dict = {
313
  "key_type": "Stability AI",
@@ -317,149 +339,202 @@ def get_key_stability_info(key):
317
  "models": "",
318
  }
319
  if key_avai[0]:
320
- info_dict["account_info"] = key_avai[1]
321
- info_dict["credits"] = key_avai[2]
322
- info_dict["models"] = key_avai[3]
323
  return info_dict
324
 
325
 
326
- def get_key_deepseek_info(key):
327
  key_avai = check_deepseek_status(key)
328
  info_dict = {
329
- "key_type": "deepseek",
330
  "key_availability": key_avai[0],
331
  "balance": "",
332
  "models": "",
333
  }
334
  if key_avai[0]:
335
- info_dict["models"] = key_avai[1]
336
- info_dict["balance"] = key_avai[2]
337
  return info_dict
338
 
339
 
340
- def not_supported(key):
341
  return {
342
  "key_type": "Not supported",
343
- "status": "",
 
344
  }
345
 
346
 
347
  # ─────────────────────────────────────────
348
- # μƒˆλ‘œ μΆ”κ°€: 단일 ν‚€ 비동기 처리
349
  # ─────────────────────────────────────────
350
- async def process_single_key(key: str, rate_limit: bool, claude_model: str) -> dict:
351
- """μ£Όμ–΄μ§„ key ν•˜λ‚˜λ₯Ό 뢄석해 정보 dict λ°˜ν™˜."""
352
  _key = key.strip()
353
 
 
 
 
354
  # OpenRouter
355
  if re.match(re.compile(r"sk-or-v1-[a-z0-9]{64}"), _key):
356
- return {"key": _key, **get_key_openrouter_info(_key)}
 
357
 
358
  # Anthropic Claude
359
- if re.match(re.compile(r"sk-ant-api03-[a-zA-Z0-9\-_]{93}AA"), _key) or (
360
- _key.startswith("sk-ant-") and len(_key) == 93
361
- ) or (len(_key) == 89 and re.match(re.compile(r"sk-[a-zA-Z0-9]{86}"), _key)):
362
- return {"key": _key, **await get_key_ant_info(_key, rate_limit, claude_model)}
 
363
 
364
  # Stability
365
  if re.match(re.compile(r"sk-[a-zA-Z0-9]{48}"), _key) and len(_key) == 51 and "T3BlbkFJ" not in _key:
366
- return {"key": _key, **get_key_stability_info(_key)}
 
367
 
368
  # Deepseek
369
  if re.match(re.compile(r"sk-[a-f0-9]{32}"), _key):
370
- return {"key": _key, **get_key_deepseek_info(_key)}
 
371
 
372
- # OpenAI
373
  if _key.startswith("sk-"):
374
- return {"key": _key, **get_key_oai_info(_key)}
 
375
 
376
- # Google Gemini
377
  if _key.startswith("AIzaSy"):
378
- return {"key": _key, **get_key_gemini_info(_key)}
 
 
 
 
 
 
 
 
 
 
379
 
380
  # NovelAI
381
  if _key.startswith("pst-"):
382
- return {"key": _key, **get_key_nai_info(_key)}
 
383
 
384
  # Replicate
385
  if (_key.startswith("r8_") and len(_key) == 40) or (_key.islower() and len(_key) == 40):
386
- return {"key": _key, **get_key_replicate_info(_key)}
 
387
 
388
  # xAI
389
  if _key.startswith("xai-"):
390
- return {"key": _key, **get_key_xai_info(_key)}
 
391
 
392
  # Azure endpoint: "name:key"
393
- if len(_key.split(":")) == 2 and _key.split(":")[1].islower() and len(_key.split(":")[1]) == 32 and "openai.azure.com" not in _key.split(":")[1]:
394
- endpoint, api_key = _key.split(":")
395
- return {"key": _key, **get_key_azure_info(endpoint, api_key)}
 
 
 
 
396
 
397
  # Azure endpoint: "https://xxx.openai.azure.com;key"
398
- if "openai.azure.com" in _key.split(";")[0]:
399
- endpoint, api_key = _key.split(";")
400
- return {"key": _key, **get_key_azure_info(endpoint, api_key)}
 
401
 
402
  # AWS
403
- if _key.startswith("AKIA") and len(_key.split(":")[0]) == 20 and _key.split(":")[0].isupper():
404
- return {"key": _key, **await get_key_aws_info(_key)}
 
405
 
406
  # ElevenLabs
407
- if re.match(re.compile(r"[a-f0-9]{32}"), _key) or re.match(re.compile(r"sk_[a-f0-9]{48}"), _key):
408
- return {"key": _key, **get_key_elevenlabs_info(_key)}
 
409
 
410
  # Mistral
411
- if re.match(re.compile(r"[a-zA-Z0-9]{32}"), _key):
412
- return {"key": _key, **get_key_mistral_info(_key)}
 
413
 
414
  # Groq
415
  if re.match(re.compile(r"gsk_[a-zA-Z0-9]{20}WGdyb3FY[a-zA-Z0-9]{24}"), _key):
416
- return {"key": _key, **get_key_groq_info(_key)}
 
417
 
418
  # GCP - refresh token
419
- if re.match(re.compile(r"[\w\-]+:[\w\-@\.]+:[\w-]+:.+"), _key):
420
- return {"key": _key, **await get_key_gcp_info(_key, 0)}
 
 
 
421
 
422
  # GCP - service account
423
  if re.match(re.compile(r"[\w\-]+:[\w\-@\.]+:.+\\n"), _key):
424
- return {"key": _key, **await get_key_gcp_info(_key, 1)}
 
 
 
425
 
426
  # Not supported
427
- return {"key": _key, **not_supported(_key)}
 
 
428
 
429
 
430
  # ─────────────────────────────────────────
431
- # μ—¬λŸ¬ key 비동기 처리 ν•¨μˆ˜
432
  # ─────────────────────────────────────────
433
- async def sort_keys(text: str, rate_limit: bool, claude_model: str):
434
- """ν…μŠ€νŠΈ λ°•μŠ€μ— μž…λ ₯된 μ—¬λŸ¬ ν‚€λ₯Ό 쀄 λ‹¨μœ„λ‘œ 뢄석."""
435
  keys = [k.strip() for k in text.splitlines() if k.strip()]
 
 
 
436
  tasks = [process_single_key(k, rate_limit, claude_model) for k in keys]
437
  results = await asyncio.gather(*tasks)
438
- return results # gr.JSON μ»΄ν¬λ„ŒνŠΈκ°€ λ¦¬μŠ€νŠΈλ„ μžλ™ ν‘œμ‹œ
 
 
 
 
 
 
 
 
 
 
439
 
440
 
441
  # ─────────────────────────────────────────
442
  # UI util
443
  # ─────────────────────────────────────────
444
- def clear_inputs(text: str):
445
- return ""
446
 
447
 
448
  # ─────────────────────────────────────────
449
- # Gradio UI
450
  # ─────────────────────────────────────────
451
  with gr.Blocks() as demo:
452
  gr.Markdown(
453
  """
454
- # OpenAI/Anthropic/Gemini/Azure/Mistral/Replicate/AWS Claude/OpenRouter/Vertex AI(GCP Anthropic)/Groq/NovelAI/ElevenLabs/xAI/Stability/Deepseek API Key Status Checker
455
-
456
- *(Based on shaocongma, CncAnon1, su, Drago, kingbased key checkers)*
457
-
458
- AWS credential format: `AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY` (root might not be accurate)
459
- Azure format: `RESOURCE_NAME:API_KEY` **or** `https://RESOURCE_NAME.openai.azure.com;API_KEY`
460
- GCP format:
461
- β€’ Service account β†’ `PROJECT_ID:CLIENT_EMAIL:PRIVATE_KEY(\\n 포함)`
462
- β€’ Refresh token β†’ `PROJECT_ID:CLIENT_ID:CLIENT_SECRET:REFRESH_TOKEN`
 
463
  """
464
  )
465
 
@@ -468,38 +543,54 @@ GCP format:
468
  "claude-3-sonnet-20240229",
469
  "claude-3-opus-20240229",
470
  "claude-3-5-sonnet-20240620",
471
- "claude-3-5-sonnet-20241022",
472
- "claude-3-5-haiku-20241022",
473
  ]
474
 
475
  with gr.Row():
476
- with gr.Column():
477
  key_box = gr.Textbox(
478
  lines=5,
479
  max_lines=20,
480
- label="API Key(s) β€” μ€„λ°”κΏˆμœΌλ‘œ μ—¬λŸ¬ 개 μž…λ ₯",
481
- placeholder="각 μ€„λ§ˆλ‹€ ν•˜λ‚˜μ˜ ν‚€λ₯Ό μž…λ ₯ν•˜μ„Έμš”",
482
- )
483
- claude_model = gr.Dropdown(
484
- claude_options,
485
- value="claude-3-haiku-20240307",
486
- label="Claude API model (filter/concurrent check용)",
487
  )
488
- rate_limit = gr.Checkbox(label="Check concurrent rate limit (Claude, experimental)")
 
 
 
 
 
 
 
489
 
490
  with gr.Row():
491
- clear_button = gr.Button("Clear")
492
- submit_button = gr.Button("Submit", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
493
 
494
- with gr.Column():
495
- info = gr.JSON(label="API Key Information", open=True)
 
 
 
 
496
 
497
- clear_button.click(fn=clear_inputs, inputs=[key_box], outputs=[key_box])
498
  submit_button.click(
499
  fn=sort_keys,
500
  inputs=[key_box, rate_limit, claude_model],
501
- outputs=[info],
502
  api_name="sort_keys",
503
  )
504
 
 
505
  demo.launch()
 
 
 
1
  import asyncio
2
  import gradio as gr
3
  import requests
4
  import re
5
+ from typing import List, Dict, Tuple, Any # νƒ€μž… 힌트 μΆ”κ°€
6
 
7
+ # api_usage λͺ¨λ“ˆμ€ μ‚¬μš©μžμ˜ ν™˜κ²½μ— 맞게 μ‘΄μž¬ν•œλ‹€κ³  κ°€μ •ν•©λ‹ˆλ‹€.
8
+ # ν•„μš”ν•œ ν•¨μˆ˜λ“€μ„ μž„ν¬νŠΈ (μ‹€μ œ μ‚¬μš© μ‹œ ν•΄λ‹Ή λͺ¨λ“ˆ ν•„μš”)
9
  from api_usage import (
10
  get_subscription,
11
  check_key_availability,
12
  get_orgs_me,
13
  check_key_ant_availability,
14
  check_ant_rate_limit,
15
+ check_key_gemini_availability, # 이 ν•¨μˆ˜λŠ” (bool, str) νŠœν”Œμ„ λ°˜ν™˜ν•œλ‹€κ³  κ°€μ •
16
  check_key_azure_availability,
17
  get_azure_status,
18
  get_azure_deploy,
 
32
  )
33
 
34
  # ─────────────────────────────────────────
35
+ # Key-specific helper functions (원본 μœ μ§€ - Gemini 포함)
36
  # ─────────────────────────────────────────
37
+ def get_key_oai_info(key: str) -> Dict[str, Any]:
38
  session = requests.Session()
39
  status, org_data = check_key_availability(session, key)
40
 
 
62
  org_data = orgs_me
63
 
64
  subscription_info = get_subscription(key, session, org_data)
65
+ if subscription_info:
66
+ info_dict.update(
67
+ {
68
+ "gpt4_availability": subscription_info.get("has_gpt4", ""),
69
+ "gpt4_32k_availability": subscription_info.get("has_gpt4_32k", ""),
70
+ "default_org": subscription_info.get("default_org", ""),
71
+ "org_description": subscription_info.get("org_description", ""),
72
+ "organization": subscription_info.get("organization", ""),
73
+ "models": subscription_info.get("models", ""),
74
+ "requests_per_minute": subscription_info.get("rpm", ""),
75
+ "tokens_per_minute": subscription_info.get("tpm", ""),
76
+ "quota": subscription_info.get("quota", ""),
77
+ "all_models": subscription_info.get("all_models", ""),
78
+ }
79
+ )
80
  return info_dict
81
 
82
 
83
+ async def get_key_ant_info(key: str, rate_limit: bool, claude_model: str) -> Dict[str, Any]:
84
  key_avai = await check_key_ant_availability(key, claude_model)
85
  info_dict = {
86
  "key_type": "Anthropic Claude",
 
112
  return info_dict
113
 
114
 
115
+ # μ‚¬μš©μžμ˜ 원본 get_key_gemini_info ν•¨μˆ˜ μœ μ§€
116
+ def get_key_gemini_info(key: str) -> Dict[str, Any]:
117
+ """Gemini ν‚€ 정보λ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€ (μ‚¬μš©μž 원본 버전)."""
118
+ key_avai = check_key_gemini_availability(key) # (bool, str) νŠœν”Œ λ°˜ν™˜ κ°€μ •
119
  info_dict = {
120
+ "key": key, # μ›λ³Έμ—λŠ” key ν•„λ“œκ°€ μžˆμ—ˆμŒ
121
  "key_availability": key_avai[0],
122
  "status": key_avai[1],
123
+ #"models": key_avai[2], # μ›λ³Έμ—λŠ” λͺ¨λΈ 정보가 주석 처리됨
124
  }
125
  return info_dict
126
 
127
 
128
+ def get_key_azure_info(endpoint: str, api_key: str) -> Dict[str, Any]:
129
  key_avai = check_key_azure_availability(endpoint, api_key)
130
  info_dict = {
131
  "key_type": "Microsoft Azure OpenAI",
 
140
  }
141
  if key_avai[0]:
142
  azure_deploy = get_azure_deploy(endpoint, api_key)
143
+ if azure_deploy:
144
+ status = get_azure_status(endpoint, api_key, azure_deploy)
145
+ if status:
146
+ info_dict["gpt35_availability"] = status[1]
147
+ info_dict["gpt4_availability"] = status[2]
148
+ info_dict["gpt4_32k_availability"] = status[3]
149
+ info_dict["dall_e_3_availability"] = status[4]
150
+ info_dict["moderation_status"] = status[0]
151
  info_dict["models"] = key_avai[1]
152
+ info_dict["deployments"] = azure_deploy if azure_deploy else "N/A"
153
  return info_dict
154
 
155
 
156
+ def get_key_mistral_info(key: str) -> Dict[str, Any]:
157
  key_avai = check_key_mistral_availability(key)
158
  info_dict = {
159
  "key_type": "Mistral AI",
 
164
  }
165
  if key_avai:
166
  quota_info = check_mistral_quota(key)
167
+ if quota_info:
168
+ info_dict["has_quota"] = quota_info[0]
169
+ if quota_info[1]:
170
+ info_dict["limits"] = quota_info[1]
171
  info_dict["models"] = key_avai
172
  return info_dict
173
 
174
 
175
+ def get_key_replicate_info(key: str) -> Dict[str, Any]:
176
  key_avai = check_key_replicate_availability(key)
177
  info_dict = {
178
  "key_type": "Replicate",
 
182
  "has_quota": "",
183
  "hardware_available": "",
184
  }
185
+ if key_avai[0] and isinstance(key_avai[1], dict):
186
+ info_dict["account_name"] = key_avai[1].get("username", "")
187
+ info_dict["type"] = key_avai[1].get("type", "")
188
  info_dict["has_quota"] = key_avai[2]
189
  info_dict["hardware_available"] = key_avai[3]
190
  return info_dict
191
 
192
 
193
+ async def get_key_aws_info(key: str) -> Dict[str, Any]:
194
  key_avai = await check_key_aws_availability(key)
195
  info_dict = {
196
  "key_type": "Amazon AWS Claude",
 
204
  "aws_bedrock_full_access": "",
205
  "enabled_region": "",
206
  "models_usage": "",
207
+ "cost_and_usage": key_avai[1] if not key_avai[0] else "",
208
  }
209
  if key_avai[0]:
210
  info_dict["username"] = key_avai[1]
 
220
  return info_dict
221
 
222
 
223
+ def get_key_openrouter_info(key: str) -> Dict[str, Any]:
224
  key_avai = check_key_or_availability(key)
225
  info_dict = {
226
  "key_type": "OpenRouter",
 
235
  "sonnet_per_request_tokens_limit": "",
236
  "opus_per_request_tokens_limit": "",
237
  }
238
+ if key_avai[0] and isinstance(key_avai[1], dict):
239
  models_info = check_key_or_limits(key)
240
+ info_dict["is_free_tier"] = key_avai[1].get("is_free_tier", "")
241
+ info_dict["limit"] = key_avai[1].get("limit", "")
242
+ info_dict["limit_remaining"] = key_avai[1].get("limit_remaining", "")
243
+ usage_val = key_avai[1].get("usage")
244
+ info_dict["usage"] = f"${format(usage_val, '.4f')}" if isinstance(usage_val, (int, float)) else ""
245
+
246
+ balance_val = models_info[0] if models_info else None
247
+ rate_limit_val = key_avai[2] if len(key_avai) > 2 else None
248
+
249
+ if balance_val is not None:
250
+ info_dict["balance"] = f"${format(balance_val, '.4f')}"
251
+ elif rate_limit_val is not None:
252
+ try:
253
+ estimated_balance = float(rate_limit_val) / 60
254
+ info_dict["balance"] = f"${format(estimated_balance, '.4f')} (estimated)"
255
+ except (ValueError, TypeError):
256
+ info_dict["balance"] = "$N/A (estimation failed)"
257
+ else:
258
+ info_dict["balance"] = "$N/A"
259
+
260
+ info_dict["rate_limit_per_minite"] = rate_limit_val if rate_limit_val is not None else ""
261
+
262
+ if models_info and isinstance(models_info[1], dict):
263
+ model_limits = models_info[1]
264
+ info_dict["4_turbo_per_request_tokens_limit"] = model_limits.get("openai/gpt-4o", "")
265
+ info_dict["sonnet_per_request_tokens_limit"] = model_limits.get("anthropic/claude-3.5-sonnet:beta", "")
266
+ info_dict["opus_per_request_tokens_limit"] = model_limits.get("anthropic/claude-3-opus:beta", "")
267
+ elif not key_avai[0] and len(key_avai) > 1:
268
  info_dict["usage"] = key_avai[1]
269
  return info_dict
270
 
271
 
272
+ async def get_key_gcp_info(key: str, type: int) -> Dict[str, Any]:
273
  key_avai = await check_gcp_anthropic(key, type)
274
  info_dict = {
275
  "key_type": "Vertex AI (GCP)",
 
279
  }
280
  if key_avai[0]:
281
  info_dict["enabled_region"] = key_avai[2]
282
+ elif len(key_avai) > 1:
283
  info_dict["status"] = key_avai[1]
284
  return info_dict
285
 
286
 
287
+ def get_key_groq_info(key: str) -> Dict[str, Any]:
288
  key_avai = check_groq_status(key)
289
  info_dict = {
290
  "key_type": "Groq",
 
294
  return info_dict
295
 
296
 
297
+ def get_key_nai_info(key: str) -> Dict[str, Any]:
298
  key_avai = check_nai_status(key)
299
  info_dict = {
300
  "key_type": "NovelAI",
 
304
  return info_dict
305
 
306
 
307
+ def get_key_elevenlabs_info(key: str) -> Dict[str, Any]:
308
  key_avai = check_elevenlabs_status(key)
309
  info_dict = {
310
  "key_type": "ElevenLabs",
311
  "key_availability": key_avai[0],
312
+ "user_info": key_avai[1] if len(key_avai) > 1 else "",
313
+ "voices_info": key_avai[2] if len(key_avai) > 2 else "",
314
  }
315
  return info_dict
316
 
317
 
318
+ def get_key_xai_info(key: str) -> Dict[str, Any]:
319
  key_avai = check_xai_status(key)
320
  info_dict = {
321
  "key_type": "xAI Grok",
 
324
  "models": "",
325
  }
326
  if key_avai[0]:
327
+ info_dict["key_status"] = key_avai[1] if len(key_avai) > 1 else ""
328
+ info_dict["models"] = key_avai[2] if len(key_avai) > 2 else ""
329
  return info_dict
330
 
331
 
332
+ def get_key_stability_info(key: str) -> Dict[str, Any]:
333
  key_avai = check_stability_status(key)
334
  info_dict = {
335
  "key_type": "Stability AI",
 
339
  "models": "",
340
  }
341
  if key_avai[0]:
342
+ info_dict["account_info"] = key_avai[1] if len(key_avai) > 1 else ""
343
+ info_dict["credits"] = key_avai[2] if len(key_avai) > 2 else ""
344
+ info_dict["models"] = key_avai[3] if len(key_avai) > 3 else ""
345
  return info_dict
346
 
347
 
348
+ def get_key_deepseek_info(key: str) -> Dict[str, Any]:
349
  key_avai = check_deepseek_status(key)
350
  info_dict = {
351
+ "key_type": "DeepSeek",
352
  "key_availability": key_avai[0],
353
  "balance": "",
354
  "models": "",
355
  }
356
  if key_avai[0]:
357
+ info_dict["models"] = key_avai[1] if len(key_avai) > 1 else ""
358
+ info_dict["balance"] = key_avai[2] if len(key_avai) > 2 else ""
359
  return info_dict
360
 
361
 
362
+ def not_supported(key: str) -> Dict[str, Any]:
363
  return {
364
  "key_type": "Not supported",
365
+ "key_availability": False,
366
+ "status": "Unknown key format",
367
  }
368
 
369
 
370
  # ─────────────────────────────────────────
371
+ # 단일 ν‚€ 비동기 처리 (μ—…λ°μ΄νŠΈλ¨)
372
  # ─────────────────────────────────────────
373
+ async def process_single_key(key: str, rate_limit: bool, claude_model: str) -> Dict[str, Any]:
374
+ """μ£Όμ–΄μ§„ key ν•˜λ‚˜λ₯Ό 뢄석해 정보 dict λ°˜ν™˜. Gemini ν‚€μ˜ μž‘λ™ μ—¬λΆ€ ν”Œλž˜κ·Έ 포함."""
375
  _key = key.strip()
376
 
377
+ if not _key:
378
+ return {"key": "", "key_type": "Empty", "key_availability": False}
379
+
380
  # OpenRouter
381
  if re.match(re.compile(r"sk-or-v1-[a-z0-9]{64}"), _key):
382
+ result = get_key_openrouter_info(_key)
383
+ return {"key": _key, **result} # key_type은 get_key_openrouter_infoμ—μ„œ λ°˜ν™˜
384
 
385
  # Anthropic Claude
386
+ if re.match(re.compile(r"sk-ant-api03-[a-zA-Z0-9\-_]{93}AA"), _key) or \
387
+ (_key.startswith("sk-ant-") and len(_key) == 93) or \
388
+ (len(_key) == 89 and re.match(re.compile(r"sk-[a-zA-Z0-9]{86}"), _key)):
389
+ result = await get_key_ant_info(_key, rate_limit, claude_model)
390
+ return {"key": _key, **result} # key_type 포함
391
 
392
  # Stability
393
  if re.match(re.compile(r"sk-[a-zA-Z0-9]{48}"), _key) and len(_key) == 51 and "T3BlbkFJ" not in _key:
394
+ result = get_key_stability_info(_key)
395
+ return {"key": _key, **result} # key_type 포함
396
 
397
  # Deepseek
398
  if re.match(re.compile(r"sk-[a-f0-9]{32}"), _key):
399
+ result = get_key_deepseek_info(_key)
400
+ return {"key": _key, **result} # key_type 포함
401
 
402
+ # OpenAI (λ‹€λ₯Έ sk- νŒ¨ν„΄λ³΄λ‹€ 뒀에 와야 함)
403
  if _key.startswith("sk-"):
404
+ result = get_key_oai_info(_key)
405
+ return {"key": _key, **result} # key_type 포함
406
 
407
+ # Google Gemini 처리 (μˆ˜μ •λ¨)
408
  if _key.startswith("AIzaSy"):
409
+ gemini_info = get_key_gemini_info(_key) # 원본 ν•¨μˆ˜ 호좜
410
+ # μž‘λ™ μ—¬λΆ€ ν”Œλž˜κ·Έ μΆ”κ°€ (status 확인)
411
+ is_working = gemini_info.get("key_availability") and gemini_info.get("status") == "Working"
412
+ # κ²°κ³Ό λ”•μ…”λ„ˆλ¦¬ ꡬ성: 원본 정보 + key_type + μž‘λ™ μ—¬λΆ€ ν”Œλž˜κ·Έ
413
+ # gemini_info에 이미 'key'κ°€ ν¬ν•¨λ˜μ–΄ 있음
414
+ result = {
415
+ "key_type": "Google Gemini", # νƒ€μž… 정보 λͺ…μ‹œμ  μΆ”κ°€
416
+ **gemini_info,
417
+ "is_gemini_working": is_working # μž‘λ™ μ—¬λΆ€ ν”Œλž˜κ·Έ
418
+ }
419
+ return result
420
 
421
  # NovelAI
422
  if _key.startswith("pst-"):
423
+ result = get_key_nai_info(_key)
424
+ return {"key": _key, **result} # key_type 포함
425
 
426
  # Replicate
427
  if (_key.startswith("r8_") and len(_key) == 40) or (_key.islower() and len(_key) == 40):
428
+ result = get_key_replicate_info(_key)
429
+ return {"key": _key, **result} # key_type 포함
430
 
431
  # xAI
432
  if _key.startswith("xai-"):
433
+ result = get_key_xai_info(_key)
434
+ return {"key": _key, **result} # key_type 포함
435
 
436
  # Azure endpoint: "name:key"
437
+ if len(_key.split(":")) == 2:
438
+ name, potential_key = _key.split(":", 1)
439
+ if re.fullmatch(r'[a-fA-F0-9]{32}', potential_key) and "openai.azure.com" not in name:
440
+ endpoint = f"https://{name}.openai.azure.com/"
441
+ api_key = potential_key
442
+ result = get_key_azure_info(endpoint, api_key)
443
+ return {"key": _key, **result} # key_type 포함
444
 
445
  # Azure endpoint: "https://xxx.openai.azure.com;key"
446
+ if ";" in _key and "openai.azure.com" in _key.split(";")[0]:
447
+ endpoint, api_key = _key.split(";", 1)
448
+ result = get_key_azure_info(endpoint, api_key)
449
+ return {"key": _key, **result} # key_type 포함
450
 
451
  # AWS
452
+ 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:
453
+ result = await get_key_aws_info(_key)
454
+ return {"key": _key, **result} # key_type 포함
455
 
456
  # ElevenLabs
457
+ if re.fullmatch(r"[a-f0-9]{32}", _key) or re.fullmatch(r"sk_[a-f0-9]{48}", _key):
458
+ result = get_key_elevenlabs_info(_key)
459
+ return {"key": _key, **result} # key_type 포함
460
 
461
  # Mistral
462
+ if re.fullmatch(r"[a-zA-Z0-9]{32}", _key) and not _key.startswith('sk-'):
463
+ result = get_key_mistral_info(_key)
464
+ return {"key": _key, **result} # key_type 포함
465
 
466
  # Groq
467
  if re.match(re.compile(r"gsk_[a-zA-Z0-9]{20}WGdyb3FY[a-zA-Z0-9]{24}"), _key):
468
+ result = get_key_groq_info(_key)
469
+ return {"key": _key, **result} # key_type 포함
470
 
471
  # GCP - refresh token
472
+ if re.match(re.compile(r"[\w\-]+:[\w\-@\.]+:.+:.+"), _key):
473
+ parts = _key.split(':')
474
+ if len(parts) >= 4:
475
+ result = await get_key_gcp_info(_key, 0)
476
+ return {"key": _key, **result} # key_type 포함
477
 
478
  # GCP - service account
479
  if re.match(re.compile(r"[\w\-]+:[\w\-@\.]+:.+\\n"), _key):
480
+ parts = _key.split(':')
481
+ if len(parts) >= 3:
482
+ result = await get_key_gcp_info(_key, 1)
483
+ return {"key": _key, **result} # key_type 포함
484
 
485
  # Not supported
486
+ result = not_supported(_key) # key_type, key_availability, status 포함
487
+ # ν‚€ κ°’ μΆ”κ°€ν•˜μ—¬ λ°˜ν™˜
488
+ return {"key": _key, **result}
489
 
490
 
491
  # ─────────────────────────────────────────
492
+ # μ—¬λŸ¬ key 비동기 처리 ν•¨μˆ˜ (μ—…λ°μ΄νŠΈλ¨)
493
  # ─────────────────────────────────────────
494
+ async def sort_keys(text: str, rate_limit: bool, claude_model: str) -> Tuple[List[Dict[str, Any]], str]:
495
+ """ν…μŠ€νŠΈ λ°•μŠ€μ— μž…λ ₯된 μ—¬λŸ¬ ν‚€λ₯Ό 쀄 λ‹¨μœ„λ‘œ λΆ„μ„ν•˜κ³ , 전체 결과와 μž‘λ™ν•˜λŠ” Gemini ν‚€ λͺ©λ‘μ„ λ°˜ν™˜."""
496
  keys = [k.strip() for k in text.splitlines() if k.strip()]
497
+ if not keys:
498
+ return [], ""
499
+
500
  tasks = [process_single_key(k, rate_limit, claude_model) for k in keys]
501
  results = await asyncio.gather(*tasks)
502
+
503
+ # μž‘λ™ν•˜λŠ” Gemini ν‚€λ§Œ 필터링 (is_gemini_working ν”Œλž˜κ·Έ μ‚¬μš©)
504
+ working_gemini_keys = []
505
+ for result in results:
506
+ # is_gemini_working ν‚€κ°€ μ‘΄μž¬ν•˜κ³  True인지 확인
507
+ if result.get("is_gemini_working"): # get() μ‚¬μš©ν•˜μ—¬ ν‚€ λΆ€μž¬ μ‹œ 였λ₯˜ λ°©μ§€
508
+ # 원본 get_key_gemini_infoλŠ” 'key' ν•„λ“œλ₯Ό ν¬ν•¨ν•˜λ―€λ‘œ λ°”λ‘œ μ‚¬μš©
509
+ working_gemini_keys.append(result["key"])
510
+
511
+ # κ²°κ³Όλ₯Ό JSON용 λ¦¬μŠ€νŠΈμ™€ Gemini ν‚€ λͺ©λ‘ λ¬Έμžμ—΄λ‘œ λ°˜ν™˜
512
+ return results, "\n".join(working_gemini_keys)
513
 
514
 
515
  # ─────────────────────────────────────────
516
  # UI util
517
  # ─────────────────────────────────────────
518
+ def clear_inputs(): # μž…λ ₯ 인자 제거 (key_box 값은 ν•„μš” μ—†μŒ)
519
+ return "", "", "" # λͺ¨λ“  μž…λ ₯/좜λ ₯ μ΄ˆκΈ°ν™”
520
 
521
 
522
  # ─────────────────────────────────────────
523
+ # Gradio UI (μ—…λ°μ΄νŠΈλ¨)
524
  # ─────────────────────────────────────────
525
  with gr.Blocks() as demo:
526
  gr.Markdown(
527
  """
528
+ # Multi-API Key Status Checker (Gemini Enhanced)
529
+ *(Based on shaocongma, CncAnon1, su, Drago, kingbased key checkers)*
530
+ Check the status and details of various API keys including OpenAI, Anthropic, Gemini, Azure, Mistral, Replicate, AWS Claude, OpenRouter, Vertex AI (GCP Anthropic), Groq, NovelAI, ElevenLabs, xAI, Stability AI, and DeepSeek.
531
+
532
+ **Key Formats:**
533
+ * **AWS:** `AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY` (root might not be accurate)
534
+ * **Azure:** `RESOURCE_NAME:API_KEY` **or** `https://RESOURCE_NAME.openai.azure.com;API_KEY`
535
+ * **GCP Service Account:** `PROJECT_ID:CLIENT_EMAIL:PRIVATE_KEY` (ensure `\\n` is included for newlines in the key)
536
+ * **GCP Refresh Token:** `PROJECT_ID:CLIENT_ID:CLIENT_SECRET:REFRESH_TOKEN`
537
+ * **Other keys:** Standard format provided by the vendor.
538
  """
539
  )
540
 
 
543
  "claude-3-sonnet-20240229",
544
  "claude-3-opus-20240229",
545
  "claude-3-5-sonnet-20240620",
 
 
546
  ]
547
 
548
  with gr.Row():
549
+ with gr.Column(scale=1):
550
  key_box = gr.Textbox(
551
  lines=5,
552
  max_lines=20,
553
+ label="API Key(s) - One per line",
554
+ placeholder="Enter one API key per line here.",
 
 
 
 
 
555
  )
556
+ with gr.Row():
557
+ claude_model = gr.Dropdown(
558
+ claude_options,
559
+ value="claude-3-haiku-20240307",
560
+ label="Claude Model (for filter/concurrent check)",
561
+ scale=3
562
+ )
563
+ rate_limit = gr.Checkbox(label="Check Claude concurrent limit (exp.)", scale=1)
564
 
565
  with gr.Row():
566
+ clear_button = gr.Button("Clear All")
567
+ submit_button = gr.Button("Check Keys", variant="primary")
568
+
569
+ with gr.Column(scale=2):
570
+ info = gr.JSON(label="API Key Information (All Results)", open=True)
571
+ # Gemini μ „μš© 좜λ ₯ λ°•μŠ€ μΆ”κ°€
572
+ gemini_keys_output = gr.Textbox(
573
+ label="Working Gemini Keys",
574
+ info="Lists Gemini keys confirmed as 'Working'.",
575
+ lines=3,
576
+ max_lines=10,
577
+ interactive=False, # μ‚¬μš©μžκ°€ νŽΈμ§‘ λΆˆκ°€
578
+ )
579
 
580
+ # Clear λ²„νŠΌ 클릭 μ‹œ μž…λ ₯ λ°•μŠ€μ™€ 좜λ ₯ λ°•μŠ€ λͺ¨λ‘ μ΄ˆκΈ°ν™”
581
+ clear_button.click(
582
+ fn=clear_inputs, # μˆ˜μ •λœ ν•¨μˆ˜ μ‚¬μš©
583
+ inputs=None,
584
+ outputs=[key_box, info, gemini_keys_output]
585
+ )
586
 
587
+ # Submit λ²„νŠΌ 클릭 μ‹œ sort_keys ν•¨μˆ˜ 호좜 및 κ²°κ³Ό λΆ„λ°°
588
  submit_button.click(
589
  fn=sort_keys,
590
  inputs=[key_box, rate_limit, claude_model],
591
+ outputs=[info, gemini_keys_output], # 두 개의 좜λ ₯ μ»΄ν¬λ„ŒνŠΈμ— κ²°κ³Ό λ§€ν•‘
592
  api_name="sort_keys",
593
  )
594
 
595
+ # demo.launch(share=True) # ν•„μš”μ‹œ 곡유 링크 ν™œμ„±ν™”
596
  demo.launch()