import asyncio import gradio as gr import requests, re # …(생략)… # ──────────────────────────────────── # 1. 단일 키 처리 함수로 기존 로직 이동 # ──────────────────────────────────── async def process_single_key(key, rate_limit, claude_model): _key = key.strip() if re.match(re.compile("sk-or-v1-[a-z0-9]{64}"), _key): return {"key": _key, **get_key_openrouter_info(_key)} if re.match(re.compile("sk-ant-api03-[a-zA-Z0-9\\-_]{93}AA"), _key) or ( _key.startswith("sk-ant-") and len(_key) == 93 ) or (len(_key) == 89 and re.match(re.compile("sk-[a-zA-Z0-9]{86}"), _key)): return {"key": _key, **await get_key_ant_info(_key, rate_limit, claude_model)} if re.match(re.compile(r"sk-[a-zA-Z0-9]{48}"), _key) and len(_key) == 51 and "T3BlbkFJ" not in _key: return {"key": _key, **get_key_stability_info(_key)} if re.match(re.compile(r"sk-[a-f0-9]{32}"), _key): return {"key": _key, **get_key_deepseek_info(_key)} if _key.startswith("sk-"): return {"key": _key, **get_key_oai_info(_key)} if _key.startswith("AIzaSy"): return {"key": _key, **get_key_gemini_info(_key)} if _key.startswith("pst-"): return {"key": _key, **get_key_nai_info(_key)} if (_key.startswith("r8_") and len(_key) == 40) or (_key.islower() and len(_key) == 40): return {"key": _key, **get_key_replicate_info(_key)} if _key.startswith("xai-"): return {"key": _key, **get_key_xai_info(_key)} 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]: endpoint, api_key = _key.split(":") return {"key": _key, **get_key_azure_info(endpoint, api_key)} if "openai.azure.com" in _key.split(";")[0]: endpoint, api_key = _key.split(";") return {"key": _key, **get_key_azure_info(endpoint, api_key)} if _key.startswith("AKIA") and len(_key.split(":")[0]) == 20 and _key.split(":")[0].isupper(): return {"key": _key, **await get_key_aws_info(_key)} if re.match(re.compile(r"[a-f0-9]{32}"), _key) or re.match(re.compile(r"sk_[a-f0-9]{48}"), _key): return {"key": _key, **get_key_elevenlabs_info(_key)} if re.match(re.compile(r"[a-zA-Z0-9]{32}"), _key): return {"key": _key, **get_key_mistral_info(_key)} if re.match(re.compile(r"gsk_[a-zA-Z0-9]{20}WGdyb3FY[a-zA-Z0-9]{24}"), _key): return {"key": _key, **get_key_groq_info(_key)} if re.match(re.compile(r"[\\w\\-]+:[\\w\\-@\\.]+:[\\w-]+:.+"), _key): return {"key": _key, **await get_key_gcp_info(_key, 0)} if re.match(re.compile(r"[\\w\\-]+:[\\w\\-@\\.]+:.+\\n"), _key): return {"key": _key, **await get_key_gcp_info(_key, 1)} return {"key": _key, **not_supported(_key)} # ──────────────────────────────────── # 2. 여러 키 한꺼번에 처리 # ──────────────────────────────────── async def sort_keys(text, rate_limit, claude_model): keys = [k for k in text.splitlines() if k.strip()] tasks = [process_single_key(k, rate_limit, claude_model) for k in keys] results = await asyncio.gather(*tasks) return results # JSON 컴포넌트가 리스트도 잘 보여줌 def clear_inputs(text): # 그대로 return "" # ──────────────────────────────────── # 3. UI – 입력창 줄 수 늘리고, 새 함수 연결 # ──────────────────────────────────── with gr.Blocks() as demo: gr.Markdown( """ # … (중략) … """ ) claude_options = [ "claude-3-haiku-20240307", "claude-3-sonnet-20240229", "claude-3-opus-20240229", "claude-3-5-sonnet-20240620", "claude-3-5-sonnet-20241022", "claude-3-5-haiku-20241022", ] with gr.Row(): with gr.Column(): key = gr.Textbox( lines=5, # 여러 줄 입력 max_lines=20, label="API Key(s) — 줄바꿈으로 여러 개 입력", ) claude_model = gr.Dropdown( claude_options, value="claude-3-haiku-20240307", label="Claude API model (rate-limit check용)", ) rate_limit = gr.Checkbox(label="Check concurrent rate limit (Claude, experimental)") with gr.Row(): clear_button = gr.Button("Clear") submit_button = gr.Button("Submit", variant="primary") with gr.Column(): info = gr.JSON(label="API Key Information", open=True) clear_button.click(fn=clear_inputs, inputs=[key], outputs=[key]) submit_button.click(fn=sort_keys, inputs=[key, rate_limit, claude_model], outputs=[info], api_name="sort_keys") demo.launch()