-
Notifications
You must be signed in to change notification settings - Fork 58
/
Copy path01-synthesize-txt-files.rs
69 lines (65 loc) · 2.49 KB
/
01-synthesize-txt-files.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use std::{env, error::Error, path::PathBuf};
use futures_util::{StreamExt, stream::FuturesUnordered};
use tokio::{
fs::{self, File},
io::AsyncWriteExt,
};
use aspeak::{
AudioFormat, AuthOptionsBuilder, RestSynthesizer, SynthesizerConfig, TextOptions,
TextOptionsBuilder,
};
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn Error>> {
let auth_key = env::var("ASPEAK_AUTH_KEY")?; // Read the auth key from environment variable
let auth = AuthOptionsBuilder::new(
aspeak::get_rest_endpoint_by_region("eastus"), // Use eastus endpoint, RESTful API
)
.key(auth_key) // Fill in the auth key
.build();
let config = SynthesizerConfig::new(
auth,
AudioFormat::Audio16Khz32KBitRateMonoMp3, // Let's use mp3 format!
);
let syn = config.rest_synthesizer()?; // Get the synthesizer from the config
let options = TextOptionsBuilder::new() // Adjusting text options like rate, pitch and voice
.rate("fast")
.voice("en-US-JennyNeural")
.pitch("low")
.build();
assert!(std::env::args().len() < 3); // Throw an error if we got extra arguments
let dir = PathBuf::from(
// Get the path from the first argument
env::args().nth(1).unwrap_or_else(|| ".".to_string()), // Use CWD if path is not provided
);
// Get a list of all txt files (*.txt)
let txt_paths = std::fs::read_dir(dir)?.filter_map(|r| {
r.and_then(|ent| {
let path = ent.path();
let file_type = ent.file_type()?;
Ok((path.extension() == Some("txt".as_ref())
&& (file_type.is_file() || file_type.is_symlink()))
.then_some(path))
})
.transpose()
});
// Process txt files concurrently
let mut tasks = txt_paths
.map(|path| path.map(|path| process_file(path, &syn, &options)))
.collect::<Result<FuturesUnordered<_>, _>>()?;
while let Some(next) = tasks.next().await {
// Examine the results, stop if we encounter an error.
next?;
}
Ok(())
}
async fn process_file<'a>(
mut path: PathBuf,
syn: &RestSynthesizer,
options: &TextOptions<'a>,
) -> Result<(), Box<dyn Error>> {
let text = fs::read_to_string(&path).await?; // Read the text file
path.set_extension("mp3"); // Change the extension to mp3
let data = syn.synthesize_text(text, options).await?; // Synthesize
File::create(path).await?.write_all(&data).await?; // Save the synthesized audio
Ok(())
}