Spaces:
Running
Running
File size: 2,333 Bytes
53ea208 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #!/usr/bin/env python3
"""Reconcile annotation files into one adjudicated row per key.
uv run python human_labeling/merge.py [--out annotations/adjudicated.jsonl]
Reads every annotations/rulings*.jsonl + annotations/*-export.json
(export format: {"items": [...]}, same ruling objects), majority-votes
ties -> "REVIEW", and writes adjudicated.jsonl:
{"key", "verdict", "n_keep", "n_drop", "annotators", "origins"?, ...}
Kept inputs are never modified; rerun any time.
"""
import argparse
import glob
import json
from pathlib import Path
HERE = Path(__file__).resolve().parent
ANNOT = HERE / "annotations"
def load() -> list[dict]:
rulings: list[dict] = []
for f in sorted(glob.glob(str(ANNOT / "rulings*.jsonl"))):
for line in open(f):
line = line.strip()
if line:
rulings.append(json.loads(line))
for f in sorted(glob.glob(str(ANNOT / "*-export.json"))):
try:
payload = json.load(open(f))
except json.JSONDecodeError:
continue
items = payload.get("items", payload if isinstance(payload, list) else [])
rulings.extend(i for i in items if isinstance(i, dict) and i.get("key"))
return rulings
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--out", default=str(ANNOT / "adjudicated.jsonl"))
a = ap.parse_args()
by_key: dict[str, list[dict]] = {}
for r in load():
by_key.setdefault(r["key"], []).append(r)
n_tie = 0
with open(a.out, "w") as f:
for key in sorted(by_key):
rs = by_key[key]
keep = sum(1 for r in rs if r["ruling"] == "DATA_MENTION")
drop = sum(1 for r in rs if r["ruling"] == "NON_MENTION")
verdict = "DATA_MENTION" if keep > drop else "NON_MENTION" if drop > keep else "REVIEW"
n_tie += verdict == "REVIEW"
f.write(json.dumps({
"key": key, "verdict": verdict, "n_keep": keep, "n_drop": drop,
"n": len(rs), "annotators": sorted({r.get("annotator", "?") for r in rs}),
"surface": rs[0].get("surface"), "origin": rs[0].get("origin"),
"head_score": rs[0].get("head_score"),
}) + "\n")
print(f"keys={len(by_key)} ties={n_tie} -> {a.out}")
if __name__ == "__main__":
main()
|