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 ( +

{prettifyDate(date)}

@@ -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 ( + + ); +}; + +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 ( +
+ +