mirror of
https://github.com/mii443/ncb-tts-r2.git
synced 2025-08-22 16:15:29 +00:00
support original voicevox api
This commit is contained in:
15
Cargo.toml
15
Cargo.toml
@ -28,6 +28,7 @@ symphonia-core = "0.5.4"
|
||||
tokio-util = { version = "0.7.14", features = ["compat"] }
|
||||
futures = "0.3.31"
|
||||
bytes = "1.10.1"
|
||||
voicevox-client = { git = "https://github.com/mii443/rust" }
|
||||
|
||||
[dependencies.uuid]
|
||||
version = "0.8"
|
||||
@ -43,7 +44,19 @@ features = ["mp3"]
|
||||
|
||||
[dependencies.serenity]
|
||||
version = "0.12"
|
||||
features = ["builder", "cache", "client", "gateway", "model", "utils", "unstable_discord_api", "collector", "rustls_backend", "framework", "voice"]
|
||||
features = [
|
||||
"builder",
|
||||
"cache",
|
||||
"client",
|
||||
"gateway",
|
||||
"model",
|
||||
"utils",
|
||||
"unstable_discord_api",
|
||||
"collector",
|
||||
"rustls_backend",
|
||||
"framework",
|
||||
"voice",
|
||||
]
|
||||
|
||||
|
||||
[dependencies.tokio]
|
||||
|
@ -6,6 +6,7 @@ pub struct Config {
|
||||
pub token: String,
|
||||
pub application_id: u64,
|
||||
pub redis_url: String,
|
||||
pub voicevox_key: String,
|
||||
pub voicevox_key: Option<String>,
|
||||
pub voicevox_original_api_url: Option<String>,
|
||||
pub otel_http_url: Option<String>,
|
||||
}
|
||||
|
12
src/main.rs
12
src/main.rs
@ -61,7 +61,14 @@ async fn main() {
|
||||
let application_id = env::var("NCB_APP_ID").unwrap();
|
||||
let prefix = env::var("NCB_PREFIX").unwrap();
|
||||
let redis_url = env::var("NCB_REDIS_URL").unwrap();
|
||||
let voicevox_key = env::var("NCB_VOICEVOX_KEY").unwrap();
|
||||
let voicevox_key = match env::var("NCB_VOICEVOX_KEY") {
|
||||
Ok(key) => Some(key),
|
||||
Err(_) => None,
|
||||
};
|
||||
let voicevox_original_api_url = match env::var("NCB_VOICEVOX_ORIGINAL_API_URL") {
|
||||
Ok(url) => Some(url),
|
||||
Err(_) => None,
|
||||
};
|
||||
let otel_http_url = match env::var("NCB_OTEL_HTTP_URL") {
|
||||
Ok(url) => Some(url),
|
||||
Err(_) => None,
|
||||
@ -73,6 +80,7 @@ async fn main() {
|
||||
prefix,
|
||||
redis_url,
|
||||
voicevox_key,
|
||||
voicevox_original_api_url,
|
||||
otel_http_url,
|
||||
}
|
||||
}
|
||||
@ -91,7 +99,7 @@ async fn main() {
|
||||
Err(err) => panic!("GCP init error: {}", err),
|
||||
};
|
||||
|
||||
let voicevox = VOICEVOX::new(config.voicevox_key);
|
||||
let voicevox = VOICEVOX::new(config.voicevox_key, config.voicevox_original_api_url);
|
||||
|
||||
let database_client = {
|
||||
let redis_client = redis::Client::open(config.redis_url).unwrap();
|
||||
|
@ -57,23 +57,44 @@ impl TTS {
|
||||
}
|
||||
|
||||
info!("Cache miss for VOICEVOX TTS");
|
||||
let audio = self
|
||||
.voicevox_client
|
||||
.synthesize_stream(text.to_string(), speaker)
|
||||
.await?;
|
||||
|
||||
tokio::spawn({
|
||||
let cache = self.cache.clone();
|
||||
let audio = audio.clone();
|
||||
async move {
|
||||
info!("Compressing stream audio");
|
||||
let compressed = Compressed::new(audio.into(), Bitrate::Auto).await.unwrap();
|
||||
let mut cache_guard = cache.write().unwrap();
|
||||
cache_guard.put(cache_key, compressed.clone());
|
||||
}
|
||||
});
|
||||
if self.voicevox_client.original_api_url.is_some() {
|
||||
let audio = self
|
||||
.voicevox_client
|
||||
.synthesize_original(text.to_string(), speaker)
|
||||
.await?;
|
||||
|
||||
Ok(audio.into())
|
||||
tokio::spawn({
|
||||
let cache = self.cache.clone();
|
||||
let audio = audio.clone();
|
||||
async move {
|
||||
info!("Compressing stream audio");
|
||||
let compressed = Compressed::new(audio.into(), Bitrate::Auto).await.unwrap();
|
||||
let mut cache_guard = cache.write().unwrap();
|
||||
cache_guard.put(cache_key, compressed.clone());
|
||||
}
|
||||
});
|
||||
|
||||
Ok(audio.into())
|
||||
} else {
|
||||
let audio = self
|
||||
.voicevox_client
|
||||
.synthesize_stream(text.to_string(), speaker)
|
||||
.await?;
|
||||
|
||||
tokio::spawn({
|
||||
let cache = self.cache.clone();
|
||||
let audio = audio.clone();
|
||||
async move {
|
||||
info!("Compressing stream audio");
|
||||
let compressed = Compressed::new(audio.into(), Bitrate::Auto).await.unwrap();
|
||||
let mut cache_guard = cache.write().unwrap();
|
||||
cache_guard.put(cache_key, compressed.clone());
|
||||
}
|
||||
});
|
||||
|
||||
Ok(audio.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
|
@ -6,7 +6,8 @@ const BASE_API_URL: &str = "https://deprecatedapis.tts.quest/v2/";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VOICEVOX {
|
||||
pub key: String,
|
||||
pub key: Option<String>,
|
||||
pub original_api_url: Option<String>,
|
||||
}
|
||||
|
||||
impl VOICEVOX {
|
||||
@ -34,19 +35,27 @@ impl VOICEVOX {
|
||||
speaker_list
|
||||
}
|
||||
|
||||
pub fn new(key: String) -> Self {
|
||||
Self { key }
|
||||
pub fn new(key: Option<String>, original_api_url: Option<String>) -> Self {
|
||||
Self {
|
||||
key,
|
||||
original_api_url,
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
async fn get_speaker_list(&self) -> Vec<Speaker> {
|
||||
let client = reqwest::Client::new();
|
||||
match client
|
||||
.post(BASE_API_URL.to_string() + "voicevox/speakers/")
|
||||
.query(&[("key", self.key.clone())])
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
let client = if let Some(key) = &self.key {
|
||||
client
|
||||
.get(BASE_API_URL.to_string() + "voicevox/speakers/")
|
||||
.query(&[("key", key)])
|
||||
} else if let Some(original_api_url) = &self.original_api_url {
|
||||
client.get(original_api_url.to_string() + "/speakers")
|
||||
} else {
|
||||
panic!("No API key or original API URL provided.")
|
||||
};
|
||||
|
||||
match client.send().await {
|
||||
Ok(response) => response.json().await.unwrap(),
|
||||
Err(err) => {
|
||||
panic!("Cannot get speaker list. {err:?}")
|
||||
@ -66,7 +75,7 @@ impl VOICEVOX {
|
||||
.query(&[
|
||||
("speaker", speaker.to_string()),
|
||||
("text", text),
|
||||
("key", self.key.clone()),
|
||||
("key", self.key.clone().unwrap()),
|
||||
])
|
||||
.send()
|
||||
.await
|
||||
@ -79,6 +88,22 @@ impl VOICEVOX {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn synthesize_original(
|
||||
&self,
|
||||
text: String,
|
||||
speaker: i64,
|
||||
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
let client =
|
||||
voicevox_client::Client::new(self.original_api_url.as_ref().unwrap().clone(), None);
|
||||
let audio_query = client
|
||||
.create_audio_query(&text, speaker as i32, None)
|
||||
.await?;
|
||||
println!("{:?}", audio_query.audio_query);
|
||||
let audio = audio_query.synthesis(speaker as i32, true).await?;
|
||||
Ok(audio.into())
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn synthesize_stream(
|
||||
&self,
|
||||
@ -91,7 +116,7 @@ impl VOICEVOX {
|
||||
.query(&[
|
||||
("speaker", speaker.to_string()),
|
||||
("text", text),
|
||||
("key", self.key.clone()),
|
||||
("key", self.key.clone().unwrap()),
|
||||
])
|
||||
.send()
|
||||
.await
|
||||
@ -100,10 +125,7 @@ impl VOICEVOX {
|
||||
let body = response.text().await.unwrap();
|
||||
let response: TTSResponse = serde_json::from_str(&body).unwrap();
|
||||
|
||||
Ok(Mp3Request::new(
|
||||
reqwest::Client::new(),
|
||||
response.mp3_streaming_url,
|
||||
))
|
||||
Ok(Mp3Request::new(reqwest::Client::new(), response.mp3_streaming_url).into())
|
||||
}
|
||||
Err(err) => Err(Box::new(err)),
|
||||
}
|
||||
|
Reference in New Issue
Block a user