Spaces:
Running
on
CPU Upgrade
Add initial support for web browsing (#237)
Browse files* basic poc for web search
* * Hide feature when serpapi_key is not defined
* handle error case where serpapi failed
* only use user queries for generating the query
* Update src/lib/buildPrompt.ts
Co-authored-by: Eliott C. <[email protected]>
* Update src/routes/+layout.server.ts
Co-authored-by: Eliott C. <[email protected]>
* refactored getQueryFromPrompt
* add jsdom to package.json
* begin work on fetching webpage content
* Update .env
Co-authored-by: Eliott C. <[email protected]>
* prettier fix
* Add feature for scraping webpages
* refactored search functionality
- now gets triggered from a separate endpoint
- results are stored in db
- results can be displayed in their own endpoint
* Added a stream to send updates from backend on web-search endpoint
* made stream more reliable
* Add front-end to web search feature
* made sure the web results button appears on newly posted messages
* close modal when message is done generating
* removed log statements
* Add button to open modal on loading messages too
* replace modal by collapsable menu
* make sure shared conversations also show search details
* Use spinner for collapse menu
* Fix alignment of "stop generating" button
* Fix loading indicators
- spinner only shows when web search is searching
- text loader shows after the web search is done
* fix loading icon when web search is disabled
* Update search messages & clean up summary string
* Fix alignment of timeline
* Use existing switch
* Add a background to tooltip & center it
* fix like making search messages disappear
* use correct spinner
* fix state issues
* lint
* fix bug with empty search messages
* fix like bug ?
* fix modal bug
* error handling
* fix like bug
* slice scraped text so it fits in context
* misc UI
* bottom buttons
simplify and fix
* made sure snap scrolling also works on web search updates
* loader
* margin
* remove unused function
* linter
* quickfix duplicate websearch
---------
Co-authored-by: Eliott C. <[email protected]>
Co-authored-by: Victor Mustar <[email protected]>
- .env +3 -0
- package-lock.json +430 -6
- package.json +3 -0
- src/lib/buildPrompt.ts +29 -8
- src/lib/components/OpenWebSearchResults.svelte +133 -0
- src/lib/components/StopGeneratingBtn.svelte +4 -8
- src/lib/components/Switch.svelte +3 -1
- src/lib/components/WebSearchToggle.svelte +27 -0
- src/lib/components/chat/ChatMessage.svelte +27 -3
- src/lib/components/chat/ChatMessages.svelte +21 -11
- src/lib/components/chat/ChatWindow.svelte +16 -4
- src/lib/components/icons/IconLoading.svelte +14 -27
- src/lib/server/database.ts +4 -0
- src/lib/server/generateFromDefaultEndpoint.ts +43 -0
- src/lib/server/searchWeb.ts +20 -0
- src/lib/stores/webSearchParameters.ts +9 -0
- src/lib/types/Message.ts +1 -0
- src/lib/types/WebSearch.ts +40 -0
- src/routes/+layout.server.ts +2 -0
- src/routes/conversation/[id]/+page.svelte +72 -4
- src/routes/conversation/[id]/+server.ts +4 -4
- src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts +1 -1
- src/routes/conversation/[id]/summarize/+server.ts +4 -30
- src/routes/conversation/[id]/web-search/+server.ts +232 -0
- src/routes/r/[id]/message/[messageId]/prompt/+server.ts +1 -1
- src/routes/search/[id]/+server.ts +39 -0
|
@@ -8,6 +8,9 @@ MONGODB_DIRECT_CONNECTION=false
|
|
| 8 |
COOKIE_NAME=hf-chat
|
| 9 |
HF_ACCESS_TOKEN=#hf_<token> from from https://huggingface.co/settings/token
|
| 10 |
|
|
|
|
|
|
|
|
|
|
| 11 |
# Parameters to enable "Sign in with HF"
|
| 12 |
OPENID_CLIENT_ID=
|
| 13 |
OPENID_CLIENT_SECRET=
|
|
|
|
| 8 |
COOKIE_NAME=hf-chat
|
| 9 |
HF_ACCESS_TOKEN=#hf_<token> from from https://huggingface.co/settings/token
|
| 10 |
|
| 11 |
+
# used to activate search with web functionality. disabled if not defined
|
| 12 |
+
SERPAPI_KEY=#your serpapi key here
|
| 13 |
+
|
| 14 |
# Parameters to enable "Sign in with HF"
|
| 15 |
OPENID_CLIENT_ID=
|
| 16 |
OPENID_CLIENT_SECRET=
|
|
@@ -14,12 +14,14 @@
|
|
| 14 |
"date-fns": "^2.29.3",
|
| 15 |
"dotenv": "^16.0.3",
|
| 16 |
"highlight.js": "^11.7.0",
|
|
|
|
| 17 |
"marked": "^4.3.0",
|
| 18 |
"mongodb": "^5.3.0",
|
| 19 |
"nanoid": "^4.0.2",
|
| 20 |
"openid-client": "^5.4.2",
|
| 21 |
"parquetjs": "^0.11.2",
|
| 22 |
"postcss": "^8.4.21",
|
|
|
|
| 23 |
"tailwind-scrollbar": "^3.0.0",
|
| 24 |
"tailwindcss": "^3.3.1",
|
| 25 |
"zod": "^3.21.4"
|
|
@@ -30,6 +32,7 @@
|
|
| 30 |
"@sveltejs/adapter-node": "^1.2.4",
|
| 31 |
"@sveltejs/kit": "^1.15.10",
|
| 32 |
"@tailwindcss/typography": "^0.5.9",
|
|
|
|
| 33 |
"@types/marked": "^4.0.8",
|
| 34 |
"@types/parquetjs": "^0.10.3",
|
| 35 |
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
|
@@ -890,6 +893,14 @@
|
|
| 890 |
"node": ">=4"
|
| 891 |
}
|
| 892 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 893 |
"node_modules/@types/chai": {
|
| 894 |
"version": "4.3.5",
|
| 895 |
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
|
|
@@ -917,6 +928,17 @@
|
|
| 917 |
"integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==",
|
| 918 |
"dev": true
|
| 919 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 920 |
"node_modules/@types/json-schema": {
|
| 921 |
"version": "7.0.11",
|
| 922 |
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
|
@@ -970,6 +992,12 @@
|
|
| 970 |
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
|
| 971 |
"dev": true
|
| 972 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 973 |
"node_modules/@types/webidl-conversions": {
|
| 974 |
"version": "7.0.0",
|
| 975 |
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
|
@@ -1268,6 +1296,11 @@
|
|
| 1268 |
"url": "https://opencollective.com/vitest"
|
| 1269 |
}
|
| 1270 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1271 |
"node_modules/acorn": {
|
| 1272 |
"version": "8.8.2",
|
| 1273 |
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
|
|
@@ -1298,6 +1331,17 @@
|
|
| 1298 |
"node": ">=0.4.0"
|
| 1299 |
}
|
| 1300 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1301 |
"node_modules/ajv": {
|
| 1302 |
"version": "6.12.6",
|
| 1303 |
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
|
@@ -1384,6 +1428,11 @@
|
|
| 1384 |
"node": "*"
|
| 1385 |
}
|
| 1386 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1387 |
"node_modules/autoprefixer": {
|
| 1388 |
"version": "10.4.14",
|
| 1389 |
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
|
|
@@ -1548,7 +1597,6 @@
|
|
| 1548 |
"version": "1.6.0",
|
| 1549 |
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
| 1550 |
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
| 1551 |
-
"dev": true,
|
| 1552 |
"dependencies": {
|
| 1553 |
"streamsearch": "^1.1.0"
|
| 1554 |
},
|
|
@@ -1698,6 +1746,17 @@
|
|
| 1698 |
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
| 1699 |
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
| 1700 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1701 |
"node_modules/commander": {
|
| 1702 |
"version": "4.1.1",
|
| 1703 |
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
|
@@ -1770,6 +1829,53 @@
|
|
| 1770 |
"node": ">=4"
|
| 1771 |
}
|
| 1772 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1773 |
"node_modules/date-fns": {
|
| 1774 |
"version": "2.29.3",
|
| 1775 |
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
|
|
@@ -1798,7 +1904,6 @@
|
|
| 1798 |
"version": "4.3.4",
|
| 1799 |
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
| 1800 |
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
| 1801 |
-
"dev": true,
|
| 1802 |
"dependencies": {
|
| 1803 |
"ms": "2.1.2"
|
| 1804 |
},
|
|
@@ -1811,6 +1916,11 @@
|
|
| 1811 |
}
|
| 1812 |
}
|
| 1813 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1814 |
"node_modules/deep-eql": {
|
| 1815 |
"version": "4.1.3",
|
| 1816 |
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
|
|
@@ -1838,6 +1948,14 @@
|
|
| 1838 |
"node": ">=0.10.0"
|
| 1839 |
}
|
| 1840 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1841 |
"node_modules/detect-indent": {
|
| 1842 |
"version": "6.1.0",
|
| 1843 |
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
|
|
@@ -1887,6 +2005,17 @@
|
|
| 1887 |
"node": ">=6.0.0"
|
| 1888 |
}
|
| 1889 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1890 |
"node_modules/dotenv": {
|
| 1891 |
"version": "16.0.3",
|
| 1892 |
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
|
@@ -1900,6 +2029,17 @@
|
|
| 1900 |
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.359.tgz",
|
| 1901 |
"integrity": "sha512-OoVcngKCIuNXtZnsYoqlCvr0Cf3NIPzDIgwUfI9bdTFjXCrr79lI0kwQstLPZ7WhCezLlGksZk/BFAzoXC7GDw=="
|
| 1902 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1903 |
"node_modules/es6-promise": {
|
| 1904 |
"version": "3.3.1",
|
| 1905 |
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
|
|
@@ -2366,6 +2506,19 @@
|
|
| 2366 |
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
| 2367 |
"dev": true
|
| 2368 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2369 |
"node_modules/fraction.js": {
|
| 2370 |
"version": "4.2.0",
|
| 2371 |
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
|
|
@@ -2545,6 +2698,42 @@
|
|
| 2545 |
"node": ">=12.0.0"
|
| 2546 |
}
|
| 2547 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2548 |
"node_modules/human-signals": {
|
| 2549 |
"version": "2.1.0",
|
| 2550 |
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
|
@@ -2554,6 +2743,17 @@
|
|
| 2554 |
"node": ">=10.17.0"
|
| 2555 |
}
|
| 2556 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2557 |
"node_modules/ignore": {
|
| 2558 |
"version": "5.2.4",
|
| 2559 |
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
|
@@ -2691,6 +2891,11 @@
|
|
| 2691 |
"node": ">=8"
|
| 2692 |
}
|
| 2693 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2694 |
"node_modules/is-reference": {
|
| 2695 |
"version": "1.2.1",
|
| 2696 |
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
|
|
@@ -2765,6 +2970,70 @@
|
|
| 2765 |
"js-yaml": "bin/js-yaml.js"
|
| 2766 |
}
|
| 2767 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2768 |
"node_modules/json-schema-traverse": {
|
| 2769 |
"version": "0.4.1",
|
| 2770 |
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
|
@@ -2990,6 +3259,25 @@
|
|
| 2990 |
"node": ">=10.0.0"
|
| 2991 |
}
|
| 2992 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2993 |
"node_modules/mimic-fn": {
|
| 2994 |
"version": "2.1.0",
|
| 2995 |
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
|
@@ -3114,8 +3402,7 @@
|
|
| 3114 |
"node_modules/ms": {
|
| 3115 |
"version": "2.1.2",
|
| 3116 |
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
| 3117 |
-
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
| 3118 |
-
"dev": true
|
| 3119 |
},
|
| 3120 |
"node_modules/mz": {
|
| 3121 |
"version": "2.7.0",
|
|
@@ -3194,6 +3481,11 @@
|
|
| 3194 |
"node": ">=8"
|
| 3195 |
}
|
| 3196 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3197 |
"node_modules/object-assign": {
|
| 3198 |
"version": "4.1.1",
|
| 3199 |
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
|
@@ -3358,6 +3650,17 @@
|
|
| 3358 |
"node": ">=0.6.19"
|
| 3359 |
}
|
| 3360 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3361 |
"node_modules/path-exists": {
|
| 3362 |
"version": "4.0.0",
|
| 3363 |
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
|
@@ -3747,6 +4050,11 @@
|
|
| 3747 |
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
| 3748 |
}
|
| 3749 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3750 |
"node_modules/punycode": {
|
| 3751 |
"version": "2.3.0",
|
| 3752 |
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
|
|
@@ -3764,6 +4072,11 @@
|
|
| 3764 |
"teleport": ">=0.2.0"
|
| 3765 |
}
|
| 3766 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3767 |
"node_modules/queue-microtask": {
|
| 3768 |
"version": "1.2.3",
|
| 3769 |
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
|
@@ -3831,6 +4144,11 @@
|
|
| 3831 |
"url": "https://github.com/sponsors/mysticatea"
|
| 3832 |
}
|
| 3833 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3834 |
"node_modules/resolve": {
|
| 3835 |
"version": "1.22.1",
|
| 3836 |
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
|
@@ -3896,6 +4214,11 @@
|
|
| 3896 |
"fsevents": "~2.3.2"
|
| 3897 |
}
|
| 3898 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3899 |
"node_modules/run-parallel": {
|
| 3900 |
"version": "1.2.0",
|
| 3901 |
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
|
@@ -3930,6 +4253,11 @@
|
|
| 3930 |
"node": ">=6"
|
| 3931 |
}
|
| 3932 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3933 |
"node_modules/sander": {
|
| 3934 |
"version": "0.5.1",
|
| 3935 |
"resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz",
|
|
@@ -3966,6 +4294,17 @@
|
|
| 3966 |
"node": ">=6"
|
| 3967 |
}
|
| 3968 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3969 |
"node_modules/semver": {
|
| 3970 |
"version": "7.3.8",
|
| 3971 |
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
|
@@ -3981,6 +4320,14 @@
|
|
| 3981 |
"node": ">=10"
|
| 3982 |
}
|
| 3983 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3984 |
"node_modules/set-cookie-parser": {
|
| 3985 |
"version": "2.6.0",
|
| 3986 |
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
|
|
@@ -4118,7 +4465,6 @@
|
|
| 4118 |
"version": "1.1.0",
|
| 4119 |
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
| 4120 |
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
| 4121 |
-
"dev": true,
|
| 4122 |
"engines": {
|
| 4123 |
"node": ">=10.0.0"
|
| 4124 |
}
|
|
@@ -4423,6 +4769,11 @@
|
|
| 4423 |
"node": ">=12"
|
| 4424 |
}
|
| 4425 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4426 |
"node_modules/tailwind-scrollbar": {
|
| 4427 |
"version": "3.0.0",
|
| 4428 |
"resolved": "https://registry.npmjs.org/tailwind-scrollbar/-/tailwind-scrollbar-3.0.0.tgz",
|
|
@@ -4576,6 +4927,20 @@
|
|
| 4576 |
"node": ">=6"
|
| 4577 |
}
|
| 4578 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4579 |
"node_modules/tr46": {
|
| 4580 |
"version": "3.0.0",
|
| 4581 |
"resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
|
|
@@ -4675,7 +5040,6 @@
|
|
| 4675 |
"version": "5.22.0",
|
| 4676 |
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz",
|
| 4677 |
"integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==",
|
| 4678 |
-
"dev": true,
|
| 4679 |
"dependencies": {
|
| 4680 |
"busboy": "^1.6.0"
|
| 4681 |
},
|
|
@@ -4683,6 +5047,14 @@
|
|
| 4683 |
"node": ">=14.0"
|
| 4684 |
}
|
| 4685 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4686 |
"node_modules/unplugin": {
|
| 4687 |
"version": "1.3.1",
|
| 4688 |
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.3.1.tgz",
|
|
@@ -4767,6 +5139,15 @@
|
|
| 4767 |
"punycode": "^2.1.0"
|
| 4768 |
}
|
| 4769 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4770 |
"node_modules/util-deprecate": {
|
| 4771 |
"version": "1.0.2",
|
| 4772 |
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
|
@@ -4940,6 +5321,17 @@
|
|
| 4940 |
}
|
| 4941 |
}
|
| 4942 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4943 |
"node_modules/webidl-conversions": {
|
| 4944 |
"version": "7.0.0",
|
| 4945 |
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
|
@@ -4972,6 +5364,25 @@
|
|
| 4972 |
"node": ">=6"
|
| 4973 |
}
|
| 4974 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4975 |
"node_modules/whatwg-url": {
|
| 4976 |
"version": "11.0.0",
|
| 4977 |
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
|
|
@@ -5049,6 +5460,19 @@
|
|
| 5049 |
}
|
| 5050 |
}
|
| 5051 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5052 |
"node_modules/yallist": {
|
| 5053 |
"version": "4.0.0",
|
| 5054 |
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
|
|
| 14 |
"date-fns": "^2.29.3",
|
| 15 |
"dotenv": "^16.0.3",
|
| 16 |
"highlight.js": "^11.7.0",
|
| 17 |
+
"jsdom": "^22.0.0",
|
| 18 |
"marked": "^4.3.0",
|
| 19 |
"mongodb": "^5.3.0",
|
| 20 |
"nanoid": "^4.0.2",
|
| 21 |
"openid-client": "^5.4.2",
|
| 22 |
"parquetjs": "^0.11.2",
|
| 23 |
"postcss": "^8.4.21",
|
| 24 |
+
"serpapi": "^1.1.1",
|
| 25 |
"tailwind-scrollbar": "^3.0.0",
|
| 26 |
"tailwindcss": "^3.3.1",
|
| 27 |
"zod": "^3.21.4"
|
|
|
|
| 32 |
"@sveltejs/adapter-node": "^1.2.4",
|
| 33 |
"@sveltejs/kit": "^1.15.10",
|
| 34 |
"@tailwindcss/typography": "^0.5.9",
|
| 35 |
+
"@types/jsdom": "^21.1.1",
|
| 36 |
"@types/marked": "^4.0.8",
|
| 37 |
"@types/parquetjs": "^0.10.3",
|
| 38 |
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
|
|
|
| 893 |
"node": ">=4"
|
| 894 |
}
|
| 895 |
},
|
| 896 |
+
"node_modules/@tootallnate/once": {
|
| 897 |
+
"version": "2.0.0",
|
| 898 |
+
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
|
| 899 |
+
"integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
|
| 900 |
+
"engines": {
|
| 901 |
+
"node": ">= 10"
|
| 902 |
+
}
|
| 903 |
+
},
|
| 904 |
"node_modules/@types/chai": {
|
| 905 |
"version": "4.3.5",
|
| 906 |
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
|
|
|
|
| 928 |
"integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==",
|
| 929 |
"dev": true
|
| 930 |
},
|
| 931 |
+
"node_modules/@types/jsdom": {
|
| 932 |
+
"version": "21.1.1",
|
| 933 |
+
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.1.tgz",
|
| 934 |
+
"integrity": "sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==",
|
| 935 |
+
"dev": true,
|
| 936 |
+
"dependencies": {
|
| 937 |
+
"@types/node": "*",
|
| 938 |
+
"@types/tough-cookie": "*",
|
| 939 |
+
"parse5": "^7.0.0"
|
| 940 |
+
}
|
| 941 |
+
},
|
| 942 |
"node_modules/@types/json-schema": {
|
| 943 |
"version": "7.0.11",
|
| 944 |
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
|
|
|
| 992 |
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
|
| 993 |
"dev": true
|
| 994 |
},
|
| 995 |
+
"node_modules/@types/tough-cookie": {
|
| 996 |
+
"version": "4.0.2",
|
| 997 |
+
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
|
| 998 |
+
"integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
|
| 999 |
+
"dev": true
|
| 1000 |
+
},
|
| 1001 |
"node_modules/@types/webidl-conversions": {
|
| 1002 |
"version": "7.0.0",
|
| 1003 |
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
|
|
|
| 1296 |
"url": "https://opencollective.com/vitest"
|
| 1297 |
}
|
| 1298 |
},
|
| 1299 |
+
"node_modules/abab": {
|
| 1300 |
+
"version": "2.0.6",
|
| 1301 |
+
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
| 1302 |
+
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="
|
| 1303 |
+
},
|
| 1304 |
"node_modules/acorn": {
|
| 1305 |
"version": "8.8.2",
|
| 1306 |
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
|
|
|
|
| 1331 |
"node": ">=0.4.0"
|
| 1332 |
}
|
| 1333 |
},
|
| 1334 |
+
"node_modules/agent-base": {
|
| 1335 |
+
"version": "6.0.2",
|
| 1336 |
+
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
| 1337 |
+
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
| 1338 |
+
"dependencies": {
|
| 1339 |
+
"debug": "4"
|
| 1340 |
+
},
|
| 1341 |
+
"engines": {
|
| 1342 |
+
"node": ">= 6.0.0"
|
| 1343 |
+
}
|
| 1344 |
+
},
|
| 1345 |
"node_modules/ajv": {
|
| 1346 |
"version": "6.12.6",
|
| 1347 |
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
|
|
|
| 1428 |
"node": "*"
|
| 1429 |
}
|
| 1430 |
},
|
| 1431 |
+
"node_modules/asynckit": {
|
| 1432 |
+
"version": "0.4.0",
|
| 1433 |
+
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
| 1434 |
+
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
| 1435 |
+
},
|
| 1436 |
"node_modules/autoprefixer": {
|
| 1437 |
"version": "10.4.14",
|
| 1438 |
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
|
|
|
|
| 1597 |
"version": "1.6.0",
|
| 1598 |
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
| 1599 |
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
|
|
|
| 1600 |
"dependencies": {
|
| 1601 |
"streamsearch": "^1.1.0"
|
| 1602 |
},
|
|
|
|
| 1746 |
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
| 1747 |
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
| 1748 |
},
|
| 1749 |
+
"node_modules/combined-stream": {
|
| 1750 |
+
"version": "1.0.8",
|
| 1751 |
+
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
| 1752 |
+
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
| 1753 |
+
"dependencies": {
|
| 1754 |
+
"delayed-stream": "~1.0.0"
|
| 1755 |
+
},
|
| 1756 |
+
"engines": {
|
| 1757 |
+
"node": ">= 0.8"
|
| 1758 |
+
}
|
| 1759 |
+
},
|
| 1760 |
"node_modules/commander": {
|
| 1761 |
"version": "4.1.1",
|
| 1762 |
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
|
|
|
| 1829 |
"node": ">=4"
|
| 1830 |
}
|
| 1831 |
},
|
| 1832 |
+
"node_modules/cssstyle": {
|
| 1833 |
+
"version": "3.0.0",
|
| 1834 |
+
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
|
| 1835 |
+
"integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
|
| 1836 |
+
"dependencies": {
|
| 1837 |
+
"rrweb-cssom": "^0.6.0"
|
| 1838 |
+
},
|
| 1839 |
+
"engines": {
|
| 1840 |
+
"node": ">=14"
|
| 1841 |
+
}
|
| 1842 |
+
},
|
| 1843 |
+
"node_modules/data-urls": {
|
| 1844 |
+
"version": "4.0.0",
|
| 1845 |
+
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz",
|
| 1846 |
+
"integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==",
|
| 1847 |
+
"dependencies": {
|
| 1848 |
+
"abab": "^2.0.6",
|
| 1849 |
+
"whatwg-mimetype": "^3.0.0",
|
| 1850 |
+
"whatwg-url": "^12.0.0"
|
| 1851 |
+
},
|
| 1852 |
+
"engines": {
|
| 1853 |
+
"node": ">=14"
|
| 1854 |
+
}
|
| 1855 |
+
},
|
| 1856 |
+
"node_modules/data-urls/node_modules/tr46": {
|
| 1857 |
+
"version": "4.1.1",
|
| 1858 |
+
"resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
|
| 1859 |
+
"integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
|
| 1860 |
+
"dependencies": {
|
| 1861 |
+
"punycode": "^2.3.0"
|
| 1862 |
+
},
|
| 1863 |
+
"engines": {
|
| 1864 |
+
"node": ">=14"
|
| 1865 |
+
}
|
| 1866 |
+
},
|
| 1867 |
+
"node_modules/data-urls/node_modules/whatwg-url": {
|
| 1868 |
+
"version": "12.0.1",
|
| 1869 |
+
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
|
| 1870 |
+
"integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
|
| 1871 |
+
"dependencies": {
|
| 1872 |
+
"tr46": "^4.1.1",
|
| 1873 |
+
"webidl-conversions": "^7.0.0"
|
| 1874 |
+
},
|
| 1875 |
+
"engines": {
|
| 1876 |
+
"node": ">=14"
|
| 1877 |
+
}
|
| 1878 |
+
},
|
| 1879 |
"node_modules/date-fns": {
|
| 1880 |
"version": "2.29.3",
|
| 1881 |
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
|
|
|
|
| 1904 |
"version": "4.3.4",
|
| 1905 |
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
| 1906 |
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
|
|
|
| 1907 |
"dependencies": {
|
| 1908 |
"ms": "2.1.2"
|
| 1909 |
},
|
|
|
|
| 1916 |
}
|
| 1917 |
}
|
| 1918 |
},
|
| 1919 |
+
"node_modules/decimal.js": {
|
| 1920 |
+
"version": "10.4.3",
|
| 1921 |
+
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
|
| 1922 |
+
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
|
| 1923 |
+
},
|
| 1924 |
"node_modules/deep-eql": {
|
| 1925 |
"version": "4.1.3",
|
| 1926 |
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
|
|
|
|
| 1948 |
"node": ">=0.10.0"
|
| 1949 |
}
|
| 1950 |
},
|
| 1951 |
+
"node_modules/delayed-stream": {
|
| 1952 |
+
"version": "1.0.0",
|
| 1953 |
+
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
| 1954 |
+
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
| 1955 |
+
"engines": {
|
| 1956 |
+
"node": ">=0.4.0"
|
| 1957 |
+
}
|
| 1958 |
+
},
|
| 1959 |
"node_modules/detect-indent": {
|
| 1960 |
"version": "6.1.0",
|
| 1961 |
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
|
|
|
|
| 2005 |
"node": ">=6.0.0"
|
| 2006 |
}
|
| 2007 |
},
|
| 2008 |
+
"node_modules/domexception": {
|
| 2009 |
+
"version": "4.0.0",
|
| 2010 |
+
"resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
|
| 2011 |
+
"integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
|
| 2012 |
+
"dependencies": {
|
| 2013 |
+
"webidl-conversions": "^7.0.0"
|
| 2014 |
+
},
|
| 2015 |
+
"engines": {
|
| 2016 |
+
"node": ">=12"
|
| 2017 |
+
}
|
| 2018 |
+
},
|
| 2019 |
"node_modules/dotenv": {
|
| 2020 |
"version": "16.0.3",
|
| 2021 |
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
|
|
|
| 2029 |
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.359.tgz",
|
| 2030 |
"integrity": "sha512-OoVcngKCIuNXtZnsYoqlCvr0Cf3NIPzDIgwUfI9bdTFjXCrr79lI0kwQstLPZ7WhCezLlGksZk/BFAzoXC7GDw=="
|
| 2031 |
},
|
| 2032 |
+
"node_modules/entities": {
|
| 2033 |
+
"version": "4.5.0",
|
| 2034 |
+
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
| 2035 |
+
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
| 2036 |
+
"engines": {
|
| 2037 |
+
"node": ">=0.12"
|
| 2038 |
+
},
|
| 2039 |
+
"funding": {
|
| 2040 |
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 2041 |
+
}
|
| 2042 |
+
},
|
| 2043 |
"node_modules/es6-promise": {
|
| 2044 |
"version": "3.3.1",
|
| 2045 |
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
|
|
|
|
| 2506 |
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
| 2507 |
"dev": true
|
| 2508 |
},
|
| 2509 |
+
"node_modules/form-data": {
|
| 2510 |
+
"version": "4.0.0",
|
| 2511 |
+
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
| 2512 |
+
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
| 2513 |
+
"dependencies": {
|
| 2514 |
+
"asynckit": "^0.4.0",
|
| 2515 |
+
"combined-stream": "^1.0.8",
|
| 2516 |
+
"mime-types": "^2.1.12"
|
| 2517 |
+
},
|
| 2518 |
+
"engines": {
|
| 2519 |
+
"node": ">= 6"
|
| 2520 |
+
}
|
| 2521 |
+
},
|
| 2522 |
"node_modules/fraction.js": {
|
| 2523 |
"version": "4.2.0",
|
| 2524 |
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
|
|
|
|
| 2698 |
"node": ">=12.0.0"
|
| 2699 |
}
|
| 2700 |
},
|
| 2701 |
+
"node_modules/html-encoding-sniffer": {
|
| 2702 |
+
"version": "3.0.0",
|
| 2703 |
+
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
|
| 2704 |
+
"integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
|
| 2705 |
+
"dependencies": {
|
| 2706 |
+
"whatwg-encoding": "^2.0.0"
|
| 2707 |
+
},
|
| 2708 |
+
"engines": {
|
| 2709 |
+
"node": ">=12"
|
| 2710 |
+
}
|
| 2711 |
+
},
|
| 2712 |
+
"node_modules/http-proxy-agent": {
|
| 2713 |
+
"version": "5.0.0",
|
| 2714 |
+
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
|
| 2715 |
+
"integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
|
| 2716 |
+
"dependencies": {
|
| 2717 |
+
"@tootallnate/once": "2",
|
| 2718 |
+
"agent-base": "6",
|
| 2719 |
+
"debug": "4"
|
| 2720 |
+
},
|
| 2721 |
+
"engines": {
|
| 2722 |
+
"node": ">= 6"
|
| 2723 |
+
}
|
| 2724 |
+
},
|
| 2725 |
+
"node_modules/https-proxy-agent": {
|
| 2726 |
+
"version": "5.0.1",
|
| 2727 |
+
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
| 2728 |
+
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
| 2729 |
+
"dependencies": {
|
| 2730 |
+
"agent-base": "6",
|
| 2731 |
+
"debug": "4"
|
| 2732 |
+
},
|
| 2733 |
+
"engines": {
|
| 2734 |
+
"node": ">= 6"
|
| 2735 |
+
}
|
| 2736 |
+
},
|
| 2737 |
"node_modules/human-signals": {
|
| 2738 |
"version": "2.1.0",
|
| 2739 |
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
|
|
|
| 2743 |
"node": ">=10.17.0"
|
| 2744 |
}
|
| 2745 |
},
|
| 2746 |
+
"node_modules/iconv-lite": {
|
| 2747 |
+
"version": "0.6.3",
|
| 2748 |
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
| 2749 |
+
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
| 2750 |
+
"dependencies": {
|
| 2751 |
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
| 2752 |
+
},
|
| 2753 |
+
"engines": {
|
| 2754 |
+
"node": ">=0.10.0"
|
| 2755 |
+
}
|
| 2756 |
+
},
|
| 2757 |
"node_modules/ignore": {
|
| 2758 |
"version": "5.2.4",
|
| 2759 |
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
|
|
|
| 2891 |
"node": ">=8"
|
| 2892 |
}
|
| 2893 |
},
|
| 2894 |
+
"node_modules/is-potential-custom-element-name": {
|
| 2895 |
+
"version": "1.0.1",
|
| 2896 |
+
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
| 2897 |
+
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
|
| 2898 |
+
},
|
| 2899 |
"node_modules/is-reference": {
|
| 2900 |
"version": "1.2.1",
|
| 2901 |
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
|
|
|
|
| 2970 |
"js-yaml": "bin/js-yaml.js"
|
| 2971 |
}
|
| 2972 |
},
|
| 2973 |
+
"node_modules/jsdom": {
|
| 2974 |
+
"version": "22.0.0",
|
| 2975 |
+
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.0.0.tgz",
|
| 2976 |
+
"integrity": "sha512-p5ZTEb5h+O+iU02t0GfEjAnkdYPrQSkfuTSMkMYyIoMvUNEHsbG0bHHbfXIcfTqD2UfvjQX7mmgiFsyRwGscVw==",
|
| 2977 |
+
"dependencies": {
|
| 2978 |
+
"abab": "^2.0.6",
|
| 2979 |
+
"cssstyle": "^3.0.0",
|
| 2980 |
+
"data-urls": "^4.0.0",
|
| 2981 |
+
"decimal.js": "^10.4.3",
|
| 2982 |
+
"domexception": "^4.0.0",
|
| 2983 |
+
"form-data": "^4.0.0",
|
| 2984 |
+
"html-encoding-sniffer": "^3.0.0",
|
| 2985 |
+
"http-proxy-agent": "^5.0.0",
|
| 2986 |
+
"https-proxy-agent": "^5.0.1",
|
| 2987 |
+
"is-potential-custom-element-name": "^1.0.1",
|
| 2988 |
+
"nwsapi": "^2.2.4",
|
| 2989 |
+
"parse5": "^7.1.2",
|
| 2990 |
+
"rrweb-cssom": "^0.6.0",
|
| 2991 |
+
"saxes": "^6.0.0",
|
| 2992 |
+
"symbol-tree": "^3.2.4",
|
| 2993 |
+
"tough-cookie": "^4.1.2",
|
| 2994 |
+
"w3c-xmlserializer": "^4.0.0",
|
| 2995 |
+
"webidl-conversions": "^7.0.0",
|
| 2996 |
+
"whatwg-encoding": "^2.0.0",
|
| 2997 |
+
"whatwg-mimetype": "^3.0.0",
|
| 2998 |
+
"whatwg-url": "^12.0.1",
|
| 2999 |
+
"ws": "^8.13.0",
|
| 3000 |
+
"xml-name-validator": "^4.0.0"
|
| 3001 |
+
},
|
| 3002 |
+
"engines": {
|
| 3003 |
+
"node": ">=16"
|
| 3004 |
+
},
|
| 3005 |
+
"peerDependencies": {
|
| 3006 |
+
"canvas": "^2.5.0"
|
| 3007 |
+
},
|
| 3008 |
+
"peerDependenciesMeta": {
|
| 3009 |
+
"canvas": {
|
| 3010 |
+
"optional": true
|
| 3011 |
+
}
|
| 3012 |
+
}
|
| 3013 |
+
},
|
| 3014 |
+
"node_modules/jsdom/node_modules/tr46": {
|
| 3015 |
+
"version": "4.1.1",
|
| 3016 |
+
"resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
|
| 3017 |
+
"integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
|
| 3018 |
+
"dependencies": {
|
| 3019 |
+
"punycode": "^2.3.0"
|
| 3020 |
+
},
|
| 3021 |
+
"engines": {
|
| 3022 |
+
"node": ">=14"
|
| 3023 |
+
}
|
| 3024 |
+
},
|
| 3025 |
+
"node_modules/jsdom/node_modules/whatwg-url": {
|
| 3026 |
+
"version": "12.0.1",
|
| 3027 |
+
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
|
| 3028 |
+
"integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
|
| 3029 |
+
"dependencies": {
|
| 3030 |
+
"tr46": "^4.1.1",
|
| 3031 |
+
"webidl-conversions": "^7.0.0"
|
| 3032 |
+
},
|
| 3033 |
+
"engines": {
|
| 3034 |
+
"node": ">=14"
|
| 3035 |
+
}
|
| 3036 |
+
},
|
| 3037 |
"node_modules/json-schema-traverse": {
|
| 3038 |
"version": "0.4.1",
|
| 3039 |
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
|
|
|
| 3259 |
"node": ">=10.0.0"
|
| 3260 |
}
|
| 3261 |
},
|
| 3262 |
+
"node_modules/mime-db": {
|
| 3263 |
+
"version": "1.52.0",
|
| 3264 |
+
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
| 3265 |
+
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
| 3266 |
+
"engines": {
|
| 3267 |
+
"node": ">= 0.6"
|
| 3268 |
+
}
|
| 3269 |
+
},
|
| 3270 |
+
"node_modules/mime-types": {
|
| 3271 |
+
"version": "2.1.35",
|
| 3272 |
+
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
| 3273 |
+
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
| 3274 |
+
"dependencies": {
|
| 3275 |
+
"mime-db": "1.52.0"
|
| 3276 |
+
},
|
| 3277 |
+
"engines": {
|
| 3278 |
+
"node": ">= 0.6"
|
| 3279 |
+
}
|
| 3280 |
+
},
|
| 3281 |
"node_modules/mimic-fn": {
|
| 3282 |
"version": "2.1.0",
|
| 3283 |
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
|
|
|
| 3402 |
"node_modules/ms": {
|
| 3403 |
"version": "2.1.2",
|
| 3404 |
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
| 3405 |
+
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
|
|
|
| 3406 |
},
|
| 3407 |
"node_modules/mz": {
|
| 3408 |
"version": "2.7.0",
|
|
|
|
| 3481 |
"node": ">=8"
|
| 3482 |
}
|
| 3483 |
},
|
| 3484 |
+
"node_modules/nwsapi": {
|
| 3485 |
+
"version": "2.2.4",
|
| 3486 |
+
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.4.tgz",
|
| 3487 |
+
"integrity": "sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g=="
|
| 3488 |
+
},
|
| 3489 |
"node_modules/object-assign": {
|
| 3490 |
"version": "4.1.1",
|
| 3491 |
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
|
|
|
| 3650 |
"node": ">=0.6.19"
|
| 3651 |
}
|
| 3652 |
},
|
| 3653 |
+
"node_modules/parse5": {
|
| 3654 |
+
"version": "7.1.2",
|
| 3655 |
+
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
|
| 3656 |
+
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
|
| 3657 |
+
"dependencies": {
|
| 3658 |
+
"entities": "^4.4.0"
|
| 3659 |
+
},
|
| 3660 |
+
"funding": {
|
| 3661 |
+
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
| 3662 |
+
}
|
| 3663 |
+
},
|
| 3664 |
"node_modules/path-exists": {
|
| 3665 |
"version": "4.0.0",
|
| 3666 |
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
|
|
|
| 4050 |
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
| 4051 |
}
|
| 4052 |
},
|
| 4053 |
+
"node_modules/psl": {
|
| 4054 |
+
"version": "1.9.0",
|
| 4055 |
+
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
| 4056 |
+
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
|
| 4057 |
+
},
|
| 4058 |
"node_modules/punycode": {
|
| 4059 |
"version": "2.3.0",
|
| 4060 |
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
|
|
|
|
| 4072 |
"teleport": ">=0.2.0"
|
| 4073 |
}
|
| 4074 |
},
|
| 4075 |
+
"node_modules/querystringify": {
|
| 4076 |
+
"version": "2.2.0",
|
| 4077 |
+
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
| 4078 |
+
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
|
| 4079 |
+
},
|
| 4080 |
"node_modules/queue-microtask": {
|
| 4081 |
"version": "1.2.3",
|
| 4082 |
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
|
|
|
| 4144 |
"url": "https://github.com/sponsors/mysticatea"
|
| 4145 |
}
|
| 4146 |
},
|
| 4147 |
+
"node_modules/requires-port": {
|
| 4148 |
+
"version": "1.0.0",
|
| 4149 |
+
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
| 4150 |
+
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
|
| 4151 |
+
},
|
| 4152 |
"node_modules/resolve": {
|
| 4153 |
"version": "1.22.1",
|
| 4154 |
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
|
|
|
| 4214 |
"fsevents": "~2.3.2"
|
| 4215 |
}
|
| 4216 |
},
|
| 4217 |
+
"node_modules/rrweb-cssom": {
|
| 4218 |
+
"version": "0.6.0",
|
| 4219 |
+
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
|
| 4220 |
+
"integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw=="
|
| 4221 |
+
},
|
| 4222 |
"node_modules/run-parallel": {
|
| 4223 |
"version": "1.2.0",
|
| 4224 |
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
|
|
|
| 4253 |
"node": ">=6"
|
| 4254 |
}
|
| 4255 |
},
|
| 4256 |
+
"node_modules/safer-buffer": {
|
| 4257 |
+
"version": "2.1.2",
|
| 4258 |
+
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
| 4259 |
+
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
| 4260 |
+
},
|
| 4261 |
"node_modules/sander": {
|
| 4262 |
"version": "0.5.1",
|
| 4263 |
"resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz",
|
|
|
|
| 4294 |
"node": ">=6"
|
| 4295 |
}
|
| 4296 |
},
|
| 4297 |
+
"node_modules/saxes": {
|
| 4298 |
+
"version": "6.0.0",
|
| 4299 |
+
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
|
| 4300 |
+
"integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
|
| 4301 |
+
"dependencies": {
|
| 4302 |
+
"xmlchars": "^2.2.0"
|
| 4303 |
+
},
|
| 4304 |
+
"engines": {
|
| 4305 |
+
"node": ">=v12.22.7"
|
| 4306 |
+
}
|
| 4307 |
+
},
|
| 4308 |
"node_modules/semver": {
|
| 4309 |
"version": "7.3.8",
|
| 4310 |
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
|
|
|
| 4320 |
"node": ">=10"
|
| 4321 |
}
|
| 4322 |
},
|
| 4323 |
+
"node_modules/serpapi": {
|
| 4324 |
+
"version": "1.1.1",
|
| 4325 |
+
"resolved": "https://registry.npmjs.org/serpapi/-/serpapi-1.1.1.tgz",
|
| 4326 |
+
"integrity": "sha512-t5Bqu/6VMJ9naX8K+qCgUStpZOaNQFvIM4AudhMJLS6sqQT/EHaYrhGidDZHVx8QvcEdY6y1wNlxizOCtvJtUQ==",
|
| 4327 |
+
"dependencies": {
|
| 4328 |
+
"undici": "^5.12.0"
|
| 4329 |
+
}
|
| 4330 |
+
},
|
| 4331 |
"node_modules/set-cookie-parser": {
|
| 4332 |
"version": "2.6.0",
|
| 4333 |
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
|
|
|
|
| 4465 |
"version": "1.1.0",
|
| 4466 |
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
| 4467 |
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
|
|
|
| 4468 |
"engines": {
|
| 4469 |
"node": ">=10.0.0"
|
| 4470 |
}
|
|
|
|
| 4769 |
"node": ">=12"
|
| 4770 |
}
|
| 4771 |
},
|
| 4772 |
+
"node_modules/symbol-tree": {
|
| 4773 |
+
"version": "3.2.4",
|
| 4774 |
+
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
| 4775 |
+
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
|
| 4776 |
+
},
|
| 4777 |
"node_modules/tailwind-scrollbar": {
|
| 4778 |
"version": "3.0.0",
|
| 4779 |
"resolved": "https://registry.npmjs.org/tailwind-scrollbar/-/tailwind-scrollbar-3.0.0.tgz",
|
|
|
|
| 4927 |
"node": ">=6"
|
| 4928 |
}
|
| 4929 |
},
|
| 4930 |
+
"node_modules/tough-cookie": {
|
| 4931 |
+
"version": "4.1.2",
|
| 4932 |
+
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
| 4933 |
+
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
|
| 4934 |
+
"dependencies": {
|
| 4935 |
+
"psl": "^1.1.33",
|
| 4936 |
+
"punycode": "^2.1.1",
|
| 4937 |
+
"universalify": "^0.2.0",
|
| 4938 |
+
"url-parse": "^1.5.3"
|
| 4939 |
+
},
|
| 4940 |
+
"engines": {
|
| 4941 |
+
"node": ">=6"
|
| 4942 |
+
}
|
| 4943 |
+
},
|
| 4944 |
"node_modules/tr46": {
|
| 4945 |
"version": "3.0.0",
|
| 4946 |
"resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
|
|
|
|
| 5040 |
"version": "5.22.0",
|
| 5041 |
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz",
|
| 5042 |
"integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==",
|
|
|
|
| 5043 |
"dependencies": {
|
| 5044 |
"busboy": "^1.6.0"
|
| 5045 |
},
|
|
|
|
| 5047 |
"node": ">=14.0"
|
| 5048 |
}
|
| 5049 |
},
|
| 5050 |
+
"node_modules/universalify": {
|
| 5051 |
+
"version": "0.2.0",
|
| 5052 |
+
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
| 5053 |
+
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
| 5054 |
+
"engines": {
|
| 5055 |
+
"node": ">= 4.0.0"
|
| 5056 |
+
}
|
| 5057 |
+
},
|
| 5058 |
"node_modules/unplugin": {
|
| 5059 |
"version": "1.3.1",
|
| 5060 |
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.3.1.tgz",
|
|
|
|
| 5139 |
"punycode": "^2.1.0"
|
| 5140 |
}
|
| 5141 |
},
|
| 5142 |
+
"node_modules/url-parse": {
|
| 5143 |
+
"version": "1.5.10",
|
| 5144 |
+
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
| 5145 |
+
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
| 5146 |
+
"dependencies": {
|
| 5147 |
+
"querystringify": "^2.1.1",
|
| 5148 |
+
"requires-port": "^1.0.0"
|
| 5149 |
+
}
|
| 5150 |
+
},
|
| 5151 |
"node_modules/util-deprecate": {
|
| 5152 |
"version": "1.0.2",
|
| 5153 |
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
|
|
|
| 5321 |
}
|
| 5322 |
}
|
| 5323 |
},
|
| 5324 |
+
"node_modules/w3c-xmlserializer": {
|
| 5325 |
+
"version": "4.0.0",
|
| 5326 |
+
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
|
| 5327 |
+
"integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
|
| 5328 |
+
"dependencies": {
|
| 5329 |
+
"xml-name-validator": "^4.0.0"
|
| 5330 |
+
},
|
| 5331 |
+
"engines": {
|
| 5332 |
+
"node": ">=14"
|
| 5333 |
+
}
|
| 5334 |
+
},
|
| 5335 |
"node_modules/webidl-conversions": {
|
| 5336 |
"version": "7.0.0",
|
| 5337 |
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
|
|
|
| 5364 |
"node": ">=6"
|
| 5365 |
}
|
| 5366 |
},
|
| 5367 |
+
"node_modules/whatwg-encoding": {
|
| 5368 |
+
"version": "2.0.0",
|
| 5369 |
+
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
|
| 5370 |
+
"integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
|
| 5371 |
+
"dependencies": {
|
| 5372 |
+
"iconv-lite": "0.6.3"
|
| 5373 |
+
},
|
| 5374 |
+
"engines": {
|
| 5375 |
+
"node": ">=12"
|
| 5376 |
+
}
|
| 5377 |
+
},
|
| 5378 |
+
"node_modules/whatwg-mimetype": {
|
| 5379 |
+
"version": "3.0.0",
|
| 5380 |
+
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
|
| 5381 |
+
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
|
| 5382 |
+
"engines": {
|
| 5383 |
+
"node": ">=12"
|
| 5384 |
+
}
|
| 5385 |
+
},
|
| 5386 |
"node_modules/whatwg-url": {
|
| 5387 |
"version": "11.0.0",
|
| 5388 |
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
|
|
|
|
| 5460 |
}
|
| 5461 |
}
|
| 5462 |
},
|
| 5463 |
+
"node_modules/xml-name-validator": {
|
| 5464 |
+
"version": "4.0.0",
|
| 5465 |
+
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
| 5466 |
+
"integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
|
| 5467 |
+
"engines": {
|
| 5468 |
+
"node": ">=12"
|
| 5469 |
+
}
|
| 5470 |
+
},
|
| 5471 |
+
"node_modules/xmlchars": {
|
| 5472 |
+
"version": "2.2.0",
|
| 5473 |
+
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
| 5474 |
+
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
| 5475 |
+
},
|
| 5476 |
"node_modules/yallist": {
|
| 5477 |
"version": "4.0.0",
|
| 5478 |
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
@@ -19,6 +19,7 @@
|
|
| 19 |
"@sveltejs/adapter-node": "^1.2.4",
|
| 20 |
"@sveltejs/kit": "^1.15.10",
|
| 21 |
"@tailwindcss/typography": "^0.5.9",
|
|
|
|
| 22 |
"@types/marked": "^4.0.8",
|
| 23 |
"@types/parquetjs": "^0.10.3",
|
| 24 |
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
|
@@ -45,12 +46,14 @@
|
|
| 45 |
"date-fns": "^2.29.3",
|
| 46 |
"dotenv": "^16.0.3",
|
| 47 |
"highlight.js": "^11.7.0",
|
|
|
|
| 48 |
"marked": "^4.3.0",
|
| 49 |
"mongodb": "^5.3.0",
|
| 50 |
"nanoid": "^4.0.2",
|
| 51 |
"openid-client": "^5.4.2",
|
| 52 |
"parquetjs": "^0.11.2",
|
| 53 |
"postcss": "^8.4.21",
|
|
|
|
| 54 |
"tailwind-scrollbar": "^3.0.0",
|
| 55 |
"tailwindcss": "^3.3.1",
|
| 56 |
"zod": "^3.21.4"
|
|
|
|
| 19 |
"@sveltejs/adapter-node": "^1.2.4",
|
| 20 |
"@sveltejs/kit": "^1.15.10",
|
| 21 |
"@tailwindcss/typography": "^0.5.9",
|
| 22 |
+
"@types/jsdom": "^21.1.1",
|
| 23 |
"@types/marked": "^4.0.8",
|
| 24 |
"@types/parquetjs": "^0.10.3",
|
| 25 |
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
|
|
|
| 46 |
"date-fns": "^2.29.3",
|
| 47 |
"dotenv": "^16.0.3",
|
| 48 |
"highlight.js": "^11.7.0",
|
| 49 |
+
"jsdom": "^22.0.0",
|
| 50 |
"marked": "^4.3.0",
|
| 51 |
"mongodb": "^5.3.0",
|
| 52 |
"nanoid": "^4.0.2",
|
| 53 |
"openid-client": "^5.4.2",
|
| 54 |
"parquetjs": "^0.11.2",
|
| 55 |
"postcss": "^8.4.21",
|
| 56 |
+
"serpapi": "^1.1.1",
|
| 57 |
"tailwind-scrollbar": "^3.0.0",
|
| 58 |
"tailwindcss": "^3.3.1",
|
| 59 |
"zod": "^3.21.4"
|
|
@@ -1,15 +1,18 @@
|
|
| 1 |
import type { BackendModel } from "./server/models";
|
| 2 |
import type { Message } from "./types/Message";
|
| 3 |
-
|
|
|
|
| 4 |
/**
|
| 5 |
* Convert [{user: "assistant", content: "hi"}, {user: "user", content: "hello"}] to:
|
| 6 |
*
|
| 7 |
* <|assistant|>hi<|endoftext|><|prompter|>hello<|endoftext|><|assistant|>
|
| 8 |
*/
|
| 9 |
-
|
|
|
|
| 10 |
messages: Pick<Message, "from" | "content">[],
|
| 11 |
-
model: BackendModel
|
| 12 |
-
|
|
|
|
| 13 |
const prompt =
|
| 14 |
messages
|
| 15 |
.map(
|
|
@@ -25,12 +28,30 @@ export function buildPrompt(
|
|
| 25 |
)
|
| 26 |
.join("") + model.assistantMessageToken;
|
| 27 |
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
model.preprompt +
|
|
|
|
| 31 |
prompt
|
| 32 |
.split(" ")
|
| 33 |
.slice(-(model.parameters?.truncate ?? 0))
|
| 34 |
-
.join(" ")
|
| 35 |
-
|
|
|
|
|
|
|
| 36 |
}
|
|
|
|
| 1 |
import type { BackendModel } from "./server/models";
|
| 2 |
import type { Message } from "./types/Message";
|
| 3 |
+
import { collections } from "$lib/server/database";
|
| 4 |
+
import { ObjectId } from "mongodb";
|
| 5 |
/**
|
| 6 |
* Convert [{user: "assistant", content: "hi"}, {user: "user", content: "hello"}] to:
|
| 7 |
*
|
| 8 |
* <|assistant|>hi<|endoftext|><|prompter|>hello<|endoftext|><|assistant|>
|
| 9 |
*/
|
| 10 |
+
|
| 11 |
+
export async function buildPrompt(
|
| 12 |
messages: Pick<Message, "from" | "content">[],
|
| 13 |
+
model: BackendModel,
|
| 14 |
+
webSearchId?: string
|
| 15 |
+
): Promise<string> {
|
| 16 |
const prompt =
|
| 17 |
messages
|
| 18 |
.map(
|
|
|
|
| 28 |
)
|
| 29 |
.join("") + model.assistantMessageToken;
|
| 30 |
|
| 31 |
+
let webPrompt = "";
|
| 32 |
+
|
| 33 |
+
if (webSearchId) {
|
| 34 |
+
const webSearch = await collections.webSearches.findOne({
|
| 35 |
+
_id: new ObjectId(webSearchId),
|
| 36 |
+
});
|
| 37 |
+
|
| 38 |
+
if (!webSearch) throw new Error("Web search not found");
|
| 39 |
+
|
| 40 |
+
if (webSearch.summary) {
|
| 41 |
+
webPrompt =
|
| 42 |
+
model.assistantMessageToken +
|
| 43 |
+
`The following context was found while searching the internet: ${webSearch.summary}` +
|
| 44 |
+
model.messageEndToken;
|
| 45 |
+
}
|
| 46 |
+
}
|
| 47 |
+
const finalPrompt =
|
| 48 |
model.preprompt +
|
| 49 |
+
webPrompt +
|
| 50 |
prompt
|
| 51 |
.split(" ")
|
| 52 |
.slice(-(model.parameters?.truncate ?? 0))
|
| 53 |
+
.join(" ");
|
| 54 |
+
|
| 55 |
+
// Not super precise, but it's truncated in the model's backend anyway
|
| 56 |
+
return finalPrompt;
|
| 57 |
}
|
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import type { WebSearchMessage } from "$lib/types/WebSearch";
|
| 3 |
+
import CarbonCaretRight from "~icons/carbon/caret-right";
|
| 4 |
+
|
| 5 |
+
import CarbonCheckmark from "~icons/carbon/checkmark-filled";
|
| 6 |
+
import CarbonError from "~icons/carbon/error-filled";
|
| 7 |
+
|
| 8 |
+
import EosIconsLoading from "~icons/eos-icons/loading";
|
| 9 |
+
|
| 10 |
+
import { base } from "$app/paths";
|
| 11 |
+
import { onMount } from "svelte";
|
| 12 |
+
|
| 13 |
+
export let loading = false;
|
| 14 |
+
export let classNames = "";
|
| 15 |
+
export let webSearchId: string | undefined;
|
| 16 |
+
export let webSearchMessages: WebSearchMessage[] = [];
|
| 17 |
+
|
| 18 |
+
let detailsOpen: boolean;
|
| 19 |
+
let error: boolean;
|
| 20 |
+
onMount(() => {
|
| 21 |
+
if (webSearchMessages.length === 0 && webSearchId) {
|
| 22 |
+
fetch(`${base}/search/${webSearchId}`)
|
| 23 |
+
.then((res) => res.json())
|
| 24 |
+
.then((res) => {
|
| 25 |
+
webSearchMessages = [...res.messages, { type: "result", id: webSearchId }];
|
| 26 |
+
})
|
| 27 |
+
.catch((err) => console.log(err));
|
| 28 |
+
}
|
| 29 |
+
});
|
| 30 |
+
$: error = webSearchMessages.some((message) => message.type === "error");
|
| 31 |
+
</script>
|
| 32 |
+
|
| 33 |
+
<details
|
| 34 |
+
class="details flex w-fit rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-800 dark:bg-gray-900 {classNames}"
|
| 35 |
+
on:toggle={() => {
|
| 36 |
+
if (webSearchMessages.length === 0 && webSearchId) {
|
| 37 |
+
fetch(`${base}/search/${webSearchId}`)
|
| 38 |
+
.then((res) => res.json())
|
| 39 |
+
.then((res) => {
|
| 40 |
+
webSearchMessages = [...res.messages, { type: "result", id: webSearchId }];
|
| 41 |
+
})
|
| 42 |
+
.catch((err) => console.log(err));
|
| 43 |
+
}
|
| 44 |
+
}}
|
| 45 |
+
bind:open={detailsOpen}
|
| 46 |
+
>
|
| 47 |
+
<summary
|
| 48 |
+
class="align-center flex cursor-pointer select-none list-none py-1 pl-2.5 pr-2 align-text-top transition-all"
|
| 49 |
+
>
|
| 50 |
+
{#if error}
|
| 51 |
+
<CarbonError class="my-auto text-red-700 dark:text-red-500" />
|
| 52 |
+
{:else if loading}
|
| 53 |
+
<EosIconsLoading class="my-auto text-gray-500" />
|
| 54 |
+
{:else}
|
| 55 |
+
<CarbonCheckmark class="my-auto text-gray-500" />
|
| 56 |
+
{/if}
|
| 57 |
+
<span class="px-2 font-medium" class:text-red-700={error} class:dark:text-red-500={error}
|
| 58 |
+
>Web search
|
| 59 |
+
</span>
|
| 60 |
+
<div class="my-auto transition-all" class:rotate-90={detailsOpen}>
|
| 61 |
+
<CarbonCaretRight />
|
| 62 |
+
</div>
|
| 63 |
+
</summary>
|
| 64 |
+
|
| 65 |
+
<div class="content p-5 pb-1">
|
| 66 |
+
{#if webSearchMessages.length === 0}
|
| 67 |
+
<div class="mx-auto w-fit">
|
| 68 |
+
<EosIconsLoading class="mb-3 h-10 w-10" />
|
| 69 |
+
</div>
|
| 70 |
+
{:else}
|
| 71 |
+
<ol class="relative border-l border-gray-200 dark:border-gray-600">
|
| 72 |
+
{#each webSearchMessages as message}
|
| 73 |
+
{#if message.type === "update"}
|
| 74 |
+
<li class="mb-4 ml-4">
|
| 75 |
+
<div
|
| 76 |
+
class="h-3 w-3 -translate-x-[1.4rem] rounded-full bg-gray-200 dark:bg-gray-600"
|
| 77 |
+
/>
|
| 78 |
+
<h3 class="text-md -translate-y-[1.1rem] text-gray-800 dark:text-gray-100">
|
| 79 |
+
{message.message}
|
| 80 |
+
</h3>
|
| 81 |
+
{#if message.args}
|
| 82 |
+
<p
|
| 83 |
+
class="mb-4 -translate-y-[1.1rem] font-normal text-gray-500 dark:text-gray-400 "
|
| 84 |
+
>
|
| 85 |
+
{message.args}
|
| 86 |
+
</p>
|
| 87 |
+
{/if}
|
| 88 |
+
</li>
|
| 89 |
+
{:else if message.type === "error"}
|
| 90 |
+
<li class="mb-4 ml-4">
|
| 91 |
+
<div
|
| 92 |
+
class="h-3 w-3 -translate-x-[1.4rem] rounded-full text-red-700 dark:text-red-500"
|
| 93 |
+
>
|
| 94 |
+
<CarbonError class="h-3 w-3" />
|
| 95 |
+
</div>
|
| 96 |
+
<h3 class="text-md -translate-y-[1.1rem] text-red-700 dark:text-red-500">
|
| 97 |
+
{message.message}
|
| 98 |
+
</h3>
|
| 99 |
+
{#if message.args}
|
| 100 |
+
<p class="mb-4 -translate-y-[1.1rem] font-normal text-gray-500 dark:text-gray-400 ">
|
| 101 |
+
{message.args}
|
| 102 |
+
</p>
|
| 103 |
+
{/if}
|
| 104 |
+
</li>
|
| 105 |
+
{/if}
|
| 106 |
+
<p />
|
| 107 |
+
{/each}
|
| 108 |
+
</ol>
|
| 109 |
+
{/if}
|
| 110 |
+
</div>
|
| 111 |
+
</details>
|
| 112 |
+
|
| 113 |
+
<style>
|
| 114 |
+
@keyframes grow {
|
| 115 |
+
0% {
|
| 116 |
+
font-size: 0;
|
| 117 |
+
opacity: 0;
|
| 118 |
+
}
|
| 119 |
+
30% {
|
| 120 |
+
font-size: 1em;
|
| 121 |
+
opacity: 0;
|
| 122 |
+
}
|
| 123 |
+
100% {
|
| 124 |
+
opacity: 1;
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
.details[open] .content {
|
| 129 |
+
animation-name: grow;
|
| 130 |
+
animation-duration: 300ms;
|
| 131 |
+
animation-delay: 0ms;
|
| 132 |
+
}
|
| 133 |
+
</style>
|
|
@@ -1,17 +1,13 @@
|
|
| 1 |
<script lang="ts">
|
| 2 |
-
import
|
| 3 |
|
| 4 |
-
export let
|
| 5 |
-
export let className = "";
|
| 6 |
</script>
|
| 7 |
|
| 8 |
<button
|
| 9 |
type="button"
|
| 10 |
on:click
|
| 11 |
-
class="btn flex rounded-lg border bg-white px-3 py-1 shadow-sm transition-all hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:hover:bg-gray-600
|
| 12 |
-
{className}
|
| 13 |
-
{visible ? 'visible opacity-100' : 'invisible opacity-0'}
|
| 14 |
-
"
|
| 15 |
>
|
| 16 |
-
<
|
| 17 |
</button>
|
|
|
|
| 1 |
<script lang="ts">
|
| 2 |
+
import CarbonStopFilledAlt from "~icons/carbon/stop-filled-alt";
|
| 3 |
|
| 4 |
+
export let classNames = "";
|
|
|
|
| 5 |
</script>
|
| 6 |
|
| 7 |
<button
|
| 8 |
type="button"
|
| 9 |
on:click
|
| 10 |
+
class="btn flex h-9 rounded-lg border bg-white px-3 py-1 shadow-sm transition-all hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:hover:bg-gray-600 {classNames}"
|
|
|
|
|
|
|
|
|
|
| 11 |
>
|
| 12 |
+
<CarbonStopFilledAlt class="-ml-1 mr-1 h-[1.25rem] w-[1.1875rem] text-gray-400" /> Stop generating
|
| 13 |
</button>
|
|
@@ -5,7 +5,9 @@
|
|
| 5 |
|
| 6 |
<input bind:checked type="checkbox" {name} class="peer pointer-events-none absolute opacity-0" />
|
| 7 |
<div
|
| 8 |
-
|
|
|
|
|
|
|
| 9 |
>
|
| 10 |
<div class="h-3.5 w-3.5 rounded-full bg-white shadow-sm transition-all" />
|
| 11 |
</div>
|
|
|
|
| 5 |
|
| 6 |
<input bind:checked type="checkbox" {name} class="peer pointer-events-none absolute opacity-0" />
|
| 7 |
<div
|
| 8 |
+
on:click
|
| 9 |
+
on:keypress
|
| 10 |
+
class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full bg-gray-300 p-1 shadow-inner ring-gray-400 transition-all peer-checked:bg-blue-600 peer-focus-visible:ring peer-focus-visible:ring-offset-1 hover:bg-gray-400 dark:bg-gray-600 peer-checked:[&>div]:translate-x-3.5"
|
| 11 |
>
|
| 12 |
<div class="h-3.5 w-3.5 rounded-full bg-white shadow-sm transition-all" />
|
| 13 |
</div>
|
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import { webSearchParameters } from "$lib/stores/webSearchParameters";
|
| 3 |
+
import CarbonInformation from "~icons/carbon/information";
|
| 4 |
+
import Switch from "./Switch.svelte";
|
| 5 |
+
|
| 6 |
+
const toggle = () => ($webSearchParameters.useSearch = !$webSearchParameters.useSearch);
|
| 7 |
+
</script>
|
| 8 |
+
|
| 9 |
+
<div
|
| 10 |
+
class="flex h-9 cursor-pointer select-none items-center gap-2 rounded-xl border bg-white p-1.5 shadow-sm hover:shadow-none dark:border-gray-800 dark:bg-gray-900"
|
| 11 |
+
on:click={toggle}
|
| 12 |
+
on:keypress={toggle}
|
| 13 |
+
>
|
| 14 |
+
<Switch name="useSearch" bind:checked={$webSearchParameters.useSearch} on:click on:keypress />
|
| 15 |
+
<div class="whitespace-nowrap text-sm text-gray-800 dark:text-gray-200">Search web</div>
|
| 16 |
+
<div class="group relative w-max">
|
| 17 |
+
<CarbonInformation class="text-xs text-gray-500" />
|
| 18 |
+
<div
|
| 19 |
+
class="pointer-events-none absolute -top-20 left-1/2 w-max -translate-x-1/2 rounded-md bg-gray-100 p-2 opacity-0 transition-opacity group-hover:opacity-100 dark:bg-gray-800"
|
| 20 |
+
>
|
| 21 |
+
<p class="max-w-sm text-sm text-gray-800 dark:text-gray-200">
|
| 22 |
+
When enabled, the model will try to complement its answer with information queried from the
|
| 23 |
+
web.
|
| 24 |
+
</p>
|
| 25 |
+
</div>
|
| 26 |
+
</div>
|
| 27 |
+
</div>
|
|
@@ -13,6 +13,9 @@
|
|
| 13 |
import CarbonThumbsDown from "~icons/carbon/thumbs-down";
|
| 14 |
import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken";
|
| 15 |
import type { Model } from "$lib/types/Model";
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
function sanitizeMd(md: string) {
|
| 18 |
let ret = md
|
|
@@ -43,6 +46,9 @@
|
|
| 43 |
export let isAuthor = true;
|
| 44 |
export let readOnly = false;
|
| 45 |
export let isTapped = false;
|
|
|
|
|
|
|
|
|
|
| 46 |
|
| 47 |
const dispatch = createEventDispatcher<{
|
| 48 |
retry: { content: string; id: Message["id"] };
|
|
@@ -89,6 +95,13 @@
|
|
| 89 |
|
| 90 |
$: downloadLink =
|
| 91 |
message.from === "user" ? `${$page.url.pathname}/message/${message.id}/prompt` : undefined;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
</script>
|
| 93 |
|
| 94 |
{#if message.from === "assistant"}
|
|
@@ -103,11 +116,22 @@
|
|
| 103 |
class="mt-5 h-3 w-3 flex-none select-none rounded-full shadow-lg"
|
| 104 |
/>
|
| 105 |
<div
|
| 106 |
-
class="relative min-h-[calc(2rem+theme(spacing[3.5])*2)] min-w-[
|
| 107 |
>
|
| 108 |
-
{#if
|
| 109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
{/if}
|
|
|
|
| 111 |
<div
|
| 112 |
class="prose max-w-none dark:prose-invert max-sm:prose-sm 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"
|
| 113 |
bind:this={contentEl}
|
|
|
|
| 13 |
import CarbonThumbsDown from "~icons/carbon/thumbs-down";
|
| 14 |
import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken";
|
| 15 |
import type { Model } from "$lib/types/Model";
|
| 16 |
+
import type { WebSearchMessage } from "$lib/types/WebSearch";
|
| 17 |
+
|
| 18 |
+
import OpenWebSearchResults from "../OpenWebSearchResults.svelte";
|
| 19 |
|
| 20 |
function sanitizeMd(md: string) {
|
| 21 |
let ret = md
|
|
|
|
| 46 |
export let isAuthor = true;
|
| 47 |
export let readOnly = false;
|
| 48 |
export let isTapped = false;
|
| 49 |
+
export let isLast = false;
|
| 50 |
+
|
| 51 |
+
export let webSearchMessages: WebSearchMessage[] = [];
|
| 52 |
|
| 53 |
const dispatch = createEventDispatcher<{
|
| 54 |
retry: { content: string; id: Message["id"] };
|
|
|
|
| 95 |
|
| 96 |
$: downloadLink =
|
| 97 |
message.from === "user" ? `${$page.url.pathname}/message/${message.id}/prompt` : undefined;
|
| 98 |
+
|
| 99 |
+
let webSearchIsDone = true;
|
| 100 |
+
|
| 101 |
+
$: webSearchIsDone =
|
| 102 |
+
!!message.webSearchId ||
|
| 103 |
+
(webSearchMessages.length > 0 &&
|
| 104 |
+
webSearchMessages[webSearchMessages.length - 1].type === "result");
|
| 105 |
</script>
|
| 106 |
|
| 107 |
{#if message.from === "assistant"}
|
|
|
|
| 116 |
class="mt-5 h-3 w-3 flex-none select-none rounded-full shadow-lg"
|
| 117 |
/>
|
| 118 |
<div
|
| 119 |
+
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"
|
| 120 |
>
|
| 121 |
+
{#if message.webSearchId || (webSearchMessages.length > 0 && isLast)}
|
| 122 |
+
{#key (message.webSearchId, message.score, loading)}
|
| 123 |
+
<OpenWebSearchResults
|
| 124 |
+
classNames={tokens.length ? "mb-3" : ""}
|
| 125 |
+
webSearchId={message.webSearchId}
|
| 126 |
+
{webSearchMessages}
|
| 127 |
+
loading={!webSearchIsDone}
|
| 128 |
+
/>
|
| 129 |
+
{/key}
|
| 130 |
+
{/if}
|
| 131 |
+
{#if !message.content && (webSearchIsDone || webSearchMessages.length === 0)}
|
| 132 |
+
<IconLoading />
|
| 133 |
{/if}
|
| 134 |
+
|
| 135 |
<div
|
| 136 |
class="prose max-w-none dark:prose-invert max-sm:prose-sm 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"
|
| 137 |
bind:this={contentEl}
|
|
@@ -8,6 +8,8 @@
|
|
| 8 |
import type { LayoutData } from "../../../routes/$types";
|
| 9 |
import ChatIntroduction from "./ChatIntroduction.svelte";
|
| 10 |
import ChatMessage from "./ChatMessage.svelte";
|
|
|
|
|
|
|
| 11 |
|
| 12 |
export let messages: Message[];
|
| 13 |
export let loading: boolean;
|
|
@@ -20,6 +22,8 @@
|
|
| 20 |
|
| 21 |
let chatContainer: HTMLElement;
|
| 22 |
|
|
|
|
|
|
|
| 23 |
async function scrollToBottom() {
|
| 24 |
await tick();
|
| 25 |
chatContainer.scrollTop = chatContainer.scrollHeight;
|
|
@@ -33,20 +37,24 @@
|
|
| 33 |
|
| 34 |
<div
|
| 35 |
class="scrollbar-custom mr-1 h-full overflow-y-auto"
|
| 36 |
-
use:snapScrollToBottom={messages.length ? messages : false}
|
| 37 |
bind:this={chatContainer}
|
| 38 |
>
|
| 39 |
<div class="mx-auto flex h-full max-w-3xl flex-col gap-6 px-5 pt-6 sm:gap-8 xl:max-w-4xl">
|
| 40 |
{#each messages as message, i}
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
{:else}
|
| 51 |
<ChatIntroduction {settings} {models} {currentModel} on:message />
|
| 52 |
{/each}
|
|
@@ -54,9 +62,11 @@
|
|
| 54 |
<ChatMessage
|
| 55 |
message={{ from: "assistant", content: "", id: randomUUID() }}
|
| 56 |
model={currentModel}
|
|
|
|
|
|
|
| 57 |
/>
|
| 58 |
{/if}
|
| 59 |
-
<div class="h-
|
| 60 |
</div>
|
| 61 |
<ScrollToBottomBtn
|
| 62 |
class="bottom-36 right-4 max-md:hidden lg:right-10"
|
|
|
|
| 8 |
import type { LayoutData } from "../../../routes/$types";
|
| 9 |
import ChatIntroduction from "./ChatIntroduction.svelte";
|
| 10 |
import ChatMessage from "./ChatMessage.svelte";
|
| 11 |
+
import type { WebSearchMessage } from "$lib/types/WebSearch";
|
| 12 |
+
import { page } from "$app/stores";
|
| 13 |
|
| 14 |
export let messages: Message[];
|
| 15 |
export let loading: boolean;
|
|
|
|
| 22 |
|
| 23 |
let chatContainer: HTMLElement;
|
| 24 |
|
| 25 |
+
export let webSearchMessages: WebSearchMessage[] = [];
|
| 26 |
+
|
| 27 |
async function scrollToBottom() {
|
| 28 |
await tick();
|
| 29 |
chatContainer.scrollTop = chatContainer.scrollHeight;
|
|
|
|
| 37 |
|
| 38 |
<div
|
| 39 |
class="scrollbar-custom mr-1 h-full overflow-y-auto"
|
| 40 |
+
use:snapScrollToBottom={messages.length ? [...messages, ...webSearchMessages] : false}
|
| 41 |
bind:this={chatContainer}
|
| 42 |
>
|
| 43 |
<div class="mx-auto flex h-full max-w-3xl flex-col gap-6 px-5 pt-6 sm:gap-8 xl:max-w-4xl">
|
| 44 |
{#each messages as message, i}
|
| 45 |
+
{#key (message.id, $page.params.id)}
|
| 46 |
+
<ChatMessage
|
| 47 |
+
loading={loading && i === messages.length - 1}
|
| 48 |
+
{message}
|
| 49 |
+
{isAuthor}
|
| 50 |
+
{readOnly}
|
| 51 |
+
model={currentModel}
|
| 52 |
+
{webSearchMessages}
|
| 53 |
+
isLast={i === messages.length - 1}
|
| 54 |
+
on:retry
|
| 55 |
+
on:vote
|
| 56 |
+
/>
|
| 57 |
+
{/key}
|
| 58 |
{:else}
|
| 59 |
<ChatIntroduction {settings} {models} {currentModel} on:message />
|
| 60 |
{/each}
|
|
|
|
| 62 |
<ChatMessage
|
| 63 |
message={{ from: "assistant", content: "", id: randomUUID() }}
|
| 64 |
model={currentModel}
|
| 65 |
+
isLast={true}
|
| 66 |
+
{webSearchMessages}
|
| 67 |
/>
|
| 68 |
{/if}
|
| 69 |
+
<div class="h-44 flex-none" />
|
| 70 |
</div>
|
| 71 |
<ScrollToBottomBtn
|
| 72 |
class="bottom-36 right-4 max-md:hidden lg:right-10"
|
|
@@ -4,7 +4,7 @@
|
|
| 4 |
|
| 5 |
import CarbonSendAltFilled from "~icons/carbon/send-alt-filled";
|
| 6 |
import CarbonExport from "~icons/carbon/export";
|
| 7 |
-
import
|
| 8 |
import EosIconsLoading from "~icons/eos-icons/loading";
|
| 9 |
|
| 10 |
import ChatMessages from "./ChatMessages.svelte";
|
|
@@ -12,6 +12,8 @@
|
|
| 12 |
import StopGeneratingBtn from "../StopGeneratingBtn.svelte";
|
| 13 |
import type { Model } from "$lib/types/Model";
|
| 14 |
import type { LayoutData } from "../../../routes/$types";
|
|
|
|
|
|
|
| 15 |
import LoginModal from "../LoginModal.svelte";
|
| 16 |
|
| 17 |
export let messages: Message[] = [];
|
|
@@ -21,6 +23,7 @@
|
|
| 21 |
export let currentModel: Model;
|
| 22 |
export let models: Model[];
|
| 23 |
export let settings: LayoutData["settings"];
|
|
|
|
| 24 |
|
| 25 |
export let loginRequired = false;
|
| 26 |
$: isReadOnly = !models.some((model) => model.id === currentModel.id);
|
|
@@ -55,6 +58,7 @@
|
|
| 55 |
{messages}
|
| 56 |
readOnly={isReadOnly}
|
| 57 |
isAuthor={!shared}
|
|
|
|
| 58 |
on:message
|
| 59 |
on:vote
|
| 60 |
on:retry={(ev) => {
|
|
@@ -64,8 +68,16 @@
|
|
| 64 |
<div
|
| 65 |
class="dark:via-gray-80 pointer-events-none absolute inset-x-0 bottom-0 z-0 mx-auto flex w-full max-w-3xl flex-col items-center justify-center bg-gradient-to-t from-white via-white/80 to-white/0 px-3.5 py-4 dark:border-gray-800 dark:from-gray-900 dark:to-gray-900/0 max-md:border-t max-md:bg-white max-md:dark:bg-gray-900 sm:px-5 md:py-8 xl:max-w-4xl [&>*]:pointer-events-auto"
|
| 66 |
>
|
| 67 |
-
<div class="
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
</div>
|
| 70 |
<form
|
| 71 |
on:submit|preventDefault={handleSubmit}
|
|
@@ -89,7 +101,7 @@
|
|
| 89 |
class="btn mx-1 my-1 inline-block h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400 disabled:opacity-60 enabled:hover:text-gray-700 dark:disabled:opacity-40 enabled:dark:hover:text-gray-100 md:hidden"
|
| 90 |
on:click={() => dispatch("stop")}
|
| 91 |
>
|
| 92 |
-
<
|
| 93 |
</button>
|
| 94 |
<div
|
| 95 |
class="mx-1 my-1 hidden h-[2.4rem] items-center p-1 px-[0.7rem] text-gray-400 disabled:opacity-60 enabled:hover:text-gray-700 dark:disabled:opacity-40 enabled:dark:hover:text-gray-100 md:flex"
|
|
|
|
| 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 EosIconsLoading from "~icons/eos-icons/loading";
|
| 9 |
|
| 10 |
import ChatMessages from "./ChatMessages.svelte";
|
|
|
|
| 12 |
import StopGeneratingBtn from "../StopGeneratingBtn.svelte";
|
| 13 |
import type { Model } from "$lib/types/Model";
|
| 14 |
import type { LayoutData } from "../../../routes/$types";
|
| 15 |
+
import WebSearchToggle from "../WebSearchToggle.svelte";
|
| 16 |
+
import type { WebSearchMessage } from "$lib/types/WebSearch";
|
| 17 |
import LoginModal from "../LoginModal.svelte";
|
| 18 |
|
| 19 |
export let messages: Message[] = [];
|
|
|
|
| 23 |
export let currentModel: Model;
|
| 24 |
export let models: Model[];
|
| 25 |
export let settings: LayoutData["settings"];
|
| 26 |
+
export let webSearchMessages: WebSearchMessage[] = [];
|
| 27 |
|
| 28 |
export let loginRequired = false;
|
| 29 |
$: isReadOnly = !models.some((model) => model.id === currentModel.id);
|
|
|
|
| 58 |
{messages}
|
| 59 |
readOnly={isReadOnly}
|
| 60 |
isAuthor={!shared}
|
| 61 |
+
{webSearchMessages}
|
| 62 |
on:message
|
| 63 |
on:vote
|
| 64 |
on:retry={(ev) => {
|
|
|
|
| 68 |
<div
|
| 69 |
class="dark:via-gray-80 pointer-events-none absolute inset-x-0 bottom-0 z-0 mx-auto flex w-full max-w-3xl flex-col items-center justify-center bg-gradient-to-t from-white via-white/80 to-white/0 px-3.5 py-4 dark:border-gray-800 dark:from-gray-900 dark:to-gray-900/0 max-md:border-t max-md:bg-white max-md:dark:bg-gray-900 sm:px-5 md:py-8 xl:max-w-4xl [&>*]:pointer-events-auto"
|
| 70 |
>
|
| 71 |
+
<div class="flex w-full pb-3 max-md:justify-between">
|
| 72 |
+
{#if settings?.searchEnabled}
|
| 73 |
+
<WebSearchToggle />
|
| 74 |
+
{/if}
|
| 75 |
+
{#if loading}
|
| 76 |
+
<StopGeneratingBtn
|
| 77 |
+
classNames={settings?.searchEnabled ? "md:-translate-x-1/2 md:mx-auto" : "mx-auto"}
|
| 78 |
+
on:click={() => dispatch("stop")}
|
| 79 |
+
/>
|
| 80 |
+
{/if}
|
| 81 |
</div>
|
| 82 |
<form
|
| 83 |
on:submit|preventDefault={handleSubmit}
|
|
|
|
| 101 |
class="btn mx-1 my-1 inline-block h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400 disabled:opacity-60 enabled:hover:text-gray-700 dark:disabled:opacity-40 enabled:dark:hover:text-gray-100 md:hidden"
|
| 102 |
on:click={() => dispatch("stop")}
|
| 103 |
>
|
| 104 |
+
<CarbonStopFilledAlt />
|
| 105 |
</button>
|
| 106 |
<div
|
| 107 |
class="mx-1 my-1 hidden h-[2.4rem] items-center p-1 px-[0.7rem] text-gray-400 disabled:opacity-60 enabled:hover:text-gray-700 dark:disabled:opacity-40 enabled:dark:hover:text-gray-100 md:flex"
|
|
@@ -2,30 +2,17 @@
|
|
| 2 |
export let classNames = "";
|
| 3 |
</script>
|
| 4 |
|
| 5 |
-
<
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
type="scale"
|
| 20 |
-
begin={`${-0.375 + 0.15 * index}s`}
|
| 21 |
-
calcMode="spline"
|
| 22 |
-
keySplines="0.3 0 0.7 1;0.3 0 0.7 1"
|
| 23 |
-
values="0.5;1;0.5"
|
| 24 |
-
keyTimes="0;0.5;1"
|
| 25 |
-
dur="1s"
|
| 26 |
-
repeatCount="indefinite"
|
| 27 |
-
/>
|
| 28 |
-
</circle>
|
| 29 |
-
</g>
|
| 30 |
-
{/each}
|
| 31 |
-
</svg>
|
|
|
|
| 2 |
export let classNames = "";
|
| 3 |
</script>
|
| 4 |
|
| 5 |
+
<div class={"inline-flex h-8 flex-none items-center gap-1 " + classNames}>
|
| 6 |
+
<div
|
| 7 |
+
class="h-1 w-1 animate-bounce rounded-full bg-gray-500 dark:bg-gray-400"
|
| 8 |
+
style="animation-delay: 0.25s;"
|
| 9 |
+
/>
|
| 10 |
+
<div
|
| 11 |
+
class="h-1 w-1 animate-bounce rounded-full bg-gray-500 dark:bg-gray-400"
|
| 12 |
+
style="animation-delay: 0.5s;"
|
| 13 |
+
/>
|
| 14 |
+
<div
|
| 15 |
+
class="h-1 w-1 animate-bounce rounded-full bg-gray-500 dark:bg-gray-400"
|
| 16 |
+
style="animation-delay: 0.75s;"
|
| 17 |
+
/>
|
| 18 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2,6 +2,7 @@ import { MONGODB_URL, MONGODB_DB_NAME, MONGODB_DIRECT_CONNECTION } from "$env/st
|
|
| 2 |
import { MongoClient } from "mongodb";
|
| 3 |
import type { Conversation } from "$lib/types/Conversation";
|
| 4 |
import type { SharedConversation } from "$lib/types/SharedConversation";
|
|
|
|
| 5 |
import type { AbortedGeneration } from "$lib/types/AbortedGeneration";
|
| 6 |
import type { Settings } from "$lib/types/Settings";
|
| 7 |
import type { User } from "$lib/types/User";
|
|
@@ -25,6 +26,7 @@ const sharedConversations = db.collection<SharedConversation>("sharedConversatio
|
|
| 25 |
const abortedGenerations = db.collection<AbortedGeneration>("abortedGenerations");
|
| 26 |
const settings = db.collection<Settings>("settings");
|
| 27 |
const users = db.collection<User>("users");
|
|
|
|
| 28 |
|
| 29 |
export { client, db };
|
| 30 |
export const collections = {
|
|
@@ -33,6 +35,7 @@ export const collections = {
|
|
| 33 |
abortedGenerations,
|
| 34 |
settings,
|
| 35 |
users,
|
|
|
|
| 36 |
};
|
| 37 |
|
| 38 |
client.on("open", () => {
|
|
@@ -48,6 +51,7 @@ client.on("open", () => {
|
|
| 48 |
{ partialFilterExpression: { userId: { $exists: true } } }
|
| 49 |
)
|
| 50 |
.catch(console.error);
|
|
|
|
| 51 |
abortedGenerations.createIndex({ updatedAt: 1 }, { expireAfterSeconds: 30 }).catch(console.error);
|
| 52 |
abortedGenerations.createIndex({ conversationId: 1 }, { unique: true }).catch(console.error);
|
| 53 |
sharedConversations.createIndex({ hash: 1 }, { unique: true }).catch(console.error);
|
|
|
|
| 2 |
import { MongoClient } from "mongodb";
|
| 3 |
import type { Conversation } from "$lib/types/Conversation";
|
| 4 |
import type { SharedConversation } from "$lib/types/SharedConversation";
|
| 5 |
+
import type { WebSearch } from "$lib/types/WebSearch";
|
| 6 |
import type { AbortedGeneration } from "$lib/types/AbortedGeneration";
|
| 7 |
import type { Settings } from "$lib/types/Settings";
|
| 8 |
import type { User } from "$lib/types/User";
|
|
|
|
| 26 |
const abortedGenerations = db.collection<AbortedGeneration>("abortedGenerations");
|
| 27 |
const settings = db.collection<Settings>("settings");
|
| 28 |
const users = db.collection<User>("users");
|
| 29 |
+
const webSearches = db.collection<WebSearch>("webSearches");
|
| 30 |
|
| 31 |
export { client, db };
|
| 32 |
export const collections = {
|
|
|
|
| 35 |
abortedGenerations,
|
| 36 |
settings,
|
| 37 |
users,
|
| 38 |
+
webSearches,
|
| 39 |
};
|
| 40 |
|
| 41 |
client.on("open", () => {
|
|
|
|
| 51 |
{ partialFilterExpression: { userId: { $exists: true } } }
|
| 52 |
)
|
| 53 |
.catch(console.error);
|
| 54 |
+
webSearches.createIndex({ sessionId: 1, updatedAt: -1 }).catch(console.error);
|
| 55 |
abortedGenerations.createIndex({ updatedAt: 1 }, { expireAfterSeconds: 30 }).catch(console.error);
|
| 56 |
abortedGenerations.createIndex({ conversationId: 1 }, { unique: true }).catch(console.error);
|
| 57 |
sharedConversations.createIndex({ hash: 1 }, { unique: true }).catch(console.error);
|
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { defaultModel } from "$lib/server/models";
|
| 2 |
+
import { modelEndpoint } from "./modelEndpoint";
|
| 3 |
+
import { textGeneration } from "@huggingface/inference";
|
| 4 |
+
import { trimSuffix } from "$lib/utils/trimSuffix";
|
| 5 |
+
import { trimPrefix } from "$lib/utils/trimPrefix";
|
| 6 |
+
import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken";
|
| 7 |
+
|
| 8 |
+
interface Parameters {
|
| 9 |
+
temperature: number;
|
| 10 |
+
truncate: number;
|
| 11 |
+
max_new_tokens: number;
|
| 12 |
+
stop: string[];
|
| 13 |
+
}
|
| 14 |
+
export async function generateFromDefaultEndpoint(
|
| 15 |
+
prompt: string,
|
| 16 |
+
parameters?: Partial<Parameters>
|
| 17 |
+
) {
|
| 18 |
+
const newParameters = {
|
| 19 |
+
...defaultModel.parameters,
|
| 20 |
+
...parameters,
|
| 21 |
+
return_full_text: false,
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
const endpoint = modelEndpoint(defaultModel);
|
| 25 |
+
let { generated_text } = await textGeneration(
|
| 26 |
+
{
|
| 27 |
+
model: endpoint.url,
|
| 28 |
+
inputs: prompt,
|
| 29 |
+
parameters: newParameters,
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
fetch: (url, options) =>
|
| 33 |
+
fetch(url, {
|
| 34 |
+
...options,
|
| 35 |
+
headers: { ...options?.headers, Authorization: endpoint.authorization },
|
| 36 |
+
}),
|
| 37 |
+
}
|
| 38 |
+
);
|
| 39 |
+
|
| 40 |
+
generated_text = trimSuffix(trimPrefix(generated_text, "<|startoftext|>"), PUBLIC_SEP_TOKEN);
|
| 41 |
+
|
| 42 |
+
return generated_text;
|
| 43 |
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { SERPAPI_KEY } from "$env/static/private";
|
| 2 |
+
|
| 3 |
+
import { getJson } from "serpapi";
|
| 4 |
+
import type { GoogleParameters } from "serpapi";
|
| 5 |
+
|
| 6 |
+
// Show result as JSON
|
| 7 |
+
export async function searchWeb(query: string) {
|
| 8 |
+
const params = {
|
| 9 |
+
q: query,
|
| 10 |
+
hl: "en",
|
| 11 |
+
gl: "us",
|
| 12 |
+
google_domain: "google.com",
|
| 13 |
+
api_key: SERPAPI_KEY,
|
| 14 |
+
} satisfies GoogleParameters;
|
| 15 |
+
|
| 16 |
+
// Show result as JSON
|
| 17 |
+
const response = await getJson("google", params);
|
| 18 |
+
|
| 19 |
+
return response;
|
| 20 |
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { writable } from "svelte/store";
|
| 2 |
+
export interface WebSearchParameters {
|
| 3 |
+
useSearch: boolean;
|
| 4 |
+
nItems: number;
|
| 5 |
+
}
|
| 6 |
+
export const webSearchParameters = writable<WebSearchParameters>({
|
| 7 |
+
useSearch: false,
|
| 8 |
+
nItems: 5,
|
| 9 |
+
});
|
|
@@ -2,5 +2,6 @@ export interface Message {
|
|
| 2 |
from: "user" | "assistant";
|
| 3 |
id: ReturnType<typeof crypto.randomUUID>;
|
| 4 |
content: string;
|
|
|
|
| 5 |
score?: -1 | 0 | 1;
|
| 6 |
}
|
|
|
|
| 2 |
from: "user" | "assistant";
|
| 3 |
id: ReturnType<typeof crypto.randomUUID>;
|
| 4 |
content: string;
|
| 5 |
+
webSearchId?: string;
|
| 6 |
score?: -1 | 0 | 1;
|
| 7 |
}
|
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import type { ObjectId } from "mongodb";
|
| 2 |
+
import type { Conversation } from "./Conversation";
|
| 3 |
+
import type { Timestamps } from "./Timestamps";
|
| 4 |
+
|
| 5 |
+
export interface WebSearch extends Timestamps {
|
| 6 |
+
_id: ObjectId;
|
| 7 |
+
|
| 8 |
+
convId: Conversation["_id"];
|
| 9 |
+
|
| 10 |
+
prompt: string;
|
| 11 |
+
|
| 12 |
+
searchQuery: string;
|
| 13 |
+
results: string[];
|
| 14 |
+
knowledgeGraph: string;
|
| 15 |
+
summary: string;
|
| 16 |
+
|
| 17 |
+
messages: WebSearchMessage[];
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
export type WebSearchMessageUpdate = {
|
| 21 |
+
type: "update";
|
| 22 |
+
message: string;
|
| 23 |
+
args?: string[];
|
| 24 |
+
};
|
| 25 |
+
|
| 26 |
+
export type WebSearchMessageError = {
|
| 27 |
+
type: "error";
|
| 28 |
+
message: string;
|
| 29 |
+
args?: string[];
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
export type WebSearchMessageResult = {
|
| 33 |
+
type: "result";
|
| 34 |
+
id: string;
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
export type WebSearchMessage =
|
| 38 |
+
| WebSearchMessageUpdate
|
| 39 |
+
| WebSearchMessageResult
|
| 40 |
+
| WebSearchMessageError;
|
|
@@ -6,6 +6,7 @@ import { UrlDependency } from "$lib/types/UrlDependency";
|
|
| 6 |
import { defaultModel, models, oldModels, validateModel } from "$lib/server/models";
|
| 7 |
import { authCondition, requiresUser } from "$lib/server/auth";
|
| 8 |
import { DEFAULT_SETTINGS } from "$lib/types/Settings";
|
|
|
|
| 9 |
|
| 10 |
export const load: LayoutServerLoad = async ({ locals, depends, url }) => {
|
| 11 |
const { conversations } = collections;
|
|
@@ -60,6 +61,7 @@ export const load: LayoutServerLoad = async ({ locals, depends, url }) => {
|
|
| 60 |
DEFAULT_SETTINGS.shareConversationsWithModelAuthors,
|
| 61 |
ethicsModalAcceptedAt: settings?.ethicsModalAcceptedAt ?? null,
|
| 62 |
activeModel: settings?.activeModel ?? DEFAULT_SETTINGS.activeModel,
|
|
|
|
| 63 |
},
|
| 64 |
models: models.map((model) => ({
|
| 65 |
id: model.id,
|
|
|
|
| 6 |
import { defaultModel, models, oldModels, validateModel } from "$lib/server/models";
|
| 7 |
import { authCondition, requiresUser } from "$lib/server/auth";
|
| 8 |
import { DEFAULT_SETTINGS } from "$lib/types/Settings";
|
| 9 |
+
import { SERPAPI_KEY } from "$env/static/private";
|
| 10 |
|
| 11 |
export const load: LayoutServerLoad = async ({ locals, depends, url }) => {
|
| 12 |
const { conversations } = collections;
|
|
|
|
| 61 |
DEFAULT_SETTINGS.shareConversationsWithModelAuthors,
|
| 62 |
ethicsModalAcceptedAt: settings?.ethicsModalAcceptedAt ?? null,
|
| 63 |
activeModel: settings?.activeModel ?? DEFAULT_SETTINGS.activeModel,
|
| 64 |
+
searchEnabled: !!SERPAPI_KEY,
|
| 65 |
},
|
| 66 |
models: models.map((model) => ({
|
| 67 |
id: model.id,
|
|
@@ -12,6 +12,8 @@
|
|
| 12 |
import { ERROR_MESSAGES, error } from "$lib/stores/errors";
|
| 13 |
import { randomUUID } from "$lib/utils/randomUuid";
|
| 14 |
import { findCurrentModel } from "$lib/utils/models";
|
|
|
|
|
|
|
| 15 |
import type { Message } from "$lib/types/Message";
|
| 16 |
|
| 17 |
export let data;
|
|
@@ -20,6 +22,8 @@
|
|
| 20 |
let lastLoadedMessages = data.messages;
|
| 21 |
let isAborted = false;
|
| 22 |
|
|
|
|
|
|
|
| 23 |
// Since we modify the messages array locally, we don't want to reset it if an old version is passed
|
| 24 |
$: if (data.messages !== lastLoadedMessages) {
|
| 25 |
messages = data.messages;
|
|
@@ -29,8 +33,13 @@
|
|
| 29 |
let loading = false;
|
| 30 |
let pending = false;
|
| 31 |
|
| 32 |
-
async function getTextGenerationStream(
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
const responseId = randomUUID();
|
| 35 |
|
| 36 |
const response = textGenerationStream(
|
|
@@ -47,6 +56,7 @@
|
|
| 47 |
response_id: responseId,
|
| 48 |
is_retry: isRetry,
|
| 49 |
use_cache: false,
|
|
|
|
| 50 |
} as Options
|
| 51 |
);
|
| 52 |
|
|
@@ -78,6 +88,7 @@
|
|
| 78 |
|
| 79 |
if (lastMessage) {
|
| 80 |
lastMessage.content = output.generated_text;
|
|
|
|
| 81 |
messages = [...messages];
|
| 82 |
}
|
| 83 |
break;
|
|
@@ -126,7 +137,63 @@
|
|
| 126 |
{ from: "user", content: message, id: messageId },
|
| 127 |
];
|
| 128 |
|
| 129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
|
| 131 |
if (messages.filter((m) => m.from === "user").length === 1) {
|
| 132 |
summarizeTitle($page.params.id)
|
|
@@ -186,7 +253,7 @@
|
|
| 186 |
writeMessage(val, messageId);
|
| 187 |
}
|
| 188 |
});
|
| 189 |
-
|
| 190 |
$: title = data.conversations.find((conv) => conv.id === $page.params.id)?.title ?? data.title;
|
| 191 |
</script>
|
| 192 |
|
|
@@ -198,6 +265,7 @@
|
|
| 198 |
{loading}
|
| 199 |
{pending}
|
| 200 |
{messages}
|
|
|
|
| 201 |
on:message={(event) => writeMessage(event.detail)}
|
| 202 |
on:retry={(event) => writeMessage(event.detail.content, event.detail.id)}
|
| 203 |
on:vote={(event) => voteMessage(event.detail.score, event.detail.id)}
|
|
|
|
| 12 |
import { ERROR_MESSAGES, error } from "$lib/stores/errors";
|
| 13 |
import { randomUUID } from "$lib/utils/randomUuid";
|
| 14 |
import { findCurrentModel } from "$lib/utils/models";
|
| 15 |
+
import { webSearchParameters } from "$lib/stores/webSearchParameters";
|
| 16 |
+
import type { WebSearchMessage } from "$lib/types/WebSearch.js";
|
| 17 |
import type { Message } from "$lib/types/Message";
|
| 18 |
|
| 19 |
export let data;
|
|
|
|
| 22 |
let lastLoadedMessages = data.messages;
|
| 23 |
let isAborted = false;
|
| 24 |
|
| 25 |
+
let webSearchMessages: WebSearchMessage[] = [];
|
| 26 |
+
|
| 27 |
// Since we modify the messages array locally, we don't want to reset it if an old version is passed
|
| 28 |
$: if (data.messages !== lastLoadedMessages) {
|
| 29 |
messages = data.messages;
|
|
|
|
| 33 |
let loading = false;
|
| 34 |
let pending = false;
|
| 35 |
|
| 36 |
+
async function getTextGenerationStream(
|
| 37 |
+
inputs: string,
|
| 38 |
+
messageId: string,
|
| 39 |
+
isRetry = false,
|
| 40 |
+
webSearchId?: string
|
| 41 |
+
) {
|
| 42 |
+
let conversationId = $page.params.id;
|
| 43 |
const responseId = randomUUID();
|
| 44 |
|
| 45 |
const response = textGenerationStream(
|
|
|
|
| 56 |
response_id: responseId,
|
| 57 |
is_retry: isRetry,
|
| 58 |
use_cache: false,
|
| 59 |
+
web_search_id: webSearchId,
|
| 60 |
} as Options
|
| 61 |
);
|
| 62 |
|
|
|
|
| 88 |
|
| 89 |
if (lastMessage) {
|
| 90 |
lastMessage.content = output.generated_text;
|
| 91 |
+
lastMessage.webSearchId = webSearchId;
|
| 92 |
messages = [...messages];
|
| 93 |
}
|
| 94 |
break;
|
|
|
|
| 137 |
{ from: "user", content: message, id: messageId },
|
| 138 |
];
|
| 139 |
|
| 140 |
+
let searchResponseId: string | null = "";
|
| 141 |
+
if ($webSearchParameters.useSearch) {
|
| 142 |
+
webSearchMessages = [];
|
| 143 |
+
|
| 144 |
+
const res = await fetch(
|
| 145 |
+
`${base}/conversation/${$page.params.id}/web-search?` +
|
| 146 |
+
new URLSearchParams({ prompt: message }),
|
| 147 |
+
{
|
| 148 |
+
method: "GET",
|
| 149 |
+
}
|
| 150 |
+
);
|
| 151 |
+
|
| 152 |
+
// required bc linting doesn't see TextDecoderStream for some reason?
|
| 153 |
+
// eslint-disable-next-line no-undef
|
| 154 |
+
const encoder = new TextDecoderStream();
|
| 155 |
+
const reader = res?.body?.pipeThrough(encoder).getReader();
|
| 156 |
+
|
| 157 |
+
while (searchResponseId === "") {
|
| 158 |
+
await new Promise((r) => setTimeout(r, 25));
|
| 159 |
+
|
| 160 |
+
if (isAborted) {
|
| 161 |
+
reader?.cancel();
|
| 162 |
+
return;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
reader
|
| 166 |
+
?.read()
|
| 167 |
+
.then(async ({ done, value }) => {
|
| 168 |
+
if (done) {
|
| 169 |
+
reader.cancel();
|
| 170 |
+
return;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
try {
|
| 174 |
+
webSearchMessages = (JSON.parse(value) as { messages: WebSearchMessage[] })
|
| 175 |
+
.messages;
|
| 176 |
+
} catch (parseError) {
|
| 177 |
+
// in case of parsing error we wait for the next message
|
| 178 |
+
return;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
const lastSearchMessage = webSearchMessages[webSearchMessages.length - 1];
|
| 182 |
+
if (lastSearchMessage.type === "result") {
|
| 183 |
+
searchResponseId = lastSearchMessage.id;
|
| 184 |
+
reader.cancel();
|
| 185 |
+
return;
|
| 186 |
+
}
|
| 187 |
+
})
|
| 188 |
+
.catch(() => {
|
| 189 |
+
searchResponseId = null;
|
| 190 |
+
});
|
| 191 |
+
}
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
await getTextGenerationStream(message, messageId, isRetry, searchResponseId ?? undefined);
|
| 195 |
+
|
| 196 |
+
webSearchMessages = [];
|
| 197 |
|
| 198 |
if (messages.filter((m) => m.from === "user").length === 1) {
|
| 199 |
summarizeTitle($page.params.id)
|
|
|
|
| 253 |
writeMessage(val, messageId);
|
| 254 |
}
|
| 255 |
});
|
| 256 |
+
$: $page.params.id, (isAborted = true);
|
| 257 |
$: title = data.conversations.find((conv) => conv.id === $page.params.id)?.title ?? data.title;
|
| 258 |
</script>
|
| 259 |
|
|
|
|
| 265 |
{loading}
|
| 266 |
{pending}
|
| 267 |
{messages}
|
| 268 |
+
bind:webSearchMessages
|
| 269 |
on:message={(event) => writeMessage(event.detail)}
|
| 270 |
on:retry={(event) => writeMessage(event.detail.content, event.detail.id)}
|
| 271 |
on:vote={(event) => voteMessage(event.detail.score, event.detail.id)}
|
|
@@ -38,7 +38,7 @@ export async function POST({ request, fetch, locals, params }) {
|
|
| 38 |
const json = await request.json();
|
| 39 |
const {
|
| 40 |
inputs: newPrompt,
|
| 41 |
-
options: { id: messageId, is_retry, response_id: responseId },
|
| 42 |
} = z
|
| 43 |
.object({
|
| 44 |
inputs: z.string().trim().min(1),
|
|
@@ -46,6 +46,7 @@ export async function POST({ request, fetch, locals, params }) {
|
|
| 46 |
id: z.optional(z.string().uuid()),
|
| 47 |
response_id: z.optional(z.string().uuid()),
|
| 48 |
is_retry: z.optional(z.boolean()),
|
|
|
|
| 49 |
}),
|
| 50 |
})
|
| 51 |
.parse(json);
|
|
@@ -67,8 +68,7 @@ export async function POST({ request, fetch, locals, params }) {
|
|
| 67 |
];
|
| 68 |
})() satisfies Message[];
|
| 69 |
|
| 70 |
-
const prompt = buildPrompt(messages, model);
|
| 71 |
-
|
| 72 |
const randomEndpoint = modelEndpoint(model);
|
| 73 |
|
| 74 |
const abortController = new AbortController();
|
|
@@ -114,6 +114,7 @@ export async function POST({ request, fetch, locals, params }) {
|
|
| 114 |
messages.push({
|
| 115 |
from: "assistant",
|
| 116 |
content: generated_text,
|
|
|
|
| 117 |
id: (responseId as Message["id"]) || crypto.randomUUID(),
|
| 118 |
});
|
| 119 |
|
|
@@ -131,7 +132,6 @@ export async function POST({ request, fetch, locals, params }) {
|
|
| 131 |
}
|
| 132 |
|
| 133 |
saveMessage().catch(console.error);
|
| 134 |
-
|
| 135 |
// Todo: maybe we should wait for the message to be saved before ending the response - in case of errors
|
| 136 |
return new Response(stream1, {
|
| 137 |
headers: Object.fromEntries(resp.headers.entries()),
|
|
|
|
| 38 |
const json = await request.json();
|
| 39 |
const {
|
| 40 |
inputs: newPrompt,
|
| 41 |
+
options: { id: messageId, is_retry, web_search_id, response_id: responseId },
|
| 42 |
} = z
|
| 43 |
.object({
|
| 44 |
inputs: z.string().trim().min(1),
|
|
|
|
| 46 |
id: z.optional(z.string().uuid()),
|
| 47 |
response_id: z.optional(z.string().uuid()),
|
| 48 |
is_retry: z.optional(z.boolean()),
|
| 49 |
+
web_search_id: z.ostring(),
|
| 50 |
}),
|
| 51 |
})
|
| 52 |
.parse(json);
|
|
|
|
| 68 |
];
|
| 69 |
})() satisfies Message[];
|
| 70 |
|
| 71 |
+
const prompt = await buildPrompt(messages, model, web_search_id);
|
|
|
|
| 72 |
const randomEndpoint = modelEndpoint(model);
|
| 73 |
|
| 74 |
const abortController = new AbortController();
|
|
|
|
| 114 |
messages.push({
|
| 115 |
from: "assistant",
|
| 116 |
content: generated_text,
|
| 117 |
+
webSearchId: web_search_id,
|
| 118 |
id: (responseId as Message["id"]) || crypto.randomUUID(),
|
| 119 |
});
|
| 120 |
|
|
|
|
| 132 |
}
|
| 133 |
|
| 134 |
saveMessage().catch(console.error);
|
|
|
|
| 135 |
// Todo: maybe we should wait for the message to be saved before ending the response - in case of errors
|
| 136 |
return new Response(stream1, {
|
| 137 |
headers: Object.fromEntries(resp.headers.entries()),
|
|
@@ -31,7 +31,7 @@ export async function GET({ params, locals }) {
|
|
| 31 |
throw error(404, "Conversation model not found");
|
| 32 |
}
|
| 33 |
|
| 34 |
-
const prompt = buildPrompt(conv.messages.slice(0, messageIndex + 1), model);
|
| 35 |
|
| 36 |
return new Response(
|
| 37 |
JSON.stringify(
|
|
|
|
| 31 |
throw error(404, "Conversation model not found");
|
| 32 |
}
|
| 33 |
|
| 34 |
+
const prompt = await buildPrompt(conv.messages.slice(0, messageIndex + 1), model);
|
| 35 |
|
| 36 |
return new Response(
|
| 37 |
JSON.stringify(
|
|
@@ -1,16 +1,12 @@
|
|
| 1 |
import { buildPrompt } from "$lib/buildPrompt";
|
| 2 |
-
import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken";
|
| 3 |
import { authCondition } from "$lib/server/auth";
|
| 4 |
import { collections } from "$lib/server/database";
|
| 5 |
-
import {
|
| 6 |
import { defaultModel } from "$lib/server/models";
|
| 7 |
-
import { trimPrefix } from "$lib/utils/trimPrefix";
|
| 8 |
-
import { trimSuffix } from "$lib/utils/trimSuffix";
|
| 9 |
-
import { textGeneration } from "@huggingface/inference";
|
| 10 |
import { error } from "@sveltejs/kit";
|
| 11 |
import { ObjectId } from "mongodb";
|
| 12 |
|
| 13 |
-
export async function POST({ params, locals
|
| 14 |
const convId = new ObjectId(params.id);
|
| 15 |
|
| 16 |
const conversation = await collections.conversations.findOne({
|
|
@@ -28,30 +24,8 @@ export async function POST({ params, locals, fetch }) {
|
|
| 28 |
`Please summarize the following message as a single sentence of less than 5 words:\n` +
|
| 29 |
firstMessage?.content;
|
| 30 |
|
| 31 |
-
const prompt = buildPrompt([{ from: "user", content: userPrompt }], defaultModel);
|
| 32 |
-
|
| 33 |
-
const parameters = {
|
| 34 |
-
...defaultModel.parameters,
|
| 35 |
-
return_full_text: false,
|
| 36 |
-
};
|
| 37 |
-
|
| 38 |
-
const endpoint = modelEndpoint(defaultModel);
|
| 39 |
-
let { generated_text } = await textGeneration(
|
| 40 |
-
{
|
| 41 |
-
model: endpoint.url,
|
| 42 |
-
inputs: prompt,
|
| 43 |
-
parameters,
|
| 44 |
-
},
|
| 45 |
-
{
|
| 46 |
-
fetch: (url, options) =>
|
| 47 |
-
fetch(url, {
|
| 48 |
-
...options,
|
| 49 |
-
headers: { ...options?.headers, Authorization: endpoint.authorization },
|
| 50 |
-
}),
|
| 51 |
-
}
|
| 52 |
-
);
|
| 53 |
-
|
| 54 |
-
generated_text = trimSuffix(trimPrefix(generated_text, "<|startoftext|>"), PUBLIC_SEP_TOKEN);
|
| 55 |
|
| 56 |
if (generated_text) {
|
| 57 |
await collections.conversations.updateOne(
|
|
|
|
| 1 |
import { buildPrompt } from "$lib/buildPrompt";
|
|
|
|
| 2 |
import { authCondition } from "$lib/server/auth";
|
| 3 |
import { collections } from "$lib/server/database";
|
| 4 |
+
import { generateFromDefaultEndpoint } from "$lib/server/generateFromDefaultEndpoint.js";
|
| 5 |
import { defaultModel } from "$lib/server/models";
|
|
|
|
|
|
|
|
|
|
| 6 |
import { error } from "@sveltejs/kit";
|
| 7 |
import { ObjectId } from "mongodb";
|
| 8 |
|
| 9 |
+
export async function POST({ params, locals }) {
|
| 10 |
const convId = new ObjectId(params.id);
|
| 11 |
|
| 12 |
const conversation = await collections.conversations.findOne({
|
|
|
|
| 24 |
`Please summarize the following message as a single sentence of less than 5 words:\n` +
|
| 25 |
firstMessage?.content;
|
| 26 |
|
| 27 |
+
const prompt = await buildPrompt([{ from: "user", content: userPrompt }], defaultModel);
|
| 28 |
+
const generated_text = await generateFromDefaultEndpoint(prompt);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
if (generated_text) {
|
| 31 |
await collections.conversations.updateOne(
|
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { authCondition } from "$lib/server/auth";
|
| 2 |
+
import { collections } from "$lib/server/database";
|
| 3 |
+
import { generateFromDefaultEndpoint } from "$lib/server/generateFromDefaultEndpoint.js";
|
| 4 |
+
import { defaultModel } from "$lib/server/models";
|
| 5 |
+
import { searchWeb } from "$lib/server/searchWeb.js";
|
| 6 |
+
import type { Message } from "$lib/types/Message.js";
|
| 7 |
+
import { error } from "@sveltejs/kit";
|
| 8 |
+
import { ObjectId } from "mongodb";
|
| 9 |
+
import { z } from "zod";
|
| 10 |
+
import { JSDOM, VirtualConsole } from "jsdom";
|
| 11 |
+
import type { WebSearch } from "$lib/types/WebSearch.js";
|
| 12 |
+
|
| 13 |
+
function removeTags(node: Node) {
|
| 14 |
+
if (node.hasChildNodes()) {
|
| 15 |
+
node.childNodes.forEach((childNode) => {
|
| 16 |
+
if (node.nodeName === "SCRIPT" || node.nodeName === "STYLE") {
|
| 17 |
+
node.removeChild(childNode);
|
| 18 |
+
} else {
|
| 19 |
+
removeTags(childNode);
|
| 20 |
+
}
|
| 21 |
+
});
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
function naiveInnerText(node: Node): string {
|
| 25 |
+
const Node = node; // We need Node(DOM's Node) for the constants, but Node doesn't exist in the nodejs global space, and any Node instance references the constants through the prototype chain
|
| 26 |
+
return [...node.childNodes]
|
| 27 |
+
.map((childNode) => {
|
| 28 |
+
switch (childNode.nodeType) {
|
| 29 |
+
case Node.TEXT_NODE:
|
| 30 |
+
return node.textContent;
|
| 31 |
+
case Node.ELEMENT_NODE:
|
| 32 |
+
return naiveInnerText(childNode);
|
| 33 |
+
default:
|
| 34 |
+
return "";
|
| 35 |
+
}
|
| 36 |
+
})
|
| 37 |
+
.join("\n");
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
interface GenericObject {
|
| 41 |
+
[key: string]: GenericObject | unknown;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
function removeLinks(obj: GenericObject) {
|
| 45 |
+
for (const prop in obj) {
|
| 46 |
+
if (prop.endsWith("link")) delete obj[prop];
|
| 47 |
+
else if (typeof obj[prop] === "object") removeLinks(obj[prop] as GenericObject);
|
| 48 |
+
}
|
| 49 |
+
return obj;
|
| 50 |
+
}
|
| 51 |
+
export async function GET({ params, locals, url }) {
|
| 52 |
+
const model = defaultModel;
|
| 53 |
+
const convId = new ObjectId(params.id);
|
| 54 |
+
const searchId = new ObjectId();
|
| 55 |
+
|
| 56 |
+
const conv = await collections.conversations.findOne({
|
| 57 |
+
_id: convId,
|
| 58 |
+
...authCondition(locals),
|
| 59 |
+
});
|
| 60 |
+
|
| 61 |
+
if (!conv) {
|
| 62 |
+
throw error(404, "Conversation not found");
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
const prompt = z.string().trim().min(1).parse(url.searchParams.get("prompt"));
|
| 66 |
+
|
| 67 |
+
const messages = (() => {
|
| 68 |
+
return [...conv.messages, { content: prompt, from: "user", id: crypto.randomUUID() }];
|
| 69 |
+
})() satisfies Message[];
|
| 70 |
+
|
| 71 |
+
const stream = new ReadableStream({
|
| 72 |
+
async start(controller) {
|
| 73 |
+
const webSearch: WebSearch = {
|
| 74 |
+
_id: searchId,
|
| 75 |
+
convId: convId,
|
| 76 |
+
prompt: prompt,
|
| 77 |
+
searchQuery: "",
|
| 78 |
+
knowledgeGraph: "",
|
| 79 |
+
results: [],
|
| 80 |
+
summary: "",
|
| 81 |
+
messages: [],
|
| 82 |
+
createdAt: new Date(),
|
| 83 |
+
updatedAt: new Date(),
|
| 84 |
+
};
|
| 85 |
+
try {
|
| 86 |
+
webSearch.messages.push({
|
| 87 |
+
type: "update",
|
| 88 |
+
message: "Generating search query",
|
| 89 |
+
});
|
| 90 |
+
controller.enqueue(JSON.stringify({ messages: webSearch.messages }));
|
| 91 |
+
|
| 92 |
+
const promptSearchQuery =
|
| 93 |
+
model.userMessageToken +
|
| 94 |
+
"The following messages were written by a user, trying to answer a question." +
|
| 95 |
+
model.messageEndToken +
|
| 96 |
+
messages
|
| 97 |
+
.filter((message) => message.from === "user")
|
| 98 |
+
.map((message) => model.userMessageToken + message.content + model.messageEndToken) +
|
| 99 |
+
model.userMessageToken +
|
| 100 |
+
"What plain-text english sentence would you input into Google to answer the last question? Answer with a short (10 words max) simple sentence." +
|
| 101 |
+
model.messageEndToken +
|
| 102 |
+
model.assistantMessageToken +
|
| 103 |
+
"Query: ";
|
| 104 |
+
|
| 105 |
+
webSearch.searchQuery = await generateFromDefaultEndpoint(promptSearchQuery).then(
|
| 106 |
+
(query) => {
|
| 107 |
+
const arr = query.split(/\r?\n/);
|
| 108 |
+
return arr[0].length > 0 ? arr[0] : arr[1];
|
| 109 |
+
}
|
| 110 |
+
);
|
| 111 |
+
// the model has a tendency to continue answering even when we tell it not to, so the split makes
|
| 112 |
+
// sure we only get the first line of the response
|
| 113 |
+
|
| 114 |
+
webSearch.messages.push({
|
| 115 |
+
type: "update",
|
| 116 |
+
message: "Searching Google",
|
| 117 |
+
args: [webSearch.searchQuery],
|
| 118 |
+
});
|
| 119 |
+
controller.enqueue(JSON.stringify({ messages: webSearch.messages }));
|
| 120 |
+
|
| 121 |
+
const results = await searchWeb(webSearch.searchQuery);
|
| 122 |
+
let text = "";
|
| 123 |
+
|
| 124 |
+
webSearch.results =
|
| 125 |
+
(results.organic_results &&
|
| 126 |
+
results.organic_results.map((el: { link: string }) => el.link)) ??
|
| 127 |
+
[];
|
| 128 |
+
|
| 129 |
+
if (results.knowledge_graph) {
|
| 130 |
+
// if google returns a knowledge graph, we use it
|
| 131 |
+
webSearch.knowledgeGraph = JSON.stringify(removeLinks(results.knowledge_graph));
|
| 132 |
+
|
| 133 |
+
text = webSearch.knowledgeGraph;
|
| 134 |
+
|
| 135 |
+
webSearch.messages.push({
|
| 136 |
+
type: "update",
|
| 137 |
+
message: "Found a Google knowledge page",
|
| 138 |
+
});
|
| 139 |
+
controller.enqueue(JSON.stringify({ messages: webSearch.messages }));
|
| 140 |
+
} else if (webSearch.results.length > 0) {
|
| 141 |
+
// otherwise we use the top result from search
|
| 142 |
+
const topUrl = webSearch.results[0];
|
| 143 |
+
|
| 144 |
+
webSearch.messages.push({
|
| 145 |
+
type: "update",
|
| 146 |
+
message: "Browsing first result",
|
| 147 |
+
args: [JSON.stringify(topUrl)],
|
| 148 |
+
});
|
| 149 |
+
controller.enqueue(JSON.stringify({ messages: webSearch.messages }));
|
| 150 |
+
|
| 151 |
+
// fetch the webpage
|
| 152 |
+
//10 second timeout:
|
| 153 |
+
const abortController = new AbortController();
|
| 154 |
+
setTimeout(() => abortController.abort(), 10000);
|
| 155 |
+
const htmlString = await fetch(topUrl, { signal: abortController.signal })
|
| 156 |
+
.then((response) => response.text())
|
| 157 |
+
.catch((err) => console.log(err));
|
| 158 |
+
|
| 159 |
+
const virtualConsole = new VirtualConsole();
|
| 160 |
+
virtualConsole.on("error", () => {
|
| 161 |
+
// No-op to skip console errors.
|
| 162 |
+
});
|
| 163 |
+
|
| 164 |
+
// put the html string into a DOM
|
| 165 |
+
const dom = new JSDOM(htmlString ?? "", {
|
| 166 |
+
virtualConsole,
|
| 167 |
+
});
|
| 168 |
+
|
| 169 |
+
const body = dom.window.document.querySelector("body");
|
| 170 |
+
if (!body) throw new Error("body of the webpage is null");
|
| 171 |
+
|
| 172 |
+
removeTags(body);
|
| 173 |
+
|
| 174 |
+
// recursively extract text content from the body and then remove newlines and multiple spaces
|
| 175 |
+
text = (naiveInnerText(body) ?? "").replace(/ {2}|\r\n|\n|\r/gm, "");
|
| 176 |
+
|
| 177 |
+
if (!text) throw new Error("text of the webpage is null");
|
| 178 |
+
} else {
|
| 179 |
+
throw new Error("No results found for this search query");
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
webSearch.messages.push({
|
| 183 |
+
type: "update",
|
| 184 |
+
message: "Creating summary",
|
| 185 |
+
});
|
| 186 |
+
controller.enqueue(JSON.stringify({ messages: webSearch.messages }));
|
| 187 |
+
|
| 188 |
+
const summaryPrompt =
|
| 189 |
+
model.userMessageToken +
|
| 190 |
+
text
|
| 191 |
+
.split(" ")
|
| 192 |
+
.slice(0, model.parameters?.truncate ?? 0)
|
| 193 |
+
.join(" ") +
|
| 194 |
+
model.messageEndToken +
|
| 195 |
+
model.userMessageToken +
|
| 196 |
+
`The text above should be summarized to best answer the query: ${webSearch.searchQuery}.` +
|
| 197 |
+
model.messageEndToken +
|
| 198 |
+
model.assistantMessageToken +
|
| 199 |
+
"Summary: ";
|
| 200 |
+
|
| 201 |
+
webSearch.summary = await generateFromDefaultEndpoint(summaryPrompt).then((txt: string) =>
|
| 202 |
+
txt.trim()
|
| 203 |
+
);
|
| 204 |
+
|
| 205 |
+
webSearch.messages.push({
|
| 206 |
+
type: "update",
|
| 207 |
+
message: "Injecting summary",
|
| 208 |
+
args: [JSON.stringify(webSearch.summary)],
|
| 209 |
+
});
|
| 210 |
+
controller.enqueue(JSON.stringify({ messages: webSearch.messages }));
|
| 211 |
+
} catch (searchError) {
|
| 212 |
+
if (searchError instanceof Error) {
|
| 213 |
+
webSearch.messages.push({
|
| 214 |
+
type: "error",
|
| 215 |
+
message: "An error occurred with the web search",
|
| 216 |
+
args: [JSON.stringify(searchError.message)],
|
| 217 |
+
});
|
| 218 |
+
}
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
const res = await collections.webSearches.insertOne(webSearch);
|
| 222 |
+
|
| 223 |
+
webSearch.messages.push({
|
| 224 |
+
type: "result",
|
| 225 |
+
id: res.insertedId.toString(),
|
| 226 |
+
});
|
| 227 |
+
controller.enqueue(JSON.stringify({ messages: webSearch.messages }));
|
| 228 |
+
},
|
| 229 |
+
});
|
| 230 |
+
|
| 231 |
+
return new Response(stream, { headers: { "Content-Type": "application/json" } });
|
| 232 |
+
}
|
|
@@ -26,7 +26,7 @@ export async function GET({ params }) {
|
|
| 26 |
throw error(404, "Conversation model not found");
|
| 27 |
}
|
| 28 |
|
| 29 |
-
const prompt = buildPrompt(conv.messages.slice(0, messageIndex + 1), model);
|
| 30 |
|
| 31 |
return new Response(
|
| 32 |
JSON.stringify(
|
|
|
|
| 26 |
throw error(404, "Conversation model not found");
|
| 27 |
}
|
| 28 |
|
| 29 |
+
const prompt = await buildPrompt(conv.messages.slice(0, messageIndex + 1), model);
|
| 30 |
|
| 31 |
return new Response(
|
| 32 |
JSON.stringify(
|
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { collections } from "$lib/server/database";
|
| 2 |
+
import { sha256 } from "$lib/utils/sha256.js";
|
| 3 |
+
import { error } from "@sveltejs/kit";
|
| 4 |
+
import { ObjectId } from "mongodb";
|
| 5 |
+
|
| 6 |
+
export async function GET({ params, locals }) {
|
| 7 |
+
const searchId = new ObjectId(params.id);
|
| 8 |
+
|
| 9 |
+
const search = await collections.webSearches.findOne({
|
| 10 |
+
_id: searchId,
|
| 11 |
+
});
|
| 12 |
+
|
| 13 |
+
if (!search) {
|
| 14 |
+
throw error(404, "Search query not found");
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
const conv = await collections.conversations.findOne({
|
| 18 |
+
_id: search.convId,
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
if (!conv) {
|
| 22 |
+
throw error(404, "Conversation not found");
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
// there's no better way to see if a conversation has been shared, so we hash the messages and see if there's a shared conversation with the same hash
|
| 26 |
+
const hash = await sha256(JSON.stringify(conv.messages));
|
| 27 |
+
const sharedConv = await collections.sharedConversations.findOne({
|
| 28 |
+
hash: hash,
|
| 29 |
+
});
|
| 30 |
+
|
| 31 |
+
const userShouldSeeConv =
|
| 32 |
+
(conv.userId && locals.user?._id.toString() === conv.userId.toString()) || sharedConv !== null;
|
| 33 |
+
|
| 34 |
+
if (!userShouldSeeConv) {
|
| 35 |
+
throw error(403, "You don't have access to the conversation here.");
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
return new Response(JSON.stringify(search), { headers: { "Content-Type": "application/json" } });
|
| 39 |
+
}
|