Wilma / scripts /length_experiment.py
winifred12's picture
Add length experiment: model classifies document shape, not fraud
23c24d1
Raw History Blame Contribute Delete
2.6 kB
import csv, json, os, time, urllib.request, urllib.error
from collections import defaultdict
API_URL = "https://winifred12-wilma.hf.space/classify"
CSV_PATH = "data/eval/length_experiment.csv"
API_KEY = os.environ.get("WILMA_API_KEY", "")
def classify(text):
body = json.dumps({"text": text}).encode()
req = urllib.request.Request(API_URL, data=body, method="POST")
req.add_header("Content-Type", "application/json")
if API_KEY:
req.add_header("Authorization", "Bearer " + API_KEY)
wait = 5
for attempt in range(5):
try:
with urllib.request.urlopen(req, timeout=60) as r:
return json.loads(r.read().decode())
except urllib.error.HTTPError as e:
if e.code == 429:
print(" rate limited, waiting %ds..." % wait)
time.sleep(wait)
wait *= 2
continue
raise
raise RuntimeError("gave up after rate limits")
rows = []
with open(CSV_PATH, newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
rows.append(row)
results = defaultdict(dict)
for i, row in enumerate(rows, 1):
print("[%d/%d] %s / %s" % (i, len(rows), row["id"], row["variant"]))
out = classify(row["text"])
label = out.get("label") or out.get("prediction") or out.get("verdict")
conf = out.get("confidence")
if conf is None:
scores = out.get("scores") or {}
conf = max(scores.values()) if scores else 0.0
results[row["id"]][row["variant"]] = {
"label": str(label),
"conf": float(conf),
"chars": len(row["text"]),
}
time.sleep(1)
ORDER = ["short", "medium", "long"]
print("")
print("=" * 78)
print("SAME SCAM, THREE LENGTHS")
print("=" * 78)
print("%-10s %-26s %-26s %-26s" % ("id", "short", "medium", "long"))
for rid in results:
cells = []
for v in ORDER:
d = results[rid].get(v)
cells.append("%s %.3f (%dch)" % (d["label"], d["conf"], d["chars"]) if d else "-")
print("%-10s %-26s %-26s %-26s" % (rid, cells[0], cells[1], cells[2]))
print("")
print("=" * 78)
print("DETECTION RATE BY LENGTH")
print("=" * 78)
for v in ORDER:
ds = [results[r][v] for r in results if v in results[r]]
if not ds:
continue
hits = sum(1 for d in ds if d["label"].lower() not in ("legitimate", "ham", "safe", "not_scam"))
print("%-8s detected %d/%d (%.0f%%) mean conf %.3f mean length %d chars" % (
v, hits, len(ds), 100.0 * hits / len(ds),
sum(d["conf"] for d in ds) / len(ds),
sum(d["chars"] for d in ds) / len(ds)))