Spaces:
Running
on
CPU Upgrade
Function calling (#996)
Browse files* Initial work on function calling
* wip
* Add websearch as a tool
* lint
* smol
* Move tools to their own files
* directly answer check
* Add text2img tool
* group tool calls together
* show retry even if no message
* fix trailing urls
* Add image popup
* format
* wip
* clean-up
* better loading indicator
* text colors
* extra example to summarize
* switch default model
* Add fetchUrl tool
* wip
* Add latest gradio
* fix types
* version bump sharp
* Basic tools menu
* working menu
* fix menu positioning
* deps fix
* add deps
* cleanup
* more cleanup
* cleanup
* package cleanups
* moar cleanup
* ui update
* Update ChatMessage.svelte
* upgrade gradio dep
* lint
* refactor and pass results to cohere
* feat: code interpreter tool
* fix: add e2b dependency
* feat: working TGI endpoint with tool results
* feat: allow image model to expand to 90dvw
* fix: dont block on title gen
* bump sharp
* misc cleanup
* fix url fetcher, adjust tool typing
* migrate to new MessageUpdate schema
* fix lint errors
* image editing, pdf upload + parsing
* feat: file preview for non-images
* feat: image prompting, file ui, file migration, many fixes
* feat: multiple files and tool file indices
* feat: add back remote keylogging prevention
* minor nit
* minor
* resolve nits
* feat: use node vm for calculator and improve prompt
* more nits
* feat: add index to tools settings
* chore: update invalid package lock
* feat: bump gradio client to 0.19.4
* feat: move pdf to markdown to huggingchat
* fix: uploaded file width
* feat: prompt the model when no files available
* Feat functions: UI update (#1157)
* details: close on click outside
* drag for tools
* tools ordering
* add link to community discussion
* misc
* calculator listed as last
* file style
* images with different ratios
* page scraper: longer timeout
@Saghen
@mishig25 seems to work better with this
* vertical gap
* Revert "drag for tools"
This reverts commit 8eeed3b77c164325bec8ab4f5827641acb6cc72f.
* chat padding on desktop
* file colors
* larger gap for all messages on xl screens
* feat: update pdf to markdown schema
* fix: uploaded file container width
* fix: tool name check
* fix: cohere endpoint
* fix: use most recent message for files
* feat: allow tools to access previous files
* feat: support all file types on document parser
* fix: use document parser in default tools
* feat: rename url fetcher internal name
* feat: resolve type error
* feat: enable tools on prod command r+
* feat: truncate document markdown
* feat: bump @huggingface/inference
* feat: resolve type errors
* nit
* Feat functions misc update 2 (#1158)
* update examples
a
* add tool indicator
* llama 3 description update
* image quick fix
* mobile
* icon purple
---------
Co-authored-by: Victor Mustar <[email protected]>
Co-authored-by: Liam Dyer <[email protected]>
Co-authored-by: Mishig <[email protected]>
- .env +1 -0
- .eslintrc.cjs +1 -1
- chart/env/prod.yaml +7 -6
- package-lock.json +528 -70
- package.json +4 -3
- src/lib/actions/clickOutside.ts +1 -1
- src/lib/buildPrompt.ts +11 -1
- src/lib/components/OpenWebSearchResults.svelte +14 -8
- src/lib/components/ToolsMenu.svelte +75 -0
- src/lib/components/UploadBtn.svelte +13 -8
- src/lib/components/chat/ChatMessage.svelte +177 -28
- src/lib/components/chat/ChatWindow.svelte +22 -25
- src/lib/components/chat/UploadedFile.svelte +54 -0
- src/lib/components/icons/IconTool.svelte +16 -0
- src/lib/migrations/routines/03-add-tools-in-settings.ts +29 -0
- src/lib/migrations/routines/04-update-message-updates.ts +190 -0
- src/lib/migrations/routines/05-update-message-files.ts +56 -0
- src/lib/migrations/routines/index.ts +10 -1
- src/lib/server/endpoints/cohere/endpointCohere.ts +77 -14
- src/lib/server/endpoints/endpoints.ts +10 -2
- src/lib/server/endpoints/tgi/endpointTgi.ts +11 -1
- src/lib/server/files/downloadFile.ts +16 -19
- src/lib/server/files/uploadFile.ts +3 -1
- src/lib/server/models.ts +66 -3
- src/lib/server/textGeneration/assistant.ts +53 -0
- src/lib/server/textGeneration/generate.ts +51 -0
- src/lib/server/textGeneration/index.ts +64 -0
- src/lib/server/{summarize.ts → textGeneration/title.ts} +31 -2
- src/lib/server/textGeneration/tools.ts +198 -0
- src/lib/server/textGeneration/types.ts +17 -0
- src/lib/server/tools/calculator.ts +37 -0
- src/lib/server/tools/directlyAnswer.ts +20 -0
- src/lib/server/tools/documentParser.ts +69 -0
- src/lib/server/tools/images/editing.ts +107 -0
- src/lib/server/tools/images/generation.ts +92 -0
- src/lib/server/tools/index.ts +37 -0
- src/lib/server/tools/utils.ts +29 -0
- src/lib/server/tools/web/search.ts +33 -0
- src/lib/server/tools/web/url.ts +32 -0
- src/lib/server/websearch/markdown/utils/stringify.ts +7 -0
- src/lib/server/websearch/runWebSearch.ts +30 -33
- src/lib/server/websearch/scrape/playwright.ts +4 -3
- src/lib/server/websearch/scrape/scrape.ts +33 -7
- src/lib/server/websearch/search/search.ts +14 -9
- src/lib/server/websearch/update.ts +46 -0
- src/lib/stores/settings.ts +1 -0
- src/lib/types/Message.ts +1 -0
- src/lib/types/MessageUpdate.ts +102 -37
- src/lib/types/Model.ts +1 -0
- src/lib/types/Settings.ts +2 -0
@@ -154,6 +154,7 @@ WEBHOOK_URL_REPORT_ASSISTANT=#provide webhook url to get notified when an assist
|
|
154 |
ALLOWED_USER_EMAILS=`[]` # if it's defined, only these emails will be allowed to use the app
|
155 |
|
156 |
USAGE_LIMITS=`{}`
|
|
|
157 |
ALLOW_INSECURE_COOKIES=false # recommended to keep this to false but set to true if you need to run over http without tls
|
158 |
METRICS_PORT=
|
159 |
LOG_LEVEL=info
|
|
|
154 |
ALLOWED_USER_EMAILS=`[]` # if it's defined, only these emails will be allowed to use the app
|
155 |
|
156 |
USAGE_LIMITS=`{}`
|
157 |
+
|
158 |
ALLOW_INSECURE_COOKIES=false # recommended to keep this to false but set to true if you need to run over http without tls
|
159 |
METRICS_PORT=
|
160 |
LOG_LEVEL=info
|
@@ -24,7 +24,7 @@ module.exports = {
|
|
24 |
extraFileExtensions: [".svelte"],
|
25 |
},
|
26 |
rules: {
|
27 |
-
"
|
28 |
"@typescript-eslint/no-explicit-any": "error",
|
29 |
"@typescript-eslint/no-non-null-assertion": "error",
|
30 |
"@typescript-eslint/no-unused-vars": [
|
|
|
24 |
extraFileExtensions: [".svelte"],
|
25 |
},
|
26 |
rules: {
|
27 |
+
"require-yield": "off",
|
28 |
"@typescript-eslint/no-explicit-any": "error",
|
29 |
"@typescript-eslint/no-non-null-assertion": "error",
|
30 |
"@typescript-eslint/no-unused-vars": [
|
@@ -39,6 +39,7 @@ envVars:
|
|
39 |
"modelUrl": "https://huggingface.co/CohereForAI/c4ai-command-r-plus",
|
40 |
"websiteUrl": "https://docs.cohere.com/docs/command-r-plus",
|
41 |
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/cohere-logo.png",
|
|
|
42 |
"parameters": {
|
43 |
"stop": ["<|END_OF_TURN_TOKEN|>"],
|
44 |
"truncate" : 28672,
|
@@ -47,20 +48,20 @@ envVars:
|
|
47 |
},
|
48 |
"promptExamples" : [
|
49 |
{
|
50 |
-
"title": "
|
51 |
-
"prompt": "
|
|
|
|
|
|
|
52 |
}, {
|
53 |
"title": "Code a snake game",
|
54 |
"prompt": "Code a basic snake game in python, give explanations for each step."
|
55 |
-
}, {
|
56 |
-
"title": "Assist in a task",
|
57 |
-
"prompt": "How do I make a delicious lemon cheesecake?"
|
58 |
}
|
59 |
]
|
60 |
},
|
61 |
{
|
62 |
"name" : "meta-llama/Meta-Llama-3-70B-Instruct",
|
63 |
-
"description": "
|
64 |
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/meta-logo.png",
|
65 |
"modelUrl": "https://huggingface.co/meta-llama/Meta-Llama-3-70B-Instruct",
|
66 |
"websiteUrl": "https://llama.meta.com/llama3/",
|
|
|
39 |
"modelUrl": "https://huggingface.co/CohereForAI/c4ai-command-r-plus",
|
40 |
"websiteUrl": "https://docs.cohere.com/docs/command-r-plus",
|
41 |
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/cohere-logo.png",
|
42 |
+
"tools": true,
|
43 |
"parameters": {
|
44 |
"stop": ["<|END_OF_TURN_TOKEN|>"],
|
45 |
"truncate" : 28672,
|
|
|
48 |
},
|
49 |
"promptExamples" : [
|
50 |
{
|
51 |
+
"title": "Generate a mouse portrait",
|
52 |
+
"prompt": "Generate the portrait of a scientific mouse in its laboratory."
|
53 |
+
}, {
|
54 |
+
"title": "Review a pull request",
|
55 |
+
"prompt": "Review this pull request: https://github.com/huggingface/chat-ui/pull/1131/files"
|
56 |
}, {
|
57 |
"title": "Code a snake game",
|
58 |
"prompt": "Code a basic snake game in python, give explanations for each step."
|
|
|
|
|
|
|
59 |
}
|
60 |
]
|
61 |
},
|
62 |
{
|
63 |
"name" : "meta-llama/Meta-Llama-3-70B-Instruct",
|
64 |
+
"description": "Meta Llama 3 delivers top performance on various benchmarks and introduces new features like better reasoning.",
|
65 |
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/meta-logo.png",
|
66 |
"modelUrl": "https://huggingface.co/meta-llama/Meta-Llama-3-70B-Instruct",
|
67 |
"websiteUrl": "https://llama.meta.com/llama3/",
|
@@ -9,8 +9,9 @@
|
|
9 |
"version": "0.8.4",
|
10 |
"dependencies": {
|
11 |
"@cliqz/adblocker-playwright": "^1.27.2",
|
|
|
12 |
"@huggingface/hub": "^0.5.1",
|
13 |
-
"@huggingface/inference": "^2.
|
14 |
"@iconify-json/bi": "^1.1.21",
|
15 |
"@playwright/browser-chromium": "^1.43.1",
|
16 |
"@resvg/resvg-js": "^2.6.2",
|
@@ -42,7 +43,7 @@
|
|
42 |
"satori-html": "^0.3.2",
|
43 |
"sbd": "^1.0.19",
|
44 |
"serpapi": "^1.1.1",
|
45 |
-
"sharp": "^0.33.
|
46 |
"tailwind-scrollbar": "^3.0.0",
|
47 |
"tailwindcss": "^3.4.0",
|
48 |
"uuid": "^9.0.1",
|
@@ -174,6 +175,22 @@
|
|
174 |
"google-auth-library": "^9.4.2"
|
175 |
}
|
176 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
"node_modules/@cliqz/adblocker": {
|
178 |
"version": "1.27.2",
|
179 |
"resolved": "https://registry.npmjs.org/@cliqz/adblocker/-/adblocker-1.27.2.tgz",
|
@@ -706,6 +723,23 @@
|
|
706 |
"node": ">=18.0.0"
|
707 |
}
|
708 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
709 |
"node_modules/@huggingface/hub": {
|
710 |
"version": "0.5.1",
|
711 |
"resolved": "https://registry.npmjs.org/@huggingface/hub/-/hub-0.5.1.tgz",
|
@@ -718,9 +752,12 @@
|
|
718 |
}
|
719 |
},
|
720 |
"node_modules/@huggingface/inference": {
|
721 |
-
"version": "2.
|
722 |
-
"resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-2.
|
723 |
-
"integrity": "sha512-
|
|
|
|
|
|
|
724 |
"engines": {
|
725 |
"node": ">=18"
|
726 |
}
|
@@ -733,6 +770,11 @@
|
|
733 |
"node": ">=18"
|
734 |
}
|
735 |
},
|
|
|
|
|
|
|
|
|
|
|
736 |
"node_modules/@humanwhocodes/config-array": {
|
737 |
"version": "0.11.8",
|
738 |
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
@@ -812,9 +854,9 @@
|
|
812 |
}
|
813 |
},
|
814 |
"node_modules/@img/sharp-darwin-arm64": {
|
815 |
-
"version": "0.33.
|
816 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.
|
817 |
-
"integrity": "sha512-
|
818 |
"cpu": [
|
819 |
"arm64"
|
820 |
],
|
@@ -837,9 +879,9 @@
|
|
837 |
}
|
838 |
},
|
839 |
"node_modules/@img/sharp-darwin-x64": {
|
840 |
-
"version": "0.33.
|
841 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.
|
842 |
-
"integrity": "sha512-
|
843 |
"cpu": [
|
844 |
"x64"
|
845 |
],
|
@@ -1030,9 +1072,9 @@
|
|
1030 |
}
|
1031 |
},
|
1032 |
"node_modules/@img/sharp-linux-arm": {
|
1033 |
-
"version": "0.33.
|
1034 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.
|
1035 |
-
"integrity": "sha512-
|
1036 |
"cpu": [
|
1037 |
"arm"
|
1038 |
],
|
@@ -1055,9 +1097,9 @@
|
|
1055 |
}
|
1056 |
},
|
1057 |
"node_modules/@img/sharp-linux-arm64": {
|
1058 |
-
"version": "0.33.
|
1059 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.
|
1060 |
-
"integrity": "sha512-
|
1061 |
"cpu": [
|
1062 |
"arm64"
|
1063 |
],
|
@@ -1080,9 +1122,9 @@
|
|
1080 |
}
|
1081 |
},
|
1082 |
"node_modules/@img/sharp-linux-s390x": {
|
1083 |
-
"version": "0.33.
|
1084 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.
|
1085 |
-
"integrity": "sha512-
|
1086 |
"cpu": [
|
1087 |
"s390x"
|
1088 |
],
|
@@ -1091,7 +1133,7 @@
|
|
1091 |
"linux"
|
1092 |
],
|
1093 |
"engines": {
|
1094 |
-
"glibc": ">=2.
|
1095 |
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
1096 |
"npm": ">=9.6.5",
|
1097 |
"pnpm": ">=7.1.0",
|
@@ -1105,9 +1147,9 @@
|
|
1105 |
}
|
1106 |
},
|
1107 |
"node_modules/@img/sharp-linux-x64": {
|
1108 |
-
"version": "0.33.
|
1109 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.
|
1110 |
-
"integrity": "sha512-
|
1111 |
"cpu": [
|
1112 |
"x64"
|
1113 |
],
|
@@ -1130,9 +1172,9 @@
|
|
1130 |
}
|
1131 |
},
|
1132 |
"node_modules/@img/sharp-linuxmusl-arm64": {
|
1133 |
-
"version": "0.33.
|
1134 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.
|
1135 |
-
"integrity": "sha512-
|
1136 |
"cpu": [
|
1137 |
"arm64"
|
1138 |
],
|
@@ -1155,9 +1197,9 @@
|
|
1155 |
}
|
1156 |
},
|
1157 |
"node_modules/@img/sharp-linuxmusl-x64": {
|
1158 |
-
"version": "0.33.
|
1159 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.
|
1160 |
-
"integrity": "sha512-
|
1161 |
"cpu": [
|
1162 |
"x64"
|
1163 |
],
|
@@ -1180,15 +1222,15 @@
|
|
1180 |
}
|
1181 |
},
|
1182 |
"node_modules/@img/sharp-wasm32": {
|
1183 |
-
"version": "0.33.
|
1184 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.
|
1185 |
-
"integrity": "sha512-
|
1186 |
"cpu": [
|
1187 |
"wasm32"
|
1188 |
],
|
1189 |
"optional": true,
|
1190 |
"dependencies": {
|
1191 |
-
"@emnapi/runtime": "^1.1.
|
1192 |
},
|
1193 |
"engines": {
|
1194 |
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
@@ -1201,9 +1243,9 @@
|
|
1201 |
}
|
1202 |
},
|
1203 |
"node_modules/@img/sharp-win32-ia32": {
|
1204 |
-
"version": "0.33.
|
1205 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.
|
1206 |
-
"integrity": "sha512-
|
1207 |
"cpu": [
|
1208 |
"ia32"
|
1209 |
],
|
@@ -1222,9 +1264,9 @@
|
|
1222 |
}
|
1223 |
},
|
1224 |
"node_modules/@img/sharp-win32-x64": {
|
1225 |
-
"version": "0.33.
|
1226 |
-
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.
|
1227 |
-
"integrity": "sha512-
|
1228 |
"cpu": [
|
1229 |
"x64"
|
1230 |
],
|
@@ -1242,6 +1284,76 @@
|
|
1242 |
"url": "https://opencollective.com/libvips"
|
1243 |
}
|
1244 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1245 |
"node_modules/@jridgewell/gen-mapping": {
|
1246 |
"version": "0.3.3",
|
1247 |
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
@@ -1294,6 +1406,30 @@
|
|
1294 |
"sparse-bitfield": "^3.0.3"
|
1295 |
}
|
1296 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1297 |
"node_modules/@nodelib/fs.scandir": {
|
1298 |
"version": "2.1.5",
|
1299 |
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
@@ -1326,6 +1462,25 @@
|
|
1326 |
"node": ">= 8"
|
1327 |
}
|
1328 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1329 |
"node_modules/@opentelemetry/api": {
|
1330 |
"version": "1.8.0",
|
1331 |
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz",
|
@@ -2168,6 +2323,11 @@
|
|
2168 |
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
2169 |
"dev": true
|
2170 |
},
|
|
|
|
|
|
|
|
|
|
|
2171 |
"node_modules/@types/express": {
|
2172 |
"version": "4.17.21",
|
2173 |
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
|
@@ -2266,6 +2426,14 @@
|
|
2266 |
"integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
|
2267 |
"dev": true
|
2268 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2269 |
"node_modules/@types/node": {
|
2270 |
"version": "18.13.0",
|
2271 |
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz",
|
@@ -2356,6 +2524,11 @@
|
|
2356 |
"@types/send": "*"
|
2357 |
}
|
2358 |
},
|
|
|
|
|
|
|
|
|
|
|
2359 |
"node_modules/@types/tough-cookie": {
|
2360 |
"version": "4.0.2",
|
2361 |
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
|
@@ -2382,6 +2555,11 @@
|
|
2382 |
"@types/webidl-conversions": "*"
|
2383 |
}
|
2384 |
},
|
|
|
|
|
|
|
|
|
|
|
2385 |
"node_modules/@typescript-eslint/eslint-plugin": {
|
2386 |
"version": "6.7.4",
|
2387 |
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz",
|
@@ -2799,11 +2977,35 @@
|
|
2799 |
"url": "https://github.com/sponsors/epoberezkin"
|
2800 |
}
|
2801 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2802 |
"node_modules/ansi-regex": {
|
2803 |
"version": "5.0.1",
|
2804 |
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
2805 |
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
2806 |
-
"dev": true,
|
2807 |
"engines": {
|
2808 |
"node": ">=8"
|
2809 |
}
|
@@ -2812,7 +3014,6 @@
|
|
2812 |
"version": "4.3.0",
|
2813 |
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
2814 |
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
2815 |
-
"dev": true,
|
2816 |
"dependencies": {
|
2817 |
"color-convert": "^2.0.1"
|
2818 |
},
|
@@ -3195,8 +3396,6 @@
|
|
3195 |
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz",
|
3196 |
"integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==",
|
3197 |
"hasInstallScript": true,
|
3198 |
-
"optional": true,
|
3199 |
-
"peer": true,
|
3200 |
"dependencies": {
|
3201 |
"node-gyp-build": "^4.3.0"
|
3202 |
},
|
@@ -3317,7 +3516,6 @@
|
|
3317 |
"version": "4.1.2",
|
3318 |
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
3319 |
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
3320 |
-
"dev": true,
|
3321 |
"dependencies": {
|
3322 |
"ansi-styles": "^4.1.0",
|
3323 |
"supports-color": "^7.1.0"
|
@@ -3389,6 +3587,54 @@
|
|
3389 |
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
3390 |
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
3391 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3392 |
"node_modules/code-red": {
|
3393 |
"version": "1.0.4",
|
3394 |
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
|
@@ -3538,7 +3784,6 @@
|
|
3538 |
"version": "0.5.0",
|
3539 |
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
3540 |
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
3541 |
-
"dev": true,
|
3542 |
"engines": {
|
3543 |
"node": ">= 0.6"
|
3544 |
}
|
@@ -4351,6 +4596,14 @@
|
|
4351 |
"node": ">=0.8.x"
|
4352 |
}
|
4353 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4354 |
"node_modules/execa": {
|
4355 |
"version": "5.1.1",
|
4356 |
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
@@ -4803,6 +5056,14 @@
|
|
4803 |
"node": ">=14"
|
4804 |
}
|
4805 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4806 |
"node_modules/get-func-name": {
|
4807 |
"version": "2.0.2",
|
4808 |
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
|
@@ -4971,6 +5232,14 @@
|
|
4971 |
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
|
4972 |
"dev": true
|
4973 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4974 |
"node_modules/gtoken": {
|
4975 |
"version": "7.1.0",
|
4976 |
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
|
@@ -5013,7 +5282,6 @@
|
|
5013 |
"version": "4.0.0",
|
5014 |
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
5015 |
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
5016 |
-
"dev": true,
|
5017 |
"engines": {
|
5018 |
"node": ">=8"
|
5019 |
}
|
@@ -5067,6 +5335,11 @@
|
|
5067 |
"node": ">= 0.4"
|
5068 |
}
|
5069 |
},
|
|
|
|
|
|
|
|
|
|
|
5070 |
"node_modules/help-me": {
|
5071 |
"version": "5.0.0",
|
5072 |
"resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
|
@@ -5356,6 +5629,14 @@
|
|
5356 |
"node": ">=0.10.0"
|
5357 |
}
|
5358 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5359 |
"node_modules/is-glob": {
|
5360 |
"version": "4.0.3",
|
5361 |
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
@@ -5373,6 +5654,11 @@
|
|
5373 |
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
5374 |
"dev": true
|
5375 |
},
|
|
|
|
|
|
|
|
|
|
|
5376 |
"node_modules/is-number": {
|
5377 |
"version": "7.0.0",
|
5378 |
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
@@ -6101,6 +6387,77 @@
|
|
6101 |
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
6102 |
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
6103 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6104 |
"node_modules/mz": {
|
6105 |
"version": "2.7.0",
|
6106 |
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
@@ -6233,8 +6590,6 @@
|
|
6233 |
"version": "4.6.1",
|
6234 |
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz",
|
6235 |
"integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==",
|
6236 |
-
"optional": true,
|
6237 |
-
"peer": true,
|
6238 |
"bin": {
|
6239 |
"node-gyp-build": "bin.js",
|
6240 |
"node-gyp-build-optional": "optional.js",
|
@@ -6473,6 +6828,11 @@
|
|
6473 |
"node": ">= 0.8.0"
|
6474 |
}
|
6475 |
},
|
|
|
|
|
|
|
|
|
|
|
6476 |
"node_modules/p-limit": {
|
6477 |
"version": "3.1.0",
|
6478 |
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
@@ -6866,11 +7226,11 @@
|
|
6866 |
"integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="
|
6867 |
},
|
6868 |
"node_modules/playwright": {
|
6869 |
-
"version": "1.
|
6870 |
-
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.
|
6871 |
-
"integrity": "sha512-
|
6872 |
"dependencies": {
|
6873 |
-
"playwright-core": "1.
|
6874 |
},
|
6875 |
"bin": {
|
6876 |
"playwright": "cli.js"
|
@@ -6906,6 +7266,17 @@
|
|
6906 |
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
6907 |
}
|
6908 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6909 |
"node_modules/postcss": {
|
6910 |
"version": "8.4.35",
|
6911 |
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
@@ -7542,6 +7913,14 @@
|
|
7542 |
"node": ">= 12.13.0"
|
7543 |
}
|
7544 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7545 |
"node_modules/requires-port": {
|
7546 |
"version": "1.0.0",
|
7547 |
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
@@ -7783,6 +8162,14 @@
|
|
7783 |
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
|
7784 |
"integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
|
7785 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7786 |
"node_modules/semver": {
|
7787 |
"version": "7.6.2",
|
7788 |
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
|
@@ -7885,9 +8272,9 @@
|
|
7885 |
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
|
7886 |
},
|
7887 |
"node_modules/sharp": {
|
7888 |
-
"version": "0.33.
|
7889 |
-
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.
|
7890 |
-
"integrity": "sha512-
|
7891 |
"hasInstallScript": true,
|
7892 |
"dependencies": {
|
7893 |
"color": "^4.2.3",
|
@@ -7902,8 +8289,8 @@
|
|
7902 |
"url": "https://opencollective.com/libvips"
|
7903 |
},
|
7904 |
"optionalDependencies": {
|
7905 |
-
"@img/sharp-darwin-arm64": "0.33.
|
7906 |
-
"@img/sharp-darwin-x64": "0.33.
|
7907 |
"@img/sharp-libvips-darwin-arm64": "1.0.2",
|
7908 |
"@img/sharp-libvips-darwin-x64": "1.0.2",
|
7909 |
"@img/sharp-libvips-linux-arm": "1.0.2",
|
@@ -7912,15 +8299,15 @@
|
|
7912 |
"@img/sharp-libvips-linux-x64": "1.0.2",
|
7913 |
"@img/sharp-libvips-linuxmusl-arm64": "1.0.2",
|
7914 |
"@img/sharp-libvips-linuxmusl-x64": "1.0.2",
|
7915 |
-
"@img/sharp-linux-arm": "0.33.
|
7916 |
-
"@img/sharp-linux-arm64": "0.33.
|
7917 |
-
"@img/sharp-linux-s390x": "0.33.
|
7918 |
-
"@img/sharp-linux-x64": "0.33.
|
7919 |
-
"@img/sharp-linuxmusl-arm64": "0.33.
|
7920 |
-
"@img/sharp-linuxmusl-x64": "0.33.
|
7921 |
-
"@img/sharp-wasm32": "0.33.
|
7922 |
-
"@img/sharp-win32-ia32": "0.33.
|
7923 |
-
"@img/sharp-win32-x64": "0.33.
|
7924 |
}
|
7925 |
},
|
7926 |
"node_modules/shebang-command": {
|
@@ -8163,6 +8550,11 @@
|
|
8163 |
"queue-tick": "^1.0.1"
|
8164 |
}
|
8165 |
},
|
|
|
|
|
|
|
|
|
|
|
8166 |
"node_modules/string_decoder": {
|
8167 |
"version": "1.3.0",
|
8168 |
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
@@ -8171,6 +8563,24 @@
|
|
8171 |
"safe-buffer": "~5.2.0"
|
8172 |
}
|
8173 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8174 |
"node_modules/string.prototype.codepointat": {
|
8175 |
"version": "0.2.1",
|
8176 |
"resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
|
@@ -8180,7 +8590,6 @@
|
|
8180 |
"version": "6.0.1",
|
8181 |
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
8182 |
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
8183 |
-
"dev": true,
|
8184 |
"dependencies": {
|
8185 |
"ansi-regex": "^5.0.1"
|
8186 |
},
|
@@ -8292,7 +8701,6 @@
|
|
8292 |
"version": "7.2.0",
|
8293 |
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
8294 |
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
8295 |
-
"dev": true,
|
8296 |
"dependencies": {
|
8297 |
"has-flag": "^4.0.0"
|
8298 |
},
|
@@ -8952,7 +9360,6 @@
|
|
8952 |
"version": "5.2.2",
|
8953 |
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
8954 |
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
8955 |
-
"devOptional": true,
|
8956 |
"bin": {
|
8957 |
"tsc": "bin/tsc",
|
8958 |
"tsserver": "bin/tsserver"
|
@@ -8995,6 +9402,11 @@
|
|
8995 |
"node": ">=14.0"
|
8996 |
}
|
8997 |
},
|
|
|
|
|
|
|
|
|
|
|
8998 |
"node_modules/unicode-trie": {
|
8999 |
"version": "2.0.0",
|
9000 |
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
@@ -9960,6 +10372,19 @@
|
|
9960 |
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
9961 |
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="
|
9962 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9963 |
"node_modules/wrappy": {
|
9964 |
"version": "1.0.2",
|
9965 |
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
@@ -9998,6 +10423,14 @@
|
|
9998 |
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
9999 |
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
10000 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10001 |
"node_modules/yallist": {
|
10002 |
"version": "4.0.0",
|
10003 |
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
@@ -10012,6 +10445,31 @@
|
|
10012 |
"node": ">= 6"
|
10013 |
}
|
10014 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10015 |
"node_modules/yn": {
|
10016 |
"version": "3.1.1",
|
10017 |
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
|
|
9 |
"version": "0.8.4",
|
10 |
"dependencies": {
|
11 |
"@cliqz/adblocker-playwright": "^1.27.2",
|
12 |
+
"@gradio/client": "^0.19.4",
|
13 |
"@huggingface/hub": "^0.5.1",
|
14 |
+
"@huggingface/inference": "^2.7.0",
|
15 |
"@iconify-json/bi": "^1.1.21",
|
16 |
"@playwright/browser-chromium": "^1.43.1",
|
17 |
"@resvg/resvg-js": "^2.6.2",
|
|
|
43 |
"satori-html": "^0.3.2",
|
44 |
"sbd": "^1.0.19",
|
45 |
"serpapi": "^1.1.1",
|
46 |
+
"sharp": "^0.33.4",
|
47 |
"tailwind-scrollbar": "^3.0.0",
|
48 |
"tailwindcss": "^3.4.0",
|
49 |
"uuid": "^9.0.1",
|
|
|
175 |
"google-auth-library": "^9.4.2"
|
176 |
}
|
177 |
},
|
178 |
+
"node_modules/@bundled-es-modules/cookie": {
|
179 |
+
"version": "2.0.0",
|
180 |
+
"resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz",
|
181 |
+
"integrity": "sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==",
|
182 |
+
"dependencies": {
|
183 |
+
"cookie": "^0.5.0"
|
184 |
+
}
|
185 |
+
},
|
186 |
+
"node_modules/@bundled-es-modules/statuses": {
|
187 |
+
"version": "1.0.1",
|
188 |
+
"resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz",
|
189 |
+
"integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==",
|
190 |
+
"dependencies": {
|
191 |
+
"statuses": "^2.0.1"
|
192 |
+
}
|
193 |
+
},
|
194 |
"node_modules/@cliqz/adblocker": {
|
195 |
"version": "1.27.2",
|
196 |
"resolved": "https://registry.npmjs.org/@cliqz/adblocker/-/adblocker-1.27.2.tgz",
|
|
|
723 |
"node": ">=18.0.0"
|
724 |
}
|
725 |
},
|
726 |
+
"node_modules/@gradio/client": {
|
727 |
+
"version": "0.19.4",
|
728 |
+
"resolved": "https://registry.npmjs.org/@gradio/client/-/client-0.19.4.tgz",
|
729 |
+
"integrity": "sha512-O7bSkgoGL7Fe180UTB9IF9ZlIMdiIhWkInE22NDCsH3Lyt7QdOxDSRKZUEYTPELUIBrejWiuQ1ADNJQzDTBvBg==",
|
730 |
+
"dependencies": {
|
731 |
+
"@types/eventsource": "^1.1.15",
|
732 |
+
"bufferutil": "^4.0.7",
|
733 |
+
"eventsource": "^2.0.2",
|
734 |
+
"msw": "^2.2.1",
|
735 |
+
"semiver": "^1.1.0",
|
736 |
+
"typescript": "^5.0.0",
|
737 |
+
"ws": "^8.13.0"
|
738 |
+
},
|
739 |
+
"engines": {
|
740 |
+
"node": ">=18.0.0"
|
741 |
+
}
|
742 |
+
},
|
743 |
"node_modules/@huggingface/hub": {
|
744 |
"version": "0.5.1",
|
745 |
"resolved": "https://registry.npmjs.org/@huggingface/hub/-/hub-0.5.1.tgz",
|
|
|
752 |
}
|
753 |
},
|
754 |
"node_modules/@huggingface/inference": {
|
755 |
+
"version": "2.7.0",
|
756 |
+
"resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-2.7.0.tgz",
|
757 |
+
"integrity": "sha512-u7Fn637Q3f7nUB1tajM4CgzhvoFQkOQr5W5Fm+2wT9ETgGoLBh25BLlYPTJRjAd2WY01s71v0lqAwNvHHCc3mg==",
|
758 |
+
"dependencies": {
|
759 |
+
"@huggingface/tasks": "^0.10.0"
|
760 |
+
},
|
761 |
"engines": {
|
762 |
"node": ">=18"
|
763 |
}
|
|
|
770 |
"node": ">=18"
|
771 |
}
|
772 |
},
|
773 |
+
"node_modules/@huggingface/tasks": {
|
774 |
+
"version": "0.10.8",
|
775 |
+
"resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.10.8.tgz",
|
776 |
+
"integrity": "sha512-oIp9912FwByyyyxkB/CIiW203QxPeYzBG7dydLmqZdcW0ma0if1uklGumqkJ6y/rJlv7AR/jJ9wbee0Wl5YZTw=="
|
777 |
+
},
|
778 |
"node_modules/@humanwhocodes/config-array": {
|
779 |
"version": "0.11.8",
|
780 |
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
|
|
854 |
}
|
855 |
},
|
856 |
"node_modules/@img/sharp-darwin-arm64": {
|
857 |
+
"version": "0.33.4",
|
858 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz",
|
859 |
+
"integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==",
|
860 |
"cpu": [
|
861 |
"arm64"
|
862 |
],
|
|
|
879 |
}
|
880 |
},
|
881 |
"node_modules/@img/sharp-darwin-x64": {
|
882 |
+
"version": "0.33.4",
|
883 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz",
|
884 |
+
"integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==",
|
885 |
"cpu": [
|
886 |
"x64"
|
887 |
],
|
|
|
1072 |
}
|
1073 |
},
|
1074 |
"node_modules/@img/sharp-linux-arm": {
|
1075 |
+
"version": "0.33.4",
|
1076 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz",
|
1077 |
+
"integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==",
|
1078 |
"cpu": [
|
1079 |
"arm"
|
1080 |
],
|
|
|
1097 |
}
|
1098 |
},
|
1099 |
"node_modules/@img/sharp-linux-arm64": {
|
1100 |
+
"version": "0.33.4",
|
1101 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz",
|
1102 |
+
"integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==",
|
1103 |
"cpu": [
|
1104 |
"arm64"
|
1105 |
],
|
|
|
1122 |
}
|
1123 |
},
|
1124 |
"node_modules/@img/sharp-linux-s390x": {
|
1125 |
+
"version": "0.33.4",
|
1126 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz",
|
1127 |
+
"integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==",
|
1128 |
"cpu": [
|
1129 |
"s390x"
|
1130 |
],
|
|
|
1133 |
"linux"
|
1134 |
],
|
1135 |
"engines": {
|
1136 |
+
"glibc": ">=2.31",
|
1137 |
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
1138 |
"npm": ">=9.6.5",
|
1139 |
"pnpm": ">=7.1.0",
|
|
|
1147 |
}
|
1148 |
},
|
1149 |
"node_modules/@img/sharp-linux-x64": {
|
1150 |
+
"version": "0.33.4",
|
1151 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz",
|
1152 |
+
"integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==",
|
1153 |
"cpu": [
|
1154 |
"x64"
|
1155 |
],
|
|
|
1172 |
}
|
1173 |
},
|
1174 |
"node_modules/@img/sharp-linuxmusl-arm64": {
|
1175 |
+
"version": "0.33.4",
|
1176 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz",
|
1177 |
+
"integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==",
|
1178 |
"cpu": [
|
1179 |
"arm64"
|
1180 |
],
|
|
|
1197 |
}
|
1198 |
},
|
1199 |
"node_modules/@img/sharp-linuxmusl-x64": {
|
1200 |
+
"version": "0.33.4",
|
1201 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz",
|
1202 |
+
"integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==",
|
1203 |
"cpu": [
|
1204 |
"x64"
|
1205 |
],
|
|
|
1222 |
}
|
1223 |
},
|
1224 |
"node_modules/@img/sharp-wasm32": {
|
1225 |
+
"version": "0.33.4",
|
1226 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz",
|
1227 |
+
"integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==",
|
1228 |
"cpu": [
|
1229 |
"wasm32"
|
1230 |
],
|
1231 |
"optional": true,
|
1232 |
"dependencies": {
|
1233 |
+
"@emnapi/runtime": "^1.1.1"
|
1234 |
},
|
1235 |
"engines": {
|
1236 |
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
|
|
1243 |
}
|
1244 |
},
|
1245 |
"node_modules/@img/sharp-win32-ia32": {
|
1246 |
+
"version": "0.33.4",
|
1247 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz",
|
1248 |
+
"integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==",
|
1249 |
"cpu": [
|
1250 |
"ia32"
|
1251 |
],
|
|
|
1264 |
}
|
1265 |
},
|
1266 |
"node_modules/@img/sharp-win32-x64": {
|
1267 |
+
"version": "0.33.4",
|
1268 |
+
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz",
|
1269 |
+
"integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==",
|
1270 |
"cpu": [
|
1271 |
"x64"
|
1272 |
],
|
|
|
1284 |
"url": "https://opencollective.com/libvips"
|
1285 |
}
|
1286 |
},
|
1287 |
+
"node_modules/@inquirer/confirm": {
|
1288 |
+
"version": "3.1.7",
|
1289 |
+
"resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.7.tgz",
|
1290 |
+
"integrity": "sha512-BZjjj19W8gnh5UGFTdP5ZxpgMNRjy03Dzq3k28sB2MDlEUFrcyTkMEoGgvBmGpUw0vNBoCJkTcbHZ3e9tb+d+w==",
|
1291 |
+
"dependencies": {
|
1292 |
+
"@inquirer/core": "^8.2.0",
|
1293 |
+
"@inquirer/type": "^1.3.1"
|
1294 |
+
},
|
1295 |
+
"engines": {
|
1296 |
+
"node": ">=18"
|
1297 |
+
}
|
1298 |
+
},
|
1299 |
+
"node_modules/@inquirer/core": {
|
1300 |
+
"version": "8.2.0",
|
1301 |
+
"resolved": "https://registry.npmjs.org/@inquirer/core/-/core-8.2.0.tgz",
|
1302 |
+
"integrity": "sha512-pexNF9j2orvMMTgoQ/uKOw8V6/R7x/sIDwRwXRhl4i0pPSh6paRzFehpFKpfMbqix1/+gzCekhYTmVbQpWkVjQ==",
|
1303 |
+
"dependencies": {
|
1304 |
+
"@inquirer/figures": "^1.0.1",
|
1305 |
+
"@inquirer/type": "^1.3.1",
|
1306 |
+
"@types/mute-stream": "^0.0.4",
|
1307 |
+
"@types/node": "^20.12.11",
|
1308 |
+
"@types/wrap-ansi": "^3.0.0",
|
1309 |
+
"ansi-escapes": "^4.3.2",
|
1310 |
+
"chalk": "^4.1.2",
|
1311 |
+
"cli-spinners": "^2.9.2",
|
1312 |
+
"cli-width": "^4.1.0",
|
1313 |
+
"mute-stream": "^1.0.0",
|
1314 |
+
"signal-exit": "^4.1.0",
|
1315 |
+
"strip-ansi": "^6.0.1",
|
1316 |
+
"wrap-ansi": "^6.2.0"
|
1317 |
+
},
|
1318 |
+
"engines": {
|
1319 |
+
"node": ">=18"
|
1320 |
+
}
|
1321 |
+
},
|
1322 |
+
"node_modules/@inquirer/core/node_modules/@types/node": {
|
1323 |
+
"version": "20.12.12",
|
1324 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz",
|
1325 |
+
"integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==",
|
1326 |
+
"dependencies": {
|
1327 |
+
"undici-types": "~5.26.4"
|
1328 |
+
}
|
1329 |
+
},
|
1330 |
+
"node_modules/@inquirer/core/node_modules/signal-exit": {
|
1331 |
+
"version": "4.1.0",
|
1332 |
+
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
1333 |
+
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
1334 |
+
"engines": {
|
1335 |
+
"node": ">=14"
|
1336 |
+
},
|
1337 |
+
"funding": {
|
1338 |
+
"url": "https://github.com/sponsors/isaacs"
|
1339 |
+
}
|
1340 |
+
},
|
1341 |
+
"node_modules/@inquirer/figures": {
|
1342 |
+
"version": "1.0.1",
|
1343 |
+
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.1.tgz",
|
1344 |
+
"integrity": "sha512-mtup3wVKia3ZwULPHcbs4Mor8Voi+iIXEWD7wCNbIO6lYR62oPCTQyrddi5OMYVXHzeCSoneZwJuS8sBvlEwDw==",
|
1345 |
+
"engines": {
|
1346 |
+
"node": ">=18"
|
1347 |
+
}
|
1348 |
+
},
|
1349 |
+
"node_modules/@inquirer/type": {
|
1350 |
+
"version": "1.3.1",
|
1351 |
+
"resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.3.1.tgz",
|
1352 |
+
"integrity": "sha512-Pe3PFccjPVJV1vtlfVvm9OnlbxqdnP5QcscFEFEnK5quChf1ufZtM0r8mR5ToWHMxZOh0s8o/qp9ANGRTo/DAw==",
|
1353 |
+
"engines": {
|
1354 |
+
"node": ">=18"
|
1355 |
+
}
|
1356 |
+
},
|
1357 |
"node_modules/@jridgewell/gen-mapping": {
|
1358 |
"version": "0.3.3",
|
1359 |
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
|
|
1406 |
"sparse-bitfield": "^3.0.3"
|
1407 |
}
|
1408 |
},
|
1409 |
+
"node_modules/@mswjs/cookies": {
|
1410 |
+
"version": "1.1.0",
|
1411 |
+
"resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-1.1.0.tgz",
|
1412 |
+
"integrity": "sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==",
|
1413 |
+
"engines": {
|
1414 |
+
"node": ">=18"
|
1415 |
+
}
|
1416 |
+
},
|
1417 |
+
"node_modules/@mswjs/interceptors": {
|
1418 |
+
"version": "0.29.1",
|
1419 |
+
"resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.29.1.tgz",
|
1420 |
+
"integrity": "sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==",
|
1421 |
+
"dependencies": {
|
1422 |
+
"@open-draft/deferred-promise": "^2.2.0",
|
1423 |
+
"@open-draft/logger": "^0.3.0",
|
1424 |
+
"@open-draft/until": "^2.0.0",
|
1425 |
+
"is-node-process": "^1.2.0",
|
1426 |
+
"outvariant": "^1.2.1",
|
1427 |
+
"strict-event-emitter": "^0.5.1"
|
1428 |
+
},
|
1429 |
+
"engines": {
|
1430 |
+
"node": ">=18"
|
1431 |
+
}
|
1432 |
+
},
|
1433 |
"node_modules/@nodelib/fs.scandir": {
|
1434 |
"version": "2.1.5",
|
1435 |
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
|
|
1462 |
"node": ">= 8"
|
1463 |
}
|
1464 |
},
|
1465 |
+
"node_modules/@open-draft/deferred-promise": {
|
1466 |
+
"version": "2.2.0",
|
1467 |
+
"resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz",
|
1468 |
+
"integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA=="
|
1469 |
+
},
|
1470 |
+
"node_modules/@open-draft/logger": {
|
1471 |
+
"version": "0.3.0",
|
1472 |
+
"resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz",
|
1473 |
+
"integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==",
|
1474 |
+
"dependencies": {
|
1475 |
+
"is-node-process": "^1.2.0",
|
1476 |
+
"outvariant": "^1.4.0"
|
1477 |
+
}
|
1478 |
+
},
|
1479 |
+
"node_modules/@open-draft/until": {
|
1480 |
+
"version": "2.1.0",
|
1481 |
+
"resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz",
|
1482 |
+
"integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="
|
1483 |
+
},
|
1484 |
"node_modules/@opentelemetry/api": {
|
1485 |
"version": "1.8.0",
|
1486 |
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz",
|
|
|
2323 |
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
2324 |
"dev": true
|
2325 |
},
|
2326 |
+
"node_modules/@types/eventsource": {
|
2327 |
+
"version": "1.1.15",
|
2328 |
+
"resolved": "https://registry.npmjs.org/@types/eventsource/-/eventsource-1.1.15.tgz",
|
2329 |
+
"integrity": "sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA=="
|
2330 |
+
},
|
2331 |
"node_modules/@types/express": {
|
2332 |
"version": "4.17.21",
|
2333 |
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
|
|
|
2426 |
"integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
|
2427 |
"dev": true
|
2428 |
},
|
2429 |
+
"node_modules/@types/mute-stream": {
|
2430 |
+
"version": "0.0.4",
|
2431 |
+
"resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz",
|
2432 |
+
"integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==",
|
2433 |
+
"dependencies": {
|
2434 |
+
"@types/node": "*"
|
2435 |
+
}
|
2436 |
+
},
|
2437 |
"node_modules/@types/node": {
|
2438 |
"version": "18.13.0",
|
2439 |
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz",
|
|
|
2524 |
"@types/send": "*"
|
2525 |
}
|
2526 |
},
|
2527 |
+
"node_modules/@types/statuses": {
|
2528 |
+
"version": "2.0.5",
|
2529 |
+
"resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.5.tgz",
|
2530 |
+
"integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A=="
|
2531 |
+
},
|
2532 |
"node_modules/@types/tough-cookie": {
|
2533 |
"version": "4.0.2",
|
2534 |
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
|
|
|
2555 |
"@types/webidl-conversions": "*"
|
2556 |
}
|
2557 |
},
|
2558 |
+
"node_modules/@types/wrap-ansi": {
|
2559 |
+
"version": "3.0.0",
|
2560 |
+
"resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz",
|
2561 |
+
"integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g=="
|
2562 |
+
},
|
2563 |
"node_modules/@typescript-eslint/eslint-plugin": {
|
2564 |
"version": "6.7.4",
|
2565 |
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz",
|
|
|
2977 |
"url": "https://github.com/sponsors/epoberezkin"
|
2978 |
}
|
2979 |
},
|
2980 |
+
"node_modules/ansi-escapes": {
|
2981 |
+
"version": "4.3.2",
|
2982 |
+
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
2983 |
+
"integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
|
2984 |
+
"dependencies": {
|
2985 |
+
"type-fest": "^0.21.3"
|
2986 |
+
},
|
2987 |
+
"engines": {
|
2988 |
+
"node": ">=8"
|
2989 |
+
},
|
2990 |
+
"funding": {
|
2991 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
2992 |
+
}
|
2993 |
+
},
|
2994 |
+
"node_modules/ansi-escapes/node_modules/type-fest": {
|
2995 |
+
"version": "0.21.3",
|
2996 |
+
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
|
2997 |
+
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
|
2998 |
+
"engines": {
|
2999 |
+
"node": ">=10"
|
3000 |
+
},
|
3001 |
+
"funding": {
|
3002 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
3003 |
+
}
|
3004 |
+
},
|
3005 |
"node_modules/ansi-regex": {
|
3006 |
"version": "5.0.1",
|
3007 |
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
3008 |
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
|
|
3009 |
"engines": {
|
3010 |
"node": ">=8"
|
3011 |
}
|
|
|
3014 |
"version": "4.3.0",
|
3015 |
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
3016 |
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
|
|
3017 |
"dependencies": {
|
3018 |
"color-convert": "^2.0.1"
|
3019 |
},
|
|
|
3396 |
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz",
|
3397 |
"integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==",
|
3398 |
"hasInstallScript": true,
|
|
|
|
|
3399 |
"dependencies": {
|
3400 |
"node-gyp-build": "^4.3.0"
|
3401 |
},
|
|
|
3516 |
"version": "4.1.2",
|
3517 |
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
3518 |
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
|
|
3519 |
"dependencies": {
|
3520 |
"ansi-styles": "^4.1.0",
|
3521 |
"supports-color": "^7.1.0"
|
|
|
3587 |
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
3588 |
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
3589 |
},
|
3590 |
+
"node_modules/cli-spinners": {
|
3591 |
+
"version": "2.9.2",
|
3592 |
+
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
|
3593 |
+
"integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
|
3594 |
+
"engines": {
|
3595 |
+
"node": ">=6"
|
3596 |
+
},
|
3597 |
+
"funding": {
|
3598 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
3599 |
+
}
|
3600 |
+
},
|
3601 |
+
"node_modules/cli-width": {
|
3602 |
+
"version": "4.1.0",
|
3603 |
+
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
|
3604 |
+
"integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
|
3605 |
+
"engines": {
|
3606 |
+
"node": ">= 12"
|
3607 |
+
}
|
3608 |
+
},
|
3609 |
+
"node_modules/cliui": {
|
3610 |
+
"version": "8.0.1",
|
3611 |
+
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
3612 |
+
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
3613 |
+
"dependencies": {
|
3614 |
+
"string-width": "^4.2.0",
|
3615 |
+
"strip-ansi": "^6.0.1",
|
3616 |
+
"wrap-ansi": "^7.0.0"
|
3617 |
+
},
|
3618 |
+
"engines": {
|
3619 |
+
"node": ">=12"
|
3620 |
+
}
|
3621 |
+
},
|
3622 |
+
"node_modules/cliui/node_modules/wrap-ansi": {
|
3623 |
+
"version": "7.0.0",
|
3624 |
+
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
3625 |
+
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
3626 |
+
"dependencies": {
|
3627 |
+
"ansi-styles": "^4.0.0",
|
3628 |
+
"string-width": "^4.1.0",
|
3629 |
+
"strip-ansi": "^6.0.0"
|
3630 |
+
},
|
3631 |
+
"engines": {
|
3632 |
+
"node": ">=10"
|
3633 |
+
},
|
3634 |
+
"funding": {
|
3635 |
+
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
3636 |
+
}
|
3637 |
+
},
|
3638 |
"node_modules/code-red": {
|
3639 |
"version": "1.0.4",
|
3640 |
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
|
|
|
3784 |
"version": "0.5.0",
|
3785 |
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
3786 |
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
|
|
3787 |
"engines": {
|
3788 |
"node": ">= 0.6"
|
3789 |
}
|
|
|
4596 |
"node": ">=0.8.x"
|
4597 |
}
|
4598 |
},
|
4599 |
+
"node_modules/eventsource": {
|
4600 |
+
"version": "2.0.2",
|
4601 |
+
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
|
4602 |
+
"integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==",
|
4603 |
+
"engines": {
|
4604 |
+
"node": ">=12.0.0"
|
4605 |
+
}
|
4606 |
+
},
|
4607 |
"node_modules/execa": {
|
4608 |
"version": "5.1.1",
|
4609 |
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
|
|
5056 |
"node": ">=14"
|
5057 |
}
|
5058 |
},
|
5059 |
+
"node_modules/get-caller-file": {
|
5060 |
+
"version": "2.0.5",
|
5061 |
+
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
5062 |
+
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
5063 |
+
"engines": {
|
5064 |
+
"node": "6.* || 8.* || >= 10.*"
|
5065 |
+
}
|
5066 |
+
},
|
5067 |
"node_modules/get-func-name": {
|
5068 |
"version": "2.0.2",
|
5069 |
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
|
|
|
5232 |
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
|
5233 |
"dev": true
|
5234 |
},
|
5235 |
+
"node_modules/graphql": {
|
5236 |
+
"version": "16.8.1",
|
5237 |
+
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
|
5238 |
+
"integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
|
5239 |
+
"engines": {
|
5240 |
+
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
5241 |
+
}
|
5242 |
+
},
|
5243 |
"node_modules/gtoken": {
|
5244 |
"version": "7.1.0",
|
5245 |
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
|
|
|
5282 |
"version": "4.0.0",
|
5283 |
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
5284 |
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
|
|
5285 |
"engines": {
|
5286 |
"node": ">=8"
|
5287 |
}
|
|
|
5335 |
"node": ">= 0.4"
|
5336 |
}
|
5337 |
},
|
5338 |
+
"node_modules/headers-polyfill": {
|
5339 |
+
"version": "4.0.3",
|
5340 |
+
"resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz",
|
5341 |
+
"integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ=="
|
5342 |
+
},
|
5343 |
"node_modules/help-me": {
|
5344 |
"version": "5.0.0",
|
5345 |
"resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
|
|
|
5629 |
"node": ">=0.10.0"
|
5630 |
}
|
5631 |
},
|
5632 |
+
"node_modules/is-fullwidth-code-point": {
|
5633 |
+
"version": "3.0.0",
|
5634 |
+
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
5635 |
+
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
5636 |
+
"engines": {
|
5637 |
+
"node": ">=8"
|
5638 |
+
}
|
5639 |
+
},
|
5640 |
"node_modules/is-glob": {
|
5641 |
"version": "4.0.3",
|
5642 |
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
|
|
5654 |
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
5655 |
"dev": true
|
5656 |
},
|
5657 |
+
"node_modules/is-node-process": {
|
5658 |
+
"version": "1.2.0",
|
5659 |
+
"resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
|
5660 |
+
"integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw=="
|
5661 |
+
},
|
5662 |
"node_modules/is-number": {
|
5663 |
"version": "7.0.0",
|
5664 |
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
|
|
6387 |
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
6388 |
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
6389 |
},
|
6390 |
+
"node_modules/msw": {
|
6391 |
+
"version": "2.3.0",
|
6392 |
+
"resolved": "https://registry.npmjs.org/msw/-/msw-2.3.0.tgz",
|
6393 |
+
"integrity": "sha512-cDr1q/QTMzaWhY8n9lpGhceY209k29UZtdTgJ3P8Bzne3TSMchX2EM/ldvn4ATLOktpCefCU2gcEgzHc31GTPw==",
|
6394 |
+
"hasInstallScript": true,
|
6395 |
+
"dependencies": {
|
6396 |
+
"@bundled-es-modules/cookie": "^2.0.0",
|
6397 |
+
"@bundled-es-modules/statuses": "^1.0.1",
|
6398 |
+
"@inquirer/confirm": "^3.0.0",
|
6399 |
+
"@mswjs/cookies": "^1.1.0",
|
6400 |
+
"@mswjs/interceptors": "^0.29.0",
|
6401 |
+
"@open-draft/until": "^2.1.0",
|
6402 |
+
"@types/cookie": "^0.6.0",
|
6403 |
+
"@types/statuses": "^2.0.4",
|
6404 |
+
"chalk": "^4.1.2",
|
6405 |
+
"graphql": "^16.8.1",
|
6406 |
+
"headers-polyfill": "^4.0.2",
|
6407 |
+
"is-node-process": "^1.2.0",
|
6408 |
+
"outvariant": "^1.4.2",
|
6409 |
+
"path-to-regexp": "^6.2.0",
|
6410 |
+
"strict-event-emitter": "^0.5.1",
|
6411 |
+
"type-fest": "^4.9.0",
|
6412 |
+
"yargs": "^17.7.2"
|
6413 |
+
},
|
6414 |
+
"bin": {
|
6415 |
+
"msw": "cli/index.js"
|
6416 |
+
},
|
6417 |
+
"engines": {
|
6418 |
+
"node": ">=18"
|
6419 |
+
},
|
6420 |
+
"funding": {
|
6421 |
+
"url": "https://github.com/sponsors/mswjs"
|
6422 |
+
},
|
6423 |
+
"peerDependencies": {
|
6424 |
+
"typescript": ">= 4.7.x"
|
6425 |
+
},
|
6426 |
+
"peerDependenciesMeta": {
|
6427 |
+
"typescript": {
|
6428 |
+
"optional": true
|
6429 |
+
}
|
6430 |
+
}
|
6431 |
+
},
|
6432 |
+
"node_modules/msw/node_modules/@types/cookie": {
|
6433 |
+
"version": "0.6.0",
|
6434 |
+
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
6435 |
+
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
|
6436 |
+
},
|
6437 |
+
"node_modules/msw/node_modules/path-to-regexp": {
|
6438 |
+
"version": "6.2.2",
|
6439 |
+
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz",
|
6440 |
+
"integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw=="
|
6441 |
+
},
|
6442 |
+
"node_modules/msw/node_modules/type-fest": {
|
6443 |
+
"version": "4.18.2",
|
6444 |
+
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.2.tgz",
|
6445 |
+
"integrity": "sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==",
|
6446 |
+
"engines": {
|
6447 |
+
"node": ">=16"
|
6448 |
+
},
|
6449 |
+
"funding": {
|
6450 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
6451 |
+
}
|
6452 |
+
},
|
6453 |
+
"node_modules/mute-stream": {
|
6454 |
+
"version": "1.0.0",
|
6455 |
+
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz",
|
6456 |
+
"integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==",
|
6457 |
+
"engines": {
|
6458 |
+
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
6459 |
+
}
|
6460 |
+
},
|
6461 |
"node_modules/mz": {
|
6462 |
"version": "2.7.0",
|
6463 |
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
|
|
6590 |
"version": "4.6.1",
|
6591 |
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz",
|
6592 |
"integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==",
|
|
|
|
|
6593 |
"bin": {
|
6594 |
"node-gyp-build": "bin.js",
|
6595 |
"node-gyp-build-optional": "optional.js",
|
|
|
6828 |
"node": ">= 0.8.0"
|
6829 |
}
|
6830 |
},
|
6831 |
+
"node_modules/outvariant": {
|
6832 |
+
"version": "1.4.2",
|
6833 |
+
"resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.2.tgz",
|
6834 |
+
"integrity": "sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ=="
|
6835 |
+
},
|
6836 |
"node_modules/p-limit": {
|
6837 |
"version": "3.1.0",
|
6838 |
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
|
|
7226 |
"integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="
|
7227 |
},
|
7228 |
"node_modules/playwright": {
|
7229 |
+
"version": "1.40.0",
|
7230 |
+
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.0.tgz",
|
7231 |
+
"integrity": "sha512-gyHAgQjiDf1m34Xpwzaqb76KgfzYrhK7iih+2IzcOCoZWr/8ZqmdBw+t0RU85ZmfJMgtgAiNtBQ/KS2325INXw==",
|
7232 |
"dependencies": {
|
7233 |
+
"playwright-core": "1.40.0"
|
7234 |
},
|
7235 |
"bin": {
|
7236 |
"playwright": "cli.js"
|
|
|
7266 |
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
7267 |
}
|
7268 |
},
|
7269 |
+
"node_modules/playwright/node_modules/playwright-core": {
|
7270 |
+
"version": "1.40.0",
|
7271 |
+
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.0.tgz",
|
7272 |
+
"integrity": "sha512-fvKewVJpGeca8t0ipM56jkVSU6Eo0RmFvQ/MaCQNDYm+sdvKkMBBWTE1FdeMqIdumRaXXjZChWHvIzCGM/tA/Q==",
|
7273 |
+
"bin": {
|
7274 |
+
"playwright-core": "cli.js"
|
7275 |
+
},
|
7276 |
+
"engines": {
|
7277 |
+
"node": ">=16"
|
7278 |
+
}
|
7279 |
+
},
|
7280 |
"node_modules/postcss": {
|
7281 |
"version": "8.4.35",
|
7282 |
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
|
|
7913 |
"node": ">= 12.13.0"
|
7914 |
}
|
7915 |
},
|
7916 |
+
"node_modules/require-directory": {
|
7917 |
+
"version": "2.1.1",
|
7918 |
+
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
7919 |
+
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
7920 |
+
"engines": {
|
7921 |
+
"node": ">=0.10.0"
|
7922 |
+
}
|
7923 |
+
},
|
7924 |
"node_modules/requires-port": {
|
7925 |
"version": "1.0.0",
|
7926 |
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
|
|
8162 |
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
|
8163 |
"integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
|
8164 |
},
|
8165 |
+
"node_modules/semiver": {
|
8166 |
+
"version": "1.1.0",
|
8167 |
+
"resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz",
|
8168 |
+
"integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==",
|
8169 |
+
"engines": {
|
8170 |
+
"node": ">=6"
|
8171 |
+
}
|
8172 |
+
},
|
8173 |
"node_modules/semver": {
|
8174 |
"version": "7.6.2",
|
8175 |
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
|
|
|
8272 |
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
|
8273 |
},
|
8274 |
"node_modules/sharp": {
|
8275 |
+
"version": "0.33.4",
|
8276 |
+
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz",
|
8277 |
+
"integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==",
|
8278 |
"hasInstallScript": true,
|
8279 |
"dependencies": {
|
8280 |
"color": "^4.2.3",
|
|
|
8289 |
"url": "https://opencollective.com/libvips"
|
8290 |
},
|
8291 |
"optionalDependencies": {
|
8292 |
+
"@img/sharp-darwin-arm64": "0.33.4",
|
8293 |
+
"@img/sharp-darwin-x64": "0.33.4",
|
8294 |
"@img/sharp-libvips-darwin-arm64": "1.0.2",
|
8295 |
"@img/sharp-libvips-darwin-x64": "1.0.2",
|
8296 |
"@img/sharp-libvips-linux-arm": "1.0.2",
|
|
|
8299 |
"@img/sharp-libvips-linux-x64": "1.0.2",
|
8300 |
"@img/sharp-libvips-linuxmusl-arm64": "1.0.2",
|
8301 |
"@img/sharp-libvips-linuxmusl-x64": "1.0.2",
|
8302 |
+
"@img/sharp-linux-arm": "0.33.4",
|
8303 |
+
"@img/sharp-linux-arm64": "0.33.4",
|
8304 |
+
"@img/sharp-linux-s390x": "0.33.4",
|
8305 |
+
"@img/sharp-linux-x64": "0.33.4",
|
8306 |
+
"@img/sharp-linuxmusl-arm64": "0.33.4",
|
8307 |
+
"@img/sharp-linuxmusl-x64": "0.33.4",
|
8308 |
+
"@img/sharp-wasm32": "0.33.4",
|
8309 |
+
"@img/sharp-win32-ia32": "0.33.4",
|
8310 |
+
"@img/sharp-win32-x64": "0.33.4"
|
8311 |
}
|
8312 |
},
|
8313 |
"node_modules/shebang-command": {
|
|
|
8550 |
"queue-tick": "^1.0.1"
|
8551 |
}
|
8552 |
},
|
8553 |
+
"node_modules/strict-event-emitter": {
|
8554 |
+
"version": "0.5.1",
|
8555 |
+
"resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz",
|
8556 |
+
"integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ=="
|
8557 |
+
},
|
8558 |
"node_modules/string_decoder": {
|
8559 |
"version": "1.3.0",
|
8560 |
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
|
|
8563 |
"safe-buffer": "~5.2.0"
|
8564 |
}
|
8565 |
},
|
8566 |
+
"node_modules/string-width": {
|
8567 |
+
"version": "4.2.3",
|
8568 |
+
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
8569 |
+
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
8570 |
+
"dependencies": {
|
8571 |
+
"emoji-regex": "^8.0.0",
|
8572 |
+
"is-fullwidth-code-point": "^3.0.0",
|
8573 |
+
"strip-ansi": "^6.0.1"
|
8574 |
+
},
|
8575 |
+
"engines": {
|
8576 |
+
"node": ">=8"
|
8577 |
+
}
|
8578 |
+
},
|
8579 |
+
"node_modules/string-width/node_modules/emoji-regex": {
|
8580 |
+
"version": "8.0.0",
|
8581 |
+
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
8582 |
+
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
8583 |
+
},
|
8584 |
"node_modules/string.prototype.codepointat": {
|
8585 |
"version": "0.2.1",
|
8586 |
"resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
|
|
|
8590 |
"version": "6.0.1",
|
8591 |
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
8592 |
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
|
|
8593 |
"dependencies": {
|
8594 |
"ansi-regex": "^5.0.1"
|
8595 |
},
|
|
|
8701 |
"version": "7.2.0",
|
8702 |
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
8703 |
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
|
|
8704 |
"dependencies": {
|
8705 |
"has-flag": "^4.0.0"
|
8706 |
},
|
|
|
9360 |
"version": "5.2.2",
|
9361 |
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
9362 |
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
|
|
9363 |
"bin": {
|
9364 |
"tsc": "bin/tsc",
|
9365 |
"tsserver": "bin/tsserver"
|
|
|
9402 |
"node": ">=14.0"
|
9403 |
}
|
9404 |
},
|
9405 |
+
"node_modules/undici-types": {
|
9406 |
+
"version": "5.26.5",
|
9407 |
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
9408 |
+
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
9409 |
+
},
|
9410 |
"node_modules/unicode-trie": {
|
9411 |
"version": "2.0.0",
|
9412 |
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
|
|
10372 |
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
10373 |
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="
|
10374 |
},
|
10375 |
+
"node_modules/wrap-ansi": {
|
10376 |
+
"version": "6.2.0",
|
10377 |
+
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
10378 |
+
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
10379 |
+
"dependencies": {
|
10380 |
+
"ansi-styles": "^4.0.0",
|
10381 |
+
"string-width": "^4.1.0",
|
10382 |
+
"strip-ansi": "^6.0.0"
|
10383 |
+
},
|
10384 |
+
"engines": {
|
10385 |
+
"node": ">=8"
|
10386 |
+
}
|
10387 |
+
},
|
10388 |
"node_modules/wrappy": {
|
10389 |
"version": "1.0.2",
|
10390 |
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
|
|
10423 |
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
10424 |
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
10425 |
},
|
10426 |
+
"node_modules/y18n": {
|
10427 |
+
"version": "5.0.8",
|
10428 |
+
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
10429 |
+
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
10430 |
+
"engines": {
|
10431 |
+
"node": ">=10"
|
10432 |
+
}
|
10433 |
+
},
|
10434 |
"node_modules/yallist": {
|
10435 |
"version": "4.0.0",
|
10436 |
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
|
10445 |
"node": ">= 6"
|
10446 |
}
|
10447 |
},
|
10448 |
+
"node_modules/yargs": {
|
10449 |
+
"version": "17.7.2",
|
10450 |
+
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
10451 |
+
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
10452 |
+
"dependencies": {
|
10453 |
+
"cliui": "^8.0.1",
|
10454 |
+
"escalade": "^3.1.1",
|
10455 |
+
"get-caller-file": "^2.0.5",
|
10456 |
+
"require-directory": "^2.1.1",
|
10457 |
+
"string-width": "^4.2.3",
|
10458 |
+
"y18n": "^5.0.5",
|
10459 |
+
"yargs-parser": "^21.1.1"
|
10460 |
+
},
|
10461 |
+
"engines": {
|
10462 |
+
"node": ">=12"
|
10463 |
+
}
|
10464 |
+
},
|
10465 |
+
"node_modules/yargs-parser": {
|
10466 |
+
"version": "21.1.1",
|
10467 |
+
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
10468 |
+
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
10469 |
+
"engines": {
|
10470 |
+
"node": ">=12"
|
10471 |
+
}
|
10472 |
+
},
|
10473 |
"node_modules/yn": {
|
10474 |
"version": "3.1.1",
|
10475 |
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
@@ -54,11 +54,12 @@
|
|
54 |
"type": "module",
|
55 |
"dependencies": {
|
56 |
"@cliqz/adblocker-playwright": "^1.27.2",
|
|
|
57 |
"@huggingface/hub": "^0.5.1",
|
58 |
-
"@huggingface/inference": "^2.
|
59 |
"@iconify-json/bi": "^1.1.21",
|
60 |
-
"@resvg/resvg-js": "^2.6.2",
|
61 |
"@playwright/browser-chromium": "^1.43.1",
|
|
|
62 |
"@xenova/transformers": "^2.16.1",
|
63 |
"autoprefixer": "^10.4.14",
|
64 |
"browser-image-resizer": "^2.4.1",
|
@@ -87,7 +88,7 @@
|
|
87 |
"satori-html": "^0.3.2",
|
88 |
"sbd": "^1.0.19",
|
89 |
"serpapi": "^1.1.1",
|
90 |
-
"sharp": "^0.33.
|
91 |
"tailwind-scrollbar": "^3.0.0",
|
92 |
"tailwindcss": "^3.4.0",
|
93 |
"uuid": "^9.0.1",
|
|
|
54 |
"type": "module",
|
55 |
"dependencies": {
|
56 |
"@cliqz/adblocker-playwright": "^1.27.2",
|
57 |
+
"@gradio/client": "^0.19.4",
|
58 |
"@huggingface/hub": "^0.5.1",
|
59 |
+
"@huggingface/inference": "^2.7.0",
|
60 |
"@iconify-json/bi": "^1.1.21",
|
|
|
61 |
"@playwright/browser-chromium": "^1.43.1",
|
62 |
+
"@resvg/resvg-js": "^2.6.2",
|
63 |
"@xenova/transformers": "^2.16.1",
|
64 |
"autoprefixer": "^10.4.14",
|
65 |
"browser-image-resizer": "^2.4.1",
|
|
|
88 |
"satori-html": "^0.3.2",
|
89 |
"sbd": "^1.0.19",
|
90 |
"serpapi": "^1.1.1",
|
91 |
+
"sharp": "^0.33.4",
|
92 |
"tailwind-scrollbar": "^3.0.0",
|
93 |
"tailwindcss": "^3.4.0",
|
94 |
"uuid": "^9.0.1",
|
@@ -1,4 +1,4 @@
|
|
1 |
-
export function clickOutside(element:
|
2 |
function onClick(event: MouseEvent) {
|
3 |
if (!element.contains(event.target as Node)) {
|
4 |
callbackFunction();
|
|
|
1 |
+
export function clickOutside(element: HTMLElement, callbackFunction: () => void) {
|
2 |
function onClick(event: MouseEvent) {
|
3 |
if (!element.contains(event.target as Node)) {
|
4 |
callbackFunction();
|
@@ -1,8 +1,11 @@
|
|
1 |
import type { EndpointParameters } from "./server/endpoints/endpoints";
|
2 |
import type { BackendModel } from "./server/models";
|
|
|
3 |
|
4 |
type buildPromptOptions = Pick<EndpointParameters, "messages" | "preprompt" | "continueMessage"> & {
|
5 |
model: BackendModel;
|
|
|
|
|
6 |
};
|
7 |
|
8 |
export async function buildPrompt({
|
@@ -10,11 +13,18 @@ export async function buildPrompt({
|
|
10 |
model,
|
11 |
preprompt,
|
12 |
continueMessage,
|
|
|
|
|
13 |
}: buildPromptOptions): Promise<string> {
|
14 |
const filteredMessages = messages.filter((m) => m.from !== "system");
|
15 |
|
16 |
let prompt = model
|
17 |
-
.chatPromptRender({
|
|
|
|
|
|
|
|
|
|
|
18 |
// Not super precise, but it's truncated in the model's backend anyway
|
19 |
.split(" ")
|
20 |
.slice(-(model.parameters?.truncate ?? 0))
|
|
|
1 |
import type { EndpointParameters } from "./server/endpoints/endpoints";
|
2 |
import type { BackendModel } from "./server/models";
|
3 |
+
import type { Tool, ToolResult } from "./types/Tool";
|
4 |
|
5 |
type buildPromptOptions = Pick<EndpointParameters, "messages" | "preprompt" | "continueMessage"> & {
|
6 |
model: BackendModel;
|
7 |
+
tools?: Tool[];
|
8 |
+
toolResults?: ToolResult[];
|
9 |
};
|
10 |
|
11 |
export async function buildPrompt({
|
|
|
13 |
model,
|
14 |
preprompt,
|
15 |
continueMessage,
|
16 |
+
tools,
|
17 |
+
toolResults,
|
18 |
}: buildPromptOptions): Promise<string> {
|
19 |
const filteredMessages = messages.filter((m) => m.from !== "system");
|
20 |
|
21 |
let prompt = model
|
22 |
+
.chatPromptRender({
|
23 |
+
messages: filteredMessages,
|
24 |
+
preprompt,
|
25 |
+
tools,
|
26 |
+
toolResults,
|
27 |
+
})
|
28 |
// Not super precise, but it's truncated in the model's backend anyway
|
29 |
.split(" ")
|
30 |
.slice(-(model.parameters?.truncate ?? 0))
|
@@ -1,16 +1,22 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import
|
|
|
|
|
|
|
|
|
3 |
|
4 |
import CarbonError from "~icons/carbon/error-filled";
|
5 |
import EosIconsLoading from "~icons/eos-icons/loading";
|
6 |
import IconInternet from "./icons/IconInternet.svelte";
|
7 |
|
8 |
export let classNames = "";
|
9 |
-
export let webSearchMessages:
|
10 |
|
11 |
-
$: sources = webSearchMessages.find(
|
12 |
-
$: lastMessage = webSearchMessages
|
13 |
-
|
|
|
|
|
14 |
</script>
|
15 |
|
16 |
<details
|
@@ -47,7 +53,7 @@
|
|
47 |
{#if sources}
|
48 |
Completed
|
49 |
{:else}
|
50 |
-
{lastMessage.message}
|
51 |
{/if}
|
52 |
</dt>
|
53 |
</dl>
|
@@ -61,7 +67,7 @@
|
|
61 |
{:else}
|
62 |
<ol>
|
63 |
{#each webSearchMessages as message}
|
64 |
-
{#if message.
|
65 |
<li class="group border-l pb-6 last:!border-transparent last:pb-0 dark:border-gray-800">
|
66 |
<div class="flex items-start">
|
67 |
<div
|
@@ -79,7 +85,7 @@
|
|
79 |
</p>
|
80 |
{/if}
|
81 |
</li>
|
82 |
-
{:else if message.
|
83 |
<li class="group border-l pb-6 last:!border-transparent last:pb-0 dark:border-gray-800">
|
84 |
<div class="flex items-start">
|
85 |
<CarbonError
|
|
|
1 |
<script lang="ts">
|
2 |
+
import {
|
3 |
+
MessageWebSearchUpdateType,
|
4 |
+
type MessageWebSearchUpdate,
|
5 |
+
} from "$lib/types/MessageUpdate";
|
6 |
+
import { isMessageWebSearchSourcesUpdate } from "$lib/utils/messageUpdates";
|
7 |
|
8 |
import CarbonError from "~icons/carbon/error-filled";
|
9 |
import EosIconsLoading from "~icons/eos-icons/loading";
|
10 |
import IconInternet from "./icons/IconInternet.svelte";
|
11 |
|
12 |
export let classNames = "";
|
13 |
+
export let webSearchMessages: MessageWebSearchUpdate[] = [];
|
14 |
|
15 |
+
$: sources = webSearchMessages.find(isMessageWebSearchSourcesUpdate)?.sources;
|
16 |
+
$: lastMessage = webSearchMessages
|
17 |
+
.filter((update) => update.subtype !== MessageWebSearchUpdateType.Sources)
|
18 |
+
.at(-1) as MessageWebSearchUpdate;
|
19 |
+
$: loading = !sources && lastMessage.subtype !== MessageWebSearchUpdateType.Error;
|
20 |
</script>
|
21 |
|
22 |
<details
|
|
|
53 |
{#if sources}
|
54 |
Completed
|
55 |
{:else}
|
56 |
+
{"message" in lastMessage ? lastMessage.message : "An error occurred"}
|
57 |
{/if}
|
58 |
</dt>
|
59 |
</dl>
|
|
|
67 |
{:else}
|
68 |
<ol>
|
69 |
{#each webSearchMessages as message}
|
70 |
+
{#if message.subtype === MessageWebSearchUpdateType.Update}
|
71 |
<li class="group border-l pb-6 last:!border-transparent last:pb-0 dark:border-gray-800">
|
72 |
<div class="flex items-start">
|
73 |
<div
|
|
|
85 |
</p>
|
86 |
{/if}
|
87 |
</li>
|
88 |
+
{:else if message.subtype === MessageWebSearchUpdateType.Error}
|
89 |
<li class="group border-l pb-6 last:!border-transparent last:pb-0 dark:border-gray-800">
|
90 |
<div class="flex items-start">
|
91 |
<CarbonError
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { page } from "$app/stores";
|
3 |
+
import { clickOutside } from "$lib/actions/clickOutside";
|
4 |
+
import { useSettingsStore } from "$lib/stores/settings";
|
5 |
+
import type { ToolFront } from "$lib/types/Tool";
|
6 |
+
import { isHuggingChat } from "$lib/utils/isHuggingChat";
|
7 |
+
import IconTool from "./icons/IconTool.svelte";
|
8 |
+
import CarbonInformation from "~icons/carbon/information";
|
9 |
+
|
10 |
+
export let loading = false;
|
11 |
+
const settings = useSettingsStore();
|
12 |
+
|
13 |
+
let detailsEl: HTMLDetailsElement;
|
14 |
+
|
15 |
+
// active tools are all the checked tools, either from settings or on by default
|
16 |
+
$: activeToolCount = $page.data.tools.filter(
|
17 |
+
(tool: ToolFront) => $settings?.tools?.[tool.name] ?? tool.isOnByDefault
|
18 |
+
).length;
|
19 |
+
</script>
|
20 |
+
|
21 |
+
<details
|
22 |
+
class="group relative bottom-0 h-full min-h-8"
|
23 |
+
bind:this={detailsEl}
|
24 |
+
use:clickOutside={() => {
|
25 |
+
if (detailsEl.hasAttribute("open")) {
|
26 |
+
detailsEl.removeAttribute("open");
|
27 |
+
}
|
28 |
+
}}
|
29 |
+
>
|
30 |
+
<summary
|
31 |
+
class="absolute bottom-0 flex h-8
|
32 |
+
cursor-pointer select-none items-center gap-1 rounded-lg border bg-white px-2 py-1.5 shadow-sm hover:shadow-none dark:border-gray-800 dark:bg-gray-900"
|
33 |
+
>
|
34 |
+
<IconTool classNames="dark:text-purple-600" />
|
35 |
+
Tools
|
36 |
+
<span class="text-gray-400 dark:text-gray-500"> ({activeToolCount}) </span>
|
37 |
+
</summary>
|
38 |
+
<div
|
39 |
+
class="absolute bottom-10 h-max w-max select-none items-center gap-1 rounded-lg border bg-white p-0.5 shadow-sm dark:border-gray-800 dark:bg-gray-900"
|
40 |
+
>
|
41 |
+
<div class="grid grid-cols-2 gap-x-6 gap-y-1 p-3">
|
42 |
+
<div class="col-span-2 mb-1 flex items-center gap-1.5 text-sm text-gray-500">
|
43 |
+
Available tools
|
44 |
+
{#if isHuggingChat}
|
45 |
+
<a
|
46 |
+
href="https://huggingface.co/spaces/huggingchat/chat-ui/discussions/454"
|
47 |
+
target="_blank"
|
48 |
+
class="hover:brightness-0 dark:hover:brightness-200"
|
49 |
+
><CarbonInformation class="text-xs" /></a
|
50 |
+
>
|
51 |
+
{/if}
|
52 |
+
</div>
|
53 |
+
{#each $page.data.tools as tool}
|
54 |
+
{@const isChecked = $settings?.tools?.[tool.name] ?? tool.isOnByDefault}
|
55 |
+
<div class="flex items-center gap-1.5">
|
56 |
+
<input
|
57 |
+
type="checkbox"
|
58 |
+
id={tool.name}
|
59 |
+
checked={isChecked}
|
60 |
+
disabled={loading}
|
61 |
+
on:click={async () => {
|
62 |
+
await settings.instantSet({
|
63 |
+
tools: {
|
64 |
+
...$settings.tools,
|
65 |
+
[tool.name]: !isChecked,
|
66 |
+
},
|
67 |
+
});
|
68 |
+
}}
|
69 |
+
/>
|
70 |
+
<label class="cursor-pointer" for={tool.name}>{tool.displayName ?? tool.name} </label>
|
71 |
+
</div>
|
72 |
+
{/each}
|
73 |
+
</div>
|
74 |
+
</div>
|
75 |
+
</details>
|
@@ -3,21 +3,26 @@
|
|
3 |
|
4 |
export let classNames = "";
|
5 |
export let files: File[];
|
6 |
-
let filelist: FileList;
|
7 |
|
8 |
-
|
9 |
-
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
</script>
|
12 |
|
13 |
<button
|
14 |
-
class="btn relative h-8 rounded-lg border bg-white px-3 py-1 text-sm text-gray-500 shadow-sm
|
15 |
>
|
16 |
<input
|
17 |
-
bind:files={filelist}
|
18 |
class="absolute w-full cursor-pointer opacity-0"
|
19 |
type="file"
|
20 |
-
|
|
|
21 |
/>
|
22 |
-
<CarbonUpload class="mr-2 text-
|
23 |
</button>
|
|
|
3 |
|
4 |
export let classNames = "";
|
5 |
export let files: File[];
|
|
|
6 |
|
7 |
+
/**
|
8 |
+
* Due to a bug with Svelte, we cannot use bind:files with multiple
|
9 |
+
* So we use this workaround
|
10 |
+
**/
|
11 |
+
const onFileChange = (e: Event) => {
|
12 |
+
if (!e.target) return;
|
13 |
+
const target = e.target as HTMLInputElement;
|
14 |
+
files = [...files, ...(target.files ?? [])];
|
15 |
+
};
|
16 |
</script>
|
17 |
|
18 |
<button
|
19 |
+
class="btn relative h-8 rounded-lg border bg-white px-3 py-1 text-sm text-gray-500 shadow-sm hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600 {classNames}"
|
20 |
>
|
21 |
<input
|
|
|
22 |
class="absolute w-full cursor-pointer opacity-0"
|
23 |
type="file"
|
24 |
+
on:change={onFileChange}
|
25 |
+
accept="*/*"
|
26 |
/>
|
27 |
+
<CarbonUpload class="mr-2 text-xxs" /> Upload file
|
28 |
</button>
|
@@ -1,7 +1,7 @@
|
|
1 |
<script lang="ts">
|
2 |
import { marked, type MarkedOptions } from "marked";
|
3 |
import markedKatex from "marked-katex-extension";
|
4 |
-
import type { Message } from "$lib/types/Message";
|
5 |
import { afterUpdate, createEventDispatcher, tick } from "svelte";
|
6 |
import { deepestChild } from "$lib/utils/deepestChild";
|
7 |
import { page } from "$app/stores";
|
@@ -16,14 +16,25 @@
|
|
16 |
import CarbonPen from "~icons/carbon/pen";
|
17 |
import CarbonChevronLeft from "~icons/carbon/chevron-left";
|
18 |
import CarbonChevronRight from "~icons/carbon/chevron-right";
|
19 |
-
|
20 |
import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken";
|
21 |
import type { Model } from "$lib/types/Model";
|
|
|
22 |
|
23 |
import OpenWebSearchResults from "../OpenWebSearchResults.svelte";
|
24 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
import { base } from "$app/paths";
|
26 |
import { useConvTreeStore } from "$lib/stores/convTree";
|
|
|
|
|
27 |
|
28 |
function sanitizeMd(md: string) {
|
29 |
let ret = md
|
@@ -58,6 +69,8 @@
|
|
58 |
|
59 |
$: message = messages.find((m) => m.id === id) ?? ({} as Message);
|
60 |
|
|
|
|
|
61 |
const dispatch = createEventDispatcher<{
|
62 |
retry: { content?: string; id: Message["id"] };
|
63 |
vote: { score: Message["score"]; id: Message["id"] };
|
@@ -129,19 +142,33 @@
|
|
129 |
}
|
130 |
|
131 |
$: searchUpdates = (message.updates?.filter(({ type }) => type === "webSearch") ??
|
132 |
-
[]) as
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
|
134 |
-
$: downloadLink =
|
135 |
-
message.from === "user" ? `${$page.url.pathname}/message/${message.id}/prompt` : undefined;
|
136 |
|
137 |
let webSearchIsDone = true;
|
138 |
|
139 |
-
$: webSearchIsDone =
|
140 |
-
|
|
|
141 |
|
142 |
-
$: webSearchSources =
|
143 |
-
|
144 |
-
|
|
|
145 |
|
146 |
$: if (isCopied) {
|
147 |
setTimeout(() => {
|
@@ -177,8 +204,32 @@
|
|
177 |
const convTreeStore = useConvTreeStore();
|
178 |
|
179 |
$: if (message.children?.length === 0) $convTreeStore.leaf = message.id;
|
|
|
|
|
|
|
|
|
180 |
</script>
|
181 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
{#if message.from === "assistant"}
|
183 |
<div
|
184 |
class="group relative -mb-6 flex items-start justify-start gap-4 pb-4 leading-relaxed"
|
@@ -202,6 +253,29 @@
|
|
202 |
<div
|
203 |
class="relative min-h-[calc(2rem+theme(spacing[3.5])*2)] min-w-[60px] break-words rounded-2xl border border-gray-100 bg-gradient-to-br from-gray-50 px-5 py-3.5 text-gray-600 prose-pre:my-2 dark:border-gray-800 dark:from-gray-800/40 dark:text-gray-300"
|
204 |
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
{#if searchUpdates && searchUpdates.length > 0}
|
206 |
<OpenWebSearchResults
|
207 |
classNames={tokens.length ? "mb-3.5" : ""}
|
@@ -209,6 +283,72 @@
|
|
209 |
/>
|
210 |
{/if}
|
211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
<div
|
213 |
class="prose max-w-none max-sm:prose-sm dark:prose-invert prose-headings:font-semibold prose-h1:text-lg prose-h2:text-base prose-h3:text-base prose-pre:bg-gray-800 dark:prose-pre:bg-gray-900"
|
214 |
bind:this={contentEl}
|
@@ -244,7 +384,7 @@
|
|
244 |
</div>
|
245 |
{/if}
|
246 |
</div>
|
247 |
-
{#if !loading && message.content}
|
248 |
<div
|
249 |
class="absolute bottom-1 right-0 -mb-4 flex max-md:transition-all md:bottom-0 md:group-hover:visible md:group-hover:opacity-100
|
250 |
{message.score ? 'visible opacity-100' : 'invisible max-md:-translate-y-4 max-md:opacity-0'}
|
@@ -304,24 +444,16 @@
|
|
304 |
on:click={() => (isTapped = !isTapped)}
|
305 |
on:keydown={() => (isTapped = !isTapped)}
|
306 |
>
|
307 |
-
<div class="flex w-full flex-col">
|
308 |
-
{#if message.files
|
309 |
-
<div class="
|
310 |
{#each message.files as file}
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
alt="input from user"
|
316 |
-
class="my-2 aspect-auto max-h-48 rounded-lg shadow-lg"
|
317 |
-
/>
|
318 |
{:else}
|
319 |
-
|
320 |
-
<img
|
321 |
-
src={`data:${file.mime};base64,${file.value}`}
|
322 |
-
alt="input from user"
|
323 |
-
class="my-2 aspect-auto max-h-48 rounded-lg shadow-lg"
|
324 |
-
/>
|
325 |
{/if}
|
326 |
{/each}
|
327 |
</div>
|
@@ -458,3 +590,20 @@
|
|
458 |
</svelte:fragment>
|
459 |
</svelte:self>
|
460 |
{/if}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<script lang="ts">
|
2 |
import { marked, type MarkedOptions } from "marked";
|
3 |
import markedKatex from "marked-katex-extension";
|
4 |
+
import type { Message, MessageFile } from "$lib/types/Message";
|
5 |
import { afterUpdate, createEventDispatcher, tick } from "svelte";
|
6 |
import { deepestChild } from "$lib/utils/deepestChild";
|
7 |
import { page } from "$app/stores";
|
|
|
16 |
import CarbonPen from "~icons/carbon/pen";
|
17 |
import CarbonChevronLeft from "~icons/carbon/chevron-left";
|
18 |
import CarbonChevronRight from "~icons/carbon/chevron-right";
|
19 |
+
import CarbonTools from "~icons/carbon/tools";
|
20 |
import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken";
|
21 |
import type { Model } from "$lib/types/Model";
|
22 |
+
import UploadedFile from "./UploadedFile.svelte";
|
23 |
|
24 |
import OpenWebSearchResults from "../OpenWebSearchResults.svelte";
|
25 |
+
import {
|
26 |
+
MessageToolUpdateType,
|
27 |
+
MessageWebSearchUpdateType,
|
28 |
+
type MessageToolUpdate,
|
29 |
+
type MessageWebSearchSourcesUpdate,
|
30 |
+
type MessageWebSearchUpdate,
|
31 |
+
} from "$lib/types/MessageUpdate";
|
32 |
+
import { isMessageToolCallUpdate, isMessageToolResultUpdate } from "$lib/utils/messageUpdates";
|
33 |
+
import type { ToolFront } from "$lib/types/Tool";
|
34 |
import { base } from "$app/paths";
|
35 |
import { useConvTreeStore } from "$lib/stores/convTree";
|
36 |
+
import Modal from "../Modal.svelte";
|
37 |
+
import { toolHasName } from "$lib/utils/tools";
|
38 |
|
39 |
function sanitizeMd(md: string) {
|
40 |
let ret = md
|
|
|
69 |
|
70 |
$: message = messages.find((m) => m.id === id) ?? ({} as Message);
|
71 |
|
72 |
+
$: urlNotTrailing = $page.url.pathname.replace(/\/$/, "");
|
73 |
+
|
74 |
const dispatch = createEventDispatcher<{
|
75 |
retry: { content?: string; id: Message["id"] };
|
76 |
vote: { score: Message["score"]; id: Message["id"] };
|
|
|
142 |
}
|
143 |
|
144 |
$: searchUpdates = (message.updates?.filter(({ type }) => type === "webSearch") ??
|
145 |
+
[]) as MessageWebSearchUpdate[];
|
146 |
+
|
147 |
+
// filter all updates with type === "tool" then group them by uuid field
|
148 |
+
|
149 |
+
$: toolUpdates = message.updates
|
150 |
+
?.filter(({ type }) => type === "tool")
|
151 |
+
.reduce((acc, update) => {
|
152 |
+
if (update.type !== "tool") {
|
153 |
+
return acc;
|
154 |
+
}
|
155 |
+
acc[update.uuid] = acc[update.uuid] ?? [];
|
156 |
+
acc[update.uuid].push(update);
|
157 |
+
return acc;
|
158 |
+
}, {} as Record<string, MessageToolUpdate[]>);
|
159 |
|
160 |
+
$: downloadLink = urlNotTrailing + `/message/${message.id}/prompt`;
|
|
|
161 |
|
162 |
let webSearchIsDone = true;
|
163 |
|
164 |
+
$: webSearchIsDone = searchUpdates.some(
|
165 |
+
(update) => update.subtype === MessageWebSearchUpdateType.Finished
|
166 |
+
);
|
167 |
|
168 |
+
$: webSearchSources = searchUpdates?.find(
|
169 |
+
(update): update is MessageWebSearchSourcesUpdate =>
|
170 |
+
update.subtype === MessageWebSearchUpdateType.Sources
|
171 |
+
)?.sources;
|
172 |
|
173 |
$: if (isCopied) {
|
174 |
setTimeout(() => {
|
|
|
204 |
const convTreeStore = useConvTreeStore();
|
205 |
|
206 |
$: if (message.children?.length === 0) $convTreeStore.leaf = message.id;
|
207 |
+
|
208 |
+
$: modalImageToShow = null as MessageFile | null;
|
209 |
+
|
210 |
+
const availableTools: ToolFront[] = $page.data.tools;
|
211 |
</script>
|
212 |
|
213 |
+
{#if modalImageToShow}
|
214 |
+
<!-- show the image file full screen, click outside to exit -->
|
215 |
+
<Modal width="sm:max-w-[500px]" on:close={() => (modalImageToShow = null)}>
|
216 |
+
{#if modalImageToShow.type === "hash"}
|
217 |
+
<img
|
218 |
+
src={urlNotTrailing + "/output/" + modalImageToShow.value}
|
219 |
+
alt="input from user"
|
220 |
+
class="aspect-auto"
|
221 |
+
/>
|
222 |
+
{:else}
|
223 |
+
<!-- handle the case where this is a base64 encoded image -->
|
224 |
+
<img
|
225 |
+
src={`data:${modalImageToShow.mime};base64,${modalImageToShow.value}`}
|
226 |
+
alt="input from user"
|
227 |
+
class="aspect-auto"
|
228 |
+
/>
|
229 |
+
{/if}
|
230 |
+
</Modal>
|
231 |
+
{/if}
|
232 |
+
|
233 |
{#if message.from === "assistant"}
|
234 |
<div
|
235 |
class="group relative -mb-6 flex items-start justify-start gap-4 pb-4 leading-relaxed"
|
|
|
253 |
<div
|
254 |
class="relative min-h-[calc(2rem+theme(spacing[3.5])*2)] min-w-[60px] break-words rounded-2xl border border-gray-100 bg-gradient-to-br from-gray-50 px-5 py-3.5 text-gray-600 prose-pre:my-2 dark:border-gray-800 dark:from-gray-800/40 dark:text-gray-300"
|
255 |
>
|
256 |
+
{#if message.files?.length}
|
257 |
+
<div class="flex h-fit flex-wrap gap-x-5 gap-y-2">
|
258 |
+
{#each message.files as file}
|
259 |
+
<!-- handle the case where this is a hash that points to an image in the db, hash is always 64 char long -->
|
260 |
+
<button on:click={() => (modalImageToShow = file)}>
|
261 |
+
{#if file.type === "hash"}
|
262 |
+
<img
|
263 |
+
src={urlNotTrailing + "/output/" + file.value}
|
264 |
+
alt="output from assistant"
|
265 |
+
class="my-2 aspect-auto max-h-48 cursor-pointer rounded-lg shadow-lg"
|
266 |
+
/>
|
267 |
+
{:else}
|
268 |
+
<!-- handle the case where this is a base64 encoded image -->
|
269 |
+
<img
|
270 |
+
src={`data:${file.mime};base64,${file.value}`}
|
271 |
+
alt="output from assistant"
|
272 |
+
class="my-2 aspect-auto max-h-48 cursor-pointer rounded-lg shadow-lg"
|
273 |
+
/>
|
274 |
+
{/if}
|
275 |
+
</button>
|
276 |
+
{/each}
|
277 |
+
</div>
|
278 |
+
{/if}
|
279 |
{#if searchUpdates && searchUpdates.length > 0}
|
280 |
<OpenWebSearchResults
|
281 |
classNames={tokens.length ? "mb-3.5" : ""}
|
|
|
283 |
/>
|
284 |
{/if}
|
285 |
|
286 |
+
{#if toolUpdates}
|
287 |
+
{#each Object.values(toolUpdates) as tool}
|
288 |
+
{#if tool.length}
|
289 |
+
{@const toolName = tool.find(isMessageToolCallUpdate)?.call.name}
|
290 |
+
{@const toolDone = tool.some(isMessageToolResultUpdate)}
|
291 |
+
{#if toolName && toolName !== "websearch"}
|
292 |
+
<details
|
293 |
+
class="group/tool my-2.5 w-fit cursor-pointer rounded-lg border border-gray-200 bg-white pl-1 pr-2.5 text-sm shadow-sm transition-all open:mb-3
|
294 |
+
open:border-purple-500/10 open:bg-purple-600/5 open:shadow-sm dark:border-gray-800 dark:bg-gray-900 open:dark:border-purple-800/40 open:dark:bg-purple-800/10"
|
295 |
+
>
|
296 |
+
<summary
|
297 |
+
class="flex select-none list-none items-center gap-1.5 py-1 group-open/tool:text-purple-700 group-open/tool:dark:text-purple-300"
|
298 |
+
>
|
299 |
+
<div
|
300 |
+
class="relative grid size-[22px] place-items-center rounded bg-purple-600/10 dark:bg-purple-600/20"
|
301 |
+
>
|
302 |
+
<svg
|
303 |
+
class="absolute inset-0 text-purple-500/40 transition-opacity"
|
304 |
+
class:invisible={toolDone}
|
305 |
+
width="22"
|
306 |
+
height="22"
|
307 |
+
viewBox="0 0 38 38"
|
308 |
+
fill="none"
|
309 |
+
xmlns="http://www.w3.org/2000/svg"
|
310 |
+
>
|
311 |
+
<path
|
312 |
+
class="loading-path"
|
313 |
+
d="M8 2.5H30C30 2.5 35.5 2.5 35.5 8V30C35.5 30 35.5 35.5 30 35.5H8C8 35.5 2.5 35.5 2.5 30V8C2.5 8 2.5 2.5 8 2.5Z"
|
314 |
+
stroke="currentColor"
|
315 |
+
stroke-width="1"
|
316 |
+
stroke-linecap="round"
|
317 |
+
id="shape"
|
318 |
+
/>
|
319 |
+
</svg>
|
320 |
+
<CarbonTools class="text-xs text-purple-700 dark:text-purple-500" />
|
321 |
+
</div>
|
322 |
+
|
323 |
+
<span>
|
324 |
+
{toolDone ? "Called" : "Calling"} tool
|
325 |
+
<span class="font-semibold"
|
326 |
+
>{availableTools.find((el) => toolHasName(toolName, el))?.displayName}</span
|
327 |
+
>
|
328 |
+
</span>
|
329 |
+
</summary>
|
330 |
+
{#each tool as toolUpdate}
|
331 |
+
{#if toolUpdate.subtype === MessageToolUpdateType.Call}
|
332 |
+
<div class="mt-1 flex items-center gap-2 opacity-80">
|
333 |
+
<h3 class="text-sm">Parameters</h3>
|
334 |
+
<div class="h-px flex-1 bg-gradient-to-r from-gray-500/20" />
|
335 |
+
</div>
|
336 |
+
<ul class="py-1 text-sm">
|
337 |
+
{#each Object.entries(toolUpdate.call.parameters ?? {}) as [k, v]}
|
338 |
+
<li>
|
339 |
+
<span class="font-semibold">{k}</span>:
|
340 |
+
<span>{v}</span>
|
341 |
+
</li>
|
342 |
+
{/each}
|
343 |
+
</ul>
|
344 |
+
{/if}
|
345 |
+
{/each}
|
346 |
+
</details>
|
347 |
+
{/if}
|
348 |
+
{/if}
|
349 |
+
{/each}
|
350 |
+
{/if}
|
351 |
+
|
352 |
<div
|
353 |
class="prose max-w-none max-sm:prose-sm dark:prose-invert prose-headings:font-semibold prose-h1:text-lg prose-h2:text-base prose-h3:text-base prose-pre:bg-gray-800 dark:prose-pre:bg-gray-900"
|
354 |
bind:this={contentEl}
|
|
|
384 |
</div>
|
385 |
{/if}
|
386 |
</div>
|
387 |
+
{#if !loading && (message.content || toolUpdates)}
|
388 |
<div
|
389 |
class="absolute bottom-1 right-0 -mb-4 flex max-md:transition-all md:bottom-0 md:group-hover:visible md:group-hover:opacity-100
|
390 |
{message.score ? 'visible opacity-100' : 'invisible max-md:-translate-y-4 max-md:opacity-0'}
|
|
|
444 |
on:click={() => (isTapped = !isTapped)}
|
445 |
on:keydown={() => (isTapped = !isTapped)}
|
446 |
>
|
447 |
+
<div class="flex w-full flex-col gap-2">
|
448 |
+
{#if message.files?.length}
|
449 |
+
<div class="flex w-fit gap-4 px-5">
|
450 |
{#each message.files as file}
|
451 |
+
{#if file.mime.startsWith("image/")}
|
452 |
+
<button on:click={() => (modalImageToShow = file)}>
|
453 |
+
<UploadedFile {file} canClose={false} />
|
454 |
+
</button>
|
|
|
|
|
|
|
455 |
{:else}
|
456 |
+
<UploadedFile {file} canClose={false} />
|
|
|
|
|
|
|
|
|
|
|
457 |
{/if}
|
458 |
{/each}
|
459 |
</div>
|
|
|
590 |
</svelte:fragment>
|
591 |
</svelte:self>
|
592 |
{/if}
|
593 |
+
|
594 |
+
<style>
|
595 |
+
details summary::-webkit-details-marker {
|
596 |
+
display: none;
|
597 |
+
}
|
598 |
+
|
599 |
+
.loading-path {
|
600 |
+
stroke-dasharray: 61.45;
|
601 |
+
animation: loading 2s linear infinite;
|
602 |
+
}
|
603 |
+
|
604 |
+
@keyframes loading {
|
605 |
+
to {
|
606 |
+
stroke-dashoffset: 122.9;
|
607 |
+
}
|
608 |
+
}
|
609 |
+
</style>
|
@@ -1,11 +1,10 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import type { Message } from "$lib/types/Message";
|
3 |
import { createEventDispatcher, onDestroy, tick } from "svelte";
|
4 |
|
5 |
import CarbonSendAltFilled from "~icons/carbon/send-alt-filled";
|
6 |
import CarbonExport from "~icons/carbon/export";
|
7 |
import CarbonStopFilledAlt from "~icons/carbon/stop-filled-alt";
|
8 |
-
import CarbonClose from "~icons/carbon/close";
|
9 |
import CarbonCheckmark from "~icons/carbon/checkmark";
|
10 |
import CarbonCaretDown from "~icons/carbon/caret-down";
|
11 |
|
@@ -15,6 +14,7 @@
|
|
15 |
import StopGeneratingBtn from "../StopGeneratingBtn.svelte";
|
16 |
import type { Model } from "$lib/types/Model";
|
17 |
import WebSearchToggle from "../WebSearchToggle.svelte";
|
|
|
18 |
import LoginModal from "../LoginModal.svelte";
|
19 |
import { page } from "$app/stores";
|
20 |
import FileDropzone from "./FileDropzone.svelte";
|
@@ -32,6 +32,7 @@
|
|
32 |
import SystemPromptModal from "../SystemPromptModal.svelte";
|
33 |
import ChatIntroduction from "./ChatIntroduction.svelte";
|
34 |
import { useConvTreeStore } from "$lib/stores/convTree";
|
|
|
35 |
|
36 |
export let messages: Message[] = [];
|
37 |
export let loading = false;
|
@@ -92,8 +93,8 @@
|
|
92 |
(lastMessage.from === "user" ||
|
93 |
lastMessage.updates?.findIndex((u) => u.type === "status" && u.status === "error") !== -1);
|
94 |
|
95 |
-
$: sources = files?.map((file) =>
|
96 |
-
file2base64(file).then((value) => ({ type: "base64", value, mime: file.type }))
|
97 |
);
|
98 |
|
99 |
function onShare() {
|
@@ -139,7 +140,9 @@
|
|
139 |
use:snapScrollToBottom={messages.length ? [...messages] : false}
|
140 |
bind:this={chatContainer}
|
141 |
>
|
142 |
-
<div
|
|
|
|
|
143 |
{#if $page.data?.assistant && !!messages.length}
|
144 |
<a
|
145 |
class="mx-auto flex items-center gap-1.5 rounded-full border border-gray-100 bg-gray-50 py-1 pl-1 pr-3 text-sm text-gray-800 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700"
|
@@ -167,7 +170,7 @@
|
|
167 |
{/if}
|
168 |
|
169 |
{#if messages.length > 0}
|
170 |
-
<div class="flex h-max flex-col gap-6 pb-52">
|
171 |
<ChatMessage
|
172 |
{loading}
|
173 |
{messages}
|
@@ -235,22 +238,12 @@
|
|
235 |
<div class="flex flex-row flex-wrap justify-center gap-2.5 max-md:pb-3">
|
236 |
{#each sources as source, index}
|
237 |
{#await source then src}
|
238 |
-
<
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
<!-- add a button on top that deletes this image from sources -->
|
245 |
-
<button
|
246 |
-
class="absolute left-1 top-1"
|
247 |
-
on:click={() => {
|
248 |
-
files = files.filter((_, i) => i !== index);
|
249 |
-
}}
|
250 |
-
>
|
251 |
-
<CarbonClose class="text-md font-black text-gray-300 hover:text-gray-100" />
|
252 |
-
</button>
|
253 |
-
</div>
|
254 |
{/await}
|
255 |
{/each}
|
256 |
</div>
|
@@ -258,8 +251,12 @@
|
|
258 |
|
259 |
<div class="w-full">
|
260 |
<div class="flex w-full pb-3">
|
261 |
-
{#if
|
262 |
-
|
|
|
|
|
|
|
|
|
263 |
{/if}
|
264 |
{#if loading}
|
265 |
<StopGeneratingBtn classNames="ml-auto" on:click={() => dispatch("stop")} />
|
@@ -276,7 +273,7 @@
|
|
276 |
/>
|
277 |
{:else}
|
278 |
<div class="ml-auto gap-2">
|
279 |
-
{#if currentModel.multimodal}
|
280 |
<UploadBtn bind:files classNames="ml-auto" />
|
281 |
{/if}
|
282 |
{#if messages && lastMessage && lastMessage.interrupted && !isReadOnly}
|
|
|
1 |
<script lang="ts">
|
2 |
+
import type { Message, MessageFile } from "$lib/types/Message";
|
3 |
import { createEventDispatcher, onDestroy, tick } from "svelte";
|
4 |
|
5 |
import CarbonSendAltFilled from "~icons/carbon/send-alt-filled";
|
6 |
import CarbonExport from "~icons/carbon/export";
|
7 |
import CarbonStopFilledAlt from "~icons/carbon/stop-filled-alt";
|
|
|
8 |
import CarbonCheckmark from "~icons/carbon/checkmark";
|
9 |
import CarbonCaretDown from "~icons/carbon/caret-down";
|
10 |
|
|
|
14 |
import StopGeneratingBtn from "../StopGeneratingBtn.svelte";
|
15 |
import type { Model } from "$lib/types/Model";
|
16 |
import WebSearchToggle from "../WebSearchToggle.svelte";
|
17 |
+
import ToolsMenu from "../ToolsMenu.svelte";
|
18 |
import LoginModal from "../LoginModal.svelte";
|
19 |
import { page } from "$app/stores";
|
20 |
import FileDropzone from "./FileDropzone.svelte";
|
|
|
32 |
import SystemPromptModal from "../SystemPromptModal.svelte";
|
33 |
import ChatIntroduction from "./ChatIntroduction.svelte";
|
34 |
import { useConvTreeStore } from "$lib/stores/convTree";
|
35 |
+
import UploadedFile from "./UploadedFile.svelte";
|
36 |
|
37 |
export let messages: Message[] = [];
|
38 |
export let loading = false;
|
|
|
93 |
(lastMessage.from === "user" ||
|
94 |
lastMessage.updates?.findIndex((u) => u.type === "status" && u.status === "error") !== -1);
|
95 |
|
96 |
+
$: sources = files?.map<Promise<MessageFile>>((file) =>
|
97 |
+
file2base64(file).then((value) => ({ type: "base64", value, mime: file.type, name: file.name }))
|
98 |
);
|
99 |
|
100 |
function onShare() {
|
|
|
140 |
use:snapScrollToBottom={messages.length ? [...messages] : false}
|
141 |
bind:this={chatContainer}
|
142 |
>
|
143 |
+
<div
|
144 |
+
class="mx-auto flex h-full max-w-3xl flex-col gap-6 px-5 pt-6 sm:gap-8 xl:max-w-4xl xl:pt-10"
|
145 |
+
>
|
146 |
{#if $page.data?.assistant && !!messages.length}
|
147 |
<a
|
148 |
class="mx-auto flex items-center gap-1.5 rounded-full border border-gray-100 bg-gray-50 py-1 pl-1 pr-3 text-sm text-gray-800 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700"
|
|
|
170 |
{/if}
|
171 |
|
172 |
{#if messages.length > 0}
|
173 |
+
<div class="flex h-max flex-col gap-6 pb-52 2xl:gap-7">
|
174 |
<ChatMessage
|
175 |
{loading}
|
176 |
{messages}
|
|
|
238 |
<div class="flex flex-row flex-wrap justify-center gap-2.5 max-md:pb-3">
|
239 |
{#each sources as source, index}
|
240 |
{#await source then src}
|
241 |
+
<UploadedFile
|
242 |
+
file={src}
|
243 |
+
on:close={() => {
|
244 |
+
files = files.filter((_, i) => i !== index);
|
245 |
+
}}
|
246 |
+
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 |
{/await}
|
248 |
{/each}
|
249 |
</div>
|
|
|
251 |
|
252 |
<div class="w-full">
|
253 |
<div class="flex w-full pb-3">
|
254 |
+
{#if !assistant}
|
255 |
+
{#if currentModel.tools}
|
256 |
+
<ToolsMenu {loading} />
|
257 |
+
{:else if $page.data.settings?.searchEnabled}
|
258 |
+
<WebSearchToggle />
|
259 |
+
{/if}
|
260 |
{/if}
|
261 |
{#if loading}
|
262 |
<StopGeneratingBtn classNames="ml-auto" on:click={() => dispatch("stop")} />
|
|
|
273 |
/>
|
274 |
{:else}
|
275 |
<div class="ml-auto gap-2">
|
276 |
+
{#if currentModel.multimodal || currentModel.tools}
|
277 |
<UploadBtn bind:files classNames="ml-auto" />
|
278 |
{/if}
|
279 |
{#if messages && lastMessage && lastMessage.interrupted && !isReadOnly}
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { createEventDispatcher } from "svelte";
|
3 |
+
import { page } from "$app/stores";
|
4 |
+
import type { MessageFile } from "$lib/types/Message";
|
5 |
+
import CarbonClose from "~icons/carbon/close";
|
6 |
+
import CarbonDocumentBlank from "~icons/carbon/document-blank";
|
7 |
+
|
8 |
+
export let file: MessageFile;
|
9 |
+
export let canClose = true;
|
10 |
+
const dispatch = createEventDispatcher<{ close: void }>();
|
11 |
+
</script>
|
12 |
+
|
13 |
+
<div
|
14 |
+
class="group relative flex items-center rounded-xl shadow-sm"
|
15 |
+
class:w-24={file.mime.startsWith("image/")}
|
16 |
+
class:w-72={!file.mime.startsWith("image/")}
|
17 |
+
>
|
18 |
+
{#if file.mime.startsWith("image/")}
|
19 |
+
<div class="size-24 overflow-hidden rounded-xl">
|
20 |
+
<img
|
21 |
+
src={file.type === "base64"
|
22 |
+
? `data:${file.mime};base64,${file.value}`
|
23 |
+
: $page.url.pathname + "/output/" + file.value}
|
24 |
+
alt={file.name}
|
25 |
+
class="h-full w-full bg-gray-200 object-cover dark:bg-gray-800"
|
26 |
+
/>
|
27 |
+
</div>
|
28 |
+
{:else}
|
29 |
+
<div
|
30 |
+
class="flex h-14 w-72 items-center gap-2 overflow-hidden rounded-xl border border-gray-200 bg-white p-2 dark:border-gray-800 dark:bg-gray-900"
|
31 |
+
>
|
32 |
+
<div
|
33 |
+
class="grid size-10 flex-none place-items-center rounded-lg bg-gray-100 dark:bg-gray-800"
|
34 |
+
>
|
35 |
+
<CarbonDocumentBlank class="text-base text-gray-700 dark:text-gray-300" />
|
36 |
+
</div>
|
37 |
+
<dl class="flex flex-col truncate leading-tight">
|
38 |
+
<dd class="text-sm">
|
39 |
+
{file.name}
|
40 |
+
</dd>
|
41 |
+
<dt class="text-xs text-gray-400">{file.mime.split("/")[1].toUpperCase()}</dt>
|
42 |
+
</dl>
|
43 |
+
</div>
|
44 |
+
{/if}
|
45 |
+
<!-- add a button on top that removes the image -->
|
46 |
+
{#if canClose}
|
47 |
+
<button
|
48 |
+
class="invisible absolute -right-2 -top-2 grid size-6 place-items-center rounded-full border bg-black group-hover:visible dark:border-gray-700"
|
49 |
+
on:click={() => dispatch("close")}
|
50 |
+
>
|
51 |
+
<CarbonClose class=" text-xs text-white" />
|
52 |
+
</button>
|
53 |
+
{/if}
|
54 |
+
</div>
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
export let classNames = "";
|
3 |
+
</script>
|
4 |
+
|
5 |
+
<svg
|
6 |
+
xmlns="http://www.w3.org/2000/svg"
|
7 |
+
class={classNames}
|
8 |
+
width="1em"
|
9 |
+
height="1em"
|
10 |
+
fill="none"
|
11 |
+
viewBox="0 0 15 15"
|
12 |
+
><path
|
13 |
+
fill="currentColor"
|
14 |
+
d="M8.33 6.56c0 .11-.04.22-.1.31a.55.55 0 0 1-.26.2l-.71.23c-.2.07-.38.18-.53.33-.15.15-.26.33-.33.53l-.24.7a.55.55 0 0 1-.83.26.55.55 0 0 1-.19-.27l-.23-.7a1.37 1.37 0 0 0-.85-.85l-.7-.24a.52.52 0 0 1-.27-.2.56.56 0 0 1 .27-.82l.7-.23a1.4 1.4 0 0 0 .86-.86l.23-.7c.03-.1.1-.19.18-.26a.55.55 0 0 1 .63-.02c.1.06.17.15.2.26l.24.72a1.4 1.4 0 0 0 .86.86l.7.24c.11.04.2.1.26.2.07.09.1.2.1.31ZM13.94 10.14c0 .12-.03.24-.1.34a.55.55 0 0 1-.3.21l-.96.32a2.01 2.01 0 0 0-1.27 1.27l-.33.96a.55.55 0 0 1-.2.28c-.1.07-.23.11-.35.11a.56.56 0 0 1-.57-.4l-.32-.96c-.1-.3-.26-.57-.48-.79-.22-.21-.49-.38-.78-.48l-.97-.32a.62.62 0 0 1-.28-.2.61.61 0 0 1-.02-.7c.07-.1.18-.18.3-.22l.96-.32a1.99 1.99 0 0 0 1.29-1.28l.32-.95a.56.56 0 0 1 .53-.4c.12 0 .24.02.34.09.1.07.18.17.23.28l.32.98a1.99 1.99 0 0 0 1.29 1.28l.95.34c.12.04.22.11.29.21.07.1.11.22.11.35ZM11.48 3.84c.06-.09.1-.19.1-.29a.5.5 0 0 0-.1-.29.55.55 0 0 0-.23-.16l-.35-.12a.55.55 0 0 1-.18-.11.55.55 0 0 1-.11-.19l-.12-.36a.54.54 0 0 0-.18-.23A.55.55 0 0 0 10 2c-.1.01-.2.05-.27.1a.55.55 0 0 0-.16.23l-.12.35a.55.55 0 0 1-.11.19.55.55 0 0 1-.19.1l-.34.12a.5.5 0 0 0-.24.17.55.55 0 0 0-.1.29c0 .1.04.2.1.28.06.08.14.14.23.18l.35.11c.07.02.13.06.18.11.05.05.1.11.11.18l.12.35c.04.1.1.19.18.25.09.05.18.08.28.08.1 0 .2-.03.29-.1a.55.55 0 0 0 .16-.22l.13-.35a.47.47 0 0 1 .29-.3l.35-.11c.1-.03.17-.1.23-.17Z"
|
15 |
+
/></svg
|
16 |
+
>
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { Migration } from ".";
|
2 |
+
import { collections } from "$lib/server/database";
|
3 |
+
import { ObjectId } from "mongodb";
|
4 |
+
import { logger } from "$lib/server/logger";
|
5 |
+
|
6 |
+
const addToolsToSettings: Migration = {
|
7 |
+
_id: new ObjectId("5c9c4c4c4c4c4c4c4c4c4c4c"),
|
8 |
+
name: "Add empty 'tools' record in settings",
|
9 |
+
up: async () => {
|
10 |
+
const { settings } = collections;
|
11 |
+
|
12 |
+
// Find all assistants whose modelId is not in modelIds, and update it to use defaultModelId
|
13 |
+
await settings.updateMany(
|
14 |
+
{
|
15 |
+
tools: { $exists: false },
|
16 |
+
},
|
17 |
+
{ $set: { tools: {} } }
|
18 |
+
);
|
19 |
+
|
20 |
+
settings
|
21 |
+
.createIndex({ tools: 1 })
|
22 |
+
.catch((e) => logger.error("Error creating index during tools migration", e));
|
23 |
+
|
24 |
+
return true;
|
25 |
+
},
|
26 |
+
runEveryTime: false,
|
27 |
+
};
|
28 |
+
|
29 |
+
export default addToolsToSettings;
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { Migration } from ".";
|
2 |
+
import { collections } from "$lib/server/database";
|
3 |
+
import { ObjectId, type WithId } from "mongodb";
|
4 |
+
import type { Conversation } from "$lib/types/Conversation";
|
5 |
+
import type { WebSearchSource } from "$lib/types/WebSearch";
|
6 |
+
import {
|
7 |
+
MessageUpdateStatus,
|
8 |
+
MessageUpdateType,
|
9 |
+
MessageWebSearchUpdateType,
|
10 |
+
type MessageUpdate,
|
11 |
+
type MessageWebSearchFinishedUpdate,
|
12 |
+
} from "$lib/types/MessageUpdate";
|
13 |
+
import type { Message } from "$lib/types/Message";
|
14 |
+
import { isMessageWebSearchSourcesUpdate } from "$lib/utils/messageUpdates";
|
15 |
+
|
16 |
+
// -----------
|
17 |
+
// Copy of the previous message update types
|
18 |
+
export type FinalAnswer = {
|
19 |
+
type: "finalAnswer";
|
20 |
+
text: string;
|
21 |
+
};
|
22 |
+
|
23 |
+
export type TextStreamUpdate = {
|
24 |
+
type: "stream";
|
25 |
+
token: string;
|
26 |
+
};
|
27 |
+
|
28 |
+
type WebSearchUpdate = {
|
29 |
+
type: "webSearch";
|
30 |
+
messageType: "update" | "error" | "sources";
|
31 |
+
message: string;
|
32 |
+
args?: string[];
|
33 |
+
sources?: WebSearchSource[];
|
34 |
+
};
|
35 |
+
|
36 |
+
type StatusUpdate = {
|
37 |
+
type: "status";
|
38 |
+
status: "started" | "pending" | "finished" | "error" | "title";
|
39 |
+
message?: string;
|
40 |
+
};
|
41 |
+
|
42 |
+
type ErrorUpdate = {
|
43 |
+
type: "error";
|
44 |
+
message: string;
|
45 |
+
name: string;
|
46 |
+
};
|
47 |
+
|
48 |
+
type FileUpdate = {
|
49 |
+
type: "file";
|
50 |
+
sha: string;
|
51 |
+
};
|
52 |
+
|
53 |
+
type OldMessageUpdate =
|
54 |
+
| FinalAnswer
|
55 |
+
| TextStreamUpdate
|
56 |
+
| WebSearchUpdate
|
57 |
+
| StatusUpdate
|
58 |
+
| ErrorUpdate
|
59 |
+
| FileUpdate;
|
60 |
+
|
61 |
+
/** Converts the old message update to the new schema */
|
62 |
+
function convertMessageUpdate(message: Message, update: OldMessageUpdate): MessageUpdate | null {
|
63 |
+
try {
|
64 |
+
// Text and files
|
65 |
+
if (update.type === "finalAnswer") {
|
66 |
+
return {
|
67 |
+
type: MessageUpdateType.FinalAnswer,
|
68 |
+
text: update.text,
|
69 |
+
interrupted: message.interrupted ?? false,
|
70 |
+
};
|
71 |
+
} else if (update.type === "stream") {
|
72 |
+
return {
|
73 |
+
type: MessageUpdateType.Stream,
|
74 |
+
token: update.token,
|
75 |
+
};
|
76 |
+
} else if (update.type === "file") {
|
77 |
+
return {
|
78 |
+
type: MessageUpdateType.File,
|
79 |
+
name: "Unknown",
|
80 |
+
sha: update.sha,
|
81 |
+
// assume jpeg but could be any image. should be harmless
|
82 |
+
mime: "image/jpeg",
|
83 |
+
};
|
84 |
+
}
|
85 |
+
|
86 |
+
// Status
|
87 |
+
else if (update.type === "status") {
|
88 |
+
if (update.status === "title") {
|
89 |
+
return {
|
90 |
+
type: MessageUpdateType.Title,
|
91 |
+
title: update.message ?? "New Chat",
|
92 |
+
};
|
93 |
+
}
|
94 |
+
if (update.status === "pending") return null;
|
95 |
+
|
96 |
+
const status =
|
97 |
+
update.status === "started"
|
98 |
+
? MessageUpdateStatus.Started
|
99 |
+
: update.status === "finished"
|
100 |
+
? MessageUpdateStatus.Finished
|
101 |
+
: MessageUpdateStatus.Error;
|
102 |
+
return {
|
103 |
+
type: MessageUpdateType.Status,
|
104 |
+
status,
|
105 |
+
message: update.message,
|
106 |
+
};
|
107 |
+
} else if (update.type === "error") {
|
108 |
+
// Treat it as an error status update
|
109 |
+
return {
|
110 |
+
type: MessageUpdateType.Status,
|
111 |
+
status: MessageUpdateStatus.Error,
|
112 |
+
message: update.message,
|
113 |
+
};
|
114 |
+
}
|
115 |
+
|
116 |
+
// Web Search
|
117 |
+
else if (update.type === "webSearch") {
|
118 |
+
if (update.messageType === "update") {
|
119 |
+
return {
|
120 |
+
type: MessageUpdateType.WebSearch,
|
121 |
+
subtype: MessageWebSearchUpdateType.Update,
|
122 |
+
message: update.message,
|
123 |
+
args: update.args,
|
124 |
+
};
|
125 |
+
} else if (update.messageType === "error") {
|
126 |
+
return {
|
127 |
+
type: MessageUpdateType.WebSearch,
|
128 |
+
subtype: MessageWebSearchUpdateType.Error,
|
129 |
+
message: update.message,
|
130 |
+
args: update.args,
|
131 |
+
};
|
132 |
+
} else if (update.messageType === "sources") {
|
133 |
+
return {
|
134 |
+
type: MessageUpdateType.WebSearch,
|
135 |
+
subtype: MessageWebSearchUpdateType.Sources,
|
136 |
+
message: update.message,
|
137 |
+
sources: update.sources ?? [],
|
138 |
+
};
|
139 |
+
}
|
140 |
+
}
|
141 |
+
console.warn("Unknown message update during migration:", update);
|
142 |
+
return null;
|
143 |
+
} catch (error) {
|
144 |
+
console.error("Error converting message update during migration. Skipping it... Error:", error);
|
145 |
+
return null;
|
146 |
+
}
|
147 |
+
}
|
148 |
+
|
149 |
+
const updateMessageUpdates: Migration = {
|
150 |
+
_id: new ObjectId("5f9f4f4f4f4f4f4f4f4f4f4f"),
|
151 |
+
name: "Convert message updates to the new schema",
|
152 |
+
up: async () => {
|
153 |
+
const allConversations = collections.conversations.find({}, { projection: { messages: 1 } });
|
154 |
+
|
155 |
+
let conversation: WithId<Pick<Conversation, "messages">> | null = null;
|
156 |
+
while ((conversation = await allConversations.tryNext())) {
|
157 |
+
const messages = conversation.messages.map((message) => {
|
158 |
+
// Convert all of the existing updates to the new schema
|
159 |
+
const updates = message.updates
|
160 |
+
?.map((update) => convertMessageUpdate(message, update as OldMessageUpdate))
|
161 |
+
.filter((update): update is MessageUpdate => Boolean(update));
|
162 |
+
|
163 |
+
// Add the new web search finished update if the sources update exists and webSearch is defined
|
164 |
+
const webSearchSourcesUpdateIndex = updates?.findIndex(isMessageWebSearchSourcesUpdate);
|
165 |
+
if (
|
166 |
+
message.webSearch &&
|
167 |
+
updates &&
|
168 |
+
webSearchSourcesUpdateIndex &&
|
169 |
+
webSearchSourcesUpdateIndex !== -1
|
170 |
+
) {
|
171 |
+
const webSearchFinishedUpdate: MessageWebSearchFinishedUpdate = {
|
172 |
+
type: MessageUpdateType.WebSearch,
|
173 |
+
subtype: MessageWebSearchUpdateType.Finished,
|
174 |
+
webSearch: message.webSearch,
|
175 |
+
};
|
176 |
+
updates.splice(webSearchSourcesUpdateIndex + 1, 0, webSearchFinishedUpdate);
|
177 |
+
}
|
178 |
+
return { ...message, updates };
|
179 |
+
});
|
180 |
+
|
181 |
+
// Set the new messages array
|
182 |
+
await collections.conversations.updateOne({ _id: conversation._id }, { $set: { messages } });
|
183 |
+
}
|
184 |
+
|
185 |
+
return true;
|
186 |
+
},
|
187 |
+
runEveryTime: false,
|
188 |
+
};
|
189 |
+
|
190 |
+
export default updateMessageUpdates;
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ObjectId, type WithId } from "mongodb";
|
2 |
+
import { collections } from "$lib/server/database";
|
3 |
+
|
4 |
+
import type { Migration } from ".";
|
5 |
+
import type { Conversation } from "$lib/types/Conversation";
|
6 |
+
import type { MessageFile } from "$lib/types/Message";
|
7 |
+
|
8 |
+
const updateMessageFiles: Migration = {
|
9 |
+
_id: new ObjectId("5f9f5f5f5f5f5f5f5f5f5f5f"),
|
10 |
+
name: "Convert message files to the new schema",
|
11 |
+
up: async () => {
|
12 |
+
const allConversations = collections.conversations.find({}, { projection: { messages: 1 } });
|
13 |
+
|
14 |
+
let conversation: WithId<Pick<Conversation, "messages">> | null = null;
|
15 |
+
while ((conversation = await allConversations.tryNext())) {
|
16 |
+
const messages = conversation.messages.map((message) => {
|
17 |
+
const files = (message.files as string[] | undefined)?.map<MessageFile>((file) => {
|
18 |
+
// File is already in the new format
|
19 |
+
if (typeof file !== "string") return file;
|
20 |
+
|
21 |
+
// File was a hash pointing to a file in the bucket
|
22 |
+
if (file.length === 64) {
|
23 |
+
return {
|
24 |
+
type: "hash",
|
25 |
+
name: "unknown.jpg",
|
26 |
+
value: file,
|
27 |
+
mime: "image/jpeg",
|
28 |
+
};
|
29 |
+
}
|
30 |
+
// File was a base64 string
|
31 |
+
else {
|
32 |
+
return {
|
33 |
+
type: "base64",
|
34 |
+
name: "unknown.jpg",
|
35 |
+
value: file,
|
36 |
+
mime: "image/jpeg",
|
37 |
+
};
|
38 |
+
}
|
39 |
+
});
|
40 |
+
|
41 |
+
return {
|
42 |
+
...message,
|
43 |
+
files,
|
44 |
+
};
|
45 |
+
});
|
46 |
+
|
47 |
+
// Set the new messages array
|
48 |
+
await collections.conversations.updateOne({ _id: conversation._id }, { $set: { messages } });
|
49 |
+
}
|
50 |
+
|
51 |
+
return true;
|
52 |
+
},
|
53 |
+
runEveryTime: false,
|
54 |
+
};
|
55 |
+
|
56 |
+
export default updateMessageFiles;
|
@@ -3,6 +3,9 @@ import type { ObjectId } from "mongodb";
|
|
3 |
import updateSearchAssistant from "./01-update-search-assistants";
|
4 |
import updateAssistantsModels from "./02-update-assistants-models";
|
5 |
import type { Database } from "$lib/server/database";
|
|
|
|
|
|
|
6 |
|
7 |
export interface Migration {
|
8 |
_id: ObjectId;
|
@@ -14,4 +17,10 @@ export interface Migration {
|
|
14 |
runEveryTime?: boolean;
|
15 |
}
|
16 |
|
17 |
-
export const migrations: Migration[] = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
import updateSearchAssistant from "./01-update-search-assistants";
|
4 |
import updateAssistantsModels from "./02-update-assistants-models";
|
5 |
import type { Database } from "$lib/server/database";
|
6 |
+
import addToolsToSettings from "./03-add-tools-in-settings";
|
7 |
+
import updateMessageUpdates from "./04-update-message-updates";
|
8 |
+
import updateMessageFiles from "./05-update-message-files";
|
9 |
|
10 |
export interface Migration {
|
11 |
_id: ObjectId;
|
|
|
17 |
runEveryTime?: boolean;
|
18 |
}
|
19 |
|
20 |
+
export const migrations: Migration[] = [
|
21 |
+
updateSearchAssistant,
|
22 |
+
updateAssistantsModels,
|
23 |
+
addToolsToSettings,
|
24 |
+
updateMessageUpdates,
|
25 |
+
updateMessageFiles,
|
26 |
+
];
|
@@ -4,6 +4,9 @@ import type { Endpoint } from "../endpoints";
|
|
4 |
import type { TextGenerationStreamOutput } from "@huggingface/inference";
|
5 |
import type { Cohere, CohereClient } from "cohere-ai";
|
6 |
import { buildPrompt } from "$lib/buildPrompt";
|
|
|
|
|
|
|
7 |
|
8 |
export const endpointCohereParametersSchema = z.object({
|
9 |
weight: z.number().int().positive().default(1),
|
@@ -28,12 +31,18 @@ export async function endpointCohere(
|
|
28 |
throw new Error("Failed to import cohere-ai", { cause: e });
|
29 |
}
|
30 |
|
31 |
-
return async ({ messages, preprompt, generateSettings, continueMessage }) => {
|
32 |
let system = preprompt;
|
33 |
if (messages?.[0]?.from === "system") {
|
34 |
system = messages[0].content;
|
35 |
}
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
const parameters = { ...model.parameters, ...generateSettings };
|
38 |
|
39 |
return (async function* () {
|
@@ -42,10 +51,12 @@ export async function endpointCohere(
|
|
42 |
|
43 |
if (raw) {
|
44 |
const prompt = await buildPrompt({
|
45 |
-
messages
|
46 |
model,
|
47 |
preprompt: system,
|
48 |
continueMessage,
|
|
|
|
|
49 |
});
|
50 |
|
51 |
stream = await cohere.chatStream({
|
@@ -67,18 +78,35 @@ export async function endpointCohere(
|
|
67 |
message: message.content,
|
68 |
})) satisfies Cohere.ChatMessage[];
|
69 |
|
70 |
-
stream = await cohere
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
}
|
83 |
|
84 |
for await (const output of stream) {
|
@@ -93,6 +121,18 @@ export async function endpointCohere(
|
|
93 |
generated_text: null,
|
94 |
details: null,
|
95 |
} satisfies TextGenerationStreamOutput;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
} else if (output.eventType === "stream-end") {
|
97 |
if (["ERROR", "ERROR_TOXIC", "ERROR_LIMIT"].includes(output.finishReason)) {
|
98 |
throw new Error(output.finishReason);
|
@@ -112,3 +152,26 @@ export async function endpointCohere(
|
|
112 |
})();
|
113 |
};
|
114 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
import type { TextGenerationStreamOutput } from "@huggingface/inference";
|
5 |
import type { Cohere, CohereClient } from "cohere-ai";
|
6 |
import { buildPrompt } from "$lib/buildPrompt";
|
7 |
+
import { ToolResultStatus, type ToolCall } from "$lib/types/Tool";
|
8 |
+
import { pipeline, Writable, Readable } from "node:stream";
|
9 |
+
import { toolHasName } from "$lib/utils/tools";
|
10 |
|
11 |
export const endpointCohereParametersSchema = z.object({
|
12 |
weight: z.number().int().positive().default(1),
|
|
|
31 |
throw new Error("Failed to import cohere-ai", { cause: e });
|
32 |
}
|
33 |
|
34 |
+
return async ({ messages, preprompt, generateSettings, continueMessage, tools, toolResults }) => {
|
35 |
let system = preprompt;
|
36 |
if (messages?.[0]?.from === "system") {
|
37 |
system = messages[0].content;
|
38 |
}
|
39 |
|
40 |
+
// Tools must use [A-z_] for their names and directly_answer is banned
|
41 |
+
// It's safe to convert the tool names because we treat - and _ the same
|
42 |
+
tools = tools
|
43 |
+
?.filter((tool) => !toolHasName("directly_answer", tool))
|
44 |
+
.map((tool) => ({ ...tool, name: tool.name.replaceAll("-", "_") }));
|
45 |
+
|
46 |
const parameters = { ...model.parameters, ...generateSettings };
|
47 |
|
48 |
return (async function* () {
|
|
|
51 |
|
52 |
if (raw) {
|
53 |
const prompt = await buildPrompt({
|
54 |
+
messages,
|
55 |
model,
|
56 |
preprompt: system,
|
57 |
continueMessage,
|
58 |
+
tools,
|
59 |
+
toolResults,
|
60 |
});
|
61 |
|
62 |
stream = await cohere.chatStream({
|
|
|
78 |
message: message.content,
|
79 |
})) satisfies Cohere.ChatMessage[];
|
80 |
|
81 |
+
stream = await cohere
|
82 |
+
.chatStream({
|
83 |
+
model: model.id ?? model.name,
|
84 |
+
chatHistory: formattedMessages.slice(0, -1),
|
85 |
+
message: formattedMessages[formattedMessages.length - 1].message,
|
86 |
+
preamble: system,
|
87 |
+
p: parameters?.top_p,
|
88 |
+
k: parameters?.top_k,
|
89 |
+
maxTokens: parameters?.max_new_tokens,
|
90 |
+
temperature: parameters?.temperature,
|
91 |
+
stopSequences: parameters?.stop,
|
92 |
+
frequencyPenalty: parameters?.frequency_penalty,
|
93 |
+
tools,
|
94 |
+
toolResults: toolResults?.map((toolResult) => {
|
95 |
+
if (toolResult.status === ToolResultStatus.Error) {
|
96 |
+
return { call: toolResult.call, outputs: [{ error: toolResult.message }] };
|
97 |
+
}
|
98 |
+
return { call: toolResult.call, outputs: toolResult.outputs };
|
99 |
+
}),
|
100 |
+
})
|
101 |
+
.catch(async (err) => {
|
102 |
+
if (!err.body) throw err;
|
103 |
+
|
104 |
+
// Decode the error message and throw
|
105 |
+
const message = await convertStreamToBuffer(err.body).catch(() => {
|
106 |
+
throw err;
|
107 |
+
});
|
108 |
+
throw Error(message, { cause: err });
|
109 |
+
});
|
110 |
}
|
111 |
|
112 |
for await (const output of stream) {
|
|
|
121 |
generated_text: null,
|
122 |
details: null,
|
123 |
} satisfies TextGenerationStreamOutput;
|
124 |
+
} else if (output.eventType === "tool-calls-generation") {
|
125 |
+
yield {
|
126 |
+
token: {
|
127 |
+
id: tokenId++,
|
128 |
+
text: "",
|
129 |
+
logprob: 0,
|
130 |
+
special: true,
|
131 |
+
toolCalls: output.toolCalls as ToolCall[],
|
132 |
+
},
|
133 |
+
generated_text: null,
|
134 |
+
details: null,
|
135 |
+
};
|
136 |
} else if (output.eventType === "stream-end") {
|
137 |
if (["ERROR", "ERROR_TOXIC", "ERROR_LIMIT"].includes(output.finishReason)) {
|
138 |
throw new Error(output.finishReason);
|
|
|
152 |
})();
|
153 |
};
|
154 |
}
|
155 |
+
|
156 |
+
async function convertStreamToBuffer(webReadableStream: Readable) {
|
157 |
+
return new Promise<string>((resolve, reject) => {
|
158 |
+
const chunks: Buffer[] = [];
|
159 |
+
|
160 |
+
pipeline(
|
161 |
+
webReadableStream,
|
162 |
+
new Writable({
|
163 |
+
write(chunk, _, callback) {
|
164 |
+
chunks.push(chunk);
|
165 |
+
callback();
|
166 |
+
},
|
167 |
+
}),
|
168 |
+
(err) => {
|
169 |
+
if (err) {
|
170 |
+
reject(err);
|
171 |
+
} else {
|
172 |
+
resolve(Buffer.concat(chunks).toString("utf-8"));
|
173 |
+
}
|
174 |
+
}
|
175 |
+
);
|
176 |
+
});
|
177 |
+
}
|
@@ -1,6 +1,6 @@
|
|
1 |
import type { Conversation } from "$lib/types/Conversation";
|
2 |
import type { Message } from "$lib/types/Message";
|
3 |
-
import type { TextGenerationStreamOutput } from "@huggingface/inference";
|
4 |
import { endpointTgi, endpointTgiParametersSchema } from "./tgi/endpointTgi";
|
5 |
import { z } from "zod";
|
6 |
import endpointAws, { endpointAwsParametersSchema } from "./aws/endpointAws";
|
@@ -26,23 +26,31 @@ import endpointLangserve, {
|
|
26 |
endpointLangserveParametersSchema,
|
27 |
} from "./langserve/endpointLangserve";
|
28 |
|
|
|
|
|
29 |
export type EndpointMessage = Omit<Message, "id">;
|
|
|
30 |
// parameters passed when generating text
|
31 |
export interface EndpointParameters {
|
32 |
messages: EndpointMessage[];
|
33 |
preprompt?: Conversation["preprompt"];
|
34 |
continueMessage?: boolean; // used to signal that the last message will be extended
|
35 |
generateSettings?: Partial<Model["parameters"]>;
|
|
|
|
|
36 |
isMultimodal?: boolean;
|
37 |
}
|
38 |
|
39 |
interface CommonEndpoint {
|
40 |
weight: number;
|
41 |
}
|
|
|
|
|
|
|
42 |
// type signature for the endpoint
|
43 |
export type Endpoint = (
|
44 |
params: EndpointParameters
|
45 |
-
) => Promise<AsyncGenerator<
|
46 |
|
47 |
// generator function that takes in parameters for defining the endpoint and return the endpoint
|
48 |
export type EndpointGenerator<T extends CommonEndpoint> = (parameters: T) => Endpoint;
|
|
|
1 |
import type { Conversation } from "$lib/types/Conversation";
|
2 |
import type { Message } from "$lib/types/Message";
|
3 |
+
import type { TextGenerationStreamOutput, TextGenerationStreamToken } from "@huggingface/inference";
|
4 |
import { endpointTgi, endpointTgiParametersSchema } from "./tgi/endpointTgi";
|
5 |
import { z } from "zod";
|
6 |
import endpointAws, { endpointAwsParametersSchema } from "./aws/endpointAws";
|
|
|
26 |
endpointLangserveParametersSchema,
|
27 |
} from "./langserve/endpointLangserve";
|
28 |
|
29 |
+
import type { Tool, ToolCall, ToolResult } from "$lib/types/Tool";
|
30 |
+
|
31 |
export type EndpointMessage = Omit<Message, "id">;
|
32 |
+
|
33 |
// parameters passed when generating text
|
34 |
export interface EndpointParameters {
|
35 |
messages: EndpointMessage[];
|
36 |
preprompt?: Conversation["preprompt"];
|
37 |
continueMessage?: boolean; // used to signal that the last message will be extended
|
38 |
generateSettings?: Partial<Model["parameters"]>;
|
39 |
+
tools?: Tool[];
|
40 |
+
toolResults?: ToolResult[];
|
41 |
isMultimodal?: boolean;
|
42 |
}
|
43 |
|
44 |
interface CommonEndpoint {
|
45 |
weight: number;
|
46 |
}
|
47 |
+
type TextGenerationStreamOutputWithTools = TextGenerationStreamOutput & {
|
48 |
+
token: TextGenerationStreamToken & { toolCalls?: ToolCall[] };
|
49 |
+
};
|
50 |
// type signature for the endpoint
|
51 |
export type Endpoint = (
|
52 |
params: EndpointParameters
|
53 |
+
) => Promise<AsyncGenerator<TextGenerationStreamOutputWithTools, void, void>>;
|
54 |
|
55 |
// generator function that takes in parameters for defining the endpoint and return the endpoint
|
56 |
export type EndpointGenerator<T extends CommonEndpoint> = (parameters: T) => Endpoint;
|
@@ -35,7 +35,15 @@ export function endpointTgi(input: z.input<typeof endpointTgiParametersSchema>):
|
|
35 |
endpointTgiParametersSchema.parse(input);
|
36 |
const imageProcessor = makeImageProcessor(multimodal.image);
|
37 |
|
38 |
-
return async ({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
const messagesWithResizedFiles = await Promise.all(
|
40 |
messages.map((message) => prepareMessage(Boolean(isMultimodal), message, imageProcessor))
|
41 |
);
|
@@ -45,6 +53,8 @@ export function endpointTgi(input: z.input<typeof endpointTgiParametersSchema>):
|
|
45 |
preprompt,
|
46 |
model,
|
47 |
continueMessage,
|
|
|
|
|
48 |
});
|
49 |
|
50 |
return textGenerationStream(
|
|
|
35 |
endpointTgiParametersSchema.parse(input);
|
36 |
const imageProcessor = makeImageProcessor(multimodal.image);
|
37 |
|
38 |
+
return async ({
|
39 |
+
messages,
|
40 |
+
preprompt,
|
41 |
+
continueMessage,
|
42 |
+
generateSettings,
|
43 |
+
tools,
|
44 |
+
toolResults,
|
45 |
+
isMultimodal,
|
46 |
+
}) => {
|
47 |
const messagesWithResizedFiles = await Promise.all(
|
48 |
messages.map((message) => prepareMessage(Boolean(isMultimodal), message, imageProcessor))
|
49 |
);
|
|
|
53 |
preprompt,
|
54 |
model,
|
55 |
continueMessage,
|
56 |
+
tools,
|
57 |
+
toolResults,
|
58 |
});
|
59 |
|
60 |
return textGenerationStream(
|
@@ -9,29 +9,26 @@ export async function downloadFile(
|
|
9 |
convId: Conversation["_id"] | SharedConversation["_id"]
|
10 |
): Promise<MessageFile & { type: "base64" }> {
|
11 |
const fileId = collections.bucket.find({ filename: `${convId.toString()}-${sha256}` });
|
12 |
-
let mime = "";
|
13 |
|
14 |
-
const
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
|
22 |
-
|
|
|
23 |
|
24 |
-
|
25 |
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
});
|
32 |
-
|
33 |
-
return fileBuffer;
|
34 |
});
|
35 |
|
36 |
-
return { type: "base64", value: buffer.toString("base64"), mime };
|
37 |
}
|
|
|
9 |
convId: Conversation["_id"] | SharedConversation["_id"]
|
10 |
): Promise<MessageFile & { type: "base64" }> {
|
11 |
const fileId = collections.bucket.find({ filename: `${convId.toString()}-${sha256}` });
|
|
|
12 |
|
13 |
+
const file = await fileId.next();
|
14 |
+
if (!file) {
|
15 |
+
throw error(404, "File not found");
|
16 |
+
}
|
17 |
+
if (file.metadata?.conversation !== convId.toString()) {
|
18 |
+
throw error(403, "You don't have access to this file.");
|
19 |
+
}
|
20 |
|
21 |
+
const mime = file.metadata?.mime;
|
22 |
+
const name = file.filename;
|
23 |
|
24 |
+
const fileStream = collections.bucket.openDownloadStream(file._id);
|
25 |
|
26 |
+
const buffer = await new Promise<Buffer>((resolve, reject) => {
|
27 |
+
const chunks: Uint8Array[] = [];
|
28 |
+
fileStream.on("data", (chunk) => chunks.push(chunk));
|
29 |
+
fileStream.on("error", reject);
|
30 |
+
fileStream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
|
|
|
|
|
31 |
});
|
32 |
|
33 |
+
return { type: "base64", name, value: buffer.toString("base64"), mime };
|
34 |
}
|
@@ -20,7 +20,9 @@ export async function uploadFile(file: File, conv: Conversation): Promise<Messag
|
|
20 |
|
21 |
// only return the filename when upload throws a finish event or a 20s time out occurs
|
22 |
return new Promise((resolve, reject) => {
|
23 |
-
upload.once("finish", () =>
|
|
|
|
|
24 |
upload.once("error", reject);
|
25 |
setTimeout(() => reject(new Error("Upload timed out")), 20_000);
|
26 |
});
|
|
|
20 |
|
21 |
// only return the filename when upload throws a finish event or a 20s time out occurs
|
22 |
return new Promise((resolve, reject) => {
|
23 |
+
upload.once("finish", () =>
|
24 |
+
resolve({ type: "hash", value: sha, mime: file.type, name: file.name })
|
25 |
+
);
|
26 |
upload.once("error", reject);
|
27 |
setTimeout(() => reject(new Error("Upload timed out")), 20_000);
|
28 |
});
|
@@ -12,6 +12,7 @@ import type { PreTrainedTokenizer } from "@xenova/transformers";
|
|
12 |
import JSON5 from "json5";
|
13 |
import { getTokenizer } from "$lib/utils/getTokenizer";
|
14 |
import { logger } from "$lib/server/logger";
|
|
|
15 |
|
16 |
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
17 |
|
@@ -61,6 +62,7 @@ const modelConfig = z.object({
|
|
61 |
.passthrough()
|
62 |
.optional(),
|
63 |
multimodal: z.boolean().default(false),
|
|
|
64 |
unlisted: z.boolean().default(false),
|
65 |
embeddingModel: validateEmbeddingModelByName(embeddingModels).optional(),
|
66 |
});
|
@@ -94,7 +96,7 @@ async function getChatPromptRender(
|
|
94 |
process.exit();
|
95 |
}
|
96 |
|
97 |
-
const renderTemplate = ({ messages, preprompt }: ChatTemplateInput) => {
|
98 |
let formattedMessages: { role: string; content: string }[] = messages.map((message) => ({
|
99 |
content: message.content,
|
100 |
role: message.from,
|
@@ -110,9 +112,64 @@ async function getChatPromptRender(
|
|
110 |
];
|
111 |
}
|
112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
const output = tokenizer.apply_chat_template(formattedMessages, {
|
114 |
tokenize: false,
|
115 |
add_generation_prompt: true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
});
|
117 |
|
118 |
if (typeof output !== "string") {
|
@@ -134,6 +191,10 @@ const processModel = async (m: z.infer<typeof modelConfig>) => ({
|
|
134 |
parameters: { ...m.parameters, stop_sequences: m.parameters?.stop },
|
135 |
});
|
136 |
|
|
|
|
|
|
|
|
|
137 |
const addEndpoint = (m: Awaited<ReturnType<typeof processModel>>) => ({
|
138 |
...m,
|
139 |
getEndpoint: async (): Promise<Endpoint> => {
|
@@ -189,7 +250,9 @@ const addEndpoint = (m: Awaited<ReturnType<typeof processModel>>) => ({
|
|
189 |
},
|
190 |
});
|
191 |
|
192 |
-
export const models = await Promise.all(
|
|
|
|
|
193 |
|
194 |
export const defaultModel = models[0];
|
195 |
|
@@ -224,5 +287,5 @@ export const smallModel = env.TASK_MODEL
|
|
224 |
|
225 |
export type BackendModel = Optional<
|
226 |
typeof defaultModel,
|
227 |
-
"preprompt" | "parameters" | "multimodal" | "unlisted"
|
228 |
>;
|
|
|
12 |
import JSON5 from "json5";
|
13 |
import { getTokenizer } from "$lib/utils/getTokenizer";
|
14 |
import { logger } from "$lib/server/logger";
|
15 |
+
import { ToolResultStatus } from "$lib/types/Tool";
|
16 |
|
17 |
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
18 |
|
|
|
62 |
.passthrough()
|
63 |
.optional(),
|
64 |
multimodal: z.boolean().default(false),
|
65 |
+
tools: z.boolean().default(false),
|
66 |
unlisted: z.boolean().default(false),
|
67 |
embeddingModel: validateEmbeddingModelByName(embeddingModels).optional(),
|
68 |
});
|
|
|
96 |
process.exit();
|
97 |
}
|
98 |
|
99 |
+
const renderTemplate = ({ messages, preprompt, tools, toolResults }: ChatTemplateInput) => {
|
100 |
let formattedMessages: { role: string; content: string }[] = messages.map((message) => ({
|
101 |
content: message.content,
|
102 |
role: message.from,
|
|
|
112 |
];
|
113 |
}
|
114 |
|
115 |
+
if (toolResults?.length) {
|
116 |
+
// todo: should update the command r+ tokenizer to support system messages at any location
|
117 |
+
// or use the `rag` mode without the citations
|
118 |
+
formattedMessages = [
|
119 |
+
{
|
120 |
+
role: "system",
|
121 |
+
content:
|
122 |
+
"\n\n<results>\n" +
|
123 |
+
toolResults
|
124 |
+
.flatMap((result, idx) => {
|
125 |
+
if (result.status === ToolResultStatus.Error) {
|
126 |
+
return (
|
127 |
+
`Document: ${idx}\n` + `Tool "${result.call.name}" error\n` + result.message
|
128 |
+
);
|
129 |
+
}
|
130 |
+
return (
|
131 |
+
`Document: ${idx}\n` +
|
132 |
+
result.outputs
|
133 |
+
.flatMap((output) =>
|
134 |
+
Object.entries(output).map(([title, text]) => `${title}\n${text}`)
|
135 |
+
)
|
136 |
+
.join("\n")
|
137 |
+
);
|
138 |
+
})
|
139 |
+
.join("\n\n") +
|
140 |
+
"\n</results>",
|
141 |
+
},
|
142 |
+
...formattedMessages,
|
143 |
+
];
|
144 |
+
tools = [];
|
145 |
+
}
|
146 |
+
|
147 |
+
const chatTemplate = tools?.length ? "tool_use" : undefined;
|
148 |
+
|
149 |
+
const documents = (toolResults ?? []).flatMap((result) => {
|
150 |
+
if (result.status === ToolResultStatus.Error) {
|
151 |
+
return [{ title: `Tool "${result.call.name}" error`, text: "\n" + result.message }];
|
152 |
+
}
|
153 |
+
return result.outputs.flatMap((output) =>
|
154 |
+
Object.entries(output).map(([title, text]) => ({
|
155 |
+
title: `Tool "${result.call.name}" ${title}`,
|
156 |
+
text: "\n" + text,
|
157 |
+
}))
|
158 |
+
);
|
159 |
+
});
|
160 |
+
|
161 |
const output = tokenizer.apply_chat_template(formattedMessages, {
|
162 |
tokenize: false,
|
163 |
add_generation_prompt: true,
|
164 |
+
chat_template: chatTemplate,
|
165 |
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
166 |
+
// @ts-ignore
|
167 |
+
tools:
|
168 |
+
tools?.map(({ parameterDefinitions, ...tool }) => ({
|
169 |
+
parameter_definitions: parameterDefinitions,
|
170 |
+
...tool,
|
171 |
+
})) ?? [],
|
172 |
+
documents,
|
173 |
});
|
174 |
|
175 |
if (typeof output !== "string") {
|
|
|
191 |
parameters: { ...m.parameters, stop_sequences: m.parameters?.stop },
|
192 |
});
|
193 |
|
194 |
+
export type ProcessedModel = Awaited<ReturnType<typeof processModel>> & {
|
195 |
+
getEndpoint: () => Promise<Endpoint>;
|
196 |
+
};
|
197 |
+
|
198 |
const addEndpoint = (m: Awaited<ReturnType<typeof processModel>>) => ({
|
199 |
...m,
|
200 |
getEndpoint: async (): Promise<Endpoint> => {
|
|
|
250 |
},
|
251 |
});
|
252 |
|
253 |
+
export const models: ProcessedModel[] = await Promise.all(
|
254 |
+
modelsRaw.map((e) => processModel(e).then(addEndpoint))
|
255 |
+
);
|
256 |
|
257 |
export const defaultModel = models[0];
|
258 |
|
|
|
287 |
|
288 |
export type BackendModel = Optional<
|
289 |
typeof defaultModel,
|
290 |
+
"preprompt" | "parameters" | "multimodal" | "unlisted" | "tools"
|
291 |
>;
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { isURLLocal } from "../isURLLocal";
|
2 |
+
import { env } from "$env/dynamic/private";
|
3 |
+
import { collections } from "$lib/server/database";
|
4 |
+
import type { Assistant } from "$lib/types/Assistant";
|
5 |
+
import type { ObjectId } from "mongodb";
|
6 |
+
|
7 |
+
export async function processPreprompt(preprompt: string) {
|
8 |
+
const urlRegex = /{{\s?url=(.*?)\s?}}/g;
|
9 |
+
|
10 |
+
for (const match of preprompt.matchAll(urlRegex)) {
|
11 |
+
try {
|
12 |
+
const url = new URL(match[1]);
|
13 |
+
if ((await isURLLocal(url)) && env.ENABLE_LOCAL_FETCH !== "true") {
|
14 |
+
throw new Error("URL couldn't be fetched, it resolved to a local address.");
|
15 |
+
}
|
16 |
+
|
17 |
+
const res = await fetch(url.href);
|
18 |
+
|
19 |
+
if (!res.ok) {
|
20 |
+
throw new Error("URL couldn't be fetched, error " + res.status);
|
21 |
+
}
|
22 |
+
const text = await res.text();
|
23 |
+
preprompt = preprompt.replaceAll(match[0], text);
|
24 |
+
} catch (e) {
|
25 |
+
preprompt = preprompt.replaceAll(match[0], (e as Error).message);
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
return preprompt;
|
30 |
+
}
|
31 |
+
|
32 |
+
export async function getAssistantById(id?: ObjectId) {
|
33 |
+
return collections.assistants
|
34 |
+
.findOne<Pick<Assistant, "rag" | "dynamicPrompt" | "generateSettings">>(
|
35 |
+
{ _id: id },
|
36 |
+
{ projection: { rag: 1, dynamicPrompt: 1, generateSettings: 1 } }
|
37 |
+
)
|
38 |
+
.then((a) => a ?? undefined);
|
39 |
+
}
|
40 |
+
|
41 |
+
export function assistantHasWebSearch(assistant?: Pick<Assistant, "rag"> | null) {
|
42 |
+
return (
|
43 |
+
env.ENABLE_ASSISTANTS_RAG === "true" &&
|
44 |
+
!!assistant?.rag &&
|
45 |
+
(assistant.rag.allowedLinks.length > 0 ||
|
46 |
+
assistant.rag.allowedDomains.length > 0 ||
|
47 |
+
assistant.rag.allowAllDomains)
|
48 |
+
);
|
49 |
+
}
|
50 |
+
|
51 |
+
export function assistantHasDynamicPrompt(assistant?: Pick<Assistant, "dynamicPrompt">) {
|
52 |
+
return env.ENABLE_ASSISTANTS_RAG === "true" && Boolean(assistant?.dynamicPrompt);
|
53 |
+
}
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { ToolResult } from "$lib/types/Tool";
|
2 |
+
import { MessageUpdateType, type MessageUpdate } from "$lib/types/MessageUpdate";
|
3 |
+
import { AbortedGenerations } from "../abortedGenerations";
|
4 |
+
import type { TextGenerationContext } from "./types";
|
5 |
+
import type { EndpointMessage } from "../endpoints/endpoints";
|
6 |
+
|
7 |
+
type GenerateContext = Omit<TextGenerationContext, "messages"> & { messages: EndpointMessage[] };
|
8 |
+
|
9 |
+
export async function* generate(
|
10 |
+
{ model, endpoint, conv, messages, assistant, isContinue, promptedAt }: GenerateContext,
|
11 |
+
toolResults: ToolResult[],
|
12 |
+
preprompt?: string
|
13 |
+
): AsyncIterable<MessageUpdate> {
|
14 |
+
for await (const output of await endpoint({
|
15 |
+
messages,
|
16 |
+
preprompt,
|
17 |
+
continueMessage: isContinue,
|
18 |
+
generateSettings: assistant?.generateSettings,
|
19 |
+
toolResults,
|
20 |
+
})) {
|
21 |
+
// text generation completed
|
22 |
+
if (output.generated_text) {
|
23 |
+
let interrupted =
|
24 |
+
!output.token.special && !model.parameters.stop?.includes(output.token.text);
|
25 |
+
|
26 |
+
let text = output.generated_text.trimEnd();
|
27 |
+
for (const stopToken of model.parameters.stop ?? []) {
|
28 |
+
if (!text.endsWith(stopToken)) continue;
|
29 |
+
|
30 |
+
interrupted = false;
|
31 |
+
text = text.slice(0, text.length - stopToken.length);
|
32 |
+
}
|
33 |
+
|
34 |
+
yield { type: MessageUpdateType.FinalAnswer, text, interrupted };
|
35 |
+
continue;
|
36 |
+
}
|
37 |
+
|
38 |
+
// ignore special tokens
|
39 |
+
if (output.token.special) continue;
|
40 |
+
|
41 |
+
// pass down normal token
|
42 |
+
yield { type: MessageUpdateType.Stream, token: output.token.text };
|
43 |
+
|
44 |
+
// abort check
|
45 |
+
const date = AbortedGenerations.getInstance().getList().get(conv._id.toString());
|
46 |
+
if (date && date > promptedAt) break;
|
47 |
+
|
48 |
+
// no output check
|
49 |
+
if (!output) break;
|
50 |
+
}
|
51 |
+
}
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { runWebSearch } from "$lib/server/websearch/runWebSearch";
|
2 |
+
import { preprocessMessages } from "../endpoints/preprocessMessages";
|
3 |
+
|
4 |
+
import { generateTitleForConversation } from "./title";
|
5 |
+
import {
|
6 |
+
assistantHasDynamicPrompt,
|
7 |
+
assistantHasWebSearch,
|
8 |
+
getAssistantById,
|
9 |
+
processPreprompt,
|
10 |
+
} from "./assistant";
|
11 |
+
import { pickTools, runTools } from "./tools";
|
12 |
+
import type { WebSearch } from "$lib/types/WebSearch";
|
13 |
+
import {
|
14 |
+
type MessageUpdate,
|
15 |
+
MessageUpdateType,
|
16 |
+
MessageUpdateStatus,
|
17 |
+
} from "$lib/types/MessageUpdate";
|
18 |
+
import { generate } from "./generate";
|
19 |
+
import { mergeAsyncGenerators } from "$lib/utils/mergeAsyncGenerators";
|
20 |
+
import type { TextGenerationContext } from "./types";
|
21 |
+
|
22 |
+
export async function* textGeneration(ctx: TextGenerationContext) {
|
23 |
+
yield* mergeAsyncGenerators([
|
24 |
+
textGenerationWithoutTitle(ctx),
|
25 |
+
generateTitleForConversation(ctx.conv),
|
26 |
+
]);
|
27 |
+
}
|
28 |
+
|
29 |
+
async function* textGenerationWithoutTitle(
|
30 |
+
ctx: TextGenerationContext
|
31 |
+
): AsyncGenerator<MessageUpdate, undefined, undefined> {
|
32 |
+
yield {
|
33 |
+
type: MessageUpdateType.Status,
|
34 |
+
status: MessageUpdateStatus.Started,
|
35 |
+
};
|
36 |
+
|
37 |
+
ctx.assistant ??= await getAssistantById(ctx.conv.assistantId);
|
38 |
+
const { model, conv, messages, assistant, isContinue, webSearch, toolsPreference } = ctx;
|
39 |
+
const convId = conv._id;
|
40 |
+
|
41 |
+
// perform websearch if requested
|
42 |
+
// it can be because the user toggled the webSearch or because the assistant has webSearch enabled
|
43 |
+
// if tools are enabled, we don't perform it here since we will add the websearch as a tool
|
44 |
+
let webSearchResult: WebSearch | undefined;
|
45 |
+
if (
|
46 |
+
!isContinue &&
|
47 |
+
!model.tools &&
|
48 |
+
((webSearch && !conv.assistantId) || assistantHasWebSearch(assistant))
|
49 |
+
) {
|
50 |
+
webSearchResult = yield* runWebSearch(conv, messages, assistant?.rag);
|
51 |
+
}
|
52 |
+
|
53 |
+
let preprompt = conv.preprompt;
|
54 |
+
if (assistantHasDynamicPrompt(assistant) && preprompt) {
|
55 |
+
preprompt = await processPreprompt(preprompt);
|
56 |
+
if (messages[0].from === "system") messages[0].content = preprompt;
|
57 |
+
}
|
58 |
+
|
59 |
+
const tools = pickTools(toolsPreference, Boolean(assistant));
|
60 |
+
const toolResults = yield* runTools(ctx, tools, preprompt);
|
61 |
+
|
62 |
+
const processedMessages = await preprocessMessages(messages, webSearchResult, convId);
|
63 |
+
yield* generate({ ...ctx, messages: processedMessages }, toolResults, preprompt);
|
64 |
+
}
|
@@ -1,14 +1,41 @@
|
|
1 |
import { env } from "$env/dynamic/private";
|
2 |
import { generateFromDefaultEndpoint } from "$lib/server/generateFromDefaultEndpoint";
|
3 |
-
import type { EndpointMessage } from "
|
4 |
import { logger } from "$lib/server/logger";
|
|
|
|
|
5 |
|
6 |
-
export async function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
if (!env.LLM_SUMMERIZATION) {
|
8 |
return prompt.split(/\s+/g).slice(0, 5).join(" ");
|
9 |
}
|
10 |
|
11 |
const messages: Array<EndpointMessage> = [
|
|
|
|
|
|
|
|
|
|
|
12 |
{ from: "user", content: "Who is the president of Gabon?" },
|
13 |
{ from: "assistant", content: "🇬🇦 President of Gabon" },
|
14 |
{ from: "user", content: "Who is Julien Chaumond?" },
|
@@ -23,6 +50,8 @@ export async function summarize(prompt: string) {
|
|
23 |
{ from: "assistant", content: "🎥 Favorite movie" },
|
24 |
{ from: "user", content: "Explain the concept of artificial intelligence in one sentence" },
|
25 |
{ from: "assistant", content: "🤖 AI definition" },
|
|
|
|
|
26 |
{ from: "user", content: prompt },
|
27 |
];
|
28 |
|
|
|
1 |
import { env } from "$env/dynamic/private";
|
2 |
import { generateFromDefaultEndpoint } from "$lib/server/generateFromDefaultEndpoint";
|
3 |
+
import type { EndpointMessage } from "../endpoints/endpoints";
|
4 |
import { logger } from "$lib/server/logger";
|
5 |
+
import { MessageUpdateType, type MessageUpdate } from "$lib/types/MessageUpdate";
|
6 |
+
import type { Conversation } from "$lib/types/Conversation";
|
7 |
|
8 |
+
export async function* generateTitleForConversation(
|
9 |
+
conv: Conversation
|
10 |
+
): AsyncGenerator<MessageUpdate, undefined, undefined> {
|
11 |
+
try {
|
12 |
+
const userMessage = conv.messages.find((m) => m.from === "user");
|
13 |
+
// HACK: detect if the conversation is new
|
14 |
+
if (conv.title !== "New Chat" || !userMessage) return;
|
15 |
+
|
16 |
+
const prompt = userMessage.content;
|
17 |
+
const title = (await generateTitle(prompt)) ?? "New Chat";
|
18 |
+
|
19 |
+
yield {
|
20 |
+
type: MessageUpdateType.Title,
|
21 |
+
title,
|
22 |
+
};
|
23 |
+
} catch (cause) {
|
24 |
+
console.error(Error("Failed whilte generating title for conversation", { cause }));
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
export async function generateTitle(prompt: string) {
|
29 |
if (!env.LLM_SUMMERIZATION) {
|
30 |
return prompt.split(/\s+/g).slice(0, 5).join(" ");
|
31 |
}
|
32 |
|
33 |
const messages: Array<EndpointMessage> = [
|
34 |
+
{
|
35 |
+
from: "system",
|
36 |
+
content:
|
37 |
+
"You are a summarization AI. You'll never answer a user's question directly, but instead summarize the user's request into a single short sentence of four words or less. Always start your answer with an emoji relevant to the summary",
|
38 |
+
},
|
39 |
{ from: "user", content: "Who is the president of Gabon?" },
|
40 |
{ from: "assistant", content: "🇬🇦 President of Gabon" },
|
41 |
{ from: "user", content: "Who is Julien Chaumond?" },
|
|
|
50 |
{ from: "assistant", content: "🎥 Favorite movie" },
|
51 |
{ from: "user", content: "Explain the concept of artificial intelligence in one sentence" },
|
52 |
{ from: "assistant", content: "🤖 AI definition" },
|
53 |
+
{ from: "user", content: "Draw a cute cat" },
|
54 |
+
{ from: "assistant", content: "🐱 Cute cat drawing" },
|
55 |
{ from: "user", content: prompt },
|
56 |
];
|
57 |
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ToolResultStatus, type ToolCall, type ToolResult } from "$lib/types/Tool";
|
2 |
+
import { v4 as uuidV4 } from "uuid";
|
3 |
+
import JSON5 from "json5";
|
4 |
+
import type { BackendTool, BackendToolContext } from "../tools";
|
5 |
+
import {
|
6 |
+
MessageToolUpdateType,
|
7 |
+
MessageUpdateStatus,
|
8 |
+
MessageUpdateType,
|
9 |
+
type MessageUpdate,
|
10 |
+
} from "$lib/types/MessageUpdate";
|
11 |
+
import type { TextGenerationContext } from "./types";
|
12 |
+
|
13 |
+
import { allTools } from "../tools";
|
14 |
+
import directlyAnswer from "../tools/directlyAnswer";
|
15 |
+
import websearch from "../tools/web/search";
|
16 |
+
import { z } from "zod";
|
17 |
+
import { logger } from "../logger";
|
18 |
+
import { toolHasName } from "../tools/utils";
|
19 |
+
import type { MessageFile } from "$lib/types/Message";
|
20 |
+
import { mergeAsyncGenerators } from "$lib/utils/mergeAsyncGenerators";
|
21 |
+
|
22 |
+
function makeFilesPrompt(files: MessageFile[], fileMessageIndex: number): string {
|
23 |
+
if (files.length === 0) {
|
24 |
+
return "The user has not uploaded any files. Do not attempt to use any tools that require files";
|
25 |
+
}
|
26 |
+
|
27 |
+
const stringifiedFiles = files
|
28 |
+
.map(
|
29 |
+
(file, fileIndex) =>
|
30 |
+
` - fileMessageIndex ${fileMessageIndex} | fileIndex ${fileIndex} | ${file.name} (${file.mime})`
|
31 |
+
)
|
32 |
+
.join("\n");
|
33 |
+
return `Attached ${files.length} file${files.length === 1 ? "" : "s"}:\n${stringifiedFiles}`;
|
34 |
+
}
|
35 |
+
|
36 |
+
export function pickTools(
|
37 |
+
toolsPreference: Record<string, boolean>,
|
38 |
+
isAssistant: boolean
|
39 |
+
): BackendTool[] {
|
40 |
+
// if it's an assistant, only support websearch for now
|
41 |
+
if (isAssistant) return [directlyAnswer, websearch];
|
42 |
+
|
43 |
+
// filter based on tool preferences, add the tools that are on by default
|
44 |
+
return allTools.filter((el) => {
|
45 |
+
if (el.isLocked && el.isOnByDefault) return true;
|
46 |
+
return toolsPreference?.[el.name] ?? el.isOnByDefault;
|
47 |
+
});
|
48 |
+
}
|
49 |
+
|
50 |
+
async function* runTool(
|
51 |
+
{ conv, messages, preprompt, assistant }: BackendToolContext,
|
52 |
+
tools: BackendTool[],
|
53 |
+
call: ToolCall
|
54 |
+
): AsyncGenerator<MessageUpdate, ToolResult | undefined, undefined> {
|
55 |
+
const uuid = uuidV4();
|
56 |
+
|
57 |
+
const tool = tools.find((el) => toolHasName(call.name, el));
|
58 |
+
if (!tool) {
|
59 |
+
return { call, status: ToolResultStatus.Error, message: `Could not find tool "${call.name}"` };
|
60 |
+
}
|
61 |
+
|
62 |
+
// Special case for directly_answer tool where we ignore
|
63 |
+
if (toolHasName(directlyAnswer.name, tool)) return;
|
64 |
+
|
65 |
+
yield {
|
66 |
+
type: MessageUpdateType.Tool,
|
67 |
+
subtype: MessageToolUpdateType.Call,
|
68 |
+
uuid,
|
69 |
+
call,
|
70 |
+
};
|
71 |
+
try {
|
72 |
+
const toolResult = yield* tool.call(call.parameters, {
|
73 |
+
conv,
|
74 |
+
messages,
|
75 |
+
preprompt,
|
76 |
+
assistant,
|
77 |
+
});
|
78 |
+
yield {
|
79 |
+
type: MessageUpdateType.Tool,
|
80 |
+
subtype: MessageToolUpdateType.Result,
|
81 |
+
uuid,
|
82 |
+
result: { ...toolResult, call } as ToolResult,
|
83 |
+
};
|
84 |
+
return { ...toolResult, call } as ToolResult;
|
85 |
+
} catch (cause) {
|
86 |
+
console.error(Error(`Failed while running tool ${call.name}`), { cause });
|
87 |
+
return {
|
88 |
+
call,
|
89 |
+
status: ToolResultStatus.Error,
|
90 |
+
message: cause instanceof Error ? cause.message : String(cause),
|
91 |
+
};
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
export async function* runTools(
|
96 |
+
{ endpoint, conv, messages, assistant }: TextGenerationContext,
|
97 |
+
tools: BackendTool[],
|
98 |
+
preprompt?: string
|
99 |
+
): AsyncGenerator<MessageUpdate, ToolResult[], undefined> {
|
100 |
+
const calls: ToolCall[] = [];
|
101 |
+
|
102 |
+
const messagesWithFilesPrompt = messages.map((message, idx) => {
|
103 |
+
if (!message.files?.length) return message;
|
104 |
+
return {
|
105 |
+
...message,
|
106 |
+
content: `${message.content}\n${makeFilesPrompt(message.files, idx)}`,
|
107 |
+
};
|
108 |
+
});
|
109 |
+
|
110 |
+
// do the function calling bits here
|
111 |
+
for await (const output of await endpoint({
|
112 |
+
messages: messagesWithFilesPrompt,
|
113 |
+
preprompt,
|
114 |
+
generateSettings: assistant?.generateSettings,
|
115 |
+
tools,
|
116 |
+
})) {
|
117 |
+
// model natively supports tool calls
|
118 |
+
if (output.token.toolCalls) {
|
119 |
+
calls.push(...output.token.toolCalls);
|
120 |
+
continue;
|
121 |
+
}
|
122 |
+
|
123 |
+
// look for a code blocks of ```json and parse them
|
124 |
+
// if they're valid json, add them to the calls array
|
125 |
+
if (output.generated_text) {
|
126 |
+
const codeBlocks = Array.from(output.generated_text.matchAll(/```json\n(.*?)```/gs));
|
127 |
+
if (codeBlocks.length === 0) continue;
|
128 |
+
|
129 |
+
// grab only the capture group from the regex match
|
130 |
+
for (const [, block] of codeBlocks) {
|
131 |
+
try {
|
132 |
+
calls.push(
|
133 |
+
...JSON5.parse(block).filter(isExternalToolCall).map(externalToToolCall).filter(Boolean)
|
134 |
+
);
|
135 |
+
} catch (cause) {
|
136 |
+
// error parsing the calls
|
137 |
+
yield {
|
138 |
+
type: MessageUpdateType.Status,
|
139 |
+
status: MessageUpdateStatus.Error,
|
140 |
+
message: cause instanceof Error ? cause.message : String(cause),
|
141 |
+
};
|
142 |
+
}
|
143 |
+
}
|
144 |
+
}
|
145 |
+
}
|
146 |
+
|
147 |
+
const toolContext: BackendToolContext = { conv, messages, preprompt, assistant };
|
148 |
+
const toolResults: (ToolResult | undefined)[] = yield* mergeAsyncGenerators(
|
149 |
+
calls.map((call) => runTool(toolContext, tools, call))
|
150 |
+
);
|
151 |
+
return toolResults.filter((result): result is ToolResult => result !== undefined);
|
152 |
+
}
|
153 |
+
|
154 |
+
const externalToolCall = z.object({
|
155 |
+
tool_name: z.string(),
|
156 |
+
parameters: z.record(z.any()),
|
157 |
+
});
|
158 |
+
|
159 |
+
type ExternalToolCall = z.infer<typeof externalToolCall>;
|
160 |
+
|
161 |
+
function isExternalToolCall(call: unknown): call is ExternalToolCall {
|
162 |
+
return externalToolCall.safeParse(call).success;
|
163 |
+
}
|
164 |
+
|
165 |
+
function externalToToolCall(call: ExternalToolCall): ToolCall | undefined {
|
166 |
+
// Convert - to _ since some models insist on using _ instead of -
|
167 |
+
const tool = allTools.find((tool) => toolHasName(call.tool_name, tool));
|
168 |
+
if (!tool) {
|
169 |
+
logger.debug(`Model requested tool that does not exist: "${call.tool_name}". Skipping tool...`);
|
170 |
+
return;
|
171 |
+
}
|
172 |
+
|
173 |
+
const parametersWithDefaults: Record<string, string> = {};
|
174 |
+
|
175 |
+
for (const [key, definition] of Object.entries(tool.parameterDefinitions)) {
|
176 |
+
const value = call.parameters[key];
|
177 |
+
|
178 |
+
// Required so ensure it's there, otherwise return undefined
|
179 |
+
if (definition.required) {
|
180 |
+
if (value === undefined) {
|
181 |
+
logger.debug(
|
182 |
+
`Model requested tool "${call.tool_name}" but was missing required parameter "${key}". Skipping tool...`
|
183 |
+
);
|
184 |
+
return;
|
185 |
+
}
|
186 |
+
parametersWithDefaults[key] = value;
|
187 |
+
continue;
|
188 |
+
}
|
189 |
+
|
190 |
+
// Optional so use default if not there
|
191 |
+
parametersWithDefaults[key] = value ?? definition.default;
|
192 |
+
}
|
193 |
+
|
194 |
+
return {
|
195 |
+
name: call.tool_name,
|
196 |
+
parameters: parametersWithDefaults,
|
197 |
+
};
|
198 |
+
}
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { ProcessedModel } from "../models";
|
2 |
+
import type { Endpoint } from "../endpoints/endpoints";
|
3 |
+
import type { Conversation } from "$lib/types/Conversation";
|
4 |
+
import type { Message } from "$lib/types/Message";
|
5 |
+
import type { Assistant } from "$lib/types/Assistant";
|
6 |
+
|
7 |
+
export interface TextGenerationContext {
|
8 |
+
model: ProcessedModel;
|
9 |
+
endpoint: Endpoint;
|
10 |
+
conv: Conversation;
|
11 |
+
messages: Message[];
|
12 |
+
assistant?: Pick<Assistant, "rag" | "dynamicPrompt" | "generateSettings">;
|
13 |
+
isContinue: boolean;
|
14 |
+
webSearch: boolean;
|
15 |
+
toolsPreference: Record<string, boolean>;
|
16 |
+
promptedAt: Date;
|
17 |
+
}
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ToolResultStatus } from "$lib/types/Tool";
|
2 |
+
import type { BackendTool } from ".";
|
3 |
+
import vm from "node:vm";
|
4 |
+
|
5 |
+
const calculator: BackendTool = {
|
6 |
+
name: "query_calculator",
|
7 |
+
displayName: "Calculator",
|
8 |
+
description:
|
9 |
+
"A simple calculator, takes a string containing a mathematical expression and returns the answer. Only supports +, -, *, ** (power) and /, as well as parenthesis ().",
|
10 |
+
isOnByDefault: true,
|
11 |
+
parameterDefinitions: {
|
12 |
+
equation: {
|
13 |
+
description:
|
14 |
+
"The formula to evaluate. EXACTLY as you would plug into a calculator. No words, no letters, only numbers and operators. Letters will make the tool crash.",
|
15 |
+
type: "formula",
|
16 |
+
required: true,
|
17 |
+
},
|
18 |
+
},
|
19 |
+
async *call(params) {
|
20 |
+
try {
|
21 |
+
const blocks = String(params.equation).split("\n");
|
22 |
+
const query = blocks[blocks.length - 1].replace(/[^-()\d/*+.]/g, "");
|
23 |
+
|
24 |
+
return {
|
25 |
+
status: ToolResultStatus.Success,
|
26 |
+
outputs: [{ calculator: `${query} = ${vm.runInNewContext(query)}` }],
|
27 |
+
};
|
28 |
+
} catch (e) {
|
29 |
+
return {
|
30 |
+
status: ToolResultStatus.Error,
|
31 |
+
message: "Invalid expression",
|
32 |
+
};
|
33 |
+
}
|
34 |
+
},
|
35 |
+
};
|
36 |
+
|
37 |
+
export default calculator;
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ToolResultStatus } from "$lib/types/Tool";
|
2 |
+
import type { BackendTool } from ".";
|
3 |
+
|
4 |
+
const directlyAnswer: BackendTool = {
|
5 |
+
name: "directly_answer",
|
6 |
+
isOnByDefault: true,
|
7 |
+
isHidden: true,
|
8 |
+
isLocked: true,
|
9 |
+
description: "Use this tool to let the user know you wish to answer directly",
|
10 |
+
parameterDefinitions: {},
|
11 |
+
async *call() {
|
12 |
+
return {
|
13 |
+
status: ToolResultStatus.Success,
|
14 |
+
outputs: [],
|
15 |
+
display: false,
|
16 |
+
};
|
17 |
+
},
|
18 |
+
};
|
19 |
+
|
20 |
+
export default directlyAnswer;
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { BackendTool } from ".";
|
2 |
+
import { ToolResultStatus } from "$lib/types/Tool";
|
3 |
+
import { callSpace } from "./utils";
|
4 |
+
import { downloadFile } from "$lib/server/files/downloadFile";
|
5 |
+
|
6 |
+
type PdfParserInput = [Blob /* pdf */, string /* filename */];
|
7 |
+
type PdfParserOutput = [string /* markdown */, Record<string, unknown> /* metadata */];
|
8 |
+
|
9 |
+
const documentParser: BackendTool = {
|
10 |
+
name: "document_parser",
|
11 |
+
displayName: "Document Parser",
|
12 |
+
description: "Use this tool to parse any document and get its content in markdown format.",
|
13 |
+
isOnByDefault: true,
|
14 |
+
parameterDefinitions: {
|
15 |
+
fileMessageIndex: {
|
16 |
+
description: "Index of the message containing the document file to parse",
|
17 |
+
type: "number",
|
18 |
+
required: true,
|
19 |
+
},
|
20 |
+
fileIndex: {
|
21 |
+
description: "Index of the document file to parse",
|
22 |
+
type: "number",
|
23 |
+
required: true,
|
24 |
+
},
|
25 |
+
},
|
26 |
+
async *call({ fileMessageIndex, fileIndex }, { conv, messages }) {
|
27 |
+
fileMessageIndex = Number(fileMessageIndex);
|
28 |
+
fileIndex = Number(fileIndex);
|
29 |
+
|
30 |
+
const message = messages[fileMessageIndex];
|
31 |
+
const files = message?.files ?? [];
|
32 |
+
if (!files || files.length === 0) {
|
33 |
+
return {
|
34 |
+
status: ToolResultStatus.Error,
|
35 |
+
message: "User did not provide a pdf to parse",
|
36 |
+
};
|
37 |
+
}
|
38 |
+
if (fileIndex >= files.length) {
|
39 |
+
return {
|
40 |
+
status: ToolResultStatus.Error,
|
41 |
+
message: "Model provided an invalid file index",
|
42 |
+
};
|
43 |
+
}
|
44 |
+
|
45 |
+
const file = files[fileIndex];
|
46 |
+
const fileBlob = await downloadFile(files[fileIndex].value, conv._id)
|
47 |
+
.then((file) => fetch(`data:${file.mime};base64,${file.value}`))
|
48 |
+
.then((res) => res.blob());
|
49 |
+
|
50 |
+
const outputs = await callSpace<PdfParserInput, PdfParserOutput>(
|
51 |
+
"huggingchat/document-parser",
|
52 |
+
"predict",
|
53 |
+
[fileBlob, file.name]
|
54 |
+
);
|
55 |
+
|
56 |
+
let documentMarkdown = outputs[0];
|
57 |
+
// TODO: quick fix for avoiding context limit. eventually should use the tokenizer
|
58 |
+
if (documentMarkdown.length > 30_000) {
|
59 |
+
documentMarkdown = documentMarkdown.slice(0, 30_000) + "\n\n... (truncated)";
|
60 |
+
}
|
61 |
+
return {
|
62 |
+
status: ToolResultStatus.Success,
|
63 |
+
outputs: [{ [file.name]: documentMarkdown }],
|
64 |
+
display: false,
|
65 |
+
};
|
66 |
+
},
|
67 |
+
};
|
68 |
+
|
69 |
+
export default documentParser;
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { BackendTool } from "..";
|
2 |
+
import { uploadFile } from "../../files/uploadFile";
|
3 |
+
import { ToolResultStatus } from "$lib/types/Tool";
|
4 |
+
import { MessageUpdateType } from "$lib/types/MessageUpdate";
|
5 |
+
import { callSpace, type GradioImage } from "../utils";
|
6 |
+
import { downloadFile } from "$lib/server/files/downloadFile";
|
7 |
+
|
8 |
+
type ImageEditingInput = [
|
9 |
+
Blob /* image */,
|
10 |
+
string /* prompt */,
|
11 |
+
string /* negative prompt */,
|
12 |
+
number /* guidance scale */,
|
13 |
+
number /* steps */
|
14 |
+
];
|
15 |
+
type ImageEditingOutput = [GradioImage];
|
16 |
+
|
17 |
+
const imageEditing: BackendTool = {
|
18 |
+
name: "image_editing",
|
19 |
+
displayName: "Image Editing",
|
20 |
+
description: "Use this tool to edit an image from a prompt.",
|
21 |
+
isOnByDefault: true,
|
22 |
+
parameterDefinitions: {
|
23 |
+
prompt: {
|
24 |
+
description:
|
25 |
+
"A prompt to generate an image from. Describe the image visually in simple terms, separate terms with a comma.",
|
26 |
+
type: "string",
|
27 |
+
required: true,
|
28 |
+
},
|
29 |
+
fileMessageIndex: {
|
30 |
+
description: "Index of the message containing the file to edit",
|
31 |
+
type: "number",
|
32 |
+
required: true,
|
33 |
+
},
|
34 |
+
fileIndex: {
|
35 |
+
description: "Index of the file to edit",
|
36 |
+
type: "number",
|
37 |
+
required: true,
|
38 |
+
},
|
39 |
+
},
|
40 |
+
async *call({ prompt, fileMessageIndex, fileIndex }, { conv, messages }) {
|
41 |
+
prompt = String(prompt);
|
42 |
+
fileMessageIndex = Number(fileMessageIndex);
|
43 |
+
fileIndex = Number(fileIndex);
|
44 |
+
|
45 |
+
const message = messages[fileMessageIndex];
|
46 |
+
const images = message?.files ?? [];
|
47 |
+
if (!images || images.length === 0) {
|
48 |
+
return {
|
49 |
+
status: ToolResultStatus.Error,
|
50 |
+
message: "User did not provide an image to edit.",
|
51 |
+
};
|
52 |
+
}
|
53 |
+
if (fileIndex >= images.length) {
|
54 |
+
return {
|
55 |
+
status: ToolResultStatus.Error,
|
56 |
+
message: "Model provided an invalid file index",
|
57 |
+
};
|
58 |
+
}
|
59 |
+
if (!images[fileIndex].mime.startsWith("image/")) {
|
60 |
+
return {
|
61 |
+
status: ToolResultStatus.Error,
|
62 |
+
message: "Model provided a file indx which is not an image",
|
63 |
+
};
|
64 |
+
}
|
65 |
+
|
66 |
+
// todo: should handle multiple images
|
67 |
+
const image = await downloadFile(images[fileIndex].value, conv._id)
|
68 |
+
.then((file) => fetch(`data:${file.mime};base64,${file.value}`))
|
69 |
+
.then((res) => res.blob());
|
70 |
+
|
71 |
+
const outputs = await callSpace<ImageEditingInput, ImageEditingOutput>(
|
72 |
+
"multimodalart/cosxl",
|
73 |
+
"run_edit",
|
74 |
+
[
|
75 |
+
image,
|
76 |
+
prompt,
|
77 |
+
"", // negative prompt
|
78 |
+
7, // guidance scale
|
79 |
+
20, // steps
|
80 |
+
]
|
81 |
+
);
|
82 |
+
|
83 |
+
const outputImage = await fetch(outputs[0].url)
|
84 |
+
.then((res) => res.blob())
|
85 |
+
.then((blob) => new File([blob], outputs[0].orig_name, { type: blob.type }))
|
86 |
+
.then((file) => uploadFile(file, conv));
|
87 |
+
|
88 |
+
yield {
|
89 |
+
type: MessageUpdateType.File,
|
90 |
+
name: outputImage.name,
|
91 |
+
sha: outputImage.value,
|
92 |
+
mime: outputImage.mime,
|
93 |
+
};
|
94 |
+
|
95 |
+
return {
|
96 |
+
status: ToolResultStatus.Success,
|
97 |
+
outputs: [
|
98 |
+
{
|
99 |
+
imageEditing: `An image has been generated for the following prompt: "${prompt}". Answer as if the user can already see the image. Do not try to insert the image or to add space for it. The user can already see the image. Do not try to describe the image as you the model cannot see it.`,
|
100 |
+
},
|
101 |
+
],
|
102 |
+
display: false,
|
103 |
+
};
|
104 |
+
},
|
105 |
+
};
|
106 |
+
|
107 |
+
export default imageEditing;
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { BackendTool } from "..";
|
2 |
+
import { uploadFile } from "../../files/uploadFile";
|
3 |
+
import { ToolResultStatus } from "$lib/types/Tool";
|
4 |
+
import { MessageUpdateType } from "$lib/types/MessageUpdate";
|
5 |
+
import { callSpace, type GradioImage } from "../utils";
|
6 |
+
|
7 |
+
type ImageGenerationInput = [
|
8 |
+
number /* number (numeric value between 1 and 8) in 'Number of Images' Slider component */,
|
9 |
+
number /* number in 'Image Height' Number component */,
|
10 |
+
number /* number in 'Image Width' Number component */,
|
11 |
+
string /* prompt */,
|
12 |
+
number /* seed random */
|
13 |
+
];
|
14 |
+
type ImageGenerationOutput = [{ image: GradioImage }[]];
|
15 |
+
|
16 |
+
const imageGeneration: BackendTool = {
|
17 |
+
name: "image_generation",
|
18 |
+
displayName: "Image Generation",
|
19 |
+
description: "Use this tool to generate an image from a prompt.",
|
20 |
+
isOnByDefault: true,
|
21 |
+
parameterDefinitions: {
|
22 |
+
prompt: {
|
23 |
+
description:
|
24 |
+
"A prompt to generate an image from. Describe the image visually in simple terms, separate terms with a comma.",
|
25 |
+
type: "string",
|
26 |
+
required: true,
|
27 |
+
},
|
28 |
+
numberOfImages: {
|
29 |
+
description: "Number of images to generate, between 1 and 8.",
|
30 |
+
type: "number",
|
31 |
+
required: false,
|
32 |
+
default: 1,
|
33 |
+
},
|
34 |
+
width: {
|
35 |
+
description: "Width of the generated image.",
|
36 |
+
type: "number",
|
37 |
+
required: false,
|
38 |
+
default: 1024,
|
39 |
+
},
|
40 |
+
height: {
|
41 |
+
description: "Height of the generated image.",
|
42 |
+
type: "number",
|
43 |
+
required: false,
|
44 |
+
default: 1024,
|
45 |
+
},
|
46 |
+
},
|
47 |
+
async *call({ prompt, numberOfImages }, { conv }) {
|
48 |
+
const outputs = await callSpace<ImageGenerationInput, ImageGenerationOutput>(
|
49 |
+
"ByteDance/Hyper-SDXL-1Step-T2I",
|
50 |
+
"/process_image",
|
51 |
+
[
|
52 |
+
Number(numberOfImages), // number (numeric value between 1 and 8) in 'Number of Images' Slider component
|
53 |
+
512, // number in 'Image Height' Number component
|
54 |
+
512, // number in 'Image Width' Number component
|
55 |
+
String(prompt), // prompt
|
56 |
+
Math.floor(Math.random() * 1000), // seed random
|
57 |
+
]
|
58 |
+
);
|
59 |
+
const imageBlobs = await Promise.all(
|
60 |
+
outputs[0].map((output) =>
|
61 |
+
fetch(output.image.url)
|
62 |
+
.then((res) => res.blob())
|
63 |
+
.then(
|
64 |
+
(blob) =>
|
65 |
+
new File([blob], `${prompt}.${blob.type.split("/")[1] ?? "png"}`, { type: blob.type })
|
66 |
+
)
|
67 |
+
.then((file) => uploadFile(file, conv))
|
68 |
+
)
|
69 |
+
);
|
70 |
+
|
71 |
+
for (const image of imageBlobs) {
|
72 |
+
yield {
|
73 |
+
type: MessageUpdateType.File,
|
74 |
+
name: image.name,
|
75 |
+
sha: image.value,
|
76 |
+
mime: image.mime,
|
77 |
+
};
|
78 |
+
}
|
79 |
+
|
80 |
+
return {
|
81 |
+
status: ToolResultStatus.Success,
|
82 |
+
outputs: [
|
83 |
+
{
|
84 |
+
imageGeneration: `An image has been generated for the following prompt: "${prompt}". Answer as if the user can already see the image. Do not try to insert the image or to add space for it. The user can already see the image. Do not try to describe the image as you the model cannot see it.`,
|
85 |
+
},
|
86 |
+
],
|
87 |
+
display: false,
|
88 |
+
};
|
89 |
+
},
|
90 |
+
};
|
91 |
+
|
92 |
+
export default imageGeneration;
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { Assistant } from "$lib/types/Assistant";
|
2 |
+
import type { Conversation } from "$lib/types/Conversation";
|
3 |
+
import type { Message } from "$lib/types/Message";
|
4 |
+
import type { MessageUpdate } from "$lib/types/MessageUpdate";
|
5 |
+
import type { Tool, ToolResult } from "$lib/types/Tool";
|
6 |
+
|
7 |
+
import calculator from "./calculator";
|
8 |
+
import directlyAnswer from "./directlyAnswer";
|
9 |
+
import imageEditing from "./images/editing";
|
10 |
+
import imageGeneration from "./images/generation";
|
11 |
+
import documentParser from "./documentParser";
|
12 |
+
import fetchUrl from "./web/url";
|
13 |
+
import websearch from "./web/search";
|
14 |
+
|
15 |
+
export interface BackendToolContext {
|
16 |
+
conv: Conversation;
|
17 |
+
messages: Message[];
|
18 |
+
preprompt?: string;
|
19 |
+
assistant?: Pick<Assistant, "rag" | "dynamicPrompt" | "generateSettings">;
|
20 |
+
}
|
21 |
+
|
22 |
+
export interface BackendTool extends Tool {
|
23 |
+
call(
|
24 |
+
params: Record<string, string | number | boolean>,
|
25 |
+
context: BackendToolContext
|
26 |
+
): AsyncGenerator<MessageUpdate, Omit<ToolResult, "call">, undefined>;
|
27 |
+
}
|
28 |
+
|
29 |
+
export const allTools: BackendTool[] = [
|
30 |
+
directlyAnswer,
|
31 |
+
websearch,
|
32 |
+
imageGeneration,
|
33 |
+
fetchUrl,
|
34 |
+
imageEditing,
|
35 |
+
documentParser,
|
36 |
+
calculator,
|
37 |
+
];
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { env } from "$env/dynamic/private";
|
2 |
+
import { Client } from "@gradio/client";
|
3 |
+
|
4 |
+
export type GradioImage = {
|
5 |
+
path: string;
|
6 |
+
url: string;
|
7 |
+
orig_name: string;
|
8 |
+
is_stream: boolean;
|
9 |
+
meta: Record<string, unknown>;
|
10 |
+
};
|
11 |
+
|
12 |
+
type GradioResponse = {
|
13 |
+
data: unknown[];
|
14 |
+
};
|
15 |
+
|
16 |
+
export async function callSpace<TInput extends unknown[], TOutput extends unknown[]>(
|
17 |
+
name: string,
|
18 |
+
func: string,
|
19 |
+
parameters: TInput
|
20 |
+
): Promise<TOutput> {
|
21 |
+
const client = await Client.connect(name, {
|
22 |
+
hf_token: (env.HF_TOKEN ?? env.HF_ACCESS_TOKEN) as unknown as `hf_${string}`,
|
23 |
+
});
|
24 |
+
return await client
|
25 |
+
.predict(func, parameters)
|
26 |
+
.then((res) => (res as unknown as GradioResponse).data as TOutput);
|
27 |
+
}
|
28 |
+
|
29 |
+
export { toolHasName } from "$lib/utils/tools";
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ToolResultStatus } from "$lib/types/Tool";
|
2 |
+
import type { BackendTool } from "..";
|
3 |
+
import { runWebSearch } from "../../websearch/runWebSearch";
|
4 |
+
|
5 |
+
const websearch: BackendTool = {
|
6 |
+
name: "websearch",
|
7 |
+
displayName: "Web Search",
|
8 |
+
isOnByDefault: true,
|
9 |
+
description:
|
10 |
+
"Use this tool to search web pages for answers that will help answer the user's query. Only use this tool if you need specific resources from the internet.",
|
11 |
+
parameterDefinitions: {
|
12 |
+
query: {
|
13 |
+
required: true,
|
14 |
+
type: "string",
|
15 |
+
description:
|
16 |
+
"A search query which will be used to fetch the most relevant snippets regarding the user's query",
|
17 |
+
},
|
18 |
+
},
|
19 |
+
async *call({ query }, { conv, assistant, messages }) {
|
20 |
+
const webSearchToolResults = yield* runWebSearch(conv, messages, assistant?.rag, String(query));
|
21 |
+
const chunks = webSearchToolResults?.contextSources
|
22 |
+
.map(({ context }) => context)
|
23 |
+
.join("\n------------\n");
|
24 |
+
|
25 |
+
return {
|
26 |
+
status: ToolResultStatus.Success,
|
27 |
+
outputs: [{ websearch: chunks }],
|
28 |
+
display: false,
|
29 |
+
};
|
30 |
+
},
|
31 |
+
};
|
32 |
+
|
33 |
+
export default websearch;
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { stringifyMarkdownElementTree } from "$lib/server/websearch/markdown/utils/stringify";
|
2 |
+
import { scrapeUrl } from "$lib/server/websearch/scrape/scrape";
|
3 |
+
import { ToolResultStatus } from "$lib/types/Tool";
|
4 |
+
import type { BackendTool } from "..";
|
5 |
+
|
6 |
+
const fetchUrl: BackendTool = {
|
7 |
+
name: "fetch_url",
|
8 |
+
displayName: "URL Fetcher",
|
9 |
+
description: "A tool that can be used to fetch an URL and return the content directly.",
|
10 |
+
isOnByDefault: true,
|
11 |
+
parameterDefinitions: {
|
12 |
+
url: {
|
13 |
+
description: "The url that should be fetched.",
|
14 |
+
type: "str",
|
15 |
+
required: true,
|
16 |
+
},
|
17 |
+
},
|
18 |
+
async *call(params) {
|
19 |
+
const blocks = String(params.url).split("\n");
|
20 |
+
const url = blocks[blocks.length - 1];
|
21 |
+
|
22 |
+
const { title, markdownTree } = await scrapeUrl(url, Infinity);
|
23 |
+
|
24 |
+
return {
|
25 |
+
status: ToolResultStatus.Success,
|
26 |
+
outputs: [{ title, text: stringifyMarkdownElementTree(markdownTree) }],
|
27 |
+
display: false,
|
28 |
+
};
|
29 |
+
},
|
30 |
+
};
|
31 |
+
|
32 |
+
export default fetchUrl;
|
@@ -26,6 +26,13 @@ export function stringifyMarkdownElement(elem: MarkdownElement): string {
|
|
26 |
return `${content}\n\n`;
|
27 |
}
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
// ----- HTML Elements -----
|
30 |
|
31 |
/** Ignores all non-inline tag types and grabs their text. Converts inline tags to markdown */
|
|
|
26 |
return `${content}\n\n`;
|
27 |
}
|
28 |
|
29 |
+
/** Converts a tree of markdown elements to a string with formatting */
|
30 |
+
export function stringifyMarkdownElementTree(elem: MarkdownElement): string {
|
31 |
+
const stringified = stringifyMarkdownElement(elem);
|
32 |
+
if (!("children" in elem)) return stringified;
|
33 |
+
return stringified + elem.children.map(stringifyMarkdownElementTree).join("");
|
34 |
+
}
|
35 |
+
|
36 |
// ----- HTML Elements -----
|
37 |
|
38 |
/** Ignores all non-inline tag types and grabs their text. Converts inline tags to markdown */
|
@@ -1,35 +1,35 @@
|
|
1 |
import { defaultEmbeddingModel, embeddingModels } from "$lib/server/embeddingModels";
|
2 |
|
3 |
import type { Conversation } from "$lib/types/Conversation";
|
4 |
-
import type { MessageUpdate } from "$lib/types/MessageUpdate";
|
5 |
import type { Message } from "$lib/types/Message";
|
6 |
import type { WebSearch, WebSearchScrapedSource } from "$lib/types/WebSearch";
|
7 |
import type { Assistant } from "$lib/types/Assistant";
|
|
|
8 |
|
9 |
import { search } from "./search/search";
|
10 |
import { scrape } from "./scrape/scrape";
|
11 |
import { findContextSources } from "./embed/embed";
|
12 |
import { removeParents } from "./markdown/tree";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
const MAX_N_PAGES_TO_SCRAPE = 8 as const;
|
15 |
const MAX_N_PAGES_TO_EMBED = 5 as const;
|
16 |
|
17 |
-
export
|
18 |
-
const makeAppendUpdate =
|
19 |
-
(updatePad: (upd: MessageUpdate) => void): AppendUpdate =>
|
20 |
-
(message, args, type) =>
|
21 |
-
updatePad({ type: "webSearch", messageType: type ?? "update", message, args });
|
22 |
-
|
23 |
-
export async function runWebSearch(
|
24 |
conv: Conversation,
|
25 |
messages: Message[],
|
26 |
-
|
27 |
-
|
28 |
-
):
|
29 |
const prompt = messages[messages.length - 1].content;
|
30 |
const createdAt = new Date();
|
31 |
const updatedAt = new Date();
|
32 |
-
const appendUpdate = makeAppendUpdate(updatePad);
|
33 |
|
34 |
try {
|
35 |
const embeddingModel =
|
@@ -39,29 +39,26 @@ export async function runWebSearch(
|
|
39 |
}
|
40 |
|
41 |
// Search the web
|
42 |
-
const { searchQuery, pages } =
|
43 |
if (pages.length === 0) throw Error("No results found for this search query");
|
44 |
|
45 |
// Scrape pages
|
46 |
-
|
47 |
|
48 |
-
const
|
49 |
-
pages
|
50 |
-
.slice(0, MAX_N_PAGES_TO_SCRAPE)
|
51 |
-
.map(scrape(appendUpdate, embeddingModel.chunkCharLength))
|
52 |
-
).then((allScrapedPages) =>
|
53 |
-
allScrapedPages
|
54 |
-
.filter((p): p is WebSearchScrapedSource => Boolean(p))
|
55 |
-
.filter((p) => p.page.markdownTree.children.length > 0)
|
56 |
-
.slice(0, MAX_N_PAGES_TO_EMBED)
|
57 |
);
|
|
|
|
|
|
|
|
|
58 |
|
59 |
if (!scrapedPages.length) {
|
60 |
throw Error(`No text found in the first ${MAX_N_PAGES_TO_SCRAPE} results`);
|
61 |
}
|
62 |
|
63 |
// Chunk the text of each of the elements and find the most similar chunks to the prompt
|
64 |
-
|
65 |
const contextSources = await findContextSources(scrapedPages, prompt, embeddingModel).then(
|
66 |
(ctxSources) =>
|
67 |
ctxSources.map((source) => ({
|
@@ -69,14 +66,9 @@ export async function runWebSearch(
|
|
69 |
page: { ...source.page, markdownTree: removeParents(source.page.markdownTree) },
|
70 |
}))
|
71 |
);
|
72 |
-
|
73 |
-
type: "webSearch",
|
74 |
-
messageType: "sources",
|
75 |
-
message: "sources",
|
76 |
-
sources: contextSources,
|
77 |
-
});
|
78 |
|
79 |
-
|
80 |
prompt,
|
81 |
searchQuery,
|
82 |
results: scrapedPages.map(({ page, ...source }) => ({
|
@@ -87,11 +79,14 @@ export async function runWebSearch(
|
|
87 |
createdAt,
|
88 |
updatedAt,
|
89 |
};
|
|
|
|
|
90 |
} catch (searchError) {
|
91 |
const message = searchError instanceof Error ? searchError.message : String(searchError);
|
92 |
console.error(message);
|
93 |
-
|
94 |
-
|
|
|
95 |
prompt,
|
96 |
searchQuery: "",
|
97 |
results: [],
|
@@ -99,5 +94,7 @@ export async function runWebSearch(
|
|
99 |
createdAt,
|
100 |
updatedAt,
|
101 |
};
|
|
|
|
|
102 |
}
|
103 |
}
|
|
|
1 |
import { defaultEmbeddingModel, embeddingModels } from "$lib/server/embeddingModels";
|
2 |
|
3 |
import type { Conversation } from "$lib/types/Conversation";
|
|
|
4 |
import type { Message } from "$lib/types/Message";
|
5 |
import type { WebSearch, WebSearchScrapedSource } from "$lib/types/WebSearch";
|
6 |
import type { Assistant } from "$lib/types/Assistant";
|
7 |
+
import type { MessageWebSearchUpdate } from "$lib/types/MessageUpdate";
|
8 |
|
9 |
import { search } from "./search/search";
|
10 |
import { scrape } from "./scrape/scrape";
|
11 |
import { findContextSources } from "./embed/embed";
|
12 |
import { removeParents } from "./markdown/tree";
|
13 |
+
import {
|
14 |
+
makeErrorUpdate,
|
15 |
+
makeFinalAnswerUpdate,
|
16 |
+
makeGeneralUpdate,
|
17 |
+
makeSourcesUpdate,
|
18 |
+
} from "./update";
|
19 |
+
import { mergeAsyncGenerators } from "$lib/utils/mergeAsyncGenerators";
|
20 |
|
21 |
const MAX_N_PAGES_TO_SCRAPE = 8 as const;
|
22 |
const MAX_N_PAGES_TO_EMBED = 5 as const;
|
23 |
|
24 |
+
export async function* runWebSearch(
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
conv: Conversation,
|
26 |
messages: Message[],
|
27 |
+
ragSettings?: Assistant["rag"],
|
28 |
+
query?: string
|
29 |
+
): AsyncGenerator<MessageWebSearchUpdate, WebSearch, undefined> {
|
30 |
const prompt = messages[messages.length - 1].content;
|
31 |
const createdAt = new Date();
|
32 |
const updatedAt = new Date();
|
|
|
33 |
|
34 |
try {
|
35 |
const embeddingModel =
|
|
|
39 |
}
|
40 |
|
41 |
// Search the web
|
42 |
+
const { searchQuery, pages } = yield* search(messages, ragSettings, query);
|
43 |
if (pages.length === 0) throw Error("No results found for this search query");
|
44 |
|
45 |
// Scrape pages
|
46 |
+
yield makeGeneralUpdate({ message: "Browsing search results" });
|
47 |
|
48 |
+
const allScrapedPages = yield* mergeAsyncGenerators(
|
49 |
+
pages.slice(0, MAX_N_PAGES_TO_SCRAPE).map(scrape(embeddingModel.chunkCharLength))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
);
|
51 |
+
const scrapedPages = allScrapedPages
|
52 |
+
.filter((p): p is WebSearchScrapedSource => Boolean(p))
|
53 |
+
.filter((p) => p.page.markdownTree.children.length > 0)
|
54 |
+
.slice(0, MAX_N_PAGES_TO_EMBED);
|
55 |
|
56 |
if (!scrapedPages.length) {
|
57 |
throw Error(`No text found in the first ${MAX_N_PAGES_TO_SCRAPE} results`);
|
58 |
}
|
59 |
|
60 |
// Chunk the text of each of the elements and find the most similar chunks to the prompt
|
61 |
+
yield makeGeneralUpdate({ message: "Extracting relevant information" });
|
62 |
const contextSources = await findContextSources(scrapedPages, prompt, embeddingModel).then(
|
63 |
(ctxSources) =>
|
64 |
ctxSources.map((source) => ({
|
|
|
66 |
page: { ...source.page, markdownTree: removeParents(source.page.markdownTree) },
|
67 |
}))
|
68 |
);
|
69 |
+
yield makeSourcesUpdate(contextSources);
|
|
|
|
|
|
|
|
|
|
|
70 |
|
71 |
+
const webSearch: WebSearch = {
|
72 |
prompt,
|
73 |
searchQuery,
|
74 |
results: scrapedPages.map(({ page, ...source }) => ({
|
|
|
79 |
createdAt,
|
80 |
updatedAt,
|
81 |
};
|
82 |
+
yield makeFinalAnswerUpdate(webSearch);
|
83 |
+
return webSearch;
|
84 |
} catch (searchError) {
|
85 |
const message = searchError instanceof Error ? searchError.message : String(searchError);
|
86 |
console.error(message);
|
87 |
+
yield makeErrorUpdate({ message: "An error occurred", args: [message] });
|
88 |
+
|
89 |
+
const webSearch: WebSearch = {
|
90 |
prompt,
|
91 |
searchQuery: "",
|
92 |
results: [],
|
|
|
94 |
createdAt,
|
95 |
updatedAt,
|
96 |
};
|
97 |
+
yield makeFinalAnswerUpdate(webSearch);
|
98 |
+
return webSearch;
|
99 |
}
|
100 |
}
|
@@ -4,6 +4,7 @@ import {
|
|
4 |
devices,
|
5 |
type Page,
|
6 |
type BrowserContextOptions,
|
|
|
7 |
} from "playwright";
|
8 |
import { PlaywrightBlocker } from "@cliqz/adblocker-playwright";
|
9 |
import { env } from "$env/dynamic/private";
|
@@ -44,16 +45,16 @@ async function initPlaywrightService() {
|
|
44 |
return Object.freeze({ ctx, blocker });
|
45 |
}
|
46 |
|
47 |
-
export async function loadPage(url: string): Promise<Page> {
|
48 |
if (!playwrightService) playwrightService = initPlaywrightService();
|
49 |
const { ctx, blocker } = await playwrightService;
|
50 |
|
51 |
const page = await ctx.newPage();
|
52 |
await blocker.enableBlockingInPage(page);
|
53 |
|
54 |
-
await page.goto(url, { waitUntil: "load", timeout:
|
55 |
console.warn(`Failed to load page within 2s: ${url}`);
|
56 |
});
|
57 |
|
58 |
-
return page;
|
59 |
}
|
|
|
4 |
devices,
|
5 |
type Page,
|
6 |
type BrowserContextOptions,
|
7 |
+
type Response,
|
8 |
} from "playwright";
|
9 |
import { PlaywrightBlocker } from "@cliqz/adblocker-playwright";
|
10 |
import { env } from "$env/dynamic/private";
|
|
|
45 |
return Object.freeze({ ctx, blocker });
|
46 |
}
|
47 |
|
48 |
+
export async function loadPage(url: string): Promise<{ res?: Response; page: Page }> {
|
49 |
if (!playwrightService) playwrightService = initPlaywrightService();
|
50 |
const { ctx, blocker } = await playwrightService;
|
51 |
|
52 |
const page = await ctx.newPage();
|
53 |
await blocker.enableBlockingInPage(page);
|
54 |
|
55 |
+
const res = await page.goto(url, { waitUntil: "load", timeout: 3500 }).catch(() => {
|
56 |
console.warn(`Failed to load page within 2s: ${url}`);
|
57 |
});
|
58 |
|
59 |
+
return { res: res ?? undefined, page };
|
60 |
}
|
@@ -1,26 +1,52 @@
|
|
1 |
-
import type { AppendUpdate } from "../runWebSearch";
|
2 |
import type { WebSearchScrapedSource, WebSearchSource } from "$lib/types/WebSearch";
|
|
|
3 |
import { loadPage } from "./playwright";
|
4 |
|
5 |
import { spatialParser } from "./parser";
|
6 |
import { htmlToMarkdownTree } from "../markdown/tree";
|
7 |
import { timeout } from "$lib/utils/timeout";
|
|
|
8 |
|
9 |
-
export const scrape =
|
10 |
-
|
11 |
-
|
|
|
12 |
try {
|
13 |
const page = await scrapeUrl(source.link, maxCharsPerElem);
|
14 |
-
|
15 |
return { ...source, page };
|
16 |
} catch (e) {
|
17 |
const message = e instanceof Error ? e.message : String(e);
|
18 |
-
|
19 |
}
|
20 |
};
|
21 |
|
22 |
export async function scrapeUrl(url: string, maxCharsPerElem: number) {
|
23 |
-
const page = await loadPage(url);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
|
25 |
return timeout(page.evaluate(spatialParser), 2000)
|
26 |
.then(({ elements, ...parsed }) => ({
|
|
|
|
|
1 |
import type { WebSearchScrapedSource, WebSearchSource } from "$lib/types/WebSearch";
|
2 |
+
import type { MessageWebSearchUpdate } from "$lib/types/MessageUpdate";
|
3 |
import { loadPage } from "./playwright";
|
4 |
|
5 |
import { spatialParser } from "./parser";
|
6 |
import { htmlToMarkdownTree } from "../markdown/tree";
|
7 |
import { timeout } from "$lib/utils/timeout";
|
8 |
+
import { makeErrorUpdate, makeGeneralUpdate } from "../update";
|
9 |
|
10 |
+
export const scrape = (maxCharsPerElem: number) =>
|
11 |
+
async function* (
|
12 |
+
source: WebSearchSource
|
13 |
+
): AsyncGenerator<MessageWebSearchUpdate, WebSearchScrapedSource | undefined, undefined> {
|
14 |
try {
|
15 |
const page = await scrapeUrl(source.link, maxCharsPerElem);
|
16 |
+
yield makeGeneralUpdate({ message: "Browsing webpage", args: [source.link] });
|
17 |
return { ...source, page };
|
18 |
} catch (e) {
|
19 |
const message = e instanceof Error ? e.message : String(e);
|
20 |
+
yield makeErrorUpdate({ message: "Failed to parse webpage", args: [message, source.link] });
|
21 |
}
|
22 |
};
|
23 |
|
24 |
export async function scrapeUrl(url: string, maxCharsPerElem: number) {
|
25 |
+
const { res, page } = await loadPage(url);
|
26 |
+
|
27 |
+
if (!res) throw Error("Failed to load page");
|
28 |
+
|
29 |
+
// Check if it's a non-html content type that we can handle directly
|
30 |
+
// TODO: direct mappings to markdown can be added for markdown, csv and others
|
31 |
+
const contentType = res.headers()["content-type"] ?? "";
|
32 |
+
if (
|
33 |
+
contentType.includes("text/plain") ||
|
34 |
+
contentType.includes("text/markdown") ||
|
35 |
+
contentType.includes("application/json") ||
|
36 |
+
contentType.includes("application/xml") ||
|
37 |
+
contentType.includes("text/csv")
|
38 |
+
) {
|
39 |
+
const title = await page.title();
|
40 |
+
const content = await page.content();
|
41 |
+
return {
|
42 |
+
title,
|
43 |
+
markdownTree: htmlToMarkdownTree(
|
44 |
+
title,
|
45 |
+
[{ tagName: "p", attributes: {}, content: [content] }],
|
46 |
+
maxCharsPerElem
|
47 |
+
),
|
48 |
+
};
|
49 |
+
}
|
50 |
|
51 |
return timeout(page.evaluate(spatialParser), 2000)
|
52 |
.then(({ elements, ...parsed }) => ({
|
@@ -1,7 +1,6 @@
|
|
1 |
import type { WebSearchSource } from "$lib/types/WebSearch";
|
2 |
import type { Message } from "$lib/types/Message";
|
3 |
import type { Assistant } from "$lib/types/Assistant";
|
4 |
-
import type { AppendUpdate } from "../runWebSearch";
|
5 |
import { getWebSearchProvider, searchWeb } from "./endpoints";
|
6 |
import { generateQuery } from "./generateQuery";
|
7 |
import { isURLStringLocal } from "$lib/server/isURLLocal";
|
@@ -10,30 +9,36 @@ import { isURL } from "$lib/utils/isUrl";
|
|
10 |
import z from "zod";
|
11 |
import JSON5 from "json5";
|
12 |
import { env } from "$env/dynamic/private";
|
|
|
|
|
13 |
|
14 |
const listSchema = z.array(z.string()).default([]);
|
15 |
const allowList = listSchema.parse(JSON5.parse(env.WEBSEARCH_ALLOWLIST));
|
16 |
const blockList = listSchema.parse(JSON5.parse(env.WEBSEARCH_BLOCKLIST));
|
17 |
|
18 |
-
export async function search(
|
19 |
messages: Message[],
|
20 |
-
ragSettings
|
21 |
-
|
22 |
-
):
|
|
|
|
|
|
|
|
|
23 |
if (ragSettings && ragSettings?.allowedLinks.length > 0) {
|
24 |
-
|
25 |
return {
|
26 |
searchQuery: "",
|
27 |
pages: await directLinksToSource(ragSettings.allowedLinks).then(filterByBlockList),
|
28 |
};
|
29 |
}
|
30 |
|
31 |
-
const searchQuery = await generateQuery(messages);
|
32 |
-
|
33 |
|
34 |
// handle the global and (optional) rag lists
|
35 |
if (ragSettings && ragSettings?.allowedDomains.length > 0) {
|
36 |
-
|
37 |
}
|
38 |
const filters = buildQueryFromSiteFilters(
|
39 |
[...(ragSettings?.allowedDomains ?? []), ...allowList],
|
|
|
1 |
import type { WebSearchSource } from "$lib/types/WebSearch";
|
2 |
import type { Message } from "$lib/types/Message";
|
3 |
import type { Assistant } from "$lib/types/Assistant";
|
|
|
4 |
import { getWebSearchProvider, searchWeb } from "./endpoints";
|
5 |
import { generateQuery } from "./generateQuery";
|
6 |
import { isURLStringLocal } from "$lib/server/isURLLocal";
|
|
|
9 |
import z from "zod";
|
10 |
import JSON5 from "json5";
|
11 |
import { env } from "$env/dynamic/private";
|
12 |
+
import { makeGeneralUpdate } from "../update";
|
13 |
+
import type { MessageWebSearchUpdate } from "$lib/types/MessageUpdate";
|
14 |
|
15 |
const listSchema = z.array(z.string()).default([]);
|
16 |
const allowList = listSchema.parse(JSON5.parse(env.WEBSEARCH_ALLOWLIST));
|
17 |
const blockList = listSchema.parse(JSON5.parse(env.WEBSEARCH_BLOCKLIST));
|
18 |
|
19 |
+
export async function* search(
|
20 |
messages: Message[],
|
21 |
+
ragSettings?: Assistant["rag"],
|
22 |
+
query?: string
|
23 |
+
): AsyncGenerator<
|
24 |
+
MessageWebSearchUpdate,
|
25 |
+
{ searchQuery: string; pages: WebSearchSource[] },
|
26 |
+
undefined
|
27 |
+
> {
|
28 |
if (ragSettings && ragSettings?.allowedLinks.length > 0) {
|
29 |
+
yield makeGeneralUpdate({ message: "Using links specified in Assistant" });
|
30 |
return {
|
31 |
searchQuery: "",
|
32 |
pages: await directLinksToSource(ragSettings.allowedLinks).then(filterByBlockList),
|
33 |
};
|
34 |
}
|
35 |
|
36 |
+
const searchQuery = query ?? (await generateQuery(messages));
|
37 |
+
yield makeGeneralUpdate({ message: `Searching ${getWebSearchProvider()}`, args: [searchQuery] });
|
38 |
|
39 |
// handle the global and (optional) rag lists
|
40 |
if (ragSettings && ragSettings?.allowedDomains.length > 0) {
|
41 |
+
yield makeGeneralUpdate({ message: "Filtering on specified domains" });
|
42 |
}
|
43 |
const filters = buildQueryFromSiteFilters(
|
44 |
[...(ragSettings?.allowedDomains ?? []), ...allowList],
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { WebSearch, WebSearchSource } from "$lib/types/WebSearch";
|
2 |
+
import {
|
3 |
+
MessageUpdateType,
|
4 |
+
MessageWebSearchUpdateType,
|
5 |
+
type MessageWebSearchErrorUpdate,
|
6 |
+
type MessageWebSearchFinishedUpdate,
|
7 |
+
type MessageWebSearchGeneralUpdate,
|
8 |
+
type MessageWebSearchSourcesUpdate,
|
9 |
+
} from "$lib/types/MessageUpdate";
|
10 |
+
|
11 |
+
export function makeGeneralUpdate(
|
12 |
+
update: Pick<MessageWebSearchGeneralUpdate, "message" | "args">
|
13 |
+
): MessageWebSearchGeneralUpdate {
|
14 |
+
return {
|
15 |
+
type: MessageUpdateType.WebSearch,
|
16 |
+
subtype: MessageWebSearchUpdateType.Update,
|
17 |
+
...update,
|
18 |
+
};
|
19 |
+
}
|
20 |
+
|
21 |
+
export function makeErrorUpdate(
|
22 |
+
update: Pick<MessageWebSearchErrorUpdate, "message" | "args">
|
23 |
+
): MessageWebSearchErrorUpdate {
|
24 |
+
return {
|
25 |
+
type: MessageUpdateType.WebSearch,
|
26 |
+
subtype: MessageWebSearchUpdateType.Error,
|
27 |
+
...update,
|
28 |
+
};
|
29 |
+
}
|
30 |
+
|
31 |
+
export function makeSourcesUpdate(sources: WebSearchSource[]): MessageWebSearchSourcesUpdate {
|
32 |
+
return {
|
33 |
+
type: MessageUpdateType.WebSearch,
|
34 |
+
subtype: MessageWebSearchUpdateType.Sources,
|
35 |
+
message: "sources",
|
36 |
+
sources,
|
37 |
+
};
|
38 |
+
}
|
39 |
+
|
40 |
+
export function makeFinalAnswerUpdate(webSearch: WebSearch): MessageWebSearchFinishedUpdate {
|
41 |
+
return {
|
42 |
+
type: MessageUpdateType.WebSearch,
|
43 |
+
subtype: MessageWebSearchUpdateType.Finished,
|
44 |
+
webSearch,
|
45 |
+
};
|
46 |
+
}
|
@@ -15,6 +15,7 @@ type SettingsStore = {
|
|
15 |
customPrompts: Record<string, string>;
|
16 |
recentlySaved: boolean;
|
17 |
assistants: Array<ObjectId | string>;
|
|
|
18 |
};
|
19 |
|
20 |
type SettingsStoreWritable = Writable<SettingsStore> & {
|
|
|
15 |
customPrompts: Record<string, string>;
|
16 |
recentlySaved: boolean;
|
17 |
assistants: Array<ObjectId | string>;
|
18 |
+
tools?: Record<string, boolean>;
|
19 |
};
|
20 |
|
21 |
type SettingsStoreWritable = Writable<SettingsStore> & {
|
@@ -27,6 +27,7 @@ export type Message = Partial<Timestamps> & {
|
|
27 |
|
28 |
export type MessageFile = {
|
29 |
type: "hash" | "base64";
|
|
|
30 |
value: string;
|
31 |
mime: string;
|
32 |
};
|
|
|
27 |
|
28 |
export type MessageFile = {
|
29 |
type: "hash" | "base64";
|
30 |
+
name: string;
|
31 |
value: string;
|
32 |
mime: string;
|
33 |
};
|
@@ -1,46 +1,111 @@
|
|
1 |
-
import type { WebSearchSource } from "
|
|
|
2 |
|
3 |
-
export type
|
4 |
-
|
5 |
-
|
6 |
-
|
|
|
|
|
|
|
|
|
7 |
|
8 |
-
export
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
}
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
message: string;
|
24 |
args?: string[];
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
-
|
35 |
-
|
36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
name: string;
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
| ErrorUpdate;
|
|
|
1 |
+
import type { WebSearch, WebSearchSource } from "$lib/types/WebSearch";
|
2 |
+
import type { ToolCall, ToolResult } from "$lib/types/Tool";
|
3 |
|
4 |
+
export type MessageUpdate =
|
5 |
+
| MessageStatusUpdate
|
6 |
+
| MessageTitleUpdate
|
7 |
+
| MessageToolUpdate
|
8 |
+
| MessageWebSearchUpdate
|
9 |
+
| MessageStreamUpdate
|
10 |
+
| MessageFileUpdate
|
11 |
+
| MessageFinalAnswerUpdate;
|
12 |
|
13 |
+
export enum MessageUpdateType {
|
14 |
+
Status = "status",
|
15 |
+
Title = "title",
|
16 |
+
Tool = "tool",
|
17 |
+
WebSearch = "webSearch",
|
18 |
+
Stream = "stream",
|
19 |
+
File = "file",
|
20 |
+
FinalAnswer = "finalAnswer",
|
21 |
+
}
|
22 |
|
23 |
+
// Status
|
24 |
+
export enum MessageUpdateStatus {
|
25 |
+
Started = "started",
|
26 |
+
Error = "error",
|
27 |
+
Finished = "finished",
|
28 |
+
}
|
29 |
+
export interface MessageStatusUpdate {
|
30 |
+
type: MessageUpdateType.Status;
|
31 |
+
status: MessageUpdateStatus;
|
32 |
+
message?: string;
|
33 |
+
}
|
34 |
|
35 |
+
// Web search
|
36 |
+
export enum MessageWebSearchUpdateType {
|
37 |
+
Update = "update",
|
38 |
+
Error = "error",
|
39 |
+
Sources = "sources",
|
40 |
+
Finished = "finished",
|
41 |
+
}
|
42 |
+
interface BaseMessageWebSearchUpdate<TSubType extends MessageWebSearchUpdateType> {
|
43 |
+
type: MessageUpdateType.WebSearch;
|
44 |
+
subtype: TSubType;
|
45 |
+
}
|
46 |
+
export interface MessageWebSearchErrorUpdate
|
47 |
+
extends BaseMessageWebSearchUpdate<MessageWebSearchUpdateType.Error> {
|
48 |
message: string;
|
49 |
args?: string[];
|
50 |
+
}
|
51 |
+
export interface MessageWebSearchGeneralUpdate
|
52 |
+
extends BaseMessageWebSearchUpdate<MessageWebSearchUpdateType.Update> {
|
53 |
+
message: string;
|
54 |
+
args?: string[];
|
55 |
+
}
|
56 |
+
export interface MessageWebSearchSourcesUpdate
|
57 |
+
extends BaseMessageWebSearchUpdate<MessageWebSearchUpdateType.Sources> {
|
58 |
+
message: string;
|
59 |
+
sources: WebSearchSource[];
|
60 |
+
}
|
61 |
+
export interface MessageWebSearchFinishedUpdate
|
62 |
+
extends BaseMessageWebSearchUpdate<MessageWebSearchUpdateType.Finished> {
|
63 |
+
webSearch: WebSearch;
|
64 |
+
}
|
65 |
+
export type MessageWebSearchUpdate =
|
66 |
+
| MessageWebSearchErrorUpdate
|
67 |
+
| MessageWebSearchGeneralUpdate
|
68 |
+
| MessageWebSearchSourcesUpdate
|
69 |
+
| MessageWebSearchFinishedUpdate;
|
70 |
|
71 |
+
// Tool
|
72 |
+
export enum MessageToolUpdateType {
|
73 |
+
/** A request to call a tool alongside it's parameters */
|
74 |
+
Call = "call",
|
75 |
+
/** The result of a tool call */
|
76 |
+
Result = "result",
|
77 |
+
}
|
78 |
+
interface MessageToolBaseUpdate<TSubType extends MessageToolUpdateType> {
|
79 |
+
type: MessageUpdateType.Tool;
|
80 |
+
subtype: TSubType;
|
81 |
+
uuid: string;
|
82 |
+
}
|
83 |
+
export interface MessageToolCallUpdate extends MessageToolBaseUpdate<MessageToolUpdateType.Call> {
|
84 |
+
call: ToolCall;
|
85 |
+
}
|
86 |
+
export interface MessageToolResultUpdate
|
87 |
+
extends MessageToolBaseUpdate<MessageToolUpdateType.Result> {
|
88 |
+
result: ToolResult;
|
89 |
+
}
|
90 |
+
export type MessageToolUpdate = MessageToolCallUpdate | MessageToolResultUpdate;
|
91 |
|
92 |
+
// Everything else
|
93 |
+
export interface MessageTitleUpdate {
|
94 |
+
type: MessageUpdateType.Title;
|
95 |
+
title: string;
|
96 |
+
}
|
97 |
+
export interface MessageStreamUpdate {
|
98 |
+
type: MessageUpdateType.Stream;
|
99 |
+
token: string;
|
100 |
+
}
|
101 |
+
export interface MessageFileUpdate {
|
102 |
+
type: MessageUpdateType.File;
|
103 |
name: string;
|
104 |
+
sha: string;
|
105 |
+
mime: string;
|
106 |
+
}
|
107 |
+
export interface MessageFinalAnswerUpdate {
|
108 |
+
type: MessageUpdateType.FinalAnswer;
|
109 |
+
text: string;
|
110 |
+
interrupted: boolean;
|
111 |
+
}
|
|
@@ -17,4 +17,5 @@ export type Model = Pick<
|
|
17 |
| "preprompt"
|
18 |
| "multimodal"
|
19 |
| "unlisted"
|
|
|
20 |
>;
|
|
|
17 |
| "preprompt"
|
18 |
| "multimodal"
|
19 |
| "unlisted"
|
20 |
+
| "tools"
|
21 |
>;
|
@@ -21,6 +21,7 @@ export interface Settings extends Timestamps {
|
|
21 |
customPrompts?: Record<string, string>;
|
22 |
|
23 |
assistants?: Assistant["_id"][];
|
|
|
24 |
}
|
25 |
|
26 |
// TODO: move this to a constant file along with other constants
|
@@ -30,4 +31,5 @@ export const DEFAULT_SETTINGS = {
|
|
30 |
hideEmojiOnSidebar: false,
|
31 |
customPrompts: {},
|
32 |
assistants: [],
|
|
|
33 |
};
|
|
|
21 |
customPrompts?: Record<string, string>;
|
22 |
|
23 |
assistants?: Assistant["_id"][];
|
24 |
+
tools?: Record<string, boolean>;
|
25 |
}
|
26 |
|
27 |
// TODO: move this to a constant file along with other constants
|
|
|
31 |
hideEmojiOnSidebar: false,
|
32 |
customPrompts: {},
|
33 |
assistants: [],
|
34 |
+
tools: {},
|
35 |
};
|