"""Scene catalog for interactive browser demo.""" import json import os from typing import Any def _repo_root() -> str: return os.path.dirname(os.path.dirname(os.path.abspath(__file__))) def _abs(repo_root: str, rel_path: str) -> str: return os.path.normpath(os.path.join(repo_root, rel_path)) def load_interactive_scenes(config_path: str, repo_root: str | None = None) -> list[dict[str, Any]]: repo_root = repo_root or _repo_root() config_abs = config_path if os.path.isabs(config_path) else _abs(repo_root, config_path) with open(config_abs, encoding="utf-8") as f: data = json.load(f) scenes = [] for raw in data.get("scenes", []): scene = dict(raw) scene["model_path"] = _abs(repo_root, scene["model_path"]) scene["physics_config"] = _abs(repo_root, scene["physics_config"]) if not validate_scene(scene, repo_root): print(f"[interactive] skip scene (missing files): {scene.get('id')}") continue scenes.append(scene) if not scenes: raise RuntimeError(f"No valid scenes in {config_abs}") return scenes def validate_scene(scene: dict[str, Any], repo_root: str) -> bool: required = ("id", "name", "model_path", "physics_config", "dataset", "ply_name") if not all(scene.get(k) for k in required): return False if not os.path.isdir(scene["model_path"]): return False if not os.path.isfile(scene["physics_config"]): return False preview = scene.get("preview") if preview: preview_abs = preview if os.path.isabs(preview) else _abs(repo_root, preview) if not os.path.isfile(preview_abs): scene["preview"] = None else: scene["preview"] = preview_abs return True def scene_by_id(scenes: list[dict[str, Any]], scene_id: str) -> dict[str, Any] | None: for scene in scenes: if scene["id"] == scene_id: return scene return None def scene_public_view(scene: dict[str, Any]) -> dict[str, Any]: return { "id": scene["id"], "name": scene["name"], "description": scene.get("description", ""), "preview_url": f"/api/scene_preview?id={scene['id']}", }