diff --git a/pyproject.toml b/pyproject.toml index 92f29287e..ffd7d3ea0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,9 +5,9 @@ description = "Add your description here" readme = "README.md" requires-python = "==3.11.9" dependencies = [ - "e2k==0.3.0", "fastapi-slim>=0.115.5", "jinja2>=3.1.3", # NOTE: required by fastapi.templating.Jinja2Templates (fastapi-slim's unmanaged dependency) + "kanalizer>=0.1.1", "numpy>=2.2.3", "platformdirs>=4.2.0", "pydantic>=2.7.3", diff --git a/requirements-build.txt b/requirements-build.txt index 268ef4d54..56b3e9090 100644 --- a/requirements-build.txt +++ b/requirements-build.txt @@ -4,11 +4,11 @@ anyio==4.9.0 cffi==1.17.1 click==8.1.8 colorama==0.4.6 ; sys_platform == 'win32' -e2k==0.3.0 fastapi-slim==0.115.12 h11==0.14.0 idna==3.10 jinja2==3.1.6 +kanalizer==0.1.1 macholib==1.16.3 ; sys_platform == 'darwin' markupsafe==3.0.2 numpy==2.2.4 diff --git a/requirements-dev.txt b/requirements-dev.txt index b749fb673..bd6c64391 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -14,7 +14,6 @@ cyclonedx-python-lib==9.1.0 defusedxml==0.7.1 distlib==0.3.9 docopt==0.6.2 -e2k==0.3.0 fastapi-slim==0.115.12 filelock==3.18.0 h11==0.14.0 @@ -24,6 +23,7 @@ identify==2.6.9 idna==3.10 iniconfig==2.1.0 jinja2==3.1.6 +kanalizer==0.1.1 license-expression==30.4.1 markdown-it-py==3.0.0 markupsafe==3.0.2 diff --git a/requirements.txt b/requirements.txt index 8b12219c4..0ee719282 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,11 +3,11 @@ anyio==4.9.0 cffi==1.17.1 click==8.1.8 colorama==0.4.6 ; sys_platform == 'win32' -e2k==0.3.0 fastapi-slim==0.115.12 h11==0.14.0 idna==3.10 jinja2==3.1.6 +kanalizer==0.1.1 markupsafe==3.0.2 numpy==2.2.4 platformdirs==4.3.7 diff --git a/run.spec b/run.spec index 7afd4a196..0b70b71d1 100644 --- a/run.spec +++ b/run.spec @@ -8,7 +8,6 @@ datas = [ ('engine_manifest.json', '.'), ('licenses.json', '.'), ] -datas += collect_data_files('e2k') datas += collect_data_files('pyopenjtalk') core_model_dir_path = os.environ.get('CORE_MODEL_DIR_PATH') diff --git a/test/e2e/single_api/tts_pipeline/__snapshots__/test_accent_phrases/test_post_accent_phrases_enable_e2k_200.json b/test/e2e/single_api/tts_pipeline/__snapshots__/test_accent_phrases/test_post_accent_phrases_enable_e2k_200.json index 502ce10ad..7195dbc87 100644 --- a/test/e2e/single_api/tts_pipeline/__snapshots__/test_accent_phrases/test_post_accent_phrases_enable_e2k_200.json +++ b/test/e2e/single_api/tts_pipeline/__snapshots__/test_accent_phrases/test_post_accent_phrases_enable_e2k_200.json @@ -4,10 +4,10 @@ "is_interrogative": false, "moras": [ { - "consonant": "b", - "consonant_length": 0.5, - "pitch": 2.56, - "text": "ボ", + "consonant": "v", + "consonant_length": 2.56, + "pitch": 4.62, + "text": "ヴォ", "vowel": "o", "vowel_length": 1.88 }, @@ -20,10 +20,10 @@ "vowel_length": 1.31 }, { - "consonant": "b", - "consonant_length": 0.5, - "pitch": 2.44, - "text": "ボ", + "consonant": "v", + "consonant_length": 2.56, + "pitch": 4.5, + "text": "ヴォ", "vowel": "o", "vowel_length": 1.88 } diff --git a/test/e2e/single_api/tts_pipeline/__snapshots__/test_audio_query/test_post_audio_query_enable_e2k_200.json b/test/e2e/single_api/tts_pipeline/__snapshots__/test_audio_query/test_post_audio_query_enable_e2k_200.json index 2d7759d4d..7da9188bc 100644 --- a/test/e2e/single_api/tts_pipeline/__snapshots__/test_audio_query/test_post_audio_query_enable_e2k_200.json +++ b/test/e2e/single_api/tts_pipeline/__snapshots__/test_audio_query/test_post_audio_query_enable_e2k_200.json @@ -5,10 +5,10 @@ "is_interrogative": false, "moras": [ { - "consonant": "b", - "consonant_length": 0.5, - "pitch": 2.56, - "text": "ボ", + "consonant": "v", + "consonant_length": 2.56, + "pitch": 4.62, + "text": "ヴォ", "vowel": "o", "vowel_length": 1.88 }, @@ -21,10 +21,10 @@ "vowel_length": 1.31 }, { - "consonant": "b", - "consonant_length": 0.5, - "pitch": 2.44, - "text": "ボ", + "consonant": "v", + "consonant_length": 2.56, + "pitch": 4.5, + "text": "ヴォ", "vowel": "o", "vowel_length": 1.88 } @@ -33,7 +33,7 @@ } ], "intonationScale": 1.0, - "kana": "ボ'イボ", + "kana": "ヴォ'イヴォ", "outputSamplingRate": 24000, "outputStereo": false, "pauseLength": null, diff --git a/test/unit/tts_pipeline/test_katakana_english.py b/test/unit/tts_pipeline/test_katakana_english.py index 6184b2666..69ee5c22e 100644 --- a/test/unit/tts_pipeline/test_katakana_english.py +++ b/test/unit/tts_pipeline/test_katakana_english.py @@ -44,6 +44,6 @@ def test_convert_english_to_katakana() -> None: pron = convert_english_to_katakana(string) - expected_pron = "ボイボ" + expected_pron = "ヴォイヴォ" assert expected_pron == pron diff --git a/tools/generate_licenses.py b/tools/generate_licenses.py index ac92f3c3c..6cd0befc8 100644 --- a/tools/generate_licenses.py +++ b/tools/generate_licenses.py @@ -7,6 +7,7 @@ """ import argparse +import importlib.metadata import json import subprocess import sys @@ -93,7 +94,6 @@ def _update_licenses(pip_licenses: list[_PipLicense]) -> list[_License]: """pip から取得したライセンス情報の抜けを補完する。""" package_to_license_url: dict[str, str] = { # "package_name": "https://license.adress.com/v0.0.0/LICENSE.txt", - "e2k": "https://raw.githubusercontent.com/Patchethium/e2k/refs/tags/0.3.0/LICENSE", } updated_licenses = [] @@ -304,11 +304,27 @@ def _add_licenses_manually(licenses: list[_License]) -> None: ] +def _patch_licenses_manually(licenses: list[_License]) -> None: + """手動でライセンス情報を修正する。""" + for license in licenses: + if license.package_name == "kanalizer": + # kanalizerのwheelをビルドするときに使ったライブラリの情報を追加する + for p in importlib.metadata.files("kanalizer"): # type: ignore + if p.name == "NOTICE.md": + notice_md = Path(p.locate()) + break + else: + raise Exception("kanalizerのNOTICE.mdが見つかりませんでした。") + license.license_text += "\n\n" + license.license_text += notice_md.read_text(encoding="utf-8") + + def _generate_licenses() -> list[_License]: pip_licenses = _acquire_licenses_of_pip_managed_libraries() licenses = _update_licenses(pip_licenses) _validate_license_compliance(licenses) _add_licenses_manually(licenses) + _patch_licenses_manually(licenses) return licenses diff --git a/uv.lock b/uv.lock index 1f52771c9..5a02ab3c0 100644 --- a/uv.lock +++ b/uv.lock @@ -218,18 +218,6 @@ version = "0.6.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } -[[package]] -name = "e2k" -version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/75/52/5e44462cd146c05513082522dab6ac606b3f119f58f42188fb7da02d3472/e2k-0.3.0.tar.gz", hash = "sha256:be7d40339aae8eb81f84db54183b34bd6914aad3f8396e4fe622f81b17ddb98b", size = 8225627, upload-time = "2025-03-09T13:12:26.365Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/b3/e2fe2d3d6bff7e6e2a61bfe5d90b50fa9bebcdc0861eb066a9c939054f94/e2k-0.3.0-py3-none-any.whl", hash = "sha256:67ae1a437d39d582def8c1dfec3634f61897d1b7dc49ce89e714d10b841c7c14", size = 8221224, upload-time = "2025-03-09T13:12:22.563Z" }, -] - [[package]] name = "fastapi-slim" version = "0.115.12" @@ -329,6 +317,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] +[[package]] +name = "kanalizer" +version = "0.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/ab/17afb904792db4f81b936f291d2c27bd427fc4d6519b152fb491c422814d/kanalizer-0.1.1.tar.gz", hash = "sha256:71e4523a332d1fdc43f0205a22f9cf9356edda7f4f9ff5efb5febcab60674a86", size = 57938, upload-time = "2025-05-21T22:28:28.653Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/5e/44bf1b1154430644cc88a1b0189337f1d85d38b02e78c3dd7a793c705c82/kanalizer-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9aac05e5590948850445b91ca317b257d531fa0989c28141c76f2de7ee77c813", size = 4447967, upload-time = "2025-05-21T22:28:16.235Z" }, + { url = "https://files.pythonhosted.org/packages/02/f8/df74b6d44b4abe02421bd240d2954b821a9786aac28b6a5de4eec5f9f7a2/kanalizer-0.1.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:6004b464002cb389130679f21d77523d84c494f302159ce18506d47039e0d657", size = 4441973, upload-time = "2025-05-21T22:28:18.378Z" }, + { url = "https://files.pythonhosted.org/packages/27/7b/ce684aa9fa5b512dab5e054da7cd554838b018a8579921d20973ec7a26dd/kanalizer-0.1.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9709732d7786b3c97b9b66ebbf162ba0adf88b6cdd193ba26d85e2a759f81237", size = 4452585, upload-time = "2025-05-21T22:28:20.617Z" }, + { url = "https://files.pythonhosted.org/packages/a9/82/5c93ae789fa44f3615ee465e36ce39ea4c3973d597a93dfa4c8ba4ff6edf/kanalizer-0.1.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:bb86f3fa2cfe4034fa68f3035e3235bb6ee314e1957aac9c0426d651e473709a", size = 4489970, upload-time = "2025-05-21T22:28:22.886Z" }, + { url = "https://files.pythonhosted.org/packages/1f/5d/a38e4e73a0ed7ceb5a7fa37213df72f999f224631aac0b713c46aadeace8/kanalizer-0.1.1-cp39-abi3-win32.whl", hash = "sha256:07acb02533ea8dc57dc2442ee9efe8978961ddafed13f0c35125abfea48c9e10", size = 4306111, upload-time = "2025-05-21T22:28:24.658Z" }, + { url = "https://files.pythonhosted.org/packages/f6/1c/69ad29206576664d01876e78d15a74d7f0a59691eabb15af35c9923c44d1/kanalizer-0.1.1-cp39-abi3-win_amd64.whl", hash = "sha256:ced78e0e3bc57ceafa92e008dd42cf65fe5abc02d1e9dbc8846518f6fca59e29", size = 4324435, upload-time = "2025-05-21T22:28:26.747Z" }, +] + [[package]] name = "license-expression" version = "30.4.1" @@ -727,7 +729,7 @@ wheels = [ [[package]] name = "pyopenjtalk" -version = "0.1.6.dev133+g74703b0" +version = "0.1.dev251+g74703b0" source = { git = "https://github.com/VOICEVOX/pyopenjtalk?rev=74703b034dd90a1f199f49bb70bf3b66b1728a86#74703b034dd90a1f199f49bb70bf3b66b1728a86" } dependencies = [ { name = "numpy" }, @@ -1086,9 +1088,9 @@ name = "voicevox-engine" version = "0.24.0" source = { virtual = "." } dependencies = [ - { name = "e2k" }, { name = "fastapi-slim" }, { name = "jinja2" }, + { name = "kanalizer" }, { name = "numpy" }, { name = "platformdirs" }, { name = "pydantic" }, @@ -1124,9 +1126,9 @@ dev = [ [package.metadata] requires-dist = [ - { name = "e2k", specifier = "==0.3.0" }, { name = "fastapi-slim", specifier = ">=0.115.5" }, { name = "jinja2", specifier = ">=3.1.3" }, + { name = "kanalizer", specifier = ">=0.1.1" }, { name = "numpy", specifier = ">=2.2.3" }, { name = "platformdirs", specifier = ">=4.2.0" }, { name = "pydantic", specifier = ">=2.7.3" }, diff --git a/voicevox_engine/tts_pipeline/katakana_english.py b/voicevox_engine/tts_pipeline/katakana_english.py index 8b97fc3da..9ce360f93 100644 --- a/voicevox_engine/tts_pipeline/katakana_english.py +++ b/voicevox_engine/tts_pipeline/katakana_english.py @@ -3,21 +3,11 @@ import re from typing import NewType, TypeGuard -import e2k +import kanalizer # 半角アルファベット文字列を示す型 HankakuAlphabet = NewType("HankakuAlphabet", str) -_global_c2k: e2k.C2K | None = None - - -def _initialize_c2k() -> e2k.C2K: - global _global_c2k - if _global_c2k is None: - _global_c2k = e2k.C2K() - - return _global_c2k - # OpenJTalkで使っているアルファベット→カタカナの対応表 # https://github.com/VOICEVOX/open_jtalk/blob/b9b1bf6a0cba6bc9550b4521913b20334a218dfc/src/njd_set_pronunciation/njd_set_pronunciation_rule_utf_8.h#L397 @@ -69,19 +59,17 @@ def should_convert_english_to_katakana(string: HankakuAlphabet) -> bool: def convert_english_to_katakana(string: HankakuAlphabet) -> str: - """e2kを用いて、読みが不明な英単語をカタカナに変換する""" - c2k = _initialize_c2k() - + """kanalizerを用いて、読みが不明な英単語をカタカナに変換する""" kana = "" # キャメルケース的な単語に対応させるため、大文字で分割する for word in re.findall("[a-zA-Z][a-z]*", string): word = HankakuAlphabet(word) - # 大文字のみ、もしくは短いワードの場合は、e2kでの解析を行わない + # 大文字のみ、もしくは短いワードの場合は、kanalizerでの変換を行わない if not should_convert_english_to_katakana(word): for alphabet in word: kana += ojt_alphabet_kana_mapping[alphabet.upper()] else: - kana += c2k(word.lower()) + kana += kanalizer.convert(word.lower()) return kana