#!/usr/bin/env python3 """Combine old + new live keys, filter false positives, and run deep verification. Uses urllib instead of spawning curl subprocesses per key. """ import time import json import sys import argparse import urllib.request import urllib.error from pathlib import Path from concurrent.futures import ThreadPoolExecutor, as_completed from collections import defaultdict sys.path.insert(0, str(Path(__file__).resolve().parent)) from verify_cache import CachedVerifier RESULTS_DIR = Path(__file__).parent / "results" OLD_LIVE = RESULTS_DIR / "live_keys_raw.txt.bak" NEW_LIVE = RESULTS_DIR / "live_keys_raw.txt" COMBINED_LIVE = RESULTS_DIR / "live_keys_combined.txt" DEEP_USABLE = RESULTS_DIR / "deep_verify" / "usable.txt" DEEP_NOBAL = RESULTS_DIR / "deep_verify" / "valid_no_balance.txt" DEEP_NOACC = RESULTS_DIR / "deep_verify" / "valid_no_access.txt" DEEP_DEAD = RESULTS_DIR / "deep_verify" / "dead.txt" # ── Deep verify configs ────────────────────────────────────── DEEP_CONFIGS = { "OpenAI": { "url": "https://api.openai.com/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "Anthropic": { "url": "https://api.anthropic.com/v1/messages", "headers": {"x-api-key": "{key}", "anthropic-version": "2023-06-01", "Content-Type": "application/json"}, "body": '{"model":"claude-3-5-haiku-20241022","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "Google": { "url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={key}", "headers": {"Content-Type": "application/json"}, "body": '{"contents":[{"parts":[{"text":"hi"}]}],"generationConfig":{"maxOutputTokens":1}}', }, "Groq": { "url": "https://api.groq.com/openai/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"llama-3.1-8b-instant","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "DeepSeek": { "url": "https://api.deepseek.com/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"deepseek-chat","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "OpenRouter": { "url": "https://openrouter.ai/api/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"meta-llama/llama-3.1-8b-instruct","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "Replicate": { "url": "https://api.replicate.com/v1/account", "headers": {"Authorization": "Token {key}"}, "body": None, }, "Perplexity": { "url": "https://api.perplexity.ai/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"llama-3.1-8b-online","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "DashScope": { "url": "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"qwen-plus","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "Moonshot": { "url": "https://api.moonshot.cn/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"moonshot-v1-8k","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "VolcanoArk": { "url": "https://ark.cn-beijing.volces.com/api/v3/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"doubao-seed-2-0-pro-260215","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', "fallback": { "url": "https://ark.cn-beijing.volces.com/api/coding/v1/messages", "headers": {"x-api-key": "{key}", "anthropic-version": "2023-06-01", "Content-Type": "application/json"}, "body": '{"model":"claude-sonnet-4-6","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, }, "ZhipuAI": { "url": "https://open.bigmodel.cn/api/paas/v4/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"glm-4-flash","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "TogetherAI": { "url": "https://api.together.xyz/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"meta-llama/Llama-3.2-3B-Instruct-Turbo","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "LingyiWanwu": { "url": "https://api.lingyiwanwu.com/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"yi-large","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "StepFun": { "url": "https://api.stepfun.com/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"step-1-flash","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "SiliconFlow": { "url": "https://api.siliconflow.cn/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"Qwen/Qwen2.5-7B-Instruct","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "HuggingFace": { "url": "https://huggingface.co/api/whoami-v2", "headers": {"Authorization": "Bearer {key}"}, "body": None, }, "OllamaCloud": { "url": "https://api.ollama.com/api/chat", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"gemma4:31b","messages":[{"role":"user","content":"hi"}],"stream":false}', }, "LongCat": { "url": "https://api.longcat.chat/openai/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"LongCat-2.0","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "MiniMax": { "url": "https://api.minimaxi.com/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"MiniMax-M2.5","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, "FreeModel": { "url": "https://cc.freemodel.dev/v1/messages", "headers": {"x-api-key": "{key}", "anthropic-version": "2023-06-01", "Content-Type": "application/json"}, "body": '{"model":"claude-sonnet-4-20250514","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', "fallback": { "url": "https://api.freemodel.dev/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"claude-sonnet-4-20250514","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, }, "XKiro": { "url": "https://api.xkiro.com/v1/chat/completions", "headers": {"Authorization": "Bearer {key}", "Content-Type": "application/json"}, "body": '{"model":"anthropic/claude-sonnet-4-5","messages":[{"role":"user","content":"hi"}],"max_tokens":1}', }, } def _http_request(url, headers, body): """Send an HTTP request and return (status_code, response_body).""" data = body.encode() if body else None req = urllib.request.Request(url, data=data, headers=headers, method="POST" if body else "GET") try: with urllib.request.urlopen(req, timeout=15) as resp: return resp.getcode(), resp.read().decode("utf-8", errors="replace") except urllib.error.HTTPError as e: return e.code, e.read().decode("utf-8", errors="replace") except Exception: return 0, "" def deep_verify(provider, key): """Send actual chat completion, return USABLE/NO_BALANCE/NO_ACCESS/DEAD.""" if provider not in DEEP_CONFIGS: return "SKIP" cfg = DEEP_CONFIGS[provider] url = cfg["url"].replace("{key}", key) headers = {hname: hval.replace("{key}", key) for hname, hval in cfg["headers"].items()} code, body = _http_request(url, headers, cfg.get("body")) # Check for fallback (VolcanoArk coding plan, FreeModel) if code != 200 and "fallback" in cfg: fcfg = cfg["fallback"] furl = fcfg["url"].replace("{key}", key) fheaders = {hname: hval.replace("{key}", key) for hname, hval in fcfg["headers"].items()} code, body = _http_request(furl, fheaders, fcfg.get("body")) if code == 200: bl = body.lower() if "error" in bl and ("balance" in bl or "quota" in bl or "arrearage" in bl): return "NO_BALANCE" return "USABLE" elif code in (402, 429): return "NO_BALANCE" elif code == 404: if "invalid" in body.lower() or "unauthorized" in body.lower(): return "DEAD" return "NO_ACCESS" elif code in (401, 403): return "DEAD" elif code == 400: bl = body.lower() if any(x in bl for x in ["arrearage", "insufficient", "balance", "overdue", "payment"]): return "NO_BALANCE" elif any(x in bl for x in ["suspended", "limit", "quota", "rate"]): return "NO_BALANCE" else: return "NO_ACCESS" else: return "UNKNOWN" if code else "DEAD" def main(): ap = argparse.ArgumentParser() ap.add_argument("--workers", type=int, default=20) ap.add_argument("--limit", type=int, default=0, help="max keys to verify (0 = all)") ap.add_argument("--providers", default="all", help="comma list of providers to verify, or 'all'") ap.add_argument("--no-cache", action="store_true") args = ap.parse_args() # ── Combine old + new live keys ────────────────────────── all_keys = {} # (provider, key) -> (url, desc) for filepath in [OLD_LIVE, NEW_LIVE]: if not filepath.exists(): continue with open(filepath) as f: for line in f: line = line.strip() if not line: continue parts = line.split("|") if parts[0] == "LIVE" and len(parts) >= 4: provider, key, url = parts[1], parts[2], parts[3] desc = parts[4] if len(parts) > 4 else "" elif len(parts) >= 3: provider, key, url = parts[0], parts[1], parts[2] desc = parts[3] if len(parts) > 3 else "" else: continue if not provider or not key: continue # Filter out obvious fake/mock keys if any(x in key.lower() for x in ["mock", "xxxx", "your-", "example", "test-key", "placeholder"]): continue # Filter OpenRouter (all dead, public models endpoint) if provider == "OpenRouter": continue k = (provider, key) if k not in all_keys: all_keys[k] = (url, desc) print(f"Combined live keys: {len(all_keys)} (filtered fakes + OpenRouter)") # Write combined with open(COMBINED_LIVE, "w") as f: for (provider, key), (url, desc) in sorted(all_keys.items()): f.write(f"LIVE|{provider}|{key}|{url}|{desc}\n") # Summary by provider by_provider = defaultdict(int) for (provider, key) in all_keys: by_provider[provider] += 1 print("\nBy provider:") for p in sorted(by_provider): print(f" {p:20s}: {by_provider[p]}") # ── Deep verify ────────────────────────────────────────── to_verify = [(p, k, u, d) for (p, k), (u, d) in all_keys.items() if p in DEEP_CONFIGS] if args.providers != "all": want = set(x.strip() for x in args.providers.split(",")) to_verify = [t for t in to_verify if t[0] in want] if args.limit: to_verify = to_verify[:args.limit] print(f"\nDeep verifying {len(to_verify)} keys...") results = {"USABLE": [], "NO_BALANCE": [], "NO_ACCESS": [], "DEAD": [], "SKIP": [], "UNKNOWN": []} processed = 0 start = time.time() # Cache key = "Provider::key" — verdicts persist across nightly runs # (DEAD forever, NO_BALANCE/NO_ACCESS 6h, USABLE 30m via verify_cache). with CachedVerifier("deep_verify", lambda ck: (deep_verify(*ck.split("::", 1)), ""), force=args.no_cache) as ver: with ThreadPoolExecutor(max_workers=args.workers) as pool: futures = {pool.submit(ver, f"{p}::{k}"): (p, k, u, d) for p, k, u, d in to_verify} for future in as_completed(futures): p, k, u, d = futures[future] processed += 1 try: result, _detail = future.result() except Exception: result = "DEAD" results[result].append((p, k, u, d)) if processed % 50 == 0: elapsed = time.time() - start print(f" [{processed}/{len(to_verify)}] usable={len(results['USABLE'])} " f"nobal={len(results['NO_BALANCE'])} dead={len(results['DEAD'])} " f"({processed/elapsed:.0f}/s)") elapsed = time.time() - start print(f"\nDone in {elapsed:.1f}s") print(f" USABLE: {len(results['USABLE'])}") print(f" NO_BALANCE: {len(results['NO_BALANCE'])}") print(f" NO_ACCESS: {len(results['NO_ACCESS'])}") print(f" DEAD: {len(results['DEAD'])}") print(f" SKIP: {len(results['SKIP'])}") print(f" UNKNOWN: {len(results['UNKNOWN'])}") # Write results for category, filepath in [ ("USABLE", DEEP_USABLE), ("NO_BALANCE", DEEP_NOBAL), ("NO_ACCESS", DEEP_NOACC), ("DEAD", DEEP_DEAD), ]: with open(filepath, "w") as f: for p, k, u, d in sorted(results[category]): f.write(f"{p}|{k}|{u}|{d}\n") # Print usable keys by provider print("\n=== USABLE keys by provider ===") usable_by_provider = defaultdict(int) for p, k, u, d in results["USABLE"]: usable_by_provider[p] += 1 for p in sorted(usable_by_provider): print(f" {p:20s}: {usable_by_provider[p]}") print(f"\nUsable keys written to: {DEEP_USABLE}") if __name__ == "__main__": main()