1use std::fmt;
7
8use thiserror::Error;
9
10pub mod advanced_handler;
11
12#[derive(Error, Debug)]
14pub enum CliError {
15 #[error("Configuration error: {message}")]
17 Config { message: String },
18
19 #[error("File operation failed: {operation} on {path}: {source}")]
21 File {
22 operation: String,
23 path: String,
24 #[source]
25 source: std::io::Error,
26 },
27
28 #[error("Unsupported audio format: {format}. Supported formats: {supported}")]
30 AudioFormat { format: String, supported: String },
31
32 #[error("Voice '{voice_id}' not found. Available voices: {available}")]
34 VoiceNotFound { voice_id: String, available: String },
35
36 #[error("Invalid parameter '{parameter}': {message}")]
38 InvalidParameter { parameter: String, message: String },
39
40 #[error("VoiRS SDK error: {0}")]
42 Sdk(#[from] voirs_sdk::VoirsError),
43
44 #[error("Serialization error: {0}")]
46 Serialization(#[from] serde_json::Error),
47
48 #[error("TOML error: {0}")]
50 Toml(#[from] toml::ser::Error),
51
52 #[error("IO error: {0}")]
54 Io(#[from] std::io::Error),
55
56 #[error("Voice error: {0}")]
58 VoiceError(String),
59
60 #[error("Audio error: {0}")]
62 AudioError(String),
63
64 #[error("Synthesis error: {0}")]
66 SynthesisError(String),
67
68 #[error("Validation error: {0}")]
70 ValidationError(String),
71
72 #[error("IO error: {0}")]
74 IoError(String),
75
76 #[error("Serialization error: {0}")]
78 SerializationError(String),
79
80 #[error("Invalid argument: {0}")]
82 InvalidArgument(String),
83
84 #[error("Not implemented: {0}")]
86 NotImplemented(String),
87
88 #[error("Interactive error: {0}")]
90 InteractiveError(String),
91
92 #[error("Packaging error: {0}")]
94 PackagingError(String),
95
96 #[error("Update error: {0}")]
98 UpdateError(String),
99
100 #[error("Emotion control error: {0}")]
102 EmotionError(String),
103
104 #[error("Voice cloning error: {0}")]
106 CloningError(String),
107
108 #[error("Voice conversion error: {0}")]
110 ConversionError(String),
111
112 #[error("Singing synthesis error: {0}")]
114 SingingError(String),
115
116 #[error("Spatial audio error: {0}")]
118 SpatialError(String),
119
120 #[error("Model loading error: {0}")]
122 ModelLoadingError(String),
123
124 #[error("Feature not available: {0}")]
126 FeatureNotAvailable(String),
127
128 #[error("Missing dependency: {0}")]
130 MissingDependency(String),
131
132 #[error("Hardware requirement not met: {0}")]
134 HardwareRequirement(String),
135
136 #[error("Network error: {0}")]
138 NetworkError(String),
139
140 #[error("Performance warning: {0}")]
142 PerformanceWarning(String),
143
144 #[error("Workflow error: {0}")]
146 Workflow(String),
147
148 #[error("Advanced error: {0}")]
150 Advanced(#[from] Box<advanced_handler::AdvancedError>),
151}
152
153impl CliError {
154 pub fn config<S: Into<String>>(message: S) -> Self {
156 Self::Config {
157 message: message.into(),
158 }
159 }
160
161 pub fn file_operation<S: Into<String>>(operation: S, path: S, source: std::io::Error) -> Self {
163 Self::File {
164 operation: operation.into(),
165 path: path.into(),
166 source,
167 }
168 }
169
170 pub fn audio_format<S: Into<String>>(format: S) -> Self {
172 Self::AudioFormat {
173 format: format.into(),
174 supported: "wav, flac, mp3, opus, ogg".to_string(),
175 }
176 }
177
178 pub fn voice_not_found<S: Into<String>>(voice_id: S, available: Vec<String>) -> Self {
180 Self::VoiceNotFound {
181 voice_id: voice_id.into(),
182 available: available.join(", "),
183 }
184 }
185
186 pub fn invalid_parameter<S: Into<String>>(parameter: S, message: S) -> Self {
188 Self::InvalidParameter {
189 parameter: parameter.into(),
190 message: message.into(),
191 }
192 }
193
194 pub fn emotion_error<S: Into<String>>(message: S) -> Self {
196 Self::EmotionError(message.into())
197 }
198
199 pub fn cloning_error<S: Into<String>>(message: S) -> Self {
201 Self::CloningError(message.into())
202 }
203
204 pub fn conversion_error<S: Into<String>>(message: S) -> Self {
206 Self::ConversionError(message.into())
207 }
208
209 pub fn singing_error<S: Into<String>>(message: S) -> Self {
211 Self::SingingError(message.into())
212 }
213
214 pub fn spatial_error<S: Into<String>>(message: S) -> Self {
216 Self::SpatialError(message.into())
217 }
218
219 pub fn model_loading_error<S: Into<String>>(message: S) -> Self {
221 Self::ModelLoadingError(message.into())
222 }
223
224 pub fn feature_not_available<S: Into<String>>(message: S) -> Self {
226 Self::FeatureNotAvailable(message.into())
227 }
228
229 pub fn missing_dependency<S: Into<String>>(message: S) -> Self {
231 Self::MissingDependency(message.into())
232 }
233
234 pub fn hardware_requirement<S: Into<String>>(message: S) -> Self {
236 Self::HardwareRequirement(message.into())
237 }
238
239 pub fn network_error<S: Into<String>>(message: S) -> Self {
241 Self::NetworkError(message.into())
242 }
243
244 pub fn performance_warning<S: Into<String>>(message: S) -> Self {
246 Self::PerformanceWarning(message.into())
247 }
248
249 pub fn to_advanced_error(&self) -> advanced_handler::AdvancedError {
251 use advanced_handler::*;
252 use std::collections::HashMap;
253 use std::time::{SystemTime, UNIX_EPOCH};
254
255 let (category, severity) = match self {
256 CliError::Config { .. } => (ErrorCategory::Configuration, ErrorSeverity::Error),
257 CliError::File { .. } => (ErrorCategory::FileSystem, ErrorSeverity::Error),
258 CliError::AudioFormat { .. } => (ErrorCategory::UserInput, ErrorSeverity::Error),
259 CliError::VoiceNotFound { .. } => (ErrorCategory::UserInput, ErrorSeverity::Error),
260 CliError::InvalidParameter { .. } => (ErrorCategory::UserInput, ErrorSeverity::Error),
261 CliError::NetworkError(_) => (ErrorCategory::Network, ErrorSeverity::Error),
262 CliError::ModelLoadingError(_) => (ErrorCategory::ModelLoading, ErrorSeverity::Error),
263 CliError::AudioError(_) => (ErrorCategory::AudioProcessing, ErrorSeverity::Error),
264 CliError::SynthesisError(_) => (ErrorCategory::Synthesis, ErrorSeverity::Error),
265 CliError::MissingDependency(_) => (ErrorCategory::Dependency, ErrorSeverity::Error),
266 CliError::HardwareRequirement(_) => (ErrorCategory::Hardware, ErrorSeverity::Error),
267 CliError::PerformanceWarning(_) => {
268 (ErrorCategory::ResourceExhaustion, ErrorSeverity::Warning)
269 }
270 _ => (ErrorCategory::Internal, ErrorSeverity::Error),
271 };
272
273 let context = ErrorContext {
274 operation: "cli_operation".to_string(),
275 user: std::env::var("USER").ok(),
276 session_id: None,
277 request_id: None,
278 component: "voirs-cli".to_string(),
279 function: None,
280 location: None,
281 parameters: HashMap::new(),
282 system_state: SystemState {
283 available_memory_bytes: 0, cpu_usage_percent: 0.0,
285 active_operations: 0,
286 queue_depth: 0,
287 last_success_time: None,
288 uptime_seconds: 0,
289 },
290 performance_metrics: None,
291 };
292
293 let recovery_suggestions = self.generate_recovery_suggestions();
294
295 AdvancedError {
296 category,
297 severity,
298 message: self.to_string(),
299 technical_details: format!("CLI Error: {:?}", self),
300 context,
301 recovery_suggestions,
302 related_errors: vec![],
303 timestamp: SystemTime::now()
304 .duration_since(UNIX_EPOCH)
305 .unwrap_or_default()
306 .as_secs(),
307 error_id: format!("cli_error_{}", fastrand::u64(..)),
308 recoverable: self.is_recoverable(),
309 retry_info: if self.is_recoverable() {
310 Some(RetryInfo {
311 attempt: 0,
312 max_attempts: 3,
313 retry_delay: std::time::Duration::from_secs(1),
314 backoff_strategy: BackoffStrategy::Exponential,
315 last_retry: None,
316 success_history: vec![],
317 })
318 } else {
319 None
320 },
321 }
322 }
323
324 fn generate_recovery_suggestions(&self) -> Vec<advanced_handler::RecoverySuggestion> {
326 use advanced_handler::*;
327 use std::collections::HashMap;
328
329 match self {
330 CliError::NetworkError(_) => vec![RecoverySuggestion {
331 category: RecoveryCategory::NetworkTroubleshooting,
332 priority: 8,
333 suggestion: "Check internet connection and retry".to_string(),
334 steps: vec![
335 "Check internet connectivity".to_string(),
336 "Verify DNS resolution".to_string(),
337 "Retry the operation".to_string(),
338 ],
339 estimated_time: std::time::Duration::from_secs(30),
340 difficulty: DifficultyLevel::Easy,
341 success_probability: 0.8,
342 requires_user_action: true,
343 automated_actions: vec![AutomatedAction {
344 action_type: ActionType::RetryOperation,
345 description: "Retry with exponential backoff".to_string(),
346 parameters: HashMap::new(),
347 safe_to_automate: true,
348 execution_time: std::time::Duration::from_secs(10),
349 dependencies: vec![],
350 }],
351 }],
352 CliError::Config { .. } => vec![RecoverySuggestion {
353 category: RecoveryCategory::ConfigurationFix,
354 priority: 7,
355 suggestion: "Initialize default configuration".to_string(),
356 steps: vec![
357 "Run 'voirs config --init'".to_string(),
358 "Verify configuration with 'voirs config --show'".to_string(),
359 ],
360 estimated_time: std::time::Duration::from_secs(10),
361 difficulty: DifficultyLevel::Easy,
362 success_probability: 0.9,
363 requires_user_action: true,
364 automated_actions: vec![],
365 }],
366 CliError::ModelLoadingError(_) => vec![RecoverySuggestion {
367 category: RecoveryCategory::ResourceOptimization,
368 priority: 6,
369 suggestion: "Validate and re-download model".to_string(),
370 steps: vec![
371 "Check available models with 'voirs list-models'".to_string(),
372 "Download required model".to_string(),
373 "Verify model integrity".to_string(),
374 ],
375 estimated_time: std::time::Duration::from_secs(300),
376 difficulty: DifficultyLevel::Medium,
377 success_probability: 0.7,
378 requires_user_action: true,
379 automated_actions: vec![AutomatedAction {
380 action_type: ActionType::ValidateConfiguration,
381 description: "Validate model files".to_string(),
382 parameters: HashMap::new(),
383 safe_to_automate: true,
384 execution_time: std::time::Duration::from_secs(30),
385 dependencies: vec![],
386 }],
387 }],
388 _ => vec![RecoverySuggestion {
389 category: RecoveryCategory::RetryOptimization,
390 priority: 5,
391 suggestion: "Retry the operation".to_string(),
392 steps: vec![
393 "Wait a moment".to_string(),
394 "Retry the same command".to_string(),
395 ],
396 estimated_time: std::time::Duration::from_secs(5),
397 difficulty: DifficultyLevel::Trivial,
398 success_probability: 0.5,
399 requires_user_action: true,
400 automated_actions: vec![],
401 }],
402 }
403 }
404
405 fn is_recoverable(&self) -> bool {
407 match self {
408 CliError::NetworkError(_) => true,
409 CliError::Config { .. } => true,
410 CliError::File { .. } => true,
411 CliError::ModelLoadingError(_) => true,
412 CliError::MissingDependency(_) => true,
413 CliError::InvalidParameter { .. } => false,
414 CliError::AudioFormat { .. } => false,
415 CliError::VoiceNotFound { .. } => false,
416 _ => true,
417 }
418 }
419
420 pub fn user_message(&self) -> String {
422 match self {
423 CliError::Config { message } => {
424 format!("Configuration error: {}\n\nTry running 'voirs config --init' to create a default configuration.", message)
425 }
426 CliError::File {
427 operation,
428 path,
429 source,
430 } => {
431 format!("Failed to {} '{}': {}\n\nPlease check that the path exists and you have the necessary permissions.", operation, path, source)
432 }
433 CliError::AudioFormat { format, supported } => {
434 format!("Unsupported audio format: '{}'\n\nSupported formats: {}\n\nExample: voirs synthesize \"Hello\" --output audio.wav", format, supported)
435 }
436 CliError::VoiceNotFound {
437 voice_id,
438 available,
439 } => {
440 format!("Voice '{}' not found.\n\nAvailable voices: {}\n\nUse 'voirs voices list' to see all available voices.", voice_id, available)
441 }
442 CliError::InvalidParameter { parameter, message } => {
443 format!(
444 "Invalid parameter '{}': {}\n\nUse 'voirs --help' for usage information.",
445 parameter, message
446 )
447 }
448 CliError::Sdk(e) => {
449 format!("VoiRS synthesis error: {}\n\nThis might be a model loading or synthesis issue. Try checking your voice installation with 'voirs voices list'.", e)
450 }
451 CliError::Serialization(e) => {
452 format!("Data serialization error: {}\n\nThis might indicate a configuration file corruption.", e)
453 }
454 CliError::Toml(e) => {
455 format!(
456 "TOML configuration error: {}\n\nPlease check your configuration file syntax.",
457 e
458 )
459 }
460 CliError::Io(e) => {
461 format!("File system error: {}\n\nPlease check file permissions and available disk space.", e)
462 }
463 CliError::VoiceError(e) => {
464 format!(
465 "Voice error: {}\n\nPlease check available voices with 'voirs voices list'.",
466 e
467 )
468 }
469 CliError::AudioError(e) => {
470 format!(
471 "Audio system error: {}\n\nPlease check your audio device configuration.",
472 e
473 )
474 }
475 CliError::SynthesisError(e) => {
476 format!(
477 "Synthesis error: {}\n\nThis might be a model or configuration issue.",
478 e
479 )
480 }
481 CliError::ValidationError(e) => {
482 format!("Validation error: {}\n\nPlease check your input format.", e)
483 }
484 CliError::IoError(e) => {
485 format!(
486 "I/O error: {}\n\nPlease check file paths and permissions.",
487 e
488 )
489 }
490 CliError::SerializationError(e) => {
491 format!(
492 "Serialization error: {}\n\nThis might indicate corrupted data.",
493 e
494 )
495 }
496 CliError::InvalidArgument(e) => {
497 format!(
498 "Invalid argument: {}\n\nPlease check command usage with --help.",
499 e
500 )
501 }
502 CliError::NotImplemented(e) => {
503 format!(
504 "Feature not implemented: {}\n\nThis feature is coming in a future update.",
505 e
506 )
507 }
508 CliError::InteractiveError(e) => {
509 format!(
510 "Interactive mode error: {}\n\nTry restarting the interactive session.",
511 e
512 )
513 }
514 CliError::PackagingError(e) => {
515 format!(
516 "Packaging error: {}\n\nPlease check your packaging configuration and dependencies.",
517 e
518 )
519 }
520 CliError::UpdateError(e) => {
521 format!(
522 "Update error: {}\n\nPlease check your network connection and try again.",
523 e
524 )
525 }
526 CliError::EmotionError(e) => {
527 format!(
528 "Emotion control error: {}\n\nSuggestions:\n- Check if emotion models are installed\n- Verify emotion intensity (0.0-1.0)\n- Use 'voirs capabilities check emotion' to verify feature availability\n- Use 'voirs emotion list' to see available emotions",
529 e
530 )
531 }
532 CliError::CloningError(e) => {
533 format!(
534 "Voice cloning error: {}\n\nSuggestions:\n- Ensure reference audio is high quality (16kHz+, clear speech)\n- Use at least 30 seconds of reference audio\n- Check if voice cloning models are installed\n- Use 'voirs capabilities check cloning' to verify feature availability\n- Use 'voirs clone validate' to check reference audio quality",
535 e
536 )
537 }
538 CliError::ConversionError(e) => {
539 format!(
540 "Voice conversion error: {}\n\nSuggestions:\n- Check if voice conversion models are installed\n- Verify input audio quality and format\n- Use 'voirs capabilities check conversion' to verify feature availability\n- Try reducing conversion intensity for better results",
541 e
542 )
543 }
544 CliError::SingingError(e) => {
545 format!(
546 "Singing synthesis error: {}\n\nSuggestions:\n- Check if singing models are installed\n- Verify musical score format (MusicXML, MIDI)\n- Ensure lyrics are properly formatted\n- Use 'voirs capabilities check singing' to verify feature availability\n- Use 'voirs sing validate' to check score format",
547 e
548 )
549 }
550 CliError::SpatialError(e) => {
551 format!(
552 "Spatial audio error: {}\n\nSuggestions:\n- Check if spatial audio models are installed\n- Verify HRTF dataset is available\n- Use 'voirs capabilities check spatial' to verify feature availability\n- Ensure position coordinates are valid (x,y,z format)",
553 e
554 )
555 }
556 CliError::ModelLoadingError(e) => {
557 format!(
558 "Model loading error: {}\n\nSuggestions:\n- Check if the required model files are present\n- Verify model file integrity\n- Use 'voirs list-models' to see available models\n- Try downloading the model again with 'voirs download-model'\n- Check available disk space and memory",
559 e
560 )
561 }
562 CliError::FeatureNotAvailable(e) => {
563 format!(
564 "Feature not available: {}\n\nSuggestions:\n- Check if the feature is enabled in your configuration\n- Verify feature dependencies are installed\n- Use 'voirs capabilities list' to see all available features\n- Check if your VoiRS version supports this feature",
565 e
566 )
567 }
568 CliError::MissingDependency(e) => {
569 format!(
570 "Missing dependency: {}\n\nSuggestions:\n- Install the required dependency\n- Use 'voirs capabilities requirements' to see all requirements\n- Check the installation documentation\n- Verify your system meets all prerequisites",
571 e
572 )
573 }
574 CliError::HardwareRequirement(e) => {
575 format!(
576 "Hardware requirement not met: {}\n\nSuggestions:\n- Check if your hardware meets the minimum requirements\n- Try using CPU-only mode if GPU is not available\n- Reduce quality settings for better performance\n- Use 'voirs capabilities list' to see system requirements",
577 e
578 )
579 }
580 CliError::NetworkError(e) => {
581 format!(
582 "Network error: {}\n\nSuggestions:\n- Check your internet connection\n- Verify proxy settings if applicable\n- Try again later if the server is temporarily unavailable\n- Check firewall settings",
583 e
584 )
585 }
586 CliError::PerformanceWarning(e) => {
587 format!(
588 "Performance warning: {}\n\nSuggestions:\n- Consider using GPU acceleration with --gpu flag\n- Reduce quality settings for faster processing\n- Close other resource-intensive applications\n- Use 'voirs capabilities list' to check system capabilities",
589 e
590 )
591 }
592 CliError::Workflow(e) => {
593 format!(
594 "Workflow execution error: {}\n\nSuggestions:\n- Check workflow definition syntax\n- Verify all step dependencies exist\n- Use 'voirs workflow validate' to check workflow\n- Check workflow state with 'voirs workflow status'",
595 e
596 )
597 }
598 CliError::Advanced(advanced_error) => {
599 format!("Advanced error: {}", advanced_error.message)
601 }
602 }
603 }
604
605 pub fn exit_code(&self) -> i32 {
607 match self {
608 CliError::Config { .. } => 1,
609 CliError::File { .. } => 2,
610 CliError::AudioFormat { .. } => 3,
611 CliError::VoiceNotFound { .. } => 4,
612 CliError::InvalidParameter { .. } => 5,
613 CliError::Sdk(_) => 10,
614 CliError::Serialization(_) => 11,
615 CliError::Toml(_) => 11,
616 CliError::Io(_) => 12,
617 CliError::VoiceError(_) => 13,
618 CliError::AudioError(_) => 14,
619 CliError::SynthesisError(_) => 15,
620 CliError::ValidationError(_) => 16,
621 CliError::IoError(_) => 17,
622 CliError::SerializationError(_) => 17,
623 CliError::InvalidArgument(_) => 18,
624 CliError::NotImplemented(_) => 19,
625 CliError::InteractiveError(_) => 20,
626 CliError::PackagingError(_) => 21,
627 CliError::UpdateError(_) => 22,
628 CliError::EmotionError(_) => 30,
629 CliError::CloningError(_) => 31,
630 CliError::ConversionError(_) => 32,
631 CliError::SingingError(_) => 33,
632 CliError::SpatialError(_) => 34,
633 CliError::ModelLoadingError(_) => 35,
634 CliError::FeatureNotAvailable(_) => 36,
635 CliError::MissingDependency(_) => 37,
636 CliError::HardwareRequirement(_) => 38,
637 CliError::NetworkError(_) => 39,
638 CliError::PerformanceWarning(_) => 40,
639 CliError::Workflow(_) => 41,
640 CliError::Advanced(_) => 50,
641 }
642 }
643}
644
645pub type Result<T> = std::result::Result<T, CliError>;
647pub type VoirsCliError = CliError;
648pub type VoirsCLIError = CliError;
649
650impl From<CliError> for voirs_sdk::VoirsError {
652 fn from(err: CliError) -> Self {
653 match err {
654 CliError::Sdk(voirs_err) => voirs_err,
655 other => voirs_sdk::VoirsError::InternalError {
656 component: "voirs-cli".to_string(),
657 message: other.to_string(),
658 },
659 }
660 }
661}
662
663pub trait ErrorContext<T> {
665 fn with_context<F, S>(self, f: F) -> Result<T>
666 where
667 F: FnOnce() -> S,
668 S: Into<String>;
669}
670
671impl<T> ErrorContext<T> for std::result::Result<T, std::io::Error> {
672 fn with_context<F, S>(self, f: F) -> Result<T>
673 where
674 F: FnOnce() -> S,
675 S: Into<String>,
676 {
677 self.map_err(|e| CliError::config(f().into()))
678 }
679}
680
681pub mod formatting {
683 use super::CliError;
684 use crate::output::get_formatter;
685
686 pub fn print_error(error: &CliError) {
688 let formatter = get_formatter();
689 formatter.error(&error.user_message());
690
691 match error {
693 CliError::VoiceNotFound { .. } => {
694 formatter.info("Suggested commands:");
695 formatter.list_item("voirs voices list", 1);
696 formatter.list_item("voirs voices download <voice-id>", 1);
697 }
698 CliError::AudioFormat { .. } => {
699 formatter.info("Example usage:");
700 formatter.list_item("voirs synthesize \"Hello\" -o output.wav", 1);
701 formatter.list_item("voirs synthesize \"Hello\" -o output.mp3", 1);
702 }
703 CliError::Config { .. } => {
704 formatter.info("Configuration commands:");
705 formatter.list_item("voirs config --init", 1);
706 formatter.list_item("voirs config --show", 1);
707 }
708 CliError::EmotionError(_) => {
709 formatter.info("Emotion control commands:");
710 formatter.list_item("voirs emotion list", 1);
711 formatter.list_item("voirs capabilities check emotion", 1);
712 formatter.list_item("voirs guide emotion", 1);
713 }
714 CliError::CloningError(_) => {
715 formatter.info("Voice cloning commands:");
716 formatter.list_item("voirs clone validate --reference-files samples/*.wav", 1);
717 formatter.list_item("voirs capabilities check cloning", 1);
718 formatter.list_item("voirs guide clone", 1);
719 }
720 CliError::ConversionError(_) => {
721 formatter.info("Voice conversion commands:");
722 formatter.list_item("voirs convert list-models", 1);
723 formatter.list_item("voirs capabilities check conversion", 1);
724 formatter.list_item("voirs guide convert", 1);
725 }
726 CliError::SingingError(_) => {
727 formatter.info("Singing synthesis commands:");
728 formatter.list_item("voirs sing validate --score score.xml", 1);
729 formatter.list_item("voirs capabilities check singing", 1);
730 formatter.list_item("voirs guide sing", 1);
731 }
732 CliError::SpatialError(_) => {
733 formatter.info("Spatial audio commands:");
734 formatter.list_item("voirs spatial validate --test-audio test.wav", 1);
735 formatter.list_item("voirs capabilities check spatial", 1);
736 formatter.list_item("voirs guide spatial", 1);
737 }
738 CliError::ModelLoadingError(_) => {
739 formatter.info("Model management commands:");
740 formatter.list_item("voirs list-models", 1);
741 formatter.list_item("voirs download-model <model-id>", 1);
742 formatter.list_item("voirs capabilities requirements", 1);
743 }
744 CliError::FeatureNotAvailable(_) => {
745 formatter.info("Feature diagnosis commands:");
746 formatter.list_item("voirs capabilities list", 1);
747 formatter.list_item("voirs capabilities requirements", 1);
748 formatter.list_item("voirs config --show", 1);
749 }
750 CliError::MissingDependency(_) => {
751 formatter.info("Dependency check commands:");
752 formatter.list_item("voirs capabilities requirements", 1);
753 formatter.list_item("voirs test", 1);
754 }
755 CliError::HardwareRequirement(_) => {
756 formatter.info("Hardware check commands:");
757 formatter.list_item("voirs capabilities list", 1);
758 formatter.list_item("voirs test --gpu", 1);
759 }
760 CliError::NetworkError(_) => {
761 formatter.info("Network troubleshooting:");
762 formatter.list_item("Check internet connectivity", 1);
763 formatter.list_item("Verify proxy settings", 1);
764 formatter.list_item("Try again later", 1);
765 }
766 CliError::PerformanceWarning(_) => {
767 formatter.info("Performance optimization:");
768 formatter.list_item("Use --gpu flag for acceleration", 1);
769 formatter.list_item("Reduce quality settings", 1);
770 formatter.list_item("Close other applications", 1);
771 }
772 CliError::Advanced(advanced_error) => {
773 formatter.info("Advanced error detected - recovery suggestions available");
775 for suggestion in &advanced_error.recovery_suggestions {
776 formatter.list_item(&suggestion.suggestion, 1);
777 }
778 }
779 _ => {}
780 }
781 }
782
783 pub fn print_warning(message: &str) {
785 get_formatter().warning(message);
786 }
787
788 pub fn print_info(message: &str) {
790 get_formatter().info(message);
791 }
792}