release: bump version to 0.50.0

This commit is contained in:
rayd1o
2026-05-10 22:06:01 +08:00
parent e1984c7a35
commit 455b8360d0
80 changed files with 10936 additions and 298 deletions

96
motion_agent/events.py Normal file
View File

@@ -0,0 +1,96 @@
"""Stable event models emitted by the local motion capture agent."""
from __future__ import annotations
import json
import time
from dataclasses import asdict, dataclass, field
from typing import Any, Literal
GestureName = Literal["rotate_left", "rotate_right", "zoom_in", "zoom_out", "confirm"]
GesturePhase = Literal["start", "active", "end", "discrete"]
def now_ms() -> int:
return int(time.time() * 1000)
@dataclass(frozen=True)
class GestureEvent:
gesture: GestureName
phase: GesturePhase = "discrete"
confidence: float = 1.0
intensity: float = 1.0
timestamp_ms: int = field(default_factory=now_ms)
seq: int = 0
source: str = "motion-agent"
mode: str = "single"
payload: dict[str, Any] = field(default_factory=dict)
type: Literal["gesture"] = "gesture"
def to_dict(self) -> dict[str, Any]:
return asdict(self)
def to_json(self) -> str:
return json.dumps(self.to_dict(), ensure_ascii=False, separators=(",", ":"))
@dataclass(frozen=True)
class StatusEvent:
connected: bool
camera_count: int
active_camera_ids: tuple[str, ...] = ()
mode: str = "single"
recognizer: str = "mediapipe-opencv"
fps: float = 0.0
last_gesture: str | None = None
error: str | None = None
timestamp_ms: int = field(default_factory=now_ms)
source: str = "motion-agent"
type: Literal["status"] = "status"
def to_dict(self) -> dict[str, Any]:
return asdict(self)
def to_json(self) -> str:
return json.dumps(self.to_dict(), ensure_ascii=False, separators=(",", ":"))
@dataclass(frozen=True)
class HeartbeatEvent:
timestamp_ms: int = field(default_factory=now_ms)
source: str = "motion-agent"
type: Literal["heartbeat"] = "heartbeat"
def to_dict(self) -> dict[str, Any]:
return asdict(self)
def to_json(self) -> str:
return json.dumps(self.to_dict(), ensure_ascii=False, separators=(",", ":"))
@dataclass(frozen=True)
class SkeletonJoint:
id: str
x: float
y: float
confidence: float = 1.0
@dataclass(frozen=True)
class SkeletonEvent:
joints: list[SkeletonJoint]
bones: list[tuple[str, str]]
matched_gesture: GestureName | None = None
confidence: float = 0.0
camera_id: str = "unknown"
timestamp_ms: int = field(default_factory=now_ms)
source: str = "motion-agent"
mode: str = "single"
type: Literal["skeleton"] = "skeleton"
def to_dict(self) -> dict[str, Any]:
return asdict(self)
def to_json(self) -> str:
return json.dumps(self.to_dict(), ensure_ascii=False, separators=(",", ":"))