use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ModelTask {
Classification,
Segmentation,
Detection,
ChangeDetection,
SuperResolution,
}
#[derive(Debug, Clone)]
pub enum ModelSource {
Url(String),
HuggingFace {
repo_id: String,
filename: String,
},
Local(String),
}
#[derive(Debug, Clone)]
pub struct ModelInfo {
pub name: String,
pub version: String,
pub task: ModelTask,
pub description: String,
pub input_shape: (usize, usize, usize),
pub num_classes: usize,
pub source: ModelSource,
pub format: String,
pub size_bytes: u64,
pub accuracy: Option<f32>,
pub checksum: Option<String>,
}
pub struct ModelRegistry {
models: HashMap<String, ModelInfo>,
}
impl ModelRegistry {
#[must_use]
pub fn new() -> Self {
let mut registry = Self {
models: HashMap::new(),
};
registry.populate_models();
registry
}
fn populate_models(&mut self) {
self.register(ModelInfo {
name: "resnet50_landcover".to_string(),
version: "1.0.0".to_string(),
task: ModelTask::Classification,
description: "ResNet50 model for land cover classification (10 classes)".to_string(),
input_shape: (3, 224, 224),
num_classes: 10,
source: ModelSource::Url(
"https://example.com/models/resnet50_landcover.onnx".to_string(),
),
format: "onnx".to_string(),
size_bytes: 97_800_000, accuracy: Some(92.5),
checksum: None, });
self.register(ModelInfo {
name: "unet_buildings".to_string(),
version: "1.0.0".to_string(),
task: ModelTask::Segmentation,
description: "U-Net model for building segmentation from satellite imagery".to_string(),
input_shape: (3, 256, 256),
num_classes: 2,
source: ModelSource::Url("https://example.com/models/unet_buildings.onnx".to_string()),
format: "onnx".to_string(),
size_bytes: 31_000_000, accuracy: Some(88.3),
checksum: None,
});
self.register(ModelInfo {
name: "yolov5_vehicles".to_string(),
version: "5.0.0".to_string(),
task: ModelTask::Detection,
description: "YOLOv5 model for vehicle detection in aerial imagery".to_string(),
input_shape: (3, 640, 640),
num_classes: 3,
source: ModelSource::Url("https://example.com/models/yolov5_vehicles.onnx".to_string()),
format: "onnx".to_string(),
size_bytes: 14_100_000, accuracy: Some(85.7),
checksum: None,
});
self.register(ModelInfo {
name: "deeplabv3_fields".to_string(),
version: "3.0.0".to_string(),
task: ModelTask::Segmentation,
description: "DeepLabV3 for agricultural field boundary segmentation".to_string(),
input_shape: (3, 512, 512),
num_classes: 5,
source: ModelSource::Url(
"https://example.com/models/deeplabv3_fields.onnx".to_string(),
),
format: "onnx".to_string(),
size_bytes: 168_000_000, accuracy: Some(91.2),
checksum: None,
});
self.register(ModelInfo {
name: "efficientnet_crops".to_string(),
version: "1.0.0".to_string(),
task: ModelTask::Classification,
description: "EfficientNet-B0 for crop type classification".to_string(),
input_shape: (3, 224, 224),
num_classes: 15,
source: ModelSource::Url(
"https://example.com/models/efficientnet_crops.onnx".to_string(),
),
format: "onnx".to_string(),
size_bytes: 20_500_000, accuracy: Some(89.8),
checksum: None,
});
self.register(ModelInfo {
name: "siamese_change".to_string(),
version: "1.0.0".to_string(),
task: ModelTask::ChangeDetection,
description: "Siamese network for change detection in multi-temporal imagery"
.to_string(),
input_shape: (6, 256, 256), num_classes: 2,
source: ModelSource::Url("https://example.com/models/siamese_change.onnx".to_string()),
format: "onnx".to_string(),
size_bytes: 45_000_000, accuracy: Some(86.5),
checksum: None,
});
self.register(ModelInfo {
name: "mobilenet_v3_landcover".to_string(),
version: "3.0.0".to_string(),
task: ModelTask::Classification,
description: "MobileNetV3 for efficient land cover classification".to_string(),
input_shape: (3, 224, 224),
num_classes: 10,
source: ModelSource::Url(
"https://example.com/models/mobilenet_v3_landcover.onnx".to_string(),
),
format: "onnx".to_string(),
size_bytes: 5_400_000, accuracy: Some(88.5),
checksum: None,
});
self.register(ModelInfo {
name: "segformer_b0_roads".to_string(),
version: "1.0.0".to_string(),
task: ModelTask::Segmentation,
description: "SegFormer-B0 for road segmentation from satellite imagery".to_string(),
input_shape: (3, 512, 512),
num_classes: 2,
source: ModelSource::Url(
"https://example.com/models/segformer_b0_roads.onnx".to_string(),
),
format: "onnx".to_string(),
size_bytes: 13_200_000, accuracy: Some(90.1),
checksum: None,
});
self.register(ModelInfo {
name: "esrgan_2x".to_string(),
version: "1.0.0".to_string(),
task: ModelTask::SuperResolution,
description: "ESRGAN for 2x image super-resolution".to_string(),
input_shape: (3, 256, 256),
num_classes: 1, source: ModelSource::Url("https://example.com/models/esrgan_2x.onnx".to_string()),
format: "onnx".to_string(),
size_bytes: 16_700_000, accuracy: None, checksum: None,
});
}
pub fn register(&mut self, model: ModelInfo) {
self.models.insert(model.name.clone(), model);
}
#[must_use]
pub fn get(&self, name: &str) -> Option<&ModelInfo> {
self.models.get(name)
}
#[must_use]
pub fn list_all(&self) -> Vec<&ModelInfo> {
self.models.values().collect()
}
#[must_use]
pub fn find_by_task(&self, task: ModelTask) -> Vec<&ModelInfo> {
self.models.values().filter(|m| m.task == task).collect()
}
#[must_use]
pub fn count(&self) -> usize {
self.models.len()
}
}
impl Default for ModelRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_registry_population() {
let registry = ModelRegistry::new();
assert!(registry.count() > 0);
}
#[test]
fn test_find_by_task() {
let registry = ModelRegistry::new();
let classifiers = registry.find_by_task(ModelTask::Classification);
assert!(!classifiers.is_empty());
let segmenters = registry.find_by_task(ModelTask::Segmentation);
assert!(!segmenters.is_empty());
}
#[test]
fn test_get_model() {
let registry = ModelRegistry::new();
let model = registry.get("resnet50_landcover");
assert!(model.is_some());
if let Some(m) = model {
assert_eq!(m.task, ModelTask::Classification);
assert_eq!(m.num_classes, 10);
}
}
}