"""Check Toxicity-Lens against Perspective scores you already logged, before you switch. Input: a CSV or JSONL file with a `text` column and one column per Perspective attribute you logged, named TOXICITY, INSULT, ... (or perspective_TOXICITY, ...). For each attribute it prints rank agreement and, at your threshold, how many of Perspective's flags this model keeps, how many extra texts it flags, and the threshold that flags the same share of texts as Perspective did. Run: python compare_with_perspective.py logged.csv [--model abacusai/Toxicity-Lens] [--backend onnx] [--threshold 0.7] """ import argparse import csv import json import numpy as np from server import ATTRS, Scorer def rank(x): r = np.empty(len(x)) r[np.argsort(x, kind="stable")] = np.arange(len(x)) return r def main(): ap = argparse.ArgumentParser() ap.add_argument("file") ap.add_argument("--model", default="abacusai/Toxicity-Lens") ap.add_argument("--backend", default="onnx", choices=["onnx", "torch"]) ap.add_argument("--threshold", type=float, default=0.5, help="the threshold you use with Perspective") a = ap.parse_args() with open(a.file, encoding="utf-8", newline="") as f: rows = [json.loads(line) for line in f if line.strip()] if a.file.endswith(".jsonl") else list(csv.DictReader(f)) scorer = Scorer(a.model, a.backend) ours = [s for i in range(0, len(rows), 256) for s, _ in scorer([str(r["text"]) for r in rows[i:i + 256]])] t = a.threshold print(f"{len(rows)} texts, threshold {t}\n{'attribute':<18}{'n':>7}{'spearman':>10}{'persp flags':>13}{'our flags':>11}" f"{'kept':>8}{'extra':>8}{'same-rate threshold':>21}") for attr in ATTRS: col = next((c for c in (attr, f"perspective_{attr}", attr.lower(), f"perspective_{attr.lower()}") if c in rows[0]), None) keep = [i for i, r in enumerate(rows) if col and r.get(col) not in (None, "")] if len(keep) < 2: continue p = np.array([float(rows[i][col]) for i in keep]) o = np.array([ours[i][attr] for i in keep]) flag = p >= t rho = np.corrcoef(rank(p), rank(o))[0, 1] kept = f"{(o[flag] >= t).mean():.1%}" if flag.any() else "-" extra = f"{(o[~flag] >= t).mean():.1%}" if (~flag).any() else "-" same = f"{np.quantile(o, 1 - flag.mean()):.3f}" if 0 < flag.mean() < 1 else "-" print(f"{attr:<18}{len(keep):>7}{rho:>10.3f}{flag.mean():>13.1%}{(o >= t).mean():>11.1%}{kept:>8}{extra:>8}{same:>21}") print("\nkept = share of Perspective's flags this model also flags; extra = share of texts Perspective left below the threshold " "that this model flags; same-rate threshold = the threshold at which this model flags as many texts as Perspective did.") if __name__ == "__main__": main()