Skip to content

Commit

Permalink
整理: サーバ初期設定と立ち上げの見通し改善 (#1198)
Browse files Browse the repository at this point in the history
* refactor: サーバ生成手順を明確化

* refactor: 型表記と設定値優先度を単純化

* refactor: ASGI 準拠の明確化

* refactor: not None 値代入を util 関数で統一

* refactor: None 判定を安全側に統一

* fix: lint

* refactor: 優先度解説を集約、ルートパス指定を共通化

* fix: typo

Co-authored-by: Hiroshiba <[email protected]>

* fix: typo

Co-authored-by: Hiroshiba <[email protected]>

* add: サーバー起動に関する NOTE

Co-authored-by: Hiroshiba <[email protected]>

* fix: エラー関連の日本語記述を改善

* fix: 優先度表記を一般化

---------

Co-authored-by: Hiroshiba <[email protected]>
  • Loading branch information
tarepan and Hiroshiba authored May 6, 2024
1 parent 2c78642 commit 0a6ed99
Showing 1 changed file with 77 additions and 52 deletions.
129 changes: 77 additions & 52 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from contextlib import asynccontextmanager
from io import TextIOWrapper
from pathlib import Path
from typing import Optional
from typing import TypeVar

import uvicorn
from fastapi import FastAPI, HTTPException
Expand Down Expand Up @@ -82,11 +82,12 @@ def generate_app(
setting_loader: SettingHandler,
preset_manager: PresetManager,
cancellable_engine: CancellableEngine | None = None,
root_dir: Optional[Path] = None,
root_dir: Path | None = None,
cors_policy_mode: CorsPolicyMode = CorsPolicyMode.localapps,
allow_origin: Optional[list[str]] = None,
allow_origin: list[str] | None = None,
disable_mutable_api: bool = False,
) -> FastAPI:
"""ASGI 'application' 仕様に準拠した VOICEVOX ENGINE アプリケーションインスタンスを生成する。"""
if root_dir is None:
root_dir = engine_root()

Expand Down Expand Up @@ -119,14 +120,14 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:

metas_store = MetasStore(root_dir / "speaker_info")

def get_engine(core_version: Optional[str]) -> TTSEngine:
def get_engine(core_version: str | None) -> TTSEngine:
if core_version is None:
return tts_engines[latest_core_version]
if core_version in tts_engines:
return tts_engines[core_version]
raise HTTPException(status_code=422, detail="不明なバージョンです")

def get_core(core_version: Optional[str]) -> CoreAdapter:
def get_core(core_version: str | None) -> CoreAdapter:
"""指定したバージョンのコアを取得する"""
if core_version is None:
return cores[latest_core_version]
Expand Down Expand Up @@ -176,6 +177,28 @@ async def get_portal() -> str:
return app


T = TypeVar("T")


def select_first_not_none(candidates: list[T | None]) -> T:
"""None でない最初の値を取り出す。全て None の場合はエラーを送出する。"""
for candidate in candidates:
if candidate is not None:
return candidate
raise RuntimeError("すべての候補値が None です")


S = TypeVar("S")


def select_first_not_none_or_none(candidates: list[S | None]) -> S | None:
"""None でない最初の値を取り出そうとし、全て None の場合は None を返す。"""
for candidate in candidates:
if candidate is not None:
return candidate
return None


def main() -> None:
multiprocessing.freeze_support()

Expand Down Expand Up @@ -315,6 +338,12 @@ def main() -> None:

args = parser.parse_args()

# NOTE: 型検査のため Any 値に対して明示的に型を付ける
arg_cors_policy_mode: CorsPolicyMode | None = args.cors_policy_mode
arg_allow_origin: list[str] | None = args.allow_origin
arg_preset_path: Path | None = args.preset_file
arg_disable_mutable_api: bool = args.disable_mutable_api

if args.output_log_utf8:
set_output_log_utf8()

Expand Down Expand Up @@ -356,62 +385,58 @@ def main() -> None:
enable_mock=enable_mock,
)

root_dir: Path | None = voicevox_dir
if root_dir is None:
root_dir = engine_root()

setting_loader = SettingHandler(args.setting_file)

settings = setting_loader.load()

cors_policy_mode: CorsPolicyMode | None = args.cors_policy_mode
if cors_policy_mode is None:
cors_policy_mode = settings.cors_policy_mode

allow_origin = None
if args.allow_origin is not None:
allow_origin = args.allow_origin
elif settings.allow_origin is not None:
allow_origin = settings.allow_origin.split(" ")

# Preset Manager
# preset_pathの優先順: 引数、環境変数、voicevox_dir、実行ファイルのディレクトリ
# ファイルの存在に関わらず、優先順で最初に指定されたパスをプリセットファイルとして使用する
preset_path: Path | None = args.preset_file
if preset_path is None:
# 引数 --preset_file の指定がない場合
env_preset_path = os.getenv("VV_PRESET_FILE")
if env_preset_path is not None and len(env_preset_path) != 0:
# 環境変数 VV_PRESET_FILE の指定がある場合
preset_path = Path(env_preset_path)
else:
# 環境変数 VV_PRESET_FILE の指定がない場合
preset_path = root_dir / "presets.yaml"
# 複数方式で指定可能な場合、優先度は上から「引数」「環境変数」「設定ファイル」「デフォルト値」

preset_manager = PresetManager(
preset_path=preset_path,
root_dir = select_first_not_none([voicevox_dir, engine_root()])

cors_policy_mode = select_first_not_none(
[arg_cors_policy_mode, settings.cors_policy_mode]
)

disable_mutable_api: bool = args.disable_mutable_api | decide_boolean_from_env(
"VV_DISABLE_MUTABLE_API"
setting_allow_origin = None
if settings.allow_origin is not None:
setting_allow_origin = settings.allow_origin.split(" ")
allow_origin = select_first_not_none_or_none(
[arg_allow_origin, setting_allow_origin]
)

uvicorn.run(
generate_app(
tts_engines,
cores,
latest_core_version,
setting_loader,
preset_manager=preset_manager,
cancellable_engine=cancellable_engine,
root_dir=root_dir,
cors_policy_mode=cors_policy_mode,
allow_origin=allow_origin,
disable_mutable_api=disable_mutable_api,
),
host=args.host,
port=args.port,
env_preset_path_str = os.getenv("VV_PRESET_FILE")
if env_preset_path_str is not None and len(env_preset_path_str) != 0:
env_preset_path = Path(env_preset_path_str)
else:
env_preset_path = None
root_preset_path = root_dir / "presets.yaml"
preset_path = select_first_not_none(
[arg_preset_path, env_preset_path, root_preset_path]
)
# ファイルの存在に関わらず指定されたパスをプリセットファイルとして使用する
preset_manager = PresetManager(preset_path)

if arg_disable_mutable_api:
disable_mutable_api = True
else:
disable_mutable_api = decide_boolean_from_env("VV_DISABLE_MUTABLE_API")

# ASGI に準拠した VOICEVOX ENGINE アプリケーションを生成する
app = generate_app(
tts_engines,
cores,
latest_core_version,
setting_loader,
preset_manager,
cancellable_engine,
root_dir,
cors_policy_mode,
allow_origin,
disable_mutable_api=disable_mutable_api,
)

# VOICEVOX ENGINE サーバーを起動
# NOTE: デフォルトは ASGI に準拠した HTTP/1.1 サーバー
uvicorn.run(app, host=args.host, port=args.port)


if __name__ == "__main__":
Expand Down

0 comments on commit 0a6ed99

Please sign in to comment.