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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#![doc = include_str!("../readme.md")]
pub mod models;
#[macro_use]
extern crate rocket;
use cache_manager::Cache;
use config::Config;
use converter::{Converter, Ffmpeg};
use festvox::{Flite, TtsGenerator};
use macros::failure;
use response::{Data, Response};
use rocket::{fs::NamedFile, http::Status, serde::json::Json};
use utils::phrase_package::PhrasePackage;
#[cfg(not(target_os = "linux"))]
compile_error!("Unable to compile for your platform! This API is only available for Linux due to dependence on Bash commands.");
#[get("/")]
pub fn index(cfg: &Config) -> String {
format!("Welcome to {}'s TTS API.", cfg.API_NAME())
}
#[post("/convert", data = "<phrase_package>", format = "application/json")]
pub async fn convert(
mut phrase_package: Json<PhrasePackage>,
generator: &Flite,
converter: &Converter,
cfg: &Config,
cache: Cache,
) -> Result<Response, Response> {
phrase_package.validated(cfg).map_err(|e| {
Response::TextErr(Data {
data: e,
status: Status::BadRequest,
})
})?;
let phrase_package = phrase_package.into_inner();
let generated_file = generator
.generate(&phrase_package, cfg)
.await
.map_err(|e| {
error!("{}", e);
Response::TextErr(Data {
data: String::from(
"an error occured in festival/flite while generating the requested phrase",
),
status: Status::InternalServerError,
})
})?;
if !converter.is_supported(&phrase_package.fmt) {
failure!("requested file format is not available")
}
let response = match converter.convert(
&phrase_package,
phrase_package.speed,
cfg,
).await {
Ok(f) => {
let resp_file = match NamedFile::open(f).await {
Ok(f) => f,
Err(e) => failure!("Unable to open processed file {}, this is an internal error", e),
};
Ok(Response::FileDownload((
Data {
data: resp_file,
status: Status::Ok,
},
format!("output.{}", phrase_package.fmt),
)))
},
Err(_) => failure!("unable to convert file to desired format due to internal error, try again with request as wav"),
};
if let Err(e) = cache.used(generated_file.to_path_buf()).await {
error!("cache error {}", e);
failure!("cache failure");
}
response
}
#[doc(hidden)]
#[launch]
pub fn rocket() -> _ {
rocket::build()
.mount("/", routes![index])
.mount("/api/", routes![convert])
.attach(Config::fairing())
.attach(Flite::fairing())
.attach(Converter::fairing(vec![Box::new(
Ffmpeg::new().expect("a valid ffmpeg instance"),
)]))
.attach(Cache::fairing())
}