Skip to content

Commit 91ec91f

Browse files
nsarrazinMishig
andauthored
Convert all assistants avatar to jpeg server-side (#762)
* Convert all assistants to jpeg server side, and rename endpoint appropriately * Improve avatar validation/error display * preserve aspect ratio on resize * Update src/lib/components/chat/ChatMessages.svelte Co-authored-by: Mishig <mishig.davaadorj@coloradocollege.edu> --------- Co-authored-by: Mishig <mishig.davaadorj@coloradocollege.edu>
1 parent 0b2a549 commit 91ec91f

File tree

11 files changed

+45
-34
lines changed

11 files changed

+45
-34
lines changed

src/lib/components/AssistantSettings.svelte

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,14 @@
5050
5151
function onFilesChange(e: Event) {
5252
const inputEl = e.target as HTMLInputElement;
53-
if (inputEl.files?.length) {
53+
if (inputEl.files?.length && inputEl.files[0].size > 0) {
54+
if (!inputEl.files[0].type.includes("image")) {
55+
inputEl.files = null;
56+
files = null;
57+
58+
form = { error: true, errors: [{ field: "avatar", message: "Only images are allowed" }] };
59+
return;
60+
}
5461
files = inputEl.files;
5562
resetErrors();
5663
deleteExistingAvatar = false;
@@ -90,6 +97,10 @@
9097
// else we just remove it from the input
9198
formData.delete("avatar");
9299
}
100+
} else {
101+
if (files === null) {
102+
formData.delete("avatar");
103+
}
93104
}
94105

95106
return async ({ result }) => {
@@ -135,7 +146,7 @@
135146
/>
136147
{:else if assistant?.avatar}
137148
<img
138-
src="{base}/settings/assistants/{assistant._id}/avatar?hash={assistant.avatar}"
149+
src="{base}/settings/assistants/{assistant._id}/avatar.jpg?hash={assistant.avatar}"
139150
alt="avatar"
140151
class="crop mx-auto h-12 w-12 cursor-pointer rounded-full object-cover"
141152
/>
@@ -169,8 +180,8 @@
169180
<CarbonUpload class="mr-2 text-xs " /> Upload
170181
</label>
171182
</div>
172-
<p class="text-xs text-red-500">{getError("avatar", form)}</p>
173183
{/if}
184+
<p class="text-xs text-red-500">{getError("avatar", form)}</p>
174185
</div>
175186

176187
<label>

src/lib/components/NavConversationItem.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
{/if}
3737
{#if conv.avatarHash}
3838
<img
39-
src="{base}/settings/assistants/{conv.assistantId}/avatar?hash={conv.avatarHash}"
39+
src="{base}/settings/assistants/{conv.assistantId}/avatar.jpg?hash={conv.avatarHash}"
4040
alt="Assistant avatar"
4141
class="mr-1.5 inline size-4 flex-none rounded-full object-cover"
4242
/>

src/lib/components/chat/AssistantIntroduction.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
>
2222
{#if assistant.avatar}
2323
<img
24-
src={`${base}/settings/assistants/${assistant._id.toString()}/avatar?hash=${
24+
src={`${base}/settings/assistants/${assistant._id.toString()}/avatar.jpg?hash=${
2525
assistant.avatar
2626
}`}
2727
alt="avatar"

src/lib/components/chat/ChatMessages.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
>
5555
{#if $page.data?.assistant.avatar}
5656
<img
57-
src="{base}/settings/assistants/{$page.data?.assistant._id.toString()}/avatar?hash=${$page
58-
.data?.assistant.avatar}"
57+
src="{base}/settings/assistants/{$page.data?.assistant._id.toString()}/avatar.jpg?hash=${$page
58+
.data.assistant.avatar}"
5959
alt="Avatar"
6060
class="size-5 rounded-full object-cover"
6161
/>

src/routes/assistant/[assistantId]/+page.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@
5050
{#if data.assistant.avatar}
5151
<img
5252
class="size-16 flex-none rounded-full object-cover sm:size-24"
53-
src="{base}/settings/assistants/{data.assistant._id}/avatar?hash={data.assistant.avatar}"
53+
src="{base}/settings/assistants/{data.assistant._id}/avatar.jpg?hash={data.assistant
54+
.avatar}"
5455
alt="avatar"
5556
/>
5657
{:else}

src/routes/assistants/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
>
8080
{#if assistant.avatar}
8181
<img
82-
src="{base}/settings/assistants/{assistant._id}/avatar"
82+
src="{base}/settings/assistants/{assistant._id}/avatar.jpg"
8383
alt="Avatar"
8484
class="mb-2 aspect-square size-12 flex-none rounded-full object-cover sm:mb-6 sm:size-20"
8585
/>

src/routes/settings/+layout.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
>
102102
{#if assistant.avatar}
103103
<img
104-
src="{base}/settings/assistants/{assistant._id.toString()}/avatar?hash={assistant.avatar}"
104+
src="{base}/settings/assistants/{assistant._id.toString()}/avatar.jpg?hash={assistant.avatar}"
105105
alt="Avatar"
106106
class="h-6 w-6 rounded-full object-cover"
107107
/>

src/routes/settings/assistants/[assistantId]/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
{#if assistant?.avatar}
3232
<!-- crop image if not square -->
3333
<img
34-
src={`${base}/settings/assistants/${assistant?._id}/avatar?hash=${assistant?.avatar}`}
34+
src={`${base}/settings/assistants/${assistant?._id}/avatar.jpg?hash=${assistant?.avatar}`}
3535
alt="Avatar"
3636
class="size-16 flex-none rounded-full object-cover sm:size-24"
3737
/>

src/routes/settings/assistants/[assistantId]/avatar/+server.ts renamed to src/routes/settings/assistants/[assistantId]/avatar.jpg/+server.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ export const GET: RequestHandler = async ({ params }) => {
1717

1818
const fileId = collections.bucket.find({ filename: assistant._id.toString() });
1919

20-
let mime = "";
21-
2220
const content = await fileId.next().then(async (file) => {
23-
mime = file?.metadata?.mime;
24-
2521
if (!file?._id) {
2622
throw error(404, "Avatar not found");
2723
}
@@ -40,7 +36,7 @@ export const GET: RequestHandler = async ({ params }) => {
4036

4137
return new Response(content, {
4238
headers: {
43-
"Content-Type": mime ?? "application/octet-stream",
39+
"Content-Type": "image/jpeg",
4440
},
4541
});
4642
};

src/routes/settings/assistants/[assistantId]/edit/+page.server.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import { fail, type Actions, redirect } from "@sveltejs/kit";
55
import { ObjectId } from "mongodb";
66

77
import { z } from "zod";
8-
import sizeof from "image-size";
98
import { sha256 } from "$lib/utils/sha256";
109

10+
import sharp from "sharp";
11+
1112
const newAsssistantSchema = z.object({
1213
name: z.string().min(1),
1314
modelId: z.string().min(1),
@@ -84,10 +85,14 @@ export const actions: Actions = {
8485

8586
let hash;
8687
if (parse.data.avatar && parse.data.avatar !== "null" && parse.data.avatar.size > 0) {
87-
const dims = sizeof(Buffer.from(await parse.data.avatar.arrayBuffer()));
88-
89-
if ((dims.height ?? 1000) > 512 || (dims.width ?? 1000) > 512) {
90-
const errors = [{ field: "avatar", message: "Avatar too big" }];
88+
let image;
89+
try {
90+
image = await sharp(await parse.data.avatar.arrayBuffer())
91+
.resize(512, 512, { fit: "inside" })
92+
.jpeg({ quality: 80 })
93+
.toBuffer();
94+
} catch (e) {
95+
const errors = [{ field: "avatar", message: (e as Error).message }];
9196
return fail(400, { error: true, errors });
9297
}
9398

@@ -100,7 +105,7 @@ export const actions: Actions = {
100105
fileId = await fileCursor.next();
101106
}
102107

103-
hash = await uploadAvatar(parse.data.avatar, assistant._id);
108+
hash = await uploadAvatar(new File([image], "avatar.jpg"), assistant._id);
104109
} else if (deleteAvatar) {
105110
// delete the avatar
106111
const fileCursor = collections.bucket.find({ filename: assistant._id.toString() });

0 commit comments

Comments
 (0)