1pub mod deployment;
8pub mod endpoints;
9pub mod monitoring;
10pub mod registry;
11pub mod serialization;
12pub mod server;
13
14use crate::core::error::{Error, Result};
15use crate::dataframe::DataFrame;
16use serde::{Deserialize, Serialize};
17use std::collections::HashMap;
18use std::path::Path;
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ModelMetadata {
23 pub name: String,
25 pub version: String,
27 pub model_type: String,
29 pub feature_names: Vec<String>,
31 pub target_name: Option<String>,
33 pub description: String,
35 pub created_at: chrono::DateTime<chrono::Utc>,
37 pub updated_at: chrono::DateTime<chrono::Utc>,
39 pub metrics: HashMap<String, f64>,
41 pub metadata: HashMap<String, String>,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct PredictionRequest {
48 pub data: HashMap<String, serde_json::Value>,
50 pub model_version: Option<String>,
52 pub options: Option<PredictionOptions>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct PredictionOptions {
59 pub include_probabilities: Option<bool>,
61 pub include_feature_importance: Option<bool>,
63 pub include_confidence_intervals: Option<bool>,
65 pub threshold: Option<f64>,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct PredictionResponse {
72 pub prediction: serde_json::Value,
74 pub probabilities: Option<HashMap<String, f64>>,
76 pub feature_importance: Option<HashMap<String, f64>>,
78 pub confidence_intervals: Option<ConfidenceInterval>,
80 pub model_metadata: ModelMetadata,
82 pub timestamp: chrono::DateTime<chrono::Utc>,
84 pub processing_time_ms: u64,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct ConfidenceInterval {
91 pub lower: f64,
93 pub upper: f64,
95 pub confidence_level: f64,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct BatchPredictionRequest {
102 pub data: Vec<HashMap<String, serde_json::Value>>,
104 pub model_version: Option<String>,
106 pub options: Option<PredictionOptions>,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct BatchPredictionResponse {
113 pub predictions: Vec<PredictionResponse>,
115 pub summary: BatchProcessingSummary,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct BatchProcessingSummary {
122 pub total_predictions: usize,
124 pub successful_predictions: usize,
126 pub failed_predictions: usize,
128 pub total_processing_time_ms: u64,
130 pub avg_processing_time_ms: f64,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct DeploymentConfig {
137 pub model_name: String,
139 pub model_version: String,
141 pub environment: String,
143 pub resources: ResourceConfig,
145 pub scaling: ScalingConfig,
147 pub health_check: HealthCheckConfig,
149 pub monitoring: MonitoringConfig,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct ResourceConfig {
156 pub cpu_cores: f64,
158 pub memory_mb: u64,
160 pub gpu_memory_mb: Option<u64>,
162 pub max_concurrent_requests: usize,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct ScalingConfig {
169 pub min_instances: usize,
171 pub max_instances: usize,
173 pub target_cpu_utilization: f64,
175 pub target_memory_utilization: f64,
177 pub scale_up_threshold: f64,
179 pub scale_down_threshold: f64,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct HealthCheckConfig {
186 pub path: String,
188 pub interval_seconds: u64,
190 pub timeout_seconds: u64,
192 pub failure_threshold: usize,
194 pub success_threshold: usize,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct MonitoringConfig {
201 pub enable_metrics: bool,
203 pub enable_logging: bool,
205 pub enable_tracing: bool,
207 pub metrics_interval_seconds: u64,
209 pub log_level: String,
211}
212
213pub trait ModelServing {
215 fn predict(&self, request: &PredictionRequest) -> Result<PredictionResponse>;
217
218 fn predict_batch(&self, request: &BatchPredictionRequest) -> Result<BatchPredictionResponse>;
220
221 fn get_metadata(&self) -> &ModelMetadata;
223
224 fn health_check(&self) -> Result<HealthStatus>;
226
227 fn info(&self) -> ModelInfo;
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
233pub struct HealthStatus {
234 pub status: String,
236 pub details: HashMap<String, String>,
238 pub timestamp: chrono::DateTime<chrono::Utc>,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
244pub struct ModelInfo {
245 pub metadata: ModelMetadata,
247 pub statistics: ModelStatistics,
249 pub configuration: HashMap<String, serde_json::Value>,
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct ModelStatistics {
256 pub total_predictions: u64,
258 pub avg_prediction_time_ms: f64,
260 pub error_rate: f64,
262 pub throughput_per_second: f64,
264 pub last_prediction_at: Option<chrono::DateTime<chrono::Utc>>,
266}
267
268pub struct ModelServingFactory;
270
271impl ModelServingFactory {
272 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Box<dyn ModelServing>> {
274 let model_path = path.as_ref();
275
276 match model_path.extension().and_then(|ext| ext.to_str()) {
278 Some("json") => {
279 let serializer = serialization::JsonModelSerializer;
280 serializer.load(model_path)
281 }
282 Some("yaml") | Some("yml") => {
283 let serializer = serialization::YamlModelSerializer;
284 serializer.load(model_path)
285 }
286 Some("toml") => {
287 let serializer = serialization::TomlModelSerializer;
288 serializer.load(model_path)
289 }
290 Some("bin") | Some("pandrs") => {
291 let serializer = serialization::BinaryModelSerializer;
292 serializer.load(model_path)
293 }
294 _ => Err(Error::InvalidInput(format!(
295 "Unsupported model file format: {:?}",
296 model_path.extension()
297 ))),
298 }
299 }
300
301 pub fn from_registry(
303 registry: &dyn registry::ModelRegistry,
304 model_name: &str,
305 version: Option<&str>,
306 ) -> Result<Box<dyn ModelServing>> {
307 let model_version = version.unwrap_or("latest");
308 registry.load_model(model_name, model_version)
309 }
310
311 pub fn with_deployment_config(
313 model: Box<dyn ModelServing>,
314 config: DeploymentConfig,
315 ) -> Result<deployment::DeployedModel> {
316 deployment::DeployedModel::new(model, config)
317 }
318}
319
320pub struct ModelServer {
322 models: HashMap<String, Box<dyn ModelServing>>,
324 config: ServerConfig,
326 registry: Option<Box<dyn registry::ModelRegistry>>,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize)]
332pub struct ServerConfig {
333 pub host: String,
335 pub port: u16,
337 pub max_request_size: usize,
339 pub request_timeout_seconds: u64,
341 pub enable_cors: bool,
343 pub enable_auth: bool,
345 pub api_key: Option<String>,
347}
348
349impl Default for ServerConfig {
350 fn default() -> Self {
351 Self {
352 host: "0.0.0.0".to_string(),
353 port: 8080,
354 max_request_size: 10 * 1024 * 1024, request_timeout_seconds: 30,
356 enable_cors: true,
357 enable_auth: false,
358 api_key: None,
359 }
360 }
361}
362
363impl ModelServer {
364 pub fn new(config: ServerConfig) -> Self {
366 Self {
367 models: HashMap::new(),
368 config,
369 registry: None,
370 }
371 }
372
373 pub fn register_model(&mut self, name: String, model: Box<dyn ModelServing>) -> Result<()> {
375 if self.models.contains_key(&name) {
376 return Err(Error::InvalidOperation(format!(
377 "Model '{}' is already registered",
378 name
379 )));
380 }
381
382 self.models.insert(name, model);
383 Ok(())
384 }
385
386 pub fn unregister_model(&mut self, name: &str) -> Result<()> {
388 if self.models.remove(name).is_none() {
389 return Err(Error::KeyNotFound(format!(
390 "Model '{}' is not registered",
391 name
392 )));
393 }
394
395 Ok(())
396 }
397
398 pub fn set_registry(&mut self, registry: Box<dyn registry::ModelRegistry>) {
400 self.registry = Some(registry);
401 }
402
403 pub fn list_models(&self) -> Vec<String> {
405 self.models.keys().cloned().collect()
406 }
407
408 pub fn get_model(&self, name: &str) -> Result<&dyn ModelServing> {
410 self.models
411 .get(name)
412 .map(|model| model.as_ref())
413 .ok_or_else(|| Error::KeyNotFound(format!("Model '{}' not found", name)))
414 }
415
416 pub fn start(&self) -> Result<()> {
418 log::info!(
419 "Starting model server on {}:{}",
420 self.config.host,
421 self.config.port
422 );
423
424 Err(Error::NotImplemented(
427 "HTTP server implementation requires additional dependencies".to_string(),
428 ))
429 }
430}
431
432pub use deployment::{DeployedModel, DeploymentManager, DeploymentMetrics, DeploymentStatus};
434pub use endpoints::{
435 ApiResponse, BatchPredictionEndpoint, HealthEndpoint, ModelInfoEndpoint, PredictionEndpoint,
436};
437pub use monitoring::{
438 AlertConfig, AlertSeverity, ComparisonOperator, MetricsCollector, ModelMonitor,
439 PerformanceMetrics,
440};
441pub use registry::{
442 FileSystemModelRegistry, InMemoryModelRegistry, ModelRegistry, ModelRegistryEntry,
443};
444pub use serialization::{
445 GenericServingModel, ModelSerializer, SerializableModel, SerializationFormat,
446};
447pub use server::{HttpModelServer, HttpResponse, RequestContext, ServerStats};