Skip to main content

memvid_rs/
config.rs

1//! Configuration management for memvid-rs
2//!
3//! This module provides comprehensive configuration options for all memvid operations,
4//! including video encoding, QR code generation, ML models, and search parameters.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9/// Main configuration structure for memvid operations
10#[derive(Debug, Clone, Serialize, Deserialize, Default)]
11pub struct Config {
12    /// Text chunking configuration
13    pub chunking: ChunkingConfig,
14
15    /// QR code generation configuration
16    pub qr: QrConfig,
17
18    /// Video encoding configuration
19    pub video: VideoConfig,
20
21    /// Machine learning configuration
22    pub ml: MlConfig,
23
24    /// Search configuration
25    pub search: SearchConfig,
26
27    /// Storage configuration
28    pub storage: StorageConfig,
29}
30
31/// Text chunking configuration
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct ChunkingConfig {
34    /// Default chunk size in characters
35    pub chunk_size: usize,
36
37    /// Overlap between chunks in characters
38    pub overlap: usize,
39
40    /// Minimum chunk size
41    pub min_chunk_size: usize,
42
43    /// Maximum chunk size
44    pub max_chunk_size: usize,
45}
46
47/// QR code generation configuration
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct QrConfig {
50    /// QR code version (1-40, None for auto)
51    pub version: Option<i16>,
52
53    /// Error correction level
54    pub error_correction: ErrorCorrectionLevel,
55
56    /// Box size for each QR module
57    pub box_size: u32,
58
59    /// Border size around QR code
60    pub border: u32,
61
62    /// Fill color (black modules)
63    pub fill_color: String,
64
65    /// Background color (white modules)
66    pub back_color: String,
67
68    /// Enable compression for large data
69    pub enable_compression: bool,
70
71    /// Compression threshold in bytes
72    pub compression_threshold: usize,
73}
74
75/// QR error correction levels
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub enum ErrorCorrectionLevel {
78    Low,      // ~7%
79    Medium,   // ~15%
80    Quartile, // ~25%
81    High,     // ~30%
82}
83
84/// Video encoding configuration
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct VideoConfig {
87    /// Video codec
88    pub codec: String,
89
90    /// Frames per second
91    pub fps: f64,
92
93    /// Frame width in pixels
94    pub frame_width: u32,
95
96    /// Frame height in pixels
97    pub frame_height: u32,
98
99    /// Video quality/bitrate parameters
100    pub quality_params: HashMap<String, String>,
101
102    /// Enable hardware acceleration
103    pub hardware_acceleration: bool,
104}
105
106/// Machine learning configuration
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct MlConfig {
109    /// Embedding model name or path
110    pub model_name: String,
111
112    /// Device preference (auto, cpu, cuda, metal)
113    pub device: String,
114
115    /// Maximum sequence length for tokenization
116    pub max_sequence_length: usize,
117
118    /// Batch size for embedding generation
119    pub batch_size: usize,
120
121    /// Model cache directory
122    pub cache_dir: Option<String>,
123
124    /// Enable model quantization for smaller memory footprint
125    pub quantization: bool,
126}
127
128/// Search configuration
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct SearchConfig {
131    /// Vector search engine (hnsw, flat, auto)
132    pub engine: String,
133
134    /// HNSW parameters
135    pub hnsw: HnswConfig,
136
137    /// Maximum results to return
138    pub max_results: usize,
139
140    /// Minimum similarity score threshold
141    pub min_score_threshold: f32,
142
143    /// Enable result re-ranking
144    pub enable_reranking: bool,
145
146    /// Cache size for decoded frames
147    pub cache_size: usize,
148
149    /// Maximum parallel workers for frame decoding
150    pub max_workers: usize,
151}
152
153/// HNSW (Hierarchical Navigable Small World) configuration
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct HnswConfig {
156    /// Maximum number of connections for each node
157    pub max_connections: usize,
158
159    /// Size of the dynamic candidate list during construction
160    pub ef_construction: usize,
161
162    /// Size of the dynamic candidate list during search
163    pub ef_search: usize,
164
165    /// Random seed for reproducible results
166    pub seed: Option<u64>,
167}
168
169/// Storage configuration
170#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct StorageConfig {
172    /// Database file path
173    pub database_path: Option<String>,
174
175    /// Enable WAL mode for SQLite
176    pub enable_wal_mode: bool,
177
178    /// SQLite cache size (in pages)
179    pub cache_size: i64,
180
181    /// Enable foreign key constraints
182    pub foreign_keys: bool,
183
184    /// Synchronous mode for SQLite
185    pub synchronous: String,
186
187    /// Index file format version
188    pub index_format_version: u32,
189}
190
191impl Default for ChunkingConfig {
192    fn default() -> Self {
193        Self {
194            chunk_size: 1024,
195            overlap: 32,
196            min_chunk_size: 100,
197            max_chunk_size: 4096,
198        }
199    }
200}
201
202impl Default for QrConfig {
203    fn default() -> Self {
204        Self {
205            version: None, // Auto-detect
206            error_correction: ErrorCorrectionLevel::Medium,
207            box_size: 10,
208            border: 4,
209            fill_color: "black".to_string(),
210            back_color: "white".to_string(),
211            enable_compression: true,
212            compression_threshold: 100,
213        }
214    }
215}
216
217impl Default for VideoConfig {
218    fn default() -> Self {
219        let mut quality_params = HashMap::new();
220        // H.265 parameters for QR code preservation (using compatible options)
221        quality_params.insert("crf".to_string(), "28".to_string());
222        quality_params.insert("preset".to_string(), "slower".to_string());
223        quality_params.insert("tune".to_string(), "zerolatency".to_string()); // Use zerolatency instead of stillimage
224        quality_params.insert("profile".to_string(), "main".to_string());
225        quality_params.insert("pix_fmt".to_string(), "yuv420p".to_string());
226
227        Self {
228            codec: "libx265".to_string(), // H.265 exactly like Python
229            fps: 30.0,                    // Python: video_fps: 30
230            frame_width: 256,             // Python: frame_width: 256
231            frame_height: 256,            // Python: frame_height: 256
232            quality_params,
233            hardware_acceleration: true,
234        }
235    }
236}
237
238impl Default for MlConfig {
239    fn default() -> Self {
240        Self {
241            model_name: "sentence-transformers/all-MiniLM-L6-v2".to_string(),
242            device: "auto".to_string(),
243            max_sequence_length: 512,
244            batch_size: 32,
245            cache_dir: None,
246            quantization: false,
247        }
248    }
249}
250
251impl Default for SearchConfig {
252    fn default() -> Self {
253        Self {
254            engine: "auto".to_string(),
255            hnsw: HnswConfig::default(),
256            max_results: 100,
257            min_score_threshold: 0.0,
258            enable_reranking: false,
259            cache_size: 1000,
260            max_workers: 4,
261        }
262    }
263}
264
265impl Default for HnswConfig {
266    fn default() -> Self {
267        Self {
268            max_connections: 16,
269            ef_construction: 200,
270            ef_search: 50,
271            seed: None,
272        }
273    }
274}
275
276impl Default for StorageConfig {
277    fn default() -> Self {
278        Self {
279            database_path: None,
280            enable_wal_mode: true,
281            cache_size: 10000, // 10,000 pages = ~40MB cache
282            foreign_keys: true,
283            synchronous: "NORMAL".to_string(),
284            index_format_version: 1,
285        }
286    }
287}
288
289/// Convert error correction level to qrcode crate constant
290impl From<ErrorCorrectionLevel> for qrcode::EcLevel {
291    fn from(level: ErrorCorrectionLevel) -> Self {
292        match level {
293            ErrorCorrectionLevel::Low => qrcode::EcLevel::L,
294            ErrorCorrectionLevel::Medium => qrcode::EcLevel::M,
295            ErrorCorrectionLevel::Quartile => qrcode::EcLevel::Q,
296            ErrorCorrectionLevel::High => qrcode::EcLevel::H,
297        }
298    }
299}
300
301#[cfg(test)]
302mod tests {
303    use super::*;
304
305    #[test]
306    fn test_default_config() {
307        let config = Config::default();
308        assert_eq!(config.chunking.chunk_size, 1024);
309        assert_eq!(config.qr.box_size, 10);
310        assert_eq!(config.video.fps, 30.0);
311        assert_eq!(
312            config.ml.model_name,
313            "sentence-transformers/all-MiniLM-L6-v2"
314        );
315    }
316
317    #[test]
318    fn test_config_serialization() {
319        let config = Config::default();
320        let json = serde_json::to_string(&config).unwrap();
321        let deserialized: Config = serde_json::from_str(&json).unwrap();
322
323        assert_eq!(config.chunking.chunk_size, deserialized.chunking.chunk_size);
324        assert_eq!(config.ml.model_name, deserialized.ml.model_name);
325    }
326
327    #[test]
328    fn test_error_correction_conversion() {
329        let level = ErrorCorrectionLevel::High;
330        let qr_level: qrcode::EcLevel = level.into();
331        assert_eq!(qr_level, qrcode::EcLevel::H);
332    }
333}