2023-05-03 16:36:59 +03:00
|
|
|
from concurrent.futures import ThreadPoolExecutor
|
2023-01-28 05:51:56 +03:00
|
|
|
import sys
|
2022-12-31 10:02:53 +03:00
|
|
|
|
|
|
|
from distutils.util import strtobool
|
2023-01-28 09:07:54 +03:00
|
|
|
from datetime import datetime
|
|
|
|
import socket
|
|
|
|
import platform
|
|
|
|
import os
|
|
|
|
import argparse
|
2023-05-17 20:51:40 +03:00
|
|
|
from Downloader import download, download_no_tqdm
|
|
|
|
from voice_changer.RVC.SampleDownloader import (
|
|
|
|
checkRvcModelExist,
|
|
|
|
downloadInitialSampleModels,
|
|
|
|
)
|
2023-05-03 16:36:59 +03:00
|
|
|
|
2023-04-27 17:38:25 +03:00
|
|
|
from voice_changer.utils.VoiceChangerParams import VoiceChangerParams
|
|
|
|
|
2023-01-28 09:07:54 +03:00
|
|
|
import uvicorn
|
|
|
|
from mods.ssl import create_self_signed_cert
|
|
|
|
from voice_changer.VoiceChangerManager import VoiceChangerManager
|
|
|
|
from sio.MMVC_SocketIOApp import MMVC_SocketIOApp
|
|
|
|
from restapi.MMVC_Rest import MMVC_Rest
|
2023-05-16 04:38:23 +03:00
|
|
|
from const import (
|
|
|
|
NATIVE_CLIENT_FILE_MAC,
|
|
|
|
NATIVE_CLIENT_FILE_WIN,
|
|
|
|
SSL_KEY_DIR,
|
2023-06-04 23:00:57 +03:00
|
|
|
getRVCSampleJsonAndModelIds,
|
2023-05-16 04:38:23 +03:00
|
|
|
)
|
2023-01-28 09:07:54 +03:00
|
|
|
import subprocess
|
|
|
|
import multiprocessing as mp
|
2023-04-28 07:49:40 +03:00
|
|
|
from misc.log_control import setup_loggers
|
|
|
|
|
|
|
|
setup_loggers()
|
2022-12-31 10:02:53 +03:00
|
|
|
|
2022-12-31 12:06:57 +03:00
|
|
|
|
2022-12-31 10:02:53 +03:00
|
|
|
def setupArgParser():
|
|
|
|
parser = argparse.ArgumentParser()
|
2023-05-31 08:30:35 +03:00
|
|
|
parser.add_argument(
|
|
|
|
"--logLevel",
|
|
|
|
type=str,
|
|
|
|
default="critical",
|
|
|
|
help="Log level info|critical. (default: critical)",
|
|
|
|
)
|
2023-01-14 10:51:44 +03:00
|
|
|
parser.add_argument("-p", type=int, default=18888, help="port")
|
2023-04-27 17:38:25 +03:00
|
|
|
parser.add_argument("--https", type=strtobool, default=False, help="use https")
|
|
|
|
parser.add_argument(
|
|
|
|
"--httpsKey", type=str, default="ssl.key", help="path for the key of https"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--httpsCert", type=str, default="ssl.cert", help="path for the cert of https"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--httpsSelfSigned",
|
|
|
|
type=strtobool,
|
|
|
|
default=True,
|
|
|
|
help="generate self-signed certificate",
|
|
|
|
)
|
2023-05-16 04:38:23 +03:00
|
|
|
|
2023-05-14 22:24:58 +03:00
|
|
|
parser.add_argument("--model_dir", type=str, help="path to model files")
|
2023-06-04 23:00:57 +03:00
|
|
|
parser.add_argument(
|
|
|
|
"--rvc_sample_mode", type=str, default="production", help="rvc_sample_mode"
|
|
|
|
)
|
2023-04-27 17:38:25 +03:00
|
|
|
|
|
|
|
parser.add_argument(
|
|
|
|
"--content_vec_500", type=str, help="path to content_vec_500 model(pytorch)"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--content_vec_500_onnx", type=str, help="path to content_vec_500 model(onnx)"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--content_vec_500_onnx_on",
|
|
|
|
type=strtobool,
|
|
|
|
default=False,
|
|
|
|
help="use or not onnx for content_vec_500",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--hubert_base", type=str, help="path to hubert_base model(pytorch)"
|
|
|
|
)
|
2023-05-02 06:11:00 +03:00
|
|
|
parser.add_argument(
|
|
|
|
"--hubert_base_jp", type=str, help="path to hubert_base_jp model(pytorch)"
|
|
|
|
)
|
2023-04-27 17:38:25 +03:00
|
|
|
parser.add_argument(
|
|
|
|
"--hubert_soft", type=str, help="path to hubert_soft model(pytorch)"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--nsf_hifigan", type=str, help="path to nsf_hifigan model(pytorch)"
|
|
|
|
)
|
2023-01-17 02:29:57 +03:00
|
|
|
|
2022-12-31 10:02:53 +03:00
|
|
|
return parser
|
|
|
|
|
|
|
|
|
|
|
|
def printMessage(message, level=0):
|
2023-01-15 11:59:30 +03:00
|
|
|
pf = platform.system()
|
2023-04-27 17:38:25 +03:00
|
|
|
if pf == "Windows":
|
2023-01-15 11:59:30 +03:00
|
|
|
if level == 0:
|
|
|
|
print(f"{message}")
|
|
|
|
elif level == 1:
|
|
|
|
print(f" {message}")
|
|
|
|
elif level == 2:
|
|
|
|
print(f" {message}")
|
|
|
|
else:
|
|
|
|
print(f" {message}")
|
2022-12-31 10:02:53 +03:00
|
|
|
else:
|
2023-01-15 11:59:30 +03:00
|
|
|
if level == 0:
|
|
|
|
print(f"\033[17m{message}\033[0m")
|
|
|
|
elif level == 1:
|
|
|
|
print(f"\033[34m {message}\033[0m")
|
|
|
|
elif level == 2:
|
|
|
|
print(f"\033[32m {message}\033[0m")
|
|
|
|
else:
|
|
|
|
print(f"\033[47m {message}\033[0m")
|
2022-12-31 10:02:53 +03:00
|
|
|
|
2023-01-28 05:51:56 +03:00
|
|
|
|
2023-05-09 16:40:21 +03:00
|
|
|
def downloadWeight():
|
2023-05-12 01:47:57 +03:00
|
|
|
# content_vec_500 = (args.content_vec_500,)
|
|
|
|
# content_vec_500_onnx = (args.content_vec_500_onnx,)
|
|
|
|
# content_vec_500_onnx_on = (args.content_vec_500_onnx_on,)
|
|
|
|
hubert_base = args.hubert_base
|
|
|
|
hubert_base_jp = args.hubert_base_jp
|
|
|
|
hubert_soft = args.hubert_soft
|
|
|
|
nsf_hifigan = args.nsf_hifigan
|
2023-05-09 16:40:21 +03:00
|
|
|
|
|
|
|
# file exists check (currently only for rvc)
|
|
|
|
downloadParams = []
|
2023-05-12 01:47:57 +03:00
|
|
|
if os.path.exists(hubert_base) is False:
|
2023-05-09 16:40:21 +03:00
|
|
|
downloadParams.append(
|
|
|
|
{
|
|
|
|
"url": "https://huggingface.co/ddPn08/rvc-webui-models/resolve/main/embeddings/hubert_base.pt",
|
2023-05-12 01:47:57 +03:00
|
|
|
"saveTo": hubert_base,
|
2023-05-09 16:40:21 +03:00
|
|
|
"position": 0,
|
|
|
|
}
|
|
|
|
)
|
2023-05-12 01:47:57 +03:00
|
|
|
if os.path.exists(hubert_base_jp) is False:
|
2023-05-09 16:40:21 +03:00
|
|
|
downloadParams.append(
|
|
|
|
{
|
|
|
|
"url": "https://huggingface.co/rinna/japanese-hubert-base/resolve/main/fairseq/model.pt",
|
2023-05-12 01:47:57 +03:00
|
|
|
"saveTo": hubert_base_jp,
|
2023-05-09 16:40:21 +03:00
|
|
|
"position": 1,
|
|
|
|
}
|
|
|
|
)
|
2023-05-12 01:47:57 +03:00
|
|
|
if os.path.exists(hubert_soft) is False:
|
2023-05-09 16:40:21 +03:00
|
|
|
downloadParams.append(
|
|
|
|
{
|
|
|
|
"url": "https://huggingface.co/wok000/weights/resolve/main/ddsp-svc30/embedder/hubert-soft-0d54a1f4.pt",
|
2023-05-12 01:47:57 +03:00
|
|
|
"saveTo": hubert_soft,
|
2023-05-09 16:40:21 +03:00
|
|
|
"position": 2,
|
|
|
|
}
|
|
|
|
)
|
2023-05-12 01:47:57 +03:00
|
|
|
if os.path.exists(nsf_hifigan) is False:
|
2023-05-09 16:40:21 +03:00
|
|
|
downloadParams.append(
|
|
|
|
{
|
|
|
|
"url": "https://huggingface.co/wok000/weights/resolve/main/ddsp-svc30/nsf_hifigan_20221211/model.bin",
|
2023-05-12 01:47:57 +03:00
|
|
|
"saveTo": nsf_hifigan,
|
2023-05-09 16:40:21 +03:00
|
|
|
"position": 3,
|
|
|
|
}
|
|
|
|
)
|
2023-05-12 01:47:57 +03:00
|
|
|
nsf_hifigan_config = os.path.join(os.path.dirname(nsf_hifigan), "config.json")
|
2023-05-09 16:40:21 +03:00
|
|
|
|
|
|
|
if os.path.exists(nsf_hifigan_config) is False:
|
|
|
|
downloadParams.append(
|
|
|
|
{
|
|
|
|
"url": "https://huggingface.co/wok000/weights/raw/main/ddsp-svc30/nsf_hifigan_20221211/config.json",
|
|
|
|
"saveTo": nsf_hifigan_config,
|
|
|
|
"position": 4,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
with ThreadPoolExecutor() as pool:
|
|
|
|
pool.map(download, downloadParams)
|
|
|
|
|
|
|
|
if (
|
2023-05-12 01:47:57 +03:00
|
|
|
os.path.exists(hubert_base) is False
|
|
|
|
or os.path.exists(hubert_base_jp) is False
|
|
|
|
or os.path.exists(hubert_soft) is False
|
|
|
|
or os.path.exists(nsf_hifigan) is False
|
|
|
|
or os.path.exists(nsf_hifigan_config) is False
|
2023-05-09 16:40:21 +03:00
|
|
|
):
|
|
|
|
printMessage("RVC用のモデルファイルのダウンロードに失敗しました。", level=2)
|
|
|
|
printMessage("failed to download weight for rvc", level=2)
|
|
|
|
|
|
|
|
|
2022-12-31 10:02:53 +03:00
|
|
|
parser = setupArgParser()
|
2023-01-28 05:51:56 +03:00
|
|
|
args, unknown = parser.parse_known_args()
|
2022-12-31 10:02:53 +03:00
|
|
|
|
2023-03-14 04:53:34 +03:00
|
|
|
printMessage(f"Booting PHASE :{__name__}", level=2)
|
|
|
|
|
2023-01-14 03:40:08 +03:00
|
|
|
PORT = args.p
|
|
|
|
|
|
|
|
|
2023-05-31 08:30:35 +03:00
|
|
|
def localServer(logLevel: str = "critical"):
|
2023-01-28 05:51:56 +03:00
|
|
|
uvicorn.run(
|
|
|
|
f"{os.path.basename(__file__)[:-3]}:app_socketio",
|
|
|
|
host="0.0.0.0",
|
|
|
|
port=int(PORT),
|
|
|
|
reload=False if hasattr(sys, "_MEIPASS") else True,
|
2023-05-31 08:30:35 +03:00
|
|
|
log_level=logLevel,
|
2023-01-28 05:51:56 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-04-27 17:38:25 +03:00
|
|
|
if __name__ == "MMVCServerSIO":
|
2023-05-12 01:47:57 +03:00
|
|
|
mp.freeze_support()
|
2023-04-27 17:38:25 +03:00
|
|
|
voiceChangerParams = VoiceChangerParams(
|
2023-05-14 22:24:58 +03:00
|
|
|
model_dir=args.model_dir,
|
2023-04-27 17:38:25 +03:00
|
|
|
content_vec_500=args.content_vec_500,
|
|
|
|
content_vec_500_onnx=args.content_vec_500_onnx,
|
|
|
|
content_vec_500_onnx_on=args.content_vec_500_onnx_on,
|
|
|
|
hubert_base=args.hubert_base,
|
2023-05-02 06:11:00 +03:00
|
|
|
hubert_base_jp=args.hubert_base_jp,
|
2023-04-27 17:38:25 +03:00
|
|
|
hubert_soft=args.hubert_soft,
|
|
|
|
nsf_hifigan=args.nsf_hifigan,
|
2023-06-04 23:00:57 +03:00
|
|
|
rvc_sample_mode=args.rvc_sample_mode,
|
2023-04-27 17:38:25 +03:00
|
|
|
)
|
2023-03-13 15:07:35 +03:00
|
|
|
|
2023-05-03 16:36:59 +03:00
|
|
|
if (
|
|
|
|
os.path.exists(voiceChangerParams.hubert_base) is False
|
|
|
|
or os.path.exists(voiceChangerParams.hubert_base_jp) is False
|
|
|
|
):
|
|
|
|
printMessage("RVC用のモデルファイルのダウンロードに失敗しました。", level=2)
|
|
|
|
printMessage("failed to download weight for rvc", level=2)
|
|
|
|
|
|
|
|
voiceChangerManager = VoiceChangerManager.get_instance(voiceChangerParams)
|
2023-05-28 21:29:29 +03:00
|
|
|
app_fastapi = MMVC_Rest.get_instance(voiceChangerManager, voiceChangerParams)
|
2023-03-14 04:53:34 +03:00
|
|
|
app_socketio = MMVC_SocketIOApp.get_instance(app_fastapi, voiceChangerManager)
|
2022-12-31 10:02:53 +03:00
|
|
|
|
|
|
|
|
2023-04-27 17:38:25 +03:00
|
|
|
if __name__ == "__mp_main__":
|
|
|
|
printMessage("サーバプロセスを起動しています。", level=2)
|
2022-12-31 10:02:53 +03:00
|
|
|
|
2023-04-27 17:38:25 +03:00
|
|
|
if __name__ == "__main__":
|
2023-01-28 08:01:23 +03:00
|
|
|
mp.freeze_support()
|
2023-01-28 05:51:56 +03:00
|
|
|
|
2023-04-27 17:38:25 +03:00
|
|
|
printMessage("Voice Changerを起動しています。", level=2)
|
2023-05-09 16:40:21 +03:00
|
|
|
|
2023-05-17 20:51:40 +03:00
|
|
|
# ダウンロード
|
2023-05-09 16:40:21 +03:00
|
|
|
downloadWeight()
|
2023-05-16 04:38:23 +03:00
|
|
|
os.makedirs(args.model_dir, exist_ok=True)
|
2023-05-09 16:40:21 +03:00
|
|
|
|
2023-05-17 20:51:40 +03:00
|
|
|
try:
|
2023-05-20 09:54:00 +03:00
|
|
|
sampleJsons = []
|
2023-06-04 23:00:57 +03:00
|
|
|
sampleJsonUrls, sampleModels = getRVCSampleJsonAndModelIds(args.rvc_sample_mode)
|
|
|
|
for url in sampleJsonUrls:
|
2023-05-20 09:54:00 +03:00
|
|
|
filename = os.path.basename(url)
|
|
|
|
download_no_tqdm({"url": url, "saveTo": filename, "position": 0})
|
|
|
|
sampleJsons.append(filename)
|
|
|
|
if checkRvcModelExist(args.model_dir) is False:
|
2023-06-04 23:00:57 +03:00
|
|
|
downloadInitialSampleModels(sampleJsons, sampleModels, args.model_dir)
|
2023-05-17 20:51:40 +03:00
|
|
|
except Exception as e:
|
|
|
|
print("[Voice Changer] loading sample failed", e)
|
|
|
|
|
2022-12-31 10:02:53 +03:00
|
|
|
PORT = args.p
|
|
|
|
|
2023-04-18 21:35:04 +03:00
|
|
|
if os.getenv("EX_PORT"):
|
|
|
|
EX_PORT = os.environ["EX_PORT"]
|
2023-04-27 17:38:25 +03:00
|
|
|
printMessage(f"External_Port:{EX_PORT} Internal_Port:{PORT}", level=1)
|
2023-04-18 21:35:04 +03:00
|
|
|
else:
|
|
|
|
printMessage(f"Internal_Port:{PORT}", level=1)
|
|
|
|
|
|
|
|
if os.getenv("EX_IP"):
|
|
|
|
EX_IP = os.environ["EX_IP"]
|
|
|
|
printMessage(f"External_IP:{EX_IP}", level=1)
|
|
|
|
|
|
|
|
# HTTPS key/cert作成
|
|
|
|
if args.https and args.httpsSelfSigned == 1:
|
|
|
|
# HTTPS(おれおれ証明書生成)
|
|
|
|
os.makedirs(SSL_KEY_DIR, exist_ok=True)
|
|
|
|
key_base_name = f"{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
|
|
|
keyname = f"{key_base_name}.key"
|
|
|
|
certname = f"{key_base_name}.cert"
|
2023-04-27 17:38:25 +03:00
|
|
|
create_self_signed_cert(
|
|
|
|
certname,
|
|
|
|
keyname,
|
|
|
|
certargs={
|
|
|
|
"Country": "JP",
|
|
|
|
"State": "Tokyo",
|
|
|
|
"City": "Chuo-ku",
|
|
|
|
"Organization": "F",
|
|
|
|
"Org. Unit": "F",
|
|
|
|
},
|
|
|
|
cert_dir=SSL_KEY_DIR,
|
|
|
|
)
|
2023-04-18 21:35:04 +03:00
|
|
|
key_path = os.path.join(SSL_KEY_DIR, keyname)
|
|
|
|
cert_path = os.path.join(SSL_KEY_DIR, certname)
|
|
|
|
printMessage(
|
2023-04-27 17:38:25 +03:00
|
|
|
f"protocol: HTTPS(self-signed), key:{key_path}, cert:{cert_path}", level=1
|
|
|
|
)
|
2023-01-14 12:31:20 +03:00
|
|
|
|
2023-04-18 21:35:04 +03:00
|
|
|
elif args.https and args.httpsSelfSigned == 0:
|
|
|
|
# HTTPS
|
|
|
|
key_path = args.httpsKey
|
|
|
|
cert_path = args.httpsCert
|
2023-04-27 17:38:25 +03:00
|
|
|
printMessage(f"protocol: HTTPS, key:{key_path}, cert:{cert_path}", level=1)
|
2023-04-18 21:35:04 +03:00
|
|
|
else:
|
|
|
|
# HTTP
|
2023-04-27 17:38:25 +03:00
|
|
|
printMessage("protocol: HTTP", level=1)
|
|
|
|
printMessage("-- ---- -- ", level=1)
|
2023-04-18 21:35:04 +03:00
|
|
|
|
|
|
|
# アドレス表示
|
2023-04-27 17:38:25 +03:00
|
|
|
printMessage("ブラウザで次のURLを開いてください.", level=2)
|
2023-04-18 21:35:04 +03:00
|
|
|
if args.https == 1:
|
2023-04-27 17:38:25 +03:00
|
|
|
printMessage("https://<IP>:<PORT>/", level=1)
|
2023-04-18 21:35:04 +03:00
|
|
|
else:
|
2023-04-27 17:38:25 +03:00
|
|
|
printMessage("http://<IP>:<PORT>/", level=1)
|
2023-04-18 21:35:04 +03:00
|
|
|
|
2023-04-27 17:38:25 +03:00
|
|
|
printMessage("多くの場合は次のいずれかのURLにアクセスすると起動します。", level=2)
|
2023-04-18 21:35:04 +03:00
|
|
|
if "EX_PORT" in locals() and "EX_IP" in locals(): # シェルスクリプト経由起動(docker)
|
2022-12-31 10:02:53 +03:00
|
|
|
if args.https == 1:
|
2023-04-18 21:35:04 +03:00
|
|
|
printMessage(f"https://localhost:{EX_PORT}/", level=1)
|
|
|
|
for ip in EX_IP.strip().split(" "):
|
|
|
|
printMessage(f"https://{ip}:{EX_PORT}/", level=1)
|
2022-12-31 10:02:53 +03:00
|
|
|
else:
|
2023-04-18 21:35:04 +03:00
|
|
|
printMessage(f"http://localhost:{EX_PORT}/", level=1)
|
|
|
|
else: # 直接python起動
|
|
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
|
|
s.connect(("8.8.8.8", 80))
|
|
|
|
hostname = s.getsockname()[0]
|
|
|
|
if args.https == 1:
|
|
|
|
printMessage(f"https://localhost:{PORT}/", level=1)
|
|
|
|
printMessage(f"https://{hostname}:{PORT}/", level=1)
|
2022-12-31 10:02:53 +03:00
|
|
|
else:
|
2023-04-18 21:35:04 +03:00
|
|
|
printMessage(f"http://localhost:{PORT}/", level=1)
|
2022-12-31 10:02:53 +03:00
|
|
|
|
|
|
|
# サーバ起動
|
|
|
|
if args.https:
|
|
|
|
# HTTPS サーバ起動
|
2023-04-27 17:38:25 +03:00
|
|
|
uvicorn.run(
|
2022-12-31 10:02:53 +03:00
|
|
|
f"{os.path.basename(__file__)[:-3]}:app_socketio",
|
|
|
|
host="0.0.0.0",
|
|
|
|
port=int(PORT),
|
2023-01-28 05:51:56 +03:00
|
|
|
reload=False if hasattr(sys, "_MEIPASS") else True,
|
2022-12-31 10:02:53 +03:00
|
|
|
ssl_keyfile=key_path,
|
|
|
|
ssl_certfile=cert_path,
|
2023-05-31 08:30:35 +03:00
|
|
|
log_level=args.logLevel,
|
2022-12-31 10:02:53 +03:00
|
|
|
)
|
|
|
|
else:
|
2023-05-31 08:30:35 +03:00
|
|
|
p = mp.Process(name="p", target=localServer, args=(args.logLevel,))
|
2023-04-19 02:22:08 +03:00
|
|
|
p.start()
|
|
|
|
try:
|
2023-04-27 17:38:25 +03:00
|
|
|
if sys.platform.startswith("win"):
|
|
|
|
process = subprocess.Popen(
|
|
|
|
[NATIVE_CLIENT_FILE_WIN, "-u", f"http://localhost:{PORT}/"]
|
|
|
|
)
|
2023-04-19 02:22:08 +03:00
|
|
|
return_code = process.wait()
|
|
|
|
print("client closed.")
|
|
|
|
p.terminate()
|
2023-04-27 17:38:25 +03:00
|
|
|
elif sys.platform.startswith("darwin"):
|
|
|
|
process = subprocess.Popen(
|
|
|
|
[NATIVE_CLIENT_FILE_MAC, "-u", f"http://localhost:{PORT}/"]
|
|
|
|
)
|
2023-04-19 02:22:08 +03:00
|
|
|
return_code = process.wait()
|
|
|
|
print("client closed.")
|
|
|
|
p.terminate()
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print(e)
|