common sample

This commit is contained in:
wataru 2023-06-16 16:49:55 +09:00
parent 4d55e19bd0
commit 99cf22041f
10 changed files with 490 additions and 315 deletions

View File

@ -3,9 +3,7 @@ class NoModeLoadedException(Exception):
self.framework = framework
def __str__(self):
return repr(
f"No model for {self.framework} loaded. Please confirm the model uploaded."
)
return repr(f"No model for {self.framework} loaded. Please confirm the model uploaded.")
class HalfPrecisionChangingException(Exception):
@ -36,3 +34,8 @@ class DeviceCannotSupportHalfPrecisionException(Exception):
class VoiceChangerIsNotSelectedException(Exception):
def __str__(self):
return repr("Voice Changer is not selected.")
class WeightDownladException(Exception):
def __str__(self):
return repr("Failed to download weight.")

View File

@ -1,4 +1,3 @@
from concurrent.futures import ThreadPoolExecutor
import sys
from distutils.util import strtobool
@ -7,11 +6,9 @@ import socket
import platform
import os
import argparse
from Downloader import download, download_no_tqdm
from voice_changer.RVC.SampleDownloader import (
checkRvcModelExist,
downloadInitialSampleModels,
)
from Exceptions import WeightDownladException
from utils.downloader.SampleDownloader import downloadInitialSamples
from utils.downloader.WeightDownloader import downloadWeight
from voice_changer.utils.VoiceChangerParams import VoiceChangerParams
@ -24,7 +21,6 @@ from const import (
NATIVE_CLIENT_FILE_MAC,
NATIVE_CLIENT_FILE_WIN,
SSL_KEY_DIR,
getRVCSampleJsonAndModelIds,
)
import subprocess
import multiprocessing as mp
@ -35,56 +31,23 @@ setup_loggers()
def setupArgParser():
parser = argparse.ArgumentParser()
parser.add_argument(
"--logLevel",
type=str,
default="critical",
help="Log level info|critical. (default: critical)",
)
parser.add_argument("--logLevel", type=str, default="critical", help="Log level info|critical. (default: critical)")
parser.add_argument("-p", type=int, default=18888, help="port")
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",
)
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")
parser.add_argument("--model_dir", type=str, help="path to model files")
parser.add_argument(
"--rvc_sample_mode", type=str, default="production", help="rvc_sample_mode"
)
parser.add_argument("--sample_mode", type=str, default="production", help="rvc_sample_mode")
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)"
)
parser.add_argument(
"--hubert_base_jp", type=str, help="path to hubert_base_jp model(pytorch)"
)
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)"
)
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)")
parser.add_argument("--hubert_base_jp", type=str, help="path to hubert_base_jp model(pytorch)")
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)")
return parser
@ -111,76 +74,19 @@ def printMessage(message, level=0):
print(f"\033[47m {message}\033[0m")
def downloadWeight():
# 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
# file exists check (currently only for rvc)
downloadParams = []
if os.path.exists(hubert_base) is False:
downloadParams.append(
{
"url": "https://huggingface.co/ddPn08/rvc-webui-models/resolve/main/embeddings/hubert_base.pt",
"saveTo": hubert_base,
"position": 0,
}
)
if os.path.exists(hubert_base_jp) is False:
downloadParams.append(
{
"url": "https://huggingface.co/rinna/japanese-hubert-base/resolve/main/fairseq/model.pt",
"saveTo": hubert_base_jp,
"position": 1,
}
)
if os.path.exists(hubert_soft) is False:
downloadParams.append(
{
"url": "https://huggingface.co/wok000/weights/resolve/main/ddsp-svc30/embedder/hubert-soft-0d54a1f4.pt",
"saveTo": hubert_soft,
"position": 2,
}
)
if os.path.exists(nsf_hifigan) is False:
downloadParams.append(
{
"url": "https://huggingface.co/wok000/weights/resolve/main/ddsp-svc30/nsf_hifigan_20221211/model.bin",
"saveTo": nsf_hifigan,
"position": 3,
}
)
nsf_hifigan_config = os.path.join(os.path.dirname(nsf_hifigan), "config.json")
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 (
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
):
printMessage("RVC用のモデルファイルのダウンロードに失敗しました。", level=2)
printMessage("failed to download weight for rvc", level=2)
parser = setupArgParser()
args, unknown = parser.parse_known_args()
voiceChangerParams = VoiceChangerParams(
model_dir=args.model_dir,
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,
sample_mode=args.sample_mode,
)
printMessage(f"Booting PHASE :{__name__}", level=2)
@ -199,24 +105,6 @@ def localServer(logLevel: str = "critical"):
if __name__ == "MMVCServerSIO":
mp.freeze_support()
voiceChangerParams = VoiceChangerParams(
model_dir=args.model_dir,
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,
rvc_sample_mode=args.rvc_sample_mode,
)
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)
app_fastapi = MMVC_Rest.get_instance(voiceChangerManager, voiceChangerParams)
@ -230,24 +118,20 @@ if __name__ == "__main__":
mp.freeze_support()
printMessage("Voice Changerを起動しています。", level=2)
# ダウンロード
downloadWeight()
os.makedirs(args.model_dir, exist_ok=True)
# ダウンロード(Weight)
try:
sampleJsons = []
sampleJsonUrls, sampleModels = getRVCSampleJsonAndModelIds(args.rvc_sample_mode)
for url in sampleJsonUrls:
filename = os.path.basename(url)
download_no_tqdm({"url": url, "saveTo": filename, "position": 0})
sampleJsons.append(filename)
if checkRvcModelExist(args.model_dir) is False:
downloadInitialSampleModels(sampleJsons, sampleModels, args.model_dir)
downloadWeight(voiceChangerParams)
except WeightDownladException:
printMessage("RVC用のモデルファイルのダウンロードに失敗しました。", level=2)
printMessage("failed to download weight for rvc", level=2)
# ダウンロード(Sample)
try:
downloadInitialSamples(args.sample_mode, args.model_dir)
except Exception as e:
print("[Voice Changer] loading sample failed", e)
PORT = args.p
# PORT = args.p
if os.getenv("EX_PORT"):
EX_PORT = os.environ["EX_PORT"]
@ -280,9 +164,7 @@ if __name__ == "__main__":
)
key_path = os.path.join(SSL_KEY_DIR, keyname)
cert_path = os.path.join(SSL_KEY_DIR, certname)
printMessage(
f"protocol: HTTPS(self-signed), key:{key_path}, cert:{cert_path}", level=1
)
printMessage(f"protocol: HTTPS(self-signed), key:{key_path}, cert:{cert_path}", level=1)
elif args.https and args.httpsSelfSigned == 0:
# HTTPS
@ -336,16 +218,12 @@ if __name__ == "__main__":
p.start()
try:
if sys.platform.startswith("win"):
process = subprocess.Popen(
[NATIVE_CLIENT_FILE_WIN, "-u", f"http://localhost:{PORT}/"]
)
process = subprocess.Popen([NATIVE_CLIENT_FILE_WIN, "-u", f"http://localhost:{PORT}/"])
return_code = process.wait()
print("client closed.")
p.terminate()
elif sys.platform.startswith("darwin"):
process = subprocess.Popen(
[NATIVE_CLIENT_FILE_MAC, "-u", f"http://localhost:{PORT}/"]
)
process = subprocess.Popen([NATIVE_CLIENT_FILE_MAC, "-u", f"http://localhost:{PORT}/"])
return_code = process.wait()
print("client closed.")
p.terminate()

View File

@ -5,6 +5,14 @@ import tempfile
from typing import Literal, TypeAlias
VoiceChangerType: TypeAlias = Literal[
"MMVCv13",
"MMVCv15",
"so-vits-svc-40",
"DDSP-SVC",
"RVC",
]
ModelType: TypeAlias = Literal[
"MMVCv15",
"MMVCv13",
@ -22,16 +30,8 @@ tmpdir = tempfile.TemporaryDirectory()
# print("generate tmpdir:::",tmpdir)
SSL_KEY_DIR = os.path.join(tmpdir.name, "keys") if hasattr(sys, "_MEIPASS") else "keys"
MODEL_DIR = os.path.join(tmpdir.name, "logs") if hasattr(sys, "_MEIPASS") else "logs"
UPLOAD_DIR = (
os.path.join(tmpdir.name, "upload_dir")
if hasattr(sys, "_MEIPASS")
else "upload_dir"
)
NATIVE_CLIENT_FILE_WIN = (
os.path.join(sys._MEIPASS, "voice-changer-native-client.exe") # type: ignore
if hasattr(sys, "_MEIPASS")
else "voice-changer-native-client"
)
UPLOAD_DIR = os.path.join(tmpdir.name, "upload_dir") if hasattr(sys, "_MEIPASS") else "upload_dir"
NATIVE_CLIENT_FILE_WIN = os.path.join(sys._MEIPASS, "voice-changer-native-client.exe") if hasattr(sys, "_MEIPASS") else "voice-changer-native-client" # type: ignore
NATIVE_CLIENT_FILE_MAC = (
os.path.join(
sys._MEIPASS, # type: ignore
@ -44,25 +44,15 @@ NATIVE_CLIENT_FILE_MAC = (
else "voice-changer-native-client"
)
HUBERT_ONNX_MODEL_PATH = (
os.path.join(sys._MEIPASS, "model_hubert/hubert_simple.onnx") # type: ignore
if hasattr(sys, "_MEIPASS")
else "model_hubert/hubert_simple.onnx"
)
HUBERT_ONNX_MODEL_PATH = os.path.join(sys._MEIPASS, "model_hubert/hubert_simple.onnx") if hasattr(sys, "_MEIPASS") else "model_hubert/hubert_simple.onnx" # type: ignore
TMP_DIR = (
os.path.join(tmpdir.name, "tmp_dir") if hasattr(sys, "_MEIPASS") else "tmp_dir"
)
TMP_DIR = os.path.join(tmpdir.name, "tmp_dir") if hasattr(sys, "_MEIPASS") else "tmp_dir"
os.makedirs(TMP_DIR, exist_ok=True)
def getFrontendPath():
frontend_path = (
os.path.join(sys._MEIPASS, "dist")
if hasattr(sys, "_MEIPASS")
else "../client/demo/dist"
)
frontend_path = os.path.join(sys._MEIPASS, "dist") if hasattr(sys, "_MEIPASS") else "../client/demo/dist"
return frontend_path
@ -100,80 +90,81 @@ class ServerAudioDeviceTypes(Enum):
audiooutput = "audiooutput"
class RVCSampleMode(Enum):
production = "production"
testOfficial = "testOfficial"
testDDPNTorch = "testDDPNTorch"
testDDPNONNX = "testDDPNONNX"
testONNXFull = "testONNXFull"
RVCSampleMode: TypeAlias = Literal[
"production",
"testOfficial",
"testDDPNTorch",
"testDDPNONNX",
"testONNXFull",
]
def getRVCSampleJsonAndModelIds(mode: RVCSampleMode):
if mode == RVCSampleMode.production.value:
def getSampleJsonAndModelIds(mode: RVCSampleMode):
if mode == "production":
return [
# "https://huggingface.co/wok000/vcclient_model/raw/main/samples_0001.json",
# "https://huggingface.co/wok000/vcclient_model/raw/main/samples_0002.json",
"https://huggingface.co/wok000/vcclient_model/raw/main/samples_0003_t.json",
"https://huggingface.co/wok000/vcclient_model/raw/main/samples_0003_o.json",
"https://huggingface.co/wok000/vcclient_model/raw/main/samples_0003_t2.json",
"https://huggingface.co/wok000/vcclient_model/raw/main/samples_0003_o2.json",
], [
("TokinaShigure_o", True),
("KikotoMahiro_o", False),
("Amitaro_o", False),
("Tsukuyomi-chan_o", False),
("TokinaShigure_o", {"useIndex": True}),
("KikotoMahiro_o", {"useIndex": False}),
("Amitaro_o", {"useIndex": False}),
("Tsukuyomi-chan_o", {"useIndex": False}),
]
elif mode == RVCSampleMode.testOfficial.value:
elif mode == "testOfficial":
return [
"https://huggingface.co/wok000/vcclient_model/raw/main/test/test_official_v1_v2.json",
"https://huggingface.co/wok000/vcclient_model/raw/main/test/test_ddpn_v1_v2.json",
], [
("test-official-v1-f0-48k-l9-hubert_t", True),
("test-official-v1-nof0-48k-l9-hubert_t", False),
("test-official-v2-f0-40k-l12-hubert_t", False),
("test-official-v2-nof0-40k-l12-hubert_t", False),
("test-official-v1-f0-48k-l9-hubert_o", True),
("test-official-v1-nof0-48k-l9-hubert_o", False),
("test-official-v2-f0-40k-l12-hubert_o", False),
("test-official-v2-nof0-40k-l12-hubert_o", False),
("test-official-v1-f0-48k-l9-hubert_t", {"useIndex": True}),
("test-official-v1-nof0-48k-l9-hubert_t", {"useIndex": False}),
("test-official-v2-f0-40k-l12-hubert_t", {"useIndex": False}),
("test-official-v2-nof0-40k-l12-hubert_t", {"useIndex": False}),
("test-official-v1-f0-48k-l9-hubert_o", {"useIndex": True}),
("test-official-v1-nof0-48k-l9-hubert_o", {"useIndex": False}),
("test-official-v2-f0-40k-l12-hubert_o", {"useIndex": False}),
("test-official-v2-nof0-40k-l12-hubert_o", {"useIndex": False}),
]
elif mode == RVCSampleMode.testDDPNTorch.value:
elif mode == "testDDPNTorch":
return [
"https://huggingface.co/wok000/vcclient_model/raw/main/test/test_official_v1_v2.json",
"https://huggingface.co/wok000/vcclient_model/raw/main/test/test_ddpn_v1_v2.json",
], [
("test-ddpn-v1-f0-48k-l9-hubert_t", False),
("test-ddpn-v1-nof0-48k-l9-hubert_t", False),
("test-ddpn-v2-f0-40k-l12-hubert_t", False),
("test-ddpn-v2-nof0-40k-l12-hubert_t", False),
("test-ddpn-v2-f0-40k-l12-hubert_jp_t", False),
("test-ddpn-v2-nof0-40k-l12-hubert_jp_t", False),
("test-ddpn-v1-f0-48k-l9-hubert_t", {"useIndex": False}),
("test-ddpn-v1-nof0-48k-l9-hubert_t", {"useIndex": False}),
("test-ddpn-v2-f0-40k-l12-hubert_t", {"useIndex": False}),
("test-ddpn-v2-nof0-40k-l12-hubert_t", {"useIndex": False}),
("test-ddpn-v2-f0-40k-l12-hubert_jp_t", {"useIndex": False}),
("test-ddpn-v2-nof0-40k-l12-hubert_jp_t", {"useIndex": False}),
]
elif mode == RVCSampleMode.testDDPNONNX.value:
elif mode == "testDDPNONNX":
return [
"https://huggingface.co/wok000/vcclient_model/raw/main/test/test_official_v1_v2.json",
"https://huggingface.co/wok000/vcclient_model/raw/main/test/test_ddpn_v1_v2.json",
], [
("test-ddpn-v1-f0-48k-l9-hubert_o", False),
("test-ddpn-v1-nof0-48k-l9-hubert_o", False),
("test-ddpn-v2-f0-40k-l12-hubert_o", False),
("test-ddpn-v2-nof0-40k-l12-hubert_o", False),
("test-ddpn-v2-f0-40k-l12-hubert_jp_o", False),
("test-ddpn-v2-nof0-40k-l12-hubert_jp_o", False),
("test-ddpn-v1-f0-48k-l9-hubert_o", {"useIndex": False}),
("test-ddpn-v1-nof0-48k-l9-hubert_o", {"useIndex": False}),
("test-ddpn-v2-f0-40k-l12-hubert_o", {"useIndex": False}),
("test-ddpn-v2-nof0-40k-l12-hubert_o", {"useIndex": False}),
("test-ddpn-v2-f0-40k-l12-hubert_jp_o", {"useIndex": False}),
("test-ddpn-v2-nof0-40k-l12-hubert_jp_o", {"useIndex": False}),
]
elif mode == RVCSampleMode.testONNXFull.value:
elif mode == "testONNXFull":
return [
"https://huggingface.co/wok000/vcclient_model/raw/main/test/test_official_v1_v2.json",
"https://huggingface.co/wok000/vcclient_model/raw/main/test/test_ddpn_v1_v2.json",
], [
("test-official-v1-f0-48k-l9-hubert_o_full", False),
("test-official-v1-nof0-48k-l9-hubert_o_full", False),
("test-official-v2-f0-40k-l12-hubert_o_full", False),
("test-official-v2-nof0-40k-l12-hubert_o_full", False),
("test-ddpn-v1-f0-48k-l9-hubert_o_full", False),
("test-ddpn-v1-nof0-48k-l9-hubert_o_full", False),
("test-ddpn-v2-f0-40k-l12-hubert_o_full", False),
("test-ddpn-v2-nof0-40k-l12-hubert_o_full", False),
("test-ddpn-v2-f0-40k-l12-hubert_jp_o_full", False),
("test-ddpn-v2-nof0-40k-l12-hubert_jp_o_full", False),
("test-official-v1-f0-48k-l9-hubert_o_full", {"useIndex": False}),
("test-official-v1-nof0-48k-l9-hubert_o_full", {"useIndex": False}),
("test-official-v2-f0-40k-l12-hubert_o_full", {"useIndex": False}),
("test-official-v2-nof0-40k-l12-hubert_o_full", {"useIndex": False}),
("test-ddpn-v1-f0-48k-l9-hubert_o_full", {"useIndex": False}),
("test-ddpn-v1-nof0-48k-l9-hubert_o_full", {"useIndex": False}),
("test-ddpn-v2-f0-40k-l12-hubert_o_full", {"useIndex": False}),
("test-ddpn-v2-nof0-40k-l12-hubert_o_full", {"useIndex": False}),
("test-ddpn-v2-f0-40k-l12-hubert_jp_o_full", {"useIndex": False}),
("test-ddpn-v2-nof0-40k-l12-hubert_jp_o_full", {"useIndex": False}),
]
else:
return [], []

View File

@ -0,0 +1,37 @@
from dataclasses import dataclass, field
from typing import TypeAlias, Union, Any
from const import VoiceChangerType
@dataclass
class ModelSample:
id: str = ""
voiceChangerType: VoiceChangerType | None = None
@dataclass
class RVCModelSample(ModelSample):
voiceChangerType: VoiceChangerType = "RVC"
lang: str = ""
tag: list[str] = field(default_factory=lambda: [])
name: str = ""
modelUrl: str = ""
indexUrl: str = ""
termsOfUseUrl: str = ""
icon: str = ""
credit: str = ""
description: str = ""
sampleRate: int = 48000
modelType: str = ""
f0: bool = True
ModelSamples: TypeAlias = Union[ModelSample, RVCModelSample]
def generateModelSample(params: Any) -> ModelSamples:
if params["voiceChangerType"] == "RVC":
return RVCModelSample(**params)
else:
return ModelSample(**{k: v for k, v in params.items() if k in ModelSample.__annotations__})

59
server/data/ModelSlot.py Normal file
View File

@ -0,0 +1,59 @@
from typing import TypeAlias, Union
from const import EnumInferenceTypes, EnumEmbedderTypes, VoiceChangerType
from dataclasses import dataclass, asdict
import os
import json
@dataclass
class ModelSlot:
voiceChangerType: VoiceChangerType | None = None
@dataclass
class RVCModelSlot(ModelSlot):
voiceChangerType: VoiceChangerType = "RVC"
modelFile: str = ""
indexFile: str = ""
defaultTune: int = 0
defaultIndexRatio: int = 1
defaultProtect: float = 0.5
isONNX: bool = False
modelType: str = EnumInferenceTypes.pyTorchRVC.value
samplingRate: int = -1
f0: bool = True
embChannels: int = 256
embOutputLayer: int = 9
useFinalProj: bool = True
deprecated: bool = False
embedder: str = EnumEmbedderTypes.hubert.value
name: str = ""
description: str = ""
credit: str = ""
termsOfUseUrl: str = ""
sampleId: str = ""
iconFile: str = ""
ModelSlots: TypeAlias = Union[ModelSlot, RVCModelSlot]
def loadSlotInfo(model_dir: str, slotIndex: int) -> ModelSlots:
slotDir = os.path.join(model_dir, str(slotIndex))
jsonFile = os.path.join(slotDir, "params.json")
if not os.path.exists(jsonFile):
return ModelSlot()
jsonDict = json.load(open(os.path.join(slotDir, "params.json")))
slotInfo = ModelSlot(**{k: v for k, v in jsonDict.items() if k in ModelSlot.__annotations__})
if slotInfo.voiceChangerType == "RVC":
return RVCModelSlot(**jsonDict)
else:
return ModelSlot()
def saveSlotInfo(model_dir: str, slotIndex: int, slotInfo: ModelSlots):
slotDir = os.path.join(model_dir, str(slotIndex))
json.dump(asdict(slotInfo), open(os.path.join(slotDir, "params.json"), "w"))

View File

@ -1,79 +0,0 @@
{
"RVC": [
{
"id": "KikotoKurage_o",
"lang": "ja-JP",
"tag": ["v2", "onnx"],
"name": "黄琴海月(onnx)",
"modelUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/kikoto_kurage/kikoto_kurage_v2_40k_e100_simple.onnx",
"indexUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/kikoto_kurage/added_IVF5181_Flat_nprobe_1_v2.index.bin",
"termsOfUseUrl": "https://huggingface.co/wok000/vcclient_model/raw/main/rvc_v2_alpha/kikoto_kurage/terms_of_use.txt",
"icon": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/kikoto_kurage/kikoto_kurage.png",
"credit": "黄琴海月",
"description": "",
"sampleRate": 40000,
"modelType": "rvc_v2",
"f0": true
},
{
"id": "KikotoMahiro_o",
"lang": "ja-JP",
"tag": ["v2", "onnx"],
"name": "黄琴まひろ(onnx)",
"modelUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/kikoto_mahiro/kikoto_mahiro_v2_40k_simple.onnx",
"indexUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/kikoto_mahiro/added_IVF6881_Flat_nprobe_1_v2.index.bin",
"termsOfUseUrl": "https://huggingface.co/wok000/vcclient_model/raw/main/rvc_v2_alpha/kikoto_mahiro/terms_of_use.txt",
"icon": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/kikoto_mahiro/kikoto_mahiro.png",
"credit": "黄琴まひろ",
"description": "",
"sampleRate": 40000,
"modelType": "rvc_v2",
"f0": true
},
{
"id": "TokinaShigure_o",
"lang": "ja-JP",
"tag": ["v2", "onnx"],
"name": "刻鳴時雨(onnx)",
"modelUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/tokina_shigure/tokina_shigure_v2_40k_e100_simple.onnx",
"indexUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/tokina_shigure/added_IVF2736_Flat_nprobe_1_v2.index.bin",
"termsOfUseUrl": "https://huggingface.co/wok000/vcclient_model/raw/main/rvc_v2_alpha/tokina_shigure/terms_of_use.txt",
"icon": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/tokina_shigure/tokina_shigure.png",
"credit": "刻鳴時雨",
"description": "",
"sampleRate": 40000,
"modelType": "rvc_v2",
"f0": true
},
{
"id": "Amitaro_o",
"lang": "ja-JP",
"tag": ["v2", "onnx"],
"name": "あみたろ(onnx)",
"modelUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/amitaro/amitaro_v2_40k_e100_simple.onnx",
"indexUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/amitaro/added_IVF3139_Flat_nprobe_1_v2.index.bin",
"termsOfUseUrl": "https://huggingface.co/wok000/vcclient_model/raw/main/rvc_v2_alpha/amitaro/terms_of_use.txt",
"icon": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/amitaro/amitaro.png",
"credit": "あみたろ",
"description": "",
"sampleRate": 40000,
"modelType": "rvc_v2",
"f0": true
},
{
"id": "Tsukuyomi-chan_o",
"lang": "ja-JP",
"tag": ["v2", "onnx"],
"name": "つくよみちゃん(onnx)",
"modelUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/tsukuyomi-chan/tsukuyomi_v2_40k_e100_simple.onnx",
"indexUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/tsukuyomi-chan/added_IVF7852_Flat_nprobe_1_v2.index.bin",
"termsOfUseUrl": "https://huggingface.co/wok000/vcclient_model/raw/main/rvc_v2_alpha/tsukuyomi-chan/terms_of_use.txt",
"icon": "https://huggingface.co/wok000/vcclient_model/resolve/main/rvc_v2_alpha/tsukuyomi-chan/tsukuyomi-chan.png",
"credit": "つくよみちゃん",
"description": "",
"sampleRate": 40000,
"modelType": "rvc_v2",
"f0": true
}
]
}

View File

@ -0,0 +1,56 @@
import requests # type: ignore
import os
from tqdm import tqdm
def download(params):
url = params["url"]
saveTo = params["saveTo"]
position = params["position"]
dirname = os.path.dirname(saveTo)
if dirname != "":
os.makedirs(dirname, exist_ok=True)
try:
req = requests.get(url, stream=True, allow_redirects=True)
content_length = req.headers.get("content-length")
progress_bar = tqdm(
total=int(content_length) if content_length is not None else None,
leave=False,
unit="B",
unit_scale=True,
unit_divisor=1024,
position=position,
)
# with tqdm
with open(saveTo, "wb") as f:
for chunk in req.iter_content(chunk_size=1024):
if chunk:
progress_bar.update(len(chunk))
f.write(chunk)
except Exception as e:
print(e)
def download_no_tqdm(params):
url = params["url"]
saveTo = params["saveTo"]
dirname = os.path.dirname(saveTo)
if dirname != "":
os.makedirs(dirname, exist_ok=True)
try:
req = requests.get(url, stream=True, allow_redirects=True)
with open(saveTo, "wb") as f:
countToDot = 0
for chunk in req.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
countToDot += 1
if countToDot % 1024 == 0:
print(".", end="", flush=True)
print("+", end="", flush=True)
except Exception as e:
print(e)

View File

@ -0,0 +1,166 @@
import json
import os
from concurrent.futures import ThreadPoolExecutor
from typing import Any, Tuple
from const import RVCSampleMode, getSampleJsonAndModelIds
from data.ModelSample import ModelSamples, generateModelSample
from data.ModelSlot import RVCModelSlot, loadSlotInfo, saveSlotInfo
from voice_changer.RVC.ModelSlotGenerator import _setInfoByONNX, _setInfoByPytorch
from utils.downloader.Downloader import download, download_no_tqdm
def downloadInitialSamples(mode: RVCSampleMode, model_dir: str):
sampleJsonUrls, sampleModels = getSampleJsonAndModelIds(mode)
sampleJsons = _downloadSampleJsons(sampleJsonUrls)
if os.path.exists(model_dir):
print("[Voice Changer] model_dir is already exists. skil download samples.")
return
samples = _generateSampleList(sampleJsons)
slotIndex = list(range(len(sampleModels)))
_downloadSamples(samples, sampleModels, model_dir, slotIndex)
pass
def downloadSample(mode: RVCSampleMode, modelId: str, model_dir: str, slotIndex: int, params: Any):
sampleJsonUrls, _sampleModels = getSampleJsonAndModelIds(mode)
sampleJsons = _generateSampleJsons(sampleJsonUrls)
samples = _generateSampleList(sampleJsons)
_downloadSamples(samples, [(modelId, params)], model_dir, [slotIndex])
pass
def getSampleInfos(mode: RVCSampleMode):
sampleJsonUrls, _sampleModels = getSampleJsonAndModelIds(mode)
sampleJsons = _generateSampleJsons(sampleJsonUrls)
samples = _generateSampleList(sampleJsons)
return samples
def _downloadSampleJsons(sampleJsonUrls: list[str]):
sampleJsons = []
for url in sampleJsonUrls:
filename = os.path.basename(url)
download_no_tqdm({"url": url, "saveTo": filename, "position": 0})
sampleJsons.append(filename)
return sampleJsons
def _generateSampleJsons(sampleJsonUrls: list[str]):
sampleJsons = []
for url in sampleJsonUrls:
filename = os.path.basename(url)
sampleJsons.append(filename)
return sampleJsons
def _generateSampleList(sampleJsons: list[str]):
samples: list[ModelSamples] = []
for file in sampleJsons:
with open(file, "r", encoding="utf-8") as f:
jsonDict = json.load(f)
for vcType in jsonDict:
for sampleParams in jsonDict[vcType]:
sample = generateModelSample(sampleParams)
samples.append(sample)
return samples
def _downloadSamples(samples: list[ModelSamples], sampleModelIds: list[Tuple[str, Any]], model_dir: str, slotIndex: list[int]):
downloadParams = []
line_num = 0
for i, initSampleId in enumerate(sampleModelIds):
targetSampleId = initSampleId[0]
targetSampleParams = initSampleId[1]
tagetSlotIndex = slotIndex[i]
# 初期サンプルをサーチ
match = False
for sample in samples:
if sample.id == targetSampleId:
match = True
break
if match is False:
print(f"[Voice Changer] initiail sample not found. {targetSampleId}")
continue
# 検出されたら、、、
slotDir = os.path.join(model_dir, str(tagetSlotIndex))
if sample.voiceChangerType == "RVC":
slotInfo: RVCModelSlot = RVCModelSlot()
os.makedirs(slotDir, exist_ok=True)
modelFilePath = os.path.join(
slotDir,
os.path.basename(sample.modelUrl),
)
downloadParams.append(
{
"url": sample.modelUrl,
"saveTo": modelFilePath,
"position": line_num,
}
)
slotInfo.modelFile = modelFilePath
line_num += 1
if targetSampleParams["useIndex"] is True and hasattr(sample, "indexUrl") and sample.indexUrl != "":
indexPath = os.path.join(
slotDir,
os.path.basename(sample.indexUrl),
)
downloadParams.append(
{
"url": sample.indexUrl,
"saveTo": indexPath,
"position": line_num,
}
)
slotInfo.indexFile = indexPath
line_num += 1
if hasattr(sample, "icon") and sample.icon != "":
iconPath = os.path.join(
slotDir,
os.path.basename(sample.icon),
)
downloadParams.append(
{
"url": sample.icon,
"saveTo": iconPath,
"position": line_num,
}
)
slotInfo.iconFile = iconPath
line_num += 1
slotInfo.sampleId = sample.id
slotInfo.credit = sample.credit
slotInfo.description = sample.description
slotInfo.name = sample.name
slotInfo.termsOfUseUrl = sample.termsOfUseUrl
slotInfo.defaultTune = 0
slotInfo.defaultIndexRatio = 1
slotInfo.defaultProtect = 0.5
slotInfo.isONNX = slotInfo.modelFile.endswith(".onnx")
saveSlotInfo(model_dir, tagetSlotIndex, slotInfo)
else:
print(f"[Voice Changer] {sample.voiceChangerType} is not supported.")
# ダウンロード
print("[Voice Changer] Downloading model files...")
with ThreadPoolExecutor() as pool:
pool.map(download, downloadParams)
# メタデータ作成
print("[Voice Changer] Generating metadata...")
for targetSlotIndex in slotIndex:
slotInfo = loadSlotInfo(model_dir, targetSlotIndex)
if slotInfo.voiceChangerType == "RVC":
if slotInfo.isONNX:
_setInfoByONNX(slotInfo)
else:
_setInfoByPytorch(slotInfo)
saveSlotInfo(model_dir, targetSlotIndex, slotInfo)

View File

@ -0,0 +1,64 @@
import os
from concurrent.futures import ThreadPoolExecutor
from utils.downloader.Downloader import download
from voice_changer.utils.VoiceChangerParams import VoiceChangerParams
from Exceptions import WeightDownladException
def downloadWeight(voiceChangerParams: VoiceChangerParams):
hubert_base = voiceChangerParams.hubert_base
hubert_base_jp = voiceChangerParams.hubert_base_jp
hubert_soft = voiceChangerParams.hubert_soft
nsf_hifigan = voiceChangerParams.nsf_hifigan
# file exists check (currently only for rvc)
downloadParams = []
if os.path.exists(hubert_base) is False:
downloadParams.append(
{
"url": "https://huggingface.co/ddPn08/rvc-webui-models/resolve/main/embeddings/hubert_base.pt",
"saveTo": hubert_base,
"position": 0,
}
)
if os.path.exists(hubert_base_jp) is False:
downloadParams.append(
{
"url": "https://huggingface.co/rinna/japanese-hubert-base/resolve/main/fairseq/model.pt",
"saveTo": hubert_base_jp,
"position": 1,
}
)
if os.path.exists(hubert_soft) is False:
downloadParams.append(
{
"url": "https://huggingface.co/wok000/weights/resolve/main/ddsp-svc30/embedder/hubert-soft-0d54a1f4.pt",
"saveTo": hubert_soft,
"position": 2,
}
)
if os.path.exists(nsf_hifigan) is False:
downloadParams.append(
{
"url": "https://huggingface.co/wok000/weights/resolve/main/ddsp-svc30/nsf_hifigan_20221211/model.bin",
"saveTo": nsf_hifigan,
"position": 3,
}
)
nsf_hifigan_config = os.path.join(os.path.dirname(nsf_hifigan), "config.json")
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 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:
raise WeightDownladException()

View File

@ -11,4 +11,4 @@ class VoiceChangerParams:
hubert_base_jp: str
hubert_soft: str
nsf_hifigan: str
rvc_sample_mode: str
sample_mode: str