subx_cli/config/
builder.rs

1//! Configuration builder for fluent test configuration creation.
2//!
3//! This module provides a fluent API for building test configurations,
4//! making it easy to create specific configuration scenarios for testing.
5
6use crate::config::test_service::TestConfigService;
7use crate::config::{Config, OverflowStrategy};
8
9/// Fluent builder for creating test configurations.
10///
11/// This builder provides a convenient way to create configurations
12/// for testing with specific settings, using method chaining for clarity.
13///
14/// # Examples
15///
16/// ```rust
17/// use subx_cli::config::TestConfigBuilder;
18///
19/// let config = TestConfigBuilder::new()
20///     .with_ai_provider("openai")
21///     .with_ai_model("gpt-4")
22///     .with_sync_threshold(0.8)
23///     .build_config();
24/// ```
25pub struct TestConfigBuilder {
26    config: Config,
27}
28
29impl TestConfigBuilder {
30    /// Create a new configuration builder with default values.
31    pub fn new() -> Self {
32        Self {
33            config: Config::default(),
34        }
35    }
36
37    // AI Configuration Methods
38
39    /// Set the AI provider.
40    ///
41    /// # Arguments
42    ///
43    /// * `provider` - The AI provider name (e.g., "openai", "anthropic")
44    pub fn with_ai_provider(mut self, provider: &str) -> Self {
45        self.config.ai.provider = provider.to_string();
46        self
47    }
48
49    /// Set the AI model.
50    ///
51    /// # Arguments
52    ///
53    /// * `model` - The AI model name (e.g., "gpt-4", "claude-3")
54    pub fn with_ai_model(mut self, model: &str) -> Self {
55        self.config.ai.model = model.to_string();
56        self
57    }
58
59    /// Set the AI API key.
60    ///
61    /// # Arguments
62    ///
63    /// * `api_key` - The API key for authentication
64    pub fn with_ai_api_key(mut self, api_key: &str) -> Self {
65        self.config.ai.api_key = Some(api_key.to_string());
66        self
67    }
68
69    /// Set the AI base URL.
70    ///
71    /// # Arguments
72    ///
73    /// * `base_url` - The base URL for the AI service
74    pub fn with_ai_base_url(mut self, base_url: &str) -> Self {
75        self.config.ai.base_url = base_url.to_string();
76        self
77    }
78
79    /// Set the maximum sample length for AI requests.
80    ///
81    /// # Arguments
82    ///
83    /// * `length` - Maximum sample length in characters
84    pub fn with_max_sample_length(mut self, length: usize) -> Self {
85        self.config.ai.max_sample_length = length;
86        self
87    }
88
89    /// Set the AI temperature parameter.
90    ///
91    /// # Arguments
92    ///
93    /// * `temperature` - Temperature value (0.0-1.0)
94    pub fn with_ai_temperature(mut self, temperature: f32) -> Self {
95        self.config.ai.temperature = temperature;
96        self
97    }
98
99    /// Set the AI retry parameters.
100    ///
101    /// # Arguments
102    ///
103    /// * `attempts` - Number of retry attempts
104    /// * `delay_ms` - Delay between retries in milliseconds
105    pub fn with_ai_retry(mut self, attempts: u32, delay_ms: u64) -> Self {
106        self.config.ai.retry_attempts = attempts;
107        self.config.ai.retry_delay_ms = delay_ms;
108        self
109    }
110
111    // Sync Configuration Methods
112
113    /// Set the sync correlation threshold.
114    ///
115    /// # Arguments
116    ///
117    /// * `threshold` - Correlation threshold (0.0-1.0)
118    pub fn with_sync_threshold(mut self, threshold: f32) -> Self {
119        self.config.sync.correlation_threshold = threshold;
120        self
121    }
122
123    /// Set the maximum offset for synchronization.
124    ///
125    /// # Arguments
126    ///
127    /// * `offset` - Maximum offset in seconds
128    pub fn with_max_offset(mut self, offset: f32) -> Self {
129        self.config.sync.max_offset_seconds = offset;
130        self
131    }
132
133    /// Set the audio sample rate.
134    ///
135    /// # Arguments
136    ///
137    /// * `sample_rate` - Sample rate in Hz
138    pub fn with_audio_sample_rate(mut self, sample_rate: u32) -> Self {
139        self.config.sync.audio_sample_rate = sample_rate;
140        self
141    }
142
143    /// Enable or disable dialogue detection.
144    ///
145    /// # Arguments
146    ///
147    /// * `enabled` - Whether to enable dialogue detection
148    pub fn with_dialogue_detection(mut self, enabled: bool) -> Self {
149        self.config.sync.enable_dialogue_detection = enabled;
150        self
151    }
152
153    /// Set dialogue detection parameters.
154    ///
155    /// # Arguments
156    ///
157    /// * `threshold` - Detection threshold (0.0-1.0)
158    /// * `min_duration_ms` - Minimum dialogue duration in milliseconds
159    /// * `merge_gap_ms` - Gap for merging dialogue segments in milliseconds
160    pub fn with_dialogue_params(
161        mut self,
162        threshold: f32,
163        min_duration_ms: u64,
164        merge_gap_ms: u64,
165    ) -> Self {
166        self.config.sync.dialogue_detection_threshold = threshold;
167        self.config.sync.min_dialogue_duration_ms = min_duration_ms as u32;
168        self.config.sync.dialogue_merge_gap_ms = merge_gap_ms as u32;
169        self
170    }
171
172    /// Enable or disable auto-detection of sample rate.
173    ///
174    /// # Arguments
175    ///
176    /// * `enabled` - Whether to enable auto-detection
177    pub fn with_auto_detect_sample_rate(mut self, enabled: bool) -> Self {
178        self.config.sync.auto_detect_sample_rate = enabled;
179        self
180    }
181
182    // Formats Configuration Methods
183
184    /// Set the default output format.
185    ///
186    /// # Arguments
187    ///
188    /// * `format` - The output format (e.g., "srt", "ass", "vtt")
189    pub fn with_default_output_format(mut self, format: &str) -> Self {
190        self.config.formats.default_output = format.to_string();
191        self
192    }
193
194    /// Enable or disable style preservation.
195    ///
196    /// # Arguments
197    ///
198    /// * `preserve` - Whether to preserve styling
199    pub fn with_preserve_styling(mut self, preserve: bool) -> Self {
200        self.config.formats.preserve_styling = preserve;
201        self
202    }
203
204    /// Set the default encoding.
205    ///
206    /// # Arguments
207    ///
208    /// * `encoding` - The default encoding (e.g., "utf-8", "gbk")
209    pub fn with_default_encoding(mut self, encoding: &str) -> Self {
210        self.config.formats.default_encoding = encoding.to_string();
211        self
212    }
213
214    /// Set the encoding detection confidence threshold.
215    ///
216    /// # Arguments
217    ///
218    /// * `confidence` - Confidence threshold (0.0-1.0)
219    pub fn with_encoding_detection_confidence(mut self, confidence: f32) -> Self {
220        self.config.formats.encoding_detection_confidence = confidence;
221        self
222    }
223
224    // General Configuration Methods
225
226    /// Enable or disable backup.
227    ///
228    /// # Arguments
229    ///
230    /// * `enabled` - Whether to enable backup
231    pub fn with_backup_enabled(mut self, enabled: bool) -> Self {
232        self.config.general.backup_enabled = enabled;
233        self
234    }
235
236    /// Set the maximum number of concurrent jobs.
237    ///
238    /// # Arguments
239    ///
240    /// * `jobs` - Maximum concurrent jobs
241    pub fn with_max_concurrent_jobs(mut self, jobs: usize) -> Self {
242        self.config.general.max_concurrent_jobs = jobs;
243        self
244    }
245
246    /// Set the task timeout.
247    ///
248    /// # Arguments
249    ///
250    /// * `timeout_seconds` - Timeout in seconds
251    pub fn with_task_timeout(mut self, timeout_seconds: u64) -> Self {
252        self.config.general.task_timeout_seconds = timeout_seconds;
253        self
254    }
255
256    /// Enable or disable progress bar.
257    ///
258    /// # Arguments
259    ///
260    /// * `enabled` - Whether to enable progress bar
261    pub fn with_progress_bar(mut self, enabled: bool) -> Self {
262        self.config.general.enable_progress_bar = enabled;
263        self
264    }
265
266    /// Set the worker idle timeout.
267    ///
268    /// # Arguments
269    ///
270    /// * `timeout_seconds` - Idle timeout in seconds
271    pub fn with_worker_idle_timeout(mut self, timeout_seconds: u64) -> Self {
272        self.config.general.worker_idle_timeout_seconds = timeout_seconds;
273        self
274    }
275
276    // Parallel Configuration Methods
277
278    /// Set the task queue size.
279    ///
280    /// # Arguments
281    ///
282    /// * `size` - Queue size
283    pub fn with_task_queue_size(mut self, size: usize) -> Self {
284        self.config.parallel.task_queue_size = size;
285        self
286    }
287
288    /// Enable or disable task priorities.
289    ///
290    /// # Arguments
291    ///
292    /// * `enabled` - Whether to enable task priorities
293    pub fn with_task_priorities(mut self, enabled: bool) -> Self {
294        self.config.parallel.enable_task_priorities = enabled;
295        self
296    }
297
298    /// Enable or disable auto-balancing of workers.
299    ///
300    /// # Arguments
301    ///
302    /// * `enabled` - Whether to enable auto-balancing
303    pub fn with_auto_balance_workers(mut self, enabled: bool) -> Self {
304        self.config.parallel.auto_balance_workers = enabled;
305        self
306    }
307
308    /// Set the queue overflow strategy.
309    ///
310    /// # Arguments
311    ///
312    /// * `strategy` - Overflow strategy
313    pub fn with_queue_overflow_strategy(mut self, strategy: OverflowStrategy) -> Self {
314        self.config.parallel.overflow_strategy = strategy;
315        self
316    }
317
318    // Builder Methods
319
320    /// Build a test configuration service with the configured settings.
321    pub fn build_service(self) -> TestConfigService {
322        TestConfigService::new(self.config)
323    }
324
325    /// Build a configuration object with the configured settings.
326    pub fn build_config(self) -> Config {
327        self.config
328    }
329
330    /// Get a reference to the current configuration being built.
331    pub fn config(&self) -> &Config {
332        &self.config
333    }
334
335    /// Get a mutable reference to the current configuration being built.
336    pub fn config_mut(&mut self) -> &mut Config {
337        &mut self.config
338    }
339}
340
341impl Default for TestConfigBuilder {
342    fn default() -> Self {
343        Self::new()
344    }
345}
346
347#[cfg(test)]
348mod tests {
349    use super::*;
350    use crate::config::service::ConfigService;
351
352    #[test]
353    fn test_builder_default() {
354        let config = TestConfigBuilder::new().build_config();
355        let default_config = Config::default();
356
357        assert_eq!(config.ai.provider, default_config.ai.provider);
358        assert_eq!(config.ai.model, default_config.ai.model);
359    }
360
361    #[test]
362    fn test_builder_ai_configuration() {
363        let config = TestConfigBuilder::new()
364            .with_ai_provider("anthropic")
365            .with_ai_model("claude-3")
366            .with_ai_api_key("test-key")
367            .with_max_sample_length(5000)
368            .with_ai_temperature(0.7)
369            .build_config();
370
371        assert_eq!(config.ai.provider, "anthropic");
372        assert_eq!(config.ai.model, "claude-3");
373        assert_eq!(config.ai.api_key, Some("test-key".to_string()));
374        assert_eq!(config.ai.max_sample_length, 5000);
375        assert_eq!(config.ai.temperature, 0.7);
376    }
377
378    #[test]
379    fn test_builder_sync_configuration() {
380        let config = TestConfigBuilder::new()
381            .with_sync_threshold(0.9)
382            .with_max_offset(60.0)
383            .with_audio_sample_rate(48000)
384            .with_dialogue_detection(false)
385            .build_config();
386
387        assert_eq!(config.sync.correlation_threshold, 0.9);
388        assert_eq!(config.sync.max_offset_seconds, 60.0);
389        assert_eq!(config.sync.audio_sample_rate, 48000);
390        assert!(!config.sync.enable_dialogue_detection);
391    }
392
393    #[test]
394    fn test_builder_service_creation() {
395        let service = TestConfigBuilder::new()
396            .with_ai_provider("test-provider")
397            .build_service();
398
399        let config = service.get_config().unwrap();
400        assert_eq!(config.ai.provider, "test-provider");
401    }
402
403    #[test]
404    fn test_builder_chaining() {
405        let config = TestConfigBuilder::new()
406            .with_ai_provider("openai")
407            .with_ai_model("gpt-4")
408            .with_sync_threshold(0.8)
409            .with_max_concurrent_jobs(8)
410            .with_task_queue_size(200)
411            .build_config();
412
413        assert_eq!(config.ai.provider, "openai");
414        assert_eq!(config.ai.model, "gpt-4");
415        assert_eq!(config.sync.correlation_threshold, 0.8);
416        assert_eq!(config.general.max_concurrent_jobs, 8);
417        assert_eq!(config.parallel.task_queue_size, 200);
418    }
419}