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

CancellableEngineが必要な引数だけを受け取るようにする #762

Merged
merged 24 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6aa539f
cancellable_engine.py: take typed arguments
aoirint Oct 9, 2023
328bdcb
run.py: fix cancellable engine initialization
aoirint Oct 9, 2023
3eb3cf4
run.py: type hint init_processes even if not enable_cancellable_synth…
aoirint Oct 9, 2023
ddae54e
root_dir: do not reparse voicevox_dir again
aoirint Oct 9, 2023
2755cce
root_dir: explicit type hint
aoirint Oct 9, 2023
0a41ab9
start_synthesis_subprocess: update docstring
aoirint Oct 9, 2023
421a919
Merge remote-tracking branch 'origin/master' into patch-cancellable_e…
aoirint Oct 9, 2023
0c4122b
run.py: add comment Cancellable Engine
aoirint Oct 9, 2023
7f17e69
run.py: add comment Synthesis Engine
aoirint Oct 9, 2023
80f0571
cancellable_engine.py: update type hint to python>=3.9 style
aoirint Oct 9, 2023
0e6faff
cancellable_engine.py: update type hint to python>=3.10 style
aoirint Oct 9, 2023
9037279
cancellable_engine.py: fix unmatched type hint on Windows: multiproce…
aoirint Oct 9, 2023
663014f
import _ConnectionBase as ConnectionBase
aoirint Oct 9, 2023
5b7297c
start_synthesis_subprocess: fix no-untyped-def
aoirint Oct 9, 2023
7c99b9a
root_dir: remove None assignment
aoirint Oct 9, 2023
f65e99b
root_dir: simple assignment
aoirint Oct 9, 2023
2bce3e5
add note
aoirint Oct 9, 2023
5088c9f
cancellable_engine.py: add docstring for new instance variables
aoirint Oct 9, 2023
c3a499a
format docstring
aoirint Oct 9, 2023
b4b6b3d
start_synthesis_subprocess docstring: enable_mock fallback
aoirint Oct 9, 2023
19e1ce2
cancellable_engine.py: procs_and_cons: add in-function type hint
aoirint Oct 9, 2023
01ff380
cancellable_engine.py conditional import from multiprocessing.connect…
aoirint Oct 9, 2023
fde9269
simplify docstring with redirection
aoirint Oct 9, 2023
9bba42d
CancellableEngine: remove class-side instance-var type hint
aoirint Oct 16, 2023
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
36 changes: 27 additions & 9 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -1286,26 +1286,44 @@ def main() -> None:
if args.output_log_utf8:
set_output_log_utf8()

cpu_num_threads: Optional[int] = args.cpu_num_threads
# Synthesis Engine
use_gpu: bool = args.use_gpu
voicevox_dir: Path | None = args.voicevox_dir
voicelib_dirs: list[Path] | None = args.voicelib_dir
runtime_dirs: list[Path] | None = args.runtime_dir
enable_mock: bool = args.enable_mock
cpu_num_threads: int | None = args.cpu_num_threads
load_all_models: bool = args.load_all_models

synthesis_engines = make_synthesis_engines(
use_gpu=args.use_gpu,
voicelib_dirs=args.voicelib_dir,
voicevox_dir=args.voicevox_dir,
runtime_dirs=args.runtime_dir,
use_gpu=use_gpu,
voicelib_dirs=voicelib_dirs,
voicevox_dir=voicevox_dir,
runtime_dirs=runtime_dirs,
cpu_num_threads=cpu_num_threads,
enable_mock=args.enable_mock,
load_all_models=args.load_all_models,
enable_mock=enable_mock,
load_all_models=load_all_models,
)
assert len(synthesis_engines) != 0, "音声合成エンジンがありません。"
latest_core_version = get_latest_core_version(versions=synthesis_engines.keys())

# Cancellable Engine
enable_cancellable_synthesis: bool = args.enable_cancellable_synthesis
init_processes: int = args.init_processes

cancellable_engine: CancellableEngine | None = None
if enable_cancellable_synthesis:
cancellable_engine = CancellableEngine(args)
cancellable_engine = CancellableEngine(
init_processes=init_processes,
use_gpu=use_gpu,
voicelib_dirs=voicelib_dirs,
voicevox_dir=voicevox_dir,
runtime_dirs=runtime_dirs,
cpu_num_threads=cpu_num_threads,
enable_mock=enable_mock,
)

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

Expand Down
103 changes: 67 additions & 36 deletions voicevox_engine/cancellable_engine.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import argparse
import asyncio
import queue
import sys
from multiprocessing import Pipe, Process
from multiprocessing.connection import Connection

if sys.platform == "win32":
from multiprocessing.connection import PipeConnection as ConnectionType
else:
from multiprocessing.connection import Connection as ConnectionType

from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import List, Optional, Tuple

import soundfile

Expand All @@ -22,52 +27,72 @@ class CancellableEngine:
初期化後は、synthesis関数で音声合成できる
(オリジナルと比べ引数が増えているので注意)

パラメータ use_gpu, voicelib_dirs, voicevox_dir,
runtime_dirs, cpu_num_threads, enable_mock は、 make_synthesis_engines を参照
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved

Attributes
----------
watch_con_list: List[Tuple[Request, Process]]
watch_con_list: list[tuple[Request, Process]]
Requestは接続の監視に使用され、Processは通信切断時のプロセスキルに使用される
クライアントから接続があるとListにTupleが追加される
接続が切断、もしくは音声合成が終了すると削除される
procs_and_cons: queue.Queue[Tuple[Process, Connection]]
procs_and_cons: queue.Queue[tuple[Process, ConnectionType]]
音声合成の準備が終わっているプロセスのList
(音声合成中のプロセスは入っていない)
"""

def __init__(self, args: argparse.Namespace) -> None:
def __init__(
self,
init_processes: int,
use_gpu: bool,
voicelib_dirs: list[Path] | None,
voicevox_dir: Path | None,
runtime_dirs: list[Path] | None,
cpu_num_threads: int | None,
enable_mock: bool,
) -> None:
"""
変数の初期化を行う
また、args.init_processesの数だけプロセスを起動し、procs_and_consに格納する
また、init_processesの数だけプロセスを起動し、procs_and_consに格納する
"""
self.args = args
if not self.args.enable_cancellable_synthesis:
raise HTTPException(
status_code=404,
detail="実験的機能はデフォルトで無効になっています。使用するには引数を指定してください。",
)

self.watch_con_list: List[Tuple[Request, Process]] = []
self.procs_and_cons: queue.Queue[Tuple[Process, Connection]] = queue.Queue()
for _ in range(self.args.init_processes):
self.procs_and_cons.put(self.start_new_proc())

self.use_gpu = use_gpu
self.voicelib_dirs = voicelib_dirs
self.voicevox_dir = voicevox_dir
self.runtime_dirs = runtime_dirs
self.cpu_num_threads = cpu_num_threads
self.enable_mock = enable_mock

self.watch_con_list: list[tuple[Request, Process]] = []

procs_and_cons: queue.Queue[tuple[Process, ConnectionType]] = queue.Queue()
for _ in range(init_processes):
procs_and_cons.put(self.start_new_proc())
self.procs_and_cons = procs_and_cons

def start_new_proc(
self,
) -> Tuple[Process, Connection]:
) -> tuple[Process, ConnectionType]:
"""
新しく開始したプロセスを返す関数

Returns
-------
ret_proc: Process
新規のプロセス
sub_proc_con1: Connection
sub_proc_con1: ConnectionType
ret_procのプロセスと通信するためのPipe
"""
sub_proc_con1, sub_proc_con2 = Pipe(True)
ret_proc = Process(
target=start_synthesis_subprocess,
kwargs={
"args": self.args,
"use_gpu": self.use_gpu,
"voicelib_dirs": self.voicelib_dirs,
"voicevox_dir": self.voicevox_dir,
"runtime_dirs": self.runtime_dirs,
"cpu_num_threads": self.cpu_num_threads,
"enable_mock": self.enable_mock,
"sub_proc_con": sub_proc_con2,
},
daemon=True,
Expand All @@ -79,7 +104,7 @@ def finalize_con(
self,
req: Request,
proc: Process,
sub_proc_con: Optional[Connection],
sub_proc_con: ConnectionType | None,
) -> None:
"""
接続が切断された時の処理を行う関数
Expand All @@ -94,7 +119,7 @@ def finalize_con(
https://fastapi.tiangolo.com/advanced/using-request-directly/
proc: Process
音声合成を行っていたプロセス
sub_proc_con: Connection, optional
sub_proc_con: ConnectionType, optional
音声合成を行っていたプロセスとのPipe
指定されていない場合、プロセスは再利用されず終了される
"""
Expand All @@ -117,7 +142,7 @@ def _synthesis_impl(
query: AudioQuery,
speaker_id: int,
request: Request,
core_version: Optional[str],
core_version: str | None,
) -> str:
"""
音声合成を行う関数
Expand Down Expand Up @@ -173,28 +198,34 @@ async def catch_disconnection(self):


def start_synthesis_subprocess(
args: argparse.Namespace,
sub_proc_con: Connection,
):
use_gpu: bool,
voicelib_dirs: list[Path] | None,
voicevox_dir: Path | None,
runtime_dirs: list[Path] | None,
cpu_num_threads: int | None,
enable_mock: bool,
sub_proc_con: ConnectionType,
) -> None:
"""
音声合成を行うサブプロセスで行うための関数
pickle化の関係でグローバルに書いている

引数 use_gpu, voicelib_dirs, voicevox_dir,
runtime_dirs, cpu_num_threads, enable_mock は、 make_synthesis_engines を参照

Parameters
----------
args: argparse.Namespace
起動時に作られたものをそのまま渡す
sub_proc_con: Connection
sub_proc_con: ConnectionType
メインプロセスと通信するためのPipe
"""

synthesis_engines = make_synthesis_engines(
use_gpu=args.use_gpu,
voicelib_dirs=args.voicelib_dir,
voicevox_dir=args.voicevox_dir,
runtime_dirs=args.runtime_dir,
cpu_num_threads=args.cpu_num_threads,
enable_mock=args.enable_mock,
use_gpu=use_gpu,
voicelib_dirs=voicelib_dirs,
voicevox_dir=voicevox_dir,
runtime_dirs=runtime_dirs,
cpu_num_threads=cpu_num_threads,
enable_mock=enable_mock,
)
assert len(synthesis_engines) != 0, "音声合成エンジンがありません。"
latest_core_version = get_latest_core_version(versions=synthesis_engines.keys())
Expand Down