gui improvement

This commit is contained in:
w-okada 2023-07-22 13:23:43 +09:00
parent acab6644f7
commit 20e7a472be
7 changed files with 1322 additions and 246 deletions

View File

@ -1 +1,10 @@
<!doctype html><html style="width:100%;height:100%;overflow:hidden"><head><meta charset="utf-8"/><title>Voice Changer Client Demo</title><script defer="defer" src="index.js"></script></head><body style="width:100%;height:100%;margin:0"><div id="app" style="width:100%;height:100%"></div></body></html>
<!DOCTYPE html>
<html style="width: 100%; height: 100%; overflow: hidden">
<head>
<meta charset="utf-8" />
<title>Voice Changer Client Demo</title>
<script defer src="index.js"></script></head>
<body style="width: 100%; height: 100%; margin: 0px">
<div id="app" style="width: 100%; height: 100%"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -1,31 +0,0 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

View File

@ -144,7 +144,7 @@ export const GuiStateProvider = ({ children }: Props) => {
deviceId: "screen",
groupId: "screen",
kind: "audioinput",
label: "screen",
label: "system(only win)",
toJSON: () => {},
});
const audioOutputs = mediaDeviceInfos.filter((x) => {

View File

@ -6,33 +6,33 @@ import { ModelSlotManagerDialogScreen } from "./904_ModelSlotManagerDialog";
import { checkExtention, trimfileName } from "../../utils/utils";
export type FileUploaderScreenProps = {
screen: ModelSlotManagerDialogScreen
targetIndex: number
close: () => void
backToSlotManager: () => void
}
screen: ModelSlotManagerDialogScreen;
targetIndex: number;
close: () => void;
backToSlotManager: () => void;
};
export const FileUploaderScreen = (props: FileUploaderScreenProps) => {
const { serverSetting } = useAppState()
const [voiceChangerType, setVoiceChangerType] = useState<VoiceChangerType>("RVC")
const [uploadSetting, setUploadSetting] = useState<ModelUploadSetting>()
const messageBuilderState = useMessageBuilder()
const { serverSetting } = useAppState();
const [voiceChangerType, setVoiceChangerType] = useState<VoiceChangerType>("RVC");
const [uploadSetting, setUploadSetting] = useState<ModelUploadSetting>();
const messageBuilderState = useMessageBuilder();
useMemo(() => {
messageBuilderState.setMessage(__filename, "header_message", { "ja": "ファイルをアップロードしてください. 対象:", "en": "Upload Files for " })
messageBuilderState.setMessage(__filename, "back", { "ja": "戻る", "en": "back" })
messageBuilderState.setMessage(__filename, "select", { "ja": "ファイル選択", "en": "select file" })
messageBuilderState.setMessage(__filename, "upload", { "ja": "アップロード", "en": "upload" })
messageBuilderState.setMessage(__filename, "uploading", { "ja": "アップロード中", "en": "uploading" })
messageBuilderState.setMessage(__filename, "header_message", { ja: "ファイルをアップロードしてください. 対象:", en: "Upload Files for " });
messageBuilderState.setMessage(__filename, "back", { ja: "戻る", en: "back" });
messageBuilderState.setMessage(__filename, "select", { ja: "ファイル選択", en: "select file" });
messageBuilderState.setMessage(__filename, "upload", { ja: "アップロード", en: "upload" });
messageBuilderState.setMessage(__filename, "uploading", { ja: "アップロード中", en: "uploading" });
messageBuilderState.setMessage(__filename, "alert-model-ext", {
"ja": "ファイルの拡張子は次のモノである必要があります。",
"en": "extension of file should be the following."
})
ja: "ファイルの拡張子は次のモノである必要があります。",
en: "extension of file should be the following.",
});
messageBuilderState.setMessage(__filename, "alert-model-file", {
"ja": "ファイルが選択されていません",
"en": "file is not selected."
})
}, [])
ja: "ファイルが選択されていません",
en: "file is not selected.",
});
}, []);
useEffect(() => {
setUploadSetting({
@ -41,167 +41,198 @@ export const FileUploaderScreen = (props: FileUploaderScreenProps) => {
isSampleMode: false,
sampleId: null,
files: [],
params: {}
})
}, [props.targetIndex, voiceChangerType])
params: {},
});
}, [props.targetIndex, voiceChangerType]);
const screen = useMemo(() => {
if (props.screen != "FileUploader") {
return <></>
return <></>;
}
const vcTypeOptions = (
Object.values(VoiceChangerType).map(x => {
return <option key={x} value={x}>{x}</option>
})
)
const vcTypeOptions = Object.values(VoiceChangerType).map((x) => {
return (
<option key={x} value={x}>
{x}
</option>
);
});
const checkModelSetting = (setting: ModelUploadSetting) => {
if (setting.voiceChangerType == "RVC") {
const enough = !!setting.files.find(x => { return x.kind == "rvcModel" })
return enough
const enough = !!setting.files.find((x) => {
return x.kind == "rvcModel";
});
return enough;
} else if (setting.voiceChangerType == "MMVCv13") {
const enough = !!setting.files.find(x => { return x.kind == "mmvcv13Model" }) &&
!!setting.files.find(x => { return x.kind == "mmvcv13Config" })
return enough
const enough =
!!setting.files.find((x) => {
return x.kind == "mmvcv13Model";
}) &&
!!setting.files.find((x) => {
return x.kind == "mmvcv13Config";
});
return enough;
} else if (setting.voiceChangerType == "MMVCv15") {
const enough = !!setting.files.find(x => { return x.kind == "mmvcv15Model" }) &&
!!setting.files.find(x => { return x.kind == "mmvcv15Config" })
return enough
const enough =
!!setting.files.find((x) => {
return x.kind == "mmvcv15Model";
}) &&
!!setting.files.find((x) => {
return x.kind == "mmvcv15Config";
});
return enough;
} else if (setting.voiceChangerType == "so-vits-svc-40") {
const enough = !!setting.files.find(x => { return x.kind == "soVitsSvc40Config" }) &&
!!setting.files.find(x => { return x.kind == "soVitsSvc40Model" })
return enough
const enough =
!!setting.files.find((x) => {
return x.kind == "soVitsSvc40Config";
}) &&
!!setting.files.find((x) => {
return x.kind == "soVitsSvc40Model";
});
return enough;
} else if (setting.voiceChangerType == "DDSP-SVC") {
const enough = !!setting.files.find(x => { return x.kind == "ddspSvcModel" }) &&
!!setting.files.find(x => { return x.kind == "ddspSvcModelConfig" }) &&
!!setting.files.find(x => { return x.kind == "ddspSvcDiffusion" }) &&
!!setting.files.find(x => { return x.kind == "ddspSvcDiffusionConfig" })
return enough
const enough =
!!setting.files.find((x) => {
return x.kind == "ddspSvcModel";
}) &&
!!setting.files.find((x) => {
return x.kind == "ddspSvcModelConfig";
}) &&
!!setting.files.find((x) => {
return x.kind == "ddspSvcDiffusion";
}) &&
!!setting.files.find((x) => {
return x.kind == "ddspSvcDiffusionConfig";
});
return enough;
} else if (setting.voiceChangerType == "Diffusion-SVC") {
const enough = !!setting.files.find(x => { return x.kind == "diffusionSVCModel" })
return enough
}
return false
const enough = !!setting.files.find((x) => {
return x.kind == "diffusionSVCModel";
});
return enough;
}
return false;
};
const generateFileRow = (setting: ModelUploadSetting, title: string, kind: ModelFileKind, ext: string[], dir: string = "") => {
const selectedFile = setting.files.find(x => { return x.kind == kind })
const selectedFilename = selectedFile?.file.name || ""
const selectedFile = setting.files.find((x) => {
return x.kind == kind;
});
const selectedFilename = selectedFile?.file.name || "";
return (
<div key={`${title}`} className="file-uploader-file-select-row">
<div className="file-uploader-file-select-row-label">{title}:</div>
<div className="file-uploader-file-select-row-value" >
{trimfileName(selectedFilename, 30)}
</div>
<div className="file-uploader-file-select-row-button" onClick={async () => {
const file = await fileSelector("")
<div className="file-uploader-file-select-row-value">{trimfileName(selectedFilename, 30)}</div>
<div
className="file-uploader-file-select-row-button"
onClick={async () => {
const file = await fileSelector("");
if (checkExtention(file.name, ext) == false) {
const alertMessage = `${messageBuilderState.getMessage(__filename, "alert-model-ext")} ${ext}`
alert(alertMessage)
return
const alertMessage = `${messageBuilderState.getMessage(__filename, "alert-model-ext")} ${ext}`;
alert(alertMessage);
return;
}
if (selectedFile) {
selectedFile.file = file
selectedFile.file = file;
} else {
setting.files.push({ kind: kind, file: file, dir: dir })
setting.files.push({ kind: kind, file: file, dir: dir });
}
setUploadSetting({ ...setting })
}}>
setUploadSetting({ ...setting });
}}
>
{messageBuilderState.getMessage(__filename, "select")}
</div>
</div>
)
}
);
};
const generateFileRowsByVCType = (vcType: VoiceChangerType) => {
const rows: JSX.Element[] = []
const rows: JSX.Element[] = [];
if (vcType == "RVC") {
rows.push(generateFileRow(uploadSetting!, "Model", "rvcModel", ["pth", "onnx"]))
rows.push(generateFileRow(uploadSetting!, "Index", "rvcIndex", ["index", "bin"]))
rows.push(generateFileRow(uploadSetting!, "Model", "rvcModel", ["pth", "onnx"]));
rows.push(generateFileRow(uploadSetting!, "Index", "rvcIndex", ["index", "bin"]));
} else if (vcType == "MMVCv13") {
rows.push(generateFileRow(uploadSetting!, "Config", "mmvcv13Config", ["json"]))
rows.push(generateFileRow(uploadSetting!, "Model", "mmvcv13Model", ["pth", "onnx"]))
rows.push(generateFileRow(uploadSetting!, "Config", "mmvcv13Config", ["json"]));
rows.push(generateFileRow(uploadSetting!, "Model", "mmvcv13Model", ["pth", "onnx"]));
} else if (vcType == "MMVCv15") {
rows.push(generateFileRow(uploadSetting!, "Config", "mmvcv15Config", ["json"]))
rows.push(generateFileRow(uploadSetting!, "Corres", "mmvcv15Correspondence", ["txt"]))
rows.push(generateFileRow(uploadSetting!, "Model", "mmvcv15Model", ["pth", "onnx"]))
rows.push(generateFileRow(uploadSetting!, "Config", "mmvcv15Config", ["json"]));
rows.push(generateFileRow(uploadSetting!, "Corres", "mmvcv15Correspondence", ["txt"]));
rows.push(generateFileRow(uploadSetting!, "Model", "mmvcv15Model", ["pth", "onnx"]));
} else if (vcType == "so-vits-svc-40") {
rows.push(generateFileRow(uploadSetting!, "Config", "soVitsSvc40Config", ["json"]))
rows.push(generateFileRow(uploadSetting!, "Model", "soVitsSvc40Model", ["pth"]))
rows.push(generateFileRow(uploadSetting!, "Cluster", "soVitsSvc40Cluster", ["pth", "pt"]))
rows.push(generateFileRow(uploadSetting!, "Config", "soVitsSvc40Config", ["json"]));
rows.push(generateFileRow(uploadSetting!, "Model", "soVitsSvc40Model", ["pth"]));
rows.push(generateFileRow(uploadSetting!, "Cluster", "soVitsSvc40Cluster", ["pth", "pt"]));
} else if (vcType == "DDSP-SVC") {
rows.push(generateFileRow(uploadSetting!, "Config", "ddspSvcModelConfig", ["yaml"], "model/"))
rows.push(generateFileRow(uploadSetting!, "Model", "ddspSvcModel", ["pth", "pt"], "model/"))
rows.push(generateFileRow(uploadSetting!, "Config(diff)", "ddspSvcDiffusionConfig", ["yaml"], "diff/"))
rows.push(generateFileRow(uploadSetting!, "Model(diff)", "ddspSvcDiffusion", ["pth", "pt"], "diff/"))
} else if(vcType == "Diffusion-SVC") {
rows.push(generateFileRow(uploadSetting!, "Model", "diffusionSVCModel", ["ptc"]))
rows.push(generateFileRow(uploadSetting!, "Config", "ddspSvcModelConfig", ["yaml"], "model/"));
rows.push(generateFileRow(uploadSetting!, "Model", "ddspSvcModel", ["pth", "pt"], "model/"));
rows.push(generateFileRow(uploadSetting!, "Config(diff)", "ddspSvcDiffusionConfig", ["yaml"], "diff/"));
rows.push(generateFileRow(uploadSetting!, "Model(diff)", "ddspSvcDiffusion", ["pth", "pt"], "diff/"));
} else if (vcType == "Diffusion-SVC") {
rows.push(generateFileRow(uploadSetting!, "Model(combo)", "diffusionSVCModel", ["ptc"]));
}
return rows
}
const fileRows = generateFileRowsByVCType(voiceChangerType)
return rows;
};
const fileRows = generateFileRowsByVCType(voiceChangerType);
// appState.serverSetting.uploadProgress == 0 ? `loading model...(wait about 20sec)` : `processing.... ${appState.serverSetting.uploadProgress.toFixed(1)}%` : ""
const buttonLabel = serverSetting.uploadProgress == 0 ?
messageBuilderState.getMessage(__filename, "upload") :
messageBuilderState.getMessage(__filename, "uploading") + `(${serverSetting.uploadProgress.toFixed(1)}%)`
const buttonLabel = serverSetting.uploadProgress == 0 ? messageBuilderState.getMessage(__filename, "upload") : messageBuilderState.getMessage(__filename, "uploading") + `(${serverSetting.uploadProgress.toFixed(1)}%)`;
return (
<div className="dialog-frame">
<div className="dialog-title">File Uploader</div>
<div className="dialog-fixed-size-content">
<div className="file-uploader-header">
{messageBuilderState.getMessage(__filename, "header_message")} Slot[{props.targetIndex}]
<span onClick={() => {
props.backToSlotManager()
}} className="file-uploader-header-button">&lt;&lt;{messageBuilderState.getMessage(__filename, "back")}</span></div>
<div className="file-uploader-voice-changer-select" >VoiceChangerType:
<select value={voiceChangerType} onChange={(e) => {
setVoiceChangerType(e.target.value as VoiceChangerType)
}}>
<span
onClick={() => {
props.backToSlotManager();
}}
className="file-uploader-header-button"
>
&lt;&lt;{messageBuilderState.getMessage(__filename, "back")}
</span>
</div>
<div className="file-uploader-voice-changer-select">
VoiceChangerType:
<select
value={voiceChangerType}
onChange={(e) => {
setVoiceChangerType(e.target.value as VoiceChangerType);
}}
>
{vcTypeOptions}
</select>
</div>
<div className="file-uploader-file-select-container">
{fileRows}
</div>
<div className="file-uploader-file-select-container">{fileRows}</div>
<div className="file-uploader-file-select-upload-button-container">
<div className="file-uploader-file-select-upload-button" onClick={() => {
<div
className="file-uploader-file-select-upload-button"
onClick={() => {
if (!uploadSetting) {
return
return;
}
if (serverSetting.uploadProgress != 0) {
return
return;
}
if (checkModelSetting(uploadSetting)) {
serverSetting.uploadModel(uploadSetting).then(() => {
props.backToSlotManager()
})
props.backToSlotManager();
});
} else {
const errorMessage = messageBuilderState.getMessage(__filename, "alert-model-file")
alert(errorMessage)
const errorMessage = messageBuilderState.getMessage(__filename, "alert-model-file");
alert(errorMessage);
}
}}>
}}
>
{buttonLabel}
</div>
</div>
</div>
</div>
)
}, [
props.screen,
props.targetIndex,
voiceChangerType,
uploadSetting,
serverSetting.uploadModel,
serverSetting.uploadProgress
])
);
}, [props.screen, props.targetIndex, voiceChangerType, uploadSetting, serverSetting.uploadModel, serverSetting.uploadProgress]);
return screen;
};

View File

@ -883,10 +883,10 @@ body {
flex-direction: row;
margin: 0.2rem;
.file-uploader-file-select-row-label {
width: 5rem;
width: 10rem;
}
.file-uploader-file-select-row-value {
width: 20rem;
width: 15rem;
color: #f00;
white-space: nowrap;
}

View File

@ -1,76 +0,0 @@
{
"Diffusion-SVC": [
{
"id": "diffusion_combo_spk5_nl3_dl20_k50_500ep",
"voiceChangerType": "Diffusion-SVC",
"lang": "ja-JP",
"tag": ["diffsuion-svc", "torch"],
"name": "初期メン(3,20)",
"modelUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/diffusion-svc/combo_spk5_nl3_dl20_k50_500ep.ptc.bin",
"termsOfUseUrl": "https://huggingface.co/wok000/vcclient_model/raw/main/diffusion-svc/term_of_use.txt",
"icon": "https://huggingface.co/wok000/vcclient_model/resolve/main/diffusion-svc/diffusion-svc.png",
"credit": "あみたろ,つくよみちゃん,黄琴海月,黄琴まひろ,刻鳴時雨",
"description": "",
"sampleRate": 44100,
"modelType": "combo",
"f0": true,
"numOfDiffLayers":20,
"numOfNativeLayers":3,
"maxKStep":50
},
{
"id": "diffusion_combo_spk5_nl3_dl10_k50_500ep",
"voiceChangerType": "Diffusion-SVC",
"lang": "ja-JP",
"tag": ["diffsuion-svc", "torch"],
"name": "初期メン(3,10)",
"modelUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/diffusion-svc/combo_spk5_nl3_dl10_k50_500ep.ptc.bin",
"termsOfUseUrl": "https://huggingface.co/wok000/vcclient_model/raw/main/diffusion-svc/term_of_use.txt",
"icon": "https://huggingface.co/wok000/vcclient_model/resolve/main/diffusion-svc/diffusion-svc.png",
"credit": "あみたろ,つくよみちゃん,黄琴海月,黄琴まひろ,刻鳴時雨",
"description": "",
"sampleRate": 44100,
"modelType": "combo",
"f0": true,
"numOfDiffLayers":10,
"numOfNativeLayers":3,
"maxKStep":50
},
{
"id": "diffusion_combo_spk5_nl3_dl1_k50_500ep",
"voiceChangerType": "Diffusion-SVC",
"lang": "ja-JP",
"tag": ["diffsuion-svc", "torch"],
"name": "初期メン(3,1)",
"modelUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/diffusion-svc/combo_spk5_nl3_dl1_k50_500ep.ptc.bin",
"termsOfUseUrl": "https://huggingface.co/wok000/vcclient_model/raw/main/diffusion-svc/term_of_use.txt",
"icon": "https://huggingface.co/wok000/vcclient_model/resolve/main/diffusion-svc/diffusion-svc.png",
"credit": "あみたろ,つくよみちゃん,黄琴海月,黄琴まひろ,刻鳴時雨",
"description": "",
"sampleRate": 44100,
"modelType": "combo",
"f0": true,
"numOfDiffLayers":1,
"numOfNativeLayers":3,
"maxKStep":50
},
{
"id": "diffusion_combo_spk5_nl1_dl1_k50_500ep",
"voiceChangerType": "Diffusion-SVC",
"lang": "ja-JP",
"tag": ["diffsuion-svc", "torch"],
"name": "初期メン(1,1)",
"modelUrl": "https://huggingface.co/wok000/vcclient_model/resolve/main/diffusion-svc/combo_spk5_nl1_dl1_k50_500ep.ptc.bin",
"termsOfUseUrl": "https://huggingface.co/wok000/vcclient_model/raw/main/diffusion-svc/term_of_use.txt",
"icon": "https://huggingface.co/wok000/vcclient_model/resolve/main/diffusion-svc/diffusion-svc.png",
"credit": "あみたろ,つくよみちゃん,黄琴海月,黄琴まひろ,刻鳴時雨",
"description": "",
"sampleRate": 44100,
"modelType": "combo",
"f0": true,
"numOfDiffLayers":1,
"numOfNativeLayers":1,
"maxKStep":50
}
]
}