Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

open_jtalk-rsを更新し、caminoを利用 #745

Merged
merged 1 commit into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 16 additions & 26 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ async-std = "1.12.0"
async_zip = "0.0.11"
binstall-tar = "0.4.39"
bytes = "1.1.0"
camino = "1.1.6"
cbindgen = "0.24.3"
chrono = { version = "0.4.26", default-features = false }
clap = "4.0.10"
Expand Down Expand Up @@ -87,7 +88,7 @@ rev = "ebb9dcb9b26ee681889b52b6db3b4f642b04a250"

[workspace.dependencies.open_jtalk]
git = "https://github.com/VOICEVOX/open_jtalk-rs.git"
rev = "a16714ce16dec76fd0e3041a7acfa484921db3b5"
rev = "70c76bb54522830e92803038191bf533ba68ce85"

# FIXME: iOS対応のpull request(https://github.com/wesleywiser/process_path/pull/16)がマージされる見込みが無いため
[workspace.dependencies.process_path]
Expand Down
1 change: 1 addition & 0 deletions crates/voicevox_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ directml = ["onnxruntime/directml"]
[dependencies]
anyhow.workspace = true
async_zip = { workspace = true, features = ["full"] }
camino.workspace = true
derive-getters.workspace = true
derive-new.workspace = true
derive_more.workspace = true
Expand Down
4 changes: 2 additions & 2 deletions crates/voicevox_core/src/__internal/doctest_fixtures.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::path::Path;
use camino::Utf8Path;

use crate::{AccelerationMode, InitializeOptions};

pub async fn synthesizer_with_sample_voice_model(
open_jtalk_dic_dir: impl AsRef<Path>,
open_jtalk_dic_dir: impl AsRef<Utf8Path>,
) -> anyhow::Result<crate::tokio::Synthesizer<crate::tokio::OpenJtalk>> {
let syntesizer = crate::tokio::Synthesizer::new(
crate::tokio::OpenJtalk::new(open_jtalk_dic_dir).await?,
Expand Down
54 changes: 27 additions & 27 deletions crates/voicevox_core/src/engine/open_jtalk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ pub trait FullcontextExtractor: Clone + Send + Sync + 'static {
pub(crate) mod blocking {
use std::{
io::Write as _,
path::Path,
sync::{Arc, Mutex},
};

use anyhow::anyhow;
use anyhow::Context as _;
use camino::{Utf8Path, Utf8PathBuf};
use open_jtalk::{mecab_dict_index, text2mecab, JpCommon, ManagedResource, Mecab, Njd};
use tempfile::NamedTempFile;

Expand All @@ -32,12 +32,8 @@ pub(crate) mod blocking {
pub struct OpenJtalk(pub(super) Arc<Inner>);

impl self::OpenJtalk {
pub fn new(open_jtalk_dict_dir: impl AsRef<Path>) -> crate::result::Result<Self> {
let dict_dir = open_jtalk_dict_dir
.as_ref()
.to_str()
.unwrap_or_else(|| todo!()) // FIXME: `camino::Utf8Path`を要求するようにする
.to_owned();
pub fn new(open_jtalk_dict_dir: impl AsRef<Utf8Path>) -> crate::result::Result<Self> {
let dict_dir = open_jtalk_dict_dir.as_ref().to_owned();

// FIXME: この`{}`はGitのdiffを抑えるためだけに存在
{
Expand All @@ -47,11 +43,12 @@ pub(crate) mod blocking {
jpcommon: ManagedResource::initialize(),
};

let result = resources.mecab.load(&*dict_dir);
if !result {
// FIXME: 「システム辞書を読もうとしたけど読めなかった」というエラーをちゃんと用意する
return Err(ErrorRepr::NotLoadedOpenjtalkDict.into());
}
// FIXME: 「システム辞書を読もうとしたけど読めなかった」というエラーをちゃんと用意する
resources
.mecab
.load(&*dict_dir)
.inspect_err(|e| tracing::error!("{e:?}"))
.map_err(|_| ErrorRepr::NotLoadedOpenjtalkDict)?;

Ok(Self(Arc::new(Inner {
resources: Mutex::new(resources),
Expand Down Expand Up @@ -124,7 +121,7 @@ pub(crate) mod blocking {

pub(super) struct Inner {
resources: std::sync::Mutex<Resources>,
dict_dir: String, // FIXME: `camino::Utf8PathBuf`にする
dict_dir: Utf8PathBuf,
}

impl Inner {
Expand All @@ -145,34 +142,37 @@ pub(crate) mod blocking {
NamedTempFile::new().map_err(|e| ErrorRepr::UseUserDict(e.into()))?;
let temp_dict_path = temp_dict.into_temp_path();

// FIXME: `.unwrap()`ではなく、エラーとして回収する
let temp_csv_path = Utf8Path::from_path(temp_csv_path.as_ref()).unwrap();
let temp_dict_path = Utf8Path::from_path(temp_dict_path.as_ref()).unwrap();

// Mecabでユーザー辞書をコンパイル
// TODO: エラー(SEGV)が出るパターンを把握し、それをRust側で防ぐ。
mecab_dict_index(&[
"mecab-dict-index",
"-d",
&self.dict_dir,
self.dict_dir.as_ref(),
"-u",
temp_dict_path.to_str().unwrap(),
temp_dict_path.as_ref(),
"-f",
"utf-8",
"-t",
"utf-8",
temp_csv_path.to_str().unwrap(),
temp_csv_path.as_ref(),
"-q",
]);

self.load_with_userdic(Some(temp_dict_path.as_ref()))
self.load_with_userdic(Some(temp_dict_path))
}
}
fn load_with_userdic(&self, dict_path: Option<&Path>) -> crate::result::Result<()> {
fn load_with_userdic(&self, dict_path: Option<&Utf8Path>) -> crate::result::Result<()> {
let Resources { mecab, .. } = &mut *self.resources.lock().unwrap();

let result = mecab.load_with_userdic(self.dict_dir.as_ref(), dict_path);

if !result {
return Err(ErrorRepr::UseUserDict(anyhow!("辞書を読み込めませんでした。")).into());
}
Ok(())
mecab
.load_with_userdic(self.dict_dir.as_ref(), dict_path)
.context("辞書を読み込めませんでした。")
.map_err(ErrorRepr::UseUserDict)
.map_err(Into::into)
}
}

Expand All @@ -188,7 +188,7 @@ pub(crate) mod blocking {
}

pub(crate) mod tokio {
use std::path::Path;
use camino::Utf8Path;

use super::FullcontextExtractor;

Expand All @@ -197,7 +197,7 @@ pub(crate) mod tokio {
pub struct OpenJtalk(super::blocking::OpenJtalk);

impl self::OpenJtalk {
pub async fn new(open_jtalk_dict_dir: impl AsRef<Path>) -> crate::result::Result<Self> {
pub async fn new(open_jtalk_dict_dir: impl AsRef<Utf8Path>) -> crate::result::Result<Self> {
let open_jtalk_dict_dir = open_jtalk_dict_dir.as_ref().to_owned();
let blocking =
crate::task::asyncify(|| super::blocking::OpenJtalk::new(open_jtalk_dict_dir))
Expand Down
1 change: 1 addition & 0 deletions crates/voicevox_core_c_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ directml = ["voicevox_core/directml"]
[dependencies]
anstream = { workspace = true, default-features = false, features = ["auto"] }
anstyle-query.workspace = true
camino.workspace = true
chrono = { workspace = true, default-features = false, features = ["clock"] }
colorchoice.workspace = true
cstr.workspace = true
Expand Down
3 changes: 2 additions & 1 deletion crates/voicevox_core_c_api/src/c_impls.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::{ffi::CString, path::Path};

use camino::Utf8Path;
use voicevox_core::{InitializeOptions, Result, VoiceModelId};

use crate::{helpers::CApiResult, OpenJtalkRc, VoicevoxSynthesizer, VoicevoxVoiceModel};

impl OpenJtalkRc {
pub(crate) fn new(open_jtalk_dic_dir: impl AsRef<Path>) -> Result<Self> {
pub(crate) fn new(open_jtalk_dic_dir: impl AsRef<Utf8Path>) -> Result<Self> {
Ok(Self {
open_jtalk: voicevox_core::blocking::OpenJtalk::new(open_jtalk_dic_dir)?,
})
Expand Down
1 change: 1 addition & 0 deletions crates/voicevox_core_python_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ crate-type = ["cdylib"]
directml = ["voicevox_core/directml"]

[dependencies]
camino.workspace = true
easy-ext.workspace = true
log.workspace = true
pyo3 = { workspace = true, features = ["abi3-py38", "extension-module"] }
Expand Down
5 changes: 4 additions & 1 deletion crates/voicevox_core_python_api/src/convert.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{error::Error as _, future::Future, iter, path::PathBuf};

use camino::Utf8PathBuf;
use easy_ext::ext;
use pyo3::{
exceptions::{PyException, PyValueError},
Expand Down Expand Up @@ -38,10 +39,12 @@ pub fn from_acceleration_mode(ob: &PyAny) -> PyResult<AccelerationMode> {
}
}

pub fn from_utf8_path(ob: &PyAny) -> PyResult<String> {
// FIXME: `VoiceModel`や`UserDict`についてはこれではなく、`PathBuf::extract`を直接使うようにする
pub fn from_utf8_path(ob: &PyAny) -> PyResult<Utf8PathBuf> {
PathBuf::extract(ob)?
.into_os_string()
.into_string()
.map(Utf8PathBuf::from)
.map_err(|s| PyValueError::new_err(format!("{s:?} cannot be encoded to UTF-8")))
}

Expand Down
10 changes: 6 additions & 4 deletions crates/voicevox_core_python_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use self::convert::{
to_py_user_dict_word, to_py_uuid, to_pydantic_dataclass, to_pydantic_voice_model_meta,
to_rust_user_dict_word, to_rust_uuid, VoicevoxCoreResultExt as _,
};
use camino::Utf8PathBuf;
use easy_ext::ext;
use log::debug;
use pyo3::{
Expand Down Expand Up @@ -115,7 +116,7 @@ impl VoiceModel {
#[staticmethod]
fn from_path(
py: Python<'_>,
#[pyo3(from_py_with = "from_utf8_path")] path: String,
#[pyo3(from_py_with = "from_utf8_path")] path: Utf8PathBuf,
) -> PyResult<&PyAny> {
pyo3_asyncio::tokio::future_into_py(py, async move {
let model = voicevox_core::tokio::VoiceModel::from_path(path).await;
Expand Down Expand Up @@ -146,7 +147,7 @@ impl OpenJtalk {
#[allow(clippy::new_ret_no_self)]
#[staticmethod]
fn new(
#[pyo3(from_py_with = "from_utf8_path")] open_jtalk_dict_dir: String,
#[pyo3(from_py_with = "from_utf8_path")] open_jtalk_dict_dir: Utf8PathBuf,
py: Python<'_>,
) -> PyResult<&PyAny> {
pyo3_asyncio::tokio::future_into_py(py, async move {
Expand Down Expand Up @@ -637,6 +638,7 @@ impl UserDict {
mod blocking {
use std::sync::Arc;

use camino::Utf8PathBuf;
use pyo3::{
pyclass, pymethods,
types::{IntoPyDict as _, PyBytes, PyDict, PyList},
Expand All @@ -661,7 +663,7 @@ mod blocking {
#[staticmethod]
fn from_path(
py: Python<'_>,
#[pyo3(from_py_with = "crate::convert::from_utf8_path")] path: String,
#[pyo3(from_py_with = "crate::convert::from_utf8_path")] path: Utf8PathBuf,
) -> PyResult<Self> {
let model = voicevox_core::blocking::VoiceModel::from_path(path).into_py_result(py)?;
Ok(Self { model })
Expand All @@ -688,7 +690,7 @@ mod blocking {
impl OpenJtalk {
#[new]
fn new(
#[pyo3(from_py_with = "super::from_utf8_path")] open_jtalk_dict_dir: String,
#[pyo3(from_py_with = "super::from_utf8_path")] open_jtalk_dict_dir: Utf8PathBuf,
py: Python<'_>,
) -> PyResult<Self> {
let open_jtalk =
Expand Down
Loading