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

整理: MetasStore にコアを内蔵 #1419

Merged
merged 14 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
26 changes: 21 additions & 5 deletions voicevox_engine/app/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
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
from voicevox_engine.metas.MetasStore import MetasStore
from voicevox_engine.metas.MetasStore import GetCoreCharacters, MetasStore
from voicevox_engine.preset.preset_manager import PresetManager
from voicevox_engine.resource_manager import ResourceManager
from voicevox_engine.setting.model import CorsPolicyMode
Expand All @@ -33,6 +34,19 @@
from voicevox_engine.utility.runtime_utility import is_development


def _generate_core_characters_getter(core_manager: CoreManager) -> GetCoreCharacters:
"""コアマネージャーを基に `get_core_characters()` 関数を生成する。"""

def get_core_characters(version: str | None) -> list[CoreCharacter]:
"""バージョンで指定されたコアからキャラクター一覧を取得する。"""
# NOTE: CoreManager へ直接触れずにキャラクター情報を取得するために関数化している
version = version or core_manager.latest_version()
core = core_manager.get_core(version)
return core.characters

return get_core_characters
tarepan marked this conversation as resolved.
Show resolved Hide resolved


def generate_app(
tts_engines: TTSEngineManager,
core_manager: CoreManager,
Expand Down Expand Up @@ -66,7 +80,11 @@ def generate_app(

resource_manager = ResourceManager(is_development())
resource_manager.register_dir(character_info_dir)
metas_store = MetasStore(character_info_dir, resource_manager)
metas_store = MetasStore(
character_info_dir,
_generate_core_characters_getter(core_manager),
resource_manager,
)

app.include_router(
generate_tts_pipeline_router(
Expand All @@ -77,9 +95,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(
指定されたspeaker_uuidの話者に関する情報をjson形式で返します。
画像や音声は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(
指定されたspeaker_uuidの歌手に関する情報をjson形式で返します。
画像や音声は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
37 changes: 22 additions & 15 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,21 +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 @@ -78,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 @@ -109,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 @@ -136,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 @@ -205,15 +214,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
Loading