auto load voiecvox speaker list

This commit is contained in:
mii
2023-10-03 14:54:34 +00:00
parent 5aa5e09bb7
commit c39800da18
6 changed files with 120 additions and 42 deletions

View File

@ -7,8 +7,8 @@ use serenity::{
};
use crate::{
data::DatabaseClientData,
tts::{tts_type::TTSType, voicevox::voicevox::VOICEVOX},
data::{DatabaseClientData, TTSClientData},
tts::tts_type::TTSType,
};
pub async fn config_command(
@ -30,6 +30,12 @@ pub async fn config_command(
.unwrap()
};
let tts_client = data_read
.get::<TTSClientData>()
.expect("Cannot get TTSClientData")
.clone();
let voicevox_speakers = tts_client.lock().await.1.get_styles().await;
let voicevox_speaker = config.voicevox_speaker.unwrap_or(1);
let tts_type = config.tts_type.unwrap_or(TTSType::GCP);
@ -65,7 +71,7 @@ pub async fn config_command(
m.custom_id("TTS_CONFIG_VOICEVOX_SPEAKER")
.options(|o| {
let mut o = o;
for (name, value) in VOICEVOX::get_speakers() {
for (name, value) in voicevox_speakers {
o = o.create_option(|co| {
co.label(name)
.value(format!(

View File

@ -6,7 +6,10 @@ use serenity::{
prelude::Context,
};
use crate::{data::TTSData, tts::instance::TTSInstance};
use crate::{
data::{TTSClientData, TTSData},
tts::instance::TTSInstance,
};
pub async fn setup_command(
ctx: &Context,
@ -138,11 +141,29 @@ pub async fn setup_command(
.await?;
let _handler = manager.join(guild.id.0, channel_id.0).await;
text_channel_id.send_message(&ctx.http, |f| f.embed(|e| e.title("読み上げ (Serenity)")
.field("クレジット", "```\n四国めたん  ずんだもん\n春日部つむぎ 雨晴はう\n波音リツ   玄野武宏\n白上虎太郎  青山龍星\n冥鳴ひまり  九州そら\nモチノ・キョウコ\nナースロボ_タイプT```", false)
let tts_client = ctx
.data
.read()
.await
.get::<TTSClientData>()
.expect("Cannot get TTSClientData")
.clone();
let voicevox_speakers = tts_client.lock().await.1.get_speakers().await;
text_channel_id
.send_message(&ctx.http, |f| {
f.embed(|e| {
e.title("読み上げ (Serenity)")
.field(
"VOICEVOXクレジット",
format!("```\n{}\n```", voicevox_speakers.join("\n")),
false,
)
.field("設定コマンド", "`/config`", false)
.field("フィードバック", "https://feedback.mii.codes/", false)
)).await?;
})
})
.await?;
Ok(())
}

View File

@ -1,5 +1,5 @@
use crate::{
data::{DatabaseClientData, TTSData},
data::{DatabaseClientData, TTSClientData, TTSData},
implement::{
member_name::ReadName,
voice_move_state::{VoiceMoveState, VoiceMoveStateTrait},
@ -65,10 +65,30 @@ pub async fn voice_state_update(ctx: Context, old: Option<VoiceState>, new: Voic
);
let _handler = manager.join(guild_id.0, new_channel.0).await;
new_channel.send_message(&ctx.http, |f| f.embed(|e| e.title("読み上げ (Serenity)")
.field("クレジット", "```\n四国めたん  ずんだもん\n春日部つむぎ 雨晴はう\n波音リツ   玄野武宏\n白上虎太郎  青山龍星\n冥鳴ひまり  九州そら\nモチノ・キョウコ\nナースロボ_タイプT```", false)
.field("設定コマンド", "`/config`", false)
.field("フィードバック", "https://feedback.mii.codes/", false))).await.unwrap();
let tts_client = ctx
.data
.read()
.await
.get::<TTSClientData>()
.expect("Cannot get TTSClientData")
.clone();
let voicevox_speakers = tts_client.lock().await.1.get_speakers().await;
new_channel
.send_message(&ctx.http, |f| {
f.embed(|e| {
e.title("自動参加 読み上げ (Serenity)")
.field(
"VOICEVOXクレジット",
format!("```\n{}\n```", voicevox_speakers.join("\n")),
false,
)
.field("設定コマンド", "`/config`", false)
.field("フィードバック", "https://feedback.mii.codes/", false)
})
})
.await
.unwrap();
}
}
return;

View File

@ -1,3 +1,4 @@
pub mod accent_phrase;
pub mod audio_query;
pub mod mora;
pub mod speaker;

View File

@ -0,0 +1,21 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Speaker {
pub supported_features: SupportedFeatures,
pub name: String,
pub speaker_uuid: String,
pub styles: Vec<Style>,
pub version: String,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SupportedFeatures {
pub permitted_synthesis_morphing: String,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Style {
pub name: String,
pub id: i64,
}

View File

@ -1,4 +1,6 @@
const API_URL: &str = "https://api.su-shiki.com/v2/voicevox/audio";
use super::structs::speaker::Speaker;
const BASE_API_URL: &str = "https://deprecatedapis.tts.quest/v2/";
#[derive(Clone)]
pub struct VOICEVOX {
@ -6,40 +8,47 @@ pub struct VOICEVOX {
}
impl VOICEVOX {
pub fn get_speakers() -> Vec<(String, i64)> {
vec![
("四国めたん - ノーマル".to_string(), 2),
("四国めたん - あまあま".to_string(), 0),
("四国めたん - ツンツン".to_string(), 6),
("四国めたん - セクシー".to_string(), 4),
("ずんだもん - ノーマル".to_string(), 3),
("ずんだもん - あまあま".to_string(), 1),
("ずんだもん - ツンツン".to_string(), 7),
("ずんだもん - セクシー".to_string(), 5),
("春日部つむぎ - ノーマル".to_string(), 8),
("雨晴はう - ノーマル".to_string(), 10),
("波音リツ - ノーマル".to_string(), 9),
("玄野武宏 - ノーマル".to_string(), 11),
("白上虎太郎 - ノーマル".to_string(), 12),
("青山龍星 - ノーマル".to_string(), 13),
("冥鳴ひまり - ノーマル".to_string(), 14),
("九州そら - ノーマル".to_string(), 16),
("九州そら - あまあま".to_string(), 15),
("九州そら - ツンツン".to_string(), 18),
("九州そら - セクシー".to_string(), 17),
("九州そら - ささやき".to_string(), 19),
("モチノ・キョウコ - ノーマル".to_string(), 20),
("ナースロボ_タイプT - ノーマル".to_string(), 47),
("ナースロボ_タイプT - 楽々".to_string(), 48),
("ナースロボ_タイプT - 恐怖".to_string(), 49),
("ナースロボ_タイプT - 内緒話".to_string(), 50),
]
pub async fn get_styles(&self) -> Vec<(String, i64)> {
let speakers = self.get_speaker_list().await;
let mut speaker_list = vec![];
for speaker in speakers {
for style in speaker.styles {
speaker_list.push((format!("{} - {}", speaker.name, style.name), style.id))
}
}
speaker_list
}
pub async fn get_speakers(&self) -> Vec<String> {
let speakers = self.get_speaker_list().await;
let mut speaker_list = vec![];
for speaker in speakers {
speaker_list.push(speaker.name)
}
speaker_list
}
pub fn new(key: String) -> Self {
Self { key }
}
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
{
Ok(response) => response.json().await.unwrap(),
Err(err) => {
panic!("Cannot get speaker list. {err:?}")
}
}
}
pub async fn synthesize(
&self,
text: String,
@ -47,7 +56,7 @@ impl VOICEVOX {
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
match client
.post(API_URL)
.post(BASE_API_URL.to_string() + "voicevox/audio/")
.query(&[
("speaker", speaker.to_string()),
("text", text),