Plaiglab / scripts /score_daigt.py
SanidhyaDhangar's picture
PlaigLab β€” Hugging Face Space (Docker) clean deploy
ebebfe8
Raw
History Blame Contribute Delete
3.25 kB
"""Score DAIGT essays (real human + real multi-LLM AI text) through the 7-detector
ensemble to produce IN-DOMAIN calibration rows β€” the humanised-AI positives the
HC3-only meta never had (roadmap U1, the Ollama alternative: download real
LLM-written essays instead of generating them).
DAIGT: thedrcat/daigt-v2-train-dataset β€” columns text, label (0=human, 1=AI),
source (model). We sample a balanced, length-filtered subset so every essay
fires all seven detectors, then score.
Output: data/calibration/daigt_scored.jsonl (schema: {y, x:[7], src})
Run: python scripts/score_daigt.py [n_per_class] (default 250)
"""
import glob
import json
import os
import random
import sys
import time
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT)
from plagdetect.aidetect import FEATURE_ORDER, detect_ai # noqa: E402
from plagdetect.normalize import deobfuscate # noqa: E402
from plagdetect.textutils import sentences # noqa: E402
CSV = glob.glob(os.path.join(
os.path.expanduser("~"), ".cache", "kagglehub", "datasets", "thedrcat",
"daigt-v2-train-dataset", "versions", "*", "*.csv"))
OUT = os.path.join(ROOT, "data", "calibration", "daigt_scored.jsonl")
MIN_CHARS, MIN_SENTS = 700, 8
def load_balanced(n_per_class, seed=13):
import pandas as pd
df = pd.read_csv(sorted(CSV)[-1], usecols=["text", "label"])
rng = random.Random(seed)
pools = {0: [], 1: []}
idx = list(range(len(df)))
rng.shuffle(idx)
for i in idx:
lab = int(df.iloc[i]["label"])
if lab not in (0, 1) or len(pools[lab]) >= n_per_class:
continue
t = str(df.iloc[i]["text"] or "").strip()
if len(t) >= MIN_CHARS and len(sentences(t)) >= MIN_SENTS:
pools[lab].append(t)
if len(pools[0]) >= n_per_class and len(pools[1]) >= n_per_class:
break
return pools[0], pools[1]
def score_all(texts, label):
rows, t0 = [], time.time()
for i, t in enumerate(texts):
t = deobfuscate(t)[0]
try:
r = detect_ai(t)
except Exception as exc:
print(" [skip]", exc); continue
det = {d["name"]: d["score"] for d in r["detectors"]}
if not all(k in det for k in FEATURE_ORDER):
continue
rows.append({"y": label, "x": [det[k] for k in FEATURE_ORDER],
"src": "daigt"})
if (i + 1) % 25 == 0:
rate = (i + 1) / (time.time() - t0)
print(f" label={label}: {i+1}/{len(texts)} "
f"({rate:.2f}/s, eta {(len(texts)-i-1)/max(rate,1e-9):.0f}s)",
flush=True)
return rows
def main(n_per_class=250):
if not CSV:
print("DAIGT csv not found β€” download via kagglehub first."); return
print("loading + length-filtering DAIGT...")
human, ai = load_balanced(n_per_class)
print(f"human={len(human)} ai={len(ai)} β€” scoring through 7 detectors")
rows = score_all(human, 0) + score_all(ai, 1)
with open(OUT, "w", encoding="utf-8") as f:
for r in rows:
f.write(json.dumps(r) + "\n")
print(f"saved {len(rows)} DAIGT rows -> {OUT}")
if __name__ == "__main__":
main(int(sys.argv[1]) if len(sys.argv) > 1 else 250)