mirror of
https://github.com/w-okada/voice-changer.git
synced 2025-01-23 21:45:00 +03:00
WIP:common sample
This commit is contained in:
parent
d192e21093
commit
bd3d3375c3
@ -24,61 +24,58 @@ class MMVC_Rest_Fileuploader:
|
||||
self.router = APIRouter()
|
||||
self.router.add_api_route("/info", self.get_info, methods=["GET"])
|
||||
self.router.add_api_route("/performance", self.get_performance, methods=["GET"])
|
||||
self.router.add_api_route(
|
||||
"/upload_file", self.post_upload_file, methods=["POST"]
|
||||
)
|
||||
self.router.add_api_route(
|
||||
"/concat_uploaded_file", self.post_concat_uploaded_file, methods=["POST"]
|
||||
)
|
||||
self.router.add_api_route(
|
||||
"/update_settings", self.post_update_settings, methods=["POST"]
|
||||
)
|
||||
self.router.add_api_route("/upload_file", self.post_upload_file, methods=["POST"])
|
||||
self.router.add_api_route("/concat_uploaded_file", self.post_concat_uploaded_file, methods=["POST"])
|
||||
self.router.add_api_route("/update_settings", self.post_update_settings, methods=["POST"])
|
||||
self.router.add_api_route("/load_model", self.post_load_model, methods=["POST"])
|
||||
self.router.add_api_route("/model_type", self.post_model_type, methods=["POST"])
|
||||
self.router.add_api_route("/model_type", self.get_model_type, methods=["GET"])
|
||||
self.router.add_api_route("/onnx", self.get_onnx, methods=["GET"])
|
||||
self.router.add_api_route(
|
||||
"/merge_model", self.post_merge_models, methods=["POST"]
|
||||
)
|
||||
self.router.add_api_route(
|
||||
"/update_model_default", self.post_update_model_default, methods=["POST"]
|
||||
)
|
||||
self.router.add_api_route(
|
||||
"/update_model_info", self.post_update_model_info, methods=["POST"]
|
||||
)
|
||||
self.router.add_api_route(
|
||||
"/upload_model_assets", self.post_upload_model_assets, methods=["POST"]
|
||||
)
|
||||
self.router.add_api_route("/merge_model", self.post_merge_models, methods=["POST"])
|
||||
self.router.add_api_route("/update_model_default", self.post_update_model_default, methods=["POST"])
|
||||
self.router.add_api_route("/update_model_info", self.post_update_model_info, methods=["POST"])
|
||||
self.router.add_api_route("/upload_model_assets", self.post_upload_model_assets, methods=["POST"])
|
||||
|
||||
def post_upload_file(self, file: UploadFile = File(...), filename: str = Form(...)):
|
||||
try:
|
||||
res = upload_file(UPLOAD_DIR, file, filename)
|
||||
json_compatible_item_data = jsonable_encoder(res)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def post_concat_uploaded_file(
|
||||
self, filename: str = Form(...), filenameChunkNum: int = Form(...)
|
||||
):
|
||||
def post_concat_uploaded_file(self, filename: str = Form(...), filenameChunkNum: int = Form(...)):
|
||||
try:
|
||||
res = concat_file_chunks(UPLOAD_DIR, filename, filenameChunkNum, UPLOAD_DIR)
|
||||
json_compatible_item_data = jsonable_encoder(res)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def get_info(self):
|
||||
try:
|
||||
info = self.voiceChangerManager.get_info()
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def get_performance(self):
|
||||
try:
|
||||
info = self.voiceChangerManager.get_performance()
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def post_update_settings(
|
||||
self, key: str = Form(...), val: Union[int, str, float] = Form(...)
|
||||
):
|
||||
def post_update_settings(self, key: str = Form(...), val: Union[int, str, float] = Form(...)):
|
||||
try:
|
||||
print("[Voice Changer] update configuration:", key, val)
|
||||
info = self.voiceChangerManager.update_settings(key, val)
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def post_load_model(
|
||||
self,
|
||||
@ -86,6 +83,7 @@ class MMVC_Rest_Fileuploader:
|
||||
isHalf: bool = Form(...),
|
||||
params: str = Form(...),
|
||||
):
|
||||
try:
|
||||
paramDict = json.loads(params)
|
||||
# print("paramDict", paramDict)
|
||||
|
||||
@ -101,46 +99,67 @@ class MMVC_Rest_Fileuploader:
|
||||
newFilesDict[key] = storePath
|
||||
paramDict["files"] = newFilesDict
|
||||
|
||||
props: LoadModelParams = LoadModelParams(
|
||||
slot=slot, isHalf=isHalf, params=paramDict
|
||||
)
|
||||
props: LoadModelParams = LoadModelParams(slot=slot, isHalf=isHalf, params=paramDict)
|
||||
|
||||
info = self.voiceChangerManager.loadModel(props)
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def post_model_type(self, modelType: ModelType = Form(...)):
|
||||
try:
|
||||
info = self.voiceChangerManager.switchModelType(modelType)
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def get_model_type(self):
|
||||
try:
|
||||
info = self.voiceChangerManager.getModelType()
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def get_onnx(self):
|
||||
try:
|
||||
info = self.voiceChangerManager.export2onnx()
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def post_merge_models(self, request: str = Form(...)):
|
||||
try:
|
||||
print(request)
|
||||
info = self.voiceChangerManager.merge_models(request)
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def post_update_model_default(self):
|
||||
try:
|
||||
info = self.voiceChangerManager.update_model_default()
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def post_update_model_info(self, newData: str = Form(...)):
|
||||
try:
|
||||
info = self.voiceChangerManager.update_model_info(newData)
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
||||
def post_upload_model_assets(self, params: str = Form(...)):
|
||||
try:
|
||||
info = self.voiceChangerManager.upload_model_assets(params)
|
||||
json_compatible_item_data = jsonable_encoder(info)
|
||||
return JSONResponse(content=json_compatible_item_data)
|
||||
except Exception as e:
|
||||
print("[Voice Changer] ", e)
|
||||
|
60
server/voice_changer/ModelSlotManager.py
Normal file
60
server/voice_changer/ModelSlotManager.py
Normal file
@ -0,0 +1,60 @@
|
||||
from const import UPLOAD_DIR
|
||||
from data.ModelSlot import ModelSlots, loadAllSlotInfo, loadSlotInfo, saveSlotInfo
|
||||
from voice_changer.utils.VoiceChangerParams import VoiceChangerParams
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
||||
class ModelSlotManager:
|
||||
_instance = None
|
||||
|
||||
def __init__(self, params: VoiceChangerParams):
|
||||
self.params = params
|
||||
self.modelSlots = loadAllSlotInfo(self.params.model_dir)
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls, params: VoiceChangerParams):
|
||||
if cls._instance is None:
|
||||
cls._instance = cls(params)
|
||||
return cls._instance
|
||||
|
||||
def _save_model_slot(self, slotIndex: int, slotInfo: ModelSlots):
|
||||
saveSlotInfo(self.params.model_dir, slotIndex, slotInfo)
|
||||
self.modelSlots = loadAllSlotInfo(self.params.model_dir)
|
||||
|
||||
def _load_model_slot(self, slotIndex: int):
|
||||
return self.modelSlots[slotIndex]
|
||||
|
||||
def getAllSlotInfo(self):
|
||||
return self.modelSlots
|
||||
|
||||
def get_slot_info(self, slotIndex: int):
|
||||
return self._load_model_slot(slotIndex)
|
||||
|
||||
def save_model_slot(self, slotIndex: int, slotInfo: ModelSlots):
|
||||
self._save_model_slot(slotIndex, slotInfo)
|
||||
|
||||
def update_model_info(self, newData: str):
|
||||
print("[Voice Changer] UPDATE MODEL INFO", newData)
|
||||
newDataDict = json.loads(newData)
|
||||
slotInfo = self._load_model_slot(newDataDict["slot"])
|
||||
setattr(slotInfo, newDataDict["key"], newDataDict["val"])
|
||||
self._save_model_slot(newDataDict["slot"], slotInfo)
|
||||
|
||||
def store_model_assets(self, params: str):
|
||||
print("[Voice Changer] UPLOAD ASSETS", params)
|
||||
paramsDict = json.loads(params)
|
||||
uploadPath = os.path.join(UPLOAD_DIR, paramsDict["file"])
|
||||
storeDir = os.path.join(self.params.model_dir, str(paramsDict["slot"]))
|
||||
storePath = os.path.join(
|
||||
storeDir,
|
||||
paramsDict["file"],
|
||||
)
|
||||
try:
|
||||
shutil.move(uploadPath, storePath)
|
||||
slotInfo = self._load_model_slot(paramsDict["slot"])
|
||||
setattr(slotInfo, paramsDict["name"], storePath)
|
||||
self._save_model_slot(paramsDict["slot"], slotInfo)
|
||||
except Exception as e:
|
||||
print("Exception::::", e)
|
@ -5,8 +5,9 @@ from typing import cast
|
||||
import numpy as np
|
||||
import torch
|
||||
import torchaudio
|
||||
from data.ModelSlot import RVCModelSlot, loadAllSlotInfo
|
||||
from data.ModelSlot import RVCModelSlot
|
||||
from utils.downloader.SampleDownloader import getSampleInfos
|
||||
from voice_changer.ModelSlotManager import ModelSlotManager
|
||||
|
||||
|
||||
# avoiding parse arg error in RVC
|
||||
@ -65,21 +66,26 @@ class RVC:
|
||||
self.pitchExtractor = PitchExtractorManager.getPitchExtractor(self.settings.f0Detector)
|
||||
self.params = params
|
||||
EmbedderManager.initialize(params)
|
||||
self.settings.modelSlots = loadAllSlotInfo(self.params.model_dir)
|
||||
print("[Voice Changer] RVC initialization: ", params)
|
||||
self.modelSlotManager = ModelSlotManager.get_instance(self.params)
|
||||
|
||||
# サンプルカタログ作成
|
||||
samples = getSampleInfos(params.sample_mode)
|
||||
self.settings.sampleModels = samples
|
||||
# 起動時にスロットにモデルがある場合はロードしておく
|
||||
if len(self.settings.modelSlots) > 0:
|
||||
for i, slot in enumerate(self.settings.modelSlots):
|
||||
if len(slot.modelFile) > 0:
|
||||
self.prepareModel(i)
|
||||
self.settings.modelSlotIndex = i
|
||||
|
||||
allSlots = self.modelSlotManager.getAllSlotInfo()
|
||||
availableIndex = -1
|
||||
for i, slot in enumerate(allSlots):
|
||||
if slot.modelFile is not None and slot.modelFile != "":
|
||||
availableIndex = i
|
||||
break
|
||||
if availableIndex >= 0:
|
||||
self.prepareModel(availableIndex)
|
||||
self.settings.modelSlotIndex = availableIndex
|
||||
self.switchModel(self.settings.modelSlotIndex)
|
||||
self.initialLoad = False
|
||||
break
|
||||
|
||||
self.prevVol = 0.0
|
||||
|
||||
def getSampleInfo(self, id: str):
|
||||
@ -125,8 +131,8 @@ class RVC:
|
||||
slotInfo.indexFile = self.moveToModelDir(slotInfo.indexFile, slotDir)
|
||||
if slotInfo.iconFile is not None and len(slotInfo.iconFile) > 0:
|
||||
slotInfo.iconFile = self.moveToModelDir(slotInfo.iconFile, slotDir)
|
||||
json.dump(asdict(slotInfo), open(os.path.join(slotDir, "params.json"), "w"))
|
||||
self.settings.modelSlots = loadAllSlotInfo(self.params.model_dir)
|
||||
# json.dump(asdict(slotInfo), open(os.path.join(slotDir, "params.json"), "w"))
|
||||
self.modelSlotManager.save_model_slot(target_slot_idx, slotInfo)
|
||||
|
||||
# 初回のみロード(起動時にスロットにモデルがあった場合はinitialLoadはFalseになっている)
|
||||
if self.initialLoad:
|
||||
@ -147,7 +153,8 @@ class RVC:
|
||||
if val < 0:
|
||||
return True
|
||||
val = val % 1000 # Quick hack for same slot is selected
|
||||
if self.settings.modelSlots[val].modelFile is None or self.settings.modelSlots[val].modelFile == "":
|
||||
allModelSlots = self.modelSlotManager.getAllSlotInfo()
|
||||
if allModelSlots[val].modelFile is None or allModelSlots[val].modelFile == "":
|
||||
print("[Voice Changer] slot does not have model.")
|
||||
return True
|
||||
self.prepareModel(val)
|
||||
@ -174,7 +181,8 @@ class RVC:
|
||||
if slot < 0:
|
||||
print("[Voice Changer] Prepare Model of slot skip:", slot)
|
||||
return self.get_info()
|
||||
modelSlot = self.settings.modelSlots[slot]
|
||||
allModelSlots = self.modelSlotManager.getAllSlotInfo()
|
||||
modelSlot = allModelSlots[slot]
|
||||
|
||||
print("[Voice Changer] Prepare Model of slot:", slot)
|
||||
|
||||
@ -208,7 +216,6 @@ class RVC:
|
||||
)
|
||||
|
||||
def get_info(self):
|
||||
self.settings.modelSlots = loadAllSlotInfo(self.params.model_dir)
|
||||
data = asdict(self.settings)
|
||||
if self.pipeline is not None:
|
||||
pipelineInfo = self.pipeline.getPipelineInfo()
|
||||
@ -293,9 +300,15 @@ class RVC:
|
||||
f0_up_key = self.settings.tran
|
||||
index_rate = self.settings.indexRatio
|
||||
protect = self.settings.protect
|
||||
if_f0 = 1 if self.settings.modelSlots[self.currentSlot].f0 else 0
|
||||
embOutputLayer = self.settings.modelSlots[self.currentSlot].embOutputLayer
|
||||
useFinalProj = self.settings.modelSlots[self.currentSlot].useFinalProj
|
||||
|
||||
# if_f0 = 1 if self.settings.modelSlots[self.currentSlot].f0 else 0
|
||||
# embOutputLayer = self.settings.modelSlots[self.currentSlot].embOutputLayer
|
||||
# useFinalProj = self.settings.modelSlots[self.currentSlot].useFinalProj
|
||||
|
||||
if_f0 = 1 if self.modelSlotManager.get_slot_info(self.currentSlot).f0 else 0
|
||||
embOutputLayer = self.modelSlotManager.get_slot_info(self.currentSlot).embOutputLayer
|
||||
useFinalProj = self.modelSlotManager.get_slot_info(self.currentSlot).useFinalProj
|
||||
|
||||
try:
|
||||
audio_out = self.pipeline.exec(
|
||||
sid,
|
||||
@ -340,7 +353,8 @@ class RVC:
|
||||
pass
|
||||
|
||||
def export2onnx(self):
|
||||
modelSlot = self.settings.modelSlots[self.settings.modelSlotIndex]
|
||||
allModelSlots = self.modelSlotManager.getAllSlotInfo()
|
||||
modelSlot = allModelSlots[self.settings.modelSlotIndex]
|
||||
|
||||
if modelSlot.isONNX:
|
||||
print("[Voice Changer] export2onnx, No pyTorch filepath.")
|
||||
@ -359,7 +373,9 @@ class RVC:
|
||||
merged = merge_model(req)
|
||||
targetSlot = 0
|
||||
if req.slot < 0:
|
||||
targetSlot = len(self.settings.modelSlots) - 1
|
||||
# 最後尾のスロット番号を格納先とする。
|
||||
allModelSlots = self.modelSlotManager.getAllSlotInfo()
|
||||
targetSlot = len(allModelSlots) - 1
|
||||
else:
|
||||
targetSlot = req.slot
|
||||
|
||||
@ -386,47 +402,37 @@ class RVC:
|
||||
self.currentSlot = self.settings.modelSlotIndex
|
||||
|
||||
def update_model_default(self):
|
||||
print("[Voice Changer] UPDATE MODEL DEFAULT!!")
|
||||
slotDir = os.path.join(self.params.model_dir, str(self.currentSlot))
|
||||
params = json.load(open(os.path.join(slotDir, "params.json"), "r", encoding="utf-8"))
|
||||
params["defaultTune"] = self.settings.tran
|
||||
params["defaultIndexRatio"] = self.settings.indexRatio
|
||||
params["defaultProtect"] = self.settings.protect
|
||||
|
||||
json.dump(params, open(os.path.join(slotDir, "params.json"), "w"))
|
||||
self.settings.modelSlots = loadAllSlotInfo(self.params.model_dir)
|
||||
# {"slot":9,"key":"name","val":"dogsdododg"}
|
||||
self.modelSlotManager.update_model_info(
|
||||
json.dumps(
|
||||
{
|
||||
"slot": self.currentSlot,
|
||||
"key": "defaultTune",
|
||||
"val": self.settings.tran,
|
||||
}
|
||||
)
|
||||
)
|
||||
self.modelSlotManager.update_model_info(
|
||||
json.dumps(
|
||||
{
|
||||
"slot": self.currentSlot,
|
||||
"key": "defaultIndexRatio",
|
||||
"val": self.settings.indexRatio,
|
||||
}
|
||||
)
|
||||
)
|
||||
self.modelSlotManager.update_model_info(
|
||||
json.dumps(
|
||||
{
|
||||
"slot": self.currentSlot,
|
||||
"key": "defaultProtect",
|
||||
"val": self.settings.protect,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
def update_model_info(self, newData: str):
|
||||
print("[Voice Changer] UPDATE MODEL INFO", newData)
|
||||
newDataDict = json.loads(newData)
|
||||
try:
|
||||
slotDir = os.path.join(self.params.model_dir, str(newDataDict["slot"]))
|
||||
except Exception as e:
|
||||
print("Exception::::", e)
|
||||
params = json.load(open(os.path.join(slotDir, "params.json"), "r", encoding="utf-8"))
|
||||
params[newDataDict["key"]] = newDataDict["val"]
|
||||
json.dump(params, open(os.path.join(slotDir, "params.json"), "w"))
|
||||
self.settings.modelSlots = loadAllSlotInfo(self.params.model_dir)
|
||||
self.modelSlotManager.update_model_info(newData)
|
||||
|
||||
def upload_model_assets(self, params: str):
|
||||
print("[Voice Changer] UPLOAD ASSETS", params)
|
||||
paramsDict = json.loads(params)
|
||||
uploadPath = os.path.join(UPLOAD_DIR, paramsDict["file"])
|
||||
storeDir = os.path.join(self.params.model_dir, str(paramsDict["slot"]))
|
||||
storePath = os.path.join(
|
||||
storeDir,
|
||||
paramsDict["file"],
|
||||
)
|
||||
storeJson = os.path.join(
|
||||
storeDir,
|
||||
"params.json",
|
||||
)
|
||||
try:
|
||||
shutil.move(uploadPath, storePath)
|
||||
params = json.load(open(storeJson, "r", encoding="utf-8"))
|
||||
params[paramsDict["name"]] = storePath # type:ignore
|
||||
json.dump(params, open(storeJson, "w"))
|
||||
except Exception as e:
|
||||
print("Exception::::", e)
|
||||
|
||||
self.settings.modelSlots = loadAllSlotInfo(self.params.model_dir)
|
||||
self.modelSlotManager.store_model_assets(params)
|
||||
|
@ -1,7 +1,8 @@
|
||||
from dataclasses import dataclass, field
|
||||
from ModelSample import RVCModelSample
|
||||
from const import MAX_SLOT_NUM
|
||||
from data.ModelSlot import ModelSlot, ModelSlots
|
||||
|
||||
# from const import MAX_SLOT_NUM
|
||||
# from data.ModelSlot import ModelSlot, ModelSlots
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -16,7 +17,7 @@ class RVCSettings:
|
||||
clusterInferRatio: float = 0.1
|
||||
|
||||
framework: str = "PyTorch" # PyTorch or ONNX
|
||||
modelSlots: list[ModelSlots] = field(default_factory=lambda: [ModelSlot() for _x in range(MAX_SLOT_NUM)])
|
||||
# modelSlots: list[ModelSlots] = field(default_factory=lambda: [ModelSlot() for _x in range(MAX_SLOT_NUM)])
|
||||
|
||||
sampleModels: list[RVCModelSample] = field(default_factory=lambda: [])
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import numpy as np
|
||||
from data.ModelSlot import loadAllSlotInfo
|
||||
from utils.downloader.SampleDownloader import downloadSample
|
||||
from voice_changer.Local.ServerDevice import ServerDevice, ServerDeviceCallbacks
|
||||
from voice_changer.VoiceChanger import VoiceChanger
|
||||
@ -95,6 +96,7 @@ class VoiceChangerManager(ServerDeviceCallbacks):
|
||||
def get_info(self):
|
||||
data = asdict(self.settings)
|
||||
data["gpus"] = self.gpus
|
||||
data["modelSlots"] = loadAllSlotInfo(self.params.model_dir)
|
||||
|
||||
data["status"] = "OK"
|
||||
|
||||
@ -143,6 +145,9 @@ class VoiceChangerManager(ServerDeviceCallbacks):
|
||||
self.voiceChanger.merge_models(request)
|
||||
return self.get_info()
|
||||
|
||||
def setEmitTo(self, emitTo: Callable[[Any], None]):
|
||||
self.emitToFunc = emitTo
|
||||
|
||||
def update_model_default(self):
|
||||
self.voiceChanger.update_model_default()
|
||||
return self.get_info()
|
||||
@ -154,6 +159,3 @@ class VoiceChangerManager(ServerDeviceCallbacks):
|
||||
def upload_model_assets(self, params: str):
|
||||
self.voiceChanger.upload_model_assets(params)
|
||||
return self.get_info()
|
||||
|
||||
def setEmitTo(self, emitTo: Callable[[Any], None]):
|
||||
self.emitToFunc = emitTo
|
||||
|
Loading…
Reference in New Issue
Block a user