Skip to main content

cog_pose_estimation/
config.rs

1//! Runtime configuration for the pose-estimation Cog.
2//!
3//! Schema lives at `cog/config.schema.json` so the appliance can validate
4//! before launching the cog.
5
6use serde::{Deserialize, Serialize};
7use std::path::{Path, PathBuf};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(deny_unknown_fields)]
11pub struct CogConfig {
12    /// URL of the local sensing-server's frame feed.
13    /// Defaults to the appliance's loopback sensing-server.
14    #[serde(default = "default_sensing_url")]
15    pub sensing_url: String,
16
17    /// Path to the model weights bundle (safetensors or HEF).
18    /// Resolved relative to the cog's install dir if not absolute.
19    pub model_path: PathBuf,
20
21    /// Frame poll interval in milliseconds.
22    #[serde(default = "default_poll_ms")]
23    pub poll_ms: u64,
24
25    /// Confidence threshold below which a frame's keypoints are not emitted.
26    #[serde(default = "default_min_confidence")]
27    pub min_confidence: f32,
28}
29
30fn default_sensing_url() -> String {
31    "http://127.0.0.1:3000/api/v1/sensing/latest".to_string()
32}
33
34fn default_poll_ms() -> u64 {
35    40 // ~25 Hz to match ESP32 CSI rate
36}
37
38fn default_min_confidence() -> f32 {
39    0.3
40}
41
42impl CogConfig {
43    pub fn load(path: &Path) -> Result<Self, ConfigError> {
44        let raw =
45            std::fs::read_to_string(path).map_err(|e| ConfigError::Read(path.to_path_buf(), e))?;
46        let cfg: CogConfig =
47            serde_json::from_str(&raw).map_err(|e| ConfigError::Parse(path.to_path_buf(), e))?;
48        Ok(cfg)
49    }
50}
51
52#[derive(Debug, thiserror::Error)]
53pub enum ConfigError {
54    #[error("failed to read config at {0}: {1}")]
55    Read(PathBuf, std::io::Error),
56    #[error("failed to parse config at {0}: {1}")]
57    Parse(PathBuf, serde_json::Error),
58}