mecha10_models/services/model_service/
catalog.rs1use anyhow::Result;
9use mecha10_core::model::PreprocessingConfig;
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
15pub struct ModelCatalogEntry {
16 pub name: String,
18 pub description: String,
20 pub task: String,
22 pub repo: String,
24 pub filename: String,
26
27 #[serde(default)]
29 pub preprocessing_preset: Option<String>,
30
31 #[serde(default)]
33 pub classes: Vec<String>,
34
35 #[serde(default)]
37 pub quantize: Option<QuantizeConfig>,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
42pub struct QuantizeConfig {
43 pub enabled: bool,
45 pub method: String,
47}
48
49#[derive(Debug, Deserialize)]
51pub(super) struct ModelCatalog {
52 pub(super) models: Vec<ModelCatalogEntry>,
53}
54
55#[derive(Debug, Clone, Copy)]
57pub enum PreprocessingPreset {
58 ImageNet,
60 Yolo,
62 Coco,
64 Zero255,
66}
67
68impl PreprocessingPreset {
69 pub fn from_name(name: &str) -> Result<Self> {
71 match name.to_lowercase().as_str() {
72 "imagenet" => Ok(Self::ImageNet),
73 "yolo" => Ok(Self::Yolo),
74 "coco" => Ok(Self::Coco),
75 "zero255" | "0-255" => Ok(Self::Zero255),
76 _ => anyhow::bail!("Unknown preprocessing preset: {}", name),
77 }
78 }
79
80 pub fn to_config(self) -> PreprocessingConfig {
82 match self {
83 Self::ImageNet | Self::Coco => PreprocessingConfig {
84 mean: [0.485, 0.456, 0.406],
85 std: [0.229, 0.224, 0.225],
86 channel_order: "RGB".to_string(),
87 },
88 Self::Yolo => PreprocessingConfig {
89 mean: [0.0, 0.0, 0.0],
90 std: [255.0, 255.0, 255.0],
91 channel_order: "RGB".to_string(),
92 },
93 Self::Zero255 => PreprocessingConfig {
94 mean: [0.0, 0.0, 0.0],
95 std: [1.0, 1.0, 1.0],
96 channel_order: "RGB".to_string(),
97 },
98 }
99 }
100}
101
102#[cfg(feature = "model-download")]
104#[derive(Debug, Clone, Deserialize)]
105pub(super) struct HFPreprocessorConfig {
106 #[serde(default)]
107 pub(super) image_mean: Option<Vec<f32>>,
108 #[serde(default)]
109 pub(super) image_std: Option<Vec<f32>>,
110 #[serde(default)]
111 pub(super) size: Option<HFSize>,
112 #[serde(default)]
114 pub(super) crop_size: Option<HFSize>,
115}
116
117#[cfg(feature = "model-download")]
118#[derive(Debug, Clone, Deserialize)]
119#[serde(untagged)]
120pub(super) enum HFSize {
121 Dict { height: u32, width: u32 },
122 ShortestEdge { shortest_edge: u32 },
123 Single(u32), }
125
126#[cfg(feature = "model-download")]
127impl HFPreprocessorConfig {
128 pub(super) fn to_preprocessing(&self) -> PreprocessingConfig {
129 PreprocessingConfig {
130 mean: [
131 self.image_mean.as_ref().and_then(|v| v.first()).copied().unwrap_or(0.0),
132 self.image_mean.as_ref().and_then(|v| v.get(1)).copied().unwrap_or(0.0),
133 self.image_mean.as_ref().and_then(|v| v.get(2)).copied().unwrap_or(0.0),
134 ],
135 std: [
136 self.image_std.as_ref().and_then(|v| v.first()).copied().unwrap_or(1.0),
137 self.image_std.as_ref().and_then(|v| v.get(1)).copied().unwrap_or(1.0),
138 self.image_std.as_ref().and_then(|v| v.get(2)).copied().unwrap_or(1.0),
139 ],
140 channel_order: "RGB".to_string(),
141 }
142 }
143
144 pub(super) fn input_size(&self) -> Option<[u32; 2]> {
145 if let Some(crop_size) = &self.crop_size {
148 return match crop_size {
149 HFSize::Dict { height, width } => Some([*width, *height]),
150 HFSize::ShortestEdge { shortest_edge } => Some([*shortest_edge, *shortest_edge]),
151 HFSize::Single(s) => Some([*s, *s]),
152 };
153 }
154
155 match &self.size {
157 Some(HFSize::Dict { height, width }) => Some([*width, *height]),
158 Some(HFSize::ShortestEdge { shortest_edge }) => Some([*shortest_edge, *shortest_edge]),
159 Some(HFSize::Single(s)) => Some([*s, *s]),
160 None => None,
161 }
162 }
163}