Skip to main content

oar_ocr_core/core/config/
builder.rs

1//! Model inference configuration types and utilities.
2
3use super::errors::{ConfigError, ConfigValidator};
4use super::onnx::OrtSessionConfig;
5use serde::{Deserialize, Serialize};
6use std::path::PathBuf;
7
8/// Configuration for model inference and ONNX Runtime session setup.
9///
10/// This struct provides configuration options for building ONNX inference engines,
11/// including runtime settings and model metadata.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct ModelInferenceConfig {
14    /// The path to the model file (optional).
15    pub model_path: Option<PathBuf>,
16    /// The name of the model (optional).
17    pub model_name: Option<String>,
18    /// The batch size for processing (optional).
19    pub batch_size: Option<usize>,
20    /// Whether to enable logging (optional).
21    pub enable_logging: Option<bool>,
22    /// ONNX Runtime session configuration for this model (optional).
23    #[serde(default)]
24    pub ort_session: Option<OrtSessionConfig>,
25}
26
27impl ModelInferenceConfig {
28    /// Creates a new config with all fields unset.
29    pub fn new() -> Self {
30        Self {
31            model_path: None,
32            model_name: None,
33            batch_size: None,
34            enable_logging: None,
35            ort_session: None,
36        }
37    }
38
39    /// Creates a config with the given model name and batch size, logging enabled.
40    pub fn with_defaults(model_name: Option<String>, batch_size: Option<usize>) -> Self {
41        Self {
42            model_path: None,
43            model_name,
44            batch_size,
45            enable_logging: Some(true),
46            ort_session: None,
47        }
48    }
49
50    /// Creates a config with the given model path, logging enabled.
51    pub fn with_model_path(model_path: PathBuf) -> Self {
52        Self {
53            model_path: Some(model_path),
54            model_name: None,
55            batch_size: None,
56            enable_logging: Some(true),
57            ort_session: None,
58        }
59    }
60
61    /// Sets the model path.
62    pub fn model_path(mut self, model_path: impl Into<PathBuf>) -> Self {
63        self.model_path = Some(model_path.into());
64        self
65    }
66
67    /// Sets the model name.
68    pub fn model_name(mut self, model_name: impl Into<String>) -> Self {
69        self.model_name = Some(model_name.into());
70        self
71    }
72
73    /// Sets the batch size.
74    pub fn batch_size(mut self, batch_size: usize) -> Self {
75        self.batch_size = Some(batch_size);
76        self
77    }
78
79    /// Enables or disables logging.
80    pub fn enable_logging(mut self, enable: bool) -> Self {
81        self.enable_logging = Some(enable);
82        self
83    }
84
85    /// Returns whether logging is enabled (defaults to true).
86    pub fn get_enable_logging(&self) -> bool {
87        self.enable_logging.unwrap_or(true)
88    }
89
90    /// Sets the ONNX Runtime session configuration.
91    pub fn ort_session(mut self, cfg: OrtSessionConfig) -> Self {
92        self.ort_session = Some(cfg);
93        self
94    }
95
96    /// Validates the configuration.
97    pub fn validate(&self) -> Result<(), ConfigError> {
98        ConfigValidator::validate(self)
99    }
100
101    /// Merges in another config; its set fields override this one's.
102    pub fn merge_with(mut self, other: &ModelInferenceConfig) -> Self {
103        if other.model_path.is_some() {
104            self.model_path = other.model_path.clone();
105        }
106        if other.model_name.is_some() {
107            self.model_name = other.model_name.clone();
108        }
109        if other.batch_size.is_some() {
110            self.batch_size = other.batch_size;
111        }
112        if other.enable_logging.is_some() {
113            self.enable_logging = other.enable_logging;
114        }
115        if other.ort_session.is_some() {
116            self.ort_session = other.ort_session.clone();
117        }
118        self
119    }
120
121    /// Effective batch size, defaulting to 1.
122    pub fn get_batch_size(&self) -> usize {
123        self.batch_size.unwrap_or(1)
124    }
125
126    /// Model name, defaulting to `"unnamed_model"`.
127    pub fn get_model_name(&self) -> String {
128        self.model_name
129            .clone()
130            .unwrap_or_else(|| "unnamed_model".to_string())
131    }
132}
133
134impl ConfigValidator for ModelInferenceConfig {
135    /// Validates the batch size (if set) and that the model path exists (if set).
136    fn validate(&self) -> Result<(), ConfigError> {
137        if let Some(batch_size) = self.batch_size {
138            self.validate_batch_size_with_limits(batch_size, 1000)?;
139        }
140
141        if let Some(model_path) = &self.model_path {
142            self.validate_model_path(model_path)?;
143        }
144
145        Ok(())
146    }
147
148    /// Returns the default configuration.
149    fn get_defaults() -> Self {
150        Self {
151            model_path: None,
152            model_name: Some("default_model".to_string()),
153            batch_size: Some(32),
154            enable_logging: Some(false),
155            ort_session: None,
156        }
157    }
158}
159
160impl Default for ModelInferenceConfig {
161    fn default() -> Self {
162        Self::new()
163    }
164}
165
166#[cfg(test)]
167mod tests {
168    use super::*;
169
170    #[test]
171    fn test_common_builder_config_builder_pattern() {
172        let ort_cfg = OrtSessionConfig::default();
173        let config = ModelInferenceConfig::new()
174            .model_name("test_model")
175            .batch_size(16)
176            .enable_logging(true)
177            .ort_session(ort_cfg);
178
179        assert_eq!(config.model_name, Some("test_model".to_string()));
180        assert_eq!(config.batch_size, Some(16));
181        assert_eq!(config.enable_logging, Some(true));
182        assert!(config.ort_session.is_some());
183    }
184
185    #[test]
186    fn test_common_builder_config_merge() {
187        let config1 = ModelInferenceConfig::new()
188            .model_name("model1")
189            .batch_size(8);
190        let config2 = ModelInferenceConfig::new()
191            .model_name("model2")
192            .enable_logging(true);
193
194        let merged = config1.merge_with(&config2);
195        assert_eq!(merged.model_name, Some("model2".to_string()));
196        assert_eq!(merged.batch_size, Some(8));
197        assert_eq!(merged.enable_logging, Some(true));
198    }
199
200    #[test]
201    fn test_common_builder_config_getters() {
202        let ort_cfg = OrtSessionConfig::default();
203        let config = ModelInferenceConfig::new()
204            .model_name("test")
205            .batch_size(16)
206            .ort_session(ort_cfg);
207
208        assert_eq!(config.get_model_name(), "test");
209        assert_eq!(config.get_batch_size(), 16);
210        assert!(config.get_enable_logging()); // Default is true
211    }
212
213    #[test]
214    fn test_common_builder_config_validation() {
215        let ort_cfg = OrtSessionConfig::default();
216        let valid_config = ModelInferenceConfig::new()
217            .batch_size(16)
218            .ort_session(ort_cfg);
219        assert!(valid_config.validate().is_ok());
220
221        let invalid_batch_config = ModelInferenceConfig::new().batch_size(0);
222        assert!(invalid_batch_config.validate().is_err());
223    }
224}