Skip to content

Commit

Permalink
Refactor: FastAPI によって自動生成される API ドキュメントの整理
Browse files Browse the repository at this point in the history
「その他」に分類される API エンドポイントがあまりに多すぎたほか、サマリーのない API も多かったため、API ドキュメント上で見栄えよく重要な API をすぐ把握できるよう改良した
  • Loading branch information
tsukumijima committed Nov 25, 2024
1 parent f4697c0 commit 96ea82d
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 38 deletions.
8 changes: 4 additions & 4 deletions voicevox_engine/app/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,23 @@ def _get_core_characters(version: str | None) -> list[CoreCharacter]:
generate_tts_pipeline_router(tts_engines, preset_manager, cancellable_engine)
)
app.include_router(generate_morphing_router(tts_engines, aivm_manager))
app.include_router(
generate_preset_router(preset_manager, verify_mutability_allowed)
)
app.include_router(generate_character_router(resource_manager, aivm_manager))
if engine_manifest.supported_features.manage_library:
app.include_router(
generate_library_router(library_manager, verify_mutability_allowed)
)
# generate_aivm_models_router() は AivisSpeech Engine 独自追加ルーター
app.include_router(generate_aivm_models_router(aivm_manager, verify_mutability_allowed)) # noqa # fmt: skip
app.include_router(
generate_preset_router(preset_manager, verify_mutability_allowed)
)
app.include_router(generate_user_dict_router(user_dict, verify_mutability_allowed))
app.include_router(generate_engine_info_router(core_version_list, engine_manifest))
app.include_router(
generate_setting_router(
setting_loader, engine_manifest.brand_name, verify_mutability_allowed
)
)
app.include_router(generate_engine_info_router(core_version_list, engine_manifest))
app.include_router(generate_portal_page_router(engine_manifest.name))

app = configure_openapi_schema(
Expand Down
9 changes: 7 additions & 2 deletions voicevox_engine/app/routers/aivm_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ def generate_aivm_models_router(

@router.get(
"",
response_description="インストールした音声合成モデルの情報",
summary="インストール済みのすべての音声合成モデルの情報を取得する",
response_description="インストール済みのすべての音声合成モデルの情報",
)
def get_installed_aivm_infos() -> dict[str, AivmInfo]:
"""
インストールした音声合成モデルの情報を返します
インストール済みのすべての音声合成モデルの情報を返します
"""

return aivm_manager.get_installed_aivm_infos()
Expand All @@ -36,6 +37,7 @@ def get_installed_aivm_infos() -> dict[str, AivmInfo]:
"/install",
status_code=204,
dependencies=[Depends(verify_mutability)],
summary="音声合成モデルをインストールする",
)
def install_aivm(
file: Annotated[
Expand Down Expand Up @@ -65,6 +67,8 @@ def install_aivm(

@router.get(
"/{aivm_uuid}",
summary="指定された音声合成モデルの情報を取得する",
response_description="指定された音声合成モデルの情報",
)
def get_aivm_info(
aivm_uuid: Annotated[str, Path(description="音声合成モデルの UUID")]
Expand All @@ -79,6 +83,7 @@ def get_aivm_info(
"/{aivm_uuid}/uninstall",
status_code=204,
dependencies=[Depends(verify_mutability)],
summary="音声合成モデルをアンインストールする",
)
def uninstall_aivm(
aivm_uuid: Annotated[str, Path(description="音声合成モデルの UUID")]
Expand Down
18 changes: 12 additions & 6 deletions voicevox_engine/app/routers/character.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,30 @@ def generate_character_router(
aivm_manager: AivmManager,
) -> APIRouter:
"""キャラクター情報 API Router を生成する"""
router = APIRouter(tags=["その他"])
router = APIRouter(tags=["話者情報"])

@router.get("/speakers")
@router.get(
"/speakers",
summary="話者情報の一覧を取得する",
)
def speakers(
core_version: Annotated[
str | SkipJsonSchema[None],
Query(description="AivisSpeech Engine ではサポートされていないパラメータです (常に無視されます) 。"),
] = None, # fmt: skip # noqa
) -> list[Speaker]:
"""喋れるキャラクターの情報の一覧を返します。"""
"""話者情報の一覧を返します。"""
# AivisSpeech Engine では常に AivmManager から Speaker を取得する
return aivm_manager.get_speakers()
"""
characters = metas_store.talk_characters(core_version)
return _characters_to_speakers(characters)
"""

@router.get("/speaker_info")
@router.get(
"/speaker_info",
summary="UUID で指定された話者の情報を取得する",
)
def speaker_info(
resource_baseurl: Annotated[str, Depends(_get_resource_baseurl)],
speaker_uuid: str,
Expand All @@ -67,8 +73,8 @@ def speaker_info(
] = None, # fmt: skip # noqa
) -> SpeakerInfo:
"""
UUID で指定された喋れるキャラクターの情報を返します
画像や音声はresource_formatで指定した形式で返されます
UUID で指定された話者の情報を返します
画像や音声は resource_format で指定した形式で返されます
"""
# AivisSpeech Engine では常に AivmManager から SpeakerInfo を取得する
return aivm_manager.get_speaker_info(speaker_uuid)
Expand Down
14 changes: 7 additions & 7 deletions voicevox_engine/app/routers/morphing.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ def morphable_targets(
] = None, # fmt: skip # noqa
) -> list[dict[str, MorphableTargetInfo]]:
"""
指定されたベーススタイルに対してエンジン内の各キャラクターがモーフィング機能を利用可能か返します。
モーフィングの許可/禁止は `/speakers `の `speaker.supported_features.synthesis_morphing` に記載されています。
プロパティが存在しない場合は、モーフィングが許可されているとみなします。
返り値のスタイル ID は string 型なので注意。
指定されたベーススタイルに対してエンジン内の各キャラクターがモーフィング機能を利用可能か返します。<br>
モーフィングの許可/禁止は `/speakers `の `speaker.supported_features.synthesis_morphing` に記載されています。<br>
プロパティが存在しない場合は、モーフィングが許可されているとみなします。<br>
返り値のスタイル ID は string 型なので注意。<br>
AivisSpeech Engine では話者ごとに発声タイミングが異なる関係で実装不可能なため (動作こそするが聴くに耐えない) 、
全ての話者でモーフィングが禁止されています。
"""
""" # noqa
characters = aivm_manager.get_characters()
try:
morphable_targets = get_morphable_targets(characters, base_style_ids)
Expand Down Expand Up @@ -93,8 +93,8 @@ def _synthesis_morphing(
] = None, # fmt: skip # noqa
) -> FileResponse:
"""
指定された 2 種類のスタイルで音声を合成、指定した割合でモーフィングした音声を得ます。
モーフィングの割合は `morph_rate` で指定でき、0.0 でベースのスタイル、1.0 でターゲットのスタイルに近づきます。
指定された 2 種類のスタイルで音声を合成、指定した割合でモーフィングした音声を得ます。<br>
モーフィングの割合は `morph_rate` で指定でき、0.0 でベースのスタイル、1.0 でターゲットのスタイルに近づきます。<br>
AivisSpeech Engine では話者ごとに発声タイミングが異なる関係で実装不可能なため (動作こそするが聴くに耐えない) 、
常に 400 Bad Request を返します。
"""
Expand Down
14 changes: 9 additions & 5 deletions voicevox_engine/app/routers/preset.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ def generate_preset_router(
preset_manager: PresetManager, verify_mutability: VerifyMutabilityAllowed
) -> APIRouter:
"""プリセット API Router を生成する"""
router = APIRouter(tags=["その他"])
router = APIRouter(tags=["プリセット"])

@router.get(
"/presets",
summary="エンジンが保持しているプリセットの設定を取得する",
response_description="プリセットのリスト",
)
def get_presets() -> list[Preset]:
"""
エンジンが保持しているプリセットの設定を返します
エンジンが保持しているプリセットの設定を返します
"""
try:
presets = preset_manager.load_presets()
Expand All @@ -38,6 +39,7 @@ def get_presets() -> list[Preset]:

@router.post(
"/add_preset",
summary="新しいプリセットを追加する",
response_description="追加したプリセットのプリセットID",
dependencies=[Depends(verify_mutability)],
)
Expand All @@ -50,7 +52,7 @@ def add_preset(
]
) -> int:
"""
新しいプリセットを追加します
新しいプリセットを追加します
"""
try:
id = preset_manager.add_preset(preset)
Expand All @@ -62,6 +64,7 @@ def add_preset(

@router.post(
"/update_preset",
summary="既存のプリセットを更新する",
response_description="更新したプリセットのプリセットID",
dependencies=[Depends(verify_mutability)],
)
Expand All @@ -74,7 +77,7 @@ def update_preset(
]
) -> int:
"""
既存のプリセットを更新します
既存のプリセットを更新します
"""
try:
id = preset_manager.update_preset(preset)
Expand All @@ -86,14 +89,15 @@ def update_preset(

@router.post(
"/delete_preset",
summary="既存のプリセットを削除する",
status_code=204,
dependencies=[Depends(verify_mutability)],
)
def delete_preset(
id: Annotated[int, Query(description="削除するプリセットのプリセットID")]
) -> None:
"""
既存のプリセットを削除します
既存のプリセットを削除します
"""
try:
preset_manager.delete_preset(id)
Expand Down
48 changes: 35 additions & 13 deletions voicevox_engine/app/routers/tts_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def accent_phrases(
@router.post(
"/mora_data",
tags=["クエリ編集"],
summary="アクセント句から音高・音素長を得る",
summary="アクセント句から音高・音素長を得る (AivisSpeech Engine では常にダミーの値が返されます)",
)
def mora_data(
accent_phrases: list[AccentPhrase],
Expand All @@ -230,7 +230,7 @@ def mora_data(
@router.post(
"/mora_length",
tags=["クエリ編集"],
summary="アクセント句から音素長を得る",
summary="アクセント句から音素長を得る (AivisSpeech Engine では常にダミーの値が返されます)",
)
def mora_length(
accent_phrases: list[AccentPhrase],
Expand All @@ -247,7 +247,7 @@ def mora_length(
@router.post(
"/mora_pitch",
tags=["クエリ編集"],
summary="アクセント句から音高を得る",
summary="アクセント句から音高を得る (AivisSpeech Engine では常にダミーの値が返されます)",
)
def mora_pitch(
accent_phrases: list[AccentPhrase],
Expand Down Expand Up @@ -286,6 +286,9 @@ def synthesis(
Query(description="AivisSpeech Engine ではサポートされていないパラメータです (常に無視されます) 。"),
] = None, # fmt: skip # noqa
) -> FileResponse:
"""
指定されたスタイル ID に紐づく音声合成モデルを用いて音声合成を行います。
"""
version = core_version or LATEST_VERSION
engine = tts_engines.get_engine(version)
wave = engine.synthesize_wave(
Expand Down Expand Up @@ -536,7 +539,7 @@ def frame_synthesis(
},
}
},
tags=["その他"],
tags=["音声合成"],
summary="base64エンコードされた複数のwavデータを一つに結合する",
)
def connect_waves(waves: list[str]) -> FileResponse:
Expand Down Expand Up @@ -564,7 +567,7 @@ def connect_waves(waves: list[str]) -> FileResponse:

@router.post(
"/validate_kana",
tags=["その他"],
tags=["クエリ作成"],
summary="テキストが AquesTalk 風記法に従っているか判定する",
responses={
400: {
Expand All @@ -589,13 +592,18 @@ async def validate_kana(
detail=ParseKanaBadRequest(err).model_dump(),
)

@router.post("/initialize_speaker", status_code=204, tags=["その他"])
@router.post(
"/initialize_speaker",
status_code=204,
tags=["音声合成モデル管理"],
summary="指定されたスタイル ID に紐づく音声合成モデルをロードする",
)
def initialize_speaker(
style_id: Annotated[StyleId, Query(alias="speaker")],
skip_reinit: Annotated[
bool,
Query(
description="既に初期化済みのスタイルの再初期化をスキップするかどうか"
description="既にロード済みの音声合成モデルの再ロードをスキップするかどうか"
),
] = False,
core_version: Annotated[
Expand All @@ -604,14 +612,18 @@ def initialize_speaker(
] = None, # fmt: skip # noqa
) -> None:
"""
指定されたスタイルを初期化します
実行しなくても他のAPIは使用できますが、初回実行時に時間がかかることがあります。
指定されたスタイル ID に紐づく音声合成モデルをロードします
実行しなくても他の API は使用できますが、初回実行時に時間がかかることがあります。
"""
version = core_version or LATEST_VERSION
engine = tts_engines.get_engine(version)
engine.initialize_synthesis(style_id, skip_reinit=skip_reinit)

@router.get("/is_initialized_speaker", tags=["その他"])
@router.get(
"/is_initialized_speaker",
tags=["音声合成モデル管理"],
summary="指定されたスタイル ID に紐づく音声合成モデルがロードされているかを確認する",
)
def is_initialized_speaker(
style_id: Annotated[StyleId, Query(alias="speaker")],
core_version: Annotated[
Expand All @@ -620,20 +632,30 @@ def is_initialized_speaker(
] = None, # fmt: skip # noqa
) -> bool:
"""
指定されたスタイルが初期化されているかどうかを返します
指定されたスタイル ID に紐づく音声合成モデルがロードされているかどうかを返します
"""
version = core_version or LATEST_VERSION
engine = tts_engines.get_engine(version)
return engine.is_synthesis_initialized(style_id)

@router.get("/supported_devices", tags=["その他"])
@router.get(
"/supported_devices",
tags=["音声合成モデル管理"],
summary="このビルドでサポートされている、音声合成モデルの推論デバイスを取得する",
)
def supported_devices(
core_version: Annotated[
str | SkipJsonSchema[None],
Query(description="AivisSpeech Engine ではサポートされていないパラメータです (常に無視されます) 。"),
] = None, # fmt: skip # noqa
) -> SupportedDevicesInfo:
"""対応デバイスの一覧を取得します。"""
"""
このビルドでサポートされている、音声合成モデルの推論デバイスを返します。<br>
通常、下記の値が返されます。true であっても実際に推論デバイスが利用可能とは限りません。
- Windows: `{"cpu": true, "cuda": false, "dml": true}`
- macOS: `{"cpu": true, "cuda": false, "dml": false}`
- Linux: `{"cpu": true, "cuda": true, "dml": false}`
"""
version = core_version or LATEST_VERSION
supported_devices = tts_engines.get_engine(version).supported_devices
if supported_devices is None:
Expand Down
11 changes: 10 additions & 1 deletion voicevox_engine/app/routers/user_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def generate_user_dict_router(

@router.get(
"/user_dict",
summary="ユーザー辞書に登録されている単語の一覧を取得する",
response_description="単語のUUIDとその詳細",
)
def get_user_dict_words() -> dict[str, UserDictWord]:
Expand All @@ -42,7 +43,12 @@ def get_user_dict_words() -> dict[str, UserDictWord]:
status_code=500, detail="辞書の読み込みに失敗しました。"
)

@router.post("/user_dict_word", dependencies=[Depends(verify_mutability)])
@router.post(
"/user_dict_word",
dependencies=[Depends(verify_mutability)],
summary="ユーザー辞書に言葉を追加する",
response_description="追加した言葉のUUID",
)
def add_user_dict_word(
surface: Annotated[str, Query(description="言葉の表層形")],
pronunciation: Annotated[str, Query(description="言葉の発音(カタカナ)")],
Expand Down Expand Up @@ -100,6 +106,7 @@ def add_user_dict_word(
"/user_dict_word/{word_uuid}",
status_code=204,
dependencies=[Depends(verify_mutability)],
summary="ユーザー辞書に登録されている言葉を更新する",
)
def rewrite_user_dict_word(
surface: Annotated[str, Query(description="言葉の表層形")],
Expand Down Expand Up @@ -159,6 +166,7 @@ def rewrite_user_dict_word(
"/user_dict_word/{word_uuid}",
status_code=204,
dependencies=[Depends(verify_mutability)],
summary="ユーザー辞書に登録されている言葉を削除する",
)
def delete_user_dict_word(
word_uuid: Annotated[str, Path(description="削除する言葉のUUID")]
Expand All @@ -179,6 +187,7 @@ def delete_user_dict_word(
"/import_user_dict",
status_code=204,
dependencies=[Depends(verify_mutability)],
summary="他のユーザー辞書をインポートする",
)
def import_user_dict_words(
import_dict_data: Annotated[
Expand Down

0 comments on commit 96ea82d

Please sign in to comment.