From f3114aef1065c27ffbe0d1f21146fc627735347a Mon Sep 17 00:00:00 2001
From: Nathan Sarrazin
Date: Wed, 24 Jan 2024 17:01:37 +0100
Subject: [PATCH] [Assistant] Delete avatar button instead of reset (#725)
* Add rate-limited image generating endpoint
* Add generate avatar button
* add little padding for firefox focus ring
* format
* fix upload image bug
* Fix uploads, replace reset by delete
* left-align buttons
* rm avatar generation feature
* final changes to delete feature
* sys prompt min height
* padding
* Add object-cover everywhere
---------
Co-authored-by: Victor Mustar
---
.env | 4 +-
src/lib/components/AssistantSettings.svelte | 109 ++++++++++--------
src/lib/components/NavConversationItem.svelte | 2 +-
src/lib/utils/generateAvatar.ts | 24 ----
src/routes/+layout.server.ts | 3 -
src/routes/settings/+layout.svelte | 2 +-
.../[assistantId]/edit/+page.server.ts | 45 +++-----
.../settings/assistants/new/+page.server.ts | 30 -----
8 files changed, 77 insertions(+), 142 deletions(-)
delete mode 100644 src/lib/utils/generateAvatar.ts
diff --git a/.env b/.env
index 421fce63526..c14a1ae41b9 100644
--- a/.env
+++ b/.env
@@ -129,6 +129,4 @@ EXPOSE_API=true
# PUBLIC_APP_DATA_SHARING=1
# PUBLIC_APP_DISCLAIMER=1
-ENABLE_ASSISTANTS=false #set to true to enable assistants feature
-ASSISTANTS_GENERATE_AVATAR=true #requires an hf token, uses the model description and name to generate an avatar using a text to image model
-TEXT_TO_IMAGE_MODEL="runwayml/stable-diffusion-v1-5"
+ENABLE_ASSISTANTS=false #set to true to enable assistants feature
\ No newline at end of file
diff --git a/src/lib/components/AssistantSettings.svelte b/src/lib/components/AssistantSettings.svelte
index 6511ee7bee0..85394e8d6cf 100644
--- a/src/lib/components/AssistantSettings.svelte
+++ b/src/lib/components/AssistantSettings.svelte
@@ -7,8 +7,8 @@
import { applyAction, enhance } from "$app/forms";
import { base } from "$app/paths";
import CarbonPen from "~icons/carbon/pen";
+ import CarbonUpload from "~icons/carbon/upload";
import { useSettingsStore } from "$lib/stores/settings";
- import { page } from "$app/stores";
import IconLoading from "./icons/IconLoading.svelte";
type ActionData = {
@@ -41,10 +41,19 @@
let inputMessage3 = assistant?.exampleInputs[2] ?? "";
let inputMessage4 = assistant?.exampleInputs[3] ?? "";
+ function resetErrors() {
+ if (form) {
+ form.errors = [];
+ form.error = false;
+ }
+ }
+
function onFilesChange(e: Event) {
const inputEl = e.target as HTMLInputElement;
if (inputEl.files?.length) {
files = inputEl.files;
+ resetErrors();
+ deleteExistingAvatar = false;
}
}
@@ -52,9 +61,9 @@
return returnForm?.errors.find((error) => error.field === field)?.message ?? "";
}
- let loading = false;
+ let deleteExistingAvatar = false;
- let generateAvatar = false;
+ let loading = false;
{/if}
-
+
-
-
+
diff --git a/src/routes/settings/assistants/[assistantId]/edit/+page.server.ts b/src/routes/settings/assistants/[assistantId]/edit/+page.server.ts
index 020bae01128..22716f4a764 100644
--- a/src/routes/settings/assistants/[assistantId]/edit/+page.server.ts
+++ b/src/routes/settings/assistants/[assistantId]/edit/+page.server.ts
@@ -7,9 +7,6 @@ import { ObjectId } from "mongodb";
import { z } from "zod";
import sizeof from "image-size";
import { sha256 } from "$lib/utils/sha256";
-import { ASSISTANTS_GENERATE_AVATAR, HF_TOKEN } from "$env/static/private";
-import { generateAvatar } from "$lib/utils/generateAvatar";
-import { timeout } from "$lib/utils/timeout";
const newAsssistantSchema = z.object({
name: z.string().min(1),
@@ -20,11 +17,7 @@ const newAsssistantSchema = z.object({
exampleInput2: z.string().optional(),
exampleInput3: z.string().optional(),
exampleInput4: z.string().optional(),
- avatar: z.instanceof(File).optional(),
- generateAvatar: z
- .literal("on")
- .optional()
- .transform((el) => !!el),
+ avatar: z.union([z.instanceof(File), z.literal("null")]).optional(),
});
const uploadAvatar = async (avatar: File, assistantId: ObjectId): Promise
=> {
@@ -87,8 +80,10 @@ export const actions: Actions = {
parse?.data?.exampleInput4 ?? "",
].filter((input) => !!input);
+ const deleteAvatar = parse.data.avatar === "null";
+
let hash;
- if (parse.data.avatar && parse.data.avatar.size > 0) {
+ if (parse.data.avatar && parse.data.avatar !== "null" && parse.data.avatar.size > 0) {
const dims = sizeof(Buffer.from(await parse.data.avatar.arrayBuffer()));
if ((dims.height ?? 1000) > 512 || (dims.width ?? 1000) > 512) {
@@ -106,28 +101,14 @@ export const actions: Actions = {
}
hash = await uploadAvatar(parse.data.avatar, assistant._id);
- } else if (
- ASSISTANTS_GENERATE_AVATAR === "true" &&
- HF_TOKEN !== "" &&
- parse.data.generateAvatar
- ) {
- try {
- const avatar = await timeout(
- generateAvatar(parse.data.description, parse.data.name),
- 30000
- );
-
- hash = await uploadAvatar(avatar, assistant._id);
- } catch (err) {
- return fail(400, {
- error: true,
- errors: [
- {
- field: "avatar",
- message: "Avatar generation failed. Try again or disable the feature.",
- },
- ],
- });
+ } else if (deleteAvatar) {
+ // delete the avatar
+ const fileCursor = collections.bucket.find({ filename: assistant._id.toString() });
+
+ let fileId = await fileCursor.next();
+ while (fileId) {
+ await collections.bucket.delete(fileId._id);
+ fileId = await fileCursor.next();
}
}
@@ -140,7 +121,7 @@ export const actions: Actions = {
createdByName: locals.user?.username ?? locals.user?.name,
...parse.data,
exampleInputs,
- avatar: hash ?? assistant.avatar,
+ avatar: deleteAvatar ? undefined : hash ?? assistant.avatar,
createdAt: new Date(),
updatedAt: new Date(),
}
diff --git a/src/routes/settings/assistants/new/+page.server.ts b/src/routes/settings/assistants/new/+page.server.ts
index 71a51dc746a..bdb077c761a 100644
--- a/src/routes/settings/assistants/new/+page.server.ts
+++ b/src/routes/settings/assistants/new/+page.server.ts
@@ -7,9 +7,6 @@ import { ObjectId } from "mongodb";
import { z } from "zod";
import sizeof from "image-size";
import { sha256 } from "$lib/utils/sha256";
-import { ASSISTANTS_GENERATE_AVATAR, HF_TOKEN } from "$env/static/private";
-import { timeout } from "$lib/utils/timeout";
-import { generateAvatar } from "$lib/utils/generateAvatar";
const newAsssistantSchema = z.object({
name: z.string().min(1),
@@ -21,10 +18,6 @@ const newAsssistantSchema = z.object({
exampleInput3: z.string().optional(),
exampleInput4: z.string().optional(),
avatar: z.instanceof(File).optional(),
- generateAvatar: z
- .literal("on")
- .optional()
- .transform((el) => !!el),
});
const uploadAvatar = async (avatar: File, assistantId: ObjectId): Promise => {
@@ -95,29 +88,6 @@ export const actions: Actions = {
}
hash = await uploadAvatar(parse.data.avatar, newAssistantId);
- } else if (
- ASSISTANTS_GENERATE_AVATAR === "true" &&
- HF_TOKEN !== "" &&
- parse.data.generateAvatar
- ) {
- try {
- const avatar = await timeout(
- generateAvatar(parse.data.description, parse.data.name),
- 30000
- );
-
- hash = await uploadAvatar(avatar, newAssistantId);
- } catch (err) {
- return fail(400, {
- error: true,
- errors: [
- {
- field: "avatar",
- message: "Avatar generation failed. Try again or disable the feature.",
- },
- ],
- });
- }
}
const { insertedId } = await collections.assistants.insertOne({