candle_coreml/config/generator/
caching.rs

1//! Configuration caching utilities
2//!
3//! Handles saving and loading generated model configurations
4
5use crate::cache::manager::CacheManager;
6use crate::config::model::ModelConfig;
7use anyhow::Result;
8use tracing::{debug, info};
9
10pub struct ConfigCaching {
11    cache_manager: CacheManager,
12}
13
14impl ConfigCaching {
15    pub fn new(cache_manager: CacheManager) -> Self {
16        Self { cache_manager }
17    }
18
19    /// Cache a generated configuration
20    pub fn cache_config(&self, model_id: &str, config: &ModelConfig) -> Result<()> {
21        let configs_dir = self.cache_manager.configs_dir();
22        std::fs::create_dir_all(&configs_dir)?;
23
24        let config_filename = self.normalize_model_id_for_filename(model_id);
25        let config_path = configs_dir.join(config_filename);
26
27        let config_json = serde_json::to_string_pretty(config)?;
28        std::fs::write(&config_path, config_json)?;
29
30        info!("💾 Cached generated config at: {}", config_path.display());
31        Ok(())
32    }
33
34    /// Load a cached configuration if available
35    pub fn load_cached_config(&self, model_id: &str) -> Result<Option<ModelConfig>> {
36        let configs_dir = self.cache_manager.configs_dir();
37        let config_filename = self.normalize_model_id_for_filename(model_id);
38        let config_path = configs_dir.join(config_filename);
39
40        if !config_path.exists() {
41            debug!("📖 No cached config found for: {}", model_id);
42            return Ok(None);
43        }
44
45        let config_json = std::fs::read_to_string(&config_path)?;
46        let config: ModelConfig = serde_json::from_str(&config_json)?;
47
48        debug!("📖 Loaded cached config for: {}", model_id);
49        Ok(Some(config))
50    }
51
52    /// Check if a cached configuration exists
53    pub fn has_cached_config(&self, model_id: &str) -> bool {
54        let configs_dir = self.cache_manager.configs_dir();
55        let config_filename = self.normalize_model_id_for_filename(model_id);
56        let config_path = configs_dir.join(config_filename);
57
58        config_path.exists()
59    }
60
61    /// Clear cached configuration for a model
62    pub fn clear_cached_config(&self, model_id: &str) -> Result<()> {
63        let configs_dir = self.cache_manager.configs_dir();
64        let config_filename = self.normalize_model_id_for_filename(model_id);
65        let config_path = configs_dir.join(config_filename);
66
67        if config_path.exists() {
68            std::fs::remove_file(&config_path)?;
69            info!("🗑️ Cleared cached config for: {}", model_id);
70        }
71
72        Ok(())
73    }
74
75    /// List all cached model configurations
76    pub fn list_cached_configs(&self) -> Result<Vec<String>> {
77        let configs_dir = self.cache_manager.configs_dir();
78        let mut model_ids = Vec::new();
79
80        if !configs_dir.exists() {
81            return Ok(model_ids);
82        }
83
84        for entry in std::fs::read_dir(&configs_dir)? {
85            let entry = entry?;
86            let path = entry.path();
87
88            if path.is_file() && path.extension().is_some_and(|ext| ext == "json") {
89                if let Some(filename) = path.file_stem().and_then(|s| s.to_str()) {
90                    // Convert filename back to model ID
91                    let model_id = filename.replace("--", "/");
92                    model_ids.push(model_id);
93                }
94            }
95        }
96
97        model_ids.sort();
98        Ok(model_ids)
99    }
100
101    /// Get cache statistics
102    pub fn get_cache_stats(&self) -> Result<CacheStats> {
103        let configs_dir = self.cache_manager.configs_dir();
104
105        if !configs_dir.exists() {
106            return Ok(CacheStats::default());
107        }
108
109        let mut stats = CacheStats::default();
110        let mut total_size = 0u64;
111
112        for entry in std::fs::read_dir(&configs_dir)? {
113            let entry = entry?;
114            let path = entry.path();
115
116            if path.is_file() && path.extension().is_some_and(|ext| ext == "json") {
117                stats.cached_configs += 1;
118
119                if let Ok(metadata) = std::fs::metadata(&path) {
120                    total_size += metadata.len();
121                }
122            }
123        }
124
125        stats.total_size_bytes = total_size;
126        Ok(stats)
127    }
128
129    /// Clear all cached configurations
130    pub fn clear_all_cached_configs(&self) -> Result<usize> {
131        let configs_dir = self.cache_manager.configs_dir();
132        let mut cleared_count = 0;
133
134        if !configs_dir.exists() {
135            return Ok(cleared_count);
136        }
137
138        for entry in std::fs::read_dir(&configs_dir)? {
139            let entry = entry?;
140            let path = entry.path();
141
142            if path.is_file() && path.extension().is_some_and(|ext| ext == "json") {
143                std::fs::remove_file(&path)?;
144                cleared_count += 1;
145            }
146        }
147
148        info!("🗑️ Cleared {} cached configurations", cleared_count);
149        Ok(cleared_count)
150    }
151
152    // Private helper methods
153
154    fn normalize_model_id_for_filename(&self, model_id: &str) -> String {
155        format!("{}.json", model_id.replace('/', "--"))
156    }
157}
158
159#[derive(Debug, Default)]
160pub struct CacheStats {
161    pub cached_configs: usize,
162    pub total_size_bytes: u64,
163}
164
165impl CacheStats {
166    pub fn total_size_mb(&self) -> f64 {
167        self.total_size_bytes as f64 / (1024.0 * 1024.0)
168    }
169
170    pub fn average_size_kb(&self) -> f64 {
171        if self.cached_configs == 0 {
172            0.0
173        } else {
174            (self.total_size_bytes as f64 / self.cached_configs as f64) / 1024.0
175        }
176    }
177}