Files
yolov26_3d/tools/model_inference/adapters/get_clip_by_eventid.py
2026-06-24 09:35:46 +08:00

142 lines
4.5 KiB
Python
Executable File

from __future__ import annotations
import argparse
import json
import time
from typing import Any
import requests
EVENT_META_INFO_URL = "https://d.minieye.tech/ess-api/dashoard/event/meta_info"
CLIP_ID_KEYS = ("clip_id", "clip_uuid", "clip_ukey", "ukey", "id")
def fetch_event_meta(
event_id: str,
timeout: float = 60.0,
max_retries: int = 3,
retry_backoff_sec: float = 2.0,
) -> dict[str, Any]:
event_id = str(event_id).strip()
if not event_id:
raise ValueError("event_id is required")
last_error: Exception | None = None
total_attempts = max(1, int(max_retries))
for attempt in range(1, total_attempts + 1):
try:
response = requests.post(
url=EVENT_META_INFO_URL,
json={"event_id": event_id},
timeout=timeout,
)
response.raise_for_status()
payload = response.json()
if not isinstance(payload, dict):
raise ValueError(f"Unexpected event meta response type: {type(payload).__name__}")
return payload
except (requests.exceptions.Timeout, requests.exceptions.RequestException, ValueError) as exc:
last_error = exc
if attempt >= total_attempts:
break
sleep_sec = max(0.0, float(retry_backoff_sec)) * (2 ** (attempt - 1))
print(
f"[warn] event_id={event_id} request attempt {attempt}/{total_attempts} failed: "
f"{type(exc).__name__}: {exc}. retry in {sleep_sec:.1f}s"
)
if sleep_sec > 0:
time.sleep(sleep_sec)
assert last_error is not None
raise last_error
def _append_clip_id(clip_ids: list[str], seen: set[str], value: Any) -> None:
clip_id = str(value).strip()
if clip_id and clip_id not in seen:
seen.add(clip_id)
clip_ids.append(clip_id)
def _extract_clip_ids_from_item(item: Any, clip_ids: list[str], seen: set[str]) -> None:
if item is None:
return
if isinstance(item, str):
_append_clip_id(clip_ids, seen, item)
return
if isinstance(item, (list, tuple, set)):
for sub_item in item:
_extract_clip_ids_from_item(sub_item, clip_ids, seen)
return
if isinstance(item, dict):
matched_key = False
for key in CLIP_ID_KEYS:
value = item.get(key)
if value is not None:
matched_key = True
_extract_clip_ids_from_item(value, clip_ids, seen)
if matched_key:
return
for value in item.values():
_extract_clip_ids_from_item(value, clip_ids, seen)
return
_append_clip_id(clip_ids, seen, item)
def extract_associated_clip_ids(payload: dict[str, Any]) -> list[str]:
clip_items = payload.get("associated_clip_list", [])
if clip_items is None:
return []
clip_ids: list[str] = []
seen: set[str] = set()
_extract_clip_ids_from_item(clip_items, clip_ids, seen)
return clip_ids
def get_associated_clip_ids(
event_id: str,
timeout: float = 60.0,
max_retries: int = 3,
retry_backoff_sec: float = 2.0,
) -> list[str]:
payload = fetch_event_meta(
event_id,
timeout=timeout,
max_retries=max_retries,
retry_backoff_sec=retry_backoff_sec,
)
return extract_associated_clip_ids(payload)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Resolve PDCL clip ids from one or more event ids.")
parser.add_argument("event_ids", nargs="+", help="One or more event ids to resolve.")
parser.add_argument("--timeout", type=float, default=60.0, help="HTTP request timeout in seconds.")
parser.add_argument("--retries", type=int, default=3, help="Max request attempts per event id.")
parser.add_argument("--retry-backoff-sec", type=float, default=2.0, help="Base retry backoff in seconds.")
parser.add_argument("--pretty", action="store_true", help="Pretty-print the JSON result.")
return parser.parse_args()
def main() -> None:
args = parse_args()
result = {
event_id: get_associated_clip_ids(
event_id,
timeout=args.timeout,
max_retries=args.retries,
retry_backoff_sec=args.retry_backoff_sec,
)
for event_id in args.event_ids
}
if args.pretty:
print(json.dumps(result, indent=2, ensure_ascii=False))
else:
print(json.dumps(result, ensure_ascii=False))
if __name__ == "__main__":
main()