Buckets:
| #!/usr/bin/env python3 | |
| """tools/review_tool/build_relabel_pass.py — second, independent labelling pass for the automatic hand_return labels (owner request 2026-09-16: | |
| "engaged hand_return 0.559 / manual hand_return 0.765 — 我有可能看错了, 请你让我重新标注一下"). | |
| Builds results/review_tool/{relabel_hr.html,items_relabel_hr.json} from the EXISTING items.json / img/ (no frame extraction, read-only on data): | |
| * the 68 Task-B hand_return items (engaged 34 first, then manual 34), new ids <id>__r2 so the first-pass labels are neither shown nor overwritten; | |
| * a separate localStorage key; server sync via the same /save and /labels endpoints of serve_review.py (port 8791); | |
| * an explicit definition of hand_return and re-worded options. | |
| First-pass labels stay in labels.jsonl / labels_latest.json (snapshot labels_latest_pass1_<utc>.json); apply_review.py --pass2 reads the __r2 labels. | |
| """ | |
| from __future__ import annotations | |
| import argparse, json, sys, time | |
| from pathlib import Path | |
| CWM3 = Path(__file__).resolve().parents[2] | |
| sys.path.insert(0, str(Path(__file__).resolve().parent)) | |
| from build_review_tool import HTML # noqa: E402 | |
| SUFFIX = "__r2" | |
| DEF_CN = ("<b>hand_return(手回到方向盘)</b>的定义:自动标签认为在<b>中间帧(dt = 0)</b>驾驶员的手从" | |
| "<b>离开方向盘</b>变为<b>放回方向盘</b>。前两帧(−1.0 s、−0.5 s)应当至少一只手<b>不在</b>方向盘上;从中间帧起(0、+0.5、+1.0 s)手应当<b>握在/放在</b>方向盘上。" | |
| "只看手,不看头部;红框只是标出驾驭员。这一页<b>不显示</b>你上次的答案,请独立判断;备注仍可写 phone 等。") | |
| OPTS_B_NEW = ("B:[['correct','正确:前面手不在盘上,中间帧(±0.5 s 内)手回到盘上']," | |
| "['wrong','错误:中间帧附近没有“手回到盘上”(手一直在盘上 / 一直不在盘上 / 握手机或放在盘旁却没握盘)']," | |
| "['timing','时间偏差:确有回盘,但比中间帧早或晚超过 0.5 s'],['unsure','不确定 / 看不清']]") | |
| def main(argv=None) -> int: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--out", default=str(CWM3 / "results/review_tool")) | |
| ap.add_argument("--event", default="hand_return") | |
| a = ap.parse_args(argv) | |
| out = Path(a.out) | |
| src = json.load(open(out / "items.json", encoding="utf-8"))["items"] | |
| sel = [i for i in src if i["task"] == "B" and i["meta"]["event"] == a.event] | |
| sel.sort(key=lambda i: (0 if i["meta"]["regime"] == "engaged" else 1, i["id"])) | |
| items = [] | |
| for i in sel: | |
| m = dict(i["meta"]); m["pass"] = 2; m["orig_id"] = i["id"] | |
| items.append({"id": i["id"] + SUFFIX, "task": "B", "meta": m, "frames": i["frames"]}) | |
| n_e = sum(i["meta"]["regime"] == "engaged" for i in items) | |
| ts = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) | |
| json.dump({"built_utc": ts, "pass": 2, "event": a.event, "source_items": "items.json", "n_items": len(items), "items": items}, | |
| open(out / "items_relabel_hr.json", "w", encoding="utf-8"), indent=1, ensure_ascii=False) | |
| html = HTML | |
| reps = [ | |
| ("const KEY = 'cwm3_review_v1';", "const KEY = 'cwm3_review_relabel_hr_v1';"), | |
| ("B:[['correct','正确:事件发生在中间帧附近'],['wrong','错误:没有该事件'],['timing','时间偏差 >0.5 s'],['unsure','不确定/看不清']]", OPTS_B_NEW), | |
| ("let tab = 'A', cur = 0;", "let tab = 'B', cur = 0;"), | |
| ("<title>CockpitWM 人工核验</title>", "<title>CockpitWM 复核:hand_return</title>"), | |
| (" <b>CockpitWM 人工核验</b>\n <span class=\"tab active\" data-tab=\"A\" onclick=\"setTab('A')\">A 司机/乘客核验</span>\n <span class=\"tab\" data-tab=\"B\" onclick=\"setTab('B')\">B 自动标签验证</span>", | |
| f" <b>CockpitWM 复核(第 2 轮):hand_return</b>\n <span class=\"tab active\" data-tab=\"B\">第一部分 engaged {n_e} 条 → 第二部分 manual {len(items) - n_e} 条</span>"), | |
| ("<main id=\"main\"></main>", f"<div class=\"item\" style=\"margin:12px 16px;max-width:1500px;background:#fff8e1;border-color:#e0b400\">{DEF_CN}</div>\n<main id=\"main\"></main>"), | |
| (" if(r.rater && !store._rater) store._rater=r.rater;", ""), # do not inherit the first-pass rater string ('assistant' = server test ping) | |
| ("`自动标签:<b>${it.meta.event_cn}</b>,标注时刻 = 中间帧(EVENT,t=${it.meta.t_event.toFixed(1)} s,${it.meta.regime})。这个事件是否真实发生?`", | |
| "`第 ${idx+1}/${items().length} 条(<b>${it.meta.regime}</b>)· 自动标签:<b>手回到方向盘</b>,标注时刻 = 中间帧(EVENT,t=${it.meta.t_event.toFixed(1)} s)。前两帧手不在盘上、从中间帧起手在盘上吗?`"), | |
| ] | |
| for old, new in reps: | |
| assert old in html, f"template anchor not found: {old[:60]}" | |
| html = html.replace(old, new) | |
| html = html.replace("__ITEMS__", json.dumps(items, ensure_ascii=False)) | |
| (out / "relabel_hr.html").write_text(html, encoding="utf-8") | |
| print(f"relabel pass built: {len(items)} items ({n_e} engaged, {len(items) - n_e} manual) -> {out / 'relabel_hr.html'}, {out / 'items_relabel_hr.json'}") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |
Xet Storage Details
- Size:
- 5.32 kB
- Xet hash:
- b84dfaae4d002ea6d6e05fc2c16637525692cf47c6c962bf799f2813ed18d5e4
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.