Download scripts/run_eval.py from dmth10/tell: direct link, hf CLI and curl.
- Browser
- Download file 3.51 kB
-
https://huggingface.co/spaces/dmth10/tell/resolve/main/scripts/run_eval.py
- Command line
-
hf download hf://spaces/dmth10/tell/scripts/run_eval.py
-
curl -L -o run_eval.py https://huggingface.co/spaces/dmth10/tell/resolve/main/scripts/run_eval.py
3.51 kB
| """ | |
| Runs every post in eval/posts.json through TELL's text tools and scores it. | |
| python scripts/run_eval.py # language + number tricks only (free) | |
| python scripts/run_eval.py --trace # also source tracing (costs money, see estimate) | |
| python scripts/run_eval.py --only pratt-zero-votes | |
| Writes eval/results.csv and prints the numbers that go in TRAINING.md. | |
| Scoring uses expected_tricks, which you fill in by hand after reviewing suggested_tricks. | |
| """ | |
| import argparse | |
| import csv | |
| import json | |
| import sys | |
| from collections import defaultdict | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parent.parent | |
| sys.path.insert(0, str(ROOT)) | |
| try: | |
| from dotenv import load_dotenv | |
| load_dotenv(ROOT / ".env") | |
| except ImportError: | |
| pass | |
| import features # noqa: F401,E402 | |
| from core import pipeline # noqa: E402 | |
| from core.post import Post # noqa: E402 | |
| COST_PER_POST_WITH_TRACE = 0.12 # worst case: 3 claims x 4 searches x $0.01 | |
| def score(found: set, expected: set): | |
| return len(found & expected), len(expected - found), len(found - expected) | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--trace", action="store_true", help="also trace claims to sources") | |
| ap.add_argument("--only", help="run one post by id") | |
| args = ap.parse_args() | |
| posts = json.loads((ROOT / "eval" / "posts.json").read_text())["posts"] | |
| if args.only: | |
| posts = [p for p in posts if p["id"] == args.only] | |
| if args.trace: | |
| print(f"Source tracing on: up to ${COST_PER_POST_WITH_TRACE * len(posts):.2f} for {len(posts)} posts.") | |
| if input("Go? [y/N] ").strip().lower() != "y": | |
| return | |
| unreviewed = [p["id"] for p in posts if not p.get("expected_tricks") and p.get("suggested_tricks")] | |
| if unreviewed: | |
| print(f"Note: {len(unreviewed)} posts have no expected_tricks yet, so they score as all false alarms.\n") | |
| rows = [] | |
| totals = defaultdict(lambda: [0, 0, 0, 0]) # group -> hits, misses, false alarms, posts | |
| for p in posts: | |
| report = pipeline.run(Post(text=p["text"]), {"trace": args.trace}) | |
| found = {f["trick"] for f in report.findings} | |
| expected = set(p.get("expected_tricks", [])) | |
| hit, miss, fa = score(found, expected) | |
| group = "control" if p.get("control") else p["favors"].split(" ")[0] | |
| t = totals[group] | |
| t[0] += hit; t[1] += miss; t[2] += fa; t[3] += 1 | |
| verdicts = [c["verdict"] for s in report.sections for c in s.claim_checks] | |
| rows.append({ | |
| "id": p["id"], "group": group, | |
| "found": ";".join(sorted(found)), "expected": ";".join(sorted(expected)), | |
| "hits": hit, "misses": miss, "false_alarms": fa, | |
| "trace_verdicts": ";".join(verdicts), "expected_trace": p.get("expected_trace", ""), | |
| }) | |
| print(f"{p['id']:30s} found={sorted(found)} hits={hit} miss={miss} fa={fa} {verdicts or ''}") | |
| out = ROOT / "eval" / "results.csv" | |
| with out.open("w", newline="") as f: | |
| w = csv.DictWriter(f, fieldnames=rows[0].keys()) | |
| w.writeheader() | |
| w.writerows(rows) | |
| print("\ngroup posts hits misses false_alarms flags/post") | |
| for g, (h, m, fa, n) in sorted(totals.items()): | |
| print(f"{g:12s} {n:5d} {h:5d} {m:7d} {fa:13d} {(h + fa) / n:11.2f}") | |
| print("\nIf flags/post is a lot higher for one side than the other on similar posts, look at why.") | |
| print(f"Saved {out.relative_to(ROOT)}") | |
| if __name__ == "__main__": | |
| main() | |