from __future__ import annotations from typing import Any, Literal from pydantic import BaseModel, Field class Detection(BaseModel): frame_index: int = Field(ge=0) timestamp_sec: float = Field(ge=0.0) label: str confidence: float = Field(ge=0.0, le=1.0) bbox_xyxy: tuple[float, float, float, float] bbox_xyxy_norm: tuple[float, float, float, float] track_id: int | None = None class FrameSample(BaseModel): frame_index: int = Field(ge=0) timestamp_sec: float = Field(ge=0.0) class VideoProcessResult(BaseModel): output_video_path: str classes: list[str] detections: list[Detection] frames: list[FrameSample] = Field(default_factory=list) processed_frames: int source_fps: float output_fps: float frame_stride: int sample_interval_sec: float | None = None class ActionEvent(BaseModel): rule: str action: str type: Literal["simulate", "webhook"] frame_index: int timestamp_sec: float status: str = "pending" url: str | None = None payload: dict[str, Any] = Field(default_factory=dict) response_status: int | None = None error: str | None = None