From 77d841469032e61086ee4dfad69783751729a543 Mon Sep 17 00:00:00 2001 From: tarepan Date: Thu, 27 Jun 2024 13:54:26 +0900 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86:=20`MetasStore`=20=E3=81=AB?= =?UTF-8?q?=E3=82=B3=E3=82=A2=E3=82=92=E5=86=85=E8=94=B5=20(#1419)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: `.talk_characters()` / `.sing_characters()` へコアを内蔵 * refactor: `.load_combined_metas()` へコアを内蔵 * refactor: `.load_combined_metas()` → `.characters()` へリネーム * refactor: 不要になった `CoreManager` 引数を削除 * refactor: `MetasStore` と `CoreManager` の接点を最小化 * fix: docstring を追従 * refactor: `generate_core_characters_getter()` を移動 * refactor: `_generate_core_characters_getter()` を削除 * fix: lint --- voicevox_engine/app/application.py | 17 ++++++--- voicevox_engine/app/routers/character.py | 21 +++-------- voicevox_engine/app/routers/morphing.py | 8 ++--- voicevox_engine/metas/MetasStore.py | 46 +++++++++++++++--------- 4 files changed, 50 insertions(+), 42 deletions(-) diff --git a/voicevox_engine/app/application.py b/voicevox_engine/app/application.py index c6b9352ce..90611572f 100644 --- a/voicevox_engine/app/application.py +++ b/voicevox_engine/app/application.py @@ -19,6 +19,7 @@ from voicevox_engine.app.routers.tts_pipeline import generate_tts_pipeline_router from voicevox_engine.app.routers.user_dict import generate_user_dict_router from voicevox_engine.cancellable_engine import CancellableEngine +from voicevox_engine.core.core_adapter import CoreCharacter from voicevox_engine.core.core_initializer import CoreManager from voicevox_engine.engine_manifest import EngineManifest from voicevox_engine.library.library_manager import LibraryManager @@ -66,7 +67,17 @@ def generate_app( resource_manager = ResourceManager(is_development()) resource_manager.register_dir(character_info_dir) - metas_store = MetasStore(character_info_dir, resource_manager) + + def _get_core_characters(version: str | None) -> list[CoreCharacter]: + version = version or core_manager.latest_version() + core = core_manager.get_core(version) + return core.characters + + metas_store = MetasStore( + character_info_dir, + _get_core_characters, + resource_manager, + ) app.include_router( generate_tts_pipeline_router( @@ -77,9 +88,7 @@ def generate_app( app.include_router( generate_preset_router(preset_manager, verify_mutability_allowed) ) - app.include_router( - generate_character_router(core_manager, resource_manager, metas_store) - ) + app.include_router(generate_character_router(resource_manager, metas_store)) if engine_manifest.supported_features.manage_library: app.include_router( generate_library_router(library_manager, verify_mutability_allowed) diff --git a/voicevox_engine/app/routers/character.py b/voicevox_engine/app/routers/character.py index 41f02bdec..4ff607766 100644 --- a/voicevox_engine/app/routers/character.py +++ b/voicevox_engine/app/routers/character.py @@ -6,7 +6,6 @@ from fastapi.responses import FileResponse from pydantic.json_schema import SkipJsonSchema -from voicevox_engine.core.core_initializer import CoreManager from voicevox_engine.metas.Metas import Speaker, SpeakerInfo from voicevox_engine.metas.MetasStore import Character, MetasStore, ResourceFormat from voicevox_engine.resource_manager import ResourceManager, ResourceManagerError @@ -35,9 +34,7 @@ def _characters_to_speakers(characters: list[Character]) -> list[Speaker]: def generate_character_router( - core_manager: CoreManager, - resource_manager: ResourceManager, - metas_store: MetasStore, + resource_manager: ResourceManager, metas_store: MetasStore ) -> APIRouter: """キャラクター情報 API Router を生成する""" router = APIRouter(tags=["その他"]) @@ -45,9 +42,7 @@ def generate_character_router( @router.get("/speakers") def speakers(core_version: str | SkipJsonSchema[None] = None) -> list[Speaker]: """喋れるキャラクターの情報の一覧を返します。""" - version = core_version or core_manager.latest_version() - core = core_manager.get_core(version) - characters = metas_store.talk_characters(core.characters) + characters = metas_store.talk_characters(core_version) return _characters_to_speakers(characters) @router.get("/speaker_info") @@ -61,12 +56,10 @@ def speaker_info( UUID で指定された喋れるキャラクターの情報を返します。 画像や音声はresource_formatで指定した形式で返されます。 """ - version = core_version or core_manager.latest_version() - core = core_manager.get_core(version) return metas_store.character_info( character_uuid=speaker_uuid, talk_or_sing="talk", - core_characters=core.characters, + core_version=core_version, resource_baseurl=resource_baseurl, resource_format=resource_format, ) @@ -74,9 +67,7 @@ def speaker_info( @router.get("/singers") def singers(core_version: str | SkipJsonSchema[None] = None) -> list[Speaker]: """歌えるキャラクターの情報の一覧を返します。""" - version = core_version or core_manager.latest_version() - core = core_manager.get_core(version) - characters = metas_store.sing_characters(core.characters) + characters = metas_store.sing_characters(core_version) return _characters_to_speakers(characters) @router.get("/singer_info") @@ -90,12 +81,10 @@ def singer_info( UUID で指定された歌えるキャラクターの情報を返します。 画像や音声はresource_formatで指定した形式で返されます。 """ - version = core_version or core_manager.latest_version() - core = core_manager.get_core(version) return metas_store.character_info( character_uuid=speaker_uuid, talk_or_sing="sing", - core_characters=core.characters, + core_version=core_version, resource_baseurl=resource_baseurl, resource_format=resource_format, ) diff --git a/voicevox_engine/app/routers/morphing.py b/voicevox_engine/app/routers/morphing.py index c717b44e4..458a82333 100644 --- a/voicevox_engine/app/routers/morphing.py +++ b/voicevox_engine/app/routers/morphing.py @@ -54,10 +54,7 @@ def morphable_targets( プロパティが存在しない場合は、モーフィングが許可されているとみなします。 返り値のスタイルIDはstring型なので注意。 """ - version = core_version or core_manager.latest_version() - core = core_manager.get_core(version) - - characters = metas_store.load_combined_metas(core.characters) + characters = metas_store.characters(core_version) try: morphable_targets = get_morphable_targets(characters, base_style_ids) except StyleIdNotFoundError as e: @@ -94,10 +91,9 @@ def _synthesis_morphing( """ version = core_version or core_manager.latest_version() engine = tts_engines.get_engine(version) - core = core_manager.get_core(version) # モーフィングが許可されないキャラクターペアを拒否する - characters = metas_store.load_combined_metas(core.characters) + characters = metas_store.characters(core_version) try: morphable = is_morphable(characters, base_style_id, target_style_id) except StyleIdNotFoundError as e: diff --git a/voicevox_engine/metas/MetasStore.py b/voicevox_engine/metas/MetasStore.py index 64f3df69a..b8bd35678 100644 --- a/voicevox_engine/metas/MetasStore.py +++ b/voicevox_engine/metas/MetasStore.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from pathlib import Path -from typing import Final, Literal, TypeAlias +from typing import Callable, Final, Literal, TypeAlias from fastapi import HTTPException from pydantic import BaseModel, Field @@ -53,14 +53,30 @@ class _EngineCharacter(BaseModel): ) +GetCoreCharacters: TypeAlias = Callable[[str | None], list[CoreCharacter]] + + class MetasStore: """キャラクターやスタイルのメタ情報を管理する""" def __init__( - self, engine_characters_path: Path, resource_manager: ResourceManager + self, + engine_characters_path: Path, + get_core_characters: GetCoreCharacters, + resource_manager: ResourceManager, ) -> None: - """エンジンに含まれるメタ情報へのパスを基にインスタンスを生成する。""" + """ + インスタンスを生成する。 + + Parameters + ---------- + engine_characters_path : Path + エンジンに含まれるキャラクターメタ情報ディレクトリのパス。 + get_core_characters: + コアに含まれるキャラクター情報を返す関数 + """ self._characters_path = engine_characters_path + self._get_core_characters = get_core_characters self._resource_manager = resource_manager # エンジンに含まれる各キャラクターのメタ情報 self._loaded_metas: dict[str, _EngineCharacter] = { @@ -71,12 +87,12 @@ def __init__( if folder.is_dir() } - def load_combined_metas( - self, core_characters: list[CoreCharacter] - ) -> list[Character]: - """コアとエンジンのメタ情報を統合する。""" + def characters(self, core_version: str | None) -> list[Character]: + """キャラクターの情報の一覧を取得する。""" + + # エンジンとコアのキャラクター情報を統合する characters: list[Character] = [] - for core_character in core_characters: + for core_character in self._get_core_characters(core_version): character_uuid = core_character.speaker_uuid engine_character = self._loaded_metas[character_uuid] styles = cast_styles(core_character.styles) @@ -102,7 +118,7 @@ def character_info( self, character_uuid: str, talk_or_sing: Literal["talk", "sing"], - core_characters: list[CoreCharacter], + core_version: str | None, resource_baseurl: str, resource_format: ResourceFormat, ) -> SpeakerInfo: @@ -129,7 +145,7 @@ def character_info( # ... # 該当キャラクターを検索する - characters = self.load_combined_metas(core_characters) + characters = self.characters(core_version) characters = filter_characters_and_styles(characters, talk_or_sing) character = next( filter(lambda character: character.uuid == character_uuid, characters), None @@ -199,15 +215,13 @@ def _resource_str(path: Path) -> str: ) return character_info - def talk_characters(self, core_characters: list[CoreCharacter]) -> list[Character]: + def talk_characters(self, core_version: str | None) -> list[Character]: """話せるキャラクターの情報の一覧を取得する。""" - characters = self.load_combined_metas(core_characters) - return filter_characters_and_styles(characters, "talk") + return filter_characters_and_styles(self.characters(core_version), "talk") - def sing_characters(self, core_characters: list[CoreCharacter]) -> list[Character]: + def sing_characters(self, core_version: str | None) -> list[Character]: """歌えるキャラクターの情報の一覧を取得する。""" - characters = self.load_combined_metas(core_characters) - return filter_characters_and_styles(characters, "sing") + return filter_characters_and_styles(self.characters(core_version), "sing") def filter_characters_and_styles(