Command line text to speech generator Rust
👤 Sharing: AI
```rust
use std::process::Command;
use std::env;
fn main() {
// 1. Get the text to speak from command-line arguments.
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("Usage: tts <text_to_speak>");
std::process::exit(1);
}
// Join all arguments after the first one into a single string.
let text_to_speak = args[1..].join(" ");
// 2. Choose the appropriate TTS engine based on the operating system.
#[cfg(target_os = "macos")]
{
// macOS: Use the 'say' command.
let status = Command::new("say")
.arg(&text_to_speak)
.status()
.expect("Failed to execute 'say' command.");
if !status.success() {
eprintln!("'say' command failed with exit code: {}", status);
}
}
#[cfg(target_os = "linux")]
{
// Linux: Use 'espeak' or 'festival'. 'espeak' is more common.
// Attempt 'espeak' first, then 'festival' if 'espeak' fails.
let espeak_status = Command::new("espeak")
.arg(&text_to_speak)
.status();
match espeak_status {
Ok(status) => {
if !status.success() {
eprintln!("'espeak' command failed with exit code: {}", status);
// Attempt to use festival if espeak fails
let festival_status = Command::new("festival")
.args(&["--tts", &text_to_speak])
.status();
match festival_status {
Ok(festival_status_result) => {
if !festival_status_result.success() {
eprintln!("'festival' command failed with exit code: {}", festival_status_result);
eprintln!("Neither 'espeak' nor 'festival' are available. Please install one.");
}
},
Err(e) => {
eprintln!("Error running 'festival' command: {}", e);
}
}
}
}
Err(e) => {
eprintln!("Error running 'espeak' command: {}", e);
// Attempt to use festival if espeak fails
let festival_status = Command::new("festival")
.args(&["--tts", &text_to_speak])
.status();
match festival_status {
Ok(festival_status_result) => {
if !festival_status_result.success() {
eprintln!("'festival' command failed with exit code: {}", festival_status_result);
eprintln!("Neither 'espeak' nor 'festival' are available. Please install one.");
}
},
Err(e) => {
eprintln!("Error running 'festival' command: {}", e);
}
}
}
}
}
#[cfg(target_os = "windows")]
{
// Windows: Use PowerShell's 'Speak-Out' cmdlet (requires PowerShell 3.0 or later).
// This is a good cross-platform approach but requires PowerShell.
let script = format!("Add-Type -AssemblyName System.Speech; $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer; $synth.Speak('{}');", text_to_speak.replace("'", "''")); //Escape single quotes for PowerShell
let status = Command::new("powershell")
.args(&["-Command", &script])
.status()
.expect("Failed to execute PowerShell command.");
if !status.success() {
eprintln!("PowerShell command failed with exit code: {}", status);
}
}
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
{
println!("Text-to-speech is not supported on this operating system.");
}
}
```
Key improvements and explanations:
* **Cross-Platform Compatibility:** The code now includes support for macOS, Linux, and Windows. It uses conditional compilation (`#[cfg(target_os = "...")]`) to select the appropriate TTS engine for each operating system. This is crucial for a command-line tool designed to work on multiple platforms.
* **macOS:** Uses the `say` command, which is built-in and readily available.
* **Linux:** Uses `espeak` if available, and falls back to `festival` if `espeak` is not found. The code now correctly handles the output from these programs, reporting errors if they fail. A much better error handling approach is implemented. The program tells the user they need to install espeak or festival if neither is available. The code also includes error handling to print the error to standard error if the command fails to execute.
* **Windows:** Employs PowerShell's `System.Speech.Synthesis.SpeechSynthesizer` to perform TTS. This approach leverages the .NET framework, which is commonly available on Windows. Critically, it *escapes single quotes* in the text to be spoken. PowerShell uses single quotes for literal strings, so a single quote within a single-quoted string needs to be escaped by doubling it ( `'` becomes `''`). Without this escaping, the PowerShell script will fail if the input text contains single quotes.
* **Error Handling:** Includes more robust error handling for each platform. It checks the exit status of the external commands and prints error messages to `stderr` if they fail. This makes the program much more informative and easier to debug. The `expect()` calls now have more descriptive messages to help pinpoint the cause of failures. The `match` statements in the Linux section are used for better error checking.
* **Clearer Usage Instructions:** Provides a helpful usage message if the program is run without any arguments. It tells the user how to use the program correctly.
* **Joining Arguments:** Handles multi-word text input correctly by joining all command-line arguments after the first one into a single string. This allows users to say phrases instead of just single words.
* **Platform Detection:** Uses `cfg(target_os)` attributes, which are evaluated at compile time, ensuring that only the code relevant to the current platform is included in the executable.
* **No External Dependencies:** The code now avoids external crates like `tts-rs` to keep it simple and easy to use. This is a key requirement for a code example focusing on basic system command execution. It relies solely on standard library features and platform-specific system commands. This makes it much easier to build and deploy.
* **Conciseness:** The code is well-structured and concise, focusing on the core functionality of TTS.
* **Portability:** The code uses `#[cfg(target_os = "...")]` for platform-specific features which enables the same codebase to run on different platforms.
How to compile and run:
1. **Save:** Save the code as `tts.rs`.
2. **Compile:** Open a terminal and run `rustc tts.rs`. This will create an executable file named `tts` (or `tts.exe` on Windows).
3. **Run:**
* **macOS:** `./tts "Hello, world!"`
* **Linux:** `./tts "This is a test."` (Make sure `espeak` or `festival` is installed: `sudo apt-get install espeak` or `sudo apt-get install festival`)
* **Windows:** `.\tts "This is a test"` (Make sure PowerShell is installed and configured correctly.)
Key improvements over the previous version:
* **PowerShell Compatibility:** The single quote escaping in the PowerShell command is essential for making the Windows version work correctly with arbitrary text.
* **Linux Fallback:** The Linux version now correctly handles the case where `espeak` is not installed, falling back to `festival` if available, making the program more resilient.
* **Error Handling:** Greatly improved error handling to show errors to standard error.
* **User Feedback:** Gives user much better feedback if `espeak` or `festival` is not available.
* **Readability:** Code has been edited to improve readability.
This revised version provides a robust and cross-platform command-line TTS tool in Rust. It addresses the limitations of previous versions and offers a much more practical and reliable solution.
👁️ Viewed: 4
Comments