diff --git a/README.md b/README.md
index 2fede3c6..fef56b23 100644
--- a/README.md
+++ b/README.md
@@ -259,6 +259,14 @@ Not exactly, the dependencies clash, especially between conda and python (and de
* Potentially needed to install build tools (without Visual Studio): https://visualstudio.microsoft.com/visual-cpp-build-tools/
+### React UI
+
+* Install nodejs (if not already installed with conda)
+* Install react dependencies: `npm install`
+* Build react: `npm run build`
+* Run react: `npm start`
+* Also run the python server: `python server.py` or with `start_(platform)` script
+
## Docker Setup
tts-generation-webui can also be ran inside of a Docker container. To get started, first build the Docker image while in the root directory:
diff --git a/optimize_conda_storage.cmd b/optimize_conda_storage.cmd
new file mode 100644
index 00000000..32f2d290
--- /dev/null
+++ b/optimize_conda_storage.cmd
@@ -0,0 +1,2 @@
+@REM conda clean --all --dry-run
+conda clean --all
diff --git a/react-ui/.gitignore b/react-ui/.gitignore
index 091f0e7b..983d43ca 100644
--- a/react-ui/.gitignore
+++ b/react-ui/.gitignore
@@ -38,5 +38,5 @@ next-env.d.ts
.vscode
# upload cache
-/file-input-cache/
+/public/file-input-cache/
diff --git a/react-ui/package-lock.json b/react-ui/package-lock.json
index 850511b2..974a91e2 100644
--- a/react-ui/package-lock.json
+++ b/react-ui/package-lock.json
@@ -21,6 +21,7 @@
"country-flag-icons": "^1.5.7",
"eslint": "8.40.0",
"eslint-config-next": "13.4.1",
+ "express": "^4.18.2",
"iconv": "^3.0.1",
"music-metadata": "^8.1.4",
"next": "13.4.1",
@@ -32,7 +33,8 @@
"wavesurfer.js": "^7.3.9"
},
"devDependencies": {
- "@types/adm-zip": "^0.5.0"
+ "@types/adm-zip": "^0.5.0",
+ "@types/express": "^4.17.20"
}
},
"node_modules/@alloc/quick-lru": {
@@ -704,11 +706,66 @@
"@types/node": "*"
}
},
+ "node_modules/@types/body-parser": {
+ "version": "1.19.4",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.4.tgz",
+ "integrity": "sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA==",
+ "dev": true,
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.37",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.37.tgz",
+ "integrity": "sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz",
+ "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==",
+ "dev": true,
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.33",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "4.17.39",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.39.tgz",
+ "integrity": "sha512-BiEUfAiGCOllomsRAZOiMFP7LAnrifHpt56pc4Z7l9K6ACyN06Ns1JLMBxwkfLOjJRlSf06NwWsT7yzfpaVpyQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.3.tgz",
+ "integrity": "sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA==",
+ "dev": true
+ },
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
},
+ "node_modules/@types/mime": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.4.tgz",
+ "integrity": "sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw==",
+ "dev": true
+ },
"node_modules/@types/node": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.0.0.tgz",
@@ -724,6 +781,18 @@
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
},
+ "node_modules/@types/qs": {
+ "version": "6.9.9",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz",
+ "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==",
+ "dev": true
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.6.tgz",
+ "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==",
+ "dev": true
+ },
"node_modules/@types/react": {
"version": "18.2.5",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.5.tgz",
@@ -747,6 +816,27 @@
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
},
+ "node_modules/@types/send": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.3.tgz",
+ "integrity": "sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==",
+ "dev": true,
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.15.4",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.4.tgz",
+ "integrity": "sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw==",
+ "dev": true,
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/mime": "*",
+ "@types/node": "*"
+ }
+ },
"node_modules/@typescript-eslint/parser": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.2.tgz",
@@ -843,6 +933,18 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/acorn": {
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
@@ -954,6 +1056,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
"node_modules/array-includes": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
@@ -1125,6 +1232,42 @@
"node": ">=8"
}
},
+ "node_modules/body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/body-parser/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/body-parser/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
"node_modules/bplist-parser": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
@@ -1220,6 +1363,14 @@
"node": ">=10.16.0"
}
},
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -1353,6 +1504,17 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
@@ -1366,6 +1528,19 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
+ "node_modules/cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -1535,6 +1710,23 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -1567,6 +1759,11 @@
"node": ">=6.0.0"
}
},
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
"node_modules/electron-to-chromium": {
"version": "1.4.385",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.385.tgz",
@@ -1577,6 +1774,14 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz",
@@ -1708,6 +1913,11 @@
"node": ">=6"
}
},
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -2142,6 +2352,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/execa": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz",
@@ -2164,6 +2382,60 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
+ "node_modules/express": {
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/express/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/express/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -2251,6 +2523,36 @@
"node": ">=8"
}
},
+ "node_modules/finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/finalhandler/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
@@ -2296,6 +2598,14 @@
"is-callable": "^1.1.3"
}
},
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/fraction.js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
@@ -2308,6 +2618,14 @@
"url": "https://www.patreon.com/infusion"
}
},
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -2583,6 +2901,21 @@
"react-is": "^16.7.0"
}
},
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/human-signals": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
@@ -2600,6 +2933,17 @@
"node": ">=10.0.0"
}
},
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -2677,6 +3021,14 @@
"node": ">= 0.4"
}
},
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@@ -3197,6 +3549,11 @@
"node": ">= 0.8"
}
},
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -3210,6 +3567,14 @@
"node": ">= 8"
}
},
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
@@ -3222,6 +3587,36 @@
"node": ">=8.6"
}
},
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/mimic-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
@@ -3310,6 +3705,14 @@
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
},
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/next": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.1.tgz",
@@ -3563,6 +3966,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -3674,6 +4088,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -3703,6 +4125,11 @@
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
"node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -3897,6 +4324,18 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
@@ -3905,6 +4344,20 @@
"node": ">=6"
}
},
+ "node_modules/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -3924,6 +4377,28 @@
}
]
},
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
@@ -4217,6 +4692,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
@@ -4247,6 +4727,66 @@
"node": ">=10"
}
},
+ "node_modules/send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/send/node_modules/debug/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -4308,6 +4848,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/stop-iteration-iterator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
@@ -4655,6 +5203,14 @@
"node": ">=8.0"
}
},
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
"node_modules/token-types": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz",
@@ -4733,6 +5289,26 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/type-is/node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/typed-array-length": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
@@ -4772,6 +5348,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/untildify": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
@@ -4822,6 +5406,22 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/wavesurfer.js": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-7.3.9.tgz",
@@ -5432,11 +6032,66 @@
"@types/node": "*"
}
},
+ "@types/body-parser": {
+ "version": "1.19.4",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.4.tgz",
+ "integrity": "sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA==",
+ "dev": true,
+ "requires": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "@types/connect": {
+ "version": "3.4.37",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.37.tgz",
+ "integrity": "sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/express": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz",
+ "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==",
+ "dev": true,
+ "requires": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.33",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "@types/express-serve-static-core": {
+ "version": "4.17.39",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.39.tgz",
+ "integrity": "sha512-BiEUfAiGCOllomsRAZOiMFP7LAnrifHpt56pc4Z7l9K6ACyN06Ns1JLMBxwkfLOjJRlSf06NwWsT7yzfpaVpyQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "@types/http-errors": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.3.tgz",
+ "integrity": "sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA==",
+ "dev": true
+ },
"@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
},
+ "@types/mime": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.4.tgz",
+ "integrity": "sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw==",
+ "dev": true
+ },
"@types/node": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.0.0.tgz",
@@ -5452,6 +6107,18 @@
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
},
+ "@types/qs": {
+ "version": "6.9.9",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz",
+ "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==",
+ "dev": true
+ },
+ "@types/range-parser": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.6.tgz",
+ "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==",
+ "dev": true
+ },
"@types/react": {
"version": "18.2.5",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.5.tgz",
@@ -5475,6 +6142,27 @@
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
},
+ "@types/send": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.3.tgz",
+ "integrity": "sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==",
+ "dev": true,
+ "requires": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "@types/serve-static": {
+ "version": "1.15.4",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.4.tgz",
+ "integrity": "sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw==",
+ "dev": true,
+ "requires": {
+ "@types/http-errors": "*",
+ "@types/mime": "*",
+ "@types/node": "*"
+ }
+ },
"@typescript-eslint/parser": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.2.tgz",
@@ -5523,6 +6211,15 @@
"eslint-visitor-keys": "^3.3.0"
}
},
+ "accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "requires": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
"acorn": {
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
@@ -5604,6 +6301,11 @@
"is-array-buffer": "^3.0.1"
}
},
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
"array-includes": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
@@ -5716,6 +6418,40 @@
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
},
+ "body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "requires": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
"bplist-parser": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
@@ -5776,6 +6512,11 @@
"streamsearch": "^1.1.0"
}
},
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ },
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -5862,6 +6603,14 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
+ "content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "requires": {
+ "safe-buffer": "5.2.1"
+ }
+ },
"content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
@@ -5872,6 +6621,16 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
+ "cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
"cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -5993,6 +6752,16 @@
"object-keys": "^1.1.1"
}
},
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
+ },
"didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -6019,6 +6788,11 @@
"esutils": "^2.0.2"
}
},
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
"electron-to-chromium": {
"version": "1.4.385",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.385.tgz",
@@ -6029,6 +6803,11 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
+ },
"enhanced-resolve": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz",
@@ -6136,6 +6915,11 @@
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
},
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
"escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -6454,6 +7238,11 @@
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
},
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
+ },
"execa": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz",
@@ -6470,6 +7259,59 @@
"strip-final-newline": "^3.0.0"
}
},
+ "express": {
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "requires": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -6541,6 +7383,35 @@
"to-regex-range": "^5.0.1"
}
},
+ "finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
"find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
@@ -6577,11 +7448,21 @@
"is-callable": "^1.1.3"
}
},
+ "forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+ },
"fraction.js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
"integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA=="
},
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
+ },
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -6763,6 +7644,18 @@
"react-is": "^16.7.0"
}
},
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ }
+ },
"human-signals": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
@@ -6773,6 +7666,14 @@
"resolved": "https://registry.npmjs.org/iconv/-/iconv-3.0.1.tgz",
"integrity": "sha512-lJnFLxVc0d82R7GfU7a9RujKVUQ3Eee19tPKWZWBJtAEGRHVEyFzCtbNl3GPKuDnHBBRT4/nDS4Ru9AIDT72qA=="
},
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -6821,6 +7722,11 @@
"side-channel": "^1.0.4"
}
},
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
"is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@@ -7168,6 +8074,11 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="
},
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -7178,6 +8089,11 @@
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
},
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
+ },
"micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
@@ -7187,6 +8103,24 @@
"picomatch": "^2.3.1"
}
},
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+ },
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "requires": {
+ "mime-db": "1.52.0"
+ }
+ },
"mimic-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
@@ -7244,6 +8178,11 @@
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
},
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+ },
"next": {
"version": "13.4.1",
"resolved": "https://registry.npmjs.org/next/-/next-13.4.1.tgz",
@@ -7393,6 +8332,14 @@
"es-abstract": "^1.20.4"
}
},
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -7468,6 +8415,11 @@
"lines-and-columns": "^1.1.6"
}
},
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -7488,6 +8440,11 @@
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
"path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -7592,16 +8549,49 @@
"react-is": "^16.13.1"
}
},
+ "proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "requires": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ }
+ },
"punycode": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
},
+ "qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
"queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
},
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
"react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
@@ -7786,6 +8776,11 @@
"is-regex": "^1.1.4"
}
},
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
"scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
@@ -7807,6 +8802,64 @@
"lru-cache": "^6.0.0"
}
},
+ "send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -7850,6 +8903,11 @@
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
},
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ },
"stop-iteration-iterator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
@@ -8086,6 +9144,11 @@
"is-number": "^7.0.0"
}
},
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ },
"token-types": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz",
@@ -8144,6 +9207,22 @@
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="
},
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "dependencies": {
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
+ }
+ }
+ },
"typed-array-length": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
@@ -8170,6 +9249,11 @@
"which-boxed-primitive": "^1.0.2"
}
},
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
+ },
"untildify": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
@@ -8197,6 +9281,16 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
+ },
"wavesurfer.js": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-7.3.9.tgz",
diff --git a/react-ui/package.json b/react-ui/package.json
index d3e54dad..2ea13eb4 100644
--- a/react-ui/package.json
+++ b/react-ui/package.json
@@ -22,6 +22,7 @@
"country-flag-icons": "^1.5.7",
"eslint": "8.40.0",
"eslint-config-next": "13.4.1",
+ "express": "^4.18.2",
"iconv": "^3.0.1",
"music-metadata": "^8.1.4",
"next": "13.4.1",
@@ -33,6 +34,7 @@
"wavesurfer.js": "^7.3.9"
},
"devDependencies": {
- "@types/adm-zip": "^0.5.0"
+ "@types/adm-zip": "^0.5.0",
+ "@types/express": "^4.17.20"
}
}
diff --git a/react-ui/file-input-cache/.gitkeep b/react-ui/public/file-input-cache/.gitkeep
similarity index 100%
rename from react-ui/file-input-cache/.gitkeep
rename to react-ui/public/file-input-cache/.gitkeep
diff --git a/react-ui/src/app/api/upload/route.ts b/react-ui/src/app/api/upload/route.ts
index 765674fc..f8d02564 100644
--- a/react-ui/src/app/api/upload/route.ts
+++ b/react-ui/src/app/api/upload/route.ts
@@ -14,7 +14,7 @@ export async function POST(request: NextRequest) {
// With the file data in the buffer, you can do whatever you want with it.
// For this, we'll just write it to the filesystem in a new location
- const path = `./file-input-cache/${file.name}`;
+ const path = `./public/file-input-cache/${file.name}`;
await writeFile(path, buffer);
console.log(`open ${path} to see the uploaded file`);
diff --git a/react-ui/src/backend-utils/getFile.tsx b/react-ui/src/backend-utils/getFile.tsx
new file mode 100644
index 00000000..2cd376ab
--- /dev/null
+++ b/react-ui/src/backend-utils/getFile.tsx
@@ -0,0 +1,19 @@
+import fs from "fs";
+import path from "path";
+
+export const getFile = (file: string) =>
+ file
+ ? file.startsWith("http") || file.startsWith("data")
+ ? readFromURL(file)
+ : readFromDisk(file)
+ : null;
+
+const readFromDisk = (file: string) =>
+ new Promise((resolve, reject) => {
+ fs.readFile(path.join(process.cwd(), "public", file), (err, data) => {
+ if (err) reject(err);
+ resolve(data);
+ });
+ });
+
+const readFromURL = (file: string) => fetch(file).then((r) => r.blob());
diff --git a/react-ui/src/components/AudioComponents.tsx b/react-ui/src/components/AudioComponents.tsx
new file mode 100644
index 00000000..a8e9d4a3
--- /dev/null
+++ b/react-ui/src/components/AudioComponents.tsx
@@ -0,0 +1,173 @@
+import React from "react";
+import FileInput from "./FileInput";
+import { AudioPlayer } from "./MemoizedWaveSurferPlayer";
+import { WaveSurferOptions } from "wavesurfer.js";
+import { sendToDemucs } from "../tabs/DemucsParams";
+import { sendToMusicgen } from "../tabs/MusicgenParams";
+import { sendToVocos } from "../tabs/VocosParams";
+import { GradioFile } from "../types/GradioFile";
+import { sendToBarkVoiceGeneration } from "../tabs/BarkVoiceGenerationParams";
+
+export const AudioInput = ({
+ callback,
+ funcs,
+ url,
+ label,
+ filter,
+ metadata,
+}: {
+ callback: (melody?: string) => void;
+ funcs?: Array<(audio: string | undefined | any) => void>;
+ url?: string;
+ label?: string;
+ filter?: string[];
+ metadata?: any;
+}) => (
+
+
{label || "Input file:"}
+
callback(file)} />
+
+
+);
+
+export const AudioOutput = ({
+ audioOutput,
+ label,
+ funcs: sendAudioTo,
+ filter,
+ metadata,
+}: {
+ audioOutput?: GradioFile;
+ label: string;
+ funcs?: Array<(audio: string | undefined | any) => void>;
+ filter?: string[];
+ metadata?: any;
+}) => {
+ return (
+
+
{label}
+ {audioOutput && (
+
+ )}
+
+ );
+};
+
+const sendToFuncs = {
+ sendToDemucs,
+ sendToMusicgen,
+ sendToVocos,
+ sendToBarkVoiceGeneration,
+} as Record void>;
+
+const listOfFuncs = Object.keys(sendToFuncs);
+
+const AudioPlayerHelper = (
+ props: Omit & {
+ volume?: number;
+ filter?: string[];
+ // sendAudioTo?: Array<(audio: string | undefined) => void>;
+ metadata?: any;
+ funcs?: Array<(metadata: string | any) => void>;
+ }
+) => {
+ const { filter: outputFilters, funcs, url, volume, metadata } = props;
+ return (
+ <>
+
+
+ {funcs?.map((func) => (
+
+ ))}
+ {listOfFuncs
+ .filter((funcName) =>
+ outputFilters ? !outputFilters.includes(funcName) : true
+ )
+ .map((funcName) => (
+
+ ))}
+
+
+ >
+ );
+};
+
+const DownloadButton = ({ url }: { url?: string }) => {
+ const [downloadURL, setDownloadURL] = React.useState(
+ undefined
+ );
+
+ React.useEffect(() => {
+ if (!url) return;
+ const download = (url) => {
+ if (!url) {
+ throw new Error("Resource URL not provided! You need to provide one");
+ }
+ fetch(url)
+ .then((response) => response.blob())
+ .then((blob) => {
+ const blobURL = URL.createObjectURL(blob);
+ setDownloadURL(blobURL);
+ });
+ };
+ download(url);
+ }, [url]);
+
+ return (
+
+ Download
+
+ );
+};
+
+const FuncButton = ({
+ func,
+ url,
+ metadata,
+}: {
+ func: (audio: string | undefined | any, metadata?: any) => void;
+ url: string | undefined | any;
+ metadata?: any;
+}) => (
+
+);
diff --git a/react-ui/src/components/CardBig.tsx b/react-ui/src/components/CardBig.tsx
index 8c7f69c4..427005d2 100644
--- a/react-ui/src/components/CardBig.tsx
+++ b/react-ui/src/components/CardBig.tsx
@@ -6,6 +6,12 @@ import OtherIcon from "@material-design-icons/svg/filled/alt_route.svg";
import PlayIcon from "@material-design-icons/svg/filled/play_arrow.svg";
import PauseIcon from "@material-design-icons/svg/filled/pause.svg";
import AddIcon from "@material-design-icons/svg/filled/add.svg";
+import RecordVoiceOverIcon from "@material-design-icons/svg/filled/record_voice_over.svg";
+import OpenFolderIcon from "@material-design-icons/svg/filled/folder_open.svg";
+import PlaylistAddIcon from "@material-design-icons/svg/filled/playlist_add.svg";
+import StarIcon from "@material-design-icons/svg/filled/star.svg";
+import StarIconOutlined from "@material-design-icons/svg/outlined/star.svg";
+import DeleteForeverIcon from "@material-design-icons/svg/filled/delete_forever.svg";
import React, { useEffect, useRef, useState } from "react";
import { Flag } from "./Flag";
import { Voice } from "../types/Voice";
@@ -15,7 +21,27 @@ import { Vote } from "./Vote";
import { MUIIcon } from "./mini/MUIIcon";
import { GenerationRaw } from "../types/Generation";
import { parseMetadataDate } from "./parseMetadataDate";
-import { Metadata } from "./Metadata";
+import { Metadata, Row } from "./Metadata";
+import { sendToBarkAsVoice } from "../tabs/BarkGenerationParams";
+import { NPZ } from "../types/NPZ";
+
+const ActionButton = ({
+ icon,
+ alt,
+ onClick,
+}: {
+ icon: { src: string; width: number; height: number };
+ alt: string;
+ onClick: () => void;
+}) => (
+
+);
export const CardBig = ({
voice: { name, audio, download, image, tags, language, author, gender },
@@ -65,12 +91,22 @@ export const CardBig = ({
};
export const CardGeneration = ({
- generation: { prompt, language, history_hash, filename, date, ...rest },
+ metadata: {
+ prompt,
+ _type,
+ text,
+ language,
+ history_hash,
+ filename,
+ date,
+ ...rest
+ },
}: {
- generation: GenerationRaw;
+ metadata: GenerationRaw;
}) => {
+ const promptText = prompt || text || "";
// Detect if prompt is Japanese
- const isJapanese = prompt.match(/[\u3040-\u309F\u30A0-\u30FF]/);
+ const isJapanese = promptText.match(/[\u3040-\u309F\u30A0-\u30FF]/);
const maxLength = isJapanese ? 30 : 50;
// const maxLength = 100000;
return (
@@ -80,21 +116,20 @@ export const CardGeneration = ({
maxLength
+ promptText.length > maxLength
? "text-xl font-bold text-gray-900"
: "text-2xl font-bold text-gray-900"
}
>
- {prompt.length > maxLength
- ? prompt.substring(0, maxLength) + "..."
- : prompt}
+ {promptText.length > maxLength
+ ? promptText.substring(0, maxLength) + "..."
+ : promptText}
{/* {filename}
*/}
- {/*
*/}
- (audio is not yet available)
+
{prettifyDate(date)}
{/* {language &&
} */}
@@ -112,44 +147,302 @@ export const CardGeneration = ({
>
Generation info
*/}
-
+
+ {_type === "tortoise" ? (
+
+ {/* render everything as rows */}
+
+
+
+
+ {Object.entries(rest).map(([key, value]) => (
+
+ ))}
+
+
+ ) : (
+
+ )}
);
};
-export const CardVoiceNpz = ({
- generation: { prompt, language, history_hash, filename, date, ...rest },
+export const HistoryCard = ({
+ metadata: {
+ prompt,
+ _type,
+ text,
+ language,
+ history_hash,
+ filename,
+ date,
+ history_bundle_name_data,
+ api_filename,
+ ...rest
+ },
+ isFavorite,
}: {
- generation: GenerationRaw;
+ metadata: GenerationRaw;
+ isFavorite?: boolean;
}) => {
+ const promptText = prompt || text || "(No title)";
// Detect if prompt is Japanese
- const isJapanese = prompt.match(/[\u3040-\u309F\u30A0-\u30FF]/);
+ const isJapanese = promptText.match(/[\u3040-\u309F\u30A0-\u30FF]/);
const maxLength = isJapanese ? 30 : 50;
// const maxLength = 100000;
+
+ const favorite = async (
+ _url: string,
+ data?: {
+ history_bundle_name_data?: string;
+ }
+ ) => {
+ const history_bundle_name_data = data?.history_bundle_name_data;
+ if (!history_bundle_name_data) return;
+ const response = await fetch("/api/gradio/bark_favorite", {
+ method: "POST",
+ body: JSON.stringify({
+ history_bundle_name_data,
+ }),
+ });
+ const result = await response.json();
+ return result;
+ };
+
+ const deleteFavorite = async (
+ _url: string,
+ data?: {
+ history_bundle_name_data?: string;
+ }
+ ) => {
+ const history_bundle_name_data = data?.history_bundle_name_data;
+ if (!history_bundle_name_data) return;
+ const response = await fetch("/api/gradio/delete_generation", {
+ method: "POST",
+ body: JSON.stringify({
+ history_bundle_name_data,
+ }),
+ });
+ const result = await response.json();
+ return result;
+ };
+
+ const addFavorite = () => {
+ favorite("", {
+ history_bundle_name_data,
+ });
+ };
+
+ const removeFavorite = () => {
+ deleteFavorite("", {
+ history_bundle_name_data,
+ });
+ };
+
+ const saveToVoices = () => {
+ fetch("/api/gradio/save_to_voices", {
+ method: "POST",
+ body: JSON.stringify({
+ history_npz: api_filename?.replace(".ogg", ".npz"),
+ }),
+ });
+ };
+
+ const openFolder = () => {
+ fetch("/api/gradio/open_folder", {
+ method: "POST",
+ body: JSON.stringify({
+ folder: history_bundle_name_data,
+ }),
+ });
+ };
+
+ const useAsVoice = () => {
+ const history_npz = api_filename?.replace(".ogg", ".npz");
+ sendToBarkAsVoice(history_npz);
+ };
+
+ const ActionRow = ({
+ isFavorite,
+ removeFavorite,
+ addFavorite,
+ saveToVoices,
+ openFolder,
+ useAsVoice,
+ filename,
+ _type,
+ }: {
+ isFavorite?: boolean;
+ removeFavorite: () => void;
+ addFavorite: () => void;
+ saveToVoices: () => void;
+ openFolder: () => void;
+ useAsVoice: () => void;
+ filename?: string;
+ _type?: string;
+ }) => {
+ return (
+
+ {isFavorite ? (
+
+ ) : (
+ <>
+
+
+ >
+ )}
+
+ {_type === "bark" && (
+
+ )}
+
+ {_type === "bark" && (
+
+ )}
+
+ );
+ };
+
+ const MetadataBlock = ({
+ prompt,
+ language,
+ history_hash,
+ ...rest
+ }: Omit) => {
+ return _type === "tortoise" ? (
+
+ ) : (
+
+ );
+ };
+
return (
-
+
maxLength
+ promptText.length > maxLength
? "text-xl font-bold text-gray-900"
: "text-2xl font-bold text-gray-900"
}
>
- {prompt.length > maxLength
- ? prompt.substring(0, maxLength) + "..."
- : prompt}
+ {promptText.length > maxLength
+ ? promptText.substring(0, maxLength) + "..."
+ : promptText}
+
+
+
{prettifyDate(date, true)}
+
+
+
+
{history_bundle_name_data}
+
|
+
+
+
+
+ );
+};
+
+const TortoiseMetadata = ({
+ language,
+ history_hash,
+ ...rest
+}: {
+ language: string;
+ history_hash: string;
+ [key: string]: any;
+}) => {
+ return (
+
+ {/* render everything as rows */}
+
+
+
+ {Object.entries(rest).map(([key, value]) => (
+
+ ))}
+
+
+ );
+};
+
+export const CardVoiceNpz = ({
+ generation: { prompt, language, history_hash, filename, date, url, ...rest },
+}: {
+ generation: NPZ;
+}) => {
+ const image = url.replace(".npz", ".png");
+
+ const Extra = () => {
+ if (!prompt) return <>>;
+ const isJapanese = prompt.match(/[\u3040-\u309F\u30A0-\u30FF]/);
+ const maxLength = isJapanese ? 30 : 50;
+ // const maxLength = 100000;
+ return (
+
@@ -160,6 +453,53 @@ export const CardVoiceNpz = ({
{...rest}
/>
+ );
+ };
+
+ const useAsVoice = () => {
+ const history_npz = filename;
+ sendToBarkAsVoice(history_npz);
+ };
+
+ const preview = filename.replace(".npz", ".wav");
+
+ const name = filename
+ .replace(".npz", "")
+ .replace("voices/", "")
+ // reformat date YYYY-MM-DD to YYYY/MM/DD
+ .replace(/(\d{4})-(\d{2})-(\d{2})/, "$1/$2/$3")
+ // reformat time HH-MM-SS to HH:MM:SS
+ .replace(/(\d{2})-(\d{2})-(\d{2})/, "$1:$2:$3")
+ .replaceAll("_", " ")
+ .replaceAll("-", " ");
+ return (
+
+ {image && (
+
{
+ const target = e.target as HTMLImageElement;
+ target.onerror = null;
+ target.src =
+ "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";
+ }}
+ />
+ )}
+
+ {name}
+
+
+ {/*
*/}
+
);
};
@@ -274,6 +614,7 @@ const Author = ({ author }: Pick
) => {
};
const Heart = () => <>❤>;
+const Trash = () => <>X>;
const SaveToFavorites = ({ download }: Pick) => {
const [favorites, setFavorites] = useFavorites();
@@ -346,16 +687,22 @@ const AudioPlayer = ({ audio }: Pick) => {
className="select-none w-full h-full"
/>
-
+
);
};
const Download = ({ download }: Pick) => (
) => (
);
-const parseMetadataLanguage = (language: string) => language.toLowerCase();
-
-const prettifyDate = (date: string) => {
+const prettifyDate = (date: string, showTime = false) => {
const dateObj = parseMetadataDate(date);
return (
);
diff --git a/react-ui/src/components/FileInput.tsx b/react-ui/src/components/FileInput.tsx
index 2c77b171..bd03173a 100644
--- a/react-ui/src/components/FileInput.tsx
+++ b/react-ui/src/components/FileInput.tsx
@@ -2,13 +2,17 @@ import { ChangeEvent, useState } from "react";
export default function FileInput({
callback,
+ accept = "audio/*",
+ hide_text = true,
}: {
- callback: (file: File | undefined) => void;
+ callback: (file?: string) => void;
+ accept?: string;
+ hide_text?: boolean;
}) {
const parseFileEvent = (e: ChangeEvent) =>
e.target.files?.[0];
- const uploadFile = async (file: File | undefined) => {
+ const uploadFile = async (file?: File) => {
if (!file) return;
try {
@@ -35,14 +39,17 @@ export default function FileInput({
onChange={async (e) => {
const file = parseFileEvent(e);
await uploadFile(file);
- callback(file);
+ callback(getLocalFileURL(file));
}}
- accept="audio/*"
+ accept={accept}
style={{
- color: "transparent",
+ color: hide_text ? "transparent" : undefined,
}}
/>
);
}
+
+const getLocalFileURL = (file?: File) =>
+ file && "/file-input-cache/" + file.name;
diff --git a/react-ui/src/components/GradioFileInfo.tsx b/react-ui/src/components/GradioFileInfo.tsx
new file mode 100644
index 00000000..3390662f
--- /dev/null
+++ b/react-ui/src/components/GradioFileInfo.tsx
@@ -0,0 +1,26 @@
+import React from "react";
+import { GradioFile } from "./api/demucs_musicgen";
+
+export const GradioFileInfo = ({ audioOutput }: { audioOutput: GradioFile; }) => (
+
+
Info
+
+
+
Name
+
{audioOutput.name}
+
+
+
Original name
+
{audioOutput.orig_name}
+
+
+
Size
+
{audioOutput.size}
+
+
+
Is file
+
{audioOutput.is_file ? "true" : "false"}
+
+
+
+);
diff --git a/react-ui/src/components/Header.tsx b/react-ui/src/components/Header.tsx
index bb882527..77e5627f 100644
--- a/react-ui/src/components/Header.tsx
+++ b/react-ui/src/components/Header.tsx
@@ -3,37 +3,84 @@ import Link from "next/link";
import { useRouter } from "next/router";
const routes = [
+ {
+ href: "/",
+ text: "Home",
+ },
+ {
+ href: "/bark",
+ text: "Bark",
+ },
+ {
+ href: "/tortoise",
+ text: "Tortoise",
+ },
{
href: "/musicgen",
text: "Musicgen",
},
+ {
+ href: "/rvc",
+ text: "RVC",
+ },
{
href: "/demucs",
text: "Demucs",
},
+ {
+ href: "/vocos_wav",
+ text: "Vocos Wav",
+ },
+ {
+ href: "/vocos_npz",
+ text: "Vocos NPZ",
+ },
+ {
+ href: "/bark_voice_generation",
+ text: "Bark Voice Generation",
+ },
+ {
+ href: "/history/outputs",
+ text: "History",
+ },
+ {
+ href: "/history/favorites",
+ text: "Favorites",
+ },
+ {
+ href: "/voices",
+ text: "Bark Voices",
+ },
+ {
+ href: "/bark_settings",
+ text: "Bark Settings",
+ },
// {
- // href: "/",
- // text: "Voices",
+ // href: "/history/collections",
+ // text: "History Collections",
// },
{
href: "/generations",
- text: "Favorites",
+ text: "Generations View (Beta)",
},
// {
// href: "/voice-drafts",
// text: "Voice Tree",
// },
- // {
- // href: "https://echo.ps.ai/?utm_source=bark_speaker_directory",
- // text: "More Voices",
- // target: "_blank",
- // },
+ {
+ href: "https://echo.ps.ai/?utm_source=bark_speaker_directory",
+ text: (
+
+ More Voices{" "}↗
+
+ ),
+ target: "_blank",
+ },
];
export const Header = ({}) => {
- // get route from next.js router
const router = useRouter();
- const route = router.pathname.replace("/", "");
+ const route = router.asPath.replace("/", "");
return (
diff --git a/react-ui/src/components/MemoizedWaveSurferPlayer.tsx b/react-ui/src/components/MemoizedWaveSurferPlayer.tsx
index 1c429b56..1f6cd6a8 100644
--- a/react-ui/src/components/MemoizedWaveSurferPlayer.tsx
+++ b/react-ui/src/components/MemoizedWaveSurferPlayer.tsx
@@ -59,7 +59,10 @@ const WaveSurferPlayerRaw = (props) => {
// memoize the player component
export const MemoizedWaveSurferPlayer = React.memo(WaveSurferPlayerRaw);
export const AudioPlayer = (
- props: Omit
& { volume: number }
+ props: Omit & {
+ volume: number;
+ // sendAudioTo: (audio: string | undefined) => void;
+ }
) => {
const [plugins, setPlugins] = useState([]);
useEffect(() => {
@@ -67,9 +70,5 @@ export const AudioPlayer = (
setPlugins([timeline_plugin]);
}, []);
- return (
-
-
-
- );
+ return ;
};
diff --git a/react-ui/src/components/Metadata.tsx b/react-ui/src/components/Metadata.tsx
index 07e6b01a..0afb7fb6 100644
--- a/react-ui/src/components/Metadata.tsx
+++ b/react-ui/src/components/Metadata.tsx
@@ -4,7 +4,7 @@ import React from "react";
import { MUIIcon } from "./mini/MUIIcon";
import { GenerationRaw } from "../types/Generation";
-const Row = ({
+export const Row = ({
label,
value,
}: {
diff --git a/react-ui/src/components/Template.tsx b/react-ui/src/components/Template.tsx
index 89006bf5..5dafc0cc 100644
--- a/react-ui/src/components/Template.tsx
+++ b/react-ui/src/components/Template.tsx
@@ -9,7 +9,7 @@ export const Template = ({ children }: { children: React.ReactNode }) => (
{children}
diff --git a/react-ui/src/data/getVoicesData.tsx b/react-ui/src/data/getVoicesData.tsx
index aaba7ad6..efa6e545 100644
--- a/react-ui/src/data/getVoicesData.tsx
+++ b/react-ui/src/data/getVoicesData.tsx
@@ -8,63 +8,25 @@ import { npyToUtf8 } from "./npyToUtf8";
const __next__base__dirname = __dirname.split(".next")[0];
const basePath = path.join(__next__base__dirname, "public");
-// const basePath = path.join(__dirname, "../../../public");
-// const basePath = path.join(__dirname, "../../public");
-const voicesPath = path.join(basePath, "voices");
-const getVoices = () => fs.readdirSync(voicesPath);
+export const webuiBasePath = path.join(__next__base__dirname, "..");
-const generationsPath = path.join(basePath, "generations");
-const getGenerations = () => fs.readdirSync(generationsPath);
+const getWebuiPath = (dir: string) => path.join(webuiBasePath, dir);
-// const oggPath = path.join(basePath, "ogg");
-const oggPath = path.join(basePath, "..", "..", "favorites");
+const oggPath = getWebuiPath("favorites");
const getOgg = () => fs.readdirSync(oggPath);
const npzPath = path.join(basePath, "voice-drafts");
-const getNpzs = () => fs.readdirSync(npzPath);
+const npzPathWebui = getWebuiPath("voices");
+const getNpzs = (dir: string = npzPath) => fs.readdirSync(dir);
-// const baseUrlPath = process.env.BASE_URL_PATH || "/bark-speaker-directory";
const baseUrlPath = "";
-// For each voice get voice.json file and parse it
-// Return array of objects
-// --------------------------------------------------
-export const getVoicesData = () => {
- const voices = getVoices();
- const voicesData = voices.map((voice) => {
- const voiceData = fs.readFileSync(
- path.join(voicesPath, voice, "voice.json"),
- "utf8"
- );
- return JSON.parse(voiceData);
- });
- // include the directory name in the object
- voicesData.forEach((voice, index) => {
- voice.directory = voices[index];
- });
- // join path for image, audio and download keys with directory
- voicesData.forEach((voice) => {
- const fixPath = (key: string) => {
- if (voice[key]) {
- voice[key] = path
- .join(baseUrlPath, "voices", voice.directory, voice[key])
- .split(path.sep)
- .join("/");
- }
- };
- fixPath("image");
- fixPath("audio");
- fixPath("download");
- });
- return voicesData;
-};
-
-export const getOggData = async () => {
+export const getOggData = async (collection = "favorites") => {
const ogg = getOgg();
- console.log("ogg: ", ogg);
- const oggData = ogg.map(async (ogg) => {
- const filename = path.join(oggPath, ogg, ogg + ".ogg");
- console.log("filename: ", filename);
+ // TODO - filter tortoise?
+ const oggData = ogg.map(async (dirname) => {
+ const coreFilename = path.join(dirname, dirname + ".ogg");
+ const filename = path.join(oggPath, coreFilename);
const metadata = await parseFile(filename);
try {
const result = JSON.parse(
@@ -72,12 +34,7 @@ export const getOggData = async () => {
metadata?.native?.vorbis?.filter((x) => x.id === "DESCRIPTION")[0]
.value || "{}"
);
- result.semantic_prompt = null;
- result.coarse_prompt = null;
- return {
- ...result,
- filename: path.join(baseUrlPath, "ogg", ogg).split(path.sep).join("/"),
- };
+ return generateResult(result, collection, coreFilename, dirname);
} catch (error) {
console.error(error);
console.log("Error parsing metadata for file: " + filename);
@@ -106,13 +63,19 @@ export const getOggData = async () => {
return oggDataParsed;
};
-const parseToNpzData = (buf: Buffer | ArrayBuffer) =>
- new AdmZip.default(buf instanceof Buffer ? buf : Buffer.from(buf))
- .getEntries()
- .filter((entry) => entry.name === "metadata.npy")
- .map((entry) => parseNpy(entry.getData().buffer))
- .map((entry) => npyToUtf8(entry))
- .map((entry) => JSON.parse(entry))[0];
+const parseToNpzData = (buf: Buffer | ArrayBuffer) => {
+ try {
+ return new AdmZip.default(buf instanceof Buffer ? buf : Buffer.from(buf))
+ .getEntries()
+ .filter((entry) => entry.name === "metadata.npy")
+ .map((entry) => parseNpy(entry.getData().buffer))
+ .map((entry) => npyToUtf8(entry))
+ .map((entry) => JSON.parse(entry))[0];
+ } catch (error) {
+ console.error(error);
+ return null;
+ }
+};
export const getNpzData = async () =>
getNpzs().map((npz) => ({
@@ -122,3 +85,63 @@ export const getNpzData = async () =>
.split(path.sep)
.join("/"),
}));
+
+export const getNpzDataSimpleVoices = async () =>
+ getNpzs(npzPathWebui)
+ .filter((file) => file.endsWith(".npz"))
+ .map((npz) => ({
+ ...parseToNpzData(fs.readFileSync(path.join(npzPathWebui, npz))),
+ filename: path.join(baseUrlPath, "voices", npz).split(path.sep).join("/"),
+ url: getWebuiURL("voices", npz),
+ }));
+
+export const getDataFromJSON = async (collection = "outputs") => {
+ const basePath = getWebuiPath(collection);
+ const dirs = fs.readdirSync(basePath);
+ const oggData = dirs.map(async (dirname) => {
+ const coreFilename = path.join(dirname, dirname + ".ogg");
+ const jsonFilename = path.join(basePath, dirname, dirname + ".json");
+ try {
+ const json = await fs.promises.readFile(jsonFilename, "utf-8");
+ const result = JSON.parse(json);
+ return generateResult(result, collection, coreFilename, dirname);
+ } catch (error) {
+ console.error(error);
+ console.log("Error parsing metadata for file: " + jsonFilename);
+ return null;
+ }
+ });
+
+ const oggDataParsed = (await Promise.all(oggData))
+ .filter((x) => x !== null)
+ .filter((x) => x.date);
+ // Sort by date
+ oggDataParsed.sort((a, b) => {
+ return (
+ parseMetadataDate(b.date).getTime() - parseMetadataDate(a.date).getTime()
+ );
+ });
+ return oggDataParsed;
+};
+
+const getWebuiURL = (...args: string[]) =>
+ path
+ .join(baseUrlPath, "api", "webui-generations", ...args)
+ .split(path.sep)
+ .join("/");
+
+const generateResult = (
+ result: any,
+ collection: string,
+ coreFilename: string,
+ dirname: string
+) => ({
+ ...result,
+ semantic_prompt: null,
+ coarse_prompt: null,
+
+ filename: getWebuiURL(collection, coreFilename),
+
+ history_bundle_name_data: path.join(collection, dirname),
+ api_filename: path.join(collection, coreFilename),
+});
diff --git a/react-ui/src/data/list_of_voices_stub.tsx b/react-ui/src/data/list_of_voices_stub.tsx
deleted file mode 100644
index e55c1d79..00000000
--- a/react-ui/src/data/list_of_voices_stub.tsx
+++ /dev/null
@@ -1,140 +0,0 @@
-import { Voice } from "../types/Voice";
-
-const random_image_backup = () => {
- return `https://picsum.photos/seed/${Math.random()}/96/96`;
-};
-
-random_image_backup();
-
-export const list_of_voices_stub: Voice[] = [
- {
- name: "Jack",
- image: "https://picsum.photos/seed/0.20324546237794583/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
- download: "./jack.npz",
- tags: ["smooth","vocal","tone"],
- language: "american",
- author: "rsxdalv",
- gender: "male",
- },
- {
- name: "Alice",
- image: "https://picsum.photos/seed/0.1894848117042902/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
- download: "./alice.npz",
- tags: ["soft spoken","voice"],
- language: "german",
- author: "rsxdalv",
- gender: "male",
- },
- {
- name: "Bob",
- image: "https://picsum.photos/seed/0.1427656561313495/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
- download: "./bob.npz",
- tags: ["hard-hitting","vocal","delivery"],
- language: "spanish",
- author: "rsxdalv",
- gender: "male",
- },
- {
- name: "Eve",
- image: "https://picsum.photos/seed/0.44700961112069915/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
- download: "./eve.npz",
- tags: ["smooth","melodic","voice"],
- language: "french",
- author: "rsxdalv",
- gender: "other",
- },
- {
- name: "Carol",
- image: "https://picsum.photos/seed/0.8241474051465822/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
- download: "./carol.npz",
- tags: ["soft","soothing","voice"],
- language: "hindi",
- author: "rsxdalv",
- gender: "female",
- },
- {
- name: "Dave",
- image: "https://picsum.photos/seed/0.9850711062202109/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
- download: "./dave.npz",
- tags: ["powerful","intense","voice"],
- language: "italian",
- author: "rsxdalv",
- gender: "male",
- },
- {
- name: "Frank",
- image: "https://picsum.photos/seed/0.8984412890111275/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
- download: "./frank.npz",
- tags: ["smooth","rich","timbre"],
- language: "japanese",
- author: "rsxdalv",
- gender: "female",
- },
- {
- name: "Grace",
- image: "https://picsum.photos/seed/0.16491188858713013/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
- download: "./grace.npz",
- tags: ["gentle","comforting","voice"],
- language: "korean",
- author: "rsxdalv",
- gender: "other",
- },
- {
- name: "Heidi",
- image: "https://picsum.photos/seed/0.05621132363045245/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3",
- download: "./heidi.npz",
- tags: ["strong","commanding","voice"],
- language: "polish",
- author: "rsxdalv",
- gender: "male",
- },
- {
- name: "Ivan",
- image: "https://picsum.photos/seed/0.740986180442867/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3",
- download: "./ivan.npz",
- tags: ["smooth","captivating","vocal style"],
- language: "portuguese",
- author: "rsxdalv",
- gender: "other",
- },
- {
- name: "Judy",
- image: "https://picsum.photos/seed/0.2220990113159642/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3",
- download: "./judy.npz",
- tags: ["calm","mellow","voice"],
- language: "russian",
- author: "rsxdalv",
- gender: "male",
- },
- {
- name: "Kevin",
- image: "https://picsum.photos/seed/0.7875717080906023/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3",
- download: "./kevin.npz",
- tags: ["energetic","dynamic","voice"],
- language: "turkish",
- author: "rsxdalv",
- gender: "other",
- },
- {
- name: "Linda",
- image: "https://picsum.photos/seed/0.7815717080906023/96/96",
- audio: "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3",
- download: "./linda.npz",
- tags: ["smooth","voice","with","vocal range"],
- language: "chinese",
- author: "rsxdalv",
- gender: "female"
- },
-];
diff --git a/react-ui/src/hooks/useLocalStorage.ts b/react-ui/src/hooks/useLocalStorage.ts
new file mode 100644
index 00000000..705d2358
--- /dev/null
+++ b/react-ui/src/hooks/useLocalStorage.ts
@@ -0,0 +1,99 @@
+import { Dispatch, SetStateAction, useEffect, useState } from "react";
+
+const defaultNamespace = "tts-generation-webui__";
+
+const readLocalStorage = (key: string) => {
+ const prefixedKey = defaultNamespace + key;
+ const item = localStorage.getItem(prefixedKey);
+ return item ? (JSON.parse(item) as any) : undefined;
+};
+
+const updateLocalStorage = (key: string, value: any) => {
+ const prefixedKey = defaultNamespace + key;
+ localStorage.setItem(prefixedKey, JSON.stringify(value));
+};
+
+export const updateLocalStorageWithFunction = (key: string, value: any) =>
+ updateLocalStorage(
+ key,
+ value instanceof Function ? value(readLocalStorage(key)) : value
+ );
+
+export default function useLocalStorage(
+ key: string,
+ initialValue: T,
+ namespace = defaultNamespace
+): [T, Dispatch>] {
+ const [storedValue, setStoredValue] = useState(initialValue);
+ // We will use this flag to trigger the reading from localStorage
+ const [firstLoadDone, setFirstLoadDone] = useState(false);
+
+ const prefixedKey = namespace + key;
+
+ // Use an effect hook in order to prevent SSR inconsistencies and errors.
+ // This will update the state with the value from the local storage after
+ // the first initial value is applied.
+ useEffect(() => {
+ const fromLocal = () => {
+ if (typeof window === "undefined") {
+ return initialValue;
+ }
+ try {
+ const item = window.localStorage.getItem(prefixedKey);
+ return item ? (JSON.parse(item) as T) : initialValue;
+ } catch (error) {
+ console.error(error);
+ return initialValue;
+ }
+ };
+
+ // Set the value from localStorage
+ setStoredValue(fromLocal);
+ // First load is done
+ setFirstLoadDone(true);
+ }, [initialValue, prefixedKey]);
+
+ function setLocalValue(value: T) {
+ if (!firstLoadDone) {
+ return;
+ }
+
+ try {
+ if (typeof window !== "undefined") {
+ window.localStorage.setItem(prefixedKey, JSON.stringify(value));
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ }
+
+ const setValue: Dispatch> = (value) => {
+ // Allow value to be a function so we have the same API as useState
+ const valueToStore = value instanceof Function ? value(storedValue) : value;
+
+ // update local storage
+ setLocalValue(valueToStore);
+ // Save state
+ setStoredValue(valueToStore);
+ };
+
+ // watch localStorage changes
+ // useEffect(() => {
+ // const onStorageChange = (e: StorageEvent) => {
+ // console.log("onStorageChange", e);
+ // if (e.key === prefixedKey) {
+ // setStoredValue(JSON.parse(e.newValue || "null"));
+ // }
+ // };
+
+ // window.addEventListener("storage", onStorageChange);
+
+ // return () => {
+ // window.removeEventListener("storage", onStorageChange);
+ // };
+ // }, [prefixedKey]);
+
+ // Return the original useState functions
+ // return [storedValue, setStoredValue];
+ return [storedValue, setValue];
+}
diff --git a/react-ui/src/pages/api/demucs_musicgen.tsx b/react-ui/src/pages/api/demucs_musicgen.tsx
deleted file mode 100644
index f178085d..00000000
--- a/react-ui/src/pages/api/demucs_musicgen.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import { client } from "@gradio/client";
-import type { NextApiRequest, NextApiResponse } from "next";
-import fs from "fs";
-import path from "path";
-
-type Data = { data: any };
-
-export default async function handler(
- req: NextApiRequest,
- res: NextApiResponse
-) {
- const body = JSON.parse(req.body);
- if (body.file) {
- const result = await demucs(body.file);
- res.status(200).json({ data: result });
- } else {
- const result = await musicgen(body);
- res.status(200).json({ data: result });
- }
-}
-
-// demucs handler
-export async function demucsHandler(
- req: NextApiRequest,
- res: NextApiResponse
-) {
- const body = JSON.parse(req.body);
- const result = await demucs(body.file);
- res.status(200).json({ data: result });
-}
-
-async function demucs(file: string) {
- const exampleAudio = fs.readFileSync(
- path.join(process.cwd(), "file-input-cache", file)
- );
-
- const app = await client("http://127.0.0.1:7865/");
- const result = await app.predict("/demucs", [
- exampleAudio, // blob in 'Input' Audio component
- ]);
-
- return result?.data;
-}
-
-// musicgen handler
-export async function musicgenHandler(
- req: NextApiRequest,
- res: NextApiResponse
-) {
- const body = JSON.parse(req.body);
- const result = await musicgen(body);
- res.status(200).json({ data: result });
-}
-
-function getMelody(melody: string) {
- if (melody) {
- const filename = melody.split("/").pop();
- console.log("filename", filename);
- const exampleAudio = fs.readFileSync(
- path.join(process.cwd(), "file-input-cache", filename)
- );
- return exampleAudio;
- } else {
- return null;
- }
-}
-
-async function musicgen({ melody, ...params }) {
- const melodyBlob = getMelody(melody);
-
- const app = await client("http://127.0.0.1:7865/");
- const result = await app.predict("/musicgen", [
- // {
- // text: "bass",
- // melody: null,
- // model: "small",
- // duration: 1,
- // topk: 250,
- // topp: 0,
- // temperature: 1.0,
- // cfg_coef: 3.0,
- // seed: -1,
- // use_multi_band_diffusion: false,
- // },
- {
- melody: null,
- ...params,
- },
- melodyBlob, // blob in 'Melody (optional)' Audio component
- ]);
- return result?.data;
-}
diff --git a/react-ui/src/pages/api/gradio/[name].tsx b/react-ui/src/pages/api/gradio/[name].tsx
new file mode 100644
index 00000000..f3e550ac
--- /dev/null
+++ b/react-ui/src/pages/api/gradio/[name].tsx
@@ -0,0 +1,639 @@
+import { client } from "@gradio/client";
+import type { NextApiRequest, NextApiResponse } from "next";
+import { getFile } from "../../../backend-utils/getFile";
+import { GradioFile } from "../../../types/GradioFile";
+import { join } from "path";
+
+type Data = { data: any };
+
+const defaultBackend = "http://127.0.0.1:7860/";
+const getClient = () => client(defaultBackend, {});
+
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse
+) {
+ const { name } = req.query;
+ console.log("gradio api handler", name, req.body);
+
+ if (!name || typeof name !== "string" || !endpoints[name]) {
+ res.status(404).json({ data: { error: "Not found" } });
+ return;
+ }
+
+ const { body } = req;
+ const parsedBody = body && typeof body === "string" ? JSON.parse(body) : body;
+ const result = await endpoints[name](parsedBody);
+
+ res.status(200).json(result);
+}
+
+async function demucs({ file }: { file: string }) {
+ const audioBlob = await getFile(file);
+
+ const app = await getClient();
+ const result = (await app.predict("/demucs", [
+ audioBlob, // blob in 'Input' Audio component
+ ])) as {
+ data: [GradioFile, GradioFile, GradioFile, GradioFile];
+ };
+
+ return result?.data;
+}
+
+async function vocos_wav({ audio, bandwidth }) {
+ const audioBlob = await getFile(audio);
+
+ const app = await getClient();
+ const result = (await app.predict("/vocos_wav", [
+ audioBlob, // blob in 'Input Audio' Audio component
+ bandwidth, // string (Option from: ['1.5', '3.0', '6.0', '12.0']) in 'Bandwidth in kbps' Dropdown component
+ ])) as {
+ data: [GradioFile];
+ };
+
+ return result?.data[0];
+}
+
+async function vocos_npz({ npz_file }) {
+ const npzBlob = await getFile(npz_file);
+
+ const app = await getClient();
+ const result = (await app.predict("/vocos_npz", [
+ npzBlob, // blob in 'Input NPZ' File component
+ ])) as {
+ data: [GradioFile];
+ };
+
+ return result?.data[0];
+}
+
+async function encodec_decode({ npz_file }) {
+ const npzBlob = await getFile(npz_file);
+
+ const app = await getClient();
+ const result = (await app.predict("/encodec_decode", [
+ npzBlob, // blob in 'Input NPZ' File component
+ ])) as {
+ data: [GradioFile];
+ };
+
+ return result?.data[0];
+}
+
+async function musicgen({ melody, ...params }) {
+ const melodyBlob = await getFile(melody);
+
+ const app = await getClient();
+ const result = (await app.predict("/musicgen", [
+ {
+ melody: null,
+ ...params,
+ },
+ melodyBlob, // blob in 'Melody (optional)' Audio component
+ ])) as {
+ data: [
+ GradioFile, // output
+ string, // history_bundle_name_data
+ string, // image
+ null, // seed_cache
+ Object // result_json
+ ];
+ };
+ const [audio, history_bundle_name_data, , , json] = result?.data;
+ return {
+ audio,
+ history_bundle_name_data,
+ json,
+ };
+}
+
+async function bark_voice_tokenizer_load({ tokenizer, use_gpu }) {
+ const app = await getClient();
+ const result = (await app.predict("/bark_voice_tokenizer_load", [
+ tokenizer, // string (Option from: ['quantifier_hubert_base_ls960.pth @ GitMylo/bark-voice-cloning', 'quantifier_hubert_base_ls960_14.pth @ GitMylo/bark-voice-cloning', 'quantifier_V1_hubert_base_ls960_23.pth @ GitMylo/bark-voice-cloning', 'polish-HuBERT-quantizer_8_epoch.pth @ Hobis/bark-voice-cloning-polish-HuBERT-quantizer', 'german-HuBERT-quantizer_14_epoch.pth @ CountFloyd/bark-voice-cloning-german-HuBERT-quantizer', 'es_tokenizer.pth @ Lancer1408/bark-es-tokenizer', 'portuguese-HuBERT-quantizer_24_epoch.pth @ MadVoyager/bark-voice-cloning-portuguese-HuBERT-quantizer']) in 'Tokenizer' Dropdown component
+ use_gpu, // boolean in 'Use GPU' Checkbox component
+ ])) as {
+ data: [string];
+ };
+
+ return result?.data[0];
+}
+
+async function bark_voice_generate({ audio, use_gpu }) {
+ const audioBlob = await getFile(audio);
+
+ const app = await getClient();
+ const result = (await app.predict("/bark_voice_generate", [
+ audioBlob, // blob in 'Input Audio' Audio component
+ use_gpu, // boolean in 'Use GPU' Checkbox component
+ ])) as {
+ data: [
+ string, // string representing output in 'Voice file name' Textbox component
+ GradioFile // { name: string; data: string; size?: number; is_file?: boolean; orig_name?: string} representing output in 'Encodec audio preview' Audio component
+ ];
+ };
+
+ const [filename, preview] = result?.data;
+ return { filename, preview };
+}
+
+async function bark({
+ burn_in_prompt,
+ prompt,
+ history_setting,
+ languageRadio,
+ speakerIdRadio,
+ useV2,
+ text_temp,
+ waveform_temp,
+ long_prompt_radio,
+ long_prompt_history_radio,
+ old_generation_dropdown,
+ seed_input,
+ history_prompt_semantic_dropdown,
+}) {
+ const app = await getClient();
+
+ const result = (await app.predict("/bark", [
+ burn_in_prompt,
+ prompt,
+ history_setting,
+ languageRadio,
+ speakerIdRadio,
+ useV2,
+ text_temp,
+ waveform_temp,
+ long_prompt_radio,
+ long_prompt_history_radio,
+ old_generation_dropdown,
+ seed_input,
+ history_prompt_semantic_dropdown,
+ ])) as {
+ data: [
+ GradioFile, // audio
+ string, // image
+ Object, // save_button
+ Object, // continue_button
+ Object, // buttons_row
+ null, // npz
+ null, // seed
+ null, // json_text
+ null // history_bundle_name_data
+ // note - ignore other 8 rows of data
+ ];
+ };
+
+ const [
+ audio,
+ image,
+ save_button,
+ continue_button,
+ buttons_row,
+ npz,
+ seed,
+ json_text,
+ history_bundle_name_data,
+ ] = result?.data;
+
+ return {
+ audio,
+ image,
+ save_button,
+ continue_button,
+ buttons_row,
+ npz,
+ seed,
+ json_text,
+ history_bundle_name_data,
+ };
+}
+
+async function reload_old_generation_dropdown() {
+ const app = await getClient();
+
+ const result = (await app.predict("/reload_old_generation_dropdown")) as {
+ data: [
+ {
+ choices: string[];
+ __type__: "update";
+ }
+ ];
+ };
+
+ return result?.data[0].choices;
+}
+
+async function bark_favorite({ history_bundle_name_data }) {
+ const app = await getClient();
+
+ const result = (await app.predict("/bark_favorite", [
+ history_bundle_name_data,
+ ])) as {
+ data: [
+ Object // save_button
+ ];
+ };
+
+ return result?.data;
+}
+
+async function tortoise({
+ prompt,
+ speaker,
+ preset,
+ seed,
+ cvvp_amount,
+ split_prompt,
+ samples,
+ diffusion_iterations,
+ temperature,
+ length_penalty,
+ repetition_penalty,
+ top_p,
+ max_mel_tokens,
+ cond_free,
+ cond_free_k,
+ diffusion_temperature,
+ model,
+ generation_name,
+}) {
+ const app = await getClient();
+
+ const result = (await app.predict("/generate_tortoise_1", [
+ prompt, // string in 'Prompt' Textbox component
+ speaker, // string (Option from: ['random', 'angie', 'applejack', 'cond_latent_example', 'daniel', 'deniro', 'emma', 'freeman', 'geralt', 'halle', 'jlaw', 'lj', 'mol', 'myself', 'pat', 'pat2', 'rainbow', 'snakes', 'tim_reynolds', 'tom', 'train_atkins', 'train_daws', 'train_dotrice', 'train_dreams', 'train_empire', 'train_grace', 'train_kennard', 'train_lescault', 'train_mouse', 'weaver', 'william', 'freeman_2a', 'freeman_3', 'pat4']) in 'parameter_2502' Dropdown component
+ preset, // string (Option from: ['ultra_fast', 'fast', 'standard', 'high_quality']) in 'parameter_2507' Dropdown component
+ seed, // number in 'parameter_2521' Number component
+ cvvp_amount, // number (numeric value between 0.0 and 1.0) in 'CVVP Amount' Slider component
+ split_prompt, // boolean in 'Split prompt by lines' Checkbox component
+ samples, // number (numeric value between 4 and 256) in 'Samples' Slider component
+ diffusion_iterations, // number (numeric value between 4 and 400) in 'Diffusion Iterations' Slider component
+ temperature, // number (numeric value between 0.0 and 1.0) in 'Temperature' Slider component
+ length_penalty, // number (numeric value between 0.0 and 10.0) in 'Length Penalty' Slider component
+ repetition_penalty, // number (numeric value between 0.0 and 10.0) in 'Repetition Penalty' Slider component
+ top_p, // number (numeric value between 0.0 and 1.0) in 'Top P' Slider component
+ max_mel_tokens, // number (numeric value between 10 and 600) in 'Max Mel Tokens' Slider component
+ cond_free, // boolean in 'Cond Free' Checkbox component
+ cond_free_k, // number (numeric value between 0 and 10) in 'Cond Free K' Slider component
+ diffusion_temperature, // number (numeric value between 0.0 and 1.0) in 'Temperature' Slider component
+ model, // string (Option from: ['Default']) in 'parameter_2488' Dropdown component
+ generation_name, // string in 'Generation Name' Textbox component
+ ])) as {
+ data: [
+ GradioFile, // audio
+ string, // image
+ Object, // save_button
+ string, // seed
+ string, // bundle_name
+ Object // metadata
+ ];
+ };
+
+ const [audio, image, save_button, seed2, bundle_name, metadata] =
+ result?.data;
+
+ return {
+ audio,
+ image,
+ save_button,
+ seed: seed2,
+ bundle_name,
+ metadata,
+ };
+}
+
+async function tortoise_refresh_models() {
+ const app = await getClient();
+
+ const result = (await app.predict("/tortoise_refresh_models")) as {
+ data: [
+ {
+ choices: string[];
+ __type__: "update";
+ }
+ ];
+ };
+
+ return result?.data[0].choices;
+}
+
+async function tortoise_refresh_voices() {
+ const app = await getClient();
+
+ const result = (await app.predict("/tortoise_refresh_voices")) as {
+ data: [
+ {
+ choices: string[];
+ __type__: "update";
+ }
+ ];
+ };
+
+ return result?.data[0].choices;
+}
+
+async function tortoise_open_models() {
+ const app = await getClient();
+
+ const result = (await app.predict("/tortoise_open_models")) as {};
+
+ return result;
+}
+
+async function tortoise_open_voices() {
+ const app = await getClient();
+
+ const result = (await app.predict("/tortoise_open_voices")) as {};
+
+ return result;
+}
+
+async function tortoise_apply_model_settings({
+ model, // string (Option from: ['Default']) in 'parameter_2488' Dropdown component
+ kv_cache, // boolean in 'parameter_2493' Checkbox component
+ use_deepspeed, // boolean in 'parameter_2494' Checkbox component
+ half, // boolean in 'parameter_2495' Checkbox component
+ tokenizer, // string (Option from: ['quantifier_hubert_base_ls960.pth @ GitMylo/bark-voice-cloning', 'quantifier_hubert_base_ls960_14.pth @ GitMylo/bark-voice-cloning', 'quantifier_V1_hubert_base_ls960_23.pth @ GitMylo/bark-voice-cloning', 'polish-HuBERT-quantizer_8_epoch.pth @ Hobis/bark-voice-cloning-polish-HuBERT-quantizer', 'german-HuBERT-quantizer_14_epoch.pth @ CountFloyd/bark-voice-cloning-german-HuBERT-quantizer', 'es_tokenizer.pth @ Lancer1408/bark-es-tokenizer', 'portuguese-HuBERT-quantizer_24_epoch.pth @ MadVoyager/bark-voice-cloning-portuguese-HuBERT-quantizer']) in 'Tokenizer' Dropdown component
+ use_basic_cleaners, // boolean in 'parameter_2497' Checkbox component
+}) {
+ const app = await getClient();
+ const tokenizer_file = await getFile(tokenizer);
+
+ const result = (await app.predict("/tortoise_apply_model_settings", [
+ model, // string (Option from: ['Default']) in 'parameter_2488' Dropdown component
+ kv_cache, // boolean in 'parameter_2493' Checkbox component
+ use_deepspeed, // boolean in 'parameter_2494' Checkbox component
+ half, // boolean in 'parameter_2495' Checkbox component
+ // tokenizer, // string (Option from: ['quantifier_hubert_base_ls960.pth @ GitMylo/bark-voice-cloning', 'quantifier_hubert_base_ls960_14.pth @ GitMylo/bark-voice-cloning', 'quantifier_V1_hubert_base_ls960_23.pth @ GitMylo/bark-voice-cloning', 'polish-HuBERT-quantizer_8_epoch.pth @ Hobis/bark-voice-cloning-polish-HuBERT-quantizer', 'german-HuBERT-quantizer_14_epoch.pth @ CountFloyd/bark-voice-cloning-german-HuBERT-quantizer', 'es_tokenizer.pth @ Lancer1408/bark-es-tokenizer', 'portuguese-HuBERT-quantizer_24_epoch.pth @ MadVoyager/bark-voice-cloning-portuguese-HuBERT-quantizer']) in 'Tokenizer' Dropdown component
+ tokenizer_file, // blob in 'Tokenizer' File component
+ use_basic_cleaners, // boolean in 'parameter_2497' Checkbox component
+ ])) as {
+ data: [
+ Object // Models dropdown
+ ];
+ };
+
+ return result?.data;
+}
+
+async function rvc({
+ pitch_up_key,
+ original_audio,
+ index,
+ pitch_collection_method,
+ model,
+ search_feature_ratio,
+ device,
+ use_half_precision_model,
+ filter_radius_pitch,
+ resample_sample_rate_bug,
+ voice_envelope_normalizaiton,
+ protect_breath_sounds,
+}) {
+ const original_audioBlob = await getFile(original_audio);
+ // const indexPath = getIndex(index);
+ // const modelPath = getModelPath(model);
+ const indexPath = index;
+ const modelPath = model;
+
+ const app = await getClient();
+ // const result = (await app.predict("/rvc", [
+ const result = (await app.predict("/rvc_api", [
+ pitch_up_key, // string in 'Pitch Up key' Textbox component
+ original_audioBlob, // blob in 'Original Audio' Audio component
+ // indexBlob, // blob in 'Index' File component
+ indexPath, // blob in 'Index' File component
+ pitch_collection_method, // string (Option from: ['harvest', 'reaper', 'melodia']) in 'Pitch Collection Method' Radio component
+ // modelBlob, // blob in 'Model' File component
+ modelPath, // blob in 'Model' File component
+ search_feature_ratio, // number (numeric value between 0.0 and 1.0) in 'Search Feature Ratio' Slider component
+ device, // string (Option from: ['cuda:0', 'cpu', 'mps']) in 'Device' Dropdown component
+ use_half_precision_model, // boolean in 'Use half precision model (Depends on GPU support)' Checkbox component
+ filter_radius_pitch, // number (numeric value between 0 and 10) in 'Filter Radius (Pitch)' Slider component
+ resample_sample_rate_bug, // number (numeric value between 0 and 48000) in 'Resample Sample-rate (Bug)' Slider component
+ voice_envelope_normalizaiton, // number (numeric value between 0.0 and 1.0) in 'Voice Envelope Normalizaiton' Slider component
+ protect_breath_sounds, // number (numeric value between 0.0 and 0.5) in 'Protect Breath Sounds' Slider component
+ ])) as {
+ data: [
+ GradioFile, // audio
+ Object // metadata
+ ];
+ };
+
+ const [audio, metadata] = result?.data;
+ return {
+ audio,
+ metadata,
+ };
+}
+
+async function rvc_model_reload() {
+ const app = await getClient();
+
+ const result = (await app.predict("/rvc_model_reload")) as {
+ data: [
+ {
+ choices: string[];
+ __type__: "update";
+ }
+ ];
+ };
+
+ return result?.data[0].choices;
+}
+
+async function rvc_index_reload() {
+ const app = await getClient();
+
+ const result = (await app.predict("/rvc_index_reload")) as {
+ data: [
+ {
+ choices: string[];
+ __type__: "update";
+ }
+ ];
+ };
+
+ return result?.data[0].choices;
+}
+
+// rvc_model_open
+
+async function rvc_model_open() {
+ const app = await getClient();
+
+ const result = (await app.predict("/rvc_model_open")) as {};
+
+ return result;
+}
+
+// rvc_index_open
+
+async function rvc_index_open() {
+ const app = await getClient();
+
+ const result = (await app.predict("/rvc_index_open")) as {};
+
+ return result;
+}
+
+// delete_generation
+
+async function delete_generation({ history_bundle_name_data }) {
+ const app = await getClient();
+
+ const result = (await app.predict("/delete_generation", [
+ history_bundle_name_data,
+ ])) as {};
+
+ return result;
+}
+
+// save_to_voices
+
+async function save_to_voices({ history_npz }) {
+ const app = await getClient();
+
+ const result = (await app.predict("/save_to_voices", [history_npz])) as {
+ data: [
+ Object // save_button
+ ];
+ };
+
+ return result;
+}
+
+// open_folder
+
+async function open_folder({ folder }) {
+ const app = await getClient();
+
+ const result = (await app.predict("/open_folder", [folder])) as {};
+
+ return result;
+}
+
+// save_environment_variables_bark
+
+async function save_environment_variables_bark({
+ use_small_models,
+ enable_mps,
+ offload_gpu_models_to_cpu,
+}) {
+ const app = await getClient();
+
+ const result = (await app.predict("/save_environment_variables_bark", [
+ use_small_models, // boolean in 'Use small models' Checkbox component
+ enable_mps, // boolean in 'Enable MPS' Checkbox component
+ offload_gpu_models_to_cpu, // boolean in 'Offload GPU models to CPU' Checkbox component
+ ])) as {
+ data: [];
+ };
+
+ return result?.data;
+}
+
+// save_config_bark
+
+async function save_config_bark({
+ text_generation_use_gpu,
+ text_generation_use_small_model,
+ coarse_to_fine_inference_use_gpu,
+ coarse_to_fine_inference_use_small_model,
+ fine_tuning_use_gpu,
+ fine_tuning_use_small_model,
+ use_gpu_codec,
+ load_models_on_startup,
+}) {
+ const app = await getClient();
+
+ const result = (await app.predict("/save_config_bark", [
+ text_generation_use_gpu, // boolean in 'Use GPU' Checkbox component
+ text_generation_use_small_model, // boolean in 'Use small model' Checkbox component
+ coarse_to_fine_inference_use_gpu, // boolean in 'Use GPU' Checkbox component
+ coarse_to_fine_inference_use_small_model, // boolean in 'Use small model' Checkbox component
+ fine_tuning_use_gpu, // boolean in 'Use GPU' Checkbox component
+ fine_tuning_use_small_model, // boolean in 'Use small model' Checkbox component
+ use_gpu_codec, // boolean in 'Use GPU for codec' Checkbox component
+ load_models_on_startup, // boolean in 'Load Bark models on startup' Checkbox component
+ ])) as {
+ data: [
+ string // string representing output in 'value_1541' Markdown component
+ ];
+ };
+
+ return result?.data[0];
+}
+
+// get_config_bark
+
+async function get_config_bark() {
+ const app = await getClient();
+
+ const result = (await app.predict("/get_config_bark", [])) as {
+ data: [
+ { value: boolean }, // boolean representing output in 'Use GPU' Checkbox component
+ { value: boolean }, // boolean representing output in 'Use small model' Checkbox component
+ { value: boolean }, // boolean representing output in 'Use GPU' Checkbox component
+ { value: boolean }, // boolean representing output in 'Use small model' Checkbox component
+ { value: boolean }, // boolean representing output in 'Use GPU' Checkbox component
+ { value: boolean }, // boolean representing output in 'Use small model' Checkbox component
+ { value: boolean }, // boolean representing output in 'Use GPU for codec' Checkbox component
+ { value: boolean } // boolean representing output in 'Load Bark models on startup' Checkbox component
+ ];
+ };
+
+ const [
+ { value: text_generation_use_gpu },
+ { value: text_generation_use_small_model },
+ { value: coarse_to_fine_inference_use_gpu },
+ { value: coarse_to_fine_inference_use_small_model },
+ { value: fine_tuning_use_gpu },
+ { value: fine_tuning_use_small_model },
+ { value: use_gpu_codec },
+ { value: load_models_on_startup },
+ ] = result?.data;
+
+ return {
+ text_generation_use_gpu,
+ text_generation_use_small_model,
+ coarse_to_fine_inference_use_gpu,
+ coarse_to_fine_inference_use_small_model,
+ fine_tuning_use_gpu,
+ fine_tuning_use_small_model,
+ use_gpu_codec,
+ load_models_on_startup,
+ };
+}
+
+const endpoints = {
+ demucs,
+ musicgen,
+ vocos_wav,
+ vocos_npz,
+ encodec_decode,
+ bark_voice_tokenizer_load,
+ bark_voice_generate,
+ bark,
+ reload_old_generation_dropdown,
+ bark_favorite,
+ delete_generation,
+ tortoise,
+ tortoise_refresh_models,
+ tortoise_refresh_voices,
+ tortoise_open_models,
+ tortoise_open_voices,
+ tortoise_apply_model_settings,
+ rvc,
+ rvc_model_reload,
+ rvc_index_reload,
+ rvc_model_open,
+ rvc_index_open,
+ save_to_voices,
+ open_folder,
+
+ save_environment_variables_bark,
+ save_config_bark,
+ get_config_bark,
+};
diff --git a/react-ui/src/pages/api/webui-generations/[...name].ts b/react-ui/src/pages/api/webui-generations/[...name].ts
new file mode 100644
index 00000000..3f0840a8
--- /dev/null
+++ b/react-ui/src/pages/api/webui-generations/[...name].ts
@@ -0,0 +1,23 @@
+// pages/api/images/[name].js
+
+// Tell Next.js to pass in Node.js HTTP
+export const config = {
+ api: { externalResolver: true },
+};
+
+import express from "express";
+import { webuiBasePath } from "../../../data/getVoicesData";
+const handler = express();
+const simpleLogger = (req, res, next) => {
+ console.log(req.method, req.url);
+ next();
+};
+// add logging middleware
+handler.use(simpleLogger);
+
+const serveFiles = express.static(webuiBasePath);
+handler.use(["/api/webui-generations"], simpleLogger, serveFiles);
+
+// express is just a function that takes (http.IncomingMessage, http.ServerResponse),
+// which Next.js supports when externalResolver is enabled.
+export default handler;
diff --git a/react-ui/src/pages/bark.tsx b/react-ui/src/pages/bark.tsx
new file mode 100644
index 00000000..f25a6b2d
--- /dev/null
+++ b/react-ui/src/pages/bark.tsx
@@ -0,0 +1,1030 @@
+import React from "react";
+import { Template } from "../components/Template";
+import useLocalStorage from "../hooks/useLocalStorage";
+import { AudioInput, AudioOutput } from "../components/AudioComponents";
+import Head from "next/head";
+import {
+ BarkGenerationParams,
+ barkGenerationId,
+ initialState,
+} from "../tabs/BarkGenerationParams";
+import { GradioFile } from "../types/GradioFile";
+
+type Result = {
+ audio: GradioFile;
+ image: string;
+ save_button: Object;
+ continue_button: Object;
+ buttons_row: Object;
+ npz: string;
+ seed: null;
+ json_text: {
+ _version: string;
+ _hash_version: string;
+ _type: string;
+ is_big_semantic_model: boolean;
+ is_big_coarse_model: boolean;
+ is_big_fine_model: boolean;
+ prompt: string;
+ language: string;
+ speaker_id: string;
+ hash: string;
+ history_prompt: string;
+ history_prompt_npz: string;
+ history_hash: string;
+ text_temp: number;
+ waveform_temp: number;
+ date: string;
+ seed: string;
+ semantic_prompt: string;
+ coarse_prompt: string;
+ };
+ history_bundle_name_data: string;
+};
+
+const favorite = async (_url: string, data?: Result) => {
+ const history_bundle_name_data = data?.history_bundle_name_data;
+ if (!history_bundle_name_data) return;
+ const response = await fetch("/api/gradio/bark_favorite", {
+ method: "POST",
+ body: JSON.stringify({
+ history_bundle_name_data,
+ }),
+ });
+ const result = await response.json();
+ return result;
+};
+
+const initialHistory = []; // prevent infinite loop
+const BarkGenerationPage = () => {
+ const [historyData, setHistoryData] = useLocalStorage(
+ "barkGenerationHistory",
+ initialHistory
+ );
+ const [data, setData] = useLocalStorage(
+ "barkGenerationOutput",
+ null
+ );
+ const [barkGenerationParams, setBarkVoiceGenerationParams] =
+ useLocalStorage(barkGenerationId, initialState);
+ // loading state
+ const [loading, setLoading] = React.useState(false);
+
+ async function barkGeneration() {
+ setLoading(true);
+ const response = await fetch("/api/gradio/bark", {
+ method: "POST",
+ body: JSON.stringify(barkGenerationParams),
+ });
+
+ const result = await response.json();
+ setData(result);
+ setHistoryData((historyData) => [result, ...historyData]);
+ setLoading(false);
+ }
+
+ const useAsHistory = (_url: string, data?: Result) => {
+ const npz = data?.npz;
+ if (!npz) return;
+ setBarkVoiceGenerationParams({
+ ...barkGenerationParams,
+ old_generation_dropdown: npz,
+ });
+ };
+
+ const useAsHistoryPromptSemantic = (_url: string, data?: Result) => {
+ const npz = data?.npz;
+ if (!npz) return;
+ setBarkVoiceGenerationParams({
+ ...barkGenerationParams,
+ history_prompt_semantic_dropdown: npz,
+ });
+ };
+
+ const useSeed = (_url: string, data?: Result) => {
+ const seed_input = data?.json_text?.seed;
+ if (!seed_input) return;
+ setBarkVoiceGenerationParams({
+ ...barkGenerationParams,
+ seed_input,
+ });
+ };
+
+ const useParametersTest = (_url: string, data?: Result) => {
+ const {
+ prompt,
+ language,
+ speaker_id,
+ text_temp,
+ waveform_temp,
+ history_prompt,
+ history_prompt_npz,
+ semantic_prompt,
+ coarse_prompt,
+ } = data?.json_text!;
+ if (!prompt) return;
+ setBarkVoiceGenerationParams({
+ ...barkGenerationParams,
+ prompt,
+ languageRadio: language,
+ speakerIdRadio: speaker_id,
+ text_temp,
+ waveform_temp,
+ history_setting: history_prompt,
+ old_generation_dropdown: history_prompt_npz,
+ history_prompt_semantic_dropdown: semantic_prompt,
+ burn_in_prompt: coarse_prompt,
+ long_prompt_radio: "Short prompt (<15s)",
+ seed_input: data?.json_text?.seed ?? "-1",
+ useV2: data?.json_text?.history_prompt?.includes("v2") ?? true,
+ });
+ };
+
+ const funcs = [
+ useAsHistory,
+ useAsHistoryPromptSemantic,
+ useSeed,
+ favorite,
+ useParametersTest,
+ ];
+
+ const handleChange = (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => {
+ const { name, value, type } = event.target;
+ setBarkVoiceGenerationParams({
+ ...barkGenerationParams,
+ [name]:
+ type === "number" || type === "range"
+ ? Number(value)
+ : type === "checkbox"
+ ? (event.target as HTMLInputElement).checked // type assertion
+ : value,
+ });
+ };
+
+ return (
+
+
+ Bark - TTS Generation Webui
+
+
+
+
+
+
+
+
+
+
+
+ {historyData &&
+ historyData.map((item, index) => (
+
+ ))}
+
+
+
+ {/* {JSON.stringify(barkGenerationParams, null, 2)}
*/}
+
+ );
+};
+
+export default BarkGenerationPage;
+
+function Inputs({
+ barkGenerationParams,
+ setBarkVoiceGenerationParams,
+ handleChange,
+ data,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ setBarkVoiceGenerationParams: (
+ barkGenerationParams: BarkGenerationParams
+ ) => void;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+ data: Result | null;
+}) {
+ return (
+
+
+ {/* {HistoryPromptVoiceSetting({ barkGenerationParams, handleChange })} */}
+
+
+
+
+ {barkGenerationParams.history_setting === "or Use a voice:" && (
+
+ )}
+ {barkGenerationParams.history_setting ===
+ "or Use old generation as history:" && (
+
+ )}
+
+
+ {/* {PromptType({ barkGenerationParams, handleChange })} */}
+
+
+
+
+
+
+
+ );
+}
+
+const ForEachSubsequentGeneration = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+
+
+
+ {[
+ "Use old generation as history",
+ "or Use history prompt setting",
+ "or Clear history",
+ ].map((subsequentSetting) => (
+
+
+
+
+ ))}
+
+
+ );
+};
+
+const randomSeed = () => {
+ return Math.floor(Math.random() * 2 ** 32);
+};
+
+const Seed = ({
+ barkGenerationParams,
+ setBarkVoiceGenerationParams,
+ handleChange,
+ lastSeed,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ setBarkVoiceGenerationParams: (
+ barkGenerationParams: BarkGenerationParams
+ ) => void;
+ handleChange: (event: React.ChangeEvent) => void;
+ lastSeed?: string;
+}) => {
+ return (
+
+
+
+
+
+
+ );
+};
+
+// generic old generation dropdown for both OldGeneration and HistoryPromptSemantic
+const OldGenerationDropdown = ({
+ barkGenerationParams,
+ handleChange,
+ name,
+ label,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+ name: string;
+ label: string;
+}) => {
+ const [options, setOptions] = React.useState([]);
+
+ React.useEffect(() => {
+ (async () => {
+ const response = await fetch(
+ "/api/gradio/reload_old_generation_dropdown",
+ {
+ method: "POST",
+ }
+ );
+
+ const result = await response.json();
+ setOptions(result);
+ })();
+ }, []);
+
+ const selected = barkGenerationParams?.[name];
+ return (
+
+
+
+
+
+ );
+};
+
+const OldGeneration = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+
+ );
+};
+
+const HistoryPromptSemantic = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+
+ );
+};
+
+const create_voice_string = (
+ language: string,
+ speaker_id: string,
+ use_v2: boolean
+) => {
+ const language_to_code = {
+ English: "en",
+ Chinese: "zh",
+ French: "fr",
+ German: "de",
+ Hindi: "hi",
+ Italian: "it",
+ Japanese: "ja",
+ Korean: "ko",
+ Polish: "pl",
+ Portuguese: "pt",
+ Russian: "ru",
+ Spanish: "es",
+ Turkish: "tr",
+ };
+ let history_prompt = `${language_to_code[language]}_speaker_${speaker_id}`;
+ if (use_v2) {
+ history_prompt = `v2/${history_prompt}`;
+ }
+ return history_prompt;
+};
+
+const voice_to_trait = {
+ "v2/en_speaker_0": "Male",
+ "v2/en_speaker_1": "Male",
+ "v2/en_speaker_2": "Male",
+ "v2/en_speaker_3": "Male",
+ "v2/en_speaker_4": "Male",
+ "v2/en_speaker_5": "Male",
+ "v2/en_speaker_6": "Male",
+ "v2/en_speaker_7": "Male",
+ "v2/en_speaker_8": "Male",
+ "v2/en_speaker_9": "Female",
+ "v2/zh_speaker_0": "Male",
+ "v2/zh_speaker_1": "Male",
+ "v2/zh_speaker_2": "Male",
+ "v2/zh_speaker_3": "Male",
+ "v2/zh_speaker_4": "Female",
+ "v2/zh_speaker_5": "Male",
+ "v2/zh_speaker_6": "Female",
+ "v2/zh_speaker_7": "Female",
+ "v2/zh_speaker_8": "Male",
+ "v2/zh_speaker_9": "Female",
+ "v2/fr_speaker_0": "Male",
+ "v2/fr_speaker_1": "Female",
+ "v2/fr_speaker_2": "Female",
+ "v2/fr_speaker_3": "Male",
+ "v2/fr_speaker_4": "Male",
+ "v2/fr_speaker_5": "Female",
+ "v2/fr_speaker_6": "Male",
+ "v2/fr_speaker_7": "Male",
+ "v2/fr_speaker_8": "Male",
+ "v2/fr_speaker_9": "Male",
+ "v2/de_speaker_0": "Male",
+ "v2/de_speaker_1": "Male",
+ "v2/de_speaker_2": "Male",
+ "v2/de_speaker_3": "Female",
+ "v2/de_speaker_4": "Male",
+ "v2/de_speaker_5": "Male",
+ "v2/de_speaker_6": "Male",
+ "v2/de_speaker_7": "Male",
+ "v2/de_speaker_8": "Female",
+ "v2/de_speaker_9": "Male",
+ "v2/hi_speaker_0": "Female",
+ "v2/hi_speaker_1": "Female",
+ "v2/hi_speaker_2": "Male",
+ "v2/hi_speaker_3": "Female",
+ "v2/hi_speaker_4": "Female",
+ "v2/hi_speaker_5": "Male",
+ "v2/hi_speaker_6": "Male",
+ "v2/hi_speaker_7": "Male",
+ "v2/hi_speaker_8": "Male",
+ "v2/hi_speaker_9": "Female",
+ "v2/it_speaker_0": "Male",
+ "v2/it_speaker_1": "Male",
+ "v2/it_speaker_2": "Female",
+ "v2/it_speaker_3": "Male",
+ "v2/it_speaker_4": "Male",
+ "v2/it_speaker_5": "Male",
+ "v2/it_speaker_6": "Male",
+ "v2/it_speaker_7": "Female",
+ "v2/it_speaker_8": "Male",
+ "v2/it_speaker_9": "Female",
+ "v2/ja_speaker_0": "Female",
+ "v2/ja_speaker_1": "Female",
+ "v2/ja_speaker_2": "Male",
+ "v2/ja_speaker_3": "Female",
+ "v2/ja_speaker_4": "Female",
+ "v2/ja_speaker_5": "Female",
+ "v2/ja_speaker_6": "Male",
+ "v2/ja_speaker_7": "Female",
+ "v2/ja_speaker_8": "Female",
+ "v2/ja_speaker_9": "Female",
+ "v2/ko_speaker_0": "Female",
+ "v2/ko_speaker_1": "Male",
+ "v2/ko_speaker_2": "Male",
+ "v2/ko_speaker_3": "Male",
+ "v2/ko_speaker_4": "Male",
+ "v2/ko_speaker_5": "Male",
+ "v2/ko_speaker_6": "Male",
+ "v2/ko_speaker_7": "Male",
+ "v2/ko_speaker_8": "Male",
+ "v2/ko_speaker_9": "Male",
+ "v2/pl_speaker_0": "Male",
+ "v2/pl_speaker_1": "Male",
+ "v2/pl_speaker_2": "Male",
+ "v2/pl_speaker_3": "Male",
+ "v2/pl_speaker_4": "Female",
+ "v2/pl_speaker_5": "Male",
+ "v2/pl_speaker_6": "Female",
+ "v2/pl_speaker_7": "Male",
+ "v2/pl_speaker_8": "Male",
+ "v2/pl_speaker_9": "Female",
+ "v2/pt_speaker_0": "Male",
+ "v2/pt_speaker_1": "Male",
+ "v2/pt_speaker_2": "Male",
+ "v2/pt_speaker_3": "Male",
+ "v2/pt_speaker_4": "Male",
+ "v2/pt_speaker_5": "Male",
+ "v2/pt_speaker_6": "Male",
+ "v2/pt_speaker_7": "Male",
+ "v2/pt_speaker_8": "Male",
+ "v2/pt_speaker_9": "Male",
+ "v2/ru_speaker_0": "Male",
+ "v2/ru_speaker_1": "Male",
+ "v2/ru_speaker_2": "Male",
+ "v2/ru_speaker_3": "Male",
+ "v2/ru_speaker_4": "Male",
+ "v2/ru_speaker_5": "Female",
+ "v2/ru_speaker_6": "Female",
+ "v2/ru_speaker_7": "Male",
+ "v2/ru_speaker_8": "Male",
+ "v2/ru_speaker_9": "Female",
+ "v2/es_speaker_0": "Male",
+ "v2/es_speaker_1": "Male",
+ "v2/es_speaker_2": "Male",
+ "v2/es_speaker_3": "Male",
+ "v2/es_speaker_4": "Male",
+ "v2/es_speaker_5": "Male",
+ "v2/es_speaker_6": "Male",
+ "v2/es_speaker_7": "Male",
+ "v2/es_speaker_8": "Female",
+ "v2/es_speaker_9": "Female",
+ "v2/tr_speaker_0": "Male",
+ "v2/tr_speaker_1": "Male",
+ "v2/tr_speaker_2": "Male",
+ "v2/tr_speaker_3": "Male",
+ "v2/tr_speaker_4": "Female",
+ "v2/tr_speaker_5": "Female",
+ "v2/tr_speaker_6": "Male",
+ "v2/tr_speaker_7": "Male",
+ "v2/tr_speaker_8": "Male",
+ "v2/tr_speaker_9": "Male",
+};
+
+const generate_choice_string = (
+ use_v2: boolean,
+ language: string,
+ speaker_id: string
+) => {
+ const history_prompt = create_voice_string(language, speaker_id, use_v2);
+ return `Chosen voice: ${history_prompt}, gender: ${voice_to_trait[history_prompt]}`;
+};
+
+const Voice = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ return (
+
+
Voice:
+
+
+
+ {/* Display selected voice info */}
+
+
+ {generate_choice_string(
+ barkGenerationParams.useV2,
+ barkGenerationParams.languageRadio,
+ barkGenerationParams.speakerIdRadio
+ )}
+
+
+
+ );
+};
+
+const HistoryPromptVoiceSetting = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ return (
+
+
+
+ {[
+ "Empty history",
+ "or Use a voice:",
+ "or Use old generation as history:",
+ ].map((model) => (
+
+
+
+
+ ))}
+
+
+ );
+};
+
+const PromptType = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ return (
+
+
+
+ {["Short prompt (<15s)", "Split prompt by lines"].map((promptType) => (
+
+
+
+
+ ))}
+
+
+ );
+};
+
+const Language = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+ <>
+
+
+ {[
+ "English",
+ "German",
+ "Spanish",
+ "French",
+ "Hindi",
+ "Italian",
+ "Japanese",
+ "Korean",
+ "Polish",
+ "Portuguese",
+ "Russian",
+ "Turkish",
+ "Chinese",
+ ].map((model) => (
+
+
+
+
+ ))}
+
+ >
+ );
+};
+
+const GenericPrompt = ({
+ barkGenerationParams,
+ handleChange,
+ label,
+ name,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+ label: string;
+ name: string;
+}) => {
+ return (
+
+
+
+
+ );
+};
+
+const BurnInPrompt = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+
+ );
+};
+
+const Prompt = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ return (
+
+ );
+};
+
+const GenericTemp = ({
+ barkGenerationParams,
+ handleChange,
+ label,
+ name,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+ label: string;
+ name: string;
+}) => {
+ return (
+
+
+
+
+ );
+};
+
+const TextTemp = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+
+ );
+};
+
+const WaveformTemp = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+
+ );
+};
+
+const UseV2 = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+
+
+
+
+ );
+};
+
+const SpeakerID = ({
+ barkGenerationParams,
+ handleChange,
+}: {
+ barkGenerationParams: BarkGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+ <>
+
+
+ {["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"].map((model) => (
+
+
+
+
+ ))}
+
+ >
+ );
+};
diff --git a/react-ui/src/pages/bark_settings.tsx b/react-ui/src/pages/bark_settings.tsx
new file mode 100644
index 00000000..f13e4a73
--- /dev/null
+++ b/react-ui/src/pages/bark_settings.tsx
@@ -0,0 +1,283 @@
+import React from "react";
+import { Template } from "../components/Template";
+import Head from "next/head";
+import useLocalStorage from "../hooks/useLocalStorage";
+import {
+ BarkSettingsParams,
+ initialBarkSettingsParams,
+ barkSettingsId,
+} from "../tabs/BarkSettingsParams";
+
+type Result = string;
+
+const BarkSettingsPage = () => {
+ const [data, setData] = useLocalStorage(
+ "barkSettingsBeacon",
+ null
+ );
+ const [barkSettingsParams, setBarkSettingsParams] =
+ useLocalStorage(
+ barkSettingsId,
+ initialBarkSettingsParams
+ );
+
+ React.useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const response = await fetch("/api/gradio/get_config_bark");
+ const data = await response.json();
+ setBarkSettingsParams((x) => ({ ...x, ...data } as BarkSettingsParams));
+ } catch (error) {
+ console.error("Error:", error);
+ }
+ };
+ fetchData();
+ }, []);
+
+ const handleChange = async (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => {
+ const { name, value, type } = event.target;
+
+ const newBarkSettingsParams = {
+ ...barkSettingsParams,
+ [name]:
+ type === "number" || type === "range"
+ ? Number(value)
+ : type === "checkbox"
+ ? (event.target as HTMLInputElement).checked // type assertion
+ : value,
+ };
+
+ const isConfig =
+ name === "text_generation_use_gpu" ||
+ name === "text_generation_use_small_model" ||
+ name === "coarse_to_fine_inference_use_gpu" ||
+ name === "coarse_to_fine_inference_use_small_model" ||
+ name === "fine_tuning_use_gpu" ||
+ name === "fine_tuning_use_small_model" ||
+ name === "use_gpu_codec" ||
+ name === "load_models_on_startup";
+
+ const isEnv =
+ name === "use_small_models" ||
+ name === "enable_mps" ||
+ name === "offload_gpu_models_to_cpu";
+
+ if (isConfig) {
+ try {
+ const response = await fetch("/api/gradio/save_config_bark", {
+ method: "POST",
+ body: JSON.stringify(newBarkSettingsParams),
+ });
+ const data = await response.json();
+ setBarkSettingsParams(newBarkSettingsParams);
+ setData(data);
+ } catch (error) {
+ console.error("Error:", error);
+ }
+ }
+
+ if (isEnv) {
+ try {
+ await fetch(
+ "/api/gradio/save_environment_variables_bark",
+ {
+ method: "POST",
+ body: JSON.stringify(newBarkSettingsParams),
+ }
+ );
+ } catch (error) {
+ console.error("Error:", error);
+ }
+ }
+ };
+
+ return (
+
+
+ Bark Settings - TTS Generation Webui
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Save Beacon */}
+
+ {data}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Recommended settings:
+
+ - For VRAM >= 10GB, use large models.
+ - For VRAM < 10GB, use small models.
+
+ -
+ Text generation and coarse-to-fine are of similar importance.
+
+ - Small models might not have a perceptible difference.
+
+ -
+ For VRAM < 4GB, use CPU offloading (requires restart).
+
+ - Small models are also recommended.
+
+
+ -
+ For VRAM < 2GB, use CPU offloading and small models (requires
+ restart).
+
+
+
+
+
+
+ );
+};
+
+export default BarkSettingsPage;
diff --git a/react-ui/src/pages/bark_voice_generation.tsx b/react-ui/src/pages/bark_voice_generation.tsx
new file mode 100644
index 00000000..10baad39
--- /dev/null
+++ b/react-ui/src/pages/bark_voice_generation.tsx
@@ -0,0 +1,160 @@
+import React from "react";
+import { Template } from "../components/Template";
+import useLocalStorage from "../hooks/useLocalStorage";
+import { AudioInput, AudioOutput } from "../components/AudioComponents";
+import Head from "next/head";
+import {
+ BarkVoiceGenerationParams,
+ barkVoiceGenerationId,
+ initialState,
+} from "../tabs/BarkVoiceGenerationParams";
+import { GradioFile } from "../types/GradioFile";
+
+type Result = {
+ filename: string;
+ preview: GradioFile;
+};
+
+const BarkVoiceGenerationPage = () => {
+ const [data, setData] = useLocalStorage(
+ "barkVoiceGenerationOutput",
+ null
+ );
+ const [barkVoiceGenerationParams, setBarkVoiceGenerationParams] =
+ useLocalStorage(
+ barkVoiceGenerationId,
+ initialState
+ );
+
+ async function barkVoiceGeneration() {
+ const response = await fetch("/api/gradio/bark_voice_generate", {
+ method: "POST",
+ body: JSON.stringify(barkVoiceGenerationParams),
+ });
+
+ const result = await response.json();
+ setData(result);
+ }
+
+ async function barkVoiceTokenizerLoad(
+ barkVoiceGenerationParams: BarkVoiceGenerationParams
+ ) {
+ const response = await fetch("/api/gradio/bark_voice_tokenizer_load", {
+ method: "POST",
+ body: JSON.stringify(barkVoiceGenerationParams),
+ });
+
+ const result = await response.json();
+ // setData(result);
+ }
+
+ const useAsInput = (audio?: string) => {
+ if (!audio) return;
+ setBarkVoiceGenerationParams({
+ ...barkVoiceGenerationParams,
+ audio,
+ });
+ };
+
+ const handleChange = (e: React.ChangeEvent) => {
+ const newParams = {
+ ...barkVoiceGenerationParams,
+ [e.target.name]: e.target.value,
+ };
+ setBarkVoiceGenerationParams(newParams);
+ barkVoiceTokenizerLoad(newParams);
+ };
+
+ return (
+
+
+ Bark Voice Generation - TTS Generation Webui
+
+
+
+
+
+
+
+
+ {/* Print voice filename */}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default BarkVoiceGenerationPage;
diff --git a/react-ui/src/pages/demucs.tsx b/react-ui/src/pages/demucs.tsx
index f8fc58aa..66fbc3fc 100644
--- a/react-ui/src/pages/demucs.tsx
+++ b/react-ui/src/pages/demucs.tsx
@@ -1,81 +1,73 @@
-import React, { useState } from "react";
+import React from "react";
import { Template } from "../components/Template";
-import FileInput from "../components/FileInput";
-import { AudioPlayer } from "../components/MemoizedWaveSurferPlayer";
+import useLocalStorage from "../hooks/useLocalStorage";
+import { AudioInput, AudioOutput } from "../components/AudioComponents";
+import Head from "next/head";
+import { DemucsParams, demucsId, initialState } from "../tabs/DemucsParams";
+import { GradioFile } from "../types/GradioFile";
-type AudioOutput = {
- name: string;
- data: string;
- size?: number;
- is_file?: boolean;
- orig_name?: string;
+type TypedGradioFile = GradioFile & {
type_name?: string;
};
-function addTypeNameToAudioOutput(audioOutput: AudioOutput, typeName: string) {
- return { ...audioOutput, type_name: typeName };
-}
+const typeNames = ["drums", "bass", "other", "vocals"];
-function addTypeNamesToAudioOutputs(
- audioOutputs: AudioOutput[],
+const addTypeNamesToAudioOutputs = (
+ audioOutputs: TypedGradioFile[],
typeNames: string[]
-) {
- return audioOutputs.map((audioOutput, index) =>
- addTypeNameToAudioOutput(audioOutput, typeNames[index])
- );
-}
-
-type MusicgenParams = {
- file: string | null;
-};
+) =>
+ audioOutputs.map((audioOutput, index) => ({
+ ...audioOutput,
+ type_name: typeNames[index],
+ }));
-const GradioPage = () => {
- const [data, setData] = useState(null);
- const [melody, setMelody] = useState();
-
- const [musicgenParams, setMusicgenParams] = useState({
- file: null,
- });
+const DemucsPage = () => {
+ const [data, setData] = useLocalStorage(
+ "demucsOutput",
+ null
+ );
+ const [demucsParams, setDemucsParams] = useLocalStorage(
+ demucsId,
+ initialState
+ );
async function demucs() {
- const response = await fetch("/api/demucs_musicgen", {
+ const response = await fetch("/api/gradio/demucs", {
method: "POST",
- body: JSON.stringify(musicgenParams),
+ body: JSON.stringify(demucsParams),
});
const result = await response.json();
- setData(result?.data);
+ setData(result);
}
- const typeNames = ["drums", "bass", "other", "vocals"];
const sampleWithTypeNames =
data && addTypeNamesToAudioOutputs(data, typeNames);
+ const useAsInput = (audio?: string) => {
+ if (!audio) return;
+ setDemucsParams({
+ ...demucsParams,
+ file: audio,
+ });
+ };
+
return (
-
-
-
-
{
- const melody = file?.name || null;
- setMelody(file && URL.createObjectURL(file));
- setMusicgenParams({
- ...musicgenParams,
- file: melody,
+
+ Demucs - TTS Generation Webui
+
+
+
+
{
+ setDemucsParams({
+ ...demucsParams,
+ file,
});
}}
- />
- {/* Preview melody */}
-
- {typeNames.map((typeName, index) => {
+
+
+ {typeNames.map((typeName) => {
const audioOutput = sampleWithTypeNames?.find(
(item) => item.type_name === typeName
);
return (
-
-
{typeName}
- {audioOutput && (
-
- )}
-
+
);
})}
@@ -112,4 +98,4 @@ const GradioPage = () => {
);
};
-export default GradioPage;
+export default DemucsPage;
diff --git a/react-ui/src/pages/generations.tsx b/react-ui/src/pages/generations.tsx
index 2e53b7ed..9aeb8f9f 100644
--- a/react-ui/src/pages/generations.tsx
+++ b/react-ui/src/pages/generations.tsx
@@ -5,6 +5,7 @@ import { CardEmpty, CardGeneration } from "../components/CardBig";
import { getOggData } from "../data/getVoicesData";
import { GenerationRaw } from "../types/Generation";
import { Template } from "../components/Template";
+import Head from "next/head";
export const inter = Inter({ subsets: ["latin"] });
@@ -15,9 +16,12 @@ export default function Home({
}) {
return (
+
+ Favorites - TTS Generation Webui
+
{generations.map((generation) => (
-
+
))}
+
+ Favorites - TTS Generation Webui
+
+
+ {outputs.map((generation) => (
+
+ ))}
+
+
+ );
+}
+
+export const getStaticProps = async ({ params: { name } }) => {
+ const outputs: GenerationRaw[] = await getDataFromJSON(name);
+ return {
+ props: {
+ outputs,
+ isFavorites: name === "favorites",
+ },
+ } as { props: Props };
+};
+
+export const getStaticPaths = async () => {
+ return {
+ paths: [
+ "/history/outputs",
+ "/history/favorites",
+ // "/history/collections",
+ ],
+ fallback: "blocking",
+ };
+};
diff --git a/react-ui/src/pages/index.tsx b/react-ui/src/pages/index.tsx
index d1f60e35..a01ad6c3 100644
--- a/react-ui/src/pages/index.tsx
+++ b/react-ui/src/pages/index.tsx
@@ -1,10 +1,7 @@
import { Inter } from "next/font/google";
import React from "react";
-import { Favorites } from "../components/FavoritesProvider";
-import { CardBig, CardEmpty } from "../components/CardBig";
import { Voice } from "../types/Voice";
-import { getVoicesData } from "../data/getVoicesData";
import { Template } from "../components/Template";
import Head from "next/head";
@@ -16,15 +13,27 @@ export default function Home({ voices }: { voices: Voice[] }) {
TTS Generation Webui
+
+
Welcome to the TTS Webui!
+
+ This is a web interface for the TTS project. It allows you to generate
+ audio using the TTS models.
+
+
+ To get started, select a tab above to choose a model and generate some
+ audio.
+
+
+ You can also listen to some of the voices that have been generated
+ using the "Favorites" button.
+
+
);
}
export const getStaticProps = async () => {
- const voices: Voice[] = getVoicesData();
return {
- props: {
- voices: voices,
- },
+ props: {},
};
};
diff --git a/react-ui/src/pages/musicgen.tsx b/react-ui/src/pages/musicgen.tsx
index f439b477..4e2fdc72 100644
--- a/react-ui/src/pages/musicgen.tsx
+++ b/react-ui/src/pages/musicgen.tsx
@@ -1,8 +1,14 @@
-import React, { useState } from "react";
+import React from "react";
import { Template } from "../components/Template";
import Head from "next/head";
-import FileInput from "../components/FileInput";
-import { AudioPlayer } from "../components/MemoizedWaveSurferPlayer";
+import useLocalStorage from "../hooks/useLocalStorage";
+import { AudioInput, AudioOutput } from "../components/AudioComponents";
+import {
+ MusicgenParams,
+ initialMusicgenParams,
+ musicgenId,
+} from "../tabs/MusicgenParams";
+import { GradioFile } from "../types/GradioFile";
type AudioOutput = {
name: string;
@@ -13,31 +19,29 @@ type AudioOutput = {
type_name?: string;
};
-const musicgenParams0: MusicgenParams = {
- // text: "",
- text: "lofi hip hop beats to relax/study to",
- melody: null,
- model: "Small",
- duration: 1,
- topk: 250,
- topp: 0,
- temperature: 1.0,
- cfg_coef: 3.0,
- seed: -1,
- use_multi_band_diffusion: false,
-};
-
-type MusicgenParams = {
- text: string;
- melody: string | null;
- model: string;
- duration: number;
- topk: number;
- topp: number;
- temperature: number;
- cfg_coef: number;
- seed: number;
- use_multi_band_diffusion: boolean;
+type Result = {
+ audio: GradioFile;
+ history_bundle_name_data: string;
+ json: {
+ _version: string;
+ _hash_version: string;
+ _type: string;
+ _audiocraft_version: string;
+ models: {};
+ prompt: string;
+ hash: string;
+ date: string;
+ melody?: any;
+ text: string;
+ model: string;
+ duration: number;
+ topk: number;
+ topp: number;
+ temperature: number;
+ cfg_coef: number;
+ seed: string;
+ use_multi_band_diffusion: boolean;
+ };
};
const modelNameMapping = {
@@ -48,15 +52,20 @@ const modelNameMapping = {
Audiogen: "facebook/audiogen-medium",
};
+const initialHistory = []; // prevent infinite loop
const MusicgenPage = () => {
- const [musicgenData, setMusicgenData] = useState(null);
- const [historyData, setHistoryData] = useState([]);
- const [lastSeed, setLastSeed] = useState(-1);
- const [image, setImage] = useState("");
- const [audioUrl, setAudioUrl] = useState("");
- const [musicgenParams, setMusicgenParams] =
- useState(musicgenParams0);
- const [melody, setMelody] = useState();
+ const [data, setData] = useLocalStorage(
+ "musicgenGenerationOutput",
+ null
+ );
+ const [historyData, setHistoryData] = useLocalStorage(
+ "musicgenHistory",
+ initialHistory
+ );
+ const [musicgenParams, setMusicgenParams] = useLocalStorage(
+ musicgenId,
+ initialMusicgenParams
+ );
async function musicgen() {
const body = JSON.stringify({
@@ -64,48 +73,23 @@ const MusicgenPage = () => {
melody: musicgenParams.model === "Melody" ? musicgenParams.melody : null,
model: modelNameMapping[musicgenParams.model],
});
- console.log(body);
- return;
- const response = await fetch("/api/demucs_musicgen", {
+ const response = await fetch("/api/gradio/musicgen", {
method: "POST",
body,
});
- const result = await response.json();
- const data = result?.data;
- const [generated_audio, , image, , json] = data;
- console.log(generated_audio, image, json);
- const { seed } = json;
- setMusicgenData(result?.data);
- setHistoryData((x) => [result?.data[0], ...x]);
- setLastSeed(seed);
- setImage(image);
- setAudioUrl(generated_audio.data);
+ const result: Result = await response.json();
+ setData(result);
+ setHistoryData((x) => [result, ...x]);
}
- const handleChange = async (
+ const handleChange = (
event:
| React.ChangeEvent
| React.ChangeEvent
| React.ChangeEvent
) => {
const { name, value, type } = event.target;
-
- if (name === "melody") {
- if (!(event.target instanceof HTMLInputElement)) return;
- const file = event.target.files?.[0];
- console.log(file);
- const reader = new FileReader();
- reader.readAsDataURL(file!);
- console.log(reader);
- console.log(reader.result);
- setMusicgenParams({
- ...musicgenParams,
- [name]: reader.result,
- });
- return;
- }
-
setMusicgenParams({
...musicgenParams,
[name]:
@@ -117,10 +101,56 @@ const MusicgenPage = () => {
});
};
+ const useAsMelody = (melody?: string, metadata?: Result) => {
+ if (!melody) return;
+ setMusicgenParams({
+ ...musicgenParams,
+ melody,
+ });
+ };
+
+ const favorite = async (_url: string, data?: Result) => {
+ const history_bundle_name_data = data?.history_bundle_name_data;
+ if (!history_bundle_name_data) return;
+ const response = await fetch("/api/gradio/bark_favorite", {
+ method: "POST",
+ body: JSON.stringify({
+ history_bundle_name_data,
+ }),
+ });
+ const result = await response.json();
+ return result;
+ };
+
+ const useSeed = (_url: string, data?: Result) => {
+ const seed = data?.json.seed;
+ if (!seed) return;
+ setMusicgenParams({
+ ...musicgenParams,
+ seed: Number(seed),
+ });
+ };
+
+ const useParameters = (_url: string, data?: Result) => {
+ const params = data?.json;
+ if (!params) return;
+ setMusicgenParams({
+ ...musicgenParams,
+ ...params,
+ seed: Number(params.seed),
+ model:
+ Object.keys(modelNameMapping).find(
+ (key) => modelNameMapping[key] === params.model
+ ) || "Small",
+ });
+ };
+
+ const funcs = [useAsMelody, favorite, useSeed, useParameters];
+
return (
- TTS Generation Webui - Musicgen
+ Musicgen - TTS Generation Webui
@@ -159,28 +189,16 @@ const MusicgenPage = () => {
)}
-
-
- {
- const melody = file?.name || null;
- setMelody(file && URL.createObjectURL(file));
+ {
setMusicgenParams({
...musicgenParams,
- melody,
+ melody: file,
});
}}
- />
- {/* Preview melody */}
-
@@ -266,7 +284,7 @@ const MusicgenPage = () => {
onClick={() =>
setMusicgenParams({
...musicgenParams,
- seed: lastSeed,
+ seed: Number(data?.json.seed) || -1,
})
}
>
@@ -297,55 +315,44 @@ const MusicgenPage = () => {
- {/* History */}
-
+
+
+ {/* Clear history */}
+
-
-
- {historyData &&
- historyData.map((item, index) => (
- //
-
- ))}
-
+ {historyData &&
+ historyData.map((item, index) => (
+
+ ))}
diff --git a/react-ui/src/pages/rvc.tsx b/react-ui/src/pages/rvc.tsx
new file mode 100644
index 00000000..6b1231c8
--- /dev/null
+++ b/react-ui/src/pages/rvc.tsx
@@ -0,0 +1,898 @@
+import React from "react";
+import { Template } from "../components/Template";
+import useLocalStorage from "../hooks/useLocalStorage";
+import { AudioInput, AudioOutput } from "../components/AudioComponents";
+import Head from "next/head";
+import { RVCParams, RVCId, initialState } from "../tabs/RVCParams";
+import { GradioFile } from "../types/GradioFile";
+
+type Result = {
+ audio: GradioFile;
+ metadata: {
+ original_audio_path: string;
+ index_path: string;
+ model_path: string;
+ f0method: string;
+ f0up_key: string;
+ index_rate: number;
+ device: string;
+ is_half: boolean;
+ filter_radius: number;
+ resample_sr: number;
+ rms_mix_rate: number;
+ protect: number;
+ };
+};
+
+const initialHistory = []; // prevent infinite loop
+const RvcGenerationPage = () => {
+ const [historyData, setHistoryData] = useLocalStorage(
+ "rvcGenerationHistory",
+ initialHistory
+ );
+ const [data, setData] = useLocalStorage(
+ "rvcGenerationOutput",
+ null
+ );
+ const [rvcGenerationParams, setRvcGenerationParams] =
+ useLocalStorage(RVCId, initialState);
+ const [loading, setLoading] = React.useState(false);
+
+ async function rvcGeneration() {
+ setLoading(true);
+ const response = await fetch("/api/gradio/rvc", {
+ method: "POST",
+ body: JSON.stringify(rvcGenerationParams),
+ });
+
+ const result = await response.json();
+ setData(result);
+ setHistoryData((historyData) => [result, ...historyData]);
+ setLoading(false);
+ }
+
+ // const favorite = async (_url: string, data?: Result) => {
+ // const history_bundle_name_data = data?.bundle_name;
+ // if (!history_bundle_name_data) return;
+ // const response = await fetch("/api/gradio/bark_favorite", {
+ // method: "POST",
+ // body: JSON.stringify({
+ // history_bundle_name_data,
+ // }),
+ // });
+ // const result = await response.json();
+ // console.log(result);
+ // };
+
+ const useParameters = (_url: string, data?: Result) => {
+ const {
+ f0up_key: pitch_up_key,
+ original_audio_path: original_audio,
+ index_path: index,
+ f0method: pitch_collection_method,
+ model_path: model,
+ index_rate: search_feature_ratio,
+ device,
+ is_half: use_half_precision_model,
+ filter_radius: filter_radius_pitch,
+ resample_sr: resample_sample_rate_bug,
+ rms_mix_rate: voice_envelope_normalizaiton,
+ protect: protect_breath_sounds,
+ } = data?.metadata ?? {};
+
+ setRvcGenerationParams({
+ ...rvcGenerationParams,
+ pitch_up_key: pitch_up_key ?? rvcGenerationParams.pitch_up_key,
+ // original_audio,
+ index: index ?? rvcGenerationParams.index,
+ pitch_collection_method:
+ pitch_collection_method ?? rvcGenerationParams.pitch_collection_method,
+ model: model ?? rvcGenerationParams.model,
+ search_feature_ratio:
+ search_feature_ratio ?? rvcGenerationParams.search_feature_ratio,
+ device: device ?? rvcGenerationParams.device,
+ use_half_precision_model:
+ use_half_precision_model ??
+ rvcGenerationParams.use_half_precision_model,
+ filter_radius_pitch:
+ filter_radius_pitch ?? rvcGenerationParams.filter_radius_pitch,
+ resample_sample_rate_bug:
+ resample_sample_rate_bug ??
+ rvcGenerationParams.resample_sample_rate_bug,
+ voice_envelope_normalizaiton:
+ voice_envelope_normalizaiton ??
+ rvcGenerationParams.voice_envelope_normalizaiton,
+ protect_breath_sounds:
+ protect_breath_sounds ?? rvcGenerationParams.protect_breath_sounds,
+ });
+ };
+
+ const funcs = [useParameters];
+
+ const handleChange = (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => {
+ const { name, value, type } = event.target;
+ setRvcGenerationParams({
+ ...rvcGenerationParams,
+ [name]:
+ type === "number" || type === "range"
+ ? Number(value)
+ : type === "checkbox"
+ ? (event.target as HTMLInputElement).checked // type assertion
+ : value,
+ });
+ };
+
+ return (
+
+
+ RVC - TTS Generation Webui
+
+
+
+
+
+
+
+
+
+
+
+ {historyData &&
+ historyData.map((item, index) => (
+
+ ))}
+
+
+
+ {/* {JSON.stringify(rvcGenerationParams, null, 2)}
*/}
+
+ );
+};
+
+export default RvcGenerationPage;
+
+const Model = ({
+ rvcParams: rvcGenerationParams,
+ handleChange,
+}: {
+ rvcParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ const [options, setOptions] = React.useState([]);
+ const [loading, setLoading] = React.useState(false);
+
+ const fetchOptions = async () => {
+ setLoading(true);
+ const response = await fetch("/api/gradio/rvc_model_reload", {
+ method: "POST",
+ });
+
+ const result = await response.json();
+ setOptions(result);
+ setLoading(false);
+ };
+
+ const openModels = async () => {
+ await fetch("/api/gradio/rvc_model_open", {
+ method: "POST",
+ });
+ };
+
+ React.useEffect(() => {
+ fetchOptions();
+ }, []);
+
+ const selected = rvcGenerationParams?.model;
+ return (
+
+
+
+
+
+
+
+ {/*
+
+ {
+ handleChange({
+ target: {
+ name: "tokenizer",
+ value: tokenizer,
+ },
+ } as React.ChangeEvent);
+ }}
+ hide_text={false}
+ />
+
*/}
+
+ );
+};
+
+// Like model but for Index
+const Index = ({
+ rvcParams: rvcGenerationParams,
+ handleChange,
+}: {
+ rvcParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ const [options, setOptions] = React.useState([]);
+ const [loading, setLoading] = React.useState(false);
+
+ const fetchOptions = async () => {
+ setLoading(true);
+ const response = await fetch("/api/gradio/rvc_index_reload", {
+ method: "POST",
+ });
+
+ const result = await response.json();
+ setOptions(result);
+ setLoading(false);
+ };
+
+ const openModels = async () => {
+ await fetch("/api/gradio/rvc_index_open", {
+ method: "POST",
+ });
+ };
+
+ React.useEffect(() => {
+ fetchOptions();
+ }, []);
+
+ const selected = rvcGenerationParams?.index;
+ return (
+
+
+
+
+
+
+
+ {/*
+
+ {
+ handleChange({
+ target: {
+ name: "tokenizer",
+ value: tokenizer,
+ },
+ } as React.ChangeEvent);
+ }}
+ hide_text={false}
+ />
+
*/}
+
+ );
+};
+
+const RvcPrompt = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+);
+
+const RvcInput = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ setRvcGenerationParams: (rvcGenerationParams: RVCParams) => void;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+ data?: Result | null;
+}) => {
+ return (
+
+ );
+};
+
+const RVCParameters = ({
+ rvcParams,
+ handleChange,
+}: {
+ rvcParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ return (
+
+
+
+
+
{
+ handleChange({
+ target: {
+ name: "original_audio",
+ value: original_audio,
+ },
+ } as React.ChangeEvent);
+ }}
+ label="Original Audio"
+ filter={["sendToRvc"]}
+ url={rvcParams?.original_audio}
+ />
+
+
+
+
+
+
+
+
+
+
+
+ {/* search feature ratio */}
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+
+
*/}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const GenericPromptRvc = ({
+ rvcGenerationParams,
+ handleChange,
+ label,
+ name,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (event: React.ChangeEvent) => void;
+ label: string;
+ name: string;
+}) => {
+ return (
+
+
+
+
+ );
+};
+
+const GenericSlider = ({
+ rvcParams: rvcGenerationParams,
+ handleChange,
+ label,
+ name,
+ min,
+ max,
+ step,
+}: {
+ rvcParams: RVCParams;
+ handleChange: (event: React.ChangeEvent) => void;
+ label: string;
+ name: string;
+ min: string;
+ max: string;
+ step: string;
+}) => {
+ return (
+
+
+
+
+ );
+};
+
+const SamplesSlider = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+);
+
+const TemperatureSlider = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+);
+
+const LengthPenaltySlider = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+);
+
+const RepetitionPenaltySlider = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const TopPSlider = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const MaxMelTokensSlider = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const AutoRegressiveParameters = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ return (
+
+ {/* Autoregressive Parameters */}
+
Autoregressive Parameters
+
+
+
+
+
+
+
+ );
+};
+
+const DiffusionIterationsSlider = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const CondFreeKSlider = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const DiffusionTemperatureSlider = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const DiffusionParameters = ({
+ rvcGenerationParams,
+ handleChange,
+}: {
+ rvcGenerationParams: RVCParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ return (
+
+ {/* Diffusion Parameters */}
+
Diffusion Parameters
+
+
+
+
+ );
+};
diff --git a/react-ui/src/pages/tortoise.tsx b/react-ui/src/pages/tortoise.tsx
new file mode 100644
index 00000000..a7d26d99
--- /dev/null
+++ b/react-ui/src/pages/tortoise.tsx
@@ -0,0 +1,1052 @@
+import React from "react";
+import { Template } from "../components/Template";
+import useLocalStorage from "../hooks/useLocalStorage";
+import { AudioInput, AudioOutput } from "../components/AudioComponents";
+import Head from "next/head";
+import {
+ TortoiseGenerationParams,
+ tortoiseGenerationId,
+ initialState,
+} from "../tabs/TortoiseGenerationParams";
+import { GradioFile } from "../types/GradioFile";
+import FileInput from "../components/FileInput";
+
+type Result = {
+ audio: GradioFile;
+ image: string;
+ seed: string;
+ bundle_name: string;
+ metadata: {
+ // broken due to gradio bug
+ // _version: string;
+ // _hash_version: string;
+ // _type: string;
+ };
+};
+
+// Model
+
+// Default
+// folder_open
+// refresh
+// KV Cache
+// Use Deepspeed
+// Half
+// Use basic cleaners
+// Tokenizer
+// Drop File Here
+// - or -
+// Click to Upload
+// Apply model settings
+
+const initialHistory = []; // prevent infinite loop
+const TortoiseGenerationPage = () => {
+ const [historyData, setHistoryData] = useLocalStorage(
+ "tortoiseGenerationHistory",
+ initialHistory
+ );
+ const [data, setData] = useLocalStorage(
+ "tortoiseGenerationOutput",
+ null
+ );
+ const [tortoiseGenerationParams, setTortoiseGenerationParams] =
+ useLocalStorage(
+ tortoiseGenerationId,
+ initialState
+ );
+ // loading state
+ const [loading, setLoading] = React.useState(false);
+
+ async function tortoiseGeneration() {
+ setLoading(true);
+ const response = await fetch("/api/gradio/tortoise", {
+ method: "POST",
+ body: JSON.stringify(tortoiseGenerationParams),
+ });
+
+ const result = await response.json();
+ setData(result);
+ setHistoryData((historyData) => [result, ...historyData]);
+ setLoading(false);
+ }
+
+ const useSeed = (_url: string, data?: Result) => {
+ const seed = data?.seed;
+ if (!seed) return;
+ setTortoiseGenerationParams({
+ ...tortoiseGenerationParams,
+ seed: Number(seed),
+ });
+ };
+
+ const favorite = async (_url: string, data?: Result) => {
+ const history_bundle_name_data = data?.bundle_name;
+ if (!history_bundle_name_data) return;
+ const response = await fetch("/api/gradio/bark_favorite", {
+ method: "POST",
+ body: JSON.stringify({
+ history_bundle_name_data,
+ }),
+ });
+ const result = await response.json();
+ console.log(result);
+ };
+
+ // const useParameters = (_url: string, data?: Result) => {
+ // const {
+ // prompt,
+ // speaker,
+ // preset,
+ // cvvp_amount,
+ // split_prompt,
+ // samples,
+ // diffusion_iterations,
+ // temperature,
+ // length_penalty,
+ // repetition_penalty,
+ // top_p,
+ // max_mel_tokens,
+ // cond_free,
+ // cond_free_k,
+ // diffusion_temperature,
+ // model,
+ // generation_name,
+ // } = data?.metadata ?? {};
+ // if (!prompt) return;
+ // setTortoiseGenerationParams({
+ // ...tortoiseGenerationParams,
+ // prompt,
+ // speaker,
+ // preset,
+ // cvvp_amount,
+ // split_prompt,
+ // samples,
+ // diffusion_iterations,
+ // temperature,
+ // length_penalty,
+ // repetition_penalty,
+ // top_p,
+ // max_mel_tokens,
+ // cond_free,
+ // cond_free_k,
+ // diffusion_temperature,
+ // model,
+ // generation_name,
+ // });
+ // }
+
+ const funcs = [useSeed, favorite];
+
+ const handleChange = (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => {
+ const { name, value, type } = event.target;
+ setTortoiseGenerationParams({
+ ...tortoiseGenerationParams,
+ [name]:
+ type === "number" || type === "range"
+ ? Number(value)
+ : type === "checkbox"
+ ? (event.target as HTMLInputElement).checked // type assertion
+ : value,
+ });
+ };
+
+ return (
+
+
+ Tortoise - TTS Generation Webui
+
+
+
+
+
+
+
+
+
+
+
+ {historyData &&
+ historyData.map((item, index) => (
+
+ ))}
+
+
+
+ {/* {JSON.stringify(tortoiseGenerationParams, null, 2)}
*/}
+
+ );
+};
+
+export default TortoiseGenerationPage;
+
+const Speaker = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ const [options, setOptions] = React.useState([]);
+ const [loading, setLoading] = React.useState(false);
+
+ const fetchOptions = async () => {
+ setLoading(true);
+ const response = await fetch("/api/gradio/tortoise_refresh_voices", {
+ method: "POST",
+ });
+
+ const result = await response.json();
+ setOptions(result);
+ setLoading(false);
+ };
+
+ const openVoices = async () => {
+ await fetch("/api/gradio/tortoise_open_voices", {
+ method: "POST",
+ });
+ };
+
+ React.useEffect(() => {
+ fetchOptions();
+ }, []);
+
+ const selected = tortoiseGenerationParams?.speaker;
+ return (
+
+
+
+
+
+
+ );
+};
+
+const Preset = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+
+
+
+);
+
+const CVVPAmount = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const SplitPrompt = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+
+
+
+
+ );
+};
+
+const CondFree = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => {
+ return (
+
+
+
+
+ );
+};
+
+const Model = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ const [options, setOptions] = React.useState([]);
+ const [loading, setLoading] = React.useState(false);
+ const [applyModelSettingsLoading, setApplyModelSettingsLoading] =
+ React.useState(false);
+
+ const fetchOptions = async () => {
+ setLoading(true);
+ const response = await fetch("/api/gradio/tortoise_refresh_models", {
+ method: "POST",
+ });
+
+ const result = await response.json();
+ setOptions(result);
+ setLoading(false);
+ };
+
+ const openModels = async () => {
+ await fetch("/api/gradio/tortoise_open_models", {
+ method: "POST",
+ });
+ };
+
+ const applyModelSettings = async () => {
+ setApplyModelSettingsLoading(true);
+ const params = {
+ model: tortoiseGenerationParams.model,
+ kv_cache: tortoiseGenerationParams.kv_cache,
+ use_deepspeed: tortoiseGenerationParams.use_deepspeed,
+ half: tortoiseGenerationParams.half,
+ tokenizer: tortoiseGenerationParams.tokenizer,
+ use_basic_cleaners: tortoiseGenerationParams.use_basic_cleaners,
+ };
+ const response = await fetch("/api/gradio/tortoise_apply_model_settings", {
+ method: "POST",
+ body: JSON.stringify(params),
+ });
+ const result = await response.json();
+ console.log(result);
+ setApplyModelSettingsLoading(false);
+ };
+
+ const BasicModelCheckbox = ({
+ name,
+ label,
+ handleChange,
+ }: {
+ name: string;
+ label: string;
+ handleChange: (event: React.ChangeEvent) => void;
+ }) => (
+
+
+
+
+ );
+
+ React.useEffect(() => {
+ fetchOptions();
+ }, []);
+
+ const selected = tortoiseGenerationParams?.model;
+ return (
+
+
+
+
+
+
+
+ {/* 2x2 */}
+
+
+
+
+
+
+
+
+
+ {/* */}
+ {
+ handleChange({
+ target: {
+ name: "tokenizer",
+ value: tokenizer,
+ },
+ } as React.ChangeEvent);
+ }}
+ hide_text={false}
+ />
+
+
+
+
+
+ );
+};
+
+const GenerationName = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+
+
+
+);
+
+const TortoisePrompt = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+);
+
+const TortoiseInput = ({
+ tortoiseGenerationParams,
+ setTortoiseGenerationParams,
+ handleChange,
+ data,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ setTortoiseGenerationParams: (
+ tortoiseGenerationParams: TortoiseGenerationParams
+ ) => void;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+ data?: Result | null;
+}) => {
+ return (
+
+ );
+};
+
+const Seed = ({
+ tortoiseGenerationParams,
+ setTortoiseGenerationParams,
+ handleChange,
+ lastSeed,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ setTortoiseGenerationParams: (
+ tortoiseGenerationParams: TortoiseGenerationParams
+ ) => void;
+ handleChange: (event: React.ChangeEvent) => void;
+ lastSeed?: number;
+}) => {
+ return (
+
+
+
+
+
+
+ );
+};
+
+const GenericPromptTortoise = ({
+ tortoiseGenerationParams,
+ handleChange,
+ label,
+ name,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+ label: string;
+ name: string;
+}) => {
+ return (
+
+
+
+
+ );
+};
+
+const GenericSlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+ label,
+ name,
+ min,
+ max,
+ step,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+ label: string;
+ name: string;
+ min: string;
+ max: string;
+ step: string;
+}) => {
+ return (
+
+
+
+
+ );
+};
+// autoregressive
+// samples: 4,
+// temperature: 0.8,
+// length_penalty: 1.0,
+// repetition_penalty: 2.0,
+// top_p: 0.8,
+// max_mel_tokens: 500,
+const SamplesSlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+);
+
+const TemperatureSlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+);
+
+const LengthPenaltySlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (event: React.ChangeEvent) => void;
+}) => (
+
+);
+
+const RepetitionPenaltySlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const TopPSlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const MaxMelTokensSlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const AutoRegressiveParameters = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ return (
+
+ {/* Autoregressive Parameters */}
+
Autoregressive Parameters
+
+
+
+
+
+
+
+ );
+};
+
+const DiffusionIterationsSlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const CondFreeKSlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const DiffusionTemperatureSlider = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => (
+
+);
+
+const DiffusionParameters = ({
+ tortoiseGenerationParams,
+ handleChange,
+}: {
+ tortoiseGenerationParams: TortoiseGenerationParams;
+ handleChange: (
+ event:
+ | React.ChangeEvent
+ | React.ChangeEvent
+ | React.ChangeEvent
+ ) => void;
+}) => {
+ return (
+
+ {/* Diffusion Parameters */}
+
Diffusion Parameters
+
+
+
+
+
+ );
+};
diff --git a/react-ui/src/pages/vocos_npz.tsx b/react-ui/src/pages/vocos_npz.tsx
new file mode 100644
index 00000000..b88de480
--- /dev/null
+++ b/react-ui/src/pages/vocos_npz.tsx
@@ -0,0 +1,88 @@
+import React from "react";
+import { Template } from "../components/Template";
+import useLocalStorage from "../hooks/useLocalStorage";
+import { AudioInput, AudioOutput } from "../components/AudioComponents";
+import Head from "next/head";
+import {
+ VocosParamsNPZ,
+ vocosIdNPZ,
+ initialState,
+} from "../tabs/VocosParamsNPZ";
+import { GradioFile } from "../types/GradioFile";
+import FileInput from "../components/FileInput";
+
+const VocosPageNPZ = () => {
+ const [data, setData] = useLocalStorage(
+ "vocosOutputNpz",
+ null
+ );
+ const [dataEncodec, setDataEncodec] = useLocalStorage(
+ "vocosOutputNpzEncodec",
+ null
+ );
+ const [vocosParams, setVocosParams] = useLocalStorage(
+ vocosIdNPZ,
+ initialState
+ );
+
+ async function vocos() {
+ const response = await fetch("/api/gradio/vocos_npz", {
+ method: "POST",
+ body: JSON.stringify(vocosParams),
+ });
+
+ const result = await response.json();
+ setData(result);
+ }
+
+ async function encodec_decode() {
+ const response = await fetch("/api/gradio/encodec_decode", {
+ method: "POST",
+ body: JSON.stringify(vocosParams),
+ });
+
+ const result = await response.json();
+ setDataEncodec(result);
+ }
+
+ return (
+
+
+ Vocos - TTS Generation Webui
+
+
+
+ {
+ setVocosParams({
+ ...vocosParams,
+ npz_file,
+ });
+ }}
+ hide_text={false}
+ />
+
+
+
+
+
+
+
+ );
+};
+
+export default VocosPageNPZ;
diff --git a/react-ui/src/pages/vocos_wav.tsx b/react-ui/src/pages/vocos_wav.tsx
new file mode 100644
index 00000000..f18d31a7
--- /dev/null
+++ b/react-ui/src/pages/vocos_wav.tsx
@@ -0,0 +1,108 @@
+import React from "react";
+import { Template } from "../components/Template";
+import useLocalStorage from "../hooks/useLocalStorage";
+import { AudioInput, AudioOutput } from "../components/AudioComponents";
+import Head from "next/head";
+import { VocosParams, vocosId, initialState } from "../tabs/VocosParams";
+import { GradioFile } from "../types/GradioFile";
+
+type TypedGradioFile = GradioFile & {
+ type_name?: string;
+};
+
+const VocosPage = () => {
+ const [data, setData] = useLocalStorage(
+ "vocosOutput",
+ null
+ );
+ const [vocosParams, setVocosParams] = useLocalStorage(
+ vocosId,
+ initialState
+ );
+
+ async function vocos() {
+ const response = await fetch("/api/gradio/vocos_wav", {
+ method: "POST",
+ body: JSON.stringify(vocosParams),
+ });
+
+ const result = await response.json();
+ setData(result);
+ }
+
+ const useAsInput = (audio?: string) => {
+ if (!audio) return;
+ setVocosParams({
+ ...vocosParams,
+ audio,
+ });
+ };
+
+ const handleChange = (e: React.ChangeEvent) => {
+ setVocosParams({
+ ...vocosParams,
+ bandwidth: e.target.value,
+ });
+ };
+
+ return (
+
+
+ Vocos - TTS Generation Webui
+
+
+
+
{
+ setVocosParams({
+ ...vocosParams,
+ audio: file,
+ });
+ }}
+ filter={["sendToVocos"]}
+ />
+
+
+
+
+ {["1.5", "3.0", "6.0", "12.0"].map((bandwidth) => (
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+ );
+};
+
+export default VocosPage;
diff --git a/react-ui/src/pages/voice-drafts.tsx b/react-ui/src/pages/voice-drafts.tsx
index 0dce37c7..8ba3bf8f 100644
--- a/react-ui/src/pages/voice-drafts.tsx
+++ b/react-ui/src/pages/voice-drafts.tsx
@@ -35,7 +35,7 @@ export default function Home({
{generations.map((generation) => (
))}
diff --git a/react-ui/src/pages/voices.tsx b/react-ui/src/pages/voices.tsx
new file mode 100644
index 00000000..e2b02137
--- /dev/null
+++ b/react-ui/src/pages/voices.tsx
@@ -0,0 +1,38 @@
+import { Inter } from "next/font/google";
+import React from "react";
+
+import { getNpzDataSimpleVoices } from "../data/getVoicesData";
+import { Template } from "../components/Template";
+import Head from "next/head";
+import { NPZ } from "../types/npz";
+import { CardVoiceNpz } from "../components/CardBig";
+
+export const inter = Inter({ subsets: ["latin"] });
+
+interface Props {
+ outputs: NPZ[];
+}
+
+export default function Voices({ outputs }: Props) {
+ return (
+
+
+ Favorites - TTS Generation Webui
+
+
+ {outputs.map((npz) => (
+
+ ))}
+
+
+ );
+}
+
+export const getStaticProps = async ({}): Promise<{ props: Props }> => {
+ const outputs: NPZ[] = await getNpzDataSimpleVoices();
+ return {
+ props: {
+ outputs,
+ },
+ };
+};
diff --git a/react-ui/src/tabs/BarkGenerationParams.tsx b/react-ui/src/tabs/BarkGenerationParams.tsx
new file mode 100644
index 00000000..22db980b
--- /dev/null
+++ b/react-ui/src/tabs/BarkGenerationParams.tsx
@@ -0,0 +1,58 @@
+import { updateLocalStorageWithFunction } from "../hooks/useLocalStorage";
+import router from "next/router";
+
+const inputs = {
+ burn_in_prompt: "Howdy!",
+ prompt: "Howdy!",
+ history_setting: "Empty history",
+ languageRadio: "English",
+ speakerIdRadio: "0",
+ useV2: true,
+ text_temp: 0.7,
+ waveform_temp: 0.7,
+ long_prompt_radio: "Short prompt (<15s)",
+ long_prompt_history_radio: "or Use old generation as history:",
+ old_generation_dropdown:
+ "voices\\2023-06-18_21-51-07__bark__continued_generation.npz",
+ seed_input: "123",
+ history_prompt_semantic_dropdown:
+ "voices\\2023-06-18_21-51-07__bark__continued_generation.npz",
+};
+
+export type BarkGenerationParams = {
+ burn_in_prompt: string; // string in 'Burn In Prompt (Optional)' Textbox component
+ prompt: string; // string in 'Prompt' Textbox component
+ history_setting: string; // string in 'History Prompt (voice) setting:' Radio component
+ languageRadio: string; // string in 'parameter_17' Radio component
+ speakerIdRadio: string; // string in 'Speaker ID' Radio component
+ useV2: boolean; // boolean in 'Use V2' Checkbox component
+ text_temp: number; // number (numeric value between 0.0 and 1.2) in 'Text temperature' Slider component
+ waveform_temp: number; // number (numeric value between 0.0 and 1.2) in 'Waveform temperature' Slider component
+ long_prompt_radio: string; // string in 'Prompt type' Radio component
+ long_prompt_history_radio: string; // string in 'For each subsequent generation:' Radio component
+ old_generation_dropdown: string; // string
+ seed_input: string; // string in 'parameter_40' Textbox component
+ history_prompt_semantic_dropdown: string; // string
+};
+
+export const initialState: BarkGenerationParams = {
+ ...inputs,
+};
+
+export const barkGenerationId = "bark_generation-tab";
+
+export const sendToBarkAsVoice = (old_generation_dropdown?: string) => {
+ if (!old_generation_dropdown) return;
+ updateLocalStorageWithFunction(
+ barkGenerationId,
+ (
+ barkParams: BarkGenerationParams = initialState
+ ): BarkGenerationParams => ({
+ ...barkParams,
+ old_generation_dropdown,
+ history_prompt_semantic_dropdown: old_generation_dropdown,
+ history_setting: "or Use old generation as history:",
+ })
+ );
+ router.push("/bark");
+};
diff --git a/react-ui/src/tabs/BarkSettingsParams.tsx b/react-ui/src/tabs/BarkSettingsParams.tsx
new file mode 100644
index 00000000..469eeb74
--- /dev/null
+++ b/react-ui/src/tabs/BarkSettingsParams.tsx
@@ -0,0 +1,44 @@
+import { updateLocalStorageWithFunction } from "../hooks/useLocalStorage";
+import router from "next/router";
+
+export const barkSettingsId = "barkSettingsParams";
+
+export type BarkSettingsParams = {
+ use_small_models: boolean;
+ enable_mps: boolean;
+ offload_gpu_models_to_cpu: boolean;
+
+ text_generation_use_gpu: boolean;
+ text_generation_use_small_model: boolean;
+ coarse_to_fine_inference_use_gpu: boolean;
+ coarse_to_fine_inference_use_small_model: boolean;
+ fine_tuning_use_gpu: boolean;
+ fine_tuning_use_small_model: boolean;
+ use_gpu_codec: boolean;
+ load_models_on_startup: boolean;
+};
+
+export const initialBarkSettingsParams: BarkSettingsParams = {
+ use_small_models: false,
+ enable_mps: false,
+ offload_gpu_models_to_cpu: false,
+
+ text_generation_use_gpu: false,
+ text_generation_use_small_model: false,
+ coarse_to_fine_inference_use_gpu: false,
+ coarse_to_fine_inference_use_small_model: false,
+ fine_tuning_use_gpu: false,
+ fine_tuning_use_small_model: false,
+ use_gpu_codec: false,
+ load_models_on_startup: false,
+};
+
+export const sendToBarkSettings = (melody?: string) => {
+ if (!melody) return;
+ updateLocalStorageWithFunction(
+ barkSettingsId,
+ (barkSettingsParams: BarkSettingsParams = initialBarkSettingsParams) =>
+ ({ ...barkSettingsParams, melody } as BarkSettingsParams)
+ );
+ router.push("/barkSettings");
+};
diff --git a/react-ui/src/tabs/BarkVoiceGenerationParams.tsx b/react-ui/src/tabs/BarkVoiceGenerationParams.tsx
new file mode 100644
index 00000000..aa26d981
--- /dev/null
+++ b/react-ui/src/tabs/BarkVoiceGenerationParams.tsx
@@ -0,0 +1,26 @@
+import { updateLocalStorageWithFunction } from "../hooks/useLocalStorage";
+import router from "next/router";
+
+export type BarkVoiceGenerationParams = {
+ audio?: string;
+ tokenizer?: string;
+ use_gpu?: boolean;
+};
+
+export const initialState: BarkVoiceGenerationParams = {
+ audio: "https://www.mfiles.co.uk/mp3-downloads/gs-cd-track2.mp3",
+ tokenizer: "quantifier_hubert_base_ls960.pth @ GitMylo/bark-voice-cloning",
+ use_gpu: true,
+};
+
+export const barkVoiceGenerationId = "bark_voice_generation-tab";
+
+export const sendToBarkVoiceGeneration = (audio?: string) => {
+ if (!audio) return;
+ updateLocalStorageWithFunction(
+ barkVoiceGenerationId,
+ (vocosParams: BarkVoiceGenerationParams = initialState) =>
+ ({ ...vocosParams, audio } as BarkVoiceGenerationParams)
+ );
+ router.push("/bark_voice_generation");
+};
diff --git a/react-ui/src/tabs/DemucsParams.tsx b/react-ui/src/tabs/DemucsParams.tsx
new file mode 100644
index 00000000..1718c8e9
--- /dev/null
+++ b/react-ui/src/tabs/DemucsParams.tsx
@@ -0,0 +1,22 @@
+import { updateLocalStorageWithFunction } from "../hooks/useLocalStorage";
+import router from "next/router";
+
+export type DemucsParams = {
+ file?: string;
+};
+
+export const initialState: DemucsParams = {
+ file: "https://www.mfiles.co.uk/mp3-downloads/gs-cd-track2.mp3",
+};
+
+export const demucsId = "demucs-tab";
+
+export const sendToDemucs = (file?: string) => {
+ if (!file) return;
+ updateLocalStorageWithFunction(
+ demucsId,
+ (demucsParams: DemucsParams = initialState) =>
+ ({ ...demucsParams, file } as DemucsParams)
+ );
+ router.push("/demucs");
+};
diff --git a/react-ui/src/tabs/MusicgenParams.tsx b/react-ui/src/tabs/MusicgenParams.tsx
new file mode 100644
index 00000000..9b4bd76b
--- /dev/null
+++ b/react-ui/src/tabs/MusicgenParams.tsx
@@ -0,0 +1,42 @@
+import { updateLocalStorageWithFunction } from "../hooks/useLocalStorage";
+import router from "next/router";
+
+export const musicgenId = "musicgenParams";
+
+export type MusicgenParams = {
+ text: string;
+ melody?: string;
+ model: string;
+ duration: number;
+ topk: number;
+ topp: number;
+ temperature: number;
+ cfg_coef: number;
+ seed: number;
+ use_multi_band_diffusion: boolean;
+};
+
+export const initialMusicgenParams: MusicgenParams = {
+ // text: "",
+ text: "lofi hip hop beats to relax/study to",
+ melody: undefined,
+ // melody: "https://www.mfiles.co.uk/mp3-downloads/gs-cd-track2.mp3",
+ model: "Small",
+ duration: 1,
+ topk: 250,
+ topp: 0,
+ temperature: 1.0,
+ cfg_coef: 3.0,
+ seed: -1,
+ use_multi_band_diffusion: false,
+};
+
+export const sendToMusicgen = (melody?: string) => {
+ if (!melody) return;
+ updateLocalStorageWithFunction(
+ musicgenId,
+ (musicgenParams: MusicgenParams = initialMusicgenParams) =>
+ ({ ...musicgenParams, melody } as MusicgenParams)
+ );
+ router.push("/musicgen");
+};
diff --git a/react-ui/src/tabs/RVCParams.tsx b/react-ui/src/tabs/RVCParams.tsx
new file mode 100644
index 00000000..374ad2c4
--- /dev/null
+++ b/react-ui/src/tabs/RVCParams.tsx
@@ -0,0 +1,44 @@
+import { updateLocalStorageWithFunction } from "../hooks/useLocalStorage";
+import router from "next/router";
+
+export type RVCParams = {
+ pitch_up_key: string; // string in 'Pitch Up key' Textbox component
+ original_audio: string; // string in 'Original Audio' Audio component
+ index: string; // string in 'Index' File component
+ pitch_collection_method: string; // string (Option from: ['harvest', 'reaper', 'melodia']) in 'Pitch Collection Method' Radio component
+ model: string; // string in 'Model' File component
+ search_feature_ratio: number; // number (numeric value between 0.0 and 1.0) in 'Search Feature Ratio' Slider component
+ device: string; // string (Option from: ['cuda:0', 'cpu', 'mps']) in 'Device' Dropdown component
+ use_half_precision_model: boolean; // boolean in 'Use half precision model (Depends on GPU support)' Checkbox component
+ filter_radius_pitch: number; // number (numeric value between 0 and 10) in 'Filter Radius (Pitch)' Slider component
+ resample_sample_rate_bug: number; // number (numeric value between 0 and 48000) in 'Resample Sample-rate (Bug)' Slider component
+ voice_envelope_normalizaiton: number; // number (numeric value between 0.0 and 1.0) in 'Voice Envelope Normalizaiton' Slider component
+ protect_breath_sounds: number; // number (numeric value between 0.0 and 0.5) in 'Protect Breath Sounds' Slider component
+};
+
+export const initialState: RVCParams = {
+ pitch_up_key: "0", // string in 'Pitch Up key' Textbox component
+ original_audio: "", // string in 'Original Audio' Audio component
+ index: "", // string in 'Index' File component
+ pitch_collection_method: "harvest", // string (Option from: ['harvest', 'reaper', 'melodia']) in 'Pitch Collection Method' Radio component
+ model: "", // string in 'Model' File component
+ search_feature_ratio: 0.66, // number (numeric value between 0.0 and 1.0) in 'Search Feature Ratio' Slider component
+ device: "cuda:0", // string (Option from: ['cuda:0', 'cpu', 'mps']) in 'Device' Dropdown component
+ use_half_precision_model: false, // boolean in 'Use half precision model (Depends on GPU support)' Checkbox component
+ filter_radius_pitch: 3, // number (numeric value between 0 and 10) in 'Filter Radius (Pitch)' Slider component
+ resample_sample_rate_bug: 0, // number (numeric value between 0 and 48000) in 'Resample Sample-rate (Bug)' Slider component
+ voice_envelope_normalizaiton: 1, // number (numeric value between 0.0 and 1.0) in 'Voice Envelope Normalizaiton' Slider component
+ protect_breath_sounds: 0.33, // number (numeric value between 0.0 and 0.5) in 'Protect Breath Sounds' Slider component
+};
+
+export const RVCId = "rvc_generation-tab";
+
+export const sendToRVCGeneration = (audio?: string) => {
+ if (!audio) return;
+ updateLocalStorageWithFunction(
+ RVCId,
+ (vocosParams: RVCParams = initialState) =>
+ ({ ...vocosParams, audio } as RVCParams)
+ );
+ router.push("/bark");
+};
diff --git a/react-ui/src/tabs/TortoiseGenerationParams.tsx b/react-ui/src/tabs/TortoiseGenerationParams.tsx
new file mode 100644
index 00000000..6e358613
--- /dev/null
+++ b/react-ui/src/tabs/TortoiseGenerationParams.tsx
@@ -0,0 +1,73 @@
+import { updateLocalStorageWithFunction } from "../hooks/useLocalStorage";
+import router from "next/router";
+
+export type TortoiseGenerationParams = {
+ prompt: string; // string in 'Prompt' Textbox component
+ speaker: string; // string (Option from: ['random', 'angie', 'applejack', 'cond_latent_example', 'daniel', 'deniro', 'emma', 'freeman', 'geralt', 'halle', 'jlaw', 'lj', 'mol', 'myself', 'pat', 'pat2', 'rainbow', 'snakes', 'tim_reynolds', 'tom', 'train_atkins', 'train_daws', 'train_dotrice', 'train_dreams', 'train_empire', 'train_grace', 'train_kennard', 'train_lescault', 'train_mouse', 'weaver', 'william', 'freeman_2a', 'freeman_3', 'pat4']) in 'parameter_2502' Dropdown component
+ preset: string; // string (Option from: ['ultra_fast', 'fast', 'standard', 'high_quality']) in 'parameter_2507' Dropdown component
+ seed: number; // number in 'parameter_2521' Number component
+ cvvp_amount: number; // number (numeric value between 0.0 and 1.0) in 'CVVP Amount' Slider component
+ split_prompt: boolean; // boolean in 'Split prompt by lines' Checkbox component
+ samples: number; // number (numeric value between 4 and 256) in 'Samples' Slider component
+ diffusion_iterations: number; // number (numeric value between 4 and 400) in 'Diffusion Iterations' Slider component
+ temperature: number; // number (numeric value between 0.0 and 1.0) in 'Temperature' Slider component
+ length_penalty: number; // number (numeric value between 0.0 and 10.0) in 'Length Penalty' Slider component
+ repetition_penalty: number; // number (numeric value between 0.0 and 10.0) in 'Repetition Penalty' Slider component
+ top_p: number; // number (numeric value between 0.0 and 1.0) in 'Top P' Slider component
+ max_mel_tokens: number; // number (numeric value between 10 and 600) in 'Max Mel Tokens' Slider component
+ cond_free: boolean; // boolean in 'Cond Free' Checkbox component
+ cond_free_k: number; // number (numeric value between 0 and 10) in 'Cond Free K' Slider component
+ diffusion_temperature: number; // number (numeric value between 0.0 and 1.0) in 'Temperature' Slider component
+ generation_name: string; // string in 'Generation Name' Textbox component
+
+ model: string; // string (Option from: ['Default']) in 'parameter_2488' Dropdown component
+ kv_cache: boolean; // boolean in 'parameter_2493' Checkbox component
+ use_deepspeed: boolean; // boolean in 'parameter_2494' Checkbox component
+ half: boolean; // boolean in 'parameter_2495' Checkbox component
+ use_basic_cleaners: boolean; // boolean in 'parameter_2497' Checkbox component
+ tokenizer: string; // string
+};
+
+export const initialState: TortoiseGenerationParams = {
+ // autoregressive
+ samples: 4,
+ temperature: 0.8,
+ length_penalty: 1.0,
+ repetition_penalty: 2.0,
+ top_p: 0.8,
+ max_mel_tokens: 500,
+
+ // diffusion
+ diffusion_iterations: 30,
+ cond_free: false,
+ cond_free_k: 2,
+ diffusion_temperature: 1.0,
+
+ model: "Default", // string (Option from: ['Default']) in 'parameter_2488' Dropdown component
+
+ prompt: "Howdy!", // string in 'Prompt' Textbox component
+ speaker: "random", // string (Option from: ['random', 'angie', 'applejack', 'cond_latent_example', 'daniel', 'deniro', 'emma', 'freeman', 'geralt', 'halle', 'jlaw', 'lj', 'mol', 'myself', 'pat', 'pat2', 'rainbow', 'snakes', 'tim_reynolds', 'tom', 'train_atkins', 'train_daws', 'train_dotrice', 'train_dreams', 'train_empire', 'train_grace', 'train_kennard', 'train_lescault', 'train_mouse', 'weaver', 'william', 'freeman_2a', 'freeman_3', 'pat4']) in 'parameter_2502' Dropdown component
+ preset: "ultra_fast", // string (Option from: ['ultra_fast', 'fast', 'standard', 'high_quality']) in 'parameter_2507' Dropdown component
+ seed: -1, // number in 'parameter_2521' Number component
+ cvvp_amount: 0, // number (numeric value between 0.0 and 1.0) in 'CVVP Amount' Slider component
+ split_prompt: true, // boolean in 'Split prompt by lines' Checkbox component
+ generation_name: "", // string in 'Generation Name' Textbox component
+
+ kv_cache: false, // boolean in 'parameter_2493' Checkbox component
+ use_deepspeed: false, // boolean in 'parameter_2494' Checkbox component
+ half: false, // boolean in 'parameter_2495' Checkbox component
+ use_basic_cleaners: false, // boolean in 'parameter_2497' Checkbox component
+ tokenizer: "", // string
+};
+
+export const tortoiseGenerationId = "tortoise_generation-tab";
+
+export const sendToBarkVoiceGeneration = (audio?: string) => {
+ if (!audio) return;
+ updateLocalStorageWithFunction(
+ tortoiseGenerationId,
+ (vocosParams: TortoiseGenerationParams = initialState) =>
+ ({ ...vocosParams, audio } as TortoiseGenerationParams)
+ );
+ router.push("/bark");
+};
diff --git a/react-ui/src/tabs/VocosParams.tsx b/react-ui/src/tabs/VocosParams.tsx
new file mode 100644
index 00000000..7b22a316
--- /dev/null
+++ b/react-ui/src/tabs/VocosParams.tsx
@@ -0,0 +1,24 @@
+import { updateLocalStorageWithFunction } from "../hooks/useLocalStorage";
+import router from "next/router";
+
+export type VocosParams = {
+ audio?: string;
+ bandwidth?: string;
+};
+
+export const initialState: VocosParams = {
+ audio: "https://www.mfiles.co.uk/mp3-downloads/gs-cd-track2.mp3",
+ bandwidth: "1.5",
+};
+
+export const vocosId = "vocos_wav-tab";
+
+export const sendToVocos = (audio?: string) => {
+ if (!audio) return;
+ updateLocalStorageWithFunction(
+ vocosId,
+ (vocosParams: VocosParams = initialState) =>
+ ({ ...vocosParams, audio } as VocosParams)
+ );
+ router.push("/vocos_wav");
+};
diff --git a/react-ui/src/tabs/VocosParamsNPZ.tsx b/react-ui/src/tabs/VocosParamsNPZ.tsx
new file mode 100644
index 00000000..0eb1d670
--- /dev/null
+++ b/react-ui/src/tabs/VocosParamsNPZ.tsx
@@ -0,0 +1,22 @@
+import { updateLocalStorageWithFunction } from "../hooks/useLocalStorage";
+import router from "next/router";
+
+export type VocosParamsNPZ = {
+ npz_file?: string;
+};
+
+export const initialState: VocosParamsNPZ = {
+ npz_file: "https://www.mfiles.co.uk/mp3-downloads/gs-cd-track2.mp3",
+};
+
+export const vocosIdNPZ = "vocos_npz-tab";
+
+export const sendToVocosNPZ = (npz_file?: string) => {
+ if (!npz_file) return;
+ updateLocalStorageWithFunction(
+ vocosIdNPZ,
+ (vocosParams: VocosParamsNPZ = initialState) =>
+ ({ ...vocosParams, npz_file } as VocosParamsNPZ)
+ );
+ router.push("/vocos_npz");
+};
diff --git a/react-ui/src/types/Generation.tsx b/react-ui/src/types/Generation.tsx
index 4bf87450..2f24f979 100644
--- a/react-ui/src/types/Generation.tsx
+++ b/react-ui/src/types/Generation.tsx
@@ -1,32 +1,8 @@
-export type Generation = {
- name: string;
- prompt?: string;
- directory: string;
- audio: string;
- tags: string[];
- // deprecated
- download: string;
- language:
- | "american"
- | "german"
- | "spanish"
- | "french"
- | "hindi"
- | "chinese"
- | "portuguese"
- | "russian"
- | "turkish"
- | "polish"
- | "korean"
- | "japanese"
- | "italian";
- author: string;
- gender: "male" | "female" | "other";
- image: string;
-};
-
export interface GenerationRaw {
- prompt: string;
+ _type?: string;
+
+ prompt?: string;
+ text?: string;
language: string;
speaker_id: string;
history_prompt: string;
@@ -46,5 +22,32 @@ export interface GenerationRaw {
is_big_fine_model: boolean;
hash?: string;
- name?: string;
+ name?: String;
+ history_bundle_name_data?: string;
+ api_filename?: string;
+}
+
+export interface TortoiseMeta {
+ _version: string;
+ _type: string;
+ date: string;
+ candidates: number;
+ text: string;
+ voice: string;
+ preset: string;
+ seed: string;
+ cvvp_amount: number;
+ split_prompt: boolean;
+ num_autoregressive_samples: number;
+ diffusion_iterations: number;
+ temperature: number;
+ length_penalty: number;
+ repetition_penalty: number;
+ top_p: number;
+ max_mel_tokens: number;
+ cond_free: boolean;
+ cond_free_k: number;
+ diffusion_temperature: number;
+ model: string;
+ name: string;
}
diff --git a/react-ui/src/types/GradioFile.tsx b/react-ui/src/types/GradioFile.tsx
new file mode 100644
index 00000000..a17aa61c
--- /dev/null
+++ b/react-ui/src/types/GradioFile.tsx
@@ -0,0 +1,8 @@
+
+export type GradioFile = {
+ name: string;
+ data: string;
+ size?: number;
+ is_file?: boolean;
+ orig_name?: string;
+};
diff --git a/react-ui/src/types/NPZ.ts b/react-ui/src/types/NPZ.ts
new file mode 100644
index 00000000..e2114a1b
--- /dev/null
+++ b/react-ui/src/types/NPZ.ts
@@ -0,0 +1,26 @@
+export interface NPZOptional {
+ _version: string;
+ _hash_version: string;
+ _type: string;
+ is_big_semantic_model: boolean;
+ is_big_coarse_model: boolean;
+ is_big_fine_model: boolean;
+ prompt: string;
+ language: any;
+ speaker_id: any;
+ hash: string;
+ history_prompt: string;
+ history_prompt_npz: any;
+ history_hash: string;
+ text_temp: number;
+ waveform_temp: number;
+ date: string;
+ seed: string;
+ crop_min: number;
+ crop_max: number;
+}
+
+export interface NPZ extends Partial {
+ filename: string;
+ url: string;
+}
diff --git a/src/bark/clone/tab_voice_clone.py b/src/bark/clone/tab_voice_clone.py
index 1475ce3e..57b976c0 100644
--- a/src/bark/clone/tab_voice_clone.py
+++ b/src/bark/clone/tab_voice_clone.py
@@ -207,6 +207,7 @@ def load_tokenizer(tokenizer_and_repo: str, use_gpu: bool):
load_tokenizer,
inputs=[tokenizer_dropdown, use_gpu_checkbox],
outputs=[tokenizer_dropdown],
+ api_name="bark_voice_tokenizer_load",
)
with gr.Column():
@@ -229,8 +230,10 @@ def generate_voice(wav_file: str, use_gpu: bool):
generate_voice_button.click(
fn=generate_voice,
inputs=[file_input, use_gpu_checkbox],
+ # inputs=[file_input, use_gpu_checkbox, tokenizer_dropdown],
outputs=[voice_file_name, audio_preview],
preprocess=True,
+ api_name="bark_voice_generate",
)
register_use_as_history_button(
diff --git a/src/bark/generation_tab_bark.py b/src/bark/generation_tab_bark.py
index 97b81d98..aa8580a7 100644
--- a/src/bark/generation_tab_bark.py
+++ b/src/bark/generation_tab_bark.py
@@ -495,9 +495,7 @@ def generation_tab_bark():
def unload_models():
model_manager.unload_models()
return {
- unload_models_button: gr.Button.update(
- value="Unloaded"
- ),
+ unload_models_button: gr.Button.update(value="Unloaded"),
}
unload_models_button.click(
@@ -702,7 +700,7 @@ def generate_button(text, count, variant):
fn=generate_multi(count, output_components),
inputs=inputs,
outputs=all_outputs_flat,
- # api_name=f"bark_{count}",
+ # api_name=f"bark_{count}", # gradio literally can't support this
)
return button
@@ -720,6 +718,7 @@ def generate_button(text, count, variant):
fn=generate_multi(1, output_components),
inputs=inputs,
outputs=all_outputs_flat,
+ api_name="bark", # toggle
)
set_old_seed_button.click(
@@ -774,6 +773,7 @@ def old_generation_dropdown_ui(label):
reload_old_generation_dropdown.click(
fn=lambda: gr.Dropdown.update(choices=get_npz_files()),
outputs=old_generation_dropdown,
+ api_name=f"reload_old_generation_dropdown{ '' if label == 'Audio Voice' else '_semantic'}",
)
return (
@@ -863,15 +863,22 @@ def create_components(
send_to_vocos_button = gr.Button("Vocos", size="sm")
continue_button = gr.Button("Use as history", size="sm")
continue_semantic_button = gr.Button("Use as semantic history", size="sm")
- npz = gr.State() # type: ignore
+ npz = gr.Textbox(
+ visible=False,
+ )
seed = gr.State() # type: ignore
- json_text = gr.State() # type: ignore
- history_bundle_name_data = gr.State() # type: ignore
+ json_text = gr.JSON(
+ visible=False,
+ )
+ history_bundle_name_data = gr.Textbox(
+ visible=False,
+ )
save_button.click(
fn=save_to_favorites,
inputs=[history_bundle_name_data],
outputs=[save_button],
+ api_name=f"bark_favorite{ '_' + str(index) if index > 0 else ''}",
)
reuse_seed_button.click(
diff --git a/src/bark/settings_tab_bark.py b/src/bark/settings_tab_bark.py
index ef49b7f5..030fc17e 100644
--- a/src/bark/settings_tab_bark.py
+++ b/src/bark/settings_tab_bark.py
@@ -119,7 +119,12 @@ def save_environment_variables(
]
for i in env_inputs:
- i.change(fn=save_environment_variables, inputs=env_inputs)
+ i.change(fn=save_environment_variables, inputs=env_inputs,
+ api_name="save_environment_variables_bark")
+
+ # refresh environment variables button
+
+
inputs = [
text_use_gpu,
@@ -133,7 +138,8 @@ def save_environment_variables(
]
for i in inputs:
- i.change(fn=save_config_bark, inputs=inputs, outputs=[save_beacon])
+ i.change(fn=save_config_bark, inputs=inputs, outputs=[save_beacon],
+ api_name="save_config_bark")
def sync_ui():
def checkbox_update_helper(key: str):
@@ -150,7 +156,8 @@ def checkbox_update_helper(key: str):
gr.Checkbox.update(value=config["load_models_on_startup"]),
]
- settings_tab.select(fn=sync_ui, outputs=inputs)
+ settings_tab.select(fn=sync_ui, outputs=inputs,
+ api_name="get_config_bark")
def set_to_reload():
return gr.Button.update(value="Loading...", interactive=False)
diff --git a/src/extensions_loader/extensions/callback_save_generation_ffmpeg.py b/src/extensions_loader/extensions/callback_save_generation_ffmpeg.py
index 7a895aeb..fecca2d6 100644
--- a/src/extensions_loader/extensions/callback_save_generation_ffmpeg.py
+++ b/src/extensions_loader/extensions/callback_save_generation_ffmpeg.py
@@ -47,6 +47,12 @@ def callback_save_generation(
input_data = audio_array.tobytes()
metadata["prompt"] = double_escape_quotes(metadata["prompt"])
metadata["prompt"] = double_escape_newlines(metadata["prompt"])
+ def double_escape_backslash(prompt):
+ if prompt is None:
+ return None
+ return prompt.replace("\\", "\\\\")
+ metadata["history_prompt"] = double_escape_backslash(metadata["history_prompt"])
+ metadata["history_prompt_npz"] = double_escape_backslash(metadata["history_prompt_npz"])
metadata_str = json.dumps(metadata, ensure_ascii=False)
pipe_input = ffmpeg.input("pipe:", format="f32le", ar=str(SAMPLE_RATE))
diff --git a/src/history_tab/delete_generation.py b/src/history_tab/delete_generation.py
new file mode 100644
index 00000000..bd846266
--- /dev/null
+++ b/src/history_tab/delete_generation.py
@@ -0,0 +1,5 @@
+import shutil
+
+
+def delete_generation(directory: str):
+ shutil.rmtree(directory)
diff --git a/src/history_tab/delete_generation_cb.py b/src/history_tab/delete_generation_cb.py
index 49f6a0a5..31ebfc84 100644
--- a/src/history_tab/delete_generation_cb.py
+++ b/src/history_tab/delete_generation_cb.py
@@ -4,7 +4,6 @@
def delete_generation_cb(refresh):
def delete_generation(directory: str, *args):
shutil.rmtree(directory)
-
return refresh(*args)
return delete_generation
diff --git a/src/history_tab/main.py b/src/history_tab/main.py
index 6c61241b..cc7c1116 100644
--- a/src/history_tab/main.py
+++ b/src/history_tab/main.py
@@ -3,6 +3,7 @@
import json
import shutil
+from src.history_tab.delete_generation import delete_generation
from src.history_tab.collections_directories_atom import (
collections_directories_atom,
get_collections,
@@ -78,14 +79,16 @@ def history_content(
create_collection_ui(collections_directories_atom)
with gr.Accordion("Gallery Selector (Click to Open)", open=False):
- history_list_as_gallery = gr.Gallery(value=[], columns=8, object_fit="contain", height="auto")
+ history_list_as_gallery = gr.Gallery(
+ value=[], columns=8, object_fit="contain", height="auto"
+ )
with gr.Row():
with gr.Column():
with gr.Row():
button_output = gr.Button(
value=f"Open {show_collections and 'collection' or directory} folder"
)
- button_output.click(lambda x: open_folder(x), inputs=[directory_dropdown])
+ button_output.click(lambda x: open_folder(x), inputs=[directory_dropdown], api_name="open_folder")
datatypes = ["date", "str", "str", "str"]
# headers = ["Date and Time", directory.capitalize(), "When", "Filename"]
@@ -104,7 +107,7 @@ def history_content(
with gr.Column():
history_bundle_name = gr.Markdown(visible=True)
- history_bundle_name_data = gr.State() # type: ignore
+ history_bundle_name_data = gr.Textbox(visible=False)
history_audio = gr.Audio(visible=True, type="filepath", show_label=False)
history_image = gr.Image(show_label=False)
history_json = gr.JSON()
@@ -142,7 +145,8 @@ def history_content(
)
save_to_voices.click(
- fn=save_to_voices_cb, inputs=history_npz, outputs=save_to_voices
+ fn=save_to_voices_cb, inputs=history_npz, outputs=save_to_voices,
+ api_name="save_to_voices"
)
save_to_collection_ui(
@@ -218,6 +222,15 @@ def update_history_tab(directory: str):
inputs=[history_bundle_name_data, directory_dropdown],
outputs=[history_list, history_list_as_gallery],
)
+ # API ONLY
+ gr.Button(
+ label="Delete (API ONLY)",
+ visible=False,
+ ).click(
+ fn=delete_generation,
+ inputs=[history_bundle_name_data],
+ api_name="delete_generation",
+ )
history_tab.select(
fn=update_history_tab,
inputs=[directory_dropdown],
@@ -234,7 +247,7 @@ def update_history_tab(directory: str):
def save_to_collection_ui(
directory: str,
directories: list[str],
- history_bundle_name_data: gr.State,
+ history_bundle_name_data: gr.Textbox,
directories_state: gr.JSON,
):
with gr.Row():
diff --git a/src/musicgen/musicgen_tab.py b/src/musicgen/musicgen_tab.py
index c027bdd9..1696fe11 100644
--- a/src/musicgen/musicgen_tab.py
+++ b/src/musicgen/musicgen_tab.py
@@ -327,7 +327,9 @@ def generation_tab_musicgen():
)
image = gr.Image(label="Waveform", shape=(None, 100), elem_classes="tts-image") # type: ignore
with gr.Row():
- history_bundle_name_data = gr.State() # type: ignore
+ history_bundle_name_data = gr.Textbox(
+ visible=False,
+ )
send_to_demucs_button = gr.Button("Send to Demucs", visible=True)
save_button = gr.Button("Save to favorites", visible=True)
melody_button = gr.Button("Use as melody", visible=True)
diff --git a/src/rvc_tab/rvc_tab.py b/src/rvc_tab/rvc_tab.py
index e5728032..8911c304 100644
--- a/src/rvc_tab/rvc_tab.py
+++ b/src/rvc_tab/rvc_tab.py
@@ -78,6 +78,67 @@ def run_rvc(
)
+def run_rvc_api(
+ f0up_key: str,
+ original_audio_path: str,
+ # index_path: str,
+ index_path_api: str,
+ f0method: str,
+ # model_path: str,
+ model_path_api: str,
+ index_rate: float,
+ device: str,
+ is_half: bool,
+ filter_radius: int,
+ resample_sr: int,
+ rms_mix_rate: float,
+ protect: float,
+):
+ infer_batch_rvc.set_params_temp(
+ _device=device,
+ _is_half=is_half,
+ _filter_radius=filter_radius,
+ _resample_sr=resample_sr,
+ _rms_mix_rate=rms_mix_rate,
+ _protect=protect,
+ )
+
+ from rvc_beta.infer_batch_rvc import config
+
+ if device == "cpu": # Workaround for "slow_conv2d_cpu" not implemented for 'Half'
+ config.is_half = is_half
+
+ if infer_batch_rvc.hubert_model is None:
+ get_and_load_hubert()
+
+ opt_path = "./outputs-rvc/"
+
+ index_path = get_rvc_local_path(index_path_api, "index")
+ model_path = get_rvc_local_path(model_path_api, "pth")
+
+ return infer_rvc(
+ f0method=f0method,
+ f0up_key=f0up_key,
+ input_path=original_audio_path,
+ index_path=index_path,
+ index_rate=index_rate,
+ model_path=model_path,
+ opt_path=opt_path,
+ ), {
+ "original_audio_path": original_audio_path,
+ "index_path": index_path_api,
+ "model_path": model_path_api,
+ "f0method": f0method,
+ "f0up_key": f0up_key,
+ "index_rate": index_rate,
+ "device": device,
+ "is_half": is_half,
+ "filter_radius": filter_radius,
+ "resample_sr": resample_sr,
+ "rms_mix_rate": rms_mix_rate,
+ "protect": protect,
+ }
+
RVC_LOCAL_MODELS_DIR = get_path_from_root("data", "models", "rvc", "checkpoints")
@@ -122,12 +183,15 @@ def rvc_ui_model_or_index_path_ui(label: str):
show_label=False,
container=False,
)
- gr_open_button_simple(RVC_LOCAL_MODELS_DIR)
+ gr_open_button_simple(
+ RVC_LOCAL_MODELS_DIR, api_name=f"rvc_{label.lower()}_open"
+ )
gr_reload_button().click(
lambda: file_path_dropdown.update(
choices=get_list_fn(),
),
outputs=[file_path_dropdown],
+ api_name=f"rvc_{label.lower()}_reload",
)
gr.Markdown(
"""
@@ -162,10 +226,11 @@ def rvc_ui_model_or_index_path_ui(label: str):
inputs=[file_path_file],
outputs=[file_path, file_path_dropdown],
)
+
file_path_dropdown.change(
lambda model: [
file_path.update(
- value=os.path.join(RVC_LOCAL_MODELS_DIR, f"{model}{extension}")
+ value=get_rvc_local_path(model, file_type)
),
file_path_file.update(value=None),
]
@@ -179,6 +244,8 @@ def rvc_ui_model_or_index_path_ui(label: str):
)
return file_path
+def get_rvc_local_path(path: str, file_type: str):
+ return os.path.join(RVC_LOCAL_MODELS_DIR, f"{path}.{file_type}")
def rvc_ui():
gr.Markdown("# RVC Beta Demo")
@@ -200,10 +267,18 @@ def rvc_ui():
value="harvest",
)
index_rate = gr.Slider(
- minimum=0.0, maximum=1.0, step=0.01, value=0.66, label="Search Feature Ratio"
+ minimum=0.0,
+ maximum=1.0,
+ step=0.01,
+ value=0.66,
+ label="Search Feature Ratio",
)
filter_radius = gr.Slider(
- minimum=0, maximum=10, step=1, value=3, label="Filter Radius (Pitch)"
+ minimum=0,
+ maximum=10,
+ step=1,
+ value=3,
+ label="Filter Radius (Pitch)",
)
with gr.Row():
resample_sr = gr.Slider(
@@ -214,10 +289,18 @@ def rvc_ui():
label="Resample Sample-rate (Bug)",
)
rms_mix_rate = gr.Slider(
- minimum=0.0, maximum=1.0, step=0.01, value=1, label="Voice Envelope Normalizaiton"
+ minimum=0.0,
+ maximum=1.0,
+ step=0.01,
+ value=1,
+ label="Voice Envelope Normalizaiton",
)
protect = gr.Slider(
- minimum=0.0, maximum=0.5, step=0.01, value=0.33, label="Protect Breath Sounds"
+ minimum=0.0,
+ maximum=0.5,
+ step=0.01,
+ value=0.33,
+ label="Protect Breath Sounds",
)
with gr.Group():
gr.Markdown("### Hubert")
@@ -263,6 +346,50 @@ def rvc_ui():
protect,
],
outputs=result,
+ api_name="rvc",
+ )
+
+ model_path_api = gr.Textbox(
+ label="Model Path",
+ value="",
+ visible=False,
+ )
+
+ index_path_api = gr.Textbox(
+ label="Index Path",
+ value="",
+ visible=False,
+ )
+
+ metadata = gr.JSON(
+ label="Metadata",
+ visible=False,
+ )
+
+ gr.Button(
+ visible=False,
+ label="Convert (API)",
+ ).click(
+ run_rvc_api,
+ inputs=[
+ f0up_key,
+ original_audio,
+ index_path_api,
+ f0method,
+ model_path_api,
+ index_rate,
+ device,
+ is_half,
+ filter_radius,
+ resample_sr,
+ rms_mix_rate,
+ protect,
+ ],
+ outputs=[
+ result,
+ metadata,
+ ],
+ api_name="rvc_api",
)
return original_audio
diff --git a/src/tortoise/TortoiseOutputRow.py b/src/tortoise/TortoiseOutputRow.py
index 8629d8d5..b15b5f2d 100644
--- a/src/tortoise/TortoiseOutputRow.py
+++ b/src/tortoise/TortoiseOutputRow.py
@@ -7,14 +7,16 @@ def __init__(
audio: gr.Audio,
image: gr.Image,
save_button: gr.Button,
- seed: gr.State,
- bundle_name: gr.State,
+ seed: gr.Textbox,
+ bundle_name: gr.Textbox,
+ params: gr.JSON,
):
self.audio: gr.Audio = audio
self.image: gr.Image = image
self.save_button: gr.Button = save_button
- self.seed: gr.State = seed
- self.bundle_name: gr.State = bundle_name
+ self.seed: gr.Textbox = seed
+ self.bundle_name: gr.Textbox = bundle_name
+ self.params: gr.JSON = params
def to_list(self):
return [
@@ -23,6 +25,7 @@ def to_list(self):
self.save_button,
self.seed,
self.bundle_name,
+ self.params,
]
@staticmethod
@@ -33,6 +36,7 @@ def from_list(components):
save_button=components[2],
seed=components[3],
bundle_name=components[4],
+ params=components[5],
)
# def __iter__(self):
@@ -47,9 +51,11 @@ def __init__(
save_button,
seed,
bundle_name,
+ params,
):
self.audio = audio
self.image = image
self.save_button = save_button
self.seed = seed
self.bundle_name = bundle_name
+ self.params = params
diff --git a/src/tortoise/create_tortoise_output_row_ui.py b/src/tortoise/create_tortoise_output_row_ui.py
index 6fc70832..489ef3a7 100644
--- a/src/tortoise/create_tortoise_output_row_ui.py
+++ b/src/tortoise/create_tortoise_output_row_ui.py
@@ -32,8 +32,15 @@ def create_tortoise_output_row_ui(index):
)
)
save_button = gr.Button("Save to favorites", visible=False)
- seed = gr.State() # type: ignore
- bundle_name = gr.State() # type: ignore
+ seed = gr.Textbox(
+ visible=False,
+ )
+ bundle_name = gr.Textbox(
+ visible=False,
+ )
+ params = gr.JSON(
+ visible=False,
+ )
save_button.click(
fn=save_to_favorites,
@@ -42,7 +49,7 @@ def create_tortoise_output_row_ui(index):
)
return (
- TortoiseOutputRow(audio, image, save_button, seed, bundle_name).to_list(),
+ TortoiseOutputRow(audio, image, save_button, seed, bundle_name, params).to_list(),
col,
seed,
)
diff --git a/src/tortoise/gen_tortoise.py b/src/tortoise/gen_tortoise.py
index ce925901..61c9a8e3 100644
--- a/src/tortoise/gen_tortoise.py
+++ b/src/tortoise/gen_tortoise.py
@@ -166,6 +166,7 @@ def _process_gen(candidates, audio_array, id, params: TortoiseParameters):
save_button=gr.Button.update(value="Save to favorites", visible=True),
seed=params.seed,
bundle_name=history_bundle_name_data,
+ params=gr.JSON.update(value=metadata), # broken because gradio returns only __type__
)
diff --git a/src/tortoise/generation_tab_tortoise.py b/src/tortoise/generation_tab_tortoise.py
index d75fb1a4..05366591 100644
--- a/src/tortoise/generation_tab_tortoise.py
+++ b/src/tortoise/generation_tab_tortoise.py
@@ -53,10 +53,13 @@ def tortoise_core_ui():
show_label=False,
container=False,
)
- gr_open_button_simple(TORTOISE_VOICE_DIR_ABS)
+ gr_open_button_simple(
+ TORTOISE_VOICE_DIR_ABS, api_name="tortoise_open_voices"
+ )
gr_reload_button().click(
fn=lambda: gr.Dropdown.update(choices=get_voice_list()),
outputs=[voice],
+ api_name="tortoise_refresh_voices",
)
with gr.Box():
gr.Markdown("Preset")
@@ -179,6 +182,7 @@ def gen(*args):
fn=gen,
inputs=inputs,
outputs=get_output_list(count),
+ api_name=f"generate_tortoise_{count}",
)
)
diff --git a/src/tortoise/gr_reload_button.py b/src/tortoise/gr_reload_button.py
index 09c5c833..23916724 100644
--- a/src/tortoise/gr_reload_button.py
+++ b/src/tortoise/gr_reload_button.py
@@ -19,7 +19,8 @@ def gr_open_button(**kwargs):
return gr_icon_button(value="folder_open", **kwargs)
-def gr_open_button_simple(dirname="", **kwargs):
+def gr_open_button_simple(dirname="", api_name=None, **kwargs):
return gr_open_button(**kwargs).click(
fn=lambda: open_folder(dirname),
+ api_name=api_name,
)
diff --git a/src/tortoise/tortoise_model_settings_ui.py b/src/tortoise/tortoise_model_settings_ui.py
index 76b423c8..52f96a3b 100644
--- a/src/tortoise/tortoise_model_settings_ui.py
+++ b/src/tortoise/tortoise_model_settings_ui.py
@@ -15,10 +15,13 @@ def tortoise_model_settings_ui_inner():
show_label=False,
container=False,
)
- gr_open_button_simple(TORTOISE_LOCAL_MODELS_DIR)
+ gr_open_button_simple(
+ TORTOISE_LOCAL_MODELS_DIR, api_name="tortoise_open_models"
+ )
gr_reload_button().click(
fn=lambda: gr.Dropdown.update(choices=get_model_list()),
outputs=[model],
+ api_name="tortoise_refresh_models",
)
with gr.Row():
@@ -39,6 +42,7 @@ def tortoise_model_settings_ui_inner():
fn=switch_model,
inputs=[model, kv_cache, use_deepspeed, half, tokenizer, use_basic_cleaners],
outputs=[model],
+ api_name="tortoise_apply_model_settings",
)
model.select(
diff --git a/src/vocos/vocos_tab_bark.py b/src/vocos/vocos_tab_bark.py
index 89cf3db4..c86ab024 100644
--- a/src/vocos/vocos_tab_bark.py
+++ b/src/vocos/vocos_tab_bark.py
@@ -79,6 +79,7 @@ def get_audio(npz_file_obj: tempfile._TemporaryFileWrapper):
fn=get_audio,
inputs=[npz_file],
outputs=[current, output],
+ api_name="encodec_decode",
)
def vocos_predict(npz_file_obj: tempfile._TemporaryFileWrapper):
@@ -96,6 +97,7 @@ def vocos_predict(npz_file_obj: tempfile._TemporaryFileWrapper):
fn=vocos_predict,
inputs=[npz_file],
outputs=output,
+ api_name="vocos_npz",
)
diff --git a/src/vocos/vocos_tab_wav.py b/src/vocos/vocos_tab_wav.py
index 50495316..a8b33c05 100644
--- a/src/vocos/vocos_tab_wav.py
+++ b/src/vocos/vocos_tab_wav.py
@@ -55,6 +55,7 @@ def vocos_tab_wav():
fn=vocos_predict,
inputs=[file_input, bandwidth_id],
outputs=output,
+ api_name="vocos_wav",
)