| |
| |
| |
| |
| |
| |
| |
| |
| import argparse |
| import glob |
| import json |
| import os |
|
|
| from humomni.core.streaming_driver import _emissions |
|
|
|
|
| def make_policy(name): |
| """A fresh policy per sample (no state leak). Imported lazily β each pulls heavy deps.""" |
| if name == "api": |
| from humomni.phase1.policy_api import APIPolicy |
| config = json.load(open("config.json", encoding="utf-8")) |
| return lambda: APIPolicy(config=config) |
| raise SystemExit(f"unknown policy: {name!r} (use 'api')") |
|
|
|
|
| def _video_length(sample_dir): |
| """The latest frame timestamp present β the 'video_length' the loop steps up to (frames sit on a |
| 0.5 s grid: 0.5.jpg, 1.0.jpg, β¦).""" |
| ts = [] |
| for p in glob.glob(os.path.join(sample_dir, "*.jpg")): |
| try: |
| ts.append(float(os.path.basename(p)[:-4])) |
| except ValueError: |
| pass |
| return max(ts) if ts else 0.0 |
|
|
|
|
| def infer_one(sample_dir, policy): |
| """One sample, matching the competition inference pseudocode: |
| |
| input(question) |
| for current_time in range(0.5, video_length, 0.5): |
| input(f"{current_time}.png") # frames at t > current_time are PROHIBITED |
| if respond_now: output(... @ current_time) |
| |
| The policy gets one frame per tick, in ascending time, and never sees t > current_time. |
| policy.step() may return None / a str / a list of strs β one frame can emit several answers |
| (the v5+v3 ensemble); we append each AT current_time, exactly like streaming_driver.drive(). |
| A transient failure returns an empty-but-present record (the run never aborts and every id |
| stays); a causality AssertionError is not caught. No retry/resume/parallelism β that's |
| run_inference.py. |
| """ |
| with open(os.path.join(sample_dir, "question.json"), encoding="utf-8") as f: |
| q = json.load(f) |
| question, qid = q["question"], q["question_id"] |
| try: |
| policy.reset(question=question) |
| responses, last_t = [], -1.0 |
| video_length = _video_length(sample_dir) |
| for step in range(1, int(round(video_length / 0.5)) + 1): |
| current_time = step * 0.5 |
| frame_path = os.path.join(sample_dir, f"{current_time:.1f}.jpg") |
| if not os.path.exists(frame_path): |
| continue |
| assert current_time > last_t, "frames must arrive in order (no future frames)" |
| last_t = current_time |
| reply = policy.step(current_time, frame_path) |
| for content in _emissions(reply): |
| responses.append({"time": current_time, "content": content}) |
| return {"question_id": qid, "model_response_list": responses} |
| except AssertionError: |
| raise |
| except Exception as e: |
| print(f" ! {qid} failed ({type(e).__name__}: {str(e)[:80]}) β empty record") |
| return {"question_id": qid, "model_response_list": []} |
|
|
|
|
| def main(): |
| ap = argparse.ArgumentParser() |
| ap.add_argument("--policy", choices=["api"], default="api") |
| ap.add_argument("--data_dir", default="data/phase1/data") |
| ap.add_argument("--out", default="submission.jsonl") |
| a = ap.parse_args() |
|
|
| new_policy = make_policy(a.policy) |
| dirs = [d for d in sorted(glob.glob(os.path.join(a.data_dir, "*"))) if os.path.isdir(d)] |
| total = len(dirs) |
| with open(a.out, "w", encoding="utf-8") as w: |
| for i, sample_dir in enumerate(dirs, 1): |
| rec = infer_one(sample_dir, new_policy()) |
| w.write(json.dumps(rec, ensure_ascii=False) + "\n") |
| print(f"[{i}/{total}] {rec['question_id']} -> {len(rec['model_response_list'])} responses", |
| flush=True) |
| print(f"done {total} samples -> {a.out}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|