120 lines
5.1 KiB
Python
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() |