"""Configuration for the local motion capture agent.""" from __future__ import annotations import os from dataclasses import dataclass, field SUPPORTED_INPUT_MODES = {"auto", "single", "dual", "dual_redundant", "single_fallback", "calibrated_3d"} def _parse_camera_indexes(raw: str | None) -> tuple[int, ...]: if not raw: return (0,) indexes: list[int] = [] for item in raw.split(","): value = item.strip() if not value: continue indexes.append(int(value)) return tuple(indexes or [0]) def _parse_camera_urls(raw: str | None) -> tuple[str, ...]: if not raw: return () return tuple(item.strip() for item in raw.split(",") if item.strip()) @dataclass(frozen=True) class MotionAgentConfig: host: str = "127.0.0.1" port: int = 8765 path: str = "/ws/gestures" camera_indexes: tuple[int, ...] = field(default_factory=lambda: (0,)) camera_urls: tuple[str, ...] = field(default_factory=tuple) camera_width: int = 640 camera_height: int = 360 camera_fps: int = 30 mode: str = "auto" confidence_threshold: float = 0.72 cooldown_ms: int = 450 heartbeat_interval_ms: int = 1000 max_event_hz: int = 15 max_skeleton_hz: int = 8 fusion_window_ms: int = 120 fusion_conflict_delta: float = 0.18 dry_run: bool = False @property def websocket_url(self) -> str: return f"ws://{self.host}:{self.port}{self.path}" @classmethod def from_env(cls) -> "MotionAgentConfig": return cls( host=os.getenv("MOTION_AGENT_HOST", "127.0.0.1"), port=int(os.getenv("MOTION_AGENT_PORT", "8765")), path=os.getenv("MOTION_AGENT_PATH", "/ws/gestures"), camera_indexes=_parse_camera_indexes(os.getenv("MOTION_AGENT_CAMERA_INDEXES")), camera_urls=_parse_camera_urls(os.getenv("MOTION_AGENT_CAMERA_URLS")), camera_width=int(os.getenv("MOTION_AGENT_CAMERA_WIDTH", "640")), camera_height=int(os.getenv("MOTION_AGENT_CAMERA_HEIGHT", "360")), camera_fps=int(os.getenv("MOTION_AGENT_CAMERA_FPS", "30")), mode=os.getenv("MOTION_AGENT_MODE", "auto"), confidence_threshold=float(os.getenv("MOTION_AGENT_CONFIDENCE_THRESHOLD", "0.72")), cooldown_ms=int(os.getenv("MOTION_AGENT_COOLDOWN_MS", "450")), heartbeat_interval_ms=int(os.getenv("MOTION_AGENT_HEARTBEAT_MS", "1000")), max_event_hz=int(os.getenv("MOTION_AGENT_MAX_EVENT_HZ", "15")), max_skeleton_hz=int(os.getenv("MOTION_AGENT_MAX_SKELETON_HZ", "8")), fusion_window_ms=int(os.getenv("MOTION_AGENT_FUSION_WINDOW_MS", "120")), fusion_conflict_delta=float(os.getenv("MOTION_AGENT_FUSION_CONFLICT_DELTA", "0.18")), dry_run=os.getenv("MOTION_AGENT_DRY_RUN", "").lower() in {"1", "true", "yes"}, )