Chris Leo commited on
Commit
1da0020
·
verified ·
1 Parent(s): b47deb0

scorevision: push artifact

Browse files
Files changed (1) hide show
  1. training/poll_manako.py +132 -0
training/poll_manako.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Continuous poller for in-domain frames from the manako/scoredata API for Detect-crime.
3
+
4
+ The console.scorevision.io endpoint surfaces ONE `latestAnnotatedChallenge` per element.
5
+ As the runner produces new challenges this single record rotates. By polling every couple
6
+ of minutes we accumulate distinct in-domain frames + the king's predictions for each.
7
+
8
+ Use this as a long-running collector alongside `build_dataset.py`. Run it for a few hours
9
+ or days, then re-run `build_dataset.py --extra-dir <out>/images` (or `--manako`) to fold
10
+ the new frames into the YOLO dataset.
11
+
12
+ Usage:
13
+ python poll_manako.py --out ./manako_pool --interval 120 --hours 8
14
+ python poll_manako.py --out ./manako_pool --interval 120 --forever # until killed
15
+
16
+ Output structure (each unique frame = one image + one preds JSON):
17
+ manako_pool/
18
+ images/manako_ch{cid}_f{fid}_{sha16}.png
19
+ preds/ manako_ch{cid}_f{fid}_{sha16}.json
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import argparse
25
+ import hashlib
26
+ import json
27
+ import sys
28
+ import time
29
+ from pathlib import Path
30
+ from urllib.parse import quote
31
+ from urllib.request import Request, urlopen
32
+
33
+ API = "https://console.scorevision.io/api/v2"
34
+ ELEMENT_ID = "manak0/Detect-crime"
35
+
36
+
37
+ def http_get(url: str, timeout: int = 30, retries: int = 3) -> bytes:
38
+ last = None
39
+ for i in range(retries):
40
+ try:
41
+ req = Request(url, headers={"User-Agent": "poll_manako/1.0"})
42
+ with urlopen(req, timeout=timeout) as r:
43
+ return r.read()
44
+ except Exception as e:
45
+ last = e
46
+ time.sleep(1.0 * (i + 1))
47
+ raise last # type: ignore
48
+
49
+
50
+ def sha16(b: bytes) -> str:
51
+ return hashlib.sha256(b).hexdigest()[:16]
52
+
53
+
54
+ def main() -> int:
55
+ ap = argparse.ArgumentParser()
56
+ ap.add_argument("--out", required=True, help="output dir for accumulated frames")
57
+ ap.add_argument("--interval", type=int, default=120, help="seconds between polls")
58
+ ap.add_argument("--hours", type=float, default=4.0, help="duration to run (ignored with --forever)")
59
+ ap.add_argument("--forever", action="store_true", help="run until killed")
60
+ args = ap.parse_args()
61
+
62
+ out = Path(args.out).resolve()
63
+ img_dir = out / "images"
64
+ pred_dir = out / "preds"
65
+ img_dir.mkdir(parents=True, exist_ok=True)
66
+ pred_dir.mkdir(parents=True, exist_ok=True)
67
+
68
+ deadline = time.time() + args.hours * 3600 if not args.forever else float("inf")
69
+ seen: set[str] = {p.stem.rsplit("_", 1)[-1] for p in img_dir.glob("manako_*.png")}
70
+ n_polls = 0
71
+ n_new = 0
72
+ print(f"[poll] starting; existing frames in pool: {len(seen)}", file=sys.stderr)
73
+
74
+ while time.time() < deadline:
75
+ n_polls += 1
76
+ try:
77
+ raw = http_get(f"{API}/elements/{quote(ELEMENT_ID, safe='')}?lookback_days=7")
78
+ except Exception as e:
79
+ print(f"[poll {n_polls}] API error: {e}", file=sys.stderr)
80
+ time.sleep(args.interval)
81
+ continue
82
+
83
+ elt = json.loads(raw)
84
+ lac = elt.get("latestAnnotatedChallenge")
85
+ if not lac:
86
+ print(f"[poll {n_polls}] no latestAnnotatedChallenge", file=sys.stderr)
87
+ time.sleep(args.interval)
88
+ continue
89
+
90
+ challenge_id = lac.get("challenge_id")
91
+ frames = (lac.get("response") or {}).get("frames") or []
92
+ preds = ((lac.get("response") or {}).get("predictions") or {}).get("frames") or []
93
+ preds_by_id = {p.get("frame_id"): p for p in preds}
94
+
95
+ added = 0
96
+ for f in frames:
97
+ url = f.get("url")
98
+ fid = f.get("frame_id")
99
+ if not url:
100
+ continue
101
+ try:
102
+ data = http_get(url)
103
+ except Exception as e:
104
+ print(f"[poll] image fetch failed {url}: {e}", file=sys.stderr)
105
+ continue
106
+ digest = sha16(data)
107
+ if digest in seen:
108
+ continue
109
+ seen.add(digest)
110
+ (img_dir / f"manako_ch{challenge_id}_f{fid}_{digest}.png").write_bytes(data)
111
+ preds_obj = preds_by_id.get(fid)
112
+ if preds_obj is not None:
113
+ (pred_dir / f"manako_ch{challenge_id}_f{fid}_{digest}.json").write_text(
114
+ json.dumps(preds_obj), encoding="utf-8"
115
+ )
116
+ added += 1
117
+ n_new += 1
118
+
119
+ print(f"[poll {n_polls}] cid={challenge_id} frames={len(frames)} new={added} "
120
+ f"total_unique={len(seen)} (cumulative new this run: {n_new})", file=sys.stderr)
121
+
122
+ if time.time() >= deadline:
123
+ break
124
+ time.sleep(args.interval)
125
+
126
+ print(f"[poll] done. polls={n_polls}, new frames added this run: {n_new}, "
127
+ f"pool size: {len(seen)}", file=sys.stderr)
128
+ return 0
129
+
130
+
131
+ if __name__ == "__main__":
132
+ raise SystemExit(main())