Skip to content

Commit

Permalink
整理: Character 利用範囲を拡大 (#1385)
Browse files Browse the repository at this point in the history
* refactor: `Character` 利用範囲を拡大

* refactor: 共通変数を利用

* refactor: list 化

Co-authored-by: Hiroshiba <hihokaruta@gmail.com>

* refactor: `filter_speakers_and_styles()` をリネーム

* fix: lint

* refactor: `speakers_to_characters()` をテストへ移動

* refactor: `speaker` → `character` へリネーム

* fix: lint

* fix: プライベート関数に `_` prefix を付けてリネーム

* fix: `speaker` → `character` へリネームして追従

---------

Co-authored-by: Hiroshiba <hihokaruta@gmail.com>
  • Loading branch information
tarepan and Hiroshiba authored Jun 20, 2024
1 parent 5f15d6f commit a8d4702
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 74 deletions.
63 changes: 46 additions & 17 deletions test/unit/test_metas_store.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
import uuid

from voicevox_engine.metas.Metas import Speaker, SpeakerStyle, StyleId, StyleType
from voicevox_engine.metas.MetasStore import filter_speakers_and_styles
from voicevox_engine.metas.MetasStore import (
SING_STYLE_TYPES,
TALK_STYLE_TYPES,
Character,
filter_characters_and_styles,
)


def _speakers_to_characters(speakers: list[Speaker]) -> list[Character]:
"""Speaker 配列をキャラクター配列へキャストする。"""
characters: list[Character] = []
for speaker in speakers:
styles = speaker.styles
talk_styles = filter(lambda style: style.type in TALK_STYLE_TYPES, styles)
sing_styles = filter(lambda style: style.type in SING_STYLE_TYPES, styles)
characters.append(
Character(
name=speaker.name,
uuid=speaker.speaker_uuid,
talk_styles=list(talk_styles),
sing_styles=list(sing_styles),
version=speaker.version,
supported_features=speaker.supported_features,
)
)
return characters


def _gen_speaker(style_types: list[StyleType]) -> Speaker:
Expand Down Expand Up @@ -38,14 +63,16 @@ def test_filter_speakers_and_styles_with_speaker() -> None:
speaker_allstyle = _gen_speaker(["talk", "singing_teacher", "frame_decode", "sing"])

# Outputs
result = filter_speakers_and_styles(
[
speaker_talk_only,
speaker_singing_teacher_only,
speaker_frame_decode_only,
speaker_sing_only,
speaker_allstyle,
],
result = filter_characters_and_styles(
_speakers_to_characters(
[
speaker_talk_only,
speaker_singing_teacher_only,
speaker_frame_decode_only,
speaker_sing_only,
speaker_allstyle,
]
),
"speaker",
)

Expand All @@ -70,14 +97,16 @@ def test_filter_speakers_and_styles_with_singer() -> None:
speaker_allstyle = _gen_speaker(["talk", "singing_teacher", "frame_decode", "sing"])

# Outputs
result = filter_speakers_and_styles(
[
speaker_talk_only,
speaker_singing_teacher_only,
speaker_frame_decode_only,
speaker_sing_only,
speaker_allstyle,
],
result = filter_characters_and_styles(
_speakers_to_characters(
[
speaker_talk_only,
speaker_singing_teacher_only,
speaker_frame_decode_only,
speaker_sing_only,
speaker_allstyle,
]
),
"singer",
)

Expand Down
8 changes: 5 additions & 3 deletions voicevox_engine/app/routers/morphing.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from voicevox_engine.core.core_initializer import CoreManager
from voicevox_engine.metas.Metas import StyleId
from voicevox_engine.metas.MetasStore import MetasStore
from voicevox_engine.metas.MetasStore import MetasStore, characters_to_speakers
from voicevox_engine.model import AudioQuery
from voicevox_engine.morphing.model import MorphableTargetInfo
from voicevox_engine.morphing.morphing import (
Expand Down Expand Up @@ -57,7 +57,8 @@ def morphable_targets(
version = core_version or core_manager.latest_version()
core = core_manager.get_core(version)

speakers = metas_store.load_combined_metas(core.characters)
characters = metas_store.load_combined_metas(core.characters)
speakers = characters_to_speakers(characters)
try:
morphable_targets = get_morphable_targets(speakers, base_style_ids)
except StyleIdNotFoundError as e:
Expand Down Expand Up @@ -97,7 +98,8 @@ def _synthesis_morphing(
core = core_manager.get_core(version)

# モーフィングが許可されないキャラクターペアを拒否する
speakers = metas_store.load_combined_metas(core.characters)
characters = metas_store.load_combined_metas(core.characters)
speakers = characters_to_speakers(characters)
try:
morphable = is_morphable(speakers, base_style_id, target_style_id)
except StyleIdNotFoundError as e:
Expand Down
14 changes: 7 additions & 7 deletions voicevox_engine/app/routers/speaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from voicevox_engine.core.core_initializer import CoreManager
from voicevox_engine.metas.Metas import Speaker, SpeakerInfo
from voicevox_engine.metas.MetasStore import MetasStore, filter_speakers_and_styles
from voicevox_engine.metas.MetasStore import MetasStore, filter_characters_and_styles


def b64encode_str(s: bytes) -> str:
Expand All @@ -29,8 +29,8 @@ def speakers(core_version: str | SkipJsonSchema[None] = None) -> list[Speaker]:
"""話者情報の一覧を取得します。"""
version = core_version or core_manager.latest_version()
core = core_manager.get_core(version)
speakers = metas_store.load_combined_metas(core.characters)
return filter_speakers_and_styles(speakers, "speaker")
characters = metas_store.load_combined_metas(core.characters)
return filter_characters_and_styles(characters, "speaker")

@router.get("/speaker_info")
def speaker_info(
Expand Down Expand Up @@ -79,8 +79,8 @@ def _speaker_info(

# 該当話者を検索する
core_characters = core_manager.get_core(version).characters
speakers = metas_store.load_combined_metas(core_characters)
speakers = filter_speakers_and_styles(speakers, speaker_or_singer)
characters = metas_store.load_combined_metas(core_characters)
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 @@ -143,8 +143,8 @@ def singers(core_version: str | SkipJsonSchema[None] = None) -> list[Speaker]:
"""歌手情報の一覧を取得します"""
version = core_version or core_manager.latest_version()
core = core_manager.get_core(version)
singers = metas_store.load_combined_metas(core.characters)
return filter_speakers_and_styles(singers, "singer")
characters = metas_store.load_combined_metas(core.characters)
return filter_characters_and_styles(characters, "singer")

@router.get("/singer_info")
def singer_info(
Expand Down
103 changes: 56 additions & 47 deletions voicevox_engine/metas/MetasStore.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,36 @@ def cast_styles(cores: list[CoreCharacterStyle]) -> list[SpeakerStyle]:
]


@dataclass
class Character:
"""キャラクター"""

name: str
uuid: str
talk_styles: list[SpeakerStyle]
sing_styles: list[SpeakerStyle]
version: str
supported_features: SpeakerSupportedFeatures


TALK_STYLE_TYPES: Final = ["talk"]
SING_STYLE_TYPES: Final = ["singing_teacher", "frame_decode", "sing"]


def characters_to_speakers(characters: list[Character]) -> list[Speaker]:
"""キャラクター配列を Speaker 配列へキャストする。"""
return [
Speaker(
name=character.name,
speaker_uuid=character.uuid,
styles=character.talk_styles + character.sing_styles,
version=character.version,
supported_features=character.supported_features,
)
for character in characters
]


class _EngineSpeaker(BaseModel):
"""
エンジンに含まれる話者情報
Expand Down Expand Up @@ -53,60 +83,39 @@ def __init__(self, engine_speakers_path: Path) -> None:
for folder in engine_speakers_path.iterdir()
}

def load_combined_metas(self, core_metas: list[CoreCharacter]) -> list[Speaker]:
def load_combined_metas(
self, core_characters: list[CoreCharacter]
) -> list[Character]:
"""コアとエンジンのメタ情報を統合する。"""
return [
Speaker(
supported_features=self._loaded_metas[
speaker_meta.speaker_uuid
].supported_features,
name=speaker_meta.name,
speaker_uuid=speaker_meta.speaker_uuid,
styles=cast_styles(speaker_meta.styles),
version=speaker_meta.version,
characters: list[Character] = []
for core_character in core_characters:
character_uuid = core_character.speaker_uuid
engine_character = self._loaded_metas[character_uuid]
styles = cast_styles(core_character.styles)
talk_styles = list(
filter(lambda style: style.type in TALK_STYLE_TYPES, styles)
)
for speaker_meta in core_metas
]


@dataclass
class Character:
"""キャラクター"""

name: str
uuid: str
talk_styles: list[SpeakerStyle]
sing_styles: list[SpeakerStyle]
version: str
supported_features: SpeakerSupportedFeatures


TALK_STYLE_TYPES: Final = ["talk"]
SING_STYLE_TYPES: Final = ["singing_teacher", "frame_decode", "sing"]
sing_styles = list(
filter(lambda style: style.type in SING_STYLE_TYPES, styles)
)
characters.append(
Character(
name=core_character.name,
uuid=character_uuid,
talk_styles=talk_styles,
sing_styles=sing_styles,
version=core_character.version,
supported_features=engine_character.supported_features,
)
)
return characters


def filter_speakers_and_styles(
speakers: list[Speaker],
def filter_characters_and_styles(
characters: list[Character],
speaker_or_singer: Literal["speaker", "singer"],
) -> list[Speaker]:
"""キャラクター内のスタイルをtalk系・sing系のみにする。スタイル数が0になったキャラクターは除外する。"""

characters = map(
lambda speaker: Character(
name=speaker.name,
uuid=speaker.speaker_uuid,
talk_styles=list(
filter(lambda style: style.type in TALK_STYLE_TYPES, speaker.styles)
),
sing_styles=list(
filter(lambda style: style.type in SING_STYLE_TYPES, speaker.styles)
),
version=speaker.version,
supported_features=speaker.supported_features,
),
speakers,
)

if speaker_or_singer == "speaker":
# talk 系スタイルを持たないキャラクターを除外する
talk_characters = filter(
Expand Down

0 comments on commit a8d4702

Please sign in to comment.