fix(style): playground image incomplete

This commit is contained in:
jialin
2024-11-28 17:13:51 +08:00
parent af789ee886
commit bd418b23dc
23 changed files with 704 additions and 255 deletions
+1
View File
@@ -33,6 +33,7 @@
"axios": "^1.7.2", "axios": "^1.7.2",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"colorthief": "^2.6.0",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"dayjs": "^1.11.11", "dayjs": "^1.11.11",
"echarts": "^5.5.1", "echarts": "^5.5.1",
+348 -29
View File
@@ -62,6 +62,9 @@ dependencies:
clipboard: clipboard:
specifier: ^2.0.11 specifier: ^2.0.11
version: 2.0.11 version: 2.0.11
colorthief:
specifier: ^2.6.0
version: 2.6.0
crypto-js: crypto-js:
specifier: ^4.2.0 specifier: ^4.2.0
version: 4.2.0 version: 4.2.0
@@ -3289,6 +3292,14 @@ packages:
tslib: 2.6.2 tslib: 2.6.2
dev: false dev: false
/@emnapi/runtime@1.3.1:
resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==, tarball: https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz}
requiresBuild: true
dependencies:
tslib: 2.6.2
dev: false
optional: true
/@emotion/babel-plugin@11.11.0: /@emotion/babel-plugin@11.11.0:
resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
dependencies: dependencies:
@@ -4288,6 +4299,186 @@ packages:
- supports-color - supports-color
dev: false dev: false
/@img/sharp-darwin-arm64@0.33.5:
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==, tarball: https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [darwin]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.0.4
dev: false
optional: true
/@img/sharp-darwin-x64@0.33.5:
resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==, tarball: https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [darwin]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-darwin-x64': 1.0.4
dev: false
optional: true
/@img/sharp-libvips-darwin-arm64@1.0.4:
resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==, tarball: https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-darwin-x64@1.0.4:
resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==, tarball: https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-arm64@1.0.4:
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-arm@1.0.5:
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-s390x@1.0.4:
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linux-x64@1.0.4:
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linuxmusl-arm64@1.0.4:
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-libvips-linuxmusl-x64@1.0.4:
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==, tarball: https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@img/sharp-linux-arm64@0.33.5:
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==, tarball: https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-arm64': 1.0.4
dev: false
optional: true
/@img/sharp-linux-arm@0.33.5:
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==, tarball: https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.0.5
dev: false
optional: true
/@img/sharp-linux-s390x@0.33.5:
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==, tarball: https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-s390x': 1.0.4
dev: false
optional: true
/@img/sharp-linux-x64@0.33.5:
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==, tarball: https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.0.4
dev: false
optional: true
/@img/sharp-linuxmusl-arm64@0.33.5:
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==, tarball: https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linuxmusl-arm64': 1.0.4
dev: false
optional: true
/@img/sharp-linuxmusl-x64@0.33.5:
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==, tarball: https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
requiresBuild: true
optionalDependencies:
'@img/sharp-libvips-linuxmusl-x64': 1.0.4
dev: false
optional: true
/@img/sharp-wasm32@0.33.5:
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==, tarball: https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [wasm32]
requiresBuild: true
dependencies:
'@emnapi/runtime': 1.3.1
dev: false
optional: true
/@img/sharp-win32-ia32@0.33.5:
resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==, tarball: https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@img/sharp-win32-x64@0.33.5:
resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==, tarball: https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@isaacs/cliui@8.0.2: /@isaacs/cliui@8.0.2:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, tarball: https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz} resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, tarball: https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -4445,6 +4636,10 @@ packages:
react-is: 16.13.1 react-is: 16.13.1
dev: false dev: false
/@lokesh.dhakar/quantize@1.4.0:
resolution: {integrity: sha512-+//cqVWKis//t0YH62EDtwaFSPG/CDtYNg4CZmzNmG2d5W17Iu3fuDAdpQXCDHUDrrU9q0veze4A7tPZXlR/mg==, tarball: https://registry.npmjs.org/@lokesh.dhakar/quantize/-/quantize-1.4.0.tgz}
dev: false
/@mapbox/node-pre-gyp@1.0.11: /@mapbox/node-pre-gyp@1.0.11:
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==, tarball: https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz} resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==, tarball: https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz}
hasBin: true hasBin: true
@@ -4872,7 +5067,7 @@ packages:
dependencies: dependencies:
'@babel/core': 7.24.5 '@babel/core': 7.24.5
postcss: 7.0.39 postcss: 7.0.39
postcss-syntax: 0.36.2(postcss@7.0.39) postcss-syntax: 0.36.2(postcss@8.4.38)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: false dev: false
@@ -4913,7 +5108,7 @@ packages:
postcss-syntax: '>=0.36.2' postcss-syntax: '>=0.36.2'
dependencies: dependencies:
postcss: 7.0.39 postcss: 7.0.39
postcss-syntax: 0.36.2(postcss@7.0.39) postcss-syntax: 0.36.2(postcss@8.4.38)
remark: 13.0.0 remark: 13.0.0
unist-util-find-all-after: 3.0.2 unist-util-find-all-after: 3.0.2
transitivePeerDependencies: transitivePeerDependencies:
@@ -5107,6 +5302,10 @@ packages:
use-sync-external-store: 1.2.2(react@18.2.0) use-sync-external-store: 1.2.2(react@18.2.0)
dev: false dev: false
/@tokenizer/token@0.3.0:
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==, tarball: https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz}
dev: false
/@trysound/sax@0.2.0: /@trysound/sax@0.2.0:
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==, tarball: https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz} resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==, tarball: https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
@@ -5266,6 +5465,10 @@ packages:
resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
dev: false dev: false
/@types/ndarray@1.0.14:
resolution: {integrity: sha512-oANmFZMnFQvb219SSBIhI1Ih/r4CvHDOzkWyJS/XRqkMrGH5/kaPSA1hQhdIBzouaE+5KpE/f5ylI9cujmckQg==, tarball: https://registry.npmjs.org/@types/ndarray/-/ndarray-1.0.14.tgz}
dev: false
/@types/node@20.12.11: /@types/node@20.12.11:
resolution: {integrity: sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==} resolution: {integrity: sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==}
dependencies: dependencies:
@@ -8500,6 +8703,13 @@ packages:
/color-name@1.1.4: /color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
/color-string@1.9.1:
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==, tarball: https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz}
dependencies:
color-name: 1.1.4
simple-swizzle: 0.2.2
dev: false
/color-support@1.1.3: /color-support@1.1.3:
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==, tarball: https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz} resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==, tarball: https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz}
hasBin: true hasBin: true
@@ -8507,6 +8717,14 @@ packages:
dev: false dev: false
optional: true optional: true
/color@4.2.3:
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==, tarball: https://registry.npmjs.org/color/-/color-4.2.3.tgz}
engines: {node: '>=12.5.0'}
dependencies:
color-convert: 2.0.1
color-string: 1.9.1
dev: false
/colord@2.9.3: /colord@2.9.3:
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==, tarball: https://registry.npmjs.org/colord/-/colord-2.9.3.tgz} resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==, tarball: https://registry.npmjs.org/colord/-/colord-2.9.3.tgz}
dev: false dev: false
@@ -8515,6 +8733,15 @@ packages:
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
dev: true dev: true
/colorthief@2.6.0:
resolution: {integrity: sha512-yL3B7laeOr4kH9XasFF5rl+9Taz+Pmt/CRbaTI6XepZFyQvk4K/abaGKIAsngVpxKkgFeoJ2IwdRpS228icrig==, tarball: https://registry.npmjs.org/colorthief/-/colorthief-2.6.0.tgz}
dependencies:
'@lokesh.dhakar/quantize': 1.4.0
file-type: 16.5.4
ndarray-pixels: 4.1.0
sharp: 0.33.5
dev: false
/combined-stream@1.0.8: /combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, tarball: https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz} resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, tarball: https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -8959,6 +9186,12 @@ packages:
resolution: {integrity: sha512-qv8s+G47V6Hq+g2kRE5th+ASzzrL7b6l+tap1DHKK25ZQJv3yIFhH96XaQ7NGL+zRW3t/RDbweJf/dJDe5Z5KA==, tarball: https://registry.npmjs.org/current-script-polyfill/-/current-script-polyfill-1.0.0.tgz} resolution: {integrity: sha512-qv8s+G47V6Hq+g2kRE5th+ASzzrL7b6l+tap1DHKK25ZQJv3yIFhH96XaQ7NGL+zRW3t/RDbweJf/dJDe5Z5KA==, tarball: https://registry.npmjs.org/current-script-polyfill/-/current-script-polyfill-1.0.0.tgz}
dev: false dev: false
/cwise-compiler@1.1.3:
resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==, tarball: https://registry.npmjs.org/cwise-compiler/-/cwise-compiler-1.1.3.tgz}
dependencies:
uniq: 1.0.1
dev: false
/d@1.0.2: /d@1.0.2:
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
engines: {node: '>=0.12'} engines: {node: '>=0.12'}
@@ -9201,7 +9434,6 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
requiresBuild: true requiresBuild: true
dev: false dev: false
optional: true
/detect-newline@3.1.0: /detect-newline@3.1.0:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==, tarball: https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz} resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==, tarball: https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz}
@@ -10694,6 +10926,15 @@ packages:
webpack: 5.95.0 webpack: 5.95.0
dev: true dev: true
/file-type@16.5.4:
resolution: {integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==, tarball: https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz}
engines: {node: '>=10'}
dependencies:
readable-web-to-node-stream: 3.0.2
strtok3: 6.3.0
token-types: 4.2.1
dev: false
/fill-range@7.0.1: /fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -11622,6 +11863,10 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: false dev: false
/iota-array@1.0.0:
resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==, tarball: https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz}
dev: false
/ipaddr.js@1.9.1: /ipaddr.js@1.9.1:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
@@ -11667,6 +11912,10 @@ packages:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
dev: false dev: false
/is-arrayish@0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==, tarball: https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz}
dev: false
/is-arrow-function@2.0.3: /is-arrow-function@2.0.3:
resolution: {integrity: sha512-iDStzcT1FJMzx+TjCOK//uDugSe/Mif/8a+T0htydQ3qkJGvSweTZpVYz4hpJH0baloSPiAFQdA8WslAgJphvQ==, tarball: https://registry.npmjs.org/is-arrow-function/-/is-arrow-function-2.0.3.tgz} resolution: {integrity: sha512-iDStzcT1FJMzx+TjCOK//uDugSe/Mif/8a+T0htydQ3qkJGvSweTZpVYz4hpJH0baloSPiAFQdA8WslAgJphvQ==, tarball: https://registry.npmjs.org/is-arrow-function/-/is-arrow-function-2.0.3.tgz}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -11702,6 +11951,10 @@ packages:
has-tostringtag: 1.0.2 has-tostringtag: 1.0.2
dev: false dev: false
/is-buffer@1.1.6:
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==, tarball: https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz}
dev: false
/is-buffer@2.0.5: /is-buffer@2.0.5:
resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==, tarball: https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz} resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==, tarball: https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -13055,6 +13308,28 @@ packages:
/natural-compare@1.4.0: /natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
/ndarray-ops@1.2.2:
resolution: {integrity: sha512-BppWAFRjMYF7N/r6Ie51q6D4fs0iiGmeXIACKY66fLpnwIui3Wc3CXiD/30mgLbDjPpSLrsqcp3Z62+IcHZsDw==, tarball: https://registry.npmjs.org/ndarray-ops/-/ndarray-ops-1.2.2.tgz}
dependencies:
cwise-compiler: 1.1.3
dev: false
/ndarray-pixels@4.1.0:
resolution: {integrity: sha512-xKPI4zXJ2pkUcVX24zIN1AWqqPWvRWWhRuO6PlY4EdB2VNRauNwA6rDdsAQG/ldQp0sU7nTXgPR/io1duy3Zyg==, tarball: https://registry.npmjs.org/ndarray-pixels/-/ndarray-pixels-4.1.0.tgz}
dependencies:
'@types/ndarray': 1.0.14
ndarray: 1.0.19
ndarray-ops: 1.2.2
sharp: 0.33.5
dev: false
/ndarray@1.0.19:
resolution: {integrity: sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==, tarball: https://registry.npmjs.org/ndarray/-/ndarray-1.0.19.tgz}
dependencies:
iota-array: 1.0.0
is-buffer: 1.1.6
dev: false
/needle@3.3.1: /needle@3.3.1:
resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==, tarball: https://registry.npmjs.org/needle/-/needle-3.3.1.tgz} resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==, tarball: https://registry.npmjs.org/needle/-/needle-3.3.1.tgz}
engines: {node: '>= 4.4.x'} engines: {node: '>= 4.4.x'}
@@ -13733,6 +14008,11 @@ packages:
- supports-color - supports-color
dev: false dev: false
/peek-readable@4.1.0:
resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==, tarball: https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz}
engines: {node: '>=8'}
dev: false
/performance-now@2.1.0: /performance-now@2.1.0:
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==, tarball: https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz} resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==, tarball: https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz}
dev: false dev: false
@@ -14143,7 +14423,7 @@ packages:
dependencies: dependencies:
htmlparser2: 3.10.1 htmlparser2: 3.10.1
postcss: 7.0.39 postcss: 7.0.39
postcss-syntax: 0.36.2(postcss@7.0.39) postcss-syntax: 0.36.2(postcss@8.4.38)
dev: false dev: false
/postcss-image-set-function@4.0.7(postcss@8.4.38): /postcss-image-set-function@4.0.7(postcss@8.4.38):
@@ -14617,30 +14897,6 @@ packages:
lodash: 4.17.21 lodash: 4.17.21
postcss: 8.4.38 postcss: 8.4.38
/postcss-syntax@0.36.2(postcss@7.0.39):
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
peerDependencies:
postcss: '>=5.0.0'
postcss-html: '*'
postcss-jsx: '*'
postcss-less: '*'
postcss-markdown: '*'
postcss-scss: '*'
peerDependenciesMeta:
postcss-html:
optional: true
postcss-jsx:
optional: true
postcss-less:
optional: true
postcss-markdown:
optional: true
postcss-scss:
optional: true
dependencies:
postcss: 7.0.39
dev: false
/postcss-syntax@0.36.2(postcss@8.4.38): /postcss-syntax@0.36.2(postcss@8.4.38):
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==} resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
peerDependencies: peerDependencies:
@@ -16561,6 +16817,13 @@ packages:
util-deprecate: 1.0.2 util-deprecate: 1.0.2
dev: false dev: false
/readable-web-to-node-stream@3.0.2:
resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==, tarball: https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz}
engines: {node: '>=8'}
dependencies:
readable-stream: 3.6.2
dev: false
/readdirp@3.6.0: /readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'} engines: {node: '>=8.10.0'}
@@ -17276,6 +17539,36 @@ packages:
resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
dev: false dev: false
/sharp@0.33.5:
resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==, tarball: https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
requiresBuild: true
dependencies:
color: 4.2.3
detect-libc: 2.0.3
semver: 7.6.3
optionalDependencies:
'@img/sharp-darwin-arm64': 0.33.5
'@img/sharp-darwin-x64': 0.33.5
'@img/sharp-libvips-darwin-arm64': 1.0.4
'@img/sharp-libvips-darwin-x64': 1.0.4
'@img/sharp-libvips-linux-arm': 1.0.5
'@img/sharp-libvips-linux-arm64': 1.0.4
'@img/sharp-libvips-linux-s390x': 1.0.4
'@img/sharp-libvips-linux-x64': 1.0.4
'@img/sharp-libvips-linuxmusl-arm64': 1.0.4
'@img/sharp-libvips-linuxmusl-x64': 1.0.4
'@img/sharp-linux-arm': 0.33.5
'@img/sharp-linux-arm64': 0.33.5
'@img/sharp-linux-s390x': 0.33.5
'@img/sharp-linux-x64': 0.33.5
'@img/sharp-linuxmusl-arm64': 0.33.5
'@img/sharp-linuxmusl-x64': 0.33.5
'@img/sharp-wasm32': 0.33.5
'@img/sharp-win32-ia32': 0.33.5
'@img/sharp-win32-x64': 0.33.5
dev: false
/shebang-command@2.0.0: /shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -17357,6 +17650,12 @@ packages:
dev: false dev: false
optional: true optional: true
/simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==, tarball: https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz}
dependencies:
is-arrayish: 0.3.2
dev: false
/simplebar-core@1.2.6: /simplebar-core@1.2.6:
resolution: {integrity: sha512-H5NYU+O+uvqOH5VXw3+lgoc1vTI6jL8LOZJsw4xgRpV7uIPjRpmLPdz0TrouxwKHBhpVLzVIlyKhaRLelIThMw==, tarball: https://registry.npmjs.org/simplebar-core/-/simplebar-core-1.2.6.tgz} resolution: {integrity: sha512-H5NYU+O+uvqOH5VXw3+lgoc1vTI6jL8LOZJsw4xgRpV7uIPjRpmLPdz0TrouxwKHBhpVLzVIlyKhaRLelIThMw==, tarball: https://registry.npmjs.org/simplebar-core/-/simplebar-core-1.2.6.tgz}
dependencies: dependencies:
@@ -17755,6 +18054,14 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'} engines: {node: '>=8'}
/strtok3@6.3.0:
resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==, tarball: https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz}
engines: {node: '>=10'}
dependencies:
'@tokenizer/token': 0.3.0
peek-readable: 4.1.0
dev: false
/style-search@0.1.0: /style-search@0.1.0:
resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
dev: false dev: false
@@ -17897,7 +18204,7 @@ packages:
postcss-sass: 0.4.4 postcss-sass: 0.4.4
postcss-scss: 2.1.1 postcss-scss: 2.1.1
postcss-selector-parser: 6.0.16 postcss-selector-parser: 6.0.16
postcss-syntax: 0.36.2(postcss@7.0.39) postcss-syntax: 0.36.2(postcss@8.4.38)
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
resolve-from: 5.0.0 resolve-from: 5.0.0
slash: 3.0.0 slash: 3.0.0
@@ -18281,6 +18588,14 @@ packages:
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
dev: false dev: false
/token-types@4.2.1:
resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==, tarball: https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz}
engines: {node: '>=10'}
dependencies:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
dev: false
/totalist@3.0.1: /totalist@3.0.1:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==, tarball: https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz} resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==, tarball: https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz}
engines: {node: '>=6'} engines: {node: '>=6'}
@@ -18657,6 +18972,10 @@ packages:
vfile: 4.2.1 vfile: 4.2.1
dev: false dev: false
/uniq@1.0.1:
resolution: {integrity: sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==, tarball: https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz}
dev: false
/unist-util-find-all-after@3.0.2: /unist-util-find-all-after@3.0.2:
resolution: {integrity: sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ==, tarball: https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz} resolution: {integrity: sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ==, tarball: https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz}
dependencies: dependencies:
+6
View File
@@ -49,5 +49,11 @@
.speaker { .speaker {
margin-left: 10px; margin-left: 10px;
position: relative;
.volume-slider {
position: absolute;
bottom: 30px;
}
} }
} }
+57 -5
View File
@@ -1,12 +1,14 @@
import { formatTime } from '@/utils/index'; import { formatTime } from '@/utils/index';
import { PauseCircleFilled, PlayCircleFilled } from '@ant-design/icons'; import { PauseCircleFilled, PlayCircleFilled } from '@ant-design/icons';
import { Button, Slider } from 'antd'; import { Button, Slider, Tooltip } from 'antd';
import { round } from 'lodash';
import React, { import React, {
forwardRef, forwardRef,
useCallback, useCallback,
useEffect, useEffect,
useImperativeHandle useImperativeHandle
} from 'react'; } from 'react';
import CheckButtons from '../check-buttons';
import IconFont from '../icon-font'; import IconFont from '../icon-font';
import './index.less'; import './index.less';
@@ -21,6 +23,13 @@ interface AudioPlayerProps {
duration?: number; duration?: number;
} }
const speedOptions = [
{ label: '1x', value: 1 },
{ label: '2x', value: 2 },
{ label: '3x', value: 3 },
{ label: '4x', value: 4 }
];
const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => { const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
const { autoplay = false, speed: defaultSpeed = 1 } = props; const { autoplay = false, speed: defaultSpeed = 1 } = props;
const audioRef = React.useRef<HTMLAudioElement>(null); const audioRef = React.useRef<HTMLAudioElement>(null);
@@ -45,6 +54,14 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
audioRef.current?.pause(); audioRef.current?.pause();
} }
})); }));
const handleShowVolume = useCallback(() => {
setSpeakerOn(!speakerOn);
}, [speakerOn]);
const handleSeepdChange = useCallback((value: number | string) => {
setSpeed(value as number);
audioRef.current!.playbackRate = value as number;
}, []);
const handleAudioOnPlay = useCallback(() => { const handleAudioOnPlay = useCallback(() => {
timer.current = setInterval(() => { timer.current = setInterval(() => {
@@ -78,16 +95,22 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
setPlayOn(!playOn); setPlayOn(!playOn);
}, [playOn]); }, [playOn]);
const handleFormatVolume = (val: number) => {
return `${round(val * 100)}%`;
};
const handleVolumeChange = useCallback((value: number) => {
audioRef.current!.volume = round(value, 2);
setVolume(round(value, 2));
}, []);
const initPlayerConfig = useCallback(() => { const initPlayerConfig = useCallback(() => {
// set volume
audioRef.current!.volume = volume; audioRef.current!.volume = volume;
// set playback rate
audioRef.current!.playbackRate = speed; audioRef.current!.playbackRate = speed;
}, []); }, []);
const handleLoadedMetadata = useCallback( const handleLoadedMetadata = useCallback(
(data: any) => { (data: any) => {
console.log('loadmetadata++++++++');
const duration = Math.ceil(audioRef.current?.duration || 0); const duration = Math.ceil(audioRef.current?.duration || 0);
setAudioState({ setAudioState({
currentTime: 0, currentTime: 0,
@@ -158,7 +181,23 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
onChange={handleCurrentChange} onChange={handleCurrentChange}
/> />
</div> </div>
<span>{props.speed ? `${props.speed}x` : '1x'}</span> <Tooltip
overlayInnerStyle={{
backgroundColor: 'var(--color-white-1)'
}}
arrow={false}
title={
<CheckButtons
options={speedOptions}
onChange={handleSeepdChange}
size="small"
></CheckButtons>
}
>
<span style={{ cursor: 'pointer' }}>
{speed ? `${speed}x` : '1x'}
</span>
</Tooltip>
</div> </div>
<span className="time">{formatTime(audioState.duration)}</span> <span className="time">{formatTime(audioState.duration)}</span>
</div> </div>
@@ -173,6 +212,19 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
></IconFont> ></IconFont>
} }
></Button> ></Button>
{speakerOn && (
<Slider
tooltip={{ formatter: handleFormatVolume }}
style={{ height: '100px' }}
className="volume-slider"
min={0}
max={1}
step={0.01}
value={volume}
vertical
onChange={handleVolumeChange}
/>
)}
</span> </span>
</div> </div>
<audio <audio
+43
View File
@@ -0,0 +1,43 @@
import { Button } from 'antd';
import React from 'react';
interface CheckButtonsProps {
options: Global.BaseOption<string | number>[];
onChange: (value: string | number) => void;
cancelable?: boolean;
size?: 'small' | 'middle' | 'large';
type?: 'text' | 'primary' | 'default' | 'dashed' | 'link' | undefined;
}
const CheckButtons: React.FC<CheckButtonsProps> = (props) => {
const [type, setType] = React.useState(props.type || 'text');
const [active, setActive] = React.useState<string | number | null>(null);
const handleChange = (value: string | number) => {
props.onChange(value);
if (props.cancelable && active === value) {
setActive(null);
} else {
setActive(value);
}
};
return (
<div className="flex-center gap-6">
{props.options?.map?.((option, index) => {
return (
<Button
size={props.size}
key={option.value}
onClick={() => handleChange(option.value)}
variant="filled"
color={active === option.value ? 'default' : undefined}
type={type}
>
{option.label}
</Button>
);
})}
</div>
);
};
export default React.memo(CheckButtons);
-1
View File
@@ -7,7 +7,6 @@ interface SpeechContentProps {
} }
const SpeechContent: React.FC<SpeechContentProps> = (props) => { const SpeechContent: React.FC<SpeechContentProps> = (props) => {
console.log('SpeechContent', props);
return ( return (
<> <>
{props.dataList.map((item) => ( {props.dataList.map((item) => (
+42 -21
View File
@@ -1,11 +1,29 @@
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import { DownloadOutlined, PlayCircleOutlined } from '@ant-design/icons'; import {
DownloadOutlined,
PauseCircleOutlined,
PlayCircleOutlined
} from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Tooltip } from 'antd'; import { Button, Tooltip } from 'antd';
import dayjs from 'dayjs';
import React, { useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
import AudioPlayer from './audio-player'; import AudioPlayer from './audio-player';
import './styles/index.less'; import './styles/index.less';
// const audioUrl = require('./ih.mp4'); const audioFormat = {
'audio/mpeg': 'mp3',
'audio/wav': 'wav',
'audio/ogg': 'ogg',
'audio/webm': 'webm',
'audio/aac': 'aac',
'audio/x-flac': 'flac',
'audio/pcm': 'pcm',
'audio/flac': 'flac',
'audio/x-wav': 'wav',
'audio/L16': 'pcm',
'audio/opus': 'opus'
};
interface SpeechContentProps { interface SpeechContentProps {
prompt: string; prompt: string;
@@ -16,12 +34,19 @@ interface SpeechContentProps {
audioUrl: string; audioUrl: string;
} }
const SpeechItem: React.FC<SpeechContentProps> = (props) => { const SpeechItem: React.FC<SpeechContentProps> = (props) => {
console.log('porps=======', props); const intl = useIntl();
const [collapsed, setCollapsed] = useState(false); const [collapsed, setCollapsed] = useState(false);
const [isPlay, setIsPlay] = useState(false);
const ref = useRef<HTMLAudioElement>(null); const ref = useRef<HTMLAudioElement>(null);
const handlePlay = () => { const handlePlay = () => {
if (isPlay) {
ref.current?.pause();
setIsPlay(false);
return;
}
ref.current?.play(); ref.current?.play();
setIsPlay(true);
}; };
const handleCollapse = () => { const handleCollapse = () => {
@@ -30,7 +55,7 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
const onDownload = () => { const onDownload = () => {
const url = props.audioUrl || ''; const url = props.audioUrl || '';
const filename = Date.now() + ''; const filename = `audio-${dayjs().format('YYYYMMDDHHmmss')}.${props.format}`;
const link = document.createElement('a'); const link = document.createElement('a');
link.href = url; link.href = url;
@@ -45,7 +70,6 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
<div className="speech-item"> <div className="speech-item">
<div className="voice"> <div className="voice">
<IconFont type="icon-user_voice" className="font-size-16" /> <IconFont type="icon-user_voice" className="font-size-16" />
{/* <span className="text">{props.voice}</span> */}
</div> </div>
<div className="wrapper"> <div className="wrapper">
<AudioPlayer <AudioPlayer
@@ -62,15 +86,25 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
<span className="item">{props.speed}x</span> <span className="item">{props.speed}x</span>
</span> </span>
<div className="actions"> <div className="actions">
<Tooltip title="Play"> <Tooltip
title={
isPlay
? intl.formatMessage({ id: 'playground.audio.button.stop' })
: intl.formatMessage({ id: 'playground.audio.button.play' })
}
>
<Button <Button
onClick={handlePlay} onClick={handlePlay}
icon={<PlayCircleOutlined />} icon={isPlay ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
type="text" type="text"
size="small" size="small"
></Button> ></Button>
</Tooltip> </Tooltip>
<Tooltip title="Download"> <Tooltip
title={intl.formatMessage({
id: 'playground.audio.button.download'
})}
>
<Button <Button
onClick={onDownload} onClick={onDownload}
icon={<DownloadOutlined />} icon={<DownloadOutlined />}
@@ -78,21 +112,8 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
size="small" size="small"
></Button> ></Button>
</Tooltip> </Tooltip>
{/* <Tooltip title="Show Prompt">
<Button
icon={<FileTextOutlined />}
type="text"
size="small"
onClick={handleCollapse}
></Button>
</Tooltip> */}
</div> </div>
</div> </div>
{/* {collapsed && (
<div className="prompt-box">
<div className="prompt">{props.prompt}</div>
</div>
)} */}
</div> </div>
); );
}; };
+1 -2
View File
@@ -13,12 +13,11 @@ interface UploadAudioProps {
const UploadAudio: React.FC<UploadAudioProps> = (props) => { const UploadAudio: React.FC<UploadAudioProps> = (props) => {
const intl = useIntl(); const intl = useIntl();
const beforeUpload = (file: any) => { const beforeUpload = (file: any) => {
return true; return false;
}; };
const handleOnChange = React.useCallback( const handleOnChange = React.useCallback(
(data: { file: any; fileList: any }) => { (data: { file: any; fileList: any }) => {
console.log('handleOnChange', data);
props.onChange?.(data); props.onChange?.(data);
}, },
[] []
+11 -5
View File
@@ -88,7 +88,10 @@ export default {
'playground.audio.generating.tips': 'Generated text will appear here.', 'playground.audio.generating.tips': 'Generated text will appear here.',
'playground.audio.uploadfile.tips': 'playground.audio.uploadfile.tips':
'Please upload an audio file, supported formats: {formats}', 'Please upload an audio file, supported formats: {formats}',
'playground.input.multiplePaste': 'Multi-line paste', 'playground.input.multiplePaste': 'Batch Input Mode',
'playground.input.multiplePaste.tips':
'When enabled, pasted multi-line text will be automatically split by newline into separate entries in the form.',
'playground.audio.button.generate': 'Generate Text Content',
'playground.multiple.on': 'Enable', 'playground.multiple.on': 'Enable',
'playground.multiple.off': 'Disable', 'playground.multiple.off': 'Disable',
'playground.image.params.sampler': 'Sampler', 'playground.image.params.sampler': 'Sampler',
@@ -96,12 +99,15 @@ export default {
'playground.image.params.seed': 'Seed', 'playground.image.params.seed': 'Seed',
'playground.image.params.negativePrompt': 'Negative Prompt', 'playground.image.params.negativePrompt': 'Negative Prompt',
'playground.image.params.cfgScale': 'Scale Factor', 'playground.image.params.cfgScale': 'Scale Factor',
'playground.image.params.custom': 'Custom', 'playground.image.params.custom': 'Advanced',
'playground.image.params.custom.tips': 'Parameter definition', 'playground.image.params.custom.tips': 'API Style',
'playground.image.params.openai': 'OpenAI Compatible', 'playground.image.params.openai': 'OpenAI Compatible',
'playground.embedding.handler.tips': 'Resize Height', 'playground.embedding.handler.tips': 'Resize Height',
'playground.embedding.pcatips1': 'playground.embedding.pcatips1':
'PCA is used to reduce the dimensionality of document vectors, projecting new data into PCA space.', 'PCA (Principal Component Analysis) is used to reduce the dimensionality of embedding vectors, making them easier to visualize.',
'playground.embedding.pcatips2': 'playground.embedding.pcatips2':
'In the chart, the distance between points represents the similarity between documents.' 'In the chart, the distance between points indicates the similarity between the corresponding documents. Closer points mean higher similarity.',
'playground.audio.button.play': 'Play',
'playground.audio.button.download': 'Download',
'playground.audio.button.stop': 'Stop'
}; };
+14 -9
View File
@@ -86,20 +86,25 @@ export default {
'playground.audio.generating.tips': '生成的文本将出现在这里', 'playground.audio.generating.tips': '生成的文本将出现在这里',
'playground.audio.uploadfile.tips': '请上传音频文件,支持格式:{formats}', 'playground.audio.uploadfile.tips': '请上传音频文件,支持格式:{formats}',
'playground.audio.button.generate': '生成文本', 'playground.audio.button.generate': '生成文本',
'playground.input.multiplePaste': '多行粘贴', 'playground.input.multiplePaste': '批量输入',
'playground.input.multiplePaste.tips':
'启用后,粘贴的多行文本将自动按换行符分割为表单中的单独条目。',
'playground.multiple.on': '开启', 'playground.multiple.on': '开启',
'playground.multiple.off': '关闭', 'playground.multiple.off': '关闭',
'playground.image.params.sampler': '采样', 'playground.image.params.sampler': '采样方法',
'playground.image.params.samplerSteps': '采样器步数', 'playground.image.params.samplerSteps': '迭代步数',
'playground.image.params.seed': '随机种子', 'playground.image.params.seed': '随机种子',
'playground.image.params.negativePrompt': '负提示', 'playground.image.params.negativePrompt': '负提示',
'playground.image.params.cfgScale': '缩放因子', 'playground.image.params.cfgScale': '提示词引导系数',
'playground.image.params.custom': '自定义', 'playground.image.params.custom': '高级',
'playground.image.params.custom.tips': '参数定义', 'playground.image.params.custom.tips': 'API 风格',
'playground.image.params.openai': 'OpenAI 兼容', 'playground.image.params.openai': 'OpenAI 兼容',
'playground.embedding.handler.tips': '高度调节', 'playground.embedding.handler.tips': '高度调节',
'playground.embedding.pcatips1': 'playground.embedding.pcatips1':
'采用主成分分析(PCA)对文档向量化后的数据降维,将新数据投射到PCA 空间中。', 'PCA主成分分析)用于降低嵌入向量的维数,使它们更容易可视化。',
'playground.embedding.pcatips2': 'playground.embedding.pcatips2':
'图表中,点之间的距离表示应文档之间的相似度。' '图表中,点之间的距离表示应文档之间的相似度。点越近意味着相似度越高。',
'playground.audio.button.play': '播放',
'playground.audio.button.download': '下载',
'playground.audio.button.stop': '停止'
}; };
+4 -4
View File
@@ -450,7 +450,7 @@ const Models: React.FC<ModelsProps> = ({
}} }}
color="geekblue" color="geekblue"
> >
Embedding Only Embedding
</Tag> </Tag>
); );
} }
@@ -464,7 +464,7 @@ const Models: React.FC<ModelsProps> = ({
}} }}
color="geekblue" color="geekblue"
> >
{intl.formatMessage({ id: 'playground.audio.texttospeech' })} Text-To-Speech
</Tag> </Tag>
); );
} }
@@ -478,7 +478,7 @@ const Models: React.FC<ModelsProps> = ({
}} }}
color="geekblue" color="geekblue"
> >
{intl.formatMessage({ id: 'playground.audio.speechtotext' })} Speech-To-Text
</Tag> </Tag>
); );
} }
@@ -492,7 +492,7 @@ const Models: React.FC<ModelsProps> = ({
}} }}
color="geekblue" color="geekblue"
> >
Image Only Image
</Tag> </Tag>
); );
} }
+5 -13
View File
@@ -99,25 +99,17 @@ export const textToSpeech = async (params: any, options?: any) => {
const audioBlob = await res.blob(); const audioBlob = await res.blob();
const audioUrl = URL.createObjectURL(audioBlob); const audioUrl = URL.createObjectURL(audioBlob);
return audioUrl; return {
url: audioUrl,
type: audioBlob.type
};
}; };
// export const speechToText = async (params: any, options?: any) => {
// const res = await fetch(AUDIO_SPEECH_TO_TEXT_API, {
// method: 'POST',
// body: JSON.stringify(params.data),
// signal: params.signal
// });
// if (!res.ok) {
// throw new Error('Network response was not ok');
// }
// return res.json();
// };
export const speechToText = async (params: any, options?: any) => { export const speechToText = async (params: any, options?: any) => {
return request(AUDIO_SPEECH_TO_TEXT_API, { return request(AUDIO_SPEECH_TO_TEXT_API, {
method: 'POST', method: 'POST',
data: params.data, data: params.data,
cancelToken: options?.cancelToken,
headers: { headers: {
'Content-Type': 'multipart/form-data' 'Content-Type': 'multipart/form-data'
} }
+40 -10
View File
@@ -1,7 +1,13 @@
import { AudioOutlined } from '@ant-design/icons'; import { AudioOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Space, Tooltip } from 'antd'; import { Button, Space, Tooltip } from 'antd';
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState
} from 'react';
// import '../style/audio-input.less'; // import '../style/audio-input.less';
interface AudioInputProps { interface AudioInputProps {
@@ -9,6 +15,7 @@ interface AudioInputProps {
chunks: any[]; chunks: any[];
url: string; url: string;
name: string; name: string;
type: string;
duration: number; duration: number;
}) => void; }) => void;
onAnalyse?: (analyseData: any, frequencyBinCount: any) => void; onAnalyse?: (analyseData: any, frequencyBinCount: any) => void;
@@ -19,6 +26,11 @@ interface AudioInputProps {
type?: 'text' | 'primary' | 'default'; type?: 'text' | 'primary' | 'default';
} }
const recordingFormat = {
type: 'audio/wav',
suffix: '.wav'
};
const AudioInput: React.FC<AudioInputProps> = (props) => { const AudioInput: React.FC<AudioInputProps> = (props) => {
const intl = useIntl(); const intl = useIntl();
const [audioOn, setAudioOn] = useState(false); const [audioOn, setAudioOn] = useState(false);
@@ -155,6 +167,8 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
try { try {
await EnableAudio(); await EnableAudio();
console.log('audioStream:', audioStream.current);
audioRecorder.current = new MediaRecorder(audioStream.current); audioRecorder.current = new MediaRecorder(audioStream.current);
const audioChunks: any[] = []; const audioChunks: any[] = [];
@@ -170,14 +184,14 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
// stop recording // stop recording
audioRecorder.current.onstop = () => { audioRecorder.current.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' }); const audioBlob = new Blob(audioChunks, { type: recordingFormat.type });
const audioUrl = URL.createObjectURL(audioBlob); const audioUrl = URL.createObjectURL(audioBlob);
handleAudioData({ handleAudioData({
chunks: audioBlob, chunks: audioBlob,
size: audioBlob.size, size: audioBlob.size,
type: audioBlob.type, type: audioBlob.type,
url: audioUrl, url: audioUrl,
name: `recording-${new Date().toISOString()}.wav`, name: `recording-${new Date().toISOString()}${recordingFormat.suffix}`,
duration: Math.ceil((Date.now() - startTime.current) / 1000) duration: Math.ceil((Date.now() - startTime.current) / 1000)
}); });
@@ -195,6 +209,25 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
} }
}; };
const renderRecordButtonTips = useMemo(() => {
if (!audioPermission) {
return intl.formatMessage({ id: 'playground.audio.enablemic' });
}
return isRecording
? intl.formatMessage({ id: 'playground.audio.stoprecord' })
: intl.formatMessage({ id: 'playground.audio.startrecord' });
}, [audioPermission, isRecording, intl]);
const noAudioPermissionButtonStyle = useMemo(() => {
if (!audioPermission) {
return {
backgroundColor: 'var(--ant-color-error-bg-filled-hover)',
color: 'var(--ant-color-error-border-hover)',
border: 'none'
};
}
}, [audioPermission]);
useEffect(() => { useEffect(() => {
return () => { return () => {
handleStopRecording(); handleStopRecording();
@@ -210,13 +243,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
<div className="audio-input"> <div className="audio-input">
<Space size={40} className="btns"> <Space size={40} className="btns">
{ {
<Tooltip <Tooltip title={renderRecordButtonTips}>
title={
isRecording
? intl.formatMessage({ id: 'playground.audio.stoprecord' })
: intl.formatMessage({ id: 'playground.audio.startrecord' })
}
>
<div <div
style={{ style={{
display: 'flex', display: 'flex',
@@ -231,6 +258,9 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
icon={<AudioOutlined />} icon={<AudioOutlined />}
size="middle" size="middle"
type={props.type ?? 'text'} type={props.type ?? 'text'}
style={{
...noAudioPermissionButtonStyle
}}
danger={isRecording} danger={isRecording}
onClick={StartRecording} onClick={StartRecording}
></Button> ></Button>
@@ -12,7 +12,7 @@ import {
SendOutlined SendOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useIntl, useSearchParams } from '@umijs/max'; import { useIntl, useSearchParams } from '@umijs/max';
import { Button, Checkbox, Segmented, Tabs, Tooltip } from 'antd'; import { Button, Segmented, Tabs, Tooltip } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { PCA } from 'ml-pca'; import { PCA } from 'ml-pca';
import 'overlayscrollbars/overlayscrollbars.css'; import 'overlayscrollbars/overlayscrollbars.css';
@@ -81,7 +81,7 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
copyValue: '' copyValue: ''
}); });
const [lessTwoInput, setLessTwoInput] = useState<boolean>(false); const [lessTwoInput, setLessTwoInput] = useState<boolean>(false);
const multiplePasteEnable = useRef<boolean>(true); const [multiplePasteEnable, setMultiplePasteEnable] = useState<boolean>(true);
const [textList, setTextList] = useState< const [textList, setTextList] = useState<
{ text: string; uid: number | string; name: string }[] { text: string; uid: number | string; name: string }[]
@@ -279,7 +279,7 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
const handleOnPaste = useCallback( const handleOnPaste = useCallback(
(e: any, index: number) => { (e: any, index: number) => {
if (!multiplePasteEnable.current) return; if (!multiplePasteEnable) return;
const text = e.clipboardData.getData('text'); const text = e.clipboardData.getData('text');
if (text) { if (text) {
const dataLlist = text.split('\n').map((item: string) => { const dataLlist = text.split('\n').map((item: string) => {
@@ -402,18 +402,26 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
</div> </div>
</h3> </h3>
<div className="flex-center gap-10"> <div className="flex-center gap-10">
<Button className="flex-center" size="middle"> <Tooltip
<Checkbox title={intl.formatMessage({
defaultChecked={multiplePasteEnable.current} id: 'playground.input.multiplePaste.tips'
onChange={(e: any) => { })}
multiplePasteEnable.current = e.target.checked; >
<Button
className="flex-center"
variant="filled"
size="middle"
color={multiplePasteEnable ? 'primary' : 'default'}
onClick={() => {
setMultiplePasteEnable(!multiplePasteEnable);
}} }}
> >
{intl.formatMessage({ {intl.formatMessage({
id: 'playground.input.multiplePaste' id: 'playground.input.multiplePaste'
})} })}
</Checkbox> </Button>
</Button> </Tooltip>
<Button size="middle" onClick={handleAddText}> <Button size="middle" onClick={handleAddText}>
<PlusOutlined /> <PlusOutlined />
{intl.formatMessage({ id: 'playground.embedding.addtext' })} {intl.formatMessage({ id: 'playground.embedding.addtext' })}
@@ -47,14 +47,17 @@ interface MessageProps {
const initialValues = { const initialValues = {
n: 1, n: 1,
size: '512x512', size: '512x512',
quality: 'standard', seed: null,
style: null sampler: 'euler_a',
cfg_scale: 4.5,
sample_steps: 10,
negative_prompt: null
}; };
const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => { const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
const { modelList } = props; const { modelList } = props;
const messageId = useRef<number>(0); const messageId = useRef<number>(0);
const [isOpenaiCompatible, setIsOpenaiCompatible] = useState<boolean>(true); const [isOpenaiCompatible, setIsOpenaiCompatible] = useState<boolean>(false);
const [imageList, setImageList] = useState< const [imageList, setImageList] = useState<
{ {
dataUrl: string; dataUrl: string;
@@ -223,7 +226,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
const params = { const params = {
stream: true, stream: true,
stream_options: { stream_options: {
chunk_result: true // chunk_result: false
}, },
prompt: current?.content || currentPrompt || '', prompt: current?.content || currentPrompt || '',
..._.omitBy(finalParameters, (value: string) => !value) ..._.omitBy(finalParameters, (value: string) => !value)
@@ -251,8 +254,6 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
const imgItem = newImageList[item.index]; const imgItem = newImageList[item.index];
if (item.b64_json) { if (item.b64_json) {
imgItem.dataUrl += item.b64_json; imgItem.dataUrl += item.b64_json;
// imgItem.cache.push(item.b64_json);
console.log('imgItem.dataUrl:', imgItem.dataUrl);
} }
const progress = _.round(item.progress, 0); const progress = _.round(item.progress, 0);
newImageList[item.index] = { newImageList[item.index] = {
@@ -303,7 +303,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
clearAll={handleClear} clearAll={handleClear}
setModelSelections={handleSelectModel} setModelSelections={handleSelectModel}
presetPrompt={handlePresetPrompt} presetPrompt={handlePresetPrompt}
modelList={modelList}
/> />
</div> </div>
</div> </div>
@@ -2,7 +2,7 @@ import useOverlayScroller from '@/hooks/use-overlay-scroller';
import useRequestToken from '@/hooks/use-request-token'; import useRequestToken from '@/hooks/use-request-token';
import { ClearOutlined, PlusOutlined, SendOutlined } from '@ant-design/icons'; import { ClearOutlined, PlusOutlined, SendOutlined } from '@ant-design/icons';
import { useIntl, useSearchParams } from '@umijs/max'; import { useIntl, useSearchParams } from '@umijs/max';
import { Button, Checkbox, Input, Spin, Tag } from 'antd'; import { Button, Input, Spin, Tag, Tooltip } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import _ from 'lodash'; import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css'; import 'overlayscrollbars/overlayscrollbars.css';
@@ -77,7 +77,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
const messageListLengthCache = useRef<number>(0); const messageListLengthCache = useRef<number>(0);
const requestToken = useRef<any>(null); const requestToken = useRef<any>(null);
const formRef = useRef<any>(null); const formRef = useRef<any>(null);
const multiplePasteEnable = useRef<boolean>(true); const [multiplePasteEnable, setMultiplePasteEnable] = useState<boolean>(true);
const [fileList, setFileList] = useState< const [fileList, setFileList] = useState<
{ {
text: string; text: string;
@@ -346,7 +346,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
const handleOnPaste = useCallback( const handleOnPaste = useCallback(
(e: any, index: number) => { (e: any, index: number) => {
if (!multiplePasteEnable.current) return; if (!multiplePasteEnable) return;
const text = e.clipboardData.getData('text'); const text = e.clipboardData.getData('text');
if (text) { if (text) {
console.log('text:', text); console.log('text:', text);
@@ -465,18 +465,25 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
)} )}
</span> </span>
<div className="flex-center gap-10"> <div className="flex-center gap-10">
<Button className="flex-center" size="middle"> <Tooltip
<Checkbox title={intl.formatMessage({
defaultChecked={multiplePasteEnable.current} id: 'playground.input.multiplePaste.tips'
onChange={(e: any) => { })}
multiplePasteEnable.current = e.target.checked; >
<Button
className="flex-center"
variant="filled"
size="middle"
color={multiplePasteEnable ? 'primary' : 'default'}
onClick={() => {
setMultiplePasteEnable(!multiplePasteEnable);
}} }}
> >
{intl.formatMessage({ {intl.formatMessage({
id: 'playground.input.multiplePaste' id: 'playground.input.multiplePaste'
})} })}
</Checkbox> </Button>
</Button> </Tooltip>
<Button size="middle" onClick={handleAddText}> <Button size="middle" onClick={handleAddText}>
<PlusOutlined /> <PlusOutlined />
{intl.formatMessage({ id: 'playground.embedding.addtext' })} {intl.formatMessage({ id: 'playground.embedding.addtext' })}
+16 -72
View File
@@ -4,9 +4,9 @@ import IconFont from '@/components/icon-font';
import UploadAudio from '@/components/upload-audio'; import UploadAudio from '@/components/upload-audio';
import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useOverlayScroller from '@/hooks/use-overlay-scroller';
import { readAudioFile } from '@/utils/load-audio-file'; import { readAudioFile } from '@/utils/load-audio-file';
import { AudioOutlined, SendOutlined } from '@ant-design/icons'; import { SendOutlined } from '@ant-design/icons';
import { useIntl, useSearchParams } from '@umijs/max'; import { useIntl, useSearchParams } from '@umijs/max';
import { Button, Spin, Tag, Tooltip } from 'antd'; import { Button, Spin, Tooltip } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import 'overlayscrollbars/overlayscrollbars.css'; import 'overlayscrollbars/overlayscrollbars.css';
import { import {
@@ -20,7 +20,6 @@ import {
} from 'react'; } from 'react';
import { speechToText } from '../apis'; import { speechToText } from '../apis';
import { RealtimeParamsConfig as paramsConfig } from '../config/params-config'; import { RealtimeParamsConfig as paramsConfig } from '../config/params-config';
import { MessageItem } from '../config/types';
import '../style/ground-left.less'; import '../style/ground-left.less';
import '../style/speech-to-text.less'; import '../style/speech-to-text.less';
import '../style/system-message-wrap.less'; import '../style/system-message-wrap.less';
@@ -42,14 +41,9 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
const intl = useIntl(); const intl = useIntl();
const { modelList } = props; const { modelList } = props;
const messageId = useRef<number>(0); const messageId = useRef<number>(0);
const [messageList, setMessageList] = useState<MessageItem[]>([ const [messageList, setMessageList] = useState<
{ { uid: number; content: string }[]
content: '', >([]);
title: '',
role: '',
uid: messageId.current
}
]);
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const selectModel = searchParams.get('model') || ''; const selectModel = searchParams.get('model') || '';
const [parameters, setParams] = useState<any>({}); const [parameters, setParams] = useState<any>({});
@@ -68,7 +62,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
analyser: null analyser: null
}); });
const [isRecording, setIsRecording] = useState(false); const [isRecording, setIsRecording] = useState(false);
const [recordEnd, setRecordEnd] = useState(false);
const formRef = useRef<any>(null); const formRef = useRef<any>(null);
const { initialize, updateScrollerPosition } = useOverlayScroller(); const { initialize, updateScrollerPosition } = useOverlayScroller();
@@ -127,8 +120,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
setMessageList([ setMessageList([
{ {
content: result.text, content: result.text,
title: '',
role: '',
uid: messageId.current uid: messageId.current
} }
]); ]);
@@ -136,7 +127,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
console.log('error:', error); console.log('error:', error);
} finally { } finally {
setLoading(false); setLoading(false);
setRecordEnd(false);
setIsRecording(false); setIsRecording(false);
} }
}; };
@@ -170,9 +160,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
duration: data.duration duration: data.duration
}; };
}); });
setTimeout(() => {
setRecordEnd(true);
}, 200);
}, },
[] []
); );
@@ -183,9 +170,8 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
const handleUploadChange = useCallback( const handleUploadChange = useCallback(
async (data: { file: any; fileList: any }) => { async (data: { file: any; fileList: any }) => {
const res = await readAudioFile(data.file.originFileObj); const res = await readAudioFile(data.file);
setAudioData(res); setAudioData(res);
setRecordEnd(true);
}, },
[] []
); );
@@ -208,15 +194,16 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
submitMessage(); submitMessage();
}; };
const handleOnDiscard = useCallback(() => {
setRecordEnd(false);
setAudioData(null);
setIsRecording(false);
}, []);
const renderAniamtion = () => { const renderAniamtion = () => {
if (!audioPermissionOn) { if (!audioPermissionOn) {
return null; return (
<div className="tips-text">
<IconFont type={'icon-audio'} style={{ fontSize: 20 }}></IconFont>
<span>
{intl.formatMessage({ id: 'playground.audio.enablemic' })}
</span>
</div>
);
} }
if (isRecording) { if (isRecording) {
return ( return (
@@ -240,7 +227,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
useEffect(() => { useEffect(() => {
console.log('parameters:', parameters); console.log('parameters:', parameters);
}, [parameters]); }, [parameters]);
useEffect(() => {}, [messageList]);
useEffect(() => { useEffect(() => {
if (scroller.current) { if (scroller.current) {
initialize(scroller.current); initialize(scroller.current);
@@ -259,13 +246,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
} }
}, [messageList, loading]); }, [messageList, loading]);
useEffect(() => {
if (messageList.length > messageListLengthCache.current) {
updateScrollerPosition();
}
messageListLengthCache.current = messageList.length;
}, [messageList.length]);
return ( return (
<div className="ground-left-wrapper"> <div className="ground-left-wrapper">
<div className="ground-left"> <div className="ground-left">
@@ -303,42 +283,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
renderAniamtion() renderAniamtion()
)} )}
</div> </div>
{!audioPermissionOn && (
<div
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '100%'
}}
>
<span>
<Tag
style={{
width: 36,
height: 36,
lineHeight: '36px',
textAlign: 'center'
}}
bordered={false}
color="error"
icon={
<AudioOutlined className="font-size-16"></AudioOutlined>
}
></Tag>
</span>
<span
style={{
marginTop: 10,
fontSize: 14,
fontWeight: 500
}}
>
{intl.formatMessage({ id: 'playground.audio.enablemic' })}
</span>
</div>
)}
</div> </div>
<div <div
style={{ style={{
@@ -365,7 +309,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
justifyContent: 'center' justifyContent: 'center'
}} }}
> >
{audioData ? ( {messageList.length ? (
messageList[0]?.content messageList[0]?.content
) : ( ) : (
<span className="text-tertiary"> <span className="text-tertiary">
@@ -36,8 +36,7 @@ interface MessageProps {
const initialValues = { const initialValues = {
voice: '', voice: '',
response_format: 'mp3', response_format: 'mp3'
speed: 1
}; };
const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => { const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
@@ -113,13 +112,13 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
...parameters, ...parameters,
input: current?.content || currentPrompt input: current?.content || currentPrompt
}; };
const audioUrl: any = await textToSpeech({ const res: any = await textToSpeech({
data: params, data: params,
url: CHAT_API, url: CHAT_API,
signal signal
}); });
console.log('result:', parameters, audioUrl); console.log('result:', res);
setMessageList([ setMessageList([
{ {
@@ -129,7 +128,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
speed: parameters.speed, speed: parameters.speed,
uid: messageId.current, uid: messageId.current,
autoplay: checkvalueRef.current, autoplay: checkvalueRef.current,
audioUrl: audioUrl audioUrl: res.url
} }
]); ]);
} catch (error) { } catch (error) {
@@ -229,8 +229,8 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
variant="borderless" variant="borderless"
> >
<Slider <Slider
defaultValue={1024} defaultValue={2048}
max={2048} max={16 * 1024}
step={1} step={1}
style={{ marginBottom: 0, marginTop: 16, marginInline: 0 }} style={{ marginBottom: 0, marginTop: 16, marginInline: 0 }}
tooltip={{ open: false }} tooltip={{ open: false }}
+25 -25
View File
@@ -28,11 +28,11 @@ export const TTSParamsConfig: ParamsSchema[] = [
name: 'response_format', name: 'response_format',
options: [ options: [
{ label: 'mp3', value: 'mp3' }, { label: 'mp3', value: 'mp3' },
{ label: 'opus', value: 'opus' }, // { label: 'opus', value: 'opus' },
{ label: 'aac', value: 'aac' }, // { label: 'aac', value: 'aac' },
{ label: 'flac', value: 'flac' }, // { label: 'flac', value: 'flac' },
{ label: 'wav', value: 'wav' }, { label: 'wav', value: 'wav' }
{ label: 'pcm', value: 'pcm' } // { label: 'pcm', value: 'pcm' }
], ],
label: { label: {
text: 'playground.params.format', text: 'playground.params.format',
@@ -43,27 +43,27 @@ export const TTSParamsConfig: ParamsSchema[] = [
required: false required: false
} }
] ]
},
{
type: 'Select',
name: 'speed',
options: [
{ label: '0.25x', value: 0.25 },
{ label: '0.5x', value: 0.5 },
{ label: '1x', value: 1 },
{ label: '2x', value: 2 },
{ label: '4x', value: 4 }
],
label: {
text: 'playground.params.speed',
isLocalized: true
},
rules: [
{
required: false
}
]
} }
// {
// type: 'Select',
// name: 'speed',
// options: [
// { label: '0.25x', value: 0.25 },
// { label: '0.5x', value: 0.5 },
// { label: '1x', value: 1 },
// { label: '2x', value: 2 },
// { label: '4x', value: 4 }
// ],
// label: {
// text: 'playground.params.speed',
// isLocalized: true
// },
// rules: [
// {
// required: false
// }
// ]
// }
]; ];
export const RealtimeParamsConfig: ParamsSchema[] = [ export const RealtimeParamsConfig: ParamsSchema[] = [
+42 -25
View File
@@ -86,45 +86,62 @@ export const readStreamData = async (
await readStreamData(reader, decoder, callback); await readStreamData(reader, decoder, callback);
}; };
// Process the remainder of the buffer
const processBuffer = (buffer: string, callback: (data: any) => void) => {
const lines = buffer.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const jsonStr = line.slice(6).trim();
try {
const jsonData = JSON.parse(jsonStr);
callback(jsonData);
} catch (e) {
console.error(
'Failed to parse JSON from remaining buffer:',
jsonStr,
e
);
}
}
}
};
export const readLargeStreamData = async ( export const readLargeStreamData = async (
reader: any, reader: any,
decoder: TextDecoder, decoder: TextDecoder,
callback: (data: any) => void callback: (data: any) => void
) => { ) => {
let buffer = ''; let buffer = ''; // cache incomplete line
const processStream = async () => { while (true) {
const { done, value } = await reader.read(); const { done, value } = await reader.read();
if (done) { if (done) {
if (buffer) { // Process remaining buffered data
try { if (buffer.trim()) {
extractJSON(buffer).forEach((data) => { processBuffer(buffer, callback);
callback?.(data);
});
} catch (e) {
console.error('parse buffer failed:', buffer);
}
} }
return; break;
} }
// cache each chunk // Decode new chunk of data and append to buffer
buffer += decoder.decode(value, { stream: true }); buffer += decoder.decode(value, { stream: true });
const extractedData = extractJSON(buffer); // Try to process the complete line in the buffer
const lines = buffer.split('\n');
buffer = lines.pop() || ''; // Keep last line (may be incomplete)
extractedData.forEach((data) => { for (const line of lines) {
callback?.(data); if (line.startsWith('data: ')) {
}); const jsonStr = line.slice(6).trim();
try {
const lastIndex = buffer.lastIndexOf('}'); const jsonData = JSON.parse(jsonStr);
buffer = lastIndex !== -1 ? buffer.slice(lastIndex + 1) : buffer; callback(jsonData);
} catch (e) {
// next chunk console.error('Failed to parse JSON:', jsonStr, e);
await processStream(); }
}; }
}
await processStream(); }
}; };
export const readTextEventStreamData = async ( export const readTextEventStreamData = async (
+1
View File
@@ -32,6 +32,7 @@ export const loadAudioData = async (data: any, type: string) => {
}; };
export const readAudioFile = async (file: File) => { export const readAudioFile = async (file: File) => {
console.log('file====', file);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = async function (e: any) { reader.onload = async function (e: any) {