Skip to content

Commit

Permalink
整理: MetasStore にコアを内蔵 (VOICEVOX#1419)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
tarepan authored Jun 27, 2024
1 parent 7cff4a3 commit 77d8414
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 42 deletions.
17 changes: 13 additions & 4 deletions voicevox_engine/app/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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)
Expand Down
21 changes: 5 additions & 16 deletions voicevox_engine/app/routers/character.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -35,19 +34,15 @@ 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=["その他"])

@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")
Expand All @@ -61,22 +56,18 @@ 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,
)

@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")
Expand All @@ -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,
)
Expand Down
8 changes: 2 additions & 6 deletions voicevox_engine/app/routers/morphing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
46 changes: 30 additions & 16 deletions voicevox_engine/metas/MetasStore.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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] = {
Expand All @@ -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)
Expand All @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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(
Expand Down

0 comments on commit 77d8414

Please sign in to comment.