Improve: remove Gradio dependency from style_bert_vits2 as a library
This commit is contained in:
@@ -25,7 +25,6 @@ dependencies = [
|
|||||||
'cmudict',
|
'cmudict',
|
||||||
'cn2an',
|
'cn2an',
|
||||||
'g2p_en',
|
'g2p_en',
|
||||||
'gradio',
|
|
||||||
'jieba',
|
'jieba',
|
||||||
'librosa==0.9.2',
|
'librosa==0.9.2',
|
||||||
'loguru',
|
'loguru',
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import warnings
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Optional, Union
|
from typing import TYPE_CHECKING, Any, Optional, Union
|
||||||
|
|
||||||
import gradio as gr
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyannote.audio
|
import pyannote.audio
|
||||||
import torch
|
import torch
|
||||||
from gradio.processing_utils import convert_to_16_bit_wav
|
|
||||||
from numpy.typing import NDArray
|
from numpy.typing import NDArray
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@@ -32,6 +29,13 @@ from style_bert_vits2.models.models_jp_extra import (
|
|||||||
from style_bert_vits2.voice import adjust_voice
|
from style_bert_vits2.voice import adjust_voice
|
||||||
|
|
||||||
|
|
||||||
|
# Gradio の import は重いため、ここでは型チェック時のみ import する
|
||||||
|
# ライブラリとしての利用を考慮し、TTSModelHolder の _for_gradio() 系メソッド以外では Gradio に依存しないようにする
|
||||||
|
# _for_gradio() 系メソッドの戻り値の型アノテーションを文字列としているのは、Gradio なしで実行できるようにするため
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
import gradio as gr
|
||||||
|
|
||||||
|
|
||||||
class TTSModel:
|
class TTSModel:
|
||||||
"""
|
"""
|
||||||
Style-Bert-Vits2 の音声合成モデルを操作するクラス。
|
Style-Bert-Vits2 の音声合成モデルを操作するクラス。
|
||||||
@@ -137,6 +141,43 @@ class TTSModel:
|
|||||||
xvec = mean + (xvec - mean) * weight
|
xvec = mean + (xvec - mean) * weight
|
||||||
return xvec
|
return xvec
|
||||||
|
|
||||||
|
def __convert_to_16_bit_wav(self, data: NDArray[Any]) -> NDArray[Any]:
|
||||||
|
"""
|
||||||
|
音声データを 16-bit int 形式に変換する。
|
||||||
|
gradio.processing_utils.convert_to_16_bit_wav() を移植したもの。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (NDArray[Any]): 音声データ
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
NDArray[Any]: 16-bit int 形式の音声データ
|
||||||
|
"""
|
||||||
|
# Based on: https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.wavfile.write.html
|
||||||
|
if data.dtype in [np.float64, np.float32, np.float16]: # type: ignore
|
||||||
|
data = data / np.abs(data).max()
|
||||||
|
data = data * 32767
|
||||||
|
data = data.astype(np.int16)
|
||||||
|
elif data.dtype == np.int32:
|
||||||
|
data = data / 65536
|
||||||
|
data = data.astype(np.int16)
|
||||||
|
elif data.dtype == np.int16:
|
||||||
|
pass
|
||||||
|
elif data.dtype == np.uint16:
|
||||||
|
data = data - 32768
|
||||||
|
data = data.astype(np.int16)
|
||||||
|
elif data.dtype == np.uint8:
|
||||||
|
data = data * 257 - 32768
|
||||||
|
data = data.astype(np.int16)
|
||||||
|
elif data.dtype == np.int8:
|
||||||
|
data = data * 256
|
||||||
|
data = data.astype(np.int16)
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
"Audio data cannot be converted automatically from "
|
||||||
|
f"{data.dtype} to 16-bit int format."
|
||||||
|
)
|
||||||
|
return data
|
||||||
|
|
||||||
def infer(
|
def infer(
|
||||||
self,
|
self,
|
||||||
text: str,
|
text: str,
|
||||||
@@ -260,9 +301,7 @@ class TTSModel:
|
|||||||
pitch_scale=pitch_scale,
|
pitch_scale=pitch_scale,
|
||||||
intonation_scale=intonation_scale,
|
intonation_scale=intonation_scale,
|
||||||
)
|
)
|
||||||
with warnings.catch_warnings():
|
audio = self.__convert_to_16_bit_wav(audio)
|
||||||
warnings.simplefilter("ignore")
|
|
||||||
audio = convert_to_16_bit_wav(audio)
|
|
||||||
return (self.hyper_parameters.data.sampling_rate, audio)
|
return (self.hyper_parameters.data.sampling_rate, audio)
|
||||||
|
|
||||||
|
|
||||||
@@ -381,7 +420,9 @@ class TTSModelHolder:
|
|||||||
|
|
||||||
def get_model_for_gradio(
|
def get_model_for_gradio(
|
||||||
self, model_name: str, model_path_str: str
|
self, model_name: str, model_path_str: str
|
||||||
) -> tuple[gr.Dropdown, gr.Button, gr.Dropdown]:
|
) -> tuple["gr.Dropdown", "gr.Button", "gr.Dropdown"]:
|
||||||
|
import gradio as gr
|
||||||
|
|
||||||
model_path = Path(model_path_str)
|
model_path = Path(model_path_str)
|
||||||
if model_name not in self.model_files_dict:
|
if model_name not in self.model_files_dict:
|
||||||
raise ValueError(f"Model `{model_name}` is not found")
|
raise ValueError(f"Model `{model_name}` is not found")
|
||||||
@@ -413,13 +454,17 @@ class TTSModelHolder:
|
|||||||
gr.Dropdown(choices=speakers, value=speakers[0]), # type: ignore
|
gr.Dropdown(choices=speakers, value=speakers[0]), # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_model_files_for_gradio(self, model_name: str) -> gr.Dropdown:
|
def update_model_files_for_gradio(self, model_name: str) -> "gr.Dropdown":
|
||||||
|
import gradio as gr
|
||||||
|
|
||||||
model_files = self.model_files_dict[model_name]
|
model_files = self.model_files_dict[model_name]
|
||||||
return gr.Dropdown(choices=model_files, value=model_files[0]) # type: ignore
|
return gr.Dropdown(choices=model_files, value=model_files[0]) # type: ignore
|
||||||
|
|
||||||
def update_model_names_for_gradio(
|
def update_model_names_for_gradio(
|
||||||
self,
|
self,
|
||||||
) -> tuple[gr.Dropdown, gr.Dropdown, gr.Button]:
|
) -> tuple["gr.Dropdown", "gr.Dropdown", "gr.Button"]:
|
||||||
|
import gradio as gr
|
||||||
|
|
||||||
self.refresh()
|
self.refresh()
|
||||||
initial_model_name = self.model_names[0]
|
initial_model_name = self.model_names[0]
|
||||||
initial_model_files = self.model_files_dict[initial_model_name]
|
initial_model_files = self.model_files_dict[initial_model_name]
|
||||||
|
|||||||
Reference in New Issue
Block a user