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 9 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
12 changes: 7 additions & 5 deletions voicevox_engine/app/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
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 MetasStore, generate_core_characters_getter
from voicevox_engine.preset.preset_manager import PresetManager
from voicevox_engine.resource_manager import ResourceManager
from voicevox_engine.setting.model import CorsPolicyMode
Expand Down Expand Up @@ -66,7 +66,11 @@ def generate_app(

resource_manager = ResourceManager(is_development())
resource_manager.register_dir(speaker_info_dir)
metas_store = MetasStore(speaker_info_dir, resource_manager)
metas_store = MetasStore(
speaker_info_dir,
generate_core_characters_getter(core_manager),
resource_manager,
)

app.include_router(
generate_tts_pipeline_router(
Expand All @@ -77,9 +81,7 @@ def generate_app(
app.include_router(
generate_preset_router(preset_manager, verify_mutability_allowed)
)
app.include_router(
generate_speaker_router(core_manager, resource_manager, metas_store)
)
app.include_router(generate_speaker_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
18 changes: 4 additions & 14 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 MetasStore, ResourceFormat
from voicevox_engine.resource_manager import ResourceManager, ResourceManagerError
Expand All @@ -19,7 +18,6 @@ async def _get_resource_baseurl(request: Request) -> str:


def generate_speaker_router(
core_manager: CoreManager,
resource_manager: ResourceManager,
metas_store: MetasStore,
) -> APIRouter:
Expand All @@ -29,9 +27,7 @@ def generate_speaker_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)
return metas_store.talk_characters(core.characters)
return metas_store.talk_characters(core_version)

@router.get("/speaker_info")
def speaker_info(
Expand All @@ -44,22 +40,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.speaker_info(
speaker_uuid=speaker_uuid,
speaker_or_singer="speaker",
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)
return metas_store.sing_characters(core.characters)
return metas_store.sing_characters(core_version)

@router.get("/singer_info")
def singer_info(
Expand All @@ -72,12 +64,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.speaker_info(
speaker_uuid=speaker_uuid,
speaker_or_singer="singer",
core_characters=core.characters,
core_version=core_version,
resource_baseurl=resource_baseurl,
resource_format=resource_format,
)
Expand Down
7 changes: 2 additions & 5 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)
speakers = characters_to_speakers(characters)
try:
morphable_targets = get_morphable_targets(speakers, base_style_ids)
Expand Down Expand Up @@ -98,7 +95,7 @@ def _synthesis_morphing(
core = core_manager.get_core(version)

# モーフィングが許可されないキャラクターペアを拒否する
characters = metas_store.load_combined_metas(core.characters)
characters = metas_store.characters(core_version)
speakers = characters_to_speakers(characters)
try:
morphable = is_morphable(speakers, base_style_id, target_style_id)
Expand Down
51 changes: 36 additions & 15 deletions voicevox_engine/metas/MetasStore.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

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

from voicevox_engine.core.core_adapter import CoreCharacter, CoreCharacterStyle
from voicevox_engine.core.core_initializer import CoreManager
from voicevox_engine.metas.Metas import (
Speaker,
SpeakerInfo,
Expand Down Expand Up @@ -68,21 +69,43 @@ class _EngineSpeaker(BaseModel):
)


GetCoreCharacters: TypeAlias = Callable[[str | None], list[CoreCharacter]]


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


class MetasStore:
"""
話者やスタイルのメタ情報を管理する
"""

def __init__(
self, engine_speakers_path: Path, resource_manager: ResourceManager
self,
engine_speakers_path: Path,
get_core_characters: GetCoreCharacters,
resource_manager: ResourceManager,
) -> None:
"""
Parameters
----------
engine_speakers_path : Path
エンジンに含まれる話者メタ情報ディレクトリのパス。
get_core_characters:
コアに含まれるキャラクター情報を返す関数
"""
self._speakers_path = engine_speakers_path
self._get_core_characters = get_core_characters
self._resource_manager = resource_manager
# エンジンに含まれる各話者のメタ情報
self._loaded_metas: dict[str, _EngineSpeaker] = {
Expand All @@ -93,12 +116,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 @@ -124,7 +147,7 @@ def speaker_info(
self,
speaker_uuid: str,
speaker_or_singer: Literal["speaker", "singer"],
core_characters: list[CoreCharacter],
core_version: str | None,
resource_baseurl: str,
resource_format: ResourceFormat,
) -> SpeakerInfo:
Expand All @@ -151,7 +174,7 @@ def speaker_info(
# ...

# 該当話者を検索する
characters = self.load_combined_metas(core_characters)
characters = self.characters(core_version)
speakers = filter_characters_and_styles(characters, speaker_or_singer)
speaker = next(
filter(lambda spk: spk.speaker_uuid == speaker_uuid, speakers), None
Expand Down Expand Up @@ -220,15 +243,13 @@ def _resource_str(path: Path) -> str:
)
return spk_info

def talk_characters(self, core_characters: list[CoreCharacter]) -> list[Speaker]:
def talk_characters(self, core_version: str | None) -> list[Speaker]:
"""話せるキャラクターの情報の一覧を取得する。"""
characters = self.load_combined_metas(core_characters)
return filter_characters_and_styles(characters, "speaker")
return filter_characters_and_styles(self.characters(core_version), "speaker")

def sing_characters(self, core_characters: list[CoreCharacter]) -> list[Speaker]:
def sing_characters(self, core_version: str | None) -> list[Speaker]:
"""歌えるキャラクターの情報の一覧を取得する。"""
characters = self.load_combined_metas(core_characters)
return filter_characters_and_styles(characters, "singer")
return filter_characters_and_styles(self.characters(core_version), "singer")


def filter_characters_and_styles(
Expand Down
Loading