Skip to content

Commit 5f3f7cc

Browse files
authored
refactor: api cleanup (#1849)
1 parent acdd8de commit 5f3f7cc

File tree

30 files changed

+399
-402
lines changed

30 files changed

+399
-402
lines changed

package-lock.json

Lines changed: 43 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"prettier-plugin-tailwindcss": "^0.6.11",
6161
"prom-client": "^15.1.2",
6262
"sade": "^1.8.1",
63+
"superjson": "^2.2.2",
6364
"svelte": "^5.33.3",
6465
"svelte-check": "^4.0.0",
6566
"svelte-gestures": "^5.1.3",

src/lib/APIClient.ts

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { App } from "$api";
22
import { base } from "$app/paths";
33
import { treaty, type Treaty } from "@elysiajs/eden";
44
import { browser } from "$app/environment";
5+
import superjson from "superjson";
56

67
export function useAPIClient({ fetch }: { fetch?: Treaty.Config["fetcher"] } = {}) {
78
let url;
@@ -26,30 +27,26 @@ export function useAPIClient({ fetch }: { fetch?: Treaty.Config["fetcher"] } = {
2627
url = `${window.location.origin}${base}/api/v2`;
2728
}
2829
const app = treaty<App>(url, { fetcher: fetch });
29-
3030
return app;
3131
}
3232

33-
export function throwOnErrorNullable<T extends Record<number, unknown>>(
33+
export function handleResponse<T extends Record<number, unknown>>(
3434
response: Treaty.TreatyResponse<T>
3535
): T[200] {
3636
if (response.error) {
3737
throw new Error(JSON.stringify(response.error));
3838
}
3939

40-
return response.data as T[200];
40+
return superjson.parse(
41+
typeof response.data === "string" ? response.data : JSON.stringify(response.data)
42+
) as T[200];
4143
}
4244

43-
export function throwOnError<T extends Record<number, unknown>>(
44-
response: Treaty.TreatyResponse<T>
45-
): NonNullable<T[200]> {
46-
if (response.error) {
47-
throw new Error(JSON.stringify(response.error));
48-
}
49-
50-
if (response.data === null) {
51-
throw new Error("No data received on API call");
45+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
46+
export type Success<T extends (...args: any) => any> =
47+
Awaited<ReturnType<T>> extends {
48+
data: infer D;
49+
error: unknown;
5250
}
53-
54-
return response.data as NonNullable<T[200]>;
55-
}
51+
? D
52+
: never;

src/lib/components/AssistantSettings.svelte

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@
5555
let inputMessage3 = $state(assistant?.exampleInputs[2] ?? "");
5656
let inputMessage4 = $state(assistant?.exampleInputs[3] ?? "");
5757
58-
function resetErrors() {
59-
errors = [];
58+
function clearError(field: string) {
59+
errors = errors.filter((e) => e.field !== field);
6060
}
6161
6262
function onFilesChange(e: Event) {
@@ -70,7 +70,7 @@
7070
return;
7171
}
7272
files = inputEl.files;
73-
resetErrors();
73+
clearError("avatar");
7474
deleteExistingAvatar = false;
7575
}
7676
}
@@ -164,6 +164,7 @@
164164
} else {
165165
$error = response.statusText;
166166
}
167+
loading = false;
167168
}
168169
} else {
169170
response = await fetch(`${base}/api/assistant`, {
@@ -181,6 +182,7 @@
181182
} else {
182183
$error = response.statusText;
183184
}
185+
loading = false;
184186
}
185187
}
186188
}}
@@ -245,6 +247,7 @@
245247
e.stopPropagation();
246248
files = null;
247249
deleteExistingAvatar = true;
250+
clearError("avatar");
248251
}}
249252
class="mx-auto w-max text-center text-xs text-gray-600 hover:underline"
250253
>
@@ -271,6 +274,7 @@
271274
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
272275
placeholder="Assistant Name"
273276
value={assistant?.name ?? ""}
277+
oninput={() => clearError("name")}
274278
/>
275279
<p class="text-xs text-red-500">{getError("name")}</p>
276280
</label>
@@ -282,6 +286,7 @@
282286
class="h-15 w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
283287
placeholder="It knows everything about python"
284288
value={assistant?.description ?? ""}
289+
oninput={() => clearError("description")}
285290
></textarea>
286291
<p class="text-xs text-red-500">{getError("description")}</p>
287292
</label>
@@ -293,6 +298,7 @@
293298
name="modelId"
294299
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
295300
bind:value={modelId}
301+
onchange={() => clearError("modelId")}
296302
>
297303
{#each models.filter((model) => !model.unlisted) as model}
298304
<option value={model.id}>{model.displayName}</option>
@@ -415,25 +421,29 @@
415421
placeholder="Start Message 1"
416422
bind:value={inputMessage1}
417423
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
424+
oninput={() => clearError("inputMessage1")}
418425
/>
419426
<input
420427
name="exampleInput2"
421428
placeholder="Start Message 2"
422429
bind:value={inputMessage2}
423430
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
431+
oninput={() => clearError("inputMessage1")}
424432
/>
425433

426434
<input
427435
name="exampleInput3"
428436
placeholder="Start Message 3"
429437
bind:value={inputMessage3}
430438
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
439+
oninput={() => clearError("inputMessage1")}
431440
/>
432441
<input
433442
name="exampleInput4"
434443
placeholder="Start Message 4"
435444
bind:value={inputMessage4}
436445
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
446+
oninput={() => clearError("inputMessage1")}
437447
/>
438448
</div>
439449
<p class="text-xs text-red-500">{getError("inputMessage1")}</p>
@@ -524,6 +534,7 @@
524534
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
525535
placeholder="wikipedia.org,bbc.com"
526536
value={assistant?.rag?.allowedDomains?.join(",") ?? ""}
537+
oninput={() => clearError("ragDomainList")}
527538
/>
528539
<p class="text-xs text-red-500">{getError("ragDomainList")}</p>
529540
{/if}
@@ -550,6 +561,7 @@
550561
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
551562
placeholder="https://raw.githubusercontent.com/huggingface/chat-ui/main/README.md"
552563
value={assistant?.rag?.allowedLinks.join(",") ?? ""}
564+
oninput={() => clearError("ragLinkList")}
553565
/>
554566
<p class="text-xs text-red-500">{getError("ragLinkList")}</p>
555567
{/if}
@@ -605,6 +617,7 @@
605617
class="min-h-[8lh] flex-1 rounded-lg border-2 border-gray-200 bg-gray-100 p-2 text-sm"
606618
placeholder="You'll act as..."
607619
bind:value={systemPrompt}
620+
oninput={() => clearError("preprompt")}
608621
></textarea>
609622
{#if modelId}
610623
{@const model = models.find((_model) => _model.id === modelId)}

src/lib/components/NavConversationItem.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
onclick={(e) => {
9494
e.preventDefault();
9595
confirmDelete = false;
96-
dispatch("deleteConversation", conv.id);
96+
dispatch("deleteConversation", conv.id.toString());
9797
}}
9898
>
9999
<CarbonCheckmark
@@ -109,7 +109,7 @@
109109
e.preventDefault();
110110
const newTitle = prompt("Edit this conversation title:", conv.title);
111111
if (!newTitle) return;
112-
dispatch("editConversationTitle", { id: conv.id, title: newTitle });
112+
dispatch("editConversationTitle", { id: conv.id.toString(), title: newTitle });
113113
}}
114114
>
115115
<CarbonEdit class="text-xs text-gray-400 hover:text-gray-500 dark:hover:text-gray-300" />
@@ -122,7 +122,7 @@
122122
onclick={(event) => {
123123
event.preventDefault();
124124
if (event.shiftKey) {
125-
dispatch("deleteConversation", conv.id);
125+
dispatch("deleteConversation", conv.id.toString());
126126
} else {
127127
confirmDelete = true;
128128
}

src/lib/components/NavMenu.svelte

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@
2929
import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
3030
3131
import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
32-
import { useAPIClient, throwOnError } from "$lib/APIClient";
33-
import { jsonSerialize } from "$lib/utils/serialize";
32+
import { useAPIClient, handleResponse } from "$lib/APIClient";
3433
3534
const publicConfig = usePublicConfig();
3635
const client = useAPIClient();
@@ -77,13 +76,8 @@
7776
p,
7877
},
7978
})
80-
.then(throwOnError)
81-
.then(({ conversations }) =>
82-
conversations.map((conv) => ({
83-
...jsonSerialize(conv),
84-
updatedAt: new Date(conv.updatedAt),
85-
}))
86-
)
79+
.then(handleResponse)
80+
.then((r) => r.conversations)
8781
.catch(() => []);
8882
8983
if (newConvs.length === 0) {

src/lib/components/ToolBadge.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import ToolLogo from "./ToolLogo.svelte";
33
import { base } from "$app/paths";
44
import { browser } from "$app/environment";
5-
import { throwOnError, useAPIClient } from "$lib/APIClient";
5+
import { handleResponse, useAPIClient } from "$lib/APIClient";
66
77
interface Props {
88
toolId: string;
@@ -17,7 +17,7 @@
1717
class="relative flex items-center justify-center space-x-2 rounded border border-gray-300 bg-gray-200 px-2 py-1"
1818
>
1919
{#if browser}
20-
{#await client.tools({ id: toolId }).get().then(throwOnError) then value}
20+
{#await client.tools({ id: toolId }).get().then(handleResponse) then value}
2121
{#key value.color + value.icon}
2222
<ToolLogo color={value.color} icon={value.icon} size="sm" />
2323
{/key}

src/lib/components/chat/AssistantIntroduction.svelte

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@
1818
import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
1919
2020
import { page } from "$app/state";
21-
import type { Serialize } from "$lib/utils/serialize";
2221
2322
const publicConfig = usePublicConfig();
2423
2524
interface Props {
2625
models: Model[];
2726
assistant: Pick<
28-
Serialize<Assistant>,
27+
Assistant,
2928
| "avatar"
3029
| "name"
3130
| "rag"

src/lib/components/chat/ChatInput.svelte

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import { captureScreen } from "$lib/utils/screenshot";
2424
import IconScreenshot from "../icons/IconScreenshot.svelte";
2525
import { loginModalOpen } from "$lib/stores/loginModal";
26-
import type { Serialize } from "$lib/utils/serialize";
2726
2827
import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
2928
interface Props {
@@ -33,7 +32,7 @@
3332
placeholder?: string;
3433
loading?: boolean;
3534
disabled?: boolean;
36-
assistant?: Serialize<Assistant> | undefined;
35+
assistant?: Assistant | undefined;
3736
modelHasTools?: boolean;
3837
modelIsMultimodal?: boolean;
3938
children?: import("svelte").Snippet;

src/lib/components/chat/ChatWindow.svelte

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import { cubicInOut } from "svelte/easing";
3838
import type { ToolFront } from "$lib/types/Tool";
3939
import { loginModalOpen } from "$lib/stores/loginModal";
40-
import type { Serialize } from "$lib/utils/serialize";
4140
import { beforeNavigate } from "$app/navigation";
4241
import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
4342
@@ -49,7 +48,7 @@
4948
shared?: boolean;
5049
currentModel: Model;
5150
models: Model[];
52-
assistant?: Serialize<Assistant> | undefined;
51+
assistant?: Assistant | undefined;
5352
preprompt?: string | undefined;
5453
files?: File[];
5554
}

0 commit comments

Comments
 (0)