Skip to main content

voirs_cli/help/
mod.rs

1//! Enhanced help system for VoiRS CLI
2//!
3//! Provides context-sensitive help, examples, and tips for better user experience.
4
5use console::{style, Style};
6use std::collections::HashMap;
7
8/// Help content for commands and concepts
9pub struct HelpSystem {
10    /// Command-specific help content
11    pub command_help: HashMap<String, CommandHelp>,
12    /// General tips and concepts
13    general_tips: Vec<HelpTip>,
14}
15
16/// Help content for a specific command
17#[derive(Debug, Clone)]
18pub struct CommandHelp {
19    /// Brief description
20    pub description: String,
21    /// Detailed explanation
22    pub detailed: String,
23    /// Usage examples
24    pub examples: Vec<HelpExample>,
25    /// Related commands
26    pub related: Vec<String>,
27    /// Common issues and solutions
28    pub troubleshooting: Vec<HelpTip>,
29}
30
31/// A help example with description
32#[derive(Debug, Clone)]
33pub struct HelpExample {
34    /// Example command
35    pub command: String,
36    /// Description of what it does
37    pub description: String,
38    /// Expected output or result
39    pub expected: Option<String>,
40}
41
42/// A help tip or troubleshooting item
43#[derive(Debug, Clone)]
44pub struct HelpTip {
45    /// Title of the tip
46    pub title: String,
47    /// Detailed explanation
48    pub content: String,
49    /// Severity level (info, warning, error)
50    pub level: TipLevel,
51}
52
53/// Severity level for tips
54#[derive(Debug, Clone, PartialEq)]
55pub enum TipLevel {
56    Info,
57    Warning,
58    Error,
59}
60
61impl HelpSystem {
62    /// Create a new help system with all content loaded
63    pub fn new() -> Self {
64        let mut help_system = Self {
65            command_help: HashMap::new(),
66            general_tips: Vec::new(),
67        };
68
69        help_system.load_command_help();
70        help_system.load_general_tips();
71        help_system
72    }
73
74    /// Get help for a specific command
75    pub fn get_command_help(&self, command: &str) -> Option<&CommandHelp> {
76        self.command_help.get(command)
77    }
78
79    /// Display formatted help for a command
80    pub fn display_command_help(&self, command: &str) -> String {
81        if let Some(help) = self.get_command_help(command) {
82            self.format_command_help(command, help)
83        } else {
84            self.format_unknown_command(command)
85        }
86    }
87
88    /// Get context-sensitive help based on error or situation
89    pub fn get_contextual_help(&self, context: &str) -> Vec<String> {
90        let mut suggestions = Vec::new();
91
92        match context {
93            "voice_not_found" => {
94                suggestions.push("List available voices with: voirs list-voices".to_string());
95                suggestions
96                    .push("Download a voice with: voirs download-voice <voice-id>".to_string());
97            }
98            "model_not_found" => {
99                suggestions.push("List available models with: voirs list-models".to_string());
100                suggestions
101                    .push("Download a model with: voirs download-model <model-id>".to_string());
102            }
103            "file_not_found" => {
104                suggestions.push("Check if the file path is correct".to_string());
105                suggestions.push("Use absolute paths for clarity".to_string());
106            }
107            "permission_denied" => {
108                suggestions.push("Check file/directory permissions".to_string());
109                suggestions.push("Try running with appropriate permissions".to_string());
110            }
111            "gpu_error" => {
112                suggestions.push("Check GPU availability with: voirs test --gpu".to_string());
113                suggestions.push("Fallback to CPU mode by removing --gpu flag".to_string());
114            }
115            _ => {
116                suggestions.push("Use 'voirs guide' for general help".to_string());
117                suggestions
118                    .push("Use 'voirs guide <command>' for command-specific help".to_string());
119            }
120        }
121
122        suggestions
123    }
124
125    /// Display all available commands with brief descriptions
126    pub fn display_command_overview(&self) -> String {
127        let mut output = String::new();
128
129        output.push_str(&format!(
130            "{}\n\n",
131            style("VoiRS CLI Commands").bold().cyan()
132        ));
133
134        let categories = vec![
135            (
136                "Synthesis",
137                vec!["synthesize", "synthesize-file", "batch", "interactive"],
138            ),
139            (
140                "Advanced Voice Features",
141                vec!["emotion", "clone", "convert", "sing", "spatial"],
142            ),
143            (
144                "Voice Management",
145                vec!["list-voices", "voice-info", "download-voice"],
146            ),
147            (
148                "Model Management",
149                vec![
150                    "list-models",
151                    "download-model",
152                    "benchmark-models",
153                    "optimize-model",
154                ],
155            ),
156            ("System", vec!["config", "test", "server", "capabilities"]),
157        ];
158
159        for (category, commands) in categories {
160            output.push_str(&format!("{}\n", style(category).bold().yellow()));
161
162            for cmd in commands {
163                if let Some(help) = self.get_command_help(cmd) {
164                    output.push_str(&format!(
165                        "  {} - {}\n",
166                        style(cmd).green(),
167                        help.description
168                    ));
169                }
170            }
171            output.push('\n');
172        }
173
174        output.push_str(&format!(
175            "\n{}\n",
176            style("Use 'voirs guide <command>' for detailed information about a specific command.")
177                .dim()
178        ));
179
180        output
181    }
182
183    /// Format command help output
184    fn format_command_help(&self, command: &str, help: &CommandHelp) -> String {
185        let mut output = String::new();
186
187        // Command title
188        output.push_str(&format!(
189            "{}\n",
190            style(format!("voirs {}", command)).bold().cyan()
191        ));
192        output.push_str(&format!("{}\n\n", help.description));
193
194        // Detailed description
195        if !help.detailed.is_empty() {
196            output.push_str(&format!("{}\n", style("Description:").bold().yellow()));
197            output.push_str(&format!("{}\n\n", help.detailed));
198        }
199
200        // Examples
201        if !help.examples.is_empty() {
202            output.push_str(&format!("{}\n", style("Examples:").bold().yellow()));
203            for example in &help.examples {
204                output.push_str(&format!("  {}\n", style(&example.command).green()));
205                output.push_str(&format!("    {}\n", example.description));
206
207                if let Some(expected) = &example.expected {
208                    output.push_str(&format!("    Expected: {}\n", style(expected).dim()));
209                }
210                output.push('\n');
211            }
212        }
213
214        // Related commands
215        if !help.related.is_empty() {
216            output.push_str(&format!("{}\n", style("Related Commands:").bold().yellow()));
217            for related in &help.related {
218                output.push_str(&format!("  voirs {}\n", style(related).green()));
219            }
220            output.push('\n');
221        }
222
223        // Troubleshooting
224        if !help.troubleshooting.is_empty() {
225            output.push_str(&format!("{}\n", style("Troubleshooting:").bold().yellow()));
226            for tip in &help.troubleshooting {
227                let tip_style = match tip.level {
228                    TipLevel::Info => Style::new().blue(),
229                    TipLevel::Warning => Style::new().yellow(),
230                    TipLevel::Error => Style::new().red(),
231                };
232
233                output.push_str(&format!(
234                    "  {} {}\n",
235                    tip_style.apply_to("•"),
236                    style(&tip.title).bold()
237                ));
238                output.push_str(&format!("    {}\n", tip.content));
239            }
240        }
241
242        output
243    }
244
245    /// Format response for unknown command
246    fn format_unknown_command(&self, command: &str) -> String {
247        let mut output = String::new();
248
249        output.push_str(&format!(
250            "{}\n\n",
251            style(format!("Unknown command: '{}'", command))
252                .red()
253                .bold()
254        ));
255
256        // Suggest similar commands
257        let similar = self.find_similar_commands(command);
258        if !similar.is_empty() {
259            output.push_str(&format!("{}\n", style("Did you mean:").yellow()));
260            for suggestion in similar {
261                output.push_str(&format!("  voirs {}\n", style(suggestion).green()));
262            }
263            output.push('\n');
264        }
265
266        output.push_str(&format!(
267            "{}\n",
268            style("Use 'voirs guide' to see all available commands.").dim()
269        ));
270
271        output
272    }
273
274    /// Find commands similar to the given input
275    fn find_similar_commands(&self, input: &str) -> Vec<String> {
276        let mut similar = Vec::new();
277
278        for command in self.command_help.keys() {
279            if command.contains(input) || input.contains(command) {
280                similar.push(command.clone());
281            }
282        }
283
284        // Limit to top 3 suggestions
285        similar.truncate(3);
286        similar
287    }
288
289    /// Load all command help content
290    fn load_command_help(&mut self) {
291        // Synthesis commands
292        self.add_synthesize_help();
293        self.add_synthesize_file_help();
294        self.add_batch_help();
295        self.add_interactive_help();
296
297        // Advanced voice features
298        self.add_emotion_help();
299        self.add_clone_help();
300        self.add_convert_help();
301        self.add_sing_help();
302        self.add_spatial_help();
303
304        // Voice management
305        self.add_list_voices_help();
306        self.add_voice_info_help();
307        self.add_download_voice_help();
308
309        // Model management
310        self.add_list_models_help();
311        self.add_download_model_help();
312        self.add_benchmark_models_help();
313        self.add_optimize_model_help();
314
315        // System commands
316        self.add_config_help();
317        self.add_test_help();
318        self.add_server_help();
319        self.add_guide_help();
320        self.add_capabilities_help();
321    }
322
323    /// Load general tips and concepts
324    fn load_general_tips(&mut self) {
325        self.general_tips.extend(vec![
326            HelpTip {
327                title: "Getting Started".to_string(),
328                content: "Run 'voirs test' to verify your installation and download a basic voice.".to_string(),
329                level: TipLevel::Info,
330            },
331            HelpTip {
332                title: "Configuration".to_string(),
333                content: "Use 'voirs config --init' to create a configuration file with your preferences.".to_string(),
334                level: TipLevel::Info,
335            },
336            HelpTip {
337                title: "Performance".to_string(),
338                content: "Enable GPU acceleration with --gpu flag for faster synthesis on supported hardware.".to_string(),
339                level: TipLevel::Info,
340            },
341        ]);
342    }
343
344    // Helper methods to add specific command help
345    fn add_synthesize_help(&mut self) {
346        self.command_help.insert("synthesize".to_string(), CommandHelp {
347            description: "Convert text to speech using neural synthesis".to_string(),
348            detailed: "The synthesize command processes input text and generates high-quality speech audio. \
349                      It supports various audio formats, speaking rates, pitch adjustments, and quality levels.".to_string(),
350            examples: vec![
351                HelpExample {
352                    command: "voirs synthesize \"Hello, world!\"".to_string(),
353                    description: "Basic synthesis with default settings".to_string(),
354                    expected: Some("Creates audio file with generated filename".to_string()),
355                },
356                HelpExample {
357                    command: "voirs synthesize \"Hello, world!\" --output hello.wav".to_string(),
358                    description: "Synthesize to specific output file".to_string(),
359                    expected: Some("Creates hello.wav".to_string()),
360                },
361                HelpExample {
362                    command: "voirs synthesize \"Fast speech\" --rate 1.5 --quality ultra".to_string(),
363                    description: "Faster speech with highest quality".to_string(),
364                    expected: None,
365                },
366            ],
367            related: vec!["synthesize-file".to_string(), "batch".to_string(), "interactive".to_string()],
368            troubleshooting: vec![
369                HelpTip {
370                    title: "Slow synthesis".to_string(),
371                    content: "Try using --gpu flag for hardware acceleration or lower quality settings".to_string(),
372                    level: TipLevel::Info,
373                },
374                HelpTip {
375                    title: "Quality issues".to_string(),
376                    content: "Use --quality ultra for best results, or check voice compatibility".to_string(),
377                    level: TipLevel::Warning,
378                },
379            ],
380        });
381    }
382
383    fn add_synthesize_file_help(&mut self) {
384        self.command_help.insert("synthesize-file".to_string(), CommandHelp {
385            description: "Synthesize text from input file".to_string(),
386            detailed: "Process a text file and generate speech audio. The input file is read line by line, \
387                      with each line treated as a separate synthesis request.".to_string(),
388            examples: vec![
389                HelpExample {
390                    command: "voirs synthesize-file input.txt".to_string(),
391                    description: "Synthesize all lines from input.txt".to_string(),
392                    expected: Some("Creates multiple audio files".to_string()),
393                },
394                HelpExample {
395                    command: "voirs synthesize-file input.txt --output-dir ./audio/".to_string(),
396                    description: "Output to specific directory".to_string(),
397                    expected: None,
398                },
399            ],
400            related: vec!["synthesize".to_string(), "batch".to_string()],
401            troubleshooting: vec![],
402        });
403    }
404
405    fn add_batch_help(&mut self) {
406        self.command_help.insert("batch".to_string(), CommandHelp {
407            description: "Process multiple texts with parallel synthesis".to_string(),
408            detailed: "Batch processing supports various input formats (TXT, CSV, JSON, JSONL) and \
409                      provides efficient parallel processing with progress tracking and resume capability.".to_string(),
410            examples: vec![
411                HelpExample {
412                    command: "voirs batch texts.csv --workers 4".to_string(),
413                    description: "Process CSV file with 4 parallel workers".to_string(),
414                    expected: None,
415                },
416                HelpExample {
417                    command: "voirs batch data.jsonl --resume".to_string(),
418                    description: "Resume interrupted batch processing".to_string(),
419                    expected: None,
420                },
421            ],
422            related: vec!["synthesize".to_string(), "synthesize-file".to_string()],
423            troubleshooting: vec![
424                HelpTip {
425                    title: "Memory usage".to_string(),
426                    content: "Reduce --workers count if experiencing high memory usage".to_string(),
427                    level: TipLevel::Warning,
428                },
429            ],
430        });
431    }
432
433    fn add_interactive_help(&mut self) {
434        self.command_help.insert(
435            "interactive".to_string(),
436            CommandHelp {
437                description: "Real-time interactive synthesis shell".to_string(),
438                detailed:
439                    "Interactive mode provides a shell-like interface for real-time text-to-speech \
440                      synthesis with session management and live audio playback."
441                        .to_string(),
442                examples: vec![
443                    HelpExample {
444                        command: "voirs interactive".to_string(),
445                        description: "Start interactive mode with default voice".to_string(),
446                        expected: Some("Opens interactive shell".to_string()),
447                    },
448                    HelpExample {
449                        command: "voirs interactive --voice en-us-female".to_string(),
450                        description: "Start with specific voice".to_string(),
451                        expected: None,
452                    },
453                ],
454                related: vec!["synthesize".to_string()],
455                troubleshooting: vec![HelpTip {
456                    title: "Audio playback issues".to_string(),
457                    content:
458                        "Use --no-audio flag to disable playback if experiencing audio problems"
459                            .to_string(),
460                    level: TipLevel::Warning,
461                }],
462            },
463        );
464    }
465
466    fn add_list_voices_help(&mut self) {
467        self.command_help.insert(
468            "list-voices".to_string(),
469            CommandHelp {
470                description: "Display available voices".to_string(),
471                detailed: "List all installed and available voices with their characteristics, \
472                      languages, and installation status."
473                    .to_string(),
474                examples: vec![
475                    HelpExample {
476                        command: "voirs list-voices".to_string(),
477                        description: "Show all available voices".to_string(),
478                        expected: None,
479                    },
480                    HelpExample {
481                        command: "voirs list-voices --language en".to_string(),
482                        description: "Filter by English voices only".to_string(),
483                        expected: None,
484                    },
485                ],
486                related: vec!["voice-info".to_string(), "download-voice".to_string()],
487                troubleshooting: vec![],
488            },
489        );
490    }
491
492    fn add_voice_info_help(&mut self) {
493        self.command_help.insert(
494            "voice-info".to_string(),
495            CommandHelp {
496                description: "Get detailed information about a specific voice".to_string(),
497                detailed: "Display comprehensive information about a voice including metadata, \
498                      quality metrics, and usage examples."
499                    .to_string(),
500                examples: vec![HelpExample {
501                    command: "voirs voice-info en-us-female".to_string(),
502                    description: "Show details for English US female voice".to_string(),
503                    expected: None,
504                }],
505                related: vec!["list-voices".to_string(), "download-voice".to_string()],
506                troubleshooting: vec![],
507            },
508        );
509    }
510
511    fn add_download_voice_help(&mut self) {
512        self.command_help.insert(
513            "download-voice".to_string(),
514            CommandHelp {
515                description: "Download and install a voice model".to_string(),
516                detailed: "Download voice models from the repository with progress tracking \
517                      and checksum verification."
518                    .to_string(),
519                examples: vec![HelpExample {
520                    command: "voirs download-voice en-us-female".to_string(),
521                    description: "Download English US female voice".to_string(),
522                    expected: Some("Downloads and installs voice model".to_string()),
523                }],
524                related: vec!["list-voices".to_string(), "voice-info".to_string()],
525                troubleshooting: vec![HelpTip {
526                    title: "Download fails".to_string(),
527                    content: "Check internet connection and available disk space".to_string(),
528                    level: TipLevel::Error,
529                }],
530            },
531        );
532    }
533
534    fn add_list_models_help(&mut self) {
535        self.command_help.insert(
536            "list-models".to_string(),
537            CommandHelp {
538                description: "Display available synthesis models".to_string(),
539                detailed: "List acoustic models, vocoders, and other synthesis components \
540                      with compatibility and performance information."
541                    .to_string(),
542                examples: vec![HelpExample {
543                    command: "voirs list-models".to_string(),
544                    description: "Show all available models".to_string(),
545                    expected: None,
546                }],
547                related: vec!["download-model".to_string(), "benchmark-models".to_string()],
548                troubleshooting: vec![],
549            },
550        );
551    }
552
553    fn add_download_model_help(&mut self) {
554        self.command_help.insert(
555            "download-model".to_string(),
556            CommandHelp {
557                description: "Download and install synthesis models".to_string(),
558                detailed: "Download acoustic models, vocoders, and other synthesis components \
559                      required for text-to-speech synthesis."
560                    .to_string(),
561                examples: vec![HelpExample {
562                    command: "voirs download-model tacotron2-en".to_string(),
563                    description: "Download Tacotron2 English model".to_string(),
564                    expected: None,
565                }],
566                related: vec!["list-models".to_string(), "optimize-model".to_string()],
567                troubleshooting: vec![],
568            },
569        );
570    }
571
572    fn add_benchmark_models_help(&mut self) {
573        self.command_help.insert(
574            "benchmark-models".to_string(),
575            CommandHelp {
576                description: "Benchmark model performance".to_string(),
577                detailed: "Run performance tests on synthesis models to measure speed, \
578                      quality, and resource usage."
579                    .to_string(),
580                examples: vec![HelpExample {
581                    command: "voirs benchmark-models tacotron2-en hifigan-en".to_string(),
582                    description: "Benchmark multiple models".to_string(),
583                    expected: None,
584                }],
585                related: vec!["list-models".to_string(), "optimize-model".to_string()],
586                troubleshooting: vec![],
587            },
588        );
589    }
590
591    fn add_optimize_model_help(&mut self) {
592        self.command_help.insert(
593            "optimize-model".to_string(),
594            CommandHelp {
595                description: "Optimize models for current hardware".to_string(),
596                detailed: "Apply hardware-specific optimizations to improve synthesis \
597                      performance and reduce memory usage."
598                    .to_string(),
599                examples: vec![HelpExample {
600                    command: "voirs optimize-model tacotron2-en".to_string(),
601                    description: "Optimize model for current hardware".to_string(),
602                    expected: None,
603                }],
604                related: vec!["benchmark-models".to_string(), "list-models".to_string()],
605                troubleshooting: vec![],
606            },
607        );
608    }
609
610    fn add_config_help(&mut self) {
611        self.command_help.insert(
612            "config".to_string(),
613            CommandHelp {
614                description: "Manage configuration settings".to_string(),
615                detailed: "View, modify, and manage VoiRS configuration including \
616                      default voices, quality settings, and preferences."
617                    .to_string(),
618                examples: vec![
619                    HelpExample {
620                        command: "voirs config --show".to_string(),
621                        description: "Display current configuration".to_string(),
622                        expected: None,
623                    },
624                    HelpExample {
625                        command: "voirs config --init".to_string(),
626                        description: "Create default configuration file".to_string(),
627                        expected: Some("Creates config.toml".to_string()),
628                    },
629                ],
630                related: vec![],
631                troubleshooting: vec![],
632            },
633        );
634    }
635
636    fn add_test_help(&mut self) {
637        self.command_help.insert(
638            "test".to_string(),
639            CommandHelp {
640                description: "Test synthesis pipeline and installation".to_string(),
641                detailed: "Verify that VoiRS is properly installed and configured \
642                      by running a test synthesis."
643                    .to_string(),
644                examples: vec![
645                    HelpExample {
646                        command: "voirs test".to_string(),
647                        description: "Run basic synthesis test".to_string(),
648                        expected: Some("Creates test audio file".to_string()),
649                    },
650                    HelpExample {
651                        command: "voirs test --play".to_string(),
652                        description: "Test with audio playback".to_string(),
653                        expected: Some("Plays synthesized audio".to_string()),
654                    },
655                ],
656                related: vec!["config".to_string()],
657                troubleshooting: vec![HelpTip {
658                    title: "Test fails".to_string(),
659                    content: "Check that voices and models are installed with 'voirs list-voices'"
660                        .to_string(),
661                    level: TipLevel::Error,
662                }],
663            },
664        );
665    }
666
667    fn add_server_help(&mut self) {
668        self.command_help.insert(
669            "server".to_string(),
670            CommandHelp {
671                description: "Run VoiRS as HTTP API server".to_string(),
672                detailed: "Start a production-ready HTTP server providing REST API \
673                      endpoints for synthesis, voice management, and system status."
674                    .to_string(),
675                examples: vec![
676                    HelpExample {
677                        command: "voirs server".to_string(),
678                        description: "Start server on default port 8080".to_string(),
679                        expected: Some("Server runs at http://127.0.0.1:8080".to_string()),
680                    },
681                    HelpExample {
682                        command: "voirs server --port 3000 --host 0.0.0.0".to_string(),
683                        description: "Start server on custom address".to_string(),
684                        expected: None,
685                    },
686                ],
687                related: vec![],
688                troubleshooting: vec![HelpTip {
689                    title: "Port already in use".to_string(),
690                    content: "Use --port flag to specify a different port number".to_string(),
691                    level: TipLevel::Error,
692                }],
693            },
694        );
695    }
696
697    fn add_guide_help(&mut self) {
698        self.command_help.insert("guide".to_string(), CommandHelp {
699            description: "Show detailed help and guides".to_string(),
700            detailed: "Display comprehensive help information, getting started guides, \
701                      and examples for VoiRS commands. Use this to learn about specific \
702                      commands or get an overview of available functionality.".to_string(),
703            examples: vec![
704                HelpExample {
705                    command: "voirs guide".to_string(),
706                    description: "Show overview of all commands".to_string(),
707                    expected: Some("Lists all command categories".to_string()),
708                },
709                HelpExample {
710                    command: "voirs guide synthesize".to_string(),
711                    description: "Get detailed help for synthesize command".to_string(),
712                    expected: Some("Shows usage, examples, and troubleshooting".to_string()),
713                },
714                HelpExample {
715                    command: "voirs guide --getting-started".to_string(),
716                    description: "Show getting started guide".to_string(),
717                    expected: Some("Step-by-step setup instructions".to_string()),
718                },
719                HelpExample {
720                    command: "voirs guide --examples".to_string(),
721                    description: "Show examples for all commands".to_string(),
722                    expected: Some("Command examples with descriptions".to_string()),
723                },
724            ],
725            related: vec!["test".to_string(), "config".to_string()],
726            troubleshooting: vec![
727                HelpTip {
728                    title: "Need more help".to_string(),
729                    content: "Visit the documentation or check the project repository for additional resources".to_string(),
730                    level: TipLevel::Info,
731                },
732            ],
733        });
734    }
735
736    // Advanced voice features help
737    fn add_emotion_help(&mut self) {
738        self.command_help.insert("emotion".to_string(), CommandHelp {
739            description: "Control emotional expression in synthesized speech".to_string(),
740            detailed: "The emotion command allows you to modify the emotional tone and expression \
741                      of synthesized speech. You can use predefined emotion presets, blend multiple \
742                      emotions, or create custom emotion configurations.".to_string(),
743            examples: vec![
744                HelpExample {
745                    command: "voirs emotion list".to_string(),
746                    description: "List all available emotion presets".to_string(),
747                    expected: Some("Shows emotions like happy, sad, angry, calm, etc.".to_string()),
748                },
749                HelpExample {
750                    command: "voirs emotion synth --emotion happy --intensity 0.7 \"Hello world!\" output.wav".to_string(),
751                    description: "Synthesize with happy emotion at 70% intensity".to_string(),
752                    expected: Some("Creates emotionally expressive audio".to_string()),
753                },
754                HelpExample {
755                    command: "voirs emotion blend --emotions happy,calm --weights 0.6,0.4 \"Text\" output.wav".to_string(),
756                    description: "Blend multiple emotions with specified weights".to_string(),
757                    expected: None,
758                },
759                HelpExample {
760                    command: "voirs emotion create-preset --name custom --config emotion.json".to_string(),
761                    description: "Create a custom emotion preset".to_string(),
762                    expected: Some("Saves custom emotion configuration".to_string()),
763                },
764            ],
765            related: vec!["synthesize".to_string(), "convert".to_string()],
766            troubleshooting: vec![
767                HelpTip {
768                    title: "Emotion not working".to_string(),
769                    content: "Check if emotion models are downloaded and the voice supports emotional expression".to_string(),
770                    level: TipLevel::Warning,
771                },
772                HelpTip {
773                    title: "Intensity too high".to_string(),
774                    content: "Reduce intensity value (0.0-1.0) if emotion sounds unnatural".to_string(),
775                    level: TipLevel::Info,
776                },
777            ],
778        });
779    }
780
781    fn add_clone_help(&mut self) {
782        self.command_help.insert("clone".to_string(), CommandHelp {
783            description: "Clone voices from reference audio samples".to_string(),
784            detailed: "Voice cloning allows you to create new voices from reference audio samples. \
785                      You can use multiple reference files for better quality, and the system \
786                      supports both quick cloning and detailed speaker adaptation.".to_string(),
787            examples: vec![
788                HelpExample {
789                    command: "voirs clone clone --reference-files voice_samples/*.wav --text \"Hello world\" output.wav".to_string(),
790                    description: "Clone voice from multiple reference files".to_string(),
791                    expected: Some("Creates audio with cloned voice".to_string()),
792                },
793                HelpExample {
794                    command: "voirs clone quick --reference-files sample.wav --text \"Hello world\" output.wav".to_string(),
795                    description: "Quick cloning from single reference file".to_string(),
796                    expected: Some("Faster but potentially lower quality cloning".to_string()),
797                },
798                HelpExample {
799                    command: "voirs clone list-profiles".to_string(),
800                    description: "List cached speaker profiles".to_string(),
801                    expected: Some("Shows previously cloned speaker profiles".to_string()),
802                },
803                HelpExample {
804                    command: "voirs clone validate --reference-files samples/*.wav".to_string(),
805                    description: "Validate reference audio quality for cloning".to_string(),
806                    expected: Some("Reports audio quality and suitability".to_string()),
807                },
808            ],
809            related: vec!["convert".to_string(), "synthesize".to_string()],
810            troubleshooting: vec![
811                HelpTip {
812                    title: "Poor cloning quality".to_string(),
813                    content: "Use high-quality reference audio (16kHz+) with clear speech and minimal background noise".to_string(),
814                    level: TipLevel::Warning,
815                },
816                HelpTip {
817                    title: "Cloning fails".to_string(),
818                    content: "Ensure reference files are at least 30 seconds of clear speech from the target speaker".to_string(),
819                    level: TipLevel::Error,
820                },
821            ],
822        });
823    }
824
825    fn add_convert_help(&mut self) {
826        self.command_help.insert("convert".to_string(), CommandHelp {
827            description: "Convert and transform voice characteristics".to_string(),
828            detailed: "Voice conversion allows you to transform existing audio by changing \
829                      speaker characteristics, age, gender, or other vocal properties. \
830                      Supports both file-based and real-time conversion.".to_string(),
831            examples: vec![
832                HelpExample {
833                    command: "voirs convert speaker --input source.wav --target-speaker target_voice --output converted.wav".to_string(),
834                    description: "Convert to a different speaker".to_string(),
835                    expected: Some("Creates audio with target speaker's voice".to_string()),
836                },
837                HelpExample {
838                    command: "voirs convert age --input voice.wav --target-age 25 --output aged.wav".to_string(),
839                    description: "Change apparent age of the speaker".to_string(),
840                    expected: Some("Creates audio with modified age characteristics".to_string()),
841                },
842                HelpExample {
843                    command: "voirs convert gender --input voice.wav --target male --output converted.wav".to_string(),
844                    description: "Convert gender characteristics".to_string(),
845                    expected: Some("Creates audio with modified gender characteristics".to_string()),
846                },
847                HelpExample {
848                    command: "voirs convert morph --voice1 voice1.model --voice2 voice2.model --ratio 0.5".to_string(),
849                    description: "Morph between two voice models".to_string(),
850                    expected: Some("Creates blended voice characteristics".to_string()),
851                },
852            ],
853            related: vec!["clone".to_string(), "emotion".to_string()],
854            troubleshooting: vec![
855                HelpTip {
856                    title: "Conversion artifacts".to_string(),
857                    content: "Reduce conversion intensity or use higher quality settings".to_string(),
858                    level: TipLevel::Warning,
859                },
860                HelpTip {
861                    title: "Real-time conversion slow".to_string(),
862                    content: "Use GPU acceleration or reduce audio quality for real-time processing".to_string(),
863                    level: TipLevel::Info,
864                },
865            ],
866        });
867    }
868
869    fn add_sing_help(&mut self) {
870        self.command_help.insert("sing".to_string(), CommandHelp {
871            description: "Synthesize singing voice from musical scores".to_string(),
872            detailed: "Singing voice synthesis converts musical scores and lyrics into \
873                      realistic singing. Supports various input formats including MusicXML, \
874                      MIDI, and custom score formats with advanced vocal technique controls.".to_string(),
875            examples: vec![
876                HelpExample {
877                    command: "voirs sing score --score score.musicxml --voice singer.model --output song.wav".to_string(),
878                    description: "Synthesize from MusicXML score".to_string(),
879                    expected: Some("Creates singing audio from musical score".to_string()),
880                },
881                HelpExample {
882                    command: "voirs sing midi --midi input.mid --lyrics lyrics.txt --voice singer.model --output song.wav".to_string(),
883                    description: "Synthesize from MIDI file with lyrics".to_string(),
884                    expected: Some("Creates singing audio from MIDI and lyrics".to_string()),
885                },
886                HelpExample {
887                    command: "voirs sing create-voice --samples singing_samples/ --output singer.model".to_string(),
888                    description: "Create singing voice model from samples".to_string(),
889                    expected: Some("Trains custom singing voice model".to_string()),
890                },
891                HelpExample {
892                    command: "voirs sing effects --input song.wav --vibrato 1.2 --expression happy --output processed.wav".to_string(),
893                    description: "Apply singing effects and expression".to_string(),
894                    expected: Some("Adds vocal effects to singing audio".to_string()),
895                },
896            ],
897            related: vec!["emotion".to_string(), "synthesize".to_string()],
898            troubleshooting: vec![
899                HelpTip {
900                    title: "Pitch issues".to_string(),
901                    content: "Check score format and ensure correct pitch notation".to_string(),
902                    level: TipLevel::Warning,
903                },
904                HelpTip {
905                    title: "Timing problems".to_string(),
906                    content: "Verify tempo and rhythm marks in the musical score".to_string(),
907                    level: TipLevel::Warning,
908                },
909            ],
910        });
911    }
912
913    fn add_spatial_help(&mut self) {
914        self.command_help.insert("spatial".to_string(), CommandHelp {
915            description: "Create 3D spatial audio with positioning effects".to_string(),
916            detailed: "Spatial audio synthesis creates immersive 3D soundscapes by applying \
917                      Head-Related Transfer Functions (HRTF) and room acoustics. Supports \
918                      binaural rendering for headphones and multi-channel output for speakers.".to_string(),
919            examples: vec![
920                HelpExample {
921                    command: "voirs spatial synth --text \"hello\" --position 1,0,0 --output 3d_audio.wav".to_string(),
922                    description: "Synthesize with 3D positioning".to_string(),
923                    expected: Some("Creates 3D positioned audio".to_string()),
924                },
925                HelpExample {
926                    command: "voirs spatial hrtf --input mono.wav --position x,y,z --output binaural.wav".to_string(),
927                    description: "Apply HRTF processing to existing audio".to_string(),
928                    expected: Some("Creates binaural audio for headphones".to_string()),
929                },
930                HelpExample {
931                    command: "voirs spatial room --input voice.wav --room-config room.json --output spatial.wav".to_string(),
932                    description: "Apply room acoustics simulation".to_string(),
933                    expected: Some("Creates audio with room acoustics".to_string()),
934                },
935                HelpExample {
936                    command: "voirs spatial movement --input voice.wav --path movement.json --output dynamic.wav".to_string(),
937                    description: "Apply dynamic movement path".to_string(),
938                    expected: Some("Creates audio with moving sound source".to_string()),
939                },
940            ],
941            related: vec!["synthesize".to_string()],
942            troubleshooting: vec![
943                HelpTip {
944                    title: "HRTF not working".to_string(),
945                    content: "Check if HRTF dataset is installed and compatible with your setup".to_string(),
946                    level: TipLevel::Warning,
947                },
948                HelpTip {
949                    title: "Poor spatial effect".to_string(),
950                    content: "Use high-quality headphones and ensure proper audio driver configuration".to_string(),
951                    level: TipLevel::Info,
952                },
953            ],
954        });
955    }
956
957    fn add_capabilities_help(&mut self) {
958        self.command_help.insert("capabilities".to_string(), CommandHelp {
959            description: "Show system capabilities and feature availability".to_string(),
960            detailed: "The capabilities command provides comprehensive information about \
961                      available features, system requirements, configuration status, and \
962                      hardware capabilities. Use this to troubleshoot issues and verify \
963                      your VoiRS installation.".to_string(),
964            examples: vec![
965                HelpExample {
966                    command: "voirs capabilities list".to_string(),
967                    description: "Show all available features and their status".to_string(),
968                    expected: Some("Lists features with availability status".to_string()),
969                },
970                HelpExample {
971                    command: "voirs capabilities check emotion".to_string(),
972                    description: "Check if emotion control feature is available".to_string(),
973                    expected: Some("Shows emotion feature status and requirements".to_string()),
974                },
975                HelpExample {
976                    command: "voirs capabilities requirements".to_string(),
977                    description: "Show system requirements for all features".to_string(),
978                    expected: Some("Lists hardware and software requirements".to_string()),
979                },
980                HelpExample {
981                    command: "voirs capabilities test cloning".to_string(),
982                    description: "Test voice cloning functionality".to_string(),
983                    expected: Some("Runs functional tests for voice cloning".to_string()),
984                },
985            ],
986            related: vec!["test".to_string(), "config".to_string()],
987            troubleshooting: vec![
988                HelpTip {
989                    title: "Feature unavailable".to_string(),
990                    content: "Check if required models are installed and feature is enabled in configuration".to_string(),
991                    level: TipLevel::Warning,
992                },
993                HelpTip {
994                    title: "System requirements".to_string(),
995                    content: "Use 'voirs capabilities requirements' to check specific hardware needs".to_string(),
996                    level: TipLevel::Info,
997                },
998            ],
999        });
1000    }
1001}
1002
1003impl Default for HelpSystem {
1004    fn default() -> Self {
1005        Self::new()
1006    }
1007}
1008
1009/// Display help for getting started with VoiRS
1010pub fn display_getting_started() -> String {
1011    let mut output = String::new();
1012
1013    output.push_str(&format!(
1014        "{}\n\n",
1015        style("Getting Started with VoiRS").bold().cyan()
1016    ));
1017
1018    let steps = vec![
1019        (
1020            "1. Test Installation",
1021            "voirs test",
1022            "Verify VoiRS is working correctly",
1023        ),
1024        (
1025            "2. List Voices",
1026            "voirs list-voices",
1027            "See available voices",
1028        ),
1029        (
1030            "3. Download a Voice",
1031            "voirs download-voice en-us-female",
1032            "Get a voice for synthesis",
1033        ),
1034        (
1035            "4. Synthesize Text",
1036            "voirs synthesize \"Hello, world!\"",
1037            "Create your first audio",
1038        ),
1039        (
1040            "5. Interactive Mode",
1041            "voirs interactive",
1042            "Try real-time synthesis",
1043        ),
1044    ];
1045
1046    for (step, command, description) in steps {
1047        output.push_str(&format!("{}\n", style(step).bold().yellow()));
1048        output.push_str(&format!("  {}\n", style(command).green()));
1049        output.push_str(&format!("  {}\n\n", description));
1050    }
1051
1052    output.push_str(&format!(
1053        "{}\n",
1054        style("Use 'voirs help <command>' for detailed information about specific commands.").dim()
1055    ));
1056
1057    output
1058}