Spaces:
Running
Running
Major bump to sveltekit & node-adapter versions (#1395)
Browse files* version bump
* sveltekit2 bump
* formatting
* fix imports
* fix deps
* minor bump on chat-ui itself
* better error logging
* bump svelte-check version
- package-lock.json +0 -0
- package.json +11 -9
- src/hooks.server.ts +3 -1
- src/lib/components/ExpandNavigation.svelte +1 -1
- src/lib/components/MobileNav.svelte +1 -1
- src/lib/components/NavConversationItem.svelte +1 -1
- src/lib/components/NavMenu.svelte +3 -3
- src/lib/components/Pagination.svelte +1 -1
- src/lib/components/chat/AssistantIntroduction.svelte +3 -3
- src/lib/components/chat/ChatIntroduction.svelte +1 -1
- src/lib/components/chat/ChatMessage.svelte +10 -10
- src/lib/components/chat/ChatWindow.svelte +4 -4
- src/lib/server/auth.ts +7 -1
- src/lib/server/endpoints/anthropic/utils.ts +1 -1
- src/lib/server/endpoints/cohere/endpointCohere.ts +2 -2
- src/lib/server/exitHandler.ts +1 -1
- src/lib/server/files/downloadFile.ts +2 -2
- src/routes/+layout.svelte +3 -3
- src/routes/admin/export/+server.ts +1 -1
- src/routes/assistant/[assistantId]/+page.server.ts +2 -2
- src/routes/assistant/[assistantId]/thumbnail.png/+server.ts +1 -1
- src/routes/assistants/+page.server.ts +2 -2
- src/routes/assistants/+page.svelte +4 -4
- src/routes/conversation/+server.ts +6 -9
- src/routes/conversation/[id]/+page.server.ts +5 -5
- src/routes/conversation/[id]/+server.ts +16 -16
- src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts +3 -3
- src/routes/conversation/[id]/message/[messageId]/vote/+server.ts +1 -1
- src/routes/conversation/[id]/output/[sha256]/+server.ts +3 -3
- src/routes/conversation/[id]/share/+server.ts +1 -1
- src/routes/conversation/[id]/stop-generating/+server.ts +1 -1
- src/routes/conversations/+page.server.ts +1 -1
- src/routes/login/+page.server.ts +1 -1
- src/routes/login/callback/+page.server.ts +6 -6
- src/routes/login/callback/updateUser.ts +1 -1
- src/routes/logout/+page.server.ts +1 -1
- src/routes/models/[...model]/+page.server.ts +1 -1
- src/routes/models/[...model]/thumbnail.png/+server.ts +1 -1
- src/routes/r/[id]/+page.ts +1 -1
- src/routes/settings/(nav)/+page.svelte +1 -1
- src/routes/settings/(nav)/[...model]/+page.ts +1 -1
- src/routes/settings/(nav)/assistants/[assistantId]/+page.server.ts +2 -2
- src/routes/settings/(nav)/assistants/[assistantId]/+page.ts +1 -1
- src/routes/settings/(nav)/assistants/[assistantId]/avatar.jpg/+server.ts +3 -3
- src/routes/settings/(nav)/assistants/[assistantId]/edit/+page.server.ts +1 -1
- src/routes/settings/(nav)/assistants/new/+page.server.ts +1 -1
- svelte.config.js +1 -1
package-lock.json
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
{
|
2 |
"name": "chat-ui",
|
3 |
-
"version": "0.9.
|
4 |
"private": true,
|
5 |
"packageManager": "[email protected]",
|
6 |
"scripts": {
|
@@ -20,14 +20,15 @@
|
|
20 |
"@faker-js/faker": "^8.4.1",
|
21 |
"@iconify-json/carbon": "^1.1.16",
|
22 |
"@iconify-json/eos-icons": "^1.1.6",
|
23 |
-
"@sveltejs/adapter-node": "^
|
24 |
-
"@sveltejs/kit": "^
|
25 |
"@tailwindcss/typography": "^0.5.9",
|
26 |
"@types/dompurify": "^3.0.5",
|
27 |
"@types/express": "^4.17.21",
|
28 |
"@types/js-yaml": "^4.0.9",
|
29 |
"@types/jsdom": "^21.1.1",
|
30 |
"@types/minimist": "^1.2.5",
|
|
|
31 |
"@types/parquetjs": "^0.10.3",
|
32 |
"@types/sbd": "^1.0.5",
|
33 |
"@types/uuid": "^9.0.8",
|
@@ -44,13 +45,13 @@
|
|
44 |
"prettier-plugin-svelte": "^2.10.1",
|
45 |
"prettier-plugin-tailwindcss": "^0.2.7",
|
46 |
"prom-client": "^15.1.2",
|
47 |
-
"svelte": "^4.2.
|
48 |
-
"svelte-check": "^3.
|
49 |
"ts-node": "^10.9.1",
|
50 |
"tslib": "^2.4.1",
|
51 |
"typescript": "^5.0.0",
|
52 |
"unplugin-icons": "^0.16.1",
|
53 |
-
"vite": "^
|
54 |
"vite-node": "^1.3.1",
|
55 |
"vitest": "^0.31.0"
|
56 |
},
|
@@ -72,6 +73,7 @@
|
|
72 |
"dotenv": "^16.0.3",
|
73 |
"express": "^4.19.2",
|
74 |
"file-type": "^19.0.0",
|
|
|
75 |
"handlebars": "^4.7.8",
|
76 |
"highlight.js": "^11.7.0",
|
77 |
"husky": "^9.0.11",
|
@@ -99,12 +101,12 @@
|
|
99 |
"sharp": "^0.33.4",
|
100 |
"tailwind-scrollbar": "^3.0.0",
|
101 |
"tailwindcss": "^3.4.0",
|
102 |
-
"uuid": "^
|
103 |
"zod": "^3.22.3"
|
104 |
},
|
105 |
"optionalDependencies": {
|
106 |
-
"@anthropic-ai/sdk": "^0.
|
107 |
-
"@anthropic-ai/vertex-sdk": "^0.
|
108 |
"@google-cloud/vertexai": "^1.1.0",
|
109 |
"@google/generative-ai": "^0.14.1",
|
110 |
"aws4fetch": "^1.0.17",
|
|
|
1 |
{
|
2 |
"name": "chat-ui",
|
3 |
+
"version": "0.9.2",
|
4 |
"private": true,
|
5 |
"packageManager": "[email protected]",
|
6 |
"scripts": {
|
|
|
20 |
"@faker-js/faker": "^8.4.1",
|
21 |
"@iconify-json/carbon": "^1.1.16",
|
22 |
"@iconify-json/eos-icons": "^1.1.6",
|
23 |
+
"@sveltejs/adapter-node": "^5.2.0",
|
24 |
+
"@sveltejs/kit": "^2.5.20",
|
25 |
"@tailwindcss/typography": "^0.5.9",
|
26 |
"@types/dompurify": "^3.0.5",
|
27 |
"@types/express": "^4.17.21",
|
28 |
"@types/js-yaml": "^4.0.9",
|
29 |
"@types/jsdom": "^21.1.1",
|
30 |
"@types/minimist": "^1.2.5",
|
31 |
+
"@types/node": "^22.1.0",
|
32 |
"@types/parquetjs": "^0.10.3",
|
33 |
"@types/sbd": "^1.0.5",
|
34 |
"@types/uuid": "^9.0.8",
|
|
|
45 |
"prettier-plugin-svelte": "^2.10.1",
|
46 |
"prettier-plugin-tailwindcss": "^0.2.7",
|
47 |
"prom-client": "^15.1.2",
|
48 |
+
"svelte": "^4.2.18",
|
49 |
+
"svelte-check": "^3.8.5",
|
50 |
"ts-node": "^10.9.1",
|
51 |
"tslib": "^2.4.1",
|
52 |
"typescript": "^5.0.0",
|
53 |
"unplugin-icons": "^0.16.1",
|
54 |
+
"vite": "^5.3.5",
|
55 |
"vite-node": "^1.3.1",
|
56 |
"vitest": "^0.31.0"
|
57 |
},
|
|
|
73 |
"dotenv": "^16.0.3",
|
74 |
"express": "^4.19.2",
|
75 |
"file-type": "^19.0.0",
|
76 |
+
"google-auth-library": "^9.13.0",
|
77 |
"handlebars": "^4.7.8",
|
78 |
"highlight.js": "^11.7.0",
|
79 |
"husky": "^9.0.11",
|
|
|
101 |
"sharp": "^0.33.4",
|
102 |
"tailwind-scrollbar": "^3.0.0",
|
103 |
"tailwindcss": "^3.4.0",
|
104 |
+
"uuid": "^10.0.0",
|
105 |
"zod": "^3.22.3"
|
106 |
},
|
107 |
"optionalDependencies": {
|
108 |
+
"@anthropic-ai/sdk": "^0.25.0",
|
109 |
+
"@anthropic-ai/vertex-sdk": "^0.4.1",
|
110 |
"@google-cloud/vertexai": "^1.1.0",
|
111 |
"@google/generative-ai": "^0.14.1",
|
112 |
"aws4fetch": "^1.0.17",
|
src/hooks.server.ts
CHANGED
@@ -35,7 +35,7 @@ if (!building) {
|
|
35 |
AbortedGenerations.getInstance();
|
36 |
}
|
37 |
|
38 |
-
export const handleError: HandleServerError = async ({ error, event }) => {
|
39 |
// handle 404
|
40 |
|
41 |
if (building) {
|
@@ -55,8 +55,10 @@ export const handleError: HandleServerError = async ({ error, event }) => {
|
|
55 |
url: event.request.url,
|
56 |
params: event.params,
|
57 |
request: event.request,
|
|
|
58 |
error,
|
59 |
errorId,
|
|
|
60 |
});
|
61 |
|
62 |
return {
|
|
|
35 |
AbortedGenerations.getInstance();
|
36 |
}
|
37 |
|
38 |
+
export const handleError: HandleServerError = async ({ error, event, status, message }) => {
|
39 |
// handle 404
|
40 |
|
41 |
if (building) {
|
|
|
55 |
url: event.request.url,
|
56 |
params: event.params,
|
57 |
request: event.request,
|
58 |
+
message,
|
59 |
error,
|
60 |
errorId,
|
61 |
+
status,
|
62 |
});
|
63 |
|
64 |
return {
|
src/lib/components/ExpandNavigation.svelte
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
|
6 |
<button
|
7 |
on:click
|
8 |
-
class="{classNames} group flex h-16 w-6 flex-col items-center justify-center -space-y-1 outline-none *:h-3 *:w-1 *:rounded-full *:hover:bg-gray-300
|
9 |
? '*:bg-gray-200/70 dark:*:bg-gray-800'
|
10 |
: '*:bg-gray-200 dark:*:bg-gray-700'}"
|
11 |
>
|
|
|
5 |
|
6 |
<button
|
7 |
on:click
|
8 |
+
class="{classNames} group flex h-16 w-6 flex-col items-center justify-center -space-y-1 outline-none *:h-3 *:w-1 *:rounded-full *:hover:bg-gray-300 dark:*:hover:bg-gray-600 max-md:hidden {!isCollapsed
|
9 |
? '*:bg-gray-200/70 dark:*:bg-gray-800'
|
10 |
: '*:bg-gray-200 dark:*:bg-gray-700'}"
|
11 |
>
|
src/lib/components/MobileNav.svelte
CHANGED
@@ -31,7 +31,7 @@
|
|
31 |
</script>
|
32 |
|
33 |
<nav
|
34 |
-
class="flex h-12 items-center justify-between border-b bg-gray-50 px-3
|
35 |
>
|
36 |
<button
|
37 |
type="button"
|
|
|
31 |
</script>
|
32 |
|
33 |
<nav
|
34 |
+
class="flex h-12 items-center justify-between border-b bg-gray-50 px-3 dark:border-gray-800 dark:bg-gray-800/70 md:hidden"
|
35 |
>
|
36 |
<button
|
37 |
type="button"
|
src/lib/components/NavConversationItem.svelte
CHANGED
@@ -25,7 +25,7 @@
|
|
25 |
confirmDelete = false;
|
26 |
}}
|
27 |
href="{base}/conversation/{conv.id}"
|
28 |
-
class="group flex h-10 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-600 hover:bg-gray-100
|
29 |
$page.params.id
|
30 |
? 'bg-gray-100 dark:bg-gray-700'
|
31 |
: ''}"
|
|
|
25 |
confirmDelete = false;
|
26 |
}}
|
27 |
href="{base}/conversation/{conv.id}"
|
28 |
+
class="group flex h-10 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 sm:h-[2.35rem] {conv.id ===
|
29 |
$page.params.id
|
30 |
? 'bg-gray-100 dark:bg-gray-700'
|
31 |
: ''}"
|
src/lib/components/NavMenu.svelte
CHANGED
@@ -57,13 +57,13 @@
|
|
57 |
<a
|
58 |
href={`${base}/`}
|
59 |
on:click={handleNewChatClick}
|
60 |
-
class="flex rounded-lg border bg-white px-2 py-0.5 text-center shadow-sm hover:shadow-none
|
61 |
>
|
62 |
New Chat
|
63 |
</a>
|
64 |
</div>
|
65 |
<div
|
66 |
-
class="scrollbar-custom flex flex-col gap-1 overflow-y-auto rounded-r-xl from-gray-50 px-3 pb-3 pt-2 text-[.9rem] max-sm:bg-gradient-to-t md:bg-gradient-to-l
|
67 |
>
|
68 |
{#each Object.entries(groupedConversations) as [group, convs]}
|
69 |
{#if convs.length}
|
@@ -92,7 +92,7 @@
|
|
92 |
{#if !user.logoutDisabled}
|
93 |
<button
|
94 |
type="submit"
|
95 |
-
class="ml-auto h-6 flex-none items-center gap-1.5 rounded-md border bg-white px-2 text-gray-700 shadow-sm group-hover:flex hover:shadow-none
|
96 |
>
|
97 |
Sign Out
|
98 |
</button>
|
|
|
57 |
<a
|
58 |
href={`${base}/`}
|
59 |
on:click={handleNewChatClick}
|
60 |
+
class="flex rounded-lg border bg-white px-2 py-0.5 text-center shadow-sm hover:shadow-none dark:border-gray-600 dark:bg-gray-700 sm:text-smd"
|
61 |
>
|
62 |
New Chat
|
63 |
</a>
|
64 |
</div>
|
65 |
<div
|
66 |
+
class="scrollbar-custom flex flex-col gap-1 overflow-y-auto rounded-r-xl from-gray-50 px-3 pb-3 pt-2 text-[.9rem] dark:from-gray-800/30 max-sm:bg-gradient-to-t md:bg-gradient-to-l"
|
67 |
>
|
68 |
{#each Object.entries(groupedConversations) as [group, convs]}
|
69 |
{#if convs.length}
|
|
|
92 |
{#if !user.logoutDisabled}
|
93 |
<button
|
94 |
type="submit"
|
95 |
+
class="ml-auto h-6 flex-none items-center gap-1.5 rounded-md border bg-white px-2 text-gray-700 shadow-sm group-hover:flex hover:shadow-none dark:border-gray-600 dark:bg-gray-600 dark:text-gray-400 dark:hover:text-gray-300 md:hidden"
|
96 |
>
|
97 |
Sign Out
|
98 |
</button>
|
src/lib/components/Pagination.svelte
CHANGED
@@ -57,7 +57,7 @@
|
|
57 |
{#if numTotalPages > 1}
|
58 |
<nav>
|
59 |
<ul
|
60 |
-
class="flex select-none items-center justify-between space-x-2 text-gray-700
|
61 |
>
|
62 |
<li>
|
63 |
<PaginationArrow
|
|
|
57 |
{#if numTotalPages > 1}
|
58 |
<nav>
|
59 |
<ul
|
60 |
+
class="flex select-none items-center justify-between space-x-2 text-gray-700 dark:text-gray-300 sm:justify-center {classNames}"
|
61 |
>
|
62 |
<li>
|
63 |
<PaginationArrow
|
src/lib/components/chat/AssistantIntroduction.svelte
CHANGED
@@ -67,7 +67,7 @@
|
|
67 |
/>
|
68 |
{:else}
|
69 |
<div
|
70 |
-
class="flex size-12 flex-none items-center justify-center rounded-full bg-gray-300 object-cover text-xl font-bold uppercase text-gray-500 max-sm:self-start sm:text-4xl md:size-32
|
71 |
>
|
72 |
{assistant?.name[0]}
|
73 |
</div>
|
@@ -116,7 +116,7 @@
|
|
116 |
<div class="absolute right-3 top-3 md:right-4 md:top-4">
|
117 |
<div class="flex flex-row items-center gap-1">
|
118 |
<button
|
119 |
-
class="flex h-7 items-center gap-1.5 rounded-full border bg-white px-2.5 py-1 text-gray-800 shadow-sm hover:shadow-inner
|
120 |
on:click={() => {
|
121 |
if (!isCopied) {
|
122 |
share(shareUrl, assistant.name);
|
@@ -137,7 +137,7 @@
|
|
137 |
</button>
|
138 |
<a
|
139 |
href="{base}/settings/assistants/{assistant._id.toString()}"
|
140 |
-
class="flex h-7 items-center gap-1.5 rounded-full border bg-white px-2.5 py-1 text-gray-800 shadow-sm hover:shadow-inner
|
141 |
><IconGear class="text-xxs" />Settings</a
|
142 |
>
|
143 |
</div>
|
|
|
67 |
/>
|
68 |
{:else}
|
69 |
<div
|
70 |
+
class="flex size-12 flex-none items-center justify-center rounded-full bg-gray-300 object-cover text-xl font-bold uppercase text-gray-500 dark:bg-gray-600 max-sm:self-start sm:text-4xl md:size-32"
|
71 |
>
|
72 |
{assistant?.name[0]}
|
73 |
</div>
|
|
|
116 |
<div class="absolute right-3 top-3 md:right-4 md:top-4">
|
117 |
<div class="flex flex-row items-center gap-1">
|
118 |
<button
|
119 |
+
class="flex h-7 items-center gap-1.5 rounded-full border bg-white px-2.5 py-1 text-gray-800 shadow-sm hover:shadow-inner dark:border-gray-700 dark:bg-gray-700 dark:text-gray-300/90 dark:hover:bg-gray-800 max-sm:px-1.5 md:text-sm"
|
120 |
on:click={() => {
|
121 |
if (!isCopied) {
|
122 |
share(shareUrl, assistant.name);
|
|
|
137 |
</button>
|
138 |
<a
|
139 |
href="{base}/settings/assistants/{assistant._id.toString()}"
|
140 |
+
class="flex h-7 items-center gap-1.5 rounded-full border bg-white px-2.5 py-1 text-gray-800 shadow-sm hover:shadow-inner dark:border-gray-700 dark:bg-gray-700 dark:text-gray-300/90 dark:hover:bg-gray-800 md:text-sm"
|
141 |
><IconGear class="text-xxs" />Settings</a
|
142 |
>
|
143 |
</div>
|
src/lib/components/chat/ChatIntroduction.svelte
CHANGED
@@ -86,7 +86,7 @@
|
|
86 |
{#each currentModelMetadata.promptExamples as example}
|
87 |
<button
|
88 |
type="button"
|
89 |
-
class="rounded-xl border bg-gray-50 p-3 text-gray-600 hover:bg-gray-100
|
90 |
on:click={() => dispatch("message", example.prompt)}
|
91 |
>
|
92 |
{example.title}
|
|
|
86 |
{#each currentModelMetadata.promptExamples as example}
|
87 |
<button
|
88 |
type="button"
|
89 |
+
class="rounded-xl border bg-gray-50 p-3 text-gray-600 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 max-xl:text-sm xl:p-3.5"
|
90 |
on:click={() => dispatch("message", example.prompt)}
|
91 |
>
|
92 |
{example.title}
|
src/lib/components/chat/ChatMessage.svelte
CHANGED
@@ -295,7 +295,7 @@
|
|
295 |
{/if}
|
296 |
|
297 |
<div
|
298 |
-
class="prose max-w-none max-sm:prose-sm
|
299 |
bind:this={contentEl}
|
300 |
>
|
301 |
{#if isLast && loading && $settings.disableStream}
|
@@ -343,7 +343,7 @@
|
|
343 |
>
|
344 |
{#if isAuthor}
|
345 |
<button
|
346 |
-
class="btn rounded-sm p-1 text-sm text-gray-400
|
347 |
{message.score && message.score > 0
|
348 |
? 'text-green-500 hover:text-green-500 dark:text-green-400 hover:dark:text-green-400'
|
349 |
: ''}"
|
@@ -355,7 +355,7 @@
|
|
355 |
<CarbonThumbsUp class="h-[1.14em] w-[1.14em]" />
|
356 |
</button>
|
357 |
<button
|
358 |
-
class="btn rounded-sm p-1 text-sm text-gray-400
|
359 |
{message.score && message.score < 0
|
360 |
? 'text-red-500 hover:text-red-500 dark:text-red-400 hover:dark:text-red-400'
|
361 |
: ''}"
|
@@ -368,7 +368,7 @@
|
|
368 |
</button>
|
369 |
{/if}
|
370 |
<button
|
371 |
-
class="btn rounded-sm p-1 text-sm text-gray-400
|
372 |
title="Retry"
|
373 |
type="button"
|
374 |
on:click={() => dispatch("retry", { id: message.id })}
|
@@ -439,7 +439,7 @@
|
|
439 |
class="btn rounded-lg px-3 py-1.5 text-sm
|
440 |
{loading
|
441 |
? 'bg-gray-300 text-gray-400 dark:bg-gray-700 dark:text-gray-600'
|
442 |
-
: 'bg-gray-200 text-gray-600
|
443 |
"
|
444 |
disabled={loading}
|
445 |
>
|
@@ -447,7 +447,7 @@
|
|
447 |
</button>
|
448 |
<button
|
449 |
type="button"
|
450 |
-
class="btn rounded-sm p-2 text-sm text-gray-400
|
451 |
on:click={() => {
|
452 |
$convTreeStore.editing = null;
|
453 |
}}
|
@@ -469,7 +469,7 @@
|
|
469 |
<div class="mx-auto flex flex-row flex-nowrap gap-2">
|
470 |
{#if downloadLink}
|
471 |
<a
|
472 |
-
class="rounded-lg border border-gray-100 bg-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500
|
473 |
title="Download prompt and parameters"
|
474 |
type="button"
|
475 |
target="_blank"
|
@@ -480,7 +480,7 @@
|
|
480 |
{/if}
|
481 |
{#if !readOnly}
|
482 |
<button
|
483 |
-
class="cursor-pointer rounded-lg border border-gray-100 bg-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500
|
484 |
title="Branch"
|
485 |
type="button"
|
486 |
on:click={() => ($convTreeStore.editing = message.id)}
|
@@ -515,7 +515,7 @@
|
|
515 |
class="font-white group/navbranch z-10 -mt-1 ml-3.5 mr-auto flex h-6 w-fit select-none flex-row items-center justify-center gap-1 text-sm"
|
516 |
>
|
517 |
<button
|
518 |
-
class="inline text-lg font-thin text-gray-400 disabled:pointer-events-none disabled:opacity-25
|
519 |
on:click={() => (childrenToRender = Math.max(0, childrenToRender - 1))}
|
520 |
disabled={childrenToRender === 0 || loading}
|
521 |
>
|
@@ -525,7 +525,7 @@
|
|
525 |
{childrenToRender + 1} / {nChildren}
|
526 |
</span>
|
527 |
<button
|
528 |
-
class="inline text-lg font-thin text-gray-400 disabled:pointer-events-none disabled:opacity-25
|
529 |
on:click={() =>
|
530 |
(childrenToRender = Math.min(
|
531 |
message?.children?.length ?? 1 - 1,
|
|
|
295 |
{/if}
|
296 |
|
297 |
<div
|
298 |
+
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"
|
299 |
bind:this={contentEl}
|
300 |
>
|
301 |
{#if isLast && loading && $settings.disableStream}
|
|
|
343 |
>
|
344 |
{#if isAuthor}
|
345 |
<button
|
346 |
+
class="btn rounded-sm p-1 text-sm text-gray-400 hover:text-gray-500 focus:ring-0 dark:text-gray-400 dark:hover:text-gray-300
|
347 |
{message.score && message.score > 0
|
348 |
? 'text-green-500 hover:text-green-500 dark:text-green-400 hover:dark:text-green-400'
|
349 |
: ''}"
|
|
|
355 |
<CarbonThumbsUp class="h-[1.14em] w-[1.14em]" />
|
356 |
</button>
|
357 |
<button
|
358 |
+
class="btn rounded-sm p-1 text-sm text-gray-400 hover:text-gray-500 focus:ring-0 dark:text-gray-400 dark:hover:text-gray-300
|
359 |
{message.score && message.score < 0
|
360 |
? 'text-red-500 hover:text-red-500 dark:text-red-400 hover:dark:text-red-400'
|
361 |
: ''}"
|
|
|
368 |
</button>
|
369 |
{/if}
|
370 |
<button
|
371 |
+
class="btn rounded-sm p-1 text-sm text-gray-400 hover:text-gray-500 focus:ring-0 dark:text-gray-400 dark:hover:text-gray-300"
|
372 |
title="Retry"
|
373 |
type="button"
|
374 |
on:click={() => dispatch("retry", { id: message.id })}
|
|
|
439 |
class="btn rounded-lg px-3 py-1.5 text-sm
|
440 |
{loading
|
441 |
? 'bg-gray-300 text-gray-400 dark:bg-gray-700 dark:text-gray-600'
|
442 |
+
: 'bg-gray-200 text-gray-600 hover:text-gray-800 focus:ring-0 dark:bg-gray-800 dark:text-gray-300 dark:hover:text-gray-200'}
|
443 |
"
|
444 |
disabled={loading}
|
445 |
>
|
|
|
447 |
</button>
|
448 |
<button
|
449 |
type="button"
|
450 |
+
class="btn rounded-sm p-2 text-sm text-gray-400 hover:text-gray-500 focus:ring-0 dark:text-gray-400 dark:hover:text-gray-300"
|
451 |
on:click={() => {
|
452 |
$convTreeStore.editing = null;
|
453 |
}}
|
|
|
469 |
<div class="mx-auto flex flex-row flex-nowrap gap-2">
|
470 |
{#if downloadLink}
|
471 |
<a
|
472 |
+
class="rounded-lg border border-gray-100 bg-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-400 dark:hover:text-gray-300 max-sm:!hidden md:hidden"
|
473 |
title="Download prompt and parameters"
|
474 |
type="button"
|
475 |
target="_blank"
|
|
|
480 |
{/if}
|
481 |
{#if !readOnly}
|
482 |
<button
|
483 |
+
class="cursor-pointer rounded-lg border border-gray-100 bg-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-400 dark:hover:text-gray-300 md:hidden lg:-right-2"
|
484 |
title="Branch"
|
485 |
type="button"
|
486 |
on:click={() => ($convTreeStore.editing = message.id)}
|
|
|
515 |
class="font-white group/navbranch z-10 -mt-1 ml-3.5 mr-auto flex h-6 w-fit select-none flex-row items-center justify-center gap-1 text-sm"
|
516 |
>
|
517 |
<button
|
518 |
+
class="inline text-lg font-thin text-gray-400 hover:text-gray-800 disabled:pointer-events-none disabled:opacity-25 dark:text-gray-500 dark:hover:text-gray-200"
|
519 |
on:click={() => (childrenToRender = Math.max(0, childrenToRender - 1))}
|
520 |
disabled={childrenToRender === 0 || loading}
|
521 |
>
|
|
|
525 |
{childrenToRender + 1} / {nChildren}
|
526 |
</span>
|
527 |
<button
|
528 |
+
class="inline text-lg font-thin text-gray-400 hover:text-gray-800 disabled:pointer-events-none disabled:opacity-25 dark:text-gray-500 dark:hover:text-gray-200"
|
529 |
on:click={() =>
|
530 |
(childrenToRender = Math.min(
|
531 |
message?.children?.length ?? 1 - 1,
|
src/lib/components/chat/ChatWindow.svelte
CHANGED
@@ -281,7 +281,7 @@
|
|
281 |
/>
|
282 |
</div>
|
283 |
<div
|
284 |
-
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
|
285 |
>
|
286 |
{#if sources?.length}
|
287 |
<div class="flex flex-row flex-wrap justify-center gap-2.5 max-md:pb-3">
|
@@ -373,19 +373,19 @@
|
|
373 |
|
374 |
{#if loading}
|
375 |
<button
|
376 |
-
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
|
377 |
on:click={() => dispatch("stop")}
|
378 |
>
|
379 |
<CarbonStopFilledAlt />
|
380 |
</button>
|
381 |
<div
|
382 |
-
class="mx-1 my-1 hidden h-[2.4rem] items-center p-1 px-[0.7rem] text-gray-400
|
383 |
>
|
384 |
<EosIconsLoading />
|
385 |
</div>
|
386 |
{:else}
|
387 |
<button
|
388 |
-
class="btn mx-1 my-1 h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400
|
389 |
disabled={!message || isReadOnly}
|
390 |
type="submit"
|
391 |
>
|
|
|
281 |
/>
|
282 |
</div>
|
283 |
<div
|
284 |
+
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"
|
285 |
>
|
286 |
{#if sources?.length}
|
287 |
<div class="flex flex-row flex-wrap justify-center gap-2.5 max-md:pb-3">
|
|
|
373 |
|
374 |
{#if loading}
|
375 |
<button
|
376 |
+
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 enabled:hover:text-gray-700 disabled:opacity-60 enabled:dark:hover:text-gray-100 dark:disabled:opacity-40 md:hidden"
|
377 |
on:click={() => dispatch("stop")}
|
378 |
>
|
379 |
<CarbonStopFilledAlt />
|
380 |
</button>
|
381 |
<div
|
382 |
+
class="mx-1 my-1 hidden h-[2.4rem] items-center p-1 px-[0.7rem] text-gray-400 enabled:hover:text-gray-700 disabled:opacity-60 enabled:dark:hover:text-gray-100 dark:disabled:opacity-40 md:flex"
|
383 |
>
|
384 |
<EosIconsLoading />
|
385 |
</div>
|
386 |
{:else}
|
387 |
<button
|
388 |
+
class="btn mx-1 my-1 h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400 enabled:hover:text-gray-700 disabled:opacity-60 enabled:dark:hover:text-gray-100 dark:disabled:opacity-40"
|
389 |
disabled={!message || isReadOnly}
|
390 |
type="submit"
|
391 |
>
|
src/lib/server/auth.ts
CHANGED
@@ -1,4 +1,10 @@
|
|
1 |
-
import {
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import { addHours, addWeeks } from "date-fns";
|
3 |
import { env } from "$env/dynamic/private";
|
4 |
import { sha256 } from "$lib/utils/sha256";
|
|
|
1 |
+
import {
|
2 |
+
Issuer,
|
3 |
+
type BaseClient,
|
4 |
+
type UserinfoResponse,
|
5 |
+
type TokenSet,
|
6 |
+
custom,
|
7 |
+
} from "openid-client";
|
8 |
import { addHours, addWeeks } from "date-fns";
|
9 |
import { env } from "$env/dynamic/private";
|
10 |
import { sha256 } from "$lib/utils/sha256";
|
src/lib/server/endpoints/anthropic/utils.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
-
import type { ImageBlockParam, MessageParam } from "@anthropic-ai/sdk/resources";
|
2 |
import { makeImageProcessor, type ImageProcessorOptions } from "../images";
|
3 |
import type { EndpointMessage } from "../endpoints";
|
4 |
import type { MessageFile } from "$lib/types/Message";
|
|
|
5 |
|
6 |
export async function fileToImageBlock(
|
7 |
file: MessageFile,
|
|
|
|
|
1 |
import { makeImageProcessor, type ImageProcessorOptions } from "../images";
|
2 |
import type { EndpointMessage } from "../endpoints";
|
3 |
import type { MessageFile } from "$lib/types/Message";
|
4 |
+
import type { ImageBlockParam, MessageParam } from "@anthropic-ai/sdk/resources/messages.mjs";
|
5 |
|
6 |
export async function fileToImageBlock(
|
7 |
file: MessageFile,
|
src/lib/server/endpoints/cohere/endpointCohere.ts
CHANGED
@@ -5,7 +5,7 @@ import type { TextGenerationStreamOutput } from "@huggingface/inference";
|
|
5 |
import type { Cohere, CohereClient } from "cohere-ai";
|
6 |
import { buildPrompt } from "$lib/buildPrompt";
|
7 |
import { ToolResultStatus, type ToolCall } from "$lib/types/Tool";
|
8 |
-
import { pipeline, Writable, Readable } from "node:stream";
|
9 |
import { toolHasName } from "$lib/utils/tools";
|
10 |
|
11 |
export const endpointCohereParametersSchema = z.object({
|
@@ -78,7 +78,7 @@ export async function endpointCohere(
|
|
78 |
.map((message) => ({
|
79 |
role: message.from === "user" ? "USER" : "CHATBOT",
|
80 |
message: message.content,
|
81 |
-
})) satisfies Cohere.
|
82 |
|
83 |
stream = await cohere
|
84 |
.chatStream({
|
|
|
5 |
import type { Cohere, CohereClient } from "cohere-ai";
|
6 |
import { buildPrompt } from "$lib/buildPrompt";
|
7 |
import { ToolResultStatus, type ToolCall } from "$lib/types/Tool";
|
8 |
+
import { pipeline, Writable, type Readable } from "node:stream";
|
9 |
import { toolHasName } from "$lib/utils/tools";
|
10 |
|
11 |
export const endpointCohereParametersSchema = z.object({
|
|
|
78 |
.map((message) => ({
|
79 |
role: message.from === "user" ? "USER" : "CHATBOT",
|
80 |
message: message.content,
|
81 |
+
})) satisfies Cohere.Message[];
|
82 |
|
83 |
stream = await cohere
|
84 |
.chatStream({
|
src/lib/server/exitHandler.ts
CHANGED
@@ -17,7 +17,7 @@ export function onExit(cb: ExitHandler): ExitHandlerUnsubscribe {
|
|
17 |
|
18 |
async function runExitHandler(handler: ExitHandler): Promise<void> {
|
19 |
return timeout(Promise.resolve().then(handler), 30_000).catch((err) => {
|
20 |
-
logger.error("Exit handler failed to run"
|
21 |
});
|
22 |
}
|
23 |
|
|
|
17 |
|
18 |
async function runExitHandler(handler: ExitHandler): Promise<void> {
|
19 |
return timeout(Promise.resolve().then(handler), 30_000).catch((err) => {
|
20 |
+
logger.error(err, "Exit handler failed to run");
|
21 |
});
|
22 |
}
|
23 |
|
src/lib/server/files/downloadFile.ts
CHANGED
@@ -12,10 +12,10 @@ export async function downloadFile(
|
|
12 |
|
13 |
const file = await fileId.next();
|
14 |
if (!file) {
|
15 |
-
|
16 |
}
|
17 |
if (file.metadata?.conversation !== convId.toString()) {
|
18 |
-
|
19 |
}
|
20 |
|
21 |
const mime = file.metadata?.mime;
|
|
|
12 |
|
13 |
const file = await fileId.next();
|
14 |
if (!file) {
|
15 |
+
error(404, "File not found");
|
16 |
}
|
17 |
if (file.metadata?.conversation !== convId.toString()) {
|
18 |
+
error(403, "You don't have access to this file.");
|
19 |
}
|
20 |
|
21 |
const mime = file.metadata?.mime;
|
src/routes/+layout.svelte
CHANGED
@@ -207,7 +207,7 @@
|
|
207 |
<div
|
208 |
class="grid h-full w-screen grid-cols-1 grid-rows-[auto,1fr] overflow-hidden text-smd {!isNavCollapsed
|
209 |
? 'md:grid-cols-[280px,1fr]'
|
210 |
-
: 'md:grid-cols-[0px,1fr]'} transition-[300ms] [transition-property:grid-template-columns] md:grid-rows-[1fr]
|
211 |
>
|
212 |
<MobileNav isOpen={isNavOpen} on:toggle={(ev) => (isNavOpen = ev.detail)} title={mobileNavTitle}>
|
213 |
<NavMenu
|
@@ -242,8 +242,8 @@
|
|
242 |
href="https://play.google.com/store/apps/details?id=co.huggingface.chat_ui_android"
|
243 |
class="fixed left-0 right-0 top-0 mx-auto flex h-fit min-h-12 w-screen flex-nowrap items-center justify-evenly gap-4 bg-gray-200 px-4 py-4 text-gray-900 shadow-lg backdrop-blur-md
|
244 |
hover:bg-gray-100
|
245 |
-
|
246 |
-
|
247 |
>
|
248 |
<button
|
249 |
class="border-r-2 border-black/20 pr-4 text-2xl"
|
|
|
207 |
<div
|
208 |
class="grid h-full w-screen grid-cols-1 grid-rows-[auto,1fr] overflow-hidden text-smd {!isNavCollapsed
|
209 |
? 'md:grid-cols-[280px,1fr]'
|
210 |
+
: 'md:grid-cols-[0px,1fr]'} transition-[300ms] [transition-property:grid-template-columns] dark:text-gray-300 md:grid-rows-[1fr]"
|
211 |
>
|
212 |
<MobileNav isOpen={isNavOpen} on:toggle={(ev) => (isNavOpen = ev.detail)} title={mobileNavTitle}>
|
213 |
<NavMenu
|
|
|
242 |
href="https://play.google.com/store/apps/details?id=co.huggingface.chat_ui_android"
|
243 |
class="fixed left-0 right-0 top-0 mx-auto flex h-fit min-h-12 w-screen flex-nowrap items-center justify-evenly gap-4 bg-gray-200 px-4 py-4 text-gray-900 shadow-lg backdrop-blur-md
|
244 |
hover:bg-gray-100
|
245 |
+
dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 sm:top-5
|
246 |
+
sm:max-w-fit sm:gap-4 sm:rounded-lg"
|
247 |
>
|
248 |
<button
|
249 |
class="border-r-2 border-black/20 pr-4 text-2xl"
|
src/routes/admin/export/+server.ts
CHANGED
@@ -14,7 +14,7 @@ import { logger } from "$lib/server/logger.js";
|
|
14 |
|
15 |
export async function POST({ request }) {
|
16 |
if (!env.PARQUET_EXPORT_DATASET || !env.PARQUET_EXPORT_HF_TOKEN) {
|
17 |
-
|
18 |
}
|
19 |
|
20 |
const { model } = z
|
|
|
14 |
|
15 |
export async function POST({ request }) {
|
16 |
if (!env.PARQUET_EXPORT_DATASET || !env.PARQUET_EXPORT_HF_TOKEN) {
|
17 |
+
error(500, "Parquet export is not configured.");
|
18 |
}
|
19 |
|
20 |
const { model } = z
|
src/routes/assistant/[assistantId]/+page.server.ts
CHANGED
@@ -10,11 +10,11 @@ export const load = async ({ params }) => {
|
|
10 |
});
|
11 |
|
12 |
if (!assistant) {
|
13 |
-
|
14 |
}
|
15 |
|
16 |
return { assistant: JSON.parse(JSON.stringify(assistant)) };
|
17 |
} catch {
|
18 |
-
|
19 |
}
|
20 |
};
|
|
|
10 |
});
|
11 |
|
12 |
if (!assistant) {
|
13 |
+
redirect(302, `${base}`);
|
14 |
}
|
15 |
|
16 |
return { assistant: JSON.parse(JSON.stringify(assistant)) };
|
17 |
} catch {
|
18 |
+
redirect(302, `${base}`);
|
19 |
}
|
20 |
};
|
src/routes/assistant/[assistantId]/thumbnail.png/+server.ts
CHANGED
@@ -18,7 +18,7 @@ export const GET: RequestHandler = (async ({ params }) => {
|
|
18 |
});
|
19 |
|
20 |
if (!assistant) {
|
21 |
-
|
22 |
}
|
23 |
|
24 |
let avatar = "";
|
|
|
18 |
});
|
19 |
|
20 |
if (!assistant) {
|
21 |
+
error(404, "Assistant not found.");
|
22 |
}
|
23 |
|
24 |
let avatar = "";
|
src/routes/assistants/+page.server.ts
CHANGED
@@ -11,7 +11,7 @@ const NUM_PER_PAGE = 24;
|
|
11 |
|
12 |
export const load = async ({ url, locals }) => {
|
13 |
if (!env.ENABLE_ASSISTANTS) {
|
14 |
-
|
15 |
}
|
16 |
|
17 |
const modelId = url.searchParams.get("modelId");
|
@@ -28,7 +28,7 @@ export const load = async ({ url, locals }) => {
|
|
28 |
{ projection: { _id: 1 } }
|
29 |
);
|
30 |
if (!user) {
|
31 |
-
|
32 |
}
|
33 |
}
|
34 |
|
|
|
11 |
|
12 |
export const load = async ({ url, locals }) => {
|
13 |
if (!env.ENABLE_ASSISTANTS) {
|
14 |
+
redirect(302, `${base}/`);
|
15 |
}
|
16 |
|
17 |
const modelId = url.searchParams.get("modelId");
|
|
|
28 |
{ projection: { _id: 1 } }
|
29 |
);
|
30 |
if (!user) {
|
31 |
+
error(404, `User "${username}" doesn't exist`);
|
32 |
}
|
33 |
}
|
34 |
|
src/routes/assistants/+page.svelte
CHANGED
@@ -195,7 +195,7 @@
|
|
195 |
{/if}
|
196 |
{/if}
|
197 |
<div
|
198 |
-
class="relative ml-auto flex h-[30px] w-40 items-center rounded-full border px-2 has-[:focus]:border-gray-400
|
199 |
>
|
200 |
<CarbonSearch class="pointer-events-none absolute left-2 text-xs text-gray-400" />
|
201 |
<input
|
@@ -227,7 +227,7 @@
|
|
227 |
!!assistant?.dynamicPrompt}
|
228 |
|
229 |
<button
|
230 |
-
class="relative flex flex-col items-center justify-center overflow-hidden text-balance rounded-xl border bg-gray-50/50 px-4 py-6 text-center shadow hover:bg-gray-50 hover:shadow-inner
|
231 |
on:click={() => {
|
232 |
if (data.settings.assistants.includes(assistant._id.toString())) {
|
233 |
settings.instantSet({ activeModel: assistant._id.toString() });
|
@@ -263,7 +263,7 @@
|
|
263 |
/>
|
264 |
{:else}
|
265 |
<div
|
266 |
-
class="mb-2 flex aspect-square size-12 flex-none items-center justify-center rounded-full bg-gray-300 text-2xl font-bold uppercase text-gray-500 sm:mb-6 sm:size-20
|
267 |
>
|
268 |
{assistant.name[0]}
|
269 |
</div>
|
@@ -273,7 +273,7 @@
|
|
273 |
>
|
274 |
{assistant.name}
|
275 |
</h3>
|
276 |
-
<p class="line-clamp-4 text-xs text-gray-700 sm:line-clamp-2
|
277 |
{assistant.description}
|
278 |
</p>
|
279 |
{#if assistant.createdByName}
|
|
|
195 |
{/if}
|
196 |
{/if}
|
197 |
<div
|
198 |
+
class="relative ml-auto flex h-[30px] w-40 items-center rounded-full border px-2 has-[:focus]:border-gray-400 dark:border-gray-600 sm:w-64"
|
199 |
>
|
200 |
<CarbonSearch class="pointer-events-none absolute left-2 text-xs text-gray-400" />
|
201 |
<input
|
|
|
227 |
!!assistant?.dynamicPrompt}
|
228 |
|
229 |
<button
|
230 |
+
class="relative flex flex-col items-center justify-center overflow-hidden text-balance rounded-xl border bg-gray-50/50 px-4 py-6 text-center shadow hover:bg-gray-50 hover:shadow-inner dark:border-gray-800/70 dark:bg-gray-950/20 dark:hover:bg-gray-950/40 max-sm:px-4 sm:h-64 sm:pb-4 xl:pt-8"
|
231 |
on:click={() => {
|
232 |
if (data.settings.assistants.includes(assistant._id.toString())) {
|
233 |
settings.instantSet({ activeModel: assistant._id.toString() });
|
|
|
263 |
/>
|
264 |
{:else}
|
265 |
<div
|
266 |
+
class="mb-2 flex aspect-square size-12 flex-none items-center justify-center rounded-full bg-gray-300 text-2xl font-bold uppercase text-gray-500 dark:bg-gray-800 sm:mb-6 sm:size-20"
|
267 |
>
|
268 |
{assistant.name[0]}
|
269 |
</div>
|
|
|
273 |
>
|
274 |
{assistant.name}
|
275 |
</h3>
|
276 |
+
<p class="line-clamp-4 text-xs text-gray-700 dark:text-gray-400 sm:line-clamp-2">
|
277 |
{assistant.description}
|
278 |
</p>
|
279 |
{#if assistant.createdByName}
|
src/routes/conversation/+server.ts
CHANGED
@@ -27,23 +27,20 @@ export const POST: RequestHandler = async ({ locals, request }) => {
|
|
27 |
.safeParse(JSON.parse(body));
|
28 |
|
29 |
if (!parsedBody.success) {
|
30 |
-
|
31 |
}
|
32 |
const values = parsedBody.data;
|
33 |
|
34 |
const convCount = await collections.conversations.countDocuments(authCondition(locals));
|
35 |
|
36 |
if (usageLimits?.conversations && convCount > usageLimits?.conversations) {
|
37 |
-
|
38 |
-
429,
|
39 |
-
"You have reached the maximum number of conversations. Delete some to continue."
|
40 |
-
);
|
41 |
}
|
42 |
|
43 |
const model = models.find((m) => (m.id || m.name) === values.model);
|
44 |
|
45 |
if (!model) {
|
46 |
-
|
47 |
}
|
48 |
|
49 |
let messages: Message[] = [
|
@@ -67,7 +64,7 @@ export const POST: RequestHandler = async ({ locals, request }) => {
|
|
67 |
});
|
68 |
|
69 |
if (!conversation) {
|
70 |
-
|
71 |
}
|
72 |
|
73 |
title = conversation.title;
|
@@ -82,7 +79,7 @@ export const POST: RequestHandler = async ({ locals, request }) => {
|
|
82 |
embeddingModel ??= model.embeddingModel ?? defaultEmbeddingModel.name;
|
83 |
|
84 |
if (model.unlisted) {
|
85 |
-
|
86 |
}
|
87 |
|
88 |
// get preprompt from assistant if it exists
|
@@ -127,5 +124,5 @@ export const POST: RequestHandler = async ({ locals, request }) => {
|
|
127 |
};
|
128 |
|
129 |
export const GET: RequestHandler = async () => {
|
130 |
-
|
131 |
};
|
|
|
27 |
.safeParse(JSON.parse(body));
|
28 |
|
29 |
if (!parsedBody.success) {
|
30 |
+
error(400, "Invalid request");
|
31 |
}
|
32 |
const values = parsedBody.data;
|
33 |
|
34 |
const convCount = await collections.conversations.countDocuments(authCondition(locals));
|
35 |
|
36 |
if (usageLimits?.conversations && convCount > usageLimits?.conversations) {
|
37 |
+
error(429, "You have reached the maximum number of conversations. Delete some to continue.");
|
|
|
|
|
|
|
38 |
}
|
39 |
|
40 |
const model = models.find((m) => (m.id || m.name) === values.model);
|
41 |
|
42 |
if (!model) {
|
43 |
+
error(400, "Invalid model");
|
44 |
}
|
45 |
|
46 |
let messages: Message[] = [
|
|
|
64 |
});
|
65 |
|
66 |
if (!conversation) {
|
67 |
+
error(404, "Conversation not found");
|
68 |
}
|
69 |
|
70 |
title = conversation.title;
|
|
|
79 |
embeddingModel ??= model.embeddingModel ?? defaultEmbeddingModel.name;
|
80 |
|
81 |
if (model.unlisted) {
|
82 |
+
error(400, "Can't start a conversation with an unlisted model");
|
83 |
}
|
84 |
|
85 |
// get preprompt from assistant if it exists
|
|
|
124 |
};
|
125 |
|
126 |
export const GET: RequestHandler = async () => {
|
127 |
+
redirect(302, `${base}/`);
|
128 |
};
|
src/routes/conversation/[id]/+page.server.ts
CHANGED
@@ -18,7 +18,7 @@ export const load = async ({ params, depends, locals }) => {
|
|
18 |
shared = true;
|
19 |
|
20 |
if (!conversation) {
|
21 |
-
|
22 |
}
|
23 |
} else {
|
24 |
// todo: add validation on params.id
|
@@ -36,13 +36,13 @@ export const load = async ({ params, depends, locals }) => {
|
|
36 |
})) !== 0;
|
37 |
|
38 |
if (conversationExists) {
|
39 |
-
|
40 |
403,
|
41 |
"You don't have access to this conversation. If someone gave you this link, ask them to use the 'share' feature instead."
|
42 |
);
|
43 |
}
|
44 |
|
45 |
-
|
46 |
}
|
47 |
}
|
48 |
|
@@ -73,7 +73,7 @@ export const actions = {
|
|
73 |
const messageId = data.get("messageId");
|
74 |
|
75 |
if (!messageId || typeof messageId !== "string") {
|
76 |
-
|
77 |
}
|
78 |
|
79 |
const conversation = await collections.conversations.findOne({
|
@@ -82,7 +82,7 @@ export const actions = {
|
|
82 |
});
|
83 |
|
84 |
if (!conversation) {
|
85 |
-
|
86 |
}
|
87 |
|
88 |
const filteredMessages = conversation.messages
|
|
|
18 |
shared = true;
|
19 |
|
20 |
if (!conversation) {
|
21 |
+
error(404, "Conversation not found");
|
22 |
}
|
23 |
} else {
|
24 |
// todo: add validation on params.id
|
|
|
36 |
})) !== 0;
|
37 |
|
38 |
if (conversationExists) {
|
39 |
+
error(
|
40 |
403,
|
41 |
"You don't have access to this conversation. If someone gave you this link, ask them to use the 'share' feature instead."
|
42 |
);
|
43 |
}
|
44 |
|
45 |
+
error(404, "Conversation not found.");
|
46 |
}
|
47 |
}
|
48 |
|
|
|
73 |
const messageId = data.get("messageId");
|
74 |
|
75 |
if (!messageId || typeof messageId !== "string") {
|
76 |
+
error(400, "Invalid message id");
|
77 |
}
|
78 |
|
79 |
const conversation = await collections.conversations.findOne({
|
|
|
82 |
});
|
83 |
|
84 |
if (!conversation) {
|
85 |
+
error(404, "Conversation not found");
|
86 |
}
|
87 |
|
88 |
const filteredMessages = conversation.messages
|
src/routes/conversation/[id]/+server.ts
CHANGED
@@ -33,7 +33,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
33 |
|
34 |
// check user
|
35 |
if (!userId) {
|
36 |
-
|
37 |
}
|
38 |
|
39 |
// check if the user has access to the conversation
|
@@ -56,7 +56,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
56 |
);
|
57 |
|
58 |
if (!res.acknowledged) {
|
59 |
-
|
60 |
}
|
61 |
}
|
62 |
|
@@ -66,7 +66,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
66 |
});
|
67 |
|
68 |
if (!conv) {
|
69 |
-
|
70 |
}
|
71 |
|
72 |
// register the event for ratelimiting
|
@@ -95,7 +95,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
95 |
)[0]?.messages ?? 0;
|
96 |
|
97 |
if (totalMessages > messagesBeforeLogin) {
|
98 |
-
|
99 |
}
|
100 |
}
|
101 |
|
@@ -112,12 +112,12 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
112 |
})
|
113 |
);
|
114 |
if (nEvents > usageLimits.messagesPerMinute) {
|
115 |
-
|
116 |
}
|
117 |
}
|
118 |
|
119 |
if (usageLimits?.messages && conv.messages.length > usageLimits.messages) {
|
120 |
-
|
121 |
429,
|
122 |
`This conversation has more than ${usageLimits.messages} messages. Start a new one to continue`
|
123 |
);
|
@@ -127,7 +127,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
127 |
const model = models.find((m) => m.id === conv.model);
|
128 |
|
129 |
if (!model) {
|
130 |
-
|
131 |
}
|
132 |
|
133 |
// finally parse the content of the request
|
@@ -136,7 +136,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
136 |
const json = form.get("data");
|
137 |
|
138 |
if (!json || typeof json !== "string") {
|
139 |
-
|
140 |
}
|
141 |
|
142 |
const {
|
@@ -185,7 +185,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
185 |
);
|
186 |
|
187 |
if (usageLimits?.messageLength && (newPrompt?.length ?? 0) > usageLimits.messageLength) {
|
188 |
-
|
189 |
}
|
190 |
|
191 |
// each file is either:
|
@@ -203,7 +203,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
203 |
// check sizes
|
204 |
// todo: make configurable
|
205 |
if (b64Files.some((file) => file.size > 10 * 1024 * 1024)) {
|
206 |
-
|
207 |
}
|
208 |
|
209 |
const uploadedFiles = await Promise.all(b64Files.map((file) => uploadFile(file, conv))).then(
|
@@ -219,7 +219,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
219 |
// if it's the last message and we continue then we build the prompt up to the last message
|
220 |
// we will strip the end tokens afterwards when the prompt is built
|
221 |
if ((conv.messages.find((msg) => msg.id === messageId)?.children?.length ?? 0) > 0) {
|
222 |
-
|
223 |
}
|
224 |
messageToWriteToId = messageId;
|
225 |
messagesForPrompt = buildSubtree(conv, messageId);
|
@@ -232,7 +232,7 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
232 |
const messageToRetry = conv.messages.find((message) => message.id === messageId);
|
233 |
|
234 |
if (!messageToRetry) {
|
235 |
-
|
236 |
}
|
237 |
|
238 |
if (messageToRetry.from === "user" && newPrompt) {
|
@@ -302,10 +302,10 @@ export async function POST({ request, locals, params, getClientAddress }) {
|
|
302 |
|
303 |
const messageToWriteTo = conv.messages.find((message) => message.id === messageToWriteToId);
|
304 |
if (!messageToWriteTo) {
|
305 |
-
|
306 |
}
|
307 |
if (messagesForPrompt.length === 0) {
|
308 |
-
|
309 |
}
|
310 |
|
311 |
// update the conversation with the new messages
|
@@ -491,7 +491,7 @@ export async function DELETE({ locals, params }) {
|
|
491 |
});
|
492 |
|
493 |
if (!conv) {
|
494 |
-
|
495 |
}
|
496 |
|
497 |
await collections.conversations.deleteOne({ _id: conv._id });
|
@@ -512,7 +512,7 @@ export async function PATCH({ request, locals, params }) {
|
|
512 |
});
|
513 |
|
514 |
if (!conv) {
|
515 |
-
|
516 |
}
|
517 |
|
518 |
await collections.conversations.updateOne(
|
|
|
33 |
|
34 |
// check user
|
35 |
if (!userId) {
|
36 |
+
error(401, "Unauthorized");
|
37 |
}
|
38 |
|
39 |
// check if the user has access to the conversation
|
|
|
56 |
);
|
57 |
|
58 |
if (!res.acknowledged) {
|
59 |
+
error(500, "Failed to convert conversation");
|
60 |
}
|
61 |
}
|
62 |
|
|
|
66 |
});
|
67 |
|
68 |
if (!conv) {
|
69 |
+
error(404, "Conversation not found");
|
70 |
}
|
71 |
|
72 |
// register the event for ratelimiting
|
|
|
95 |
)[0]?.messages ?? 0;
|
96 |
|
97 |
if (totalMessages > messagesBeforeLogin) {
|
98 |
+
error(429, "Exceeded number of messages before login");
|
99 |
}
|
100 |
}
|
101 |
|
|
|
112 |
})
|
113 |
);
|
114 |
if (nEvents > usageLimits.messagesPerMinute) {
|
115 |
+
error(429, ERROR_MESSAGES.rateLimited);
|
116 |
}
|
117 |
}
|
118 |
|
119 |
if (usageLimits?.messages && conv.messages.length > usageLimits.messages) {
|
120 |
+
error(
|
121 |
429,
|
122 |
`This conversation has more than ${usageLimits.messages} messages. Start a new one to continue`
|
123 |
);
|
|
|
127 |
const model = models.find((m) => m.id === conv.model);
|
128 |
|
129 |
if (!model) {
|
130 |
+
error(410, "Model not available anymore");
|
131 |
}
|
132 |
|
133 |
// finally parse the content of the request
|
|
|
136 |
const json = form.get("data");
|
137 |
|
138 |
if (!json || typeof json !== "string") {
|
139 |
+
error(400, "Invalid request");
|
140 |
}
|
141 |
|
142 |
const {
|
|
|
185 |
);
|
186 |
|
187 |
if (usageLimits?.messageLength && (newPrompt?.length ?? 0) > usageLimits.messageLength) {
|
188 |
+
error(400, "Message too long.");
|
189 |
}
|
190 |
|
191 |
// each file is either:
|
|
|
203 |
// check sizes
|
204 |
// todo: make configurable
|
205 |
if (b64Files.some((file) => file.size > 10 * 1024 * 1024)) {
|
206 |
+
error(413, "File too large, should be <10MB");
|
207 |
}
|
208 |
|
209 |
const uploadedFiles = await Promise.all(b64Files.map((file) => uploadFile(file, conv))).then(
|
|
|
219 |
// if it's the last message and we continue then we build the prompt up to the last message
|
220 |
// we will strip the end tokens afterwards when the prompt is built
|
221 |
if ((conv.messages.find((msg) => msg.id === messageId)?.children?.length ?? 0) > 0) {
|
222 |
+
error(400, "Can only continue the last message");
|
223 |
}
|
224 |
messageToWriteToId = messageId;
|
225 |
messagesForPrompt = buildSubtree(conv, messageId);
|
|
|
232 |
const messageToRetry = conv.messages.find((message) => message.id === messageId);
|
233 |
|
234 |
if (!messageToRetry) {
|
235 |
+
error(404, "Message not found");
|
236 |
}
|
237 |
|
238 |
if (messageToRetry.from === "user" && newPrompt) {
|
|
|
302 |
|
303 |
const messageToWriteTo = conv.messages.find((message) => message.id === messageToWriteToId);
|
304 |
if (!messageToWriteTo) {
|
305 |
+
error(500, "Failed to create message");
|
306 |
}
|
307 |
if (messagesForPrompt.length === 0) {
|
308 |
+
error(500, "Failed to create prompt");
|
309 |
}
|
310 |
|
311 |
// update the conversation with the new messages
|
|
|
491 |
});
|
492 |
|
493 |
if (!conv) {
|
494 |
+
error(404, "Conversation not found");
|
495 |
}
|
496 |
|
497 |
await collections.conversations.deleteOne({ _id: conv._id });
|
|
|
512 |
});
|
513 |
|
514 |
if (!conv) {
|
515 |
+
error(404, "Conversation not found");
|
516 |
}
|
517 |
|
518 |
await collections.conversations.updateOne(
|
src/routes/conversation/[id]/message/[messageId]/prompt/+server.ts
CHANGED
@@ -19,7 +19,7 @@ export async function GET({ params, locals }) {
|
|
19 |
});
|
20 |
|
21 |
if (conv === null) {
|
22 |
-
|
23 |
}
|
24 |
|
25 |
const messageId = params.messageId;
|
@@ -27,13 +27,13 @@ export async function GET({ params, locals }) {
|
|
27 |
const messageIndex = conv.messages.findIndex((msg) => msg.id === messageId);
|
28 |
|
29 |
if (!isMessageId(messageId) || messageIndex === -1) {
|
30 |
-
|
31 |
}
|
32 |
|
33 |
const model = models.find((m) => m.id === conv.model);
|
34 |
|
35 |
if (!model) {
|
36 |
-
|
37 |
}
|
38 |
|
39 |
const messagesUpTo = buildSubtree(conv, messageId);
|
|
|
19 |
});
|
20 |
|
21 |
if (conv === null) {
|
22 |
+
error(404, "Conversation not found");
|
23 |
}
|
24 |
|
25 |
const messageId = params.messageId;
|
|
|
27 |
const messageIndex = conv.messages.findIndex((msg) => msg.id === messageId);
|
28 |
|
29 |
if (!isMessageId(messageId) || messageIndex === -1) {
|
30 |
+
error(404, "Message not found");
|
31 |
}
|
32 |
|
33 |
const model = models.find((m) => m.id === conv.model);
|
34 |
|
35 |
if (!model) {
|
36 |
+
error(404, "Conversation model not found");
|
37 |
}
|
38 |
|
39 |
const messagesUpTo = buildSubtree(conv, messageId);
|
src/routes/conversation/[id]/message/[messageId]/vote/+server.ts
CHANGED
@@ -31,7 +31,7 @@ export async function POST({ params, request, locals }) {
|
|
31 |
);
|
32 |
|
33 |
if (!document.matchedCount) {
|
34 |
-
|
35 |
}
|
36 |
|
37 |
return new Response();
|
|
|
31 |
);
|
32 |
|
33 |
if (!document.matchedCount) {
|
34 |
+
error(404, "Message not found");
|
35 |
}
|
36 |
|
37 |
return new Response();
|
src/routes/conversation/[id]/output/[sha256]/+server.ts
CHANGED
@@ -13,7 +13,7 @@ export const GET: RequestHandler = async ({ locals, params }) => {
|
|
13 |
|
14 |
// check user
|
15 |
if (!userId) {
|
16 |
-
|
17 |
}
|
18 |
|
19 |
if (params.id.length !== 7) {
|
@@ -26,7 +26,7 @@ export const GET: RequestHandler = async ({ locals, params }) => {
|
|
26 |
});
|
27 |
|
28 |
if (!conv) {
|
29 |
-
|
30 |
}
|
31 |
} else {
|
32 |
// look for the conversation in shared conversations
|
@@ -35,7 +35,7 @@ export const GET: RequestHandler = async ({ locals, params }) => {
|
|
35 |
});
|
36 |
|
37 |
if (!conv) {
|
38 |
-
|
39 |
}
|
40 |
}
|
41 |
|
|
|
13 |
|
14 |
// check user
|
15 |
if (!userId) {
|
16 |
+
error(401, "Unauthorized");
|
17 |
}
|
18 |
|
19 |
if (params.id.length !== 7) {
|
|
|
26 |
});
|
27 |
|
28 |
if (!conv) {
|
29 |
+
error(404, "Conversation not found");
|
30 |
}
|
31 |
} else {
|
32 |
// look for the conversation in shared conversations
|
|
|
35 |
});
|
36 |
|
37 |
if (!conv) {
|
38 |
+
error(404, "Conversation not found");
|
39 |
}
|
40 |
}
|
41 |
|
src/routes/conversation/[id]/share/+server.ts
CHANGED
@@ -14,7 +14,7 @@ export async function POST({ params, url, locals }) {
|
|
14 |
});
|
15 |
|
16 |
if (!conversation) {
|
17 |
-
|
18 |
}
|
19 |
|
20 |
const hash = await hashConv(conversation);
|
|
|
14 |
});
|
15 |
|
16 |
if (!conversation) {
|
17 |
+
error(404, "Conversation not found");
|
18 |
}
|
19 |
|
20 |
const hash = await hashConv(conversation);
|
src/routes/conversation/[id]/stop-generating/+server.ts
CHANGED
@@ -15,7 +15,7 @@ export async function POST({ params, locals }) {
|
|
15 |
});
|
16 |
|
17 |
if (!conversation) {
|
18 |
-
|
19 |
}
|
20 |
|
21 |
await collections.abortedGenerations.updateOne(
|
|
|
15 |
});
|
16 |
|
17 |
if (!conversation) {
|
18 |
+
error(404, "Conversation not found");
|
19 |
}
|
20 |
|
21 |
await collections.abortedGenerations.updateOne(
|
src/routes/conversations/+page.server.ts
CHANGED
@@ -12,6 +12,6 @@ export const actions = {
|
|
12 |
});
|
13 |
}
|
14 |
|
15 |
-
|
16 |
},
|
17 |
};
|
|
|
12 |
});
|
13 |
}
|
14 |
|
15 |
+
redirect(303, `${base}/`);
|
16 |
},
|
17 |
};
|
src/routes/login/+page.server.ts
CHANGED
@@ -22,6 +22,6 @@ export const actions = {
|
|
22 |
{ sessionId: locals.sessionId }
|
23 |
);
|
24 |
|
25 |
-
|
26 |
},
|
27 |
};
|
|
|
22 |
{ sessionId: locals.sessionId }
|
23 |
);
|
24 |
|
25 |
+
redirect(303, authorizationUrl);
|
26 |
},
|
27 |
};
|
src/routes/login/callback/+page.server.ts
CHANGED
@@ -22,7 +22,7 @@ export async function load({ url, locals, cookies, request, getClientAddress })
|
|
22 |
.parse(Object.fromEntries(url.searchParams.entries()));
|
23 |
|
24 |
if (errorName) {
|
25 |
-
|
26 |
}
|
27 |
|
28 |
const { code, state, iss } = z
|
@@ -38,7 +38,7 @@ export async function load({ url, locals, cookies, request, getClientAddress })
|
|
38 |
const validatedToken = await validateAndParseCsrfToken(csrfToken, locals.sessionId);
|
39 |
|
40 |
if (!validatedToken) {
|
41 |
-
|
42 |
}
|
43 |
|
44 |
const { userData } = await getOIDCUserData(
|
@@ -50,14 +50,14 @@ export async function load({ url, locals, cookies, request, getClientAddress })
|
|
50 |
// Filter by allowed user emails
|
51 |
if (allowedUserEmails.length > 0) {
|
52 |
if (!userData.email) {
|
53 |
-
|
54 |
}
|
55 |
const emailVerified = userData.email_verified ?? true;
|
56 |
if (!emailVerified) {
|
57 |
-
|
58 |
}
|
59 |
if (!allowedUserEmails.includes(userData.email)) {
|
60 |
-
|
61 |
}
|
62 |
}
|
63 |
|
@@ -71,5 +71,5 @@ export async function load({ url, locals, cookies, request, getClientAddress })
|
|
71 |
ip: getClientAddress(),
|
72 |
});
|
73 |
|
74 |
-
|
75 |
}
|
|
|
22 |
.parse(Object.fromEntries(url.searchParams.entries()));
|
23 |
|
24 |
if (errorName) {
|
25 |
+
error(400, errorName + (errorDescription ? ": " + errorDescription : ""));
|
26 |
}
|
27 |
|
28 |
const { code, state, iss } = z
|
|
|
38 |
const validatedToken = await validateAndParseCsrfToken(csrfToken, locals.sessionId);
|
39 |
|
40 |
if (!validatedToken) {
|
41 |
+
error(403, "Invalid or expired CSRF token");
|
42 |
}
|
43 |
|
44 |
const { userData } = await getOIDCUserData(
|
|
|
50 |
// Filter by allowed user emails
|
51 |
if (allowedUserEmails.length > 0) {
|
52 |
if (!userData.email) {
|
53 |
+
error(403, "User not allowed: email not returned");
|
54 |
}
|
55 |
const emailVerified = userData.email_verified ?? true;
|
56 |
if (!emailVerified) {
|
57 |
+
error(403, "User not allowed: email not verified");
|
58 |
}
|
59 |
if (!allowedUserEmails.includes(userData.email)) {
|
60 |
+
error(403, "User not allowed");
|
61 |
}
|
62 |
}
|
63 |
|
|
|
71 |
ip: getClientAddress(),
|
72 |
});
|
73 |
|
74 |
+
redirect(302, `${base}/`);
|
75 |
}
|
src/routes/login/callback/updateUser.ts
CHANGED
@@ -103,7 +103,7 @@ export async function updateUser(params: {
|
|
103 |
const sessionId = await sha256(secretSessionId);
|
104 |
|
105 |
if (await collections.sessions.findOne({ sessionId })) {
|
106 |
-
|
107 |
}
|
108 |
|
109 |
locals.sessionId = sessionId;
|
|
|
103 |
const sessionId = await sha256(secretSessionId);
|
104 |
|
105 |
if (await collections.sessions.findOne({ sessionId })) {
|
106 |
+
error(500, "Session ID collision");
|
107 |
}
|
108 |
|
109 |
locals.sessionId = sessionId;
|
src/routes/logout/+page.server.ts
CHANGED
@@ -15,6 +15,6 @@ export const actions = {
|
|
15 |
secure: !dev && !(env.ALLOW_INSECURE_COOKIES === "true"),
|
16 |
httpOnly: true,
|
17 |
});
|
18 |
-
|
19 |
},
|
20 |
};
|
|
|
15 |
secure: !dev && !(env.ALLOW_INSECURE_COOKIES === "true"),
|
16 |
httpOnly: true,
|
17 |
});
|
18 |
+
redirect(303, `${base}/`);
|
19 |
},
|
20 |
};
|
src/routes/models/[...model]/+page.server.ts
CHANGED
@@ -9,7 +9,7 @@ export async function load({ params, locals, parent }) {
|
|
9 |
const data = await parent();
|
10 |
|
11 |
if (!model || model.unlisted) {
|
12 |
-
|
13 |
}
|
14 |
|
15 |
if (locals.user?._id ?? locals.sessionId) {
|
|
|
9 |
const data = await parent();
|
10 |
|
11 |
if (!model || model.unlisted) {
|
12 |
+
redirect(302, `${base}/`);
|
13 |
}
|
14 |
|
15 |
if (locals.user?._id ?? locals.sessionId) {
|
src/routes/models/[...model]/thumbnail.png/+server.ts
CHANGED
@@ -15,7 +15,7 @@ export const GET: RequestHandler = (async ({ params }) => {
|
|
15 |
const model = models.find(({ id }) => id === params.model);
|
16 |
|
17 |
if (!model || model.unlisted) {
|
18 |
-
|
19 |
}
|
20 |
const renderedComponent = (ModelThumbnail as unknown as SvelteComponent).render({
|
21 |
name: model.name,
|
|
|
15 |
const model = models.find(({ id }) => id === params.model);
|
16 |
|
17 |
if (!model || model.unlisted) {
|
18 |
+
redirect(302, `${base}/`);
|
19 |
}
|
20 |
const renderedComponent = (ModelThumbnail as unknown as SvelteComponent).render({
|
21 |
name: model.name,
|
src/routes/r/[id]/+page.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { redirect } from "@sveltejs/kit";
|
2 |
|
3 |
export const load = async ({ params }) => {
|
4 |
-
|
5 |
};
|
|
|
1 |
import { redirect } from "@sveltejs/kit";
|
2 |
|
3 |
export const load = async ({ params }) => {
|
4 |
+
redirect(302, "../conversation/" + params.id);
|
5 |
};
|
src/routes/settings/(nav)/+page.svelte
CHANGED
@@ -96,7 +96,7 @@
|
|
96 |
</p>
|
97 |
<button
|
98 |
type="submit"
|
99 |
-
class="mt-2 rounded-full bg-red-700 px-5 py-2 text-lg font-semibold text-gray-100 ring-gray-400 ring-offset-1 transition-all focus-visible:outline-none focus-visible:ring
|
100 |
>
|
101 |
Confirm deletion
|
102 |
</button>
|
|
|
96 |
</p>
|
97 |
<button
|
98 |
type="submit"
|
99 |
+
class="mt-2 rounded-full bg-red-700 px-5 py-2 text-lg font-semibold text-gray-100 ring-gray-400 ring-offset-1 transition-all hover:ring focus-visible:outline-none focus-visible:ring"
|
100 |
>
|
101 |
Confirm deletion
|
102 |
</button>
|
src/routes/settings/(nav)/[...model]/+page.ts
CHANGED
@@ -7,7 +7,7 @@ export async function load({ parent, params }) {
|
|
7 |
const model = data.models.find((m: { id: string }) => m.id === params.model);
|
8 |
|
9 |
if (!model || model.unlisted) {
|
10 |
-
|
11 |
}
|
12 |
|
13 |
return data;
|
|
|
7 |
const model = data.models.find((m: { id: string }) => m.id === params.model);
|
8 |
|
9 |
if (!model || model.unlisted) {
|
10 |
+
redirect(302, `${base}/settings`);
|
11 |
}
|
12 |
|
13 |
return data;
|
src/routes/settings/(nav)/assistants/[assistantId]/+page.server.ts
CHANGED
@@ -57,7 +57,7 @@ export const actions: Actions = {
|
|
57 |
fileId = await fileCursor.next();
|
58 |
}
|
59 |
|
60 |
-
|
61 |
},
|
62 |
report: async ({ request, params, locals, url }) => {
|
63 |
// is there already a report from this user for this model ?
|
@@ -168,7 +168,7 @@ export const actions: Actions = {
|
|
168 |
await collections.assistants.updateOne({ _id: assistant._id }, { $inc: { userCount: -1 } });
|
169 |
}
|
170 |
|
171 |
-
|
172 |
},
|
173 |
|
174 |
unfeature: async ({ params, locals }) => {
|
|
|
57 |
fileId = await fileCursor.next();
|
58 |
}
|
59 |
|
60 |
+
redirect(302, `${base}/settings`);
|
61 |
},
|
62 |
report: async ({ request, params, locals, url }) => {
|
63 |
// is there already a report from this user for this model ?
|
|
|
168 |
await collections.assistants.updateOne({ _id: assistant._id }, { $inc: { userCount: -1 } });
|
169 |
}
|
170 |
|
171 |
+
redirect(302, `${base}/settings`);
|
172 |
},
|
173 |
|
174 |
unfeature: async ({ params, locals }) => {
|
src/routes/settings/(nav)/assistants/[assistantId]/+page.ts
CHANGED
@@ -7,7 +7,7 @@ export async function load({ parent, params }) {
|
|
7 |
const assistant = data.settings.assistants.find((id) => id === params.assistantId);
|
8 |
|
9 |
if (!assistant) {
|
10 |
-
|
11 |
}
|
12 |
|
13 |
return data;
|
|
|
7 |
const assistant = data.settings.assistants.find((id) => id === params.assistantId);
|
8 |
|
9 |
if (!assistant) {
|
10 |
+
redirect(302, `${base}/assistant/${params.assistantId}`);
|
11 |
}
|
12 |
|
13 |
return data;
|
src/routes/settings/(nav)/assistants/[assistantId]/avatar.jpg/+server.ts
CHANGED
@@ -8,18 +8,18 @@ export const GET: RequestHandler = async ({ params }) => {
|
|
8 |
});
|
9 |
|
10 |
if (!assistant) {
|
11 |
-
|
12 |
}
|
13 |
|
14 |
if (!assistant.avatar) {
|
15 |
-
|
16 |
}
|
17 |
|
18 |
const fileId = collections.bucket.find({ filename: assistant._id.toString() });
|
19 |
|
20 |
const content = await fileId.next().then(async (file) => {
|
21 |
if (!file?._id) {
|
22 |
-
|
23 |
}
|
24 |
|
25 |
const fileStream = collections.bucket.openDownloadStream(file?._id);
|
|
|
8 |
});
|
9 |
|
10 |
if (!assistant) {
|
11 |
+
error(404, "No assistant found");
|
12 |
}
|
13 |
|
14 |
if (!assistant.avatar) {
|
15 |
+
error(404, "No avatar found");
|
16 |
}
|
17 |
|
18 |
const fileId = collections.bucket.find({ filename: assistant._id.toString() });
|
19 |
|
20 |
const content = await fileId.next().then(async (file) => {
|
21 |
if (!file?._id) {
|
22 |
+
error(404, "Avatar not found");
|
23 |
}
|
24 |
|
25 |
const fileStream = collections.bucket.openDownloadStream(file?._id);
|
src/routes/settings/(nav)/assistants/[assistantId]/edit/+page.server.ts
CHANGED
@@ -168,7 +168,7 @@ export const actions: Actions = {
|
|
168 |
);
|
169 |
|
170 |
if (acknowledged) {
|
171 |
-
|
172 |
} else {
|
173 |
throw Error("Update failed");
|
174 |
}
|
|
|
168 |
);
|
169 |
|
170 |
if (acknowledged) {
|
171 |
+
redirect(302, `${base}/settings/assistants/${assistant._id}`);
|
172 |
} else {
|
173 |
throw Error("Update failed");
|
174 |
}
|
src/routes/settings/(nav)/assistants/new/+page.server.ts
CHANGED
@@ -154,6 +154,6 @@ export const actions: Actions = {
|
|
154 |
$addToSet: { assistants: insertedId },
|
155 |
});
|
156 |
|
157 |
-
|
158 |
},
|
159 |
};
|
|
|
154 |
$addToSet: { assistants: insertedId },
|
155 |
});
|
156 |
|
157 |
+
redirect(302, `${base}/settings/assistants/${insertedId}`);
|
158 |
},
|
159 |
};
|
svelte.config.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import adapter from "@sveltejs/adapter-node";
|
2 |
-
import { vitePreprocess } from "@sveltejs/
|
3 |
import dotenv from "dotenv";
|
4 |
|
5 |
dotenv.config({ path: "./.env.local" });
|
|
|
1 |
import adapter from "@sveltejs/adapter-node";
|
2 |
+
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
|
3 |
import dotenv from "dotenv";
|
4 |
|
5 |
dotenv.config({ path: "./.env.local" });
|