Spaces:
Runtime error
Runtime error
matt HOFFNER
commited on
Commit
Β·
22ff301
1
Parent(s):
ed45bdf
cleanup
Browse files- package-lock.json +183 -0
- package.json +1 -0
- src/components/Chat/Chat.tsx +0 -355
- src/components/Chat/ChatInput.tsx +0 -251
- src/components/Chat/ChatLoader.tsx +0 -20
- src/components/ChatWindow.jsx +2 -2
- src/components/Loader.jsx +6 -1
- src/components/MessageList.jsx +3 -2
- src/pages/api/home.context.tsx +0 -23
- src/pages/api/home.state.tsx +0 -42
- src/pages/api/home.tsx +0 -157
- src/utils/file-handler.ts +2 -2
- src/utils/index.ts +0 -30
package-lock.json
CHANGED
@@ -22,6 +22,7 @@
|
|
22 |
"next": "13.4.2",
|
23 |
"react": "18.2.0",
|
24 |
"react-dom": "18.2.0",
|
|
|
25 |
"typescript": "5.0.4",
|
26 |
"uuid": "^9.0.0"
|
27 |
},
|
@@ -137,6 +138,18 @@
|
|
137 |
"node": ">=6.9.0"
|
138 |
}
|
139 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
"node_modules/@babel/helper-compilation-targets": {
|
141 |
"version": "7.22.1",
|
142 |
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz",
|
@@ -478,6 +491,33 @@
|
|
478 |
"node": ">=6.9.0"
|
479 |
}
|
480 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
481 |
"node_modules/@esbuild/android-arm": {
|
482 |
"version": "0.17.19",
|
483 |
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
|
@@ -1777,6 +1817,28 @@
|
|
1777 |
"deep-equal": "^2.0.5"
|
1778 |
}
|
1779 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1780 |
"node_modules/balanced-match": {
|
1781 |
"version": "1.0.2",
|
1782 |
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
@@ -1962,6 +2024,15 @@
|
|
1962 |
"node": ">=6"
|
1963 |
}
|
1964 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1965 |
"node_modules/caniuse-lite": {
|
1966 |
"version": "1.0.30001492",
|
1967 |
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001492.tgz",
|
@@ -2096,6 +2167,26 @@
|
|
2096 |
"node": ">= 8"
|
2097 |
}
|
2098 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2099 |
"node_modules/csstype": {
|
2100 |
"version": "3.1.2",
|
2101 |
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
@@ -3468,6 +3559,15 @@
|
|
3468 |
"url": "https://github.com/sponsors/ljharb"
|
3469 |
}
|
3470 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3471 |
"node_modules/human-signals": {
|
3472 |
"version": "4.3.1",
|
3473 |
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
|
@@ -4304,6 +4404,12 @@
|
|
4304 |
"url": "https://github.com/sponsors/sindresorhus"
|
4305 |
}
|
4306 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
4307 |
"node_modules/lodash.merge": {
|
4308 |
"version": "4.6.2",
|
4309 |
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
@@ -5282,6 +5388,26 @@
|
|
5282 |
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
5283 |
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
5284 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5285 |
"node_modules/readable-stream": {
|
5286 |
"version": "3.6.2",
|
5287 |
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
@@ -5628,6 +5754,12 @@
|
|
5628 |
"node": ">=10"
|
5629 |
}
|
5630 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
5631 |
"node_modules/sharp": {
|
5632 |
"version": "0.32.1",
|
5633 |
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.1.tgz",
|
@@ -5888,6 +6020,57 @@
|
|
5888 |
"url": "https://github.com/sponsors/sindresorhus"
|
5889 |
}
|
5890 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5891 |
"node_modules/styled-jsx": {
|
5892 |
"version": "5.1.1",
|
5893 |
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
|
|
|
22 |
"next": "13.4.2",
|
23 |
"react": "18.2.0",
|
24 |
"react-dom": "18.2.0",
|
25 |
+
"react95": "^4.0.0",
|
26 |
"typescript": "5.0.4",
|
27 |
"uuid": "^9.0.0"
|
28 |
},
|
|
|
138 |
"node": ">=6.9.0"
|
139 |
}
|
140 |
},
|
141 |
+
"node_modules/@babel/helper-annotate-as-pure": {
|
142 |
+
"version": "7.18.6",
|
143 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
|
144 |
+
"integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
|
145 |
+
"peer": true,
|
146 |
+
"dependencies": {
|
147 |
+
"@babel/types": "^7.18.6"
|
148 |
+
},
|
149 |
+
"engines": {
|
150 |
+
"node": ">=6.9.0"
|
151 |
+
}
|
152 |
+
},
|
153 |
"node_modules/@babel/helper-compilation-targets": {
|
154 |
"version": "7.22.1",
|
155 |
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz",
|
|
|
491 |
"node": ">=6.9.0"
|
492 |
}
|
493 |
},
|
494 |
+
"node_modules/@emotion/is-prop-valid": {
|
495 |
+
"version": "1.2.1",
|
496 |
+
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
|
497 |
+
"integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==",
|
498 |
+
"peer": true,
|
499 |
+
"dependencies": {
|
500 |
+
"@emotion/memoize": "^0.8.1"
|
501 |
+
}
|
502 |
+
},
|
503 |
+
"node_modules/@emotion/memoize": {
|
504 |
+
"version": "0.8.1",
|
505 |
+
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
506 |
+
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==",
|
507 |
+
"peer": true
|
508 |
+
},
|
509 |
+
"node_modules/@emotion/stylis": {
|
510 |
+
"version": "0.8.5",
|
511 |
+
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
|
512 |
+
"integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==",
|
513 |
+
"peer": true
|
514 |
+
},
|
515 |
+
"node_modules/@emotion/unitless": {
|
516 |
+
"version": "0.7.5",
|
517 |
+
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
|
518 |
+
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
|
519 |
+
"peer": true
|
520 |
+
},
|
521 |
"node_modules/@esbuild/android-arm": {
|
522 |
"version": "0.17.19",
|
523 |
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
|
|
|
1817 |
"deep-equal": "^2.0.5"
|
1818 |
}
|
1819 |
},
|
1820 |
+
"node_modules/babel-plugin-styled-components": {
|
1821 |
+
"version": "2.1.3",
|
1822 |
+
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.3.tgz",
|
1823 |
+
"integrity": "sha512-jBioLwBVHpOMU4NsueH/ADcHrjS0Y/WTpt2eGVmmuSFNEv2DF3XhcMncuZlbbjxQ4vzxg+yEr6E6TNjrIQbsJQ==",
|
1824 |
+
"peer": true,
|
1825 |
+
"dependencies": {
|
1826 |
+
"@babel/helper-annotate-as-pure": "^7.18.6",
|
1827 |
+
"@babel/helper-module-imports": "^7.21.4",
|
1828 |
+
"babel-plugin-syntax-jsx": "^6.18.0",
|
1829 |
+
"lodash": "^4.17.21",
|
1830 |
+
"picomatch": "^2.3.1"
|
1831 |
+
},
|
1832 |
+
"peerDependencies": {
|
1833 |
+
"styled-components": ">= 2"
|
1834 |
+
}
|
1835 |
+
},
|
1836 |
+
"node_modules/babel-plugin-syntax-jsx": {
|
1837 |
+
"version": "6.18.0",
|
1838 |
+
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
|
1839 |
+
"integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==",
|
1840 |
+
"peer": true
|
1841 |
+
},
|
1842 |
"node_modules/balanced-match": {
|
1843 |
"version": "1.0.2",
|
1844 |
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
|
|
2024 |
"node": ">=6"
|
2025 |
}
|
2026 |
},
|
2027 |
+
"node_modules/camelize": {
|
2028 |
+
"version": "1.0.1",
|
2029 |
+
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
|
2030 |
+
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
|
2031 |
+
"peer": true,
|
2032 |
+
"funding": {
|
2033 |
+
"url": "https://github.com/sponsors/ljharb"
|
2034 |
+
}
|
2035 |
+
},
|
2036 |
"node_modules/caniuse-lite": {
|
2037 |
"version": "1.0.30001492",
|
2038 |
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001492.tgz",
|
|
|
2167 |
"node": ">= 8"
|
2168 |
}
|
2169 |
},
|
2170 |
+
"node_modules/css-color-keywords": {
|
2171 |
+
"version": "1.0.0",
|
2172 |
+
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
|
2173 |
+
"integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
|
2174 |
+
"peer": true,
|
2175 |
+
"engines": {
|
2176 |
+
"node": ">=4"
|
2177 |
+
}
|
2178 |
+
},
|
2179 |
+
"node_modules/css-to-react-native": {
|
2180 |
+
"version": "3.2.0",
|
2181 |
+
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
|
2182 |
+
"integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
|
2183 |
+
"peer": true,
|
2184 |
+
"dependencies": {
|
2185 |
+
"camelize": "^1.0.0",
|
2186 |
+
"css-color-keywords": "^1.0.0",
|
2187 |
+
"postcss-value-parser": "^4.0.2"
|
2188 |
+
}
|
2189 |
+
},
|
2190 |
"node_modules/csstype": {
|
2191 |
"version": "3.1.2",
|
2192 |
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
|
|
3559 |
"url": "https://github.com/sponsors/ljharb"
|
3560 |
}
|
3561 |
},
|
3562 |
+
"node_modules/hoist-non-react-statics": {
|
3563 |
+
"version": "3.3.2",
|
3564 |
+
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
3565 |
+
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
3566 |
+
"peer": true,
|
3567 |
+
"dependencies": {
|
3568 |
+
"react-is": "^16.7.0"
|
3569 |
+
}
|
3570 |
+
},
|
3571 |
"node_modules/human-signals": {
|
3572 |
"version": "4.3.1",
|
3573 |
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
|
|
|
4404 |
"url": "https://github.com/sponsors/sindresorhus"
|
4405 |
}
|
4406 |
},
|
4407 |
+
"node_modules/lodash": {
|
4408 |
+
"version": "4.17.21",
|
4409 |
+
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
4410 |
+
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
4411 |
+
"peer": true
|
4412 |
+
},
|
4413 |
"node_modules/lodash.merge": {
|
4414 |
"version": "4.6.2",
|
4415 |
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
|
|
5388 |
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
5389 |
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
5390 |
},
|
5391 |
+
"node_modules/react95": {
|
5392 |
+
"version": "4.0.0",
|
5393 |
+
"resolved": "https://registry.npmjs.org/react95/-/react95-4.0.0.tgz",
|
5394 |
+
"integrity": "sha512-C/2Ecws+ShHMJa3/ki6d3ufCukEYyZ+up45NJhX+uecFh5sXNdkEX8bPZ4pKTGl0mSTMkiCJTGOJB1Gmf1W3dA==",
|
5395 |
+
"funding": [
|
5396 |
+
{
|
5397 |
+
"type": "paypal",
|
5398 |
+
"url": "https://www.paypal.me/react95"
|
5399 |
+
},
|
5400 |
+
{
|
5401 |
+
"type": "patreon",
|
5402 |
+
"url": "https://www.patreon.com/arturbien"
|
5403 |
+
}
|
5404 |
+
],
|
5405 |
+
"peerDependencies": {
|
5406 |
+
"react": ">= 16.8.0",
|
5407 |
+
"react-dom": ">= 16.8.0",
|
5408 |
+
"styled-components": ">= 5.3.3"
|
5409 |
+
}
|
5410 |
+
},
|
5411 |
"node_modules/readable-stream": {
|
5412 |
"version": "3.6.2",
|
5413 |
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
|
|
5754 |
"node": ">=10"
|
5755 |
}
|
5756 |
},
|
5757 |
+
"node_modules/shallowequal": {
|
5758 |
+
"version": "1.1.0",
|
5759 |
+
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
|
5760 |
+
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
|
5761 |
+
"peer": true
|
5762 |
+
},
|
5763 |
"node_modules/sharp": {
|
5764 |
"version": "0.32.1",
|
5765 |
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.1.tgz",
|
|
|
6020 |
"url": "https://github.com/sponsors/sindresorhus"
|
6021 |
}
|
6022 |
},
|
6023 |
+
"node_modules/styled-components": {
|
6024 |
+
"version": "5.3.11",
|
6025 |
+
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz",
|
6026 |
+
"integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==",
|
6027 |
+
"peer": true,
|
6028 |
+
"dependencies": {
|
6029 |
+
"@babel/helper-module-imports": "^7.0.0",
|
6030 |
+
"@babel/traverse": "^7.4.5",
|
6031 |
+
"@emotion/is-prop-valid": "^1.1.0",
|
6032 |
+
"@emotion/stylis": "^0.8.4",
|
6033 |
+
"@emotion/unitless": "^0.7.4",
|
6034 |
+
"babel-plugin-styled-components": ">= 1.12.0",
|
6035 |
+
"css-to-react-native": "^3.0.0",
|
6036 |
+
"hoist-non-react-statics": "^3.0.0",
|
6037 |
+
"shallowequal": "^1.1.0",
|
6038 |
+
"supports-color": "^5.5.0"
|
6039 |
+
},
|
6040 |
+
"engines": {
|
6041 |
+
"node": ">=10"
|
6042 |
+
},
|
6043 |
+
"funding": {
|
6044 |
+
"type": "opencollective",
|
6045 |
+
"url": "https://opencollective.com/styled-components"
|
6046 |
+
},
|
6047 |
+
"peerDependencies": {
|
6048 |
+
"react": ">= 16.8.0",
|
6049 |
+
"react-dom": ">= 16.8.0",
|
6050 |
+
"react-is": ">= 16.8.0"
|
6051 |
+
}
|
6052 |
+
},
|
6053 |
+
"node_modules/styled-components/node_modules/has-flag": {
|
6054 |
+
"version": "3.0.0",
|
6055 |
+
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
6056 |
+
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
6057 |
+
"peer": true,
|
6058 |
+
"engines": {
|
6059 |
+
"node": ">=4"
|
6060 |
+
}
|
6061 |
+
},
|
6062 |
+
"node_modules/styled-components/node_modules/supports-color": {
|
6063 |
+
"version": "5.5.0",
|
6064 |
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
6065 |
+
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
6066 |
+
"peer": true,
|
6067 |
+
"dependencies": {
|
6068 |
+
"has-flag": "^3.0.0"
|
6069 |
+
},
|
6070 |
+
"engines": {
|
6071 |
+
"node": ">=4"
|
6072 |
+
}
|
6073 |
+
},
|
6074 |
"node_modules/styled-jsx": {
|
6075 |
"version": "5.1.1",
|
6076 |
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
|
package.json
CHANGED
@@ -22,6 +22,7 @@
|
|
22 |
"next": "13.4.2",
|
23 |
"react": "18.2.0",
|
24 |
"react-dom": "18.2.0",
|
|
|
25 |
"typescript": "5.0.4",
|
26 |
"uuid": "^9.0.0"
|
27 |
},
|
|
|
22 |
"next": "13.4.2",
|
23 |
"react": "18.2.0",
|
24 |
"react-dom": "18.2.0",
|
25 |
+
"react95": "^4.0.0",
|
26 |
"typescript": "5.0.4",
|
27 |
"uuid": "^9.0.0"
|
28 |
},
|
src/components/Chat/Chat.tsx
DELETED
@@ -1,355 +0,0 @@
|
|
1 |
-
import { IconClearAll, IconSettings } from '@tabler/icons-react';
|
2 |
-
import {
|
3 |
-
MutableRefObject,
|
4 |
-
memo,
|
5 |
-
useCallback,
|
6 |
-
useContext,
|
7 |
-
useEffect,
|
8 |
-
useRef,
|
9 |
-
useState,
|
10 |
-
} from 'react';
|
11 |
-
|
12 |
-
import {
|
13 |
-
saveConversation,
|
14 |
-
saveConversations,
|
15 |
-
updateConversation,
|
16 |
-
throttle
|
17 |
-
} from '@/utils';
|
18 |
-
|
19 |
-
import { ChatBody, Conversation, Message } from '@/types/chat';
|
20 |
-
|
21 |
-
import HomeContext from '@/pages/api/home.context';
|
22 |
-
|
23 |
-
import { ChatInput } from './ChatInput';
|
24 |
-
import { ChatLoader } from './ChatLoader';
|
25 |
-
|
26 |
-
interface Props {
|
27 |
-
stopConversationRef: MutableRefObject<boolean>;
|
28 |
-
}
|
29 |
-
|
30 |
-
export const Chat = memo(({ stopConversationRef }: Props) => {
|
31 |
-
const {
|
32 |
-
state: {
|
33 |
-
selectedConversation,
|
34 |
-
conversations,
|
35 |
-
loading
|
36 |
-
},
|
37 |
-
handleUpdateConversation,
|
38 |
-
dispatch: homeDispatch,
|
39 |
-
}: any = useContext(HomeContext);
|
40 |
-
|
41 |
-
const [currentMessage, setCurrentMessage] = useState<Message>();
|
42 |
-
const [autoScrollEnabled, setAutoScrollEnabled] = useState<boolean>(true);
|
43 |
-
const [showSettings, setShowSettings] = useState<boolean>(false);
|
44 |
-
const [showScrollDownButton, setShowScrollDownButton] =
|
45 |
-
useState<boolean>(false);
|
46 |
-
|
47 |
-
const messagesEndRef = useRef<HTMLDivElement>(null);
|
48 |
-
const chatContainerRef = useRef<HTMLDivElement>(null);
|
49 |
-
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
50 |
-
|
51 |
-
const handleSend = useCallback(
|
52 |
-
async (message: Message, deleteCount = 0, plugin: Plugin | null = null) => {
|
53 |
-
if (selectedConversation) {
|
54 |
-
let updatedConversation: Conversation;
|
55 |
-
if (deleteCount) {
|
56 |
-
const updatedMessages = [...selectedConversation.messages];
|
57 |
-
for (let i = 0; i < deleteCount; i++) {
|
58 |
-
updatedMessages.pop();
|
59 |
-
}
|
60 |
-
updatedConversation = {
|
61 |
-
...selectedConversation,
|
62 |
-
messages: [...updatedMessages, message],
|
63 |
-
};
|
64 |
-
} else {
|
65 |
-
updatedConversation = {
|
66 |
-
...selectedConversation,
|
67 |
-
messages: [...selectedConversation.messages, message],
|
68 |
-
};
|
69 |
-
}
|
70 |
-
homeDispatch({
|
71 |
-
field: 'selectedConversation',
|
72 |
-
value: updatedConversation,
|
73 |
-
});
|
74 |
-
homeDispatch({ field: 'loading', value: true });
|
75 |
-
homeDispatch({ field: 'messageIsStreaming', value: true });
|
76 |
-
const chatBody: ChatBody = {
|
77 |
-
model: updatedConversation.model,
|
78 |
-
messages: updatedConversation.messages,
|
79 |
-
prompt: updatedConversation.prompt
|
80 |
-
};
|
81 |
-
const endpoint = "/v1/api/create"
|
82 |
-
const body = JSON.stringify(chatBody);
|
83 |
-
const controller = new AbortController();
|
84 |
-
const response = await fetch(endpoint, {
|
85 |
-
method: 'POST',
|
86 |
-
headers: {
|
87 |
-
'Content-Type': 'application/json',
|
88 |
-
},
|
89 |
-
signal: controller.signal,
|
90 |
-
body,
|
91 |
-
});
|
92 |
-
if (!response.ok) {
|
93 |
-
homeDispatch({ field: 'loading', value: false });
|
94 |
-
homeDispatch({ field: 'messageIsStreaming', value: false });
|
95 |
-
console.error(response.statusText);
|
96 |
-
return;
|
97 |
-
}
|
98 |
-
const data = response.body;
|
99 |
-
if (!data) {
|
100 |
-
homeDispatch({ field: 'loading', value: false });
|
101 |
-
homeDispatch({ field: 'messageIsStreaming', value: false });
|
102 |
-
return;
|
103 |
-
}
|
104 |
-
if (!plugin) {
|
105 |
-
if (updatedConversation.messages.length === 1) {
|
106 |
-
const { content } = message;
|
107 |
-
const customName =
|
108 |
-
content.length > 30 ? content.substring(0, 30) + '...' : content;
|
109 |
-
updatedConversation = {
|
110 |
-
...updatedConversation,
|
111 |
-
name: customName,
|
112 |
-
};
|
113 |
-
}
|
114 |
-
homeDispatch({ field: 'loading', value: false });
|
115 |
-
const reader = data.getReader();
|
116 |
-
const decoder = new TextDecoder();
|
117 |
-
let done = false;
|
118 |
-
let isFirst = true;
|
119 |
-
let text = '';
|
120 |
-
while (!done) {
|
121 |
-
if (stopConversationRef.current === true) {
|
122 |
-
controller.abort();
|
123 |
-
done = true;
|
124 |
-
break;
|
125 |
-
}
|
126 |
-
const { value, done: doneReading } = await reader.read();
|
127 |
-
done = doneReading;
|
128 |
-
const chunkValue = decoder.decode(value);
|
129 |
-
text += chunkValue;
|
130 |
-
if (isFirst) {
|
131 |
-
isFirst = false;
|
132 |
-
const updatedMessages: Message[] = [
|
133 |
-
...updatedConversation.messages,
|
134 |
-
{ role: 'assistant', content: chunkValue },
|
135 |
-
];
|
136 |
-
updatedConversation = {
|
137 |
-
...updatedConversation,
|
138 |
-
messages: updatedMessages,
|
139 |
-
};
|
140 |
-
homeDispatch({
|
141 |
-
field: 'selectedConversation',
|
142 |
-
value: updatedConversation,
|
143 |
-
});
|
144 |
-
} else {
|
145 |
-
const updatedMessages: Message[] =
|
146 |
-
updatedConversation.messages.map((message: any, index: number) => {
|
147 |
-
if (index === updatedConversation.messages.length - 1) {
|
148 |
-
return {
|
149 |
-
...message,
|
150 |
-
content: text,
|
151 |
-
};
|
152 |
-
}
|
153 |
-
return message;
|
154 |
-
});
|
155 |
-
updatedConversation = {
|
156 |
-
...updatedConversation,
|
157 |
-
messages: updatedMessages,
|
158 |
-
};
|
159 |
-
homeDispatch({
|
160 |
-
field: 'selectedConversation',
|
161 |
-
value: updatedConversation,
|
162 |
-
});
|
163 |
-
}
|
164 |
-
}
|
165 |
-
saveConversation(updatedConversation);
|
166 |
-
const updatedConversations: Conversation[] = conversations.map(
|
167 |
-
(conversation: { id: any; }) => {
|
168 |
-
if (conversation.id === selectedConversation.id) {
|
169 |
-
return updatedConversation;
|
170 |
-
}
|
171 |
-
return conversation;
|
172 |
-
},
|
173 |
-
);
|
174 |
-
if (updatedConversations.length === 0) {
|
175 |
-
updatedConversations.push(updatedConversation);
|
176 |
-
}
|
177 |
-
homeDispatch({ field: 'conversations', value: updatedConversations });
|
178 |
-
saveConversations(updatedConversations);
|
179 |
-
homeDispatch({ field: 'messageIsStreaming', value: false });
|
180 |
-
} else {
|
181 |
-
const { answer } = await response.json();
|
182 |
-
const updatedMessages: Message[] = [
|
183 |
-
...updatedConversation.messages,
|
184 |
-
{ role: 'assistant', content: answer },
|
185 |
-
];
|
186 |
-
updatedConversation = {
|
187 |
-
...updatedConversation,
|
188 |
-
messages: updatedMessages,
|
189 |
-
};
|
190 |
-
homeDispatch({
|
191 |
-
field: 'selectedConversation',
|
192 |
-
value: updateConversation,
|
193 |
-
});
|
194 |
-
saveConversation(updatedConversation);
|
195 |
-
const updatedConversations: Conversation[] = conversations.map(
|
196 |
-
(conversation: { id: any; }) => {
|
197 |
-
if (conversation.id === selectedConversation.id) {
|
198 |
-
return updatedConversation;
|
199 |
-
}
|
200 |
-
return conversation;
|
201 |
-
},
|
202 |
-
);
|
203 |
-
if (updatedConversations.length === 0) {
|
204 |
-
updatedConversations.push(updatedConversation);
|
205 |
-
}
|
206 |
-
homeDispatch({ field: 'conversations', value: updatedConversations });
|
207 |
-
saveConversations(updatedConversations);
|
208 |
-
homeDispatch({ field: 'loading', value: false });
|
209 |
-
homeDispatch({ field: 'messageIsStreaming', value: false });
|
210 |
-
}
|
211 |
-
}
|
212 |
-
},
|
213 |
-
[
|
214 |
-
conversations,
|
215 |
-
selectedConversation,
|
216 |
-
stopConversationRef,
|
217 |
-
],
|
218 |
-
);
|
219 |
-
|
220 |
-
const handleScroll = () => {
|
221 |
-
if (chatContainerRef.current) {
|
222 |
-
const { scrollTop, scrollHeight, clientHeight } =
|
223 |
-
chatContainerRef.current;
|
224 |
-
const bottomTolerance = 30;
|
225 |
-
|
226 |
-
if (scrollTop + clientHeight < scrollHeight - bottomTolerance) {
|
227 |
-
setAutoScrollEnabled(false);
|
228 |
-
setShowScrollDownButton(true);
|
229 |
-
} else {
|
230 |
-
setAutoScrollEnabled(true);
|
231 |
-
setShowScrollDownButton(false);
|
232 |
-
}
|
233 |
-
}
|
234 |
-
};
|
235 |
-
|
236 |
-
const handleScrollDown = () => {
|
237 |
-
chatContainerRef.current?.scrollTo({
|
238 |
-
top: chatContainerRef.current.scrollHeight,
|
239 |
-
behavior: 'smooth',
|
240 |
-
});
|
241 |
-
};
|
242 |
-
|
243 |
-
const handleSettings = () => {
|
244 |
-
setShowSettings(!showSettings);
|
245 |
-
};
|
246 |
-
|
247 |
-
const onClearAll = () => {
|
248 |
-
if (
|
249 |
-
confirm('Are you sure you want to clear all messages?') &&
|
250 |
-
selectedConversation
|
251 |
-
) {
|
252 |
-
handleUpdateConversation(selectedConversation, {
|
253 |
-
key: 'messages',
|
254 |
-
value: [],
|
255 |
-
});
|
256 |
-
}
|
257 |
-
};
|
258 |
-
|
259 |
-
const scrollDown = () => {
|
260 |
-
if (autoScrollEnabled) {
|
261 |
-
messagesEndRef.current?.scrollIntoView(true);
|
262 |
-
}
|
263 |
-
};
|
264 |
-
const throttledScrollDown = throttle(scrollDown, 250);
|
265 |
-
|
266 |
-
useEffect(() => {
|
267 |
-
throttledScrollDown();
|
268 |
-
selectedConversation &&
|
269 |
-
setCurrentMessage(
|
270 |
-
selectedConversation.messages[selectedConversation.messages.length - 2],
|
271 |
-
);
|
272 |
-
}, [selectedConversation, throttledScrollDown]);
|
273 |
-
|
274 |
-
useEffect(() => {
|
275 |
-
const observer = new IntersectionObserver(
|
276 |
-
([entry]) => {
|
277 |
-
setAutoScrollEnabled(entry.isIntersecting);
|
278 |
-
if (entry.isIntersecting) {
|
279 |
-
textareaRef.current?.focus();
|
280 |
-
}
|
281 |
-
},
|
282 |
-
{
|
283 |
-
root: null,
|
284 |
-
threshold: 0.5,
|
285 |
-
},
|
286 |
-
);
|
287 |
-
const messagesEndElement = messagesEndRef.current;
|
288 |
-
if (messagesEndElement) {
|
289 |
-
observer.observe(messagesEndElement);
|
290 |
-
}
|
291 |
-
return () => {
|
292 |
-
if (messagesEndElement) {
|
293 |
-
observer.unobserve(messagesEndElement);
|
294 |
-
}
|
295 |
-
};
|
296 |
-
}, [messagesEndRef]);
|
297 |
-
|
298 |
-
return (
|
299 |
-
<div className="relative flex-1 overflow-hidden bg-white dark:bg-[#343541]">
|
300 |
-
<div
|
301 |
-
className="max-h-full overflow-x-hidden"
|
302 |
-
ref={chatContainerRef}
|
303 |
-
onScroll={handleScroll}
|
304 |
-
>
|
305 |
-
{selectedConversation?.messages.length === 0 ? (
|
306 |
-
<>
|
307 |
-
<div className="mx-auto flex flex-col space-y-5 md:space-y-10 px-3 pt-5 md:pt-12 sm:max-w-[600px]">
|
308 |
-
|
309 |
-
|
310 |
-
</div>
|
311 |
-
</>
|
312 |
-
) : (
|
313 |
-
<>
|
314 |
-
<div className="sticky top-0 z-10 flex justify-center border border-b-neutral-300 bg-neutral-100 py-2 text-sm text-neutral-500 dark:border-none dark:bg-[#444654] dark:text-neutral-200">
|
315 |
-
<button
|
316 |
-
className="ml-2 cursor-pointer hover:opacity-50"
|
317 |
-
onClick={handleSettings}
|
318 |
-
>
|
319 |
-
<IconSettings size={18} />
|
320 |
-
</button>
|
321 |
-
<button
|
322 |
-
className="ml-2 cursor-pointer hover:opacity-50"
|
323 |
-
onClick={onClearAll}
|
324 |
-
>
|
325 |
-
<IconClearAll size={18} />
|
326 |
-
</button>
|
327 |
-
</div>
|
328 |
-
{loading && <ChatLoader />}
|
329 |
-
<div
|
330 |
-
className="h-[162px] bg-white dark:bg-[#343541]"
|
331 |
-
ref={messagesEndRef}
|
332 |
-
/>
|
333 |
-
</>
|
334 |
-
)}
|
335 |
-
</div>
|
336 |
-
|
337 |
-
<ChatInput
|
338 |
-
stopConversationRef={stopConversationRef}
|
339 |
-
textareaRef={textareaRef}
|
340 |
-
onSend={(message: any) => {
|
341 |
-
setCurrentMessage(message);
|
342 |
-
handleSend(message, 0);
|
343 |
-
}}
|
344 |
-
onScrollDownClick={handleScrollDown}
|
345 |
-
onRegenerate={() => {
|
346 |
-
if (currentMessage) {
|
347 |
-
handleSend(currentMessage, 2, null);
|
348 |
-
}
|
349 |
-
}}
|
350 |
-
showScrollDownButton={showScrollDownButton}
|
351 |
-
/>
|
352 |
-
</div>
|
353 |
-
);
|
354 |
-
});
|
355 |
-
Chat.displayName = 'Chat';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/Chat/ChatInput.tsx
DELETED
@@ -1,251 +0,0 @@
|
|
1 |
-
import {
|
2 |
-
IconPlayerStop,
|
3 |
-
IconRepeat,
|
4 |
-
IconSend,
|
5 |
-
} from '@tabler/icons-react';
|
6 |
-
import {
|
7 |
-
KeyboardEvent,
|
8 |
-
MutableRefObject,
|
9 |
-
useCallback,
|
10 |
-
useContext,
|
11 |
-
useEffect,
|
12 |
-
useRef,
|
13 |
-
useState,
|
14 |
-
} from 'react';
|
15 |
-
|
16 |
-
import { Message } from '@/types/chat';
|
17 |
-
import { Prompt } from '@/types/prompt';
|
18 |
-
|
19 |
-
import HomeContext from '@/pages/api/home.context';
|
20 |
-
|
21 |
-
interface Props {
|
22 |
-
onSend: (message: Message) => void;
|
23 |
-
onRegenerate: () => void;
|
24 |
-
onScrollDownClick: () => void;
|
25 |
-
stopConversationRef: MutableRefObject<boolean>;
|
26 |
-
textareaRef: MutableRefObject<HTMLTextAreaElement | null>;
|
27 |
-
showScrollDownButton: boolean;
|
28 |
-
}
|
29 |
-
|
30 |
-
export const ChatInput = ({
|
31 |
-
onSend,
|
32 |
-
onRegenerate,
|
33 |
-
stopConversationRef,
|
34 |
-
textareaRef,
|
35 |
-
}: Props) => {
|
36 |
-
|
37 |
-
const {
|
38 |
-
state: { selectedConversation, messageIsStreaming, prompts },
|
39 |
-
|
40 |
-
dispatch: homeDispatch,
|
41 |
-
}: any = useContext(HomeContext);
|
42 |
-
|
43 |
-
const [content, setContent] = useState<string>();
|
44 |
-
const [isTyping, setIsTyping] = useState<boolean>(false);
|
45 |
-
const [showPromptList, setShowPromptList] = useState(false);
|
46 |
-
const [activePromptIndex, setActivePromptIndex] = useState(0);
|
47 |
-
const [promptInputValue, setPromptInputValue] = useState('');
|
48 |
-
const [variables, setVariables] = useState<string[]>([]);
|
49 |
-
|
50 |
-
const promptListRef = useRef<HTMLUListElement | null>(null);
|
51 |
-
|
52 |
-
const filteredPrompts = prompts.filter((prompt: { name: string; }) =>
|
53 |
-
prompt.name.toLowerCase().includes(promptInputValue.toLowerCase()),
|
54 |
-
);
|
55 |
-
|
56 |
-
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
57 |
-
const value = e.target.value;
|
58 |
-
const maxLength = selectedConversation?.model.maxLength;
|
59 |
-
|
60 |
-
if (maxLength && value.length > maxLength) {
|
61 |
-
alert(
|
62 |
-
`Message limit is ${maxLength} characters. You have entered ${value.length} characters.`,
|
63 |
-
);
|
64 |
-
return;
|
65 |
-
}
|
66 |
-
|
67 |
-
setContent(value);
|
68 |
-
updatePromptListVisibility(value);
|
69 |
-
};
|
70 |
-
|
71 |
-
const handleSend = () => {
|
72 |
-
if (messageIsStreaming) {
|
73 |
-
return;
|
74 |
-
}
|
75 |
-
|
76 |
-
if (!content) {
|
77 |
-
alert('Please enter a message');
|
78 |
-
return;
|
79 |
-
}
|
80 |
-
|
81 |
-
onSend({ role: 'user', content });
|
82 |
-
setContent('');
|
83 |
-
|
84 |
-
if (window.innerWidth < 640 && textareaRef && textareaRef.current) {
|
85 |
-
textareaRef.current.blur();
|
86 |
-
}
|
87 |
-
};
|
88 |
-
|
89 |
-
const handleStopConversation = () => {
|
90 |
-
stopConversationRef.current = true;
|
91 |
-
setTimeout(() => {
|
92 |
-
stopConversationRef.current = false;
|
93 |
-
}, 1000);
|
94 |
-
};
|
95 |
-
|
96 |
-
const isMobile = () => {
|
97 |
-
const userAgent =
|
98 |
-
typeof window.navigator === 'undefined' ? '' : navigator.userAgent;
|
99 |
-
const mobileRegex =
|
100 |
-
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i;
|
101 |
-
return mobileRegex.test(userAgent);
|
102 |
-
};
|
103 |
-
|
104 |
-
const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
|
105 |
-
if (e.key === 'Enter' && !isTyping && !isMobile() && !e.shiftKey) {
|
106 |
-
e.preventDefault();
|
107 |
-
handleSend();
|
108 |
-
} else if (e.key === '/' && e.metaKey) {
|
109 |
-
e.preventDefault();
|
110 |
-
|
111 |
-
}
|
112 |
-
};
|
113 |
-
|
114 |
-
const parseVariables = (content: string) => {
|
115 |
-
const regex = /{{(.*?)}}/g;
|
116 |
-
const foundVariables = [];
|
117 |
-
let match;
|
118 |
-
|
119 |
-
while ((match = regex.exec(content)) !== null) {
|
120 |
-
foundVariables.push(match[1]);
|
121 |
-
}
|
122 |
-
|
123 |
-
return foundVariables;
|
124 |
-
};
|
125 |
-
|
126 |
-
const updatePromptListVisibility = useCallback((text: string) => {
|
127 |
-
const match = text.match(/\/\w*$/);
|
128 |
-
|
129 |
-
if (match) {
|
130 |
-
setShowPromptList(true);
|
131 |
-
setPromptInputValue(match[0].slice(1));
|
132 |
-
} else {
|
133 |
-
setShowPromptList(false);
|
134 |
-
setPromptInputValue('');
|
135 |
-
}
|
136 |
-
}, []);
|
137 |
-
|
138 |
-
|
139 |
-
const handleSubmit = (updatedVariables: string[]) => {
|
140 |
-
const newContent = content?.replace(/{{(.*?)}}/g, (match, variable) => {
|
141 |
-
const index = variables.indexOf(variable);
|
142 |
-
return updatedVariables[index];
|
143 |
-
});
|
144 |
-
|
145 |
-
setContent(newContent);
|
146 |
-
|
147 |
-
if (textareaRef && textareaRef.current) {
|
148 |
-
textareaRef.current.focus();
|
149 |
-
}
|
150 |
-
};
|
151 |
-
|
152 |
-
useEffect(() => {
|
153 |
-
if (promptListRef.current) {
|
154 |
-
promptListRef.current.scrollTop = activePromptIndex * 30;
|
155 |
-
}
|
156 |
-
}, [activePromptIndex]);
|
157 |
-
|
158 |
-
useEffect(() => {
|
159 |
-
if (textareaRef && textareaRef.current) {
|
160 |
-
textareaRef.current.style.height = 'inherit';
|
161 |
-
textareaRef.current.style.height = `${textareaRef.current?.scrollHeight}px`;
|
162 |
-
textareaRef.current.style.overflow = `${
|
163 |
-
textareaRef?.current?.scrollHeight > 400 ? 'auto' : 'hidden'
|
164 |
-
}`;
|
165 |
-
}
|
166 |
-
}, [content]);
|
167 |
-
|
168 |
-
useEffect(() => {
|
169 |
-
const handleOutsideClick = (e: MouseEvent) => {
|
170 |
-
if (
|
171 |
-
promptListRef.current &&
|
172 |
-
!promptListRef.current.contains(e.target as Node)
|
173 |
-
) {
|
174 |
-
setShowPromptList(false);
|
175 |
-
}
|
176 |
-
};
|
177 |
-
|
178 |
-
window.addEventListener('click', handleOutsideClick);
|
179 |
-
|
180 |
-
return () => {
|
181 |
-
window.removeEventListener('click', handleOutsideClick);
|
182 |
-
};
|
183 |
-
}, []);
|
184 |
-
|
185 |
-
return (
|
186 |
-
<div className="absolute bottom-0 left-0 w-full border-transparent bg-gradient-to-b from-transparent via-white to-white pt-6 dark:border-white/20 dark:via-[#343541] dark:to-[#343541] md:pt-2">
|
187 |
-
<div className="stretch mx-2 mt-4 flex flex-row gap-3 last:mb-2 md:mx-4 md:mt-[52px] md:last:mb-6 lg:mx-auto lg:max-w-3xl">
|
188 |
-
{messageIsStreaming && (
|
189 |
-
<button
|
190 |
-
className="absolute top-0 left-0 right-0 mx-auto mb-3 flex w-fit items-center gap-3 rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white md:mb-0 md:mt-2"
|
191 |
-
onClick={handleStopConversation}
|
192 |
-
>
|
193 |
-
<IconPlayerStop size={16} /> {'Stop Generating'}
|
194 |
-
</button>
|
195 |
-
)}
|
196 |
-
|
197 |
-
{!messageIsStreaming &&
|
198 |
-
selectedConversation &&
|
199 |
-
selectedConversation.messages.length > 0 && (
|
200 |
-
<button
|
201 |
-
className="absolute top-0 left-0 right-0 mx-auto mb-3 flex w-fit items-center gap-3 rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white md:mb-0 md:mt-2"
|
202 |
-
onClick={onRegenerate}
|
203 |
-
>
|
204 |
-
<IconRepeat size={16} /> {'Regenerate response'}
|
205 |
-
</button>
|
206 |
-
)}
|
207 |
-
|
208 |
-
<div className="relative mx-2 flex w-full flex-grow flex-col rounded-md border border-black/10 bg-white shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 dark:bg-[#40414F] dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] sm:mx-4">
|
209 |
-
|
210 |
-
<textarea
|
211 |
-
ref={textareaRef}
|
212 |
-
className="m-0 w-full resize-none border-0 bg-transparent p-0 py-2 pr-8 pl-10 text-black dark:bg-transparent dark:text-white md:py-3 md:pl-10"
|
213 |
-
style={{
|
214 |
-
resize: 'none',
|
215 |
-
bottom: `${textareaRef?.current?.scrollHeight}px`,
|
216 |
-
maxHeight: '400px',
|
217 |
-
overflow: `${
|
218 |
-
textareaRef.current && textareaRef.current.scrollHeight > 400
|
219 |
-
? 'auto'
|
220 |
-
: 'hidden'
|
221 |
-
}`,
|
222 |
-
}}
|
223 |
-
placeholder={
|
224 |
-
'Type a message or type "/" to select a prompt...' || ''
|
225 |
-
}
|
226 |
-
value={content}
|
227 |
-
rows={1}
|
228 |
-
onCompositionStart={() => setIsTyping(true)}
|
229 |
-
onCompositionEnd={() => setIsTyping(false)}
|
230 |
-
onChange={handleChange}
|
231 |
-
onKeyDown={handleKeyDown}
|
232 |
-
/>
|
233 |
-
|
234 |
-
<button
|
235 |
-
className="absolute right-2 top-2 rounded-sm p-1 text-neutral-800 opacity-60 hover:bg-neutral-200 hover:text-neutral-900 dark:bg-opacity-50 dark:text-neutral-100 dark:hover:text-neutral-200"
|
236 |
-
onClick={handleSend}
|
237 |
-
>
|
238 |
-
{messageIsStreaming ? (
|
239 |
-
<div className="h-4 w-4 animate-spin rounded-full border-t-2 border-neutral-800 opacity-60 dark:border-neutral-100"></div>
|
240 |
-
) : (
|
241 |
-
<IconSend size={18} />
|
242 |
-
)}
|
243 |
-
</button>
|
244 |
-
</div>
|
245 |
-
</div>
|
246 |
-
<div className="px-3 pt-2 pb-3 text-center text-[12px] text-black/50 dark:text-white/50 md:px-4 md:pt-3 md:pb-6">
|
247 |
-
|
248 |
-
</div>
|
249 |
-
</div>
|
250 |
-
);
|
251 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/Chat/ChatLoader.tsx
DELETED
@@ -1,20 +0,0 @@
|
|
1 |
-
import { IconRobot } from '@tabler/icons-react';
|
2 |
-
import { FC } from 'react';
|
3 |
-
|
4 |
-
interface Props { }
|
5 |
-
|
6 |
-
export const ChatLoader: FC<Props> = () => {
|
7 |
-
return (
|
8 |
-
<div
|
9 |
-
className="group border-b border-black/10 bg-gray-50 text-gray-800 dark:border-gray-900/50 dark:bg-[#444654] dark:text-gray-100"
|
10 |
-
style={{ overflowWrap: 'anywhere' }}
|
11 |
-
>
|
12 |
-
<div className="m-auto flex gap-4 p-4 text-base md:max-w-2xl md:gap-6 md:py-6 lg:max-w-2xl lg:px-0 xl:max-w-3xl">
|
13 |
-
<div className="min-w-[40px] items-end">
|
14 |
-
<IconRobot size={30} />
|
15 |
-
</div>
|
16 |
-
<span className="animate-pulse cursor-default mt-1">β</span>
|
17 |
-
</div>
|
18 |
-
</div>
|
19 |
-
);
|
20 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/components/ChatWindow.jsx
CHANGED
@@ -54,8 +54,8 @@ function ChatWindow({
|
|
54 |
<div className="window-content w-full">
|
55 |
<div className="flex flex-col w-full">
|
56 |
<MessageList
|
57 |
-
screenName={"
|
58 |
-
assistantScreenName={"
|
59 |
/>
|
60 |
{/* <Separator /> */}
|
61 |
<div className="h-4" />
|
|
|
54 |
<div className="window-content w-full">
|
55 |
<div className="flex flex-col w-full">
|
56 |
<MessageList
|
57 |
+
screenName={"me"}
|
58 |
+
assistantScreenName={"vicuna"}
|
59 |
/>
|
60 |
{/* <Separator /> */}
|
61 |
<div className="h-4" />
|
src/components/Loader.jsx
CHANGED
@@ -28,11 +28,13 @@ const Loader = () => {
|
|
28 |
alignItems: "center",
|
29 |
flexDirection: "column",
|
30 |
gap: "10px",
|
|
|
|
|
31 |
}}
|
32 |
>
|
33 |
<div className="lg:hidden">
|
34 |
<p className="p-1">
|
35 |
-
web-llm-embed
|
36 |
</p>
|
37 |
<p className="p-1">
|
38 |
No data is sent to the server. Conversations are cached in local
|
@@ -44,6 +46,9 @@ const Loader = () => {
|
|
44 |
<p className="p-1">
|
45 |
Powered by Apache TVM and MLC Relax Runtime.
|
46 |
</p>
|
|
|
|
|
|
|
47 |
</div>
|
48 |
<div>
|
49 |
This will download the model and may take a few minutes. After the
|
|
|
28 |
alignItems: "center",
|
29 |
flexDirection: "column",
|
30 |
gap: "10px",
|
31 |
+
fontSize: "24px",
|
32 |
+
textAlign: "center"
|
33 |
}}
|
34 |
>
|
35 |
<div className="lg:hidden">
|
36 |
<p className="p-1">
|
37 |
+
<b>web-llm-embed</b>
|
38 |
</p>
|
39 |
<p className="p-1">
|
40 |
No data is sent to the server. Conversations are cached in local
|
|
|
46 |
<p className="p-1">
|
47 |
Powered by Apache TVM and MLC Relax Runtime.
|
48 |
</p>
|
49 |
+
<p className="p-1">
|
50 |
+
Model is currently Vicuna 13B trained by LLMSys
|
51 |
+
</p>
|
52 |
</div>
|
53 |
<div>
|
54 |
This will download the model and may take a few minutes. After the
|
src/components/MessageList.jsx
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import useLLM from "@react-llm/headless";
|
2 |
import { useEffect, useRef } from "react";
|
|
|
3 |
|
4 |
function MessageList({
|
5 |
screenName = "endlessbox5",
|
@@ -20,7 +21,7 @@ function MessageList({
|
|
20 |
}, [conversation, messages.length]);
|
21 |
|
22 |
return (
|
23 |
-
<
|
24 |
<div className="p-2 leading-6 w-full min-h-full">
|
25 |
{conversation?.messages.map((m) => (
|
26 |
<div key={m.id} style={{ display: "flex" }}>
|
@@ -44,7 +45,7 @@ function MessageList({
|
|
44 |
))}
|
45 |
<div ref={scrollRef}></div>
|
46 |
</div>
|
47 |
-
</
|
48 |
);
|
49 |
}
|
50 |
|
|
|
1 |
import useLLM from "@react-llm/headless";
|
2 |
import { useEffect, useRef } from "react";
|
3 |
+
import { ScrollView } from "react95";
|
4 |
|
5 |
function MessageList({
|
6 |
screenName = "endlessbox5",
|
|
|
21 |
}, [conversation, messages.length]);
|
22 |
|
23 |
return (
|
24 |
+
<ScrollView style={{ height: "350px" }} className="w-full">
|
25 |
<div className="p-2 leading-6 w-full min-h-full">
|
26 |
{conversation?.messages.map((m) => (
|
27 |
<div key={m.id} style={{ display: "flex" }}>
|
|
|
45 |
))}
|
46 |
<div ref={scrollRef}></div>
|
47 |
</div>
|
48 |
+
</ScrollView>
|
49 |
);
|
50 |
}
|
51 |
|
src/pages/api/home.context.tsx
DELETED
@@ -1,23 +0,0 @@
|
|
1 |
-
import { Dispatch, createContext } from 'react';
|
2 |
-
|
3 |
-
import { ActionType } from '@/utils/';
|
4 |
-
|
5 |
-
import { Conversation } from '@/types/chat';
|
6 |
-
import { KeyValuePair } from '@/types/data';
|
7 |
-
|
8 |
-
import { HomeInitialState } from './home.state';
|
9 |
-
|
10 |
-
export interface HomeContextProps {
|
11 |
-
state: HomeInitialState;
|
12 |
-
dispatch: Dispatch<ActionType<HomeInitialState>>;
|
13 |
-
handleNewConversation: () => void;
|
14 |
-
handleSelectConversation: (conversation: Conversation) => void;
|
15 |
-
handleUpdateConversation: (
|
16 |
-
conversation: Conversation,
|
17 |
-
data: KeyValuePair,
|
18 |
-
) => void;
|
19 |
-
}
|
20 |
-
|
21 |
-
const HomeContext = createContext<HomeContextProps>(undefined!);
|
22 |
-
|
23 |
-
export default HomeContext;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/pages/api/home.state.tsx
DELETED
@@ -1,42 +0,0 @@
|
|
1 |
-
import { Conversation, Message } from '@/types/chat';
|
2 |
-
import { Prompt } from '@/types/prompt';
|
3 |
-
|
4 |
-
export interface HomeInitialState {
|
5 |
-
loading: boolean;
|
6 |
-
lightMode: 'light' | 'dark';
|
7 |
-
messageIsStreaming: boolean;
|
8 |
-
modelError: any | null;
|
9 |
-
models: any[];
|
10 |
-
conversations: Conversation[];
|
11 |
-
selectedConversation: Conversation | undefined;
|
12 |
-
currentMessage: Message | undefined;
|
13 |
-
prompts: Prompt[];
|
14 |
-
temperature: number;
|
15 |
-
showChatbar: boolean;
|
16 |
-
showPromptbar: boolean;
|
17 |
-
messageError: boolean;
|
18 |
-
searchTerm: string;
|
19 |
-
defaultModelId: any | undefined;
|
20 |
-
serverSideApiKeyIsSet: boolean;
|
21 |
-
serverSidePluginKeysSet: boolean;
|
22 |
-
}
|
23 |
-
|
24 |
-
export const initialState: HomeInitialState = {
|
25 |
-
loading: false,
|
26 |
-
lightMode: 'dark',
|
27 |
-
messageIsStreaming: false,
|
28 |
-
modelError: null,
|
29 |
-
models: [],
|
30 |
-
conversations: [],
|
31 |
-
selectedConversation: undefined,
|
32 |
-
currentMessage: undefined,
|
33 |
-
prompts: [],
|
34 |
-
temperature: 1,
|
35 |
-
showPromptbar: true,
|
36 |
-
showChatbar: true,
|
37 |
-
messageError: false,
|
38 |
-
searchTerm: '',
|
39 |
-
defaultModelId: undefined,
|
40 |
-
serverSideApiKeyIsSet: false,
|
41 |
-
serverSidePluginKeysSet: false,
|
42 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/pages/api/home.tsx
DELETED
@@ -1,157 +0,0 @@
|
|
1 |
-
import { useEffect, useRef } from 'react';
|
2 |
-
|
3 |
-
import { GetServerSideProps } from 'next';
|
4 |
-
import Head from 'next/head';
|
5 |
-
import {
|
6 |
-
DEFAULT_SYSTEM_PROMPT,
|
7 |
-
DEFAULT_TEMPERATURE,
|
8 |
-
saveConversation,
|
9 |
-
saveConversations,
|
10 |
-
updateConversation,
|
11 |
-
useCreateReducer
|
12 |
-
} from '@/utils';
|
13 |
-
|
14 |
-
import { Chat } from '@/components/Chat/Chat';
|
15 |
-
|
16 |
-
import HomeContext from './home.context';
|
17 |
-
import { HomeInitialState, initialState } from './home.state';
|
18 |
-
|
19 |
-
import { v4 as uuidv4 } from 'uuid';
|
20 |
-
|
21 |
-
interface Props {
|
22 |
-
serverSideApiKeyIsSet: boolean;
|
23 |
-
serverSidePluginKeysSet: boolean;
|
24 |
-
defaultModelId: any;
|
25 |
-
}
|
26 |
-
|
27 |
-
const Home = ({
|
28 |
-
defaultModelId,
|
29 |
-
}: Props) => {
|
30 |
-
const contextValue = useCreateReducer<HomeInitialState>({
|
31 |
-
initialState,
|
32 |
-
});
|
33 |
-
|
34 |
-
const {
|
35 |
-
state: {
|
36 |
-
lightMode,
|
37 |
-
conversations,
|
38 |
-
selectedConversation
|
39 |
-
},
|
40 |
-
dispatch,
|
41 |
-
} = contextValue;
|
42 |
-
|
43 |
-
const stopConversationRef = useRef<boolean>(false);
|
44 |
-
|
45 |
-
// FETCH MODELS ----------------------------------------------
|
46 |
-
|
47 |
-
const handleSelectConversation = (conversation: any) => {
|
48 |
-
dispatch({
|
49 |
-
field: 'selectedConversation',
|
50 |
-
value: conversation,
|
51 |
-
});
|
52 |
-
|
53 |
-
saveConversation(conversation);
|
54 |
-
};
|
55 |
-
|
56 |
-
// CONVERSATION OPERATIONS --------------------------------------------
|
57 |
-
|
58 |
-
const handleNewConversation = () => {
|
59 |
-
const lastConversation = conversations[conversations.length - 1];
|
60 |
-
|
61 |
-
const newConversation: any = {
|
62 |
-
id: uuidv4(),
|
63 |
-
name: 'New Conversation',
|
64 |
-
messages: [],
|
65 |
-
model: lastConversation?.model || {
|
66 |
-
id: "OpenAIModels[defaultModelId].id",
|
67 |
-
name: "OpenAIModels[defaultModelId].name",
|
68 |
-
maxLength: "OpenAIModels[defaultModelId].maxLength",
|
69 |
-
tokenLimit: "OpenAIModels[defaultModelId].tokenLimit",
|
70 |
-
},
|
71 |
-
prompt: DEFAULT_SYSTEM_PROMPT,
|
72 |
-
temperature: lastConversation?.temperature ?? DEFAULT_TEMPERATURE,
|
73 |
-
folderId: null,
|
74 |
-
};
|
75 |
-
|
76 |
-
const updatedConversations = [...conversations, newConversation];
|
77 |
-
|
78 |
-
dispatch({ field: 'selectedConversation', value: newConversation });
|
79 |
-
dispatch({ field: 'conversations', value: updatedConversations });
|
80 |
-
|
81 |
-
saveConversation(newConversation);
|
82 |
-
saveConversations(updatedConversations);
|
83 |
-
|
84 |
-
dispatch({ field: 'loading', value: false });
|
85 |
-
};
|
86 |
-
|
87 |
-
const handleUpdateConversation = (
|
88 |
-
conversation: any,
|
89 |
-
data: any,
|
90 |
-
) => {
|
91 |
-
const updatedConversation = {
|
92 |
-
...conversation,
|
93 |
-
[data.key]: data.value,
|
94 |
-
};
|
95 |
-
|
96 |
-
const { single, all } = updateConversation(
|
97 |
-
updatedConversation,
|
98 |
-
conversations,
|
99 |
-
);
|
100 |
-
|
101 |
-
dispatch({ field: 'selectedConversation', value: single });
|
102 |
-
dispatch({ field: 'conversations', value: all });
|
103 |
-
};
|
104 |
-
|
105 |
-
// EFFECTS --------------------------------------------
|
106 |
-
|
107 |
-
useEffect(() => {
|
108 |
-
if (window.innerWidth < 640) {
|
109 |
-
dispatch({ field: 'showChatbar', value: false });
|
110 |
-
}
|
111 |
-
}, [selectedConversation]);
|
112 |
-
|
113 |
-
// ON LOAD --------------------------------------------
|
114 |
-
|
115 |
-
return (
|
116 |
-
<HomeContext.Provider
|
117 |
-
value={{
|
118 |
-
...contextValue,
|
119 |
-
handleNewConversation,
|
120 |
-
handleSelectConversation,
|
121 |
-
handleUpdateConversation,
|
122 |
-
}}
|
123 |
-
>
|
124 |
-
<Head>
|
125 |
-
<title>Web LLM Embed</title>
|
126 |
-
<meta name="description" content="Web LLM Embed" />
|
127 |
-
<meta
|
128 |
-
name="viewport"
|
129 |
-
content="height=device-height ,width=device-width, initial-scale=1, user-scalable=no"
|
130 |
-
/>
|
131 |
-
<link rel="icon" href="/favicon.ico" />
|
132 |
-
</Head>
|
133 |
-
<main
|
134 |
-
className={`flex h-screen w-screen flex-col text-sm text-white dark:text-white ${lightMode}`}
|
135 |
-
>
|
136 |
-
<div className="flex h-full w-full pt-[48px] sm:pt-0">
|
137 |
-
<div className="flex flex-1">
|
138 |
-
<Chat stopConversationRef={stopConversationRef} />
|
139 |
-
</div>
|
140 |
-
</div>
|
141 |
-
</main>
|
142 |
-
</HomeContext.Provider>
|
143 |
-
);
|
144 |
-
};
|
145 |
-
export default Home;
|
146 |
-
|
147 |
-
export const getServerSideProps: GetServerSideProps = async ({ locale }) => {
|
148 |
-
const defaultModelId = "fallbackModelID"
|
149 |
-
|
150 |
-
return {
|
151 |
-
props: {
|
152 |
-
defaultModelId
|
153 |
-
},
|
154 |
-
};
|
155 |
-
};
|
156 |
-
|
157 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/utils/file-handler.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
|
|
1 |
import fs from 'fs-extra';
|
2 |
-
import type { OpenAIEmbeddings } from 'langchain/embeddings/openai';
|
3 |
import {
|
4 |
HNSWLib,
|
5 |
type HNSWLib as StoreTypeHNSWLib,
|
@@ -26,7 +26,7 @@ const HNSWLibModelFilesName = {
|
|
26 |
// looking forward to a better way to transfrom hnswlibStore <=> indexes
|
27 |
export async function HNSWLibModelToVectorStore(
|
28 |
model: HNSWLibModel,
|
29 |
-
embeddings:
|
30 |
) {
|
31 |
await saveHNSWLibModelToLocal(model);
|
32 |
// load from dir
|
|
|
1 |
+
import { XenovaTransformersEmbeddings } from '@/embed/hf';
|
2 |
import fs from 'fs-extra';
|
|
|
3 |
import {
|
4 |
HNSWLib,
|
5 |
type HNSWLib as StoreTypeHNSWLib,
|
|
|
26 |
// looking forward to a better way to transfrom hnswlibStore <=> indexes
|
27 |
export async function HNSWLibModelToVectorStore(
|
28 |
model: HNSWLibModel,
|
29 |
+
embeddings: XenovaTransformersEmbeddings,
|
30 |
) {
|
31 |
await saveHNSWLibModelToLocal(model);
|
32 |
// load from dir
|
src/utils/index.ts
CHANGED
@@ -1,4 +1,3 @@
|
|
1 |
-
import { Conversation } from '@/types/chat';
|
2 |
import { useMemo, useReducer } from 'react';
|
3 |
|
4 |
// Extracts property names from initial state of reducer to allow typesafe dispatch objects
|
@@ -30,35 +29,6 @@ export const useCreateReducer = <T>({ initialState }: { initialState: T }) => {
|
|
30 |
return useMemo(() => ({ state, dispatch }), [state, dispatch]);
|
31 |
};
|
32 |
|
33 |
-
export const updateConversation = (
|
34 |
-
updatedConversation: Conversation,
|
35 |
-
allConversations: Conversation[],
|
36 |
-
) => {
|
37 |
-
const updatedConversations = allConversations.map((c) => {
|
38 |
-
if (c.id === updatedConversation.id) {
|
39 |
-
return updatedConversation;
|
40 |
-
}
|
41 |
-
|
42 |
-
return c;
|
43 |
-
});
|
44 |
-
|
45 |
-
saveConversation(updatedConversation);
|
46 |
-
saveConversations(updatedConversations);
|
47 |
-
|
48 |
-
return {
|
49 |
-
single: updatedConversation,
|
50 |
-
all: updatedConversations,
|
51 |
-
};
|
52 |
-
};
|
53 |
-
|
54 |
-
export const saveConversation = (conversation: Conversation) => {
|
55 |
-
localStorage.setItem('selectedConversation', JSON.stringify(conversation));
|
56 |
-
};
|
57 |
-
|
58 |
-
export const saveConversations = (conversations: Conversation[]) => {
|
59 |
-
localStorage.setItem('conversationHistory', JSON.stringify(conversations));
|
60 |
-
};
|
61 |
-
|
62 |
|
63 |
export function throttle<T extends (...args: any[]) => any>(
|
64 |
func: T,
|
|
|
|
|
1 |
import { useMemo, useReducer } from 'react';
|
2 |
|
3 |
// Extracts property names from initial state of reducer to allow typesafe dispatch objects
|
|
|
29 |
return useMemo(() => ({ state, dispatch }), [state, dispatch]);
|
30 |
};
|
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
export function throttle<T extends (...args: any[]) => any>(
|
34 |
func: T,
|