mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-03 08:57:54 +00:00
Add /speak and /speakers endpoints
This commit is contained in:
1 parent
0652199e8a
commit
450c4ebe0a
5 files changed
+124
-2
No files matched your search
@@ -4,7 +4,7 @@ use std::path::Path;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ModelConfigs {
|
||||
speakers: Vec<Speaker>,
|
||||
pub speakers: Vec<Speaker>,
|
||||
pub model_locations: Vec<ModelLocation>,
|
||||
tacotron: Vec<ModelDetails>,
|
||||
melgan: Vec<ModelDetails>,
|
||||
@@ -84,4 +84,9 @@ impl ModelConfigs {
|
||||
.map(|s| s.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_speaker_by_slug(&self, slug: &str) -> Option<&Speaker> {
|
||||
self.speakers.iter()
|
||||
.find(|speaker| speaker.slug == slug)
|
||||
}
|
||||
}
|
||||
@@ -2,4 +2,6 @@ pub mod index;
|
||||
pub mod liveness;
|
||||
pub mod models;
|
||||
pub mod readiness;
|
||||
pub mod tts;
|
||||
pub mod speak;
|
||||
pub mod speakers;
|
||||
pub mod tts;
|
||||
@@ -0,0 +1,77 @@
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::web::{
|
||||
Data,
|
||||
Json,
|
||||
};
|
||||
use actix_web::{
|
||||
HttpRequest,
|
||||
HttpResponse,
|
||||
get,
|
||||
};
|
||||
|
||||
use std::sync::Arc;
|
||||
use crate::AppState;
|
||||
use arpabet::Arpabet;
|
||||
use crate::text::text_to_arpabet_encoding;
|
||||
use crate::old_model::TacoMelModel;
|
||||
use crate::config::{Speaker, ModelPipeline};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SpeakRequest {
|
||||
/// Slug for the speaker
|
||||
speaker: String,
|
||||
/// Raw text to be spoken
|
||||
text: String,
|
||||
}
|
||||
|
||||
pub async fn post_speak(_request: HttpRequest,
|
||||
query: Json<SpeakRequest>,
|
||||
app_state: Data<Arc<AppState>>
|
||||
) -> std::io::Result<HttpResponse> {
|
||||
println!("POST /tts");
|
||||
|
||||
let mut app_state = app_state.into_inner();
|
||||
|
||||
let speaker = match app_state.model_configs.find_speaker_by_slug(&query.speaker) {
|
||||
Some(speaker) => speaker,
|
||||
None => {
|
||||
return Ok(HttpResponse::build(StatusCode::NOT_FOUND)
|
||||
.content_type("text/plain")
|
||||
.body("Speaker not found"));
|
||||
},
|
||||
};
|
||||
|
||||
match speaker.model_pipeline {
|
||||
ModelPipeline::ArpabetTacotronMelgan => {
|
||||
let tacotron_model = speaker.tacotron
|
||||
.as_ref()
|
||||
.map(|s| s.clone())
|
||||
.expect("TODO ERROR HANDLING");
|
||||
|
||||
let melgan_model = speaker.melgan
|
||||
.as_ref()
|
||||
.map(|s| s.clone())
|
||||
.expect("TODO ERROR HANDLING");
|
||||
|
||||
let text = query.text.to_string();
|
||||
println!("Tacotron Model: {}", tacotron_model);
|
||||
println!("Melgan Model: {}", melgan_model);
|
||||
println!("Text: {}", text);
|
||||
|
||||
let arpabet = Arpabet::load_cmudict();
|
||||
let encoded = text_to_arpabet_encoding(arpabet, &text);
|
||||
|
||||
println!("Encoded Text: {:?}", encoded);
|
||||
|
||||
let tacotron = app_state.model_cache.get_or_load_arbabet_tacotron(&tacotron_model).unwrap();
|
||||
let melgan = app_state.model_cache.get_or_load_melgan(&melgan_model).unwrap();
|
||||
|
||||
let wav_data = TacoMelModel::new().run_tts_encoded(&tacotron, &melgan, &encoded);
|
||||
|
||||
return Ok(HttpResponse::build(StatusCode::OK)
|
||||
.content_type("audio/wav")
|
||||
.body(wav_data));
|
||||
},
|
||||
ModelPipeline::RawTextTacotronMelgan => unimplemented!(),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
use actix_web::web::{
|
||||
Data,
|
||||
Json,
|
||||
};
|
||||
use actix_web::{
|
||||
HttpRequest,
|
||||
get,
|
||||
};
|
||||
|
||||
use std::sync::Arc;
|
||||
use crate::AppState;
|
||||
use crate::config::{ModelConfigs, Speaker};
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct SpeakersResult {
|
||||
speakers: Vec<Speaker>,
|
||||
}
|
||||
|
||||
#[get("/speakers")]
|
||||
pub async fn get_speakers(
|
||||
_request: HttpRequest,
|
||||
app_state: Data<Arc<AppState>>
|
||||
) -> std::io::Result<Json<SpeakersResult>> {
|
||||
println!("GET /models");
|
||||
let app_state = app_state.into_inner();
|
||||
|
||||
Ok(Json(SpeakersResult {
|
||||
speakers: app_state.model_configs.speakers.clone(),
|
||||
}))
|
||||
}
|
||||
@@ -38,6 +38,8 @@ use crate::endpoints::index::get_root;
|
||||
use crate::endpoints::liveness::get_liveness;
|
||||
use crate::endpoints::models::get_models;
|
||||
use crate::endpoints::readiness::get_readiness;
|
||||
use crate::endpoints::speak::post_speak;
|
||||
use crate::endpoints::speakers::get_speakers;
|
||||
use crate::endpoints::tts::post_tts;
|
||||
|
||||
const BIND_ADDRESS : &'static str = "BIND_ADDRESS";
|
||||
@@ -103,10 +105,16 @@ async fn main() -> std::io::Result<()> {
|
||||
.route(web::post().to(post_tts))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(
|
||||
web::resource("/speak")
|
||||
.route(web::post().to(post_speak))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(get_root)
|
||||
.service(get_readiness)
|
||||
.service(get_liveness)
|
||||
.service(get_models)
|
||||
.service(get_speakers)
|
||||
.app_data(arc.clone())
|
||||
)
|
||||
.bind(bind_address)?
|
||||
|
||||
Reference in new issue
Block a user