separate rest client

This commit is contained in:
w-okada 2023-09-27 02:24:44 +09:00
parent 3ef54e979b
commit b4b1001b70
7 changed files with 12239 additions and 9414 deletions

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@
"build:dev": "npm-run-all build:worklet:dev clean webpack:dev",
"build:prod": "npm-run-all build:worklet:prod clean webpack:prod",
"release": "npm version patch && npm publish --access=public",
"test": "echo \"Error: no test specified\" && exit 1"
"test": "jest"
},
"keywords": [
"voice conversion"
@ -27,6 +27,7 @@
"license": "ISC",
"devDependencies": {
"@types/audioworklet": "^0.0.50",
"@types/jest": "^29.5.5",
"@types/node": "^20.6.3",
"@types/react": "18.2.22",
"@types/react-dom": "18.2.7",
@ -35,6 +36,7 @@
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-webpack-plugin": "^4.0.1",
"jest": "^29.7.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.3",
"raw-loader": "^4.0.2",

View File

@ -40,7 +40,7 @@ export class VoiceChangerClient {
constructor(ctx: AudioContext, vfEnable: boolean, voiceChangerWorkletListener: VoiceChangerWorkletListener) {
this.sem.enqueue(0);
this.configurator = new ServerConfigurator();
this.configurator = new ServerConfigurator("");
this.ctx = ctx;
this.vfEnable = vfEnable;
this.promiseForInitialize = new Promise<void>(async (resolve) => {
@ -228,7 +228,7 @@ export class VoiceChangerClient {
}
}
this.vcInNode.updateSetting({ ...this.vcInNode.getSettings(), serverUrl: url });
this.configurator.setServerUrl(url);
this.configurator = new ServerConfigurator(url);
};
updateClientSetting = async (setting: VoiceChangerClientSetting) => {

View File

@ -1,277 +1,62 @@
import { MergeModelRequest, OnnxExporterInfo, ServerInfo, ServerSettingKey } from "../const";
import { MergeModelRequest, ServerSettingKey } from "../const";
import { ServerRestClient } from "./ServerRestClient";
type FileChunk = {
hash: number;
chunk: ArrayBuffer;
};
export class ServerConfigurator {
private serverUrl = "";
private restClient;
setServerUrl = (serverUrl: string) => {
this.serverUrl = serverUrl;
console.log(`[ServerConfigurator] Server URL: ${this.serverUrl}`);
};
constructor(serverUrl: string) {
this.restClient = new ServerRestClient(serverUrl);
}
getSettings = async () => {
const url = this.serverUrl + "/info";
const info = await new Promise<ServerInfo>((resolve) => {
const request = new Request(url, {
method: "GET",
});
fetch(request).then(async (response) => {
const json = (await response.json()) as ServerInfo;
resolve(json);
});
});
return info;
return this.restClient.getSettings();
};
getPerformance = async () => {
const url = this.serverUrl + "/performance";
const info = await new Promise<number[]>((resolve) => {
const request = new Request(url, {
method: "GET",
});
fetch(request).then(async (response) => {
const json = (await response.json()) as number[];
resolve(json);
});
});
return info;
return this.restClient.getPerformance();
};
updateSettings = async (key: ServerSettingKey, val: string) => {
const url = this.serverUrl + "/update_settings";
const info = await new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("key", key);
formData.append("val", val);
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
resolve(res);
});
return info;
return this.restClient.updateSettings(key, val);
};
uploadFile2 = async (dir: string, file: File, onprogress: (progress: number, end: boolean) => void) => {
const url = this.serverUrl + "/upload_file";
onprogress(0, false);
const size = 1024 * 1024;
let index = 0; // index値
const fileLength = file.size;
const filename = dir + file.name;
const fileChunkNum = Math.ceil(fileLength / size);
while (true) {
const promises: Promise<void>[] = [];
for (let i = 0; i < 10; i++) {
if (index * size >= fileLength) {
break;
}
const chunk = file.slice(index * size, (index + 1) * size);
const p = new Promise<void>((resolve) => {
const formData = new FormData();
formData.append("file", new Blob([chunk]));
formData.append("filename", `${filename}_${index}`);
const request = new Request(url, {
method: "POST",
body: formData,
});
fetch(request).then(async (_response) => {
// console.log(await response.text())
resolve();
});
});
index += 1;
promises.push(p);
}
await Promise.all(promises);
if (index * size >= fileLength) {
break;
}
onprogress(Math.floor((index / (fileChunkNum + 1)) * 100), false);
}
return fileChunkNum;
return this.restClient.uploadFile2(dir, file, onprogress);
};
uploadFile = async (buf: ArrayBuffer, filename: string, onprogress: (progress: number, end: boolean) => void) => {
const url = this.serverUrl + "/upload_file";
onprogress(0, false);
const size = 1024 * 1024;
const fileChunks: FileChunk[] = [];
let index = 0; // index値
for (let cur = 0; cur < buf.byteLength; cur += size) {
fileChunks.push({
hash: index++,
chunk: buf.slice(cur, cur + size),
});
}
const chunkNum = fileChunks.length;
// console.log("FILE_CHUNKS:", chunkNum, fileChunks)
while (true) {
const promises: Promise<void>[] = [];
for (let i = 0; i < 10; i++) {
const chunk = fileChunks.shift();
if (!chunk) {
break;
}
const p = new Promise<void>((resolve) => {
const formData = new FormData();
formData.append("file", new Blob([chunk.chunk]));
formData.append("filename", `${filename}_${chunk.hash}`);
const request = new Request(url, {
method: "POST",
body: formData,
});
fetch(request).then(async (_response) => {
// console.log(await response.text())
resolve();
});
});
promises.push(p);
}
await Promise.all(promises);
if (fileChunks.length == 0) {
break;
}
onprogress(Math.floor(((chunkNum - fileChunks.length) / (chunkNum + 1)) * 100), false);
}
return chunkNum;
return this.restClient.uploadFile(buf, filename, onprogress);
};
concatUploadedFile = async (filename: string, chunkNum: number) => {
const url = this.serverUrl + "/concat_uploaded_file";
await new Promise<void>((resolve) => {
const formData = new FormData();
formData.append("filename", filename);
formData.append("filenameChunkNum", "" + chunkNum);
const request = new Request(url, {
method: "POST",
body: formData,
});
fetch(request).then(async (response) => {
console.log(await response.text());
resolve();
});
});
return this.restClient.concatUploadedFile(filename, chunkNum);
};
loadModel = async (slot: number, isHalf: boolean, params: string = "{}") => {
if (isHalf == undefined || isHalf == null) {
console.warn("isHalf is invalid value", isHalf);
isHalf = false;
}
const url = this.serverUrl + "/load_model";
const info = new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("slot", "" + slot);
formData.append("isHalf", "" + isHalf);
formData.append("params", params);
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
resolve(res);
});
return await info;
return this.restClient.loadModel(slot, isHalf, params);
};
uploadAssets = async (params: string) => {
const url = this.serverUrl + "/upload_model_assets";
const info = new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("params", params);
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
resolve(res);
});
return await info;
return this.restClient.uploadAssets(params);
};
getModelType = async () => {
const url = this.serverUrl + "/model_type";
const info = new Promise<ServerInfo>(async (resolve) => {
const request = new Request(url, {
method: "GET",
});
const res = (await (await fetch(request)).json()) as ServerInfo;
resolve(res);
});
return await info;
return this.restClient.getModelType();
};
export2onnx = async () => {
const url = this.serverUrl + "/onnx";
const info = new Promise<OnnxExporterInfo>(async (resolve) => {
const request = new Request(url, {
method: "GET",
});
const res = (await (await fetch(request)).json()) as OnnxExporterInfo;
resolve(res);
});
return await info;
return this.restClient.export2onnx();
};
mergeModel = async (req: MergeModelRequest) => {
const url = this.serverUrl + "/merge_model";
const info = new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("request", JSON.stringify(req));
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
console.log("RESPONSE", res);
resolve(res);
});
return await info;
return this.restClient.mergeModel(req);
};
updateModelDefault = async () => {
const url = this.serverUrl + "/update_model_default";
const info = new Promise<ServerInfo>(async (resolve) => {
const request = new Request(url, {
method: "POST",
});
const res = (await (await fetch(request)).json()) as ServerInfo;
console.log("RESPONSE", res);
resolve(res);
});
return await info;
return this.restClient.updateModelDefault();
};
updateModelInfo = async (slot: number, key: string, val: string) => {
const url = this.serverUrl + "/update_model_info";
const newData = { slot, key, val };
const info = new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("newData", JSON.stringify(newData));
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
console.log("RESPONSE", res);
resolve(res);
});
return await info;
return this.restClient.updateModelInfo(slot, key, val);
};
}

View File

@ -0,0 +1,313 @@
import { MergeModelRequest, OnnxExporterInfo, ServerInfo, ServerSettingKey } from "../const";
type FileChunk = {
hash: number;
chunk: ArrayBuffer;
};
export class ServerRestClient {
private serverUrl = "";
constructor(serverUrl: string) {
this.serverUrl = serverUrl;
}
getSettings = async () => {
const url = this.serverUrl + "/info";
const info = await new Promise<ServerInfo>((resolve) => {
const request = new Request(url, {
method: "GET",
});
fetch(request).then(async (response) => {
const json = (await response.json()) as ServerInfo;
resolve(json);
});
});
return info;
};
getPerformance = async () => {
const url = this.serverUrl + "/performance";
const info = await new Promise<number[]>((resolve) => {
const request = new Request(url, {
method: "GET",
});
fetch(request).then(async (response) => {
const json = (await response.json()) as number[];
resolve(json);
});
});
return info;
};
updateSettings = async (key: ServerSettingKey, val: string) => {
const url = this.serverUrl + "/update_settings";
const info = await new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("key", key);
formData.append("val", val);
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
resolve(res);
});
return info;
};
uploadFile2 = async (dir: string, file: File, onprogress: (progress: number, end: boolean) => void) => {
const url = this.serverUrl + "/upload_file";
onprogress(0, false);
const size = 1024 * 1024;
let index = 0; // index値
const fileLength = file.size;
const filename = dir + file.name;
const fileChunkNum = Math.ceil(fileLength / size);
while (true) {
const promises: Promise<void>[] = [];
for (let i = 0; i < 10; i++) {
if (index * size >= fileLength) {
break;
}
const chunk = file.slice(index * size, (index + 1) * size);
const p = new Promise<void>((resolve) => {
const formData = new FormData();
formData.append("file", new Blob([chunk]));
formData.append("filename", `${filename}_${index}`);
const request = new Request(url, {
method: "POST",
body: formData,
});
fetch(request).then(async (_response) => {
// console.log(await response.text())
resolve();
});
});
index += 1;
promises.push(p);
}
await Promise.all(promises);
if (index * size >= fileLength) {
break;
}
onprogress(Math.floor((index / (fileChunkNum + 1)) * 100), false);
}
return fileChunkNum;
};
uploadFile = async (buf: ArrayBuffer, filename: string, onprogress: (progress: number, end: boolean) => void) => {
const url = this.serverUrl + "/upload_file";
onprogress(0, false);
const size = 1024 * 1024;
const fileChunks: FileChunk[] = [];
let index = 0; // index値
for (let cur = 0; cur < buf.byteLength; cur += size) {
fileChunks.push({
hash: index++,
chunk: buf.slice(cur, cur + size),
});
}
const chunkNum = fileChunks.length;
// console.log("FILE_CHUNKS:", chunkNum, fileChunks)
while (true) {
const promises: Promise<void>[] = [];
for (let i = 0; i < 10; i++) {
const chunk = fileChunks.shift();
if (!chunk) {
break;
}
const p = new Promise<void>((resolve) => {
const formData = new FormData();
formData.append("file", new Blob([chunk.chunk]));
formData.append("filename", `${filename}_${chunk.hash}`);
const request = new Request(url, {
method: "POST",
body: formData,
});
fetch(request).then(async (_response) => {
// console.log(await response.text())
resolve();
});
});
promises.push(p);
}
await Promise.all(promises);
if (fileChunks.length == 0) {
break;
}
onprogress(Math.floor(((chunkNum - fileChunks.length) / (chunkNum + 1)) * 100), false);
}
return chunkNum;
};
concatUploadedFile = async (filename: string, chunkNum: number) => {
const url = this.serverUrl + "/concat_uploaded_file";
await new Promise<void>((resolve) => {
const formData = new FormData();
formData.append("filename", filename);
formData.append("filenameChunkNum", "" + chunkNum);
const request = new Request(url, {
method: "POST",
body: formData,
});
fetch(request).then(async (response) => {
console.log(await response.text());
resolve();
});
});
};
loadModel = async (slot: number, isHalf: boolean, params: string = "{}") => {
if (isHalf == undefined || isHalf == null) {
console.warn("isHalf is invalid value", isHalf);
isHalf = false;
}
const url = this.serverUrl + "/load_model";
const info = new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("slot", "" + slot);
formData.append("isHalf", "" + isHalf);
formData.append("params", params);
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
resolve(res);
});
return await info;
};
uploadAssets = async (params: string) => {
const url = this.serverUrl + "/upload_model_assets";
const info = new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("params", params);
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
resolve(res);
});
return await info;
};
getModelType = async () => {
const url = this.serverUrl + "/model_type";
const info = new Promise<ServerInfo>(async (resolve) => {
const request = new Request(url, {
method: "GET",
});
const res = (await (await fetch(request)).json()) as ServerInfo;
resolve(res);
});
return await info;
};
export2onnx = async () => {
const url = this.serverUrl + "/onnx";
const info = new Promise<OnnxExporterInfo>(async (resolve) => {
const request = new Request(url, {
method: "GET",
});
const res = (await (await fetch(request)).json()) as OnnxExporterInfo;
resolve(res);
});
return await info;
};
mergeModel = async (req: MergeModelRequest) => {
const url = this.serverUrl + "/merge_model";
const info = new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("request", JSON.stringify(req));
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
console.log("RESPONSE", res);
resolve(res);
});
return await info;
};
updateModelDefault = async () => {
const url = this.serverUrl + "/update_model_default";
const info = new Promise<ServerInfo>(async (resolve) => {
const request = new Request(url, {
method: "POST",
});
const res = (await (await fetch(request)).json()) as ServerInfo;
console.log("RESPONSE", res);
resolve(res);
});
return await info;
};
updateModelInfo = async (slot: number, key: string, val: string) => {
const url = this.serverUrl + "/update_model_info";
const newData = { slot, key, val };
const info = new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("newData", JSON.stringify(newData));
const request = new Request(url, {
method: "POST",
body: formData,
});
const res = (await (await fetch(request)).json()) as ServerInfo;
console.log("RESPONSE", res);
resolve(res);
});
return await info;
};
// VoiceChangerWorkletNodeから呼び出される
//// Restで音声変換
postVoice = async (timestamp: number, buffer: ArrayBuffer) => {
const url = this.serverUrl + "/test";
const obj = {
timestamp,
buffer: Buffer.from(buffer).toString("base64"),
};
const body = JSON.stringify(obj);
const res = await fetch(`${url}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: body,
});
try {
const receivedJson = await res.json();
const changedVoiceBase64 = receivedJson["changedVoiceBase64"];
const buf = Buffer.from(changedVoiceBase64, "base64");
const ab = new ArrayBuffer(buf.length);
const view = new Uint8Array(ab);
for (let i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return ab;
} catch (e) {
console.log("Exception:", e);
return new ArrayBuffer(10);
}
};
}

View File

@ -0,0 +1,9 @@
describe("test1", () => {
test("test222", () => {
expect(
(() => {
return 1;
})()
).toBe(1);
});
});

View File

@ -2,6 +2,7 @@ import { VoiceChangerWorkletProcessorRequest } from "../@types/voice-changer-wor
import { DefaultClientSettng, DownSamplingMode, VOICE_CHANGER_CLIENT_EXCEPTION, WorkletNodeSetting, WorkletSetting } from "../const";
import { io, Socket } from "socket.io-client";
import { DefaultEventsMap } from "@socket.io/component-emitter";
import { ServerRestClient } from "./ServerRestClient";
export type VoiceChangerWorkletListener = {
notifyVolume: (vol: number) => void;
@ -261,7 +262,8 @@ export class VoiceChangerWorkletNode extends AudioWorkletNode {
// console.log("emit!")
this.socket.emit("request_message", [timestamp, newBuffer.buffer]);
} else {
const res = await postVoice(this.setting.serverUrl + "/test", timestamp, newBuffer.buffer);
const restClient = new ServerRestClient(this.setting.serverUrl);
const res = await restClient.postVoice(timestamp, newBuffer.buffer);
if (res.byteLength < 128 * 2) {
this.listener.notifyException(VOICE_CHANGER_CLIENT_EXCEPTION.ERR_REST_INVALID_RESPONSE, `[REST] recevied data is too short ${res.byteLength}`);
@ -347,35 +349,3 @@ export class VoiceChangerWorkletNode extends AudioWorkletNode {
return samples;
};
}
export const postVoice = async (url: string, timestamp: number, buffer: ArrayBuffer) => {
const obj = {
timestamp,
buffer: Buffer.from(buffer).toString("base64"),
};
const body = JSON.stringify(obj);
const res = await fetch(`${url}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: body,
});
try {
const receivedJson = await res.json();
const changedVoiceBase64 = receivedJson["changedVoiceBase64"];
const buf = Buffer.from(changedVoiceBase64, "base64");
const ab = new ArrayBuffer(buf.length);
const view = new Uint8Array(ab);
for (let i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return ab;
} catch (e) {
console.log("Exception:", e);
return new ArrayBuffer(10);
}
};