Files
hack/tools/scripts/llm-key-hunter/recheck_no_balance.py
T

120 lines
5.1 KiB
Python

#!/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()