fix(style): playground image incomplete
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
"axios": "^1.7.2",
|
||||
"classnames": "^2.5.1",
|
||||
"clipboard": "^2.0.11",
|
||||
"colorthief": "^2.6.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.11",
|
||||
"echarts": "^5.5.1",
|
||||
|
||||
Generated
+348
-29
@@ -62,6 +62,9 @@ dependencies:
|
||||
clipboard:
|
||||
specifier: ^2.0.11
|
||||
version: 2.0.11
|
||||
colorthief:
|
||||
specifier: ^2.6.0
|
||||
version: 2.6.0
|
||||
crypto-js:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
@@ -3289,6 +3292,14 @@ packages:
|
||||
tslib: 2.6.2
|
||||
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:
|
||||
resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
|
||||
dependencies:
|
||||
@@ -4288,6 +4299,186 @@ packages:
|
||||
- supports-color
|
||||
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:
|
||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, tarball: https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz}
|
||||
engines: {node: '>=12'}
|
||||
@@ -4445,6 +4636,10 @@ packages:
|
||||
react-is: 16.13.1
|
||||
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:
|
||||
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
|
||||
@@ -4872,7 +5067,7 @@ packages:
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
postcss: 7.0.39
|
||||
postcss-syntax: 0.36.2(postcss@7.0.39)
|
||||
postcss-syntax: 0.36.2(postcss@8.4.38)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
@@ -4913,7 +5108,7 @@ packages:
|
||||
postcss-syntax: '>=0.36.2'
|
||||
dependencies:
|
||||
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
|
||||
unist-util-find-all-after: 3.0.2
|
||||
transitivePeerDependencies:
|
||||
@@ -5107,6 +5302,10 @@ packages:
|
||||
use-sync-external-store: 1.2.2(react@18.2.0)
|
||||
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:
|
||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==, tarball: https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@@ -5266,6 +5465,10 @@ packages:
|
||||
resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
|
||||
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:
|
||||
resolution: {integrity: sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==}
|
||||
dependencies:
|
||||
@@ -8500,6 +8703,13 @@ packages:
|
||||
/color-name@1.1.4:
|
||||
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:
|
||||
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
|
||||
@@ -8507,6 +8717,14 @@ packages:
|
||||
dev: false
|
||||
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:
|
||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==, tarball: https://registry.npmjs.org/colord/-/colord-2.9.3.tgz}
|
||||
dev: false
|
||||
@@ -8515,6 +8733,15 @@ packages:
|
||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||
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:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, tarball: https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz}
|
||||
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}
|
||||
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:
|
||||
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
|
||||
engines: {node: '>=0.12'}
|
||||
@@ -9201,7 +9434,6 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/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}
|
||||
@@ -10694,6 +10926,15 @@ packages:
|
||||
webpack: 5.95.0
|
||||
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:
|
||||
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -11622,6 +11863,10 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
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:
|
||||
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
@@ -11667,6 +11912,10 @@ packages:
|
||||
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
||||
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:
|
||||
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'}
|
||||
@@ -11702,6 +11951,10 @@ packages:
|
||||
has-tostringtag: 1.0.2
|
||||
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:
|
||||
resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==, tarball: https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz}
|
||||
engines: {node: '>=4'}
|
||||
@@ -13055,6 +13308,28 @@ packages:
|
||||
/natural-compare@1.4.0:
|
||||
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:
|
||||
resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==, tarball: https://registry.npmjs.org/needle/-/needle-3.3.1.tgz}
|
||||
engines: {node: '>= 4.4.x'}
|
||||
@@ -13733,6 +14008,11 @@ packages:
|
||||
- supports-color
|
||||
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:
|
||||
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==, tarball: https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz}
|
||||
dev: false
|
||||
@@ -14143,7 +14423,7 @@ packages:
|
||||
dependencies:
|
||||
htmlparser2: 3.10.1
|
||||
postcss: 7.0.39
|
||||
postcss-syntax: 0.36.2(postcss@7.0.39)
|
||||
postcss-syntax: 0.36.2(postcss@8.4.38)
|
||||
dev: false
|
||||
|
||||
/postcss-image-set-function@4.0.7(postcss@8.4.38):
|
||||
@@ -14617,30 +14897,6 @@ packages:
|
||||
lodash: 4.17.21
|
||||
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):
|
||||
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
|
||||
peerDependencies:
|
||||
@@ -16561,6 +16817,13 @@ packages:
|
||||
util-deprecate: 1.0.2
|
||||
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:
|
||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||
engines: {node: '>=8.10.0'}
|
||||
@@ -17276,6 +17539,36 @@ packages:
|
||||
resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
|
||||
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:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -17357,6 +17650,12 @@ packages:
|
||||
dev: false
|
||||
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:
|
||||
resolution: {integrity: sha512-H5NYU+O+uvqOH5VXw3+lgoc1vTI6jL8LOZJsw4xgRpV7uIPjRpmLPdz0TrouxwKHBhpVLzVIlyKhaRLelIThMw==, tarball: https://registry.npmjs.org/simplebar-core/-/simplebar-core-1.2.6.tgz}
|
||||
dependencies:
|
||||
@@ -17755,6 +18054,14 @@ packages:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
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:
|
||||
resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
|
||||
dev: false
|
||||
@@ -17897,7 +18204,7 @@ packages:
|
||||
postcss-sass: 0.4.4
|
||||
postcss-scss: 2.1.1
|
||||
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
|
||||
resolve-from: 5.0.0
|
||||
slash: 3.0.0
|
||||
@@ -18281,6 +18588,14 @@ packages:
|
||||
engines: {node: '>=0.6'}
|
||||
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:
|
||||
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==, tarball: https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz}
|
||||
engines: {node: '>=6'}
|
||||
@@ -18657,6 +18972,10 @@ packages:
|
||||
vfile: 4.2.1
|
||||
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:
|
||||
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:
|
||||
|
||||
@@ -49,5 +49,11 @@
|
||||
|
||||
.speaker {
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
|
||||
.volume-slider {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { formatTime } from '@/utils/index';
|
||||
import { PauseCircleFilled, PlayCircleFilled } from '@ant-design/icons';
|
||||
import { Button, Slider } from 'antd';
|
||||
import { Button, Slider, Tooltip } from 'antd';
|
||||
import { round } from 'lodash';
|
||||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle
|
||||
} from 'react';
|
||||
import CheckButtons from '../check-buttons';
|
||||
import IconFont from '../icon-font';
|
||||
import './index.less';
|
||||
|
||||
@@ -21,6 +23,13 @@ interface AudioPlayerProps {
|
||||
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 { autoplay = false, speed: defaultSpeed = 1 } = props;
|
||||
const audioRef = React.useRef<HTMLAudioElement>(null);
|
||||
@@ -45,6 +54,14 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
||||
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(() => {
|
||||
timer.current = setInterval(() => {
|
||||
@@ -78,16 +95,22 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
||||
setPlayOn(!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(() => {
|
||||
// set volume
|
||||
audioRef.current!.volume = volume;
|
||||
// set playback rate
|
||||
audioRef.current!.playbackRate = speed;
|
||||
}, []);
|
||||
|
||||
const handleLoadedMetadata = useCallback(
|
||||
(data: any) => {
|
||||
console.log('loadmetadata++++++++');
|
||||
const duration = Math.ceil(audioRef.current?.duration || 0);
|
||||
setAudioState({
|
||||
currentTime: 0,
|
||||
@@ -158,7 +181,23 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
||||
onChange={handleCurrentChange}
|
||||
/>
|
||||
</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>
|
||||
<span className="time">{formatTime(audioState.duration)}</span>
|
||||
</div>
|
||||
@@ -173,6 +212,19 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
||||
></IconFont>
|
||||
}
|
||||
></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>
|
||||
</div>
|
||||
<audio
|
||||
|
||||
@@ -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);
|
||||
@@ -7,7 +7,6 @@ interface SpeechContentProps {
|
||||
}
|
||||
|
||||
const SpeechContent: React.FC<SpeechContentProps> = (props) => {
|
||||
console.log('SpeechContent', props);
|
||||
return (
|
||||
<>
|
||||
{props.dataList.map((item) => (
|
||||
|
||||
@@ -1,11 +1,29 @@
|
||||
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 dayjs from 'dayjs';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import AudioPlayer from './audio-player';
|
||||
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 {
|
||||
prompt: string;
|
||||
@@ -16,12 +34,19 @@ interface SpeechContentProps {
|
||||
audioUrl: string;
|
||||
}
|
||||
const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
console.log('porps=======', props);
|
||||
const intl = useIntl();
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [isPlay, setIsPlay] = useState(false);
|
||||
const ref = useRef<HTMLAudioElement>(null);
|
||||
|
||||
const handlePlay = () => {
|
||||
if (isPlay) {
|
||||
ref.current?.pause();
|
||||
setIsPlay(false);
|
||||
return;
|
||||
}
|
||||
ref.current?.play();
|
||||
setIsPlay(true);
|
||||
};
|
||||
|
||||
const handleCollapse = () => {
|
||||
@@ -30,7 +55,7 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
|
||||
const onDownload = () => {
|
||||
const url = props.audioUrl || '';
|
||||
const filename = Date.now() + '';
|
||||
const filename = `audio-${dayjs().format('YYYYMMDDHHmmss')}.${props.format}`;
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
@@ -45,7 +70,6 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
<div className="speech-item">
|
||||
<div className="voice">
|
||||
<IconFont type="icon-user_voice" className="font-size-16" />
|
||||
{/* <span className="text">{props.voice}</span> */}
|
||||
</div>
|
||||
<div className="wrapper">
|
||||
<AudioPlayer
|
||||
@@ -62,15 +86,25 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
<span className="item">{props.speed}x</span>
|
||||
</span>
|
||||
<div className="actions">
|
||||
<Tooltip title="Play">
|
||||
<Tooltip
|
||||
title={
|
||||
isPlay
|
||||
? intl.formatMessage({ id: 'playground.audio.button.stop' })
|
||||
: intl.formatMessage({ id: 'playground.audio.button.play' })
|
||||
}
|
||||
>
|
||||
<Button
|
||||
onClick={handlePlay}
|
||||
icon={<PlayCircleOutlined />}
|
||||
icon={isPlay ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
|
||||
type="text"
|
||||
size="small"
|
||||
></Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Download">
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'playground.audio.button.download'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
onClick={onDownload}
|
||||
icon={<DownloadOutlined />}
|
||||
@@ -78,21 +112,8 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||
size="small"
|
||||
></Button>
|
||||
</Tooltip>
|
||||
{/* <Tooltip title="Show Prompt">
|
||||
<Button
|
||||
icon={<FileTextOutlined />}
|
||||
type="text"
|
||||
size="small"
|
||||
onClick={handleCollapse}
|
||||
></Button>
|
||||
</Tooltip> */}
|
||||
</div>
|
||||
</div>
|
||||
{/* {collapsed && (
|
||||
<div className="prompt-box">
|
||||
<div className="prompt">{props.prompt}</div>
|
||||
</div>
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,12 +13,11 @@ interface UploadAudioProps {
|
||||
const UploadAudio: React.FC<UploadAudioProps> = (props) => {
|
||||
const intl = useIntl();
|
||||
const beforeUpload = (file: any) => {
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleOnChange = React.useCallback(
|
||||
(data: { file: any; fileList: any }) => {
|
||||
console.log('handleOnChange', data);
|
||||
props.onChange?.(data);
|
||||
},
|
||||
[]
|
||||
|
||||
@@ -88,7 +88,10 @@ export default {
|
||||
'playground.audio.generating.tips': 'Generated text will appear here.',
|
||||
'playground.audio.uploadfile.tips':
|
||||
'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.off': 'Disable',
|
||||
'playground.image.params.sampler': 'Sampler',
|
||||
@@ -96,12 +99,15 @@ export default {
|
||||
'playground.image.params.seed': 'Seed',
|
||||
'playground.image.params.negativePrompt': 'Negative Prompt',
|
||||
'playground.image.params.cfgScale': 'Scale Factor',
|
||||
'playground.image.params.custom': 'Custom',
|
||||
'playground.image.params.custom.tips': 'Parameter definition',
|
||||
'playground.image.params.custom': 'Advanced',
|
||||
'playground.image.params.custom.tips': 'API Style',
|
||||
'playground.image.params.openai': 'OpenAI Compatible',
|
||||
'playground.embedding.handler.tips': 'Resize Height',
|
||||
'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':
|
||||
'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'
|
||||
};
|
||||
|
||||
@@ -86,20 +86,25 @@ export default {
|
||||
'playground.audio.generating.tips': '生成的文本将出现在这里',
|
||||
'playground.audio.uploadfile.tips': '请上传音频文件,支持格式:{formats}',
|
||||
'playground.audio.button.generate': '生成文本',
|
||||
'playground.input.multiplePaste': '多行粘贴',
|
||||
'playground.input.multiplePaste': '批量输入',
|
||||
'playground.input.multiplePaste.tips':
|
||||
'启用后,粘贴的多行文本将自动按换行符分割为表单中的单独条目。',
|
||||
'playground.multiple.on': '开启',
|
||||
'playground.multiple.off': '关闭',
|
||||
'playground.image.params.sampler': '采样器',
|
||||
'playground.image.params.samplerSteps': '采样器步数',
|
||||
'playground.image.params.sampler': '采样方法',
|
||||
'playground.image.params.samplerSteps': '迭代步数',
|
||||
'playground.image.params.seed': '随机种子',
|
||||
'playground.image.params.negativePrompt': '负面提示',
|
||||
'playground.image.params.cfgScale': '缩放因子',
|
||||
'playground.image.params.custom': '自定义',
|
||||
'playground.image.params.custom.tips': '参数定义',
|
||||
'playground.image.params.negativePrompt': '负向提示',
|
||||
'playground.image.params.cfgScale': '提示词引导系数',
|
||||
'playground.image.params.custom': '高级',
|
||||
'playground.image.params.custom.tips': 'API 风格',
|
||||
'playground.image.params.openai': 'OpenAI 兼容',
|
||||
'playground.embedding.handler.tips': '高度调节',
|
||||
'playground.embedding.pcatips1':
|
||||
'采用主成分分析(PCA)对文档向量化后的数据降维,将新数据投射到PCA 空间中。',
|
||||
'PCA(主成分分析)用于降低嵌入向量的维数,使它们更容易可视化。',
|
||||
'playground.embedding.pcatips2':
|
||||
'图表中,点之间的距离表示对应文档之间的相似度。'
|
||||
'在图表中,点之间的距离表示相应文档之间的相似度。点越近意味着相似度越高。',
|
||||
'playground.audio.button.play': '播放',
|
||||
'playground.audio.button.download': '下载',
|
||||
'playground.audio.button.stop': '停止'
|
||||
};
|
||||
|
||||
@@ -450,7 +450,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
}}
|
||||
color="geekblue"
|
||||
>
|
||||
Embedding Only
|
||||
Embedding
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
@@ -464,7 +464,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
}}
|
||||
color="geekblue"
|
||||
>
|
||||
{intl.formatMessage({ id: 'playground.audio.texttospeech' })}
|
||||
Text-To-Speech
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
@@ -478,7 +478,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
}}
|
||||
color="geekblue"
|
||||
>
|
||||
{intl.formatMessage({ id: 'playground.audio.speechtotext' })}
|
||||
Speech-To-Text
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
@@ -492,7 +492,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
}}
|
||||
color="geekblue"
|
||||
>
|
||||
Image Only
|
||||
Image
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -99,25 +99,17 @@ export const textToSpeech = async (params: any, options?: any) => {
|
||||
|
||||
const audioBlob = await res.blob();
|
||||
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) => {
|
||||
return request(AUDIO_SPEECH_TO_TEXT_API, {
|
||||
method: 'POST',
|
||||
data: params.data,
|
||||
cancelToken: options?.cancelToken,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import { AudioOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
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';
|
||||
|
||||
interface AudioInputProps {
|
||||
@@ -9,6 +15,7 @@ interface AudioInputProps {
|
||||
chunks: any[];
|
||||
url: string;
|
||||
name: string;
|
||||
type: string;
|
||||
duration: number;
|
||||
}) => void;
|
||||
onAnalyse?: (analyseData: any, frequencyBinCount: any) => void;
|
||||
@@ -19,6 +26,11 @@ interface AudioInputProps {
|
||||
type?: 'text' | 'primary' | 'default';
|
||||
}
|
||||
|
||||
const recordingFormat = {
|
||||
type: 'audio/wav',
|
||||
suffix: '.wav'
|
||||
};
|
||||
|
||||
const AudioInput: React.FC<AudioInputProps> = (props) => {
|
||||
const intl = useIntl();
|
||||
const [audioOn, setAudioOn] = useState(false);
|
||||
@@ -155,6 +167,8 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
||||
|
||||
try {
|
||||
await EnableAudio();
|
||||
console.log('audioStream:', audioStream.current);
|
||||
|
||||
audioRecorder.current = new MediaRecorder(audioStream.current);
|
||||
|
||||
const audioChunks: any[] = [];
|
||||
@@ -170,14 +184,14 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
||||
|
||||
// stop recording
|
||||
audioRecorder.current.onstop = () => {
|
||||
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
|
||||
const audioBlob = new Blob(audioChunks, { type: recordingFormat.type });
|
||||
const audioUrl = URL.createObjectURL(audioBlob);
|
||||
handleAudioData({
|
||||
chunks: audioBlob,
|
||||
size: audioBlob.size,
|
||||
type: audioBlob.type,
|
||||
url: audioUrl,
|
||||
name: `recording-${new Date().toISOString()}.wav`,
|
||||
name: `recording-${new Date().toISOString()}${recordingFormat.suffix}`,
|
||||
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(() => {
|
||||
return () => {
|
||||
handleStopRecording();
|
||||
@@ -210,13 +243,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
||||
<div className="audio-input">
|
||||
<Space size={40} className="btns">
|
||||
{
|
||||
<Tooltip
|
||||
title={
|
||||
isRecording
|
||||
? intl.formatMessage({ id: 'playground.audio.stoprecord' })
|
||||
: intl.formatMessage({ id: 'playground.audio.startrecord' })
|
||||
}
|
||||
>
|
||||
<Tooltip title={renderRecordButtonTips}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
@@ -231,6 +258,9 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
||||
icon={<AudioOutlined />}
|
||||
size="middle"
|
||||
type={props.type ?? 'text'}
|
||||
style={{
|
||||
...noAudioPermissionButtonStyle
|
||||
}}
|
||||
danger={isRecording}
|
||||
onClick={StartRecording}
|
||||
></Button>
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
SendOutlined
|
||||
} from '@ant-design/icons';
|
||||
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 { PCA } from 'ml-pca';
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
@@ -81,7 +81,7 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
copyValue: ''
|
||||
});
|
||||
const [lessTwoInput, setLessTwoInput] = useState<boolean>(false);
|
||||
const multiplePasteEnable = useRef<boolean>(true);
|
||||
const [multiplePasteEnable, setMultiplePasteEnable] = useState<boolean>(true);
|
||||
|
||||
const [textList, setTextList] = useState<
|
||||
{ text: string; uid: number | string; name: string }[]
|
||||
@@ -279,7 +279,7 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
|
||||
const handleOnPaste = useCallback(
|
||||
(e: any, index: number) => {
|
||||
if (!multiplePasteEnable.current) return;
|
||||
if (!multiplePasteEnable) return;
|
||||
const text = e.clipboardData.getData('text');
|
||||
if (text) {
|
||||
const dataLlist = text.split('\n').map((item: string) => {
|
||||
@@ -402,18 +402,26 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
</div>
|
||||
</h3>
|
||||
<div className="flex-center gap-10">
|
||||
<Button className="flex-center" size="middle">
|
||||
<Checkbox
|
||||
defaultChecked={multiplePasteEnable.current}
|
||||
onChange={(e: any) => {
|
||||
multiplePasteEnable.current = e.target.checked;
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'playground.input.multiplePaste.tips'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
className="flex-center"
|
||||
variant="filled"
|
||||
size="middle"
|
||||
color={multiplePasteEnable ? 'primary' : 'default'}
|
||||
onClick={() => {
|
||||
setMultiplePasteEnable(!multiplePasteEnable);
|
||||
}}
|
||||
>
|
||||
{intl.formatMessage({
|
||||
id: 'playground.input.multiplePaste'
|
||||
})}
|
||||
</Checkbox>
|
||||
</Button>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Button size="middle" onClick={handleAddText}>
|
||||
<PlusOutlined />
|
||||
{intl.formatMessage({ id: 'playground.embedding.addtext' })}
|
||||
|
||||
@@ -47,14 +47,17 @@ interface MessageProps {
|
||||
const initialValues = {
|
||||
n: 1,
|
||||
size: '512x512',
|
||||
quality: 'standard',
|
||||
style: null
|
||||
seed: null,
|
||||
sampler: 'euler_a',
|
||||
cfg_scale: 4.5,
|
||||
sample_steps: 10,
|
||||
negative_prompt: null
|
||||
};
|
||||
|
||||
const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
const { modelList } = props;
|
||||
const messageId = useRef<number>(0);
|
||||
const [isOpenaiCompatible, setIsOpenaiCompatible] = useState<boolean>(true);
|
||||
const [isOpenaiCompatible, setIsOpenaiCompatible] = useState<boolean>(false);
|
||||
const [imageList, setImageList] = useState<
|
||||
{
|
||||
dataUrl: string;
|
||||
@@ -223,7 +226,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
const params = {
|
||||
stream: true,
|
||||
stream_options: {
|
||||
chunk_result: true
|
||||
// chunk_result: false
|
||||
},
|
||||
prompt: current?.content || currentPrompt || '',
|
||||
..._.omitBy(finalParameters, (value: string) => !value)
|
||||
@@ -251,8 +254,6 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
const imgItem = newImageList[item.index];
|
||||
if (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);
|
||||
newImageList[item.index] = {
|
||||
|
||||
@@ -303,7 +303,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
clearAll={handleClear}
|
||||
setModelSelections={handleSelectModel}
|
||||
presetPrompt={handlePresetPrompt}
|
||||
modelList={modelList}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||
import useRequestToken from '@/hooks/use-request-token';
|
||||
import { ClearOutlined, PlusOutlined, SendOutlined } from '@ant-design/icons';
|
||||
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 _ from 'lodash';
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
@@ -77,7 +77,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
const messageListLengthCache = useRef<number>(0);
|
||||
const requestToken = useRef<any>(null);
|
||||
const formRef = useRef<any>(null);
|
||||
const multiplePasteEnable = useRef<boolean>(true);
|
||||
const [multiplePasteEnable, setMultiplePasteEnable] = useState<boolean>(true);
|
||||
const [fileList, setFileList] = useState<
|
||||
{
|
||||
text: string;
|
||||
@@ -346,7 +346,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
|
||||
const handleOnPaste = useCallback(
|
||||
(e: any, index: number) => {
|
||||
if (!multiplePasteEnable.current) return;
|
||||
if (!multiplePasteEnable) return;
|
||||
const text = e.clipboardData.getData('text');
|
||||
if (text) {
|
||||
console.log('text:', text);
|
||||
@@ -465,18 +465,25 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
)}
|
||||
</span>
|
||||
<div className="flex-center gap-10">
|
||||
<Button className="flex-center" size="middle">
|
||||
<Checkbox
|
||||
defaultChecked={multiplePasteEnable.current}
|
||||
onChange={(e: any) => {
|
||||
multiplePasteEnable.current = e.target.checked;
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'playground.input.multiplePaste.tips'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
className="flex-center"
|
||||
variant="filled"
|
||||
size="middle"
|
||||
color={multiplePasteEnable ? 'primary' : 'default'}
|
||||
onClick={() => {
|
||||
setMultiplePasteEnable(!multiplePasteEnable);
|
||||
}}
|
||||
>
|
||||
{intl.formatMessage({
|
||||
id: 'playground.input.multiplePaste'
|
||||
})}
|
||||
</Checkbox>
|
||||
</Button>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Button size="middle" onClick={handleAddText}>
|
||||
<PlusOutlined />
|
||||
{intl.formatMessage({ id: 'playground.embedding.addtext' })}
|
||||
|
||||
@@ -4,9 +4,9 @@ import IconFont from '@/components/icon-font';
|
||||
import UploadAudio from '@/components/upload-audio';
|
||||
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||
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 { Button, Spin, Tag, Tooltip } from 'antd';
|
||||
import { Button, Spin, Tooltip } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
import {
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
} from 'react';
|
||||
import { speechToText } from '../apis';
|
||||
import { RealtimeParamsConfig as paramsConfig } from '../config/params-config';
|
||||
import { MessageItem } from '../config/types';
|
||||
import '../style/ground-left.less';
|
||||
import '../style/speech-to-text.less';
|
||||
import '../style/system-message-wrap.less';
|
||||
@@ -42,14 +41,9 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
const intl = useIntl();
|
||||
const { modelList } = props;
|
||||
const messageId = useRef<number>(0);
|
||||
const [messageList, setMessageList] = useState<MessageItem[]>([
|
||||
{
|
||||
content: '',
|
||||
title: '',
|
||||
role: '',
|
||||
uid: messageId.current
|
||||
}
|
||||
]);
|
||||
const [messageList, setMessageList] = useState<
|
||||
{ uid: number; content: string }[]
|
||||
>([]);
|
||||
const [searchParams] = useSearchParams();
|
||||
const selectModel = searchParams.get('model') || '';
|
||||
const [parameters, setParams] = useState<any>({});
|
||||
@@ -68,7 +62,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
analyser: null
|
||||
});
|
||||
const [isRecording, setIsRecording] = useState(false);
|
||||
const [recordEnd, setRecordEnd] = useState(false);
|
||||
const formRef = useRef<any>(null);
|
||||
|
||||
const { initialize, updateScrollerPosition } = useOverlayScroller();
|
||||
@@ -127,8 +120,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
setMessageList([
|
||||
{
|
||||
content: result.text,
|
||||
title: '',
|
||||
role: '',
|
||||
uid: messageId.current
|
||||
}
|
||||
]);
|
||||
@@ -136,7 +127,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
console.log('error:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setRecordEnd(false);
|
||||
setIsRecording(false);
|
||||
}
|
||||
};
|
||||
@@ -170,9 +160,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
duration: data.duration
|
||||
};
|
||||
});
|
||||
setTimeout(() => {
|
||||
setRecordEnd(true);
|
||||
}, 200);
|
||||
},
|
||||
[]
|
||||
);
|
||||
@@ -183,9 +170,8 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
|
||||
const handleUploadChange = useCallback(
|
||||
async (data: { file: any; fileList: any }) => {
|
||||
const res = await readAudioFile(data.file.originFileObj);
|
||||
const res = await readAudioFile(data.file);
|
||||
setAudioData(res);
|
||||
setRecordEnd(true);
|
||||
},
|
||||
[]
|
||||
);
|
||||
@@ -208,15 +194,16 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
submitMessage();
|
||||
};
|
||||
|
||||
const handleOnDiscard = useCallback(() => {
|
||||
setRecordEnd(false);
|
||||
setAudioData(null);
|
||||
setIsRecording(false);
|
||||
}, []);
|
||||
|
||||
const renderAniamtion = () => {
|
||||
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) {
|
||||
return (
|
||||
@@ -240,7 +227,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
useEffect(() => {
|
||||
console.log('parameters:', parameters);
|
||||
}, [parameters]);
|
||||
useEffect(() => {}, [messageList]);
|
||||
|
||||
useEffect(() => {
|
||||
if (scroller.current) {
|
||||
initialize(scroller.current);
|
||||
@@ -259,13 +246,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
}
|
||||
}, [messageList, loading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (messageList.length > messageListLengthCache.current) {
|
||||
updateScrollerPosition();
|
||||
}
|
||||
messageListLengthCache.current = messageList.length;
|
||||
}, [messageList.length]);
|
||||
|
||||
return (
|
||||
<div className="ground-left-wrapper">
|
||||
<div className="ground-left">
|
||||
@@ -303,42 +283,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
renderAniamtion()
|
||||
)}
|
||||
</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
|
||||
style={{
|
||||
@@ -365,7 +309,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
{audioData ? (
|
||||
{messageList.length ? (
|
||||
messageList[0]?.content
|
||||
) : (
|
||||
<span className="text-tertiary">
|
||||
|
||||
@@ -36,8 +36,7 @@ interface MessageProps {
|
||||
|
||||
const initialValues = {
|
||||
voice: '',
|
||||
response_format: 'mp3',
|
||||
speed: 1
|
||||
response_format: 'mp3'
|
||||
};
|
||||
|
||||
const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
@@ -113,13 +112,13 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
...parameters,
|
||||
input: current?.content || currentPrompt
|
||||
};
|
||||
const audioUrl: any = await textToSpeech({
|
||||
const res: any = await textToSpeech({
|
||||
data: params,
|
||||
url: CHAT_API,
|
||||
signal
|
||||
});
|
||||
|
||||
console.log('result:', parameters, audioUrl);
|
||||
console.log('result:', res);
|
||||
|
||||
setMessageList([
|
||||
{
|
||||
@@ -129,7 +128,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
speed: parameters.speed,
|
||||
uid: messageId.current,
|
||||
autoplay: checkvalueRef.current,
|
||||
audioUrl: audioUrl
|
||||
audioUrl: res.url
|
||||
}
|
||||
]);
|
||||
} catch (error) {
|
||||
|
||||
@@ -229,8 +229,8 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
|
||||
variant="borderless"
|
||||
>
|
||||
<Slider
|
||||
defaultValue={1024}
|
||||
max={2048}
|
||||
defaultValue={2048}
|
||||
max={16 * 1024}
|
||||
step={1}
|
||||
style={{ marginBottom: 0, marginTop: 16, marginInline: 0 }}
|
||||
tooltip={{ open: false }}
|
||||
|
||||
@@ -28,11 +28,11 @@ export const TTSParamsConfig: ParamsSchema[] = [
|
||||
name: 'response_format',
|
||||
options: [
|
||||
{ label: 'mp3', value: 'mp3' },
|
||||
{ label: 'opus', value: 'opus' },
|
||||
{ label: 'aac', value: 'aac' },
|
||||
{ label: 'flac', value: 'flac' },
|
||||
{ label: 'wav', value: 'wav' },
|
||||
{ label: 'pcm', value: 'pcm' }
|
||||
// { label: 'opus', value: 'opus' },
|
||||
// { label: 'aac', value: 'aac' },
|
||||
// { label: 'flac', value: 'flac' },
|
||||
{ label: 'wav', value: 'wav' }
|
||||
// { label: 'pcm', value: 'pcm' }
|
||||
],
|
||||
label: {
|
||||
text: 'playground.params.format',
|
||||
@@ -43,27 +43,27 @@ export const TTSParamsConfig: ParamsSchema[] = [
|
||||
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[] = [
|
||||
|
||||
@@ -86,45 +86,62 @@ export const readStreamData = async (
|
||||
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 (
|
||||
reader: any,
|
||||
decoder: TextDecoder,
|
||||
callback: (data: any) => void
|
||||
) => {
|
||||
let buffer = '';
|
||||
let buffer = ''; // cache incomplete line
|
||||
|
||||
const processStream = async () => {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
if (buffer) {
|
||||
try {
|
||||
extractJSON(buffer).forEach((data) => {
|
||||
callback?.(data);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('parse buffer failed:', buffer);
|
||||
}
|
||||
// Process remaining buffered data
|
||||
if (buffer.trim()) {
|
||||
processBuffer(buffer, callback);
|
||||
}
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
// cache each chunk
|
||||
// Decode new chunk of data and append to buffer
|
||||
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) => {
|
||||
callback?.(data);
|
||||
});
|
||||
|
||||
const lastIndex = buffer.lastIndexOf('}');
|
||||
buffer = lastIndex !== -1 ? buffer.slice(lastIndex + 1) : buffer;
|
||||
|
||||
// next chunk
|
||||
await processStream();
|
||||
};
|
||||
|
||||
await processStream();
|
||||
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:', jsonStr, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const readTextEventStreamData = async (
|
||||
|
||||
@@ -32,6 +32,7 @@ export const loadAudioData = async (data: any, type: string) => {
|
||||
};
|
||||
|
||||
export const readAudioFile = async (file: File) => {
|
||||
console.log('file====', file);
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = async function (e: any) {
|
||||
|
||||
Reference in New Issue
Block a user