Skip to main content

heldar_kernel/models/
perception.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use sqlx::types::Json;
5use sqlx::FromRow;
6
7#[derive(Debug, Clone, Serialize, FromRow)]
8pub struct Event {
9    pub id: String,
10    pub camera_id: Option<String>,
11    pub site_id: Option<String>,
12    pub event_type: String,
13    pub severity: String,
14    pub timestamp: DateTime<Utc>,
15    pub payload: Json<Value>,
16    pub created_at: DateTime<Utc>,
17}
18
19/// A perception task to run on a camera (consumed by AI workers).
20#[derive(Debug, Clone, Serialize, FromRow)]
21pub struct AiTask {
22    pub id: String,
23    pub camera_id: String,
24    pub task_type: String,
25    pub enabled: bool,
26    pub stream_profile: String,
27    pub fps: f64,
28    pub width: i64,
29    pub config: Json<Value>,
30    pub created_at: DateTime<Utc>,
31    pub updated_at: DateTime<Utc>,
32}
33
34#[derive(Debug, Deserialize)]
35pub struct AiTaskCreate {
36    pub task_type: String,
37    pub stream_profile: Option<String>,
38    pub fps: Option<f64>,
39    pub width: Option<i64>,
40    pub config: Option<Value>,
41    pub enabled: Option<bool>,
42}
43
44#[derive(Debug, Deserialize, Default)]
45pub struct AiTaskUpdate {
46    pub task_type: Option<String>,
47    pub stream_profile: Option<String>,
48    pub fps: Option<f64>,
49    pub width: Option<i64>,
50    pub config: Option<Value>,
51    pub enabled: Option<bool>,
52}
53
54/// A detection result posted by an AI worker.
55#[derive(Debug, Clone, Serialize, FromRow)]
56pub struct Detection {
57    pub id: String,
58    pub camera_id: String,
59    pub task_type: String,
60    pub timestamp: DateTime<Utc>,
61    pub label: Option<String>,
62    pub confidence: Option<f64>,
63    pub bbox: Option<Json<Value>>,
64    pub track_id: Option<String>,
65    pub attributes: Json<Value>,
66    /// Worker-supplied per-camera frame id this detection belongs to (idempotency / batch grouping).
67    pub frame_id: Option<String>,
68    pub created_at: DateTime<Utc>,
69}
70
71/// One detection inside an ingest request.
72// `Serialize` so the Wasm plugin host (heldar-wasm) can marshal a batch to JSON for a sandboxed guest.
73#[derive(Debug, Clone, Deserialize, Serialize)]
74pub struct DetectionIngest {
75    pub label: Option<String>,
76    pub confidence: Option<f64>,
77    pub bbox: Option<Value>,
78    pub track_id: Option<String>,
79    pub attributes: Option<Value>,
80}
81
82/// Optional event an AI worker can raise alongside its detections.
83#[derive(Debug, Deserialize)]
84pub struct IngestEvent {
85    pub event_type: String,
86    pub severity: Option<String>,
87    pub payload: Option<Value>,
88}
89
90/// Payload an AI worker POSTs to ingest detections (and optionally an event) for a camera.
91#[derive(Debug, Deserialize)]
92pub struct AiIngest {
93    pub camera_id: String,
94    pub task_type: String,
95    pub timestamp: Option<String>,
96    /// Optional per-camera monotonic frame id. When present, ingest is idempotent on
97    /// (camera_id, frame_id): a duplicate redelivery is a no-op (no double-insert, no re-fire of
98    /// consumer side effects). Omit it (e.g. the dependency-light client) to accept every batch.
99    pub frame_id: Option<String>,
100    #[serde(default)]
101    pub detections: Vec<DetectionIngest>,
102    pub event: Option<IngestEvent>,
103}
104
105/// A polygon region on a camera; tracked detections crossing it raise enter/exit/dwell events.
106#[derive(Debug, Clone, Serialize, FromRow)]
107pub struct Zone {
108    pub id: String,
109    pub camera_id: String,
110    pub name: String,
111    pub kind: String,
112    /// JSON array of [x, y] vertices, normalized 0..1.
113    pub polygon: Json<Value>,
114    pub dwell_seconds: f64,
115    /// JSON array of detection labels that count toward this zone (empty = all labels).
116    pub labels: Json<Value>,
117    pub severity: String,
118    pub config: Json<Value>,
119    pub enabled: bool,
120    pub created_at: DateTime<Utc>,
121    pub updated_at: DateTime<Utc>,
122}
123
124#[derive(Debug, Deserialize)]
125pub struct ZoneCreate {
126    pub name: String,
127    pub kind: Option<String>,
128    pub polygon: Value,
129    pub dwell_seconds: Option<f64>,
130    pub labels: Option<Value>,
131    pub severity: Option<String>,
132    pub config: Option<Value>,
133    pub enabled: Option<bool>,
134}
135
136#[derive(Debug, Deserialize, Default)]
137pub struct ZoneUpdate {
138    pub name: Option<String>,
139    pub kind: Option<String>,
140    pub polygon: Option<Value>,
141    pub dwell_seconds: Option<f64>,
142    pub labels: Option<Value>,
143    pub severity: Option<String>,
144    pub config: Option<Value>,
145    pub enabled: Option<bool>,
146}
147
148#[derive(Debug, Clone, Serialize, FromRow)]
149pub struct ZoneEvent {
150    pub id: String,
151    pub camera_id: String,
152    pub zone_id: String,
153    pub zone_name: String,
154    pub track_id: Option<String>,
155    pub event_type: String,
156    pub label: Option<String>,
157    pub timestamp: DateTime<Utc>,
158    pub dwell_seconds: Option<f64>,
159    pub evidence_path: Option<String>,
160    pub created_at: DateTime<Utc>,
161}