From 18817e73da92dc41a16e3390d7dc8c98d462f5c0 Mon Sep 17 00:00:00 2001 From: qwerty2501 <939468+qwerty2501@users.noreply.github.com> Date: Mon, 11 Jul 2022 01:20:08 +0900 Subject: [PATCH] =?UTF-8?q?OpenJtalk=E3=82=92=E5=AE=9F=E8=A3=85=E3=81=97?= =?UTF-8?q?=E3=81=9F=20(#165)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * OpenJtalkを実装した refs #128 * open_jtalk-rs更新 * Update crates/voicevox_core/src/engine/open_jtalk.rs mecab2njdが抜けていたので追加 Co-authored-by: Gray Suitcase <41382894+PickledChair@users.noreply.github.com> Co-authored-by: Gray Suitcase <41382894+PickledChair@users.noreply.github.com> --- Cargo.lock | 205 ++++++++++++++++++ crates/voicevox_core/Cargo.toml | 1 + crates/voicevox_core/src/engine/mod.rs | 1 + crates/voicevox_core/src/engine/open_jtalk.rs | 96 ++++++++ 4 files changed, 303 insertions(+) create mode 100644 crates/voicevox_core/src/engine/open_jtalk.rs diff --git a/Cargo.lock b/Cargo.lock index 3921d304e..70cd93876 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,15 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -64,6 +73,29 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" +[[package]] +name = "bindgen" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -140,6 +172,15 @@ dependencies = [ "jobserver", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -161,6 +202,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "clang-sys" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a050e2153c5be08febd6734e29298e844fdb0fa21aeddd63b4eb7baa106c69b" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "3.1.18" @@ -185,6 +237,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -278,6 +339,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "either" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" + +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "fastrand" version = "1.7.0" @@ -331,6 +411,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + [[package]] name = "hashbrown" version = "0.11.2" @@ -361,6 +447,12 @@ dependencies = [ "digest", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "idna" version = "0.2.3" @@ -421,12 +513,37 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cae2cd7ba2f3f63938b9c724475dfb7b9861b545a90324476324ed21dbc8c8" +dependencies = [ + "cc", +] + [[package]] name = "log" version = "0.4.17" @@ -451,6 +568,18 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.5.1" @@ -473,6 +602,16 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-complex" version = "0.4.1" @@ -545,6 +684,25 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "open_jtalk" +version = "0.1.5" +source = "git+https://github.com/qwerty2501/open_jtalk-rs.git#425e2ca31b21d95fe026218df2221d8e786d5856" +dependencies = [ + "open_jtalk-sys", + "thiserror", +] + +[[package]] +name = "open_jtalk-sys" +version = "0.1.111" +source = "git+https://github.com/qwerty2501/open_jtalk-rs.git#425e2ca31b21d95fe026218df2221d8e786d5856" +dependencies = [ + "bindgen", + "cmake", + "link-cplusplus", +] + [[package]] name = "os_str_bytes" version = "6.0.1" @@ -583,6 +741,12 @@ dependencies = [ "sha2", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "percent-encoding" version = "2.1.0" @@ -652,6 +816,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -689,6 +870,12 @@ dependencies = [ "syn", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -785,6 +972,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + [[package]] name = "spin" version = "0.5.2" @@ -1027,6 +1220,7 @@ dependencies = [ "derive-new", "once_cell", "onnxruntime", + "open_jtalk", "pretty_assertions", "rstest", "serde", @@ -1117,6 +1311,17 @@ dependencies = [ "webpki", ] +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +dependencies = [ + "either", + "lazy_static", + "libc", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/crates/voicevox_core/Cargo.toml b/crates/voicevox_core/Cargo.toml index f318a6c6f..bfb79b193 100644 --- a/crates/voicevox_core/Cargo.toml +++ b/crates/voicevox_core/Cargo.toml @@ -21,6 +21,7 @@ onnxruntime = { git = "https://github.com/qwerty2501/onnxruntime-rs.git", versio serde = "1.0.137" serde_json = "1.0.81" thiserror = "1.0.31" +open_jtalk = { git = "https://github.com/qwerty2501/open_jtalk-rs.git", version = "0.1.5" } [dev-dependencies] rstest = "0.12.0" diff --git a/crates/voicevox_core/src/engine/mod.rs b/crates/voicevox_core/src/engine/mod.rs index c6bc66dd4..69339ea7d 100644 --- a/crates/voicevox_core/src/engine/mod.rs +++ b/crates/voicevox_core/src/engine/mod.rs @@ -1,3 +1,4 @@ mod kana_parser; mod model; mod mora_list; +mod open_jtalk; diff --git a/crates/voicevox_core/src/engine/open_jtalk.rs b/crates/voicevox_core/src/engine/open_jtalk.rs new file mode 100644 index 000000000..54bd70582 --- /dev/null +++ b/crates/voicevox_core/src/engine/open_jtalk.rs @@ -0,0 +1,96 @@ +use std::path::{Path, PathBuf}; + +use ::open_jtalk::*; + +/* + * TODO: OpenJtalk機能を使用するようになったら、allow(dead_code)を消す + */ + +#[allow(dead_code)] +#[derive(thiserror::Error, Debug, PartialEq)] +pub enum OpenJtalkError { + #[error("open_jtalk load error")] + Load { mecab_dict_dir: PathBuf }, + #[error("open_jtalk extract_fullcontext error")] + ExtractFullContext { + text: String, + #[source] + source: Option, + }, +} + +#[allow(dead_code)] +pub type Result = std::result::Result; + +#[allow(dead_code)] +pub struct OpenJtalk { + mecab: ManagedResource, + njd: ManagedResource, + jpcommon: ManagedResource, + dict_loaded: bool, +} + +impl OpenJtalk { + #[allow(dead_code)] + pub fn initialize() -> Self { + Self { + mecab: ManagedResource::initialize(), + njd: ManagedResource::initialize(), + jpcommon: ManagedResource::initialize(), + dict_loaded: false, + } + } + + #[allow(dead_code)] + pub fn extract_fullcontext(&mut self, text: impl AsRef) -> Result> { + let mecab_text = + text2mecab(text.as_ref()).map_err(|e| OpenJtalkError::ExtractFullContext { + text: text.as_ref().into(), + source: Some(e.into()), + })?; + if self.mecab.analysis(mecab_text) { + self.njd.mecab2njd( + self.mecab + .get_feature() + .ok_or(OpenJtalkError::ExtractFullContext { + text: text.as_ref().into(), + source: None, + })?, + self.mecab.get_size(), + ); + self.njd.set_pronunciation(); + self.njd.set_digit(); + self.njd.set_accent_phrase(); + self.njd.set_accent_type(); + self.njd.set_unvoiced_vowel(); + self.njd.set_long_vowel(); + self.jpcommon.njd2jpcommon(&self.njd); + self.jpcommon.make_label(); + self.jpcommon + .get_label_feature_to_iter() + .ok_or_else(|| OpenJtalkError::ExtractFullContext { + text: text.as_ref().into(), + source: None, + }) + .map(|iter| iter.map(|s| s.to_string()).collect()) + } else { + Err(OpenJtalkError::ExtractFullContext { + text: text.as_ref().into(), + source: None, + }) + } + } + + #[allow(dead_code)] + pub fn load(&mut self, mecab_dict_dir: impl AsRef) -> Result<()> { + let result = self.mecab.load(mecab_dict_dir.as_ref()); + if result { + self.dict_loaded = true; + Ok(()) + } else { + Err(OpenJtalkError::Load { + mecab_dict_dir: mecab_dict_dir.as_ref().into(), + }) + } + } +}