#!/usr/bin/env python3 """Recheck DeepSeek no_balance keys for revived accounts (recharge). For each key: GET /user/balance -> if available & balance>0 -> POST /chat/completions. Only real chat 200 with choices = REVIVED (golden rule). """ import json, pathlib, urllib.request, urllib.error, time from concurrent.futures import ThreadPoolExecutor, as_completed HERE = pathlib.Path(__file__).resolve().parent SRC = HERE / "results/deepseek_v2/no_balance.txt" OUTDIR = HERE / "results/deepseek_v2/revive_check" OUTDIR.mkdir(parents=True, exist_ok=True) def get_balance(key): req = urllib.request.Request("https://api.deepseek.com/user/balance", headers={"Authorization": f"Bearer {key}"}) with urllib.request.urlopen(req, timeout=20) as r: return json.loads(r.read()) def chat(key): req = urllib.request.Request( "https://api.deepseek.com/chat/completions", data=json.dumps({"model": "deepseek-chat", "messages": [{"role": "user", "content": "hi"}], "max_tokens": 8}).encode(), headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}) with urllib.request.urlopen(req, timeout=30) as r: return json.loads(r.read()) def check(item): key, src = item try: bal = get_balance(key) infos = bal.get("balance_infos") or [] if not bal.get("is_available"): return (key, src, "dead_or_suspended", 0.0, "CNY", "") cur = infos[0]["currency"] if infos else "CNY" total = float(infos[0].get("total_balance") or 0.0) if infos else 0.0 if total <= 0: return (key, src, "still_empty", 0.0, cur, "") # has balance -> real chat try: c = chat(key) if c.get("choices"): return (key, src, "REVIVED", total, cur, f"chat 200 model={c.get('model')}") return (key, src, "chat_no_choices", total, cur, "") except urllib.error.HTTPError as e: return (key, src, f"chat_err_{e.code}", total, cur, "") except Exception as e: return (key, src, f"chat_net_{type(e).__name__}", total, cur, "") except urllib.error.HTTPError as e: return (key, src, f"http_{e.code}", 0.0, "CNY", "") except Exception as e: return (key, src, f"net_{type(e).__name__}", 0.0, "CNY", "") def main(): items = [] for line in SRC.read_text().splitlines(): parts = line.split("|") if len(parts) >= 2 and parts[0].startswith("sk-"): items.append((parts[0], parts[1])) print(f"rechecking {len(items)} no-balance keys ...", flush=True) buckets = {} for name in ["REVIVED", "still_empty", "dead_or_suspended", "chat_err_402", "chat_err_429", "chat_err_403", "chat_err_other", "chat_no_choices", "chat_net_err", "http_401", "http_other", "net_err"]: buckets[name] = [] with ThreadPoolExecutor(max_workers=32) as ex: futs = [ex.submit(check, it) for it in items] done = 0 for f in as_completed(futs): key, src, status, bal, cur, extra = f.result() if status == "REVIVED": buckets["REVIVED"].append((key, src, bal, cur, extra)) elif status.startswith("chat_err_402"): buckets["chat_err_402"].append((key, src)) elif status.startswith("chat_err_429"): buckets["chat_err_429"].append((key, src)) elif status.startswith("chat_err_403"): buckets["chat_err_403"].append((key, src)) elif status.startswith("chat_err_"): buckets["chat_err_other"].append((key, src)) elif status == "chat_no_choices": buckets["chat_no_choices"].append((key, src)) elif status.startswith("chat_net_"): buckets["chat_net_err"].append((key, src)) elif status == "http_401": buckets["http_401"].append((key, src)) elif status.startswith("http_"): buckets["http_other"].append((key, src)) elif status == "dead_or_suspended": buckets["dead_or_suspended"].append((key, src)) elif status == "still_empty": buckets["still_empty"].append((key, src)) else: buckets["net_err"].append((key, src)) done += 1 if done % 100 == 0: print(f" {done}/{len(items)}", flush=True) for name, rows in buckets.items(): pathlib.Path(OUTDIR / f"{name}.txt").write_text( "\n".join(f"{k}|{s}" + (f"|{cur} {bal:.2f}|{extra}" if name == "REVIVED" else "") for k, s, *rest in rows) + ("\n" if rows else "")) print("\n=== RESULT ===") for name, rows in buckets.items(): if rows: print(f" {name}: {len(rows)}") revived = buckets["REVIVED"] if revived: print("\n=== REVIVED (real chat 200) ===") for k, s, bal, cur, extra in sorted(revived, key=lambda r: -r[2]): print(f" {k} {cur} {bal:.2f} {s[:80]}") print(f"\ndone -> {OUTDIR}") if __name__ == "__main__": main()