rafmacalaba/data-use-annotate
0
1#!/usr/bin/env python32"""Group scored flat pool items into passage examples (multi-mention).3 4Reads the flat rescored queue (build_pool_queue.py → rescore_singlepass.py)5and emits one JSON object per distinct (origin, ctx):6 7 {queue, origin, ctx, n, band, scored_by,8 mentions: [{key, surface, start, end, head_score, band}...]} # by start9 10Passages with one mention stay as-is; multi stays multi — the UI drives11them as one example with a per-mention ruling target. The passage-level12band is the most-informative mention state:13 14 unscored any unscored15 confusion any confusion16 mixed keep + drop, no confusion17 else the single uniform band18 19 uv run python human_labeling/build_passage_queue.py \20 [--input human_labeling/queue.json] [--out human_labeling/queue_passages.json]21"""22 23import argparse24import json25from collections import defaultdict26from pathlib import Path27 28HERE = Path(__file__).resolve().parent29 30 31def passage_band(mentions: list[dict]) -> str:32 bands = {m.get("band") for m in mentions}33 if "unscored" in bands:34 return "unscored"35 if "confusion" in bands:36 return "confusion"37 if len(bands) == 1:38 return bands.pop()39 return "mixed"40 41 42def main() -> None:43 ap = argparse.ArgumentParser()44 ap.add_argument("--input", default=str(HERE / "queue.json"))45 ap.add_argument("--out", default=str(HERE / "queue_passages.json"))46 a = ap.parse_args()47 48 groups: dict[tuple, list[dict]] = defaultdict(list)49 for line in Path(a.input).read_text().splitlines():50 if not line.strip():51 continue52 r = json.loads(line)53 if r.get("ctx"):54 groups[(r.get("origin"), r["ctx"])].append(r)55 56 passages = []57 for (origin, ctx), rows in groups.items():58 mentions = sorted(59 ({"key": r["key"], "surface": r.get("surface"),60 "start": r.get("start"), "end": r.get("end"),61 "head_score": r.get("head_score"), "band": r.get("band")}62 for r in rows),63 key=lambda m: (m["start"] if isinstance(m["start"], int) else 0,64 m["surface"] or ""))65 passages.append({66 "queue": "probe_candidates/passages",67 "origin": origin, "ctx": ctx, "n": len(mentions),68 "band": passage_band(mentions), "mentions": mentions,69 "scored_by": rows[0].get("scored_by"),70 })71 72 passages.sort(key=lambda p: (p["origin"] or "", p["ctx"] or ""))73 Path(a.out).write_text(74 "\n".join(json.dumps(p) for p in passages) + "\n")75 n_multi = sum(1 for p in passages if p["n"] > 1)76 from collections import Counter77 print(f"passages={len(passages)} multi={n_multi} "78 f"{Counter(p['band'] for p in passages)} -> {a.out}")79 80 81if __name__ == "__main__":82 main()