Spaces:
Running
Running
File size: 5,192 Bytes
992a8de 91ec91f 3f5871c 537b6f5 10dbbd6 992a8de 3f5871c 6887755 d4016bc 992a8de a4c3fca 537b6f5 992a8de 91ec91f 992a8de 91ec91f 992a8de 786115c 0b2a549 3f5871c 6887755 10dbbd6 a4c3fca d4016bc 992a8de 786115c 992a8de |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
import { base } from "$app/paths";
import { authCondition, requiresUser } from "$lib/server/auth";
import { collections } from "$lib/server/database";
import { fail, type Actions, redirect } from "@sveltejs/kit";
import { ObjectId } from "mongodb";
import { z } from "zod";
import { sha256 } from "$lib/utils/sha256";
import sharp from "sharp";
import { parseStringToList } from "$lib/utils/parseStringToList";
import { usageLimits } from "$lib/server/usageLimits";
import { generateSearchTokens } from "$lib/utils/searchTokens";
const newAsssistantSchema = z.object({
name: z.string().min(1),
modelId: z.string().min(1),
preprompt: z.string().min(1),
description: z.string().optional(),
exampleInput1: z.string().optional(),
exampleInput2: z.string().optional(),
exampleInput3: z.string().optional(),
exampleInput4: z.string().optional(),
avatar: z.instanceof(File).optional(),
ragLinkList: z.preprocess(parseStringToList, z.string().url().array().max(10)),
ragDomainList: z.preprocess(parseStringToList, z.string().array()),
ragAllowAll: z.preprocess((v) => v === "true", z.boolean()),
dynamicPrompt: z.preprocess((v) => v === "on", z.boolean()),
temperature: z
.union([z.literal(""), z.coerce.number().min(0.1).max(2)])
.transform((v) => (v === "" ? undefined : v)),
top_p: z
.union([z.literal(""), z.coerce.number().min(0.05).max(1)])
.transform((v) => (v === "" ? undefined : v)),
repetition_penalty: z
.union([z.literal(""), z.coerce.number().min(0.1).max(2)])
.transform((v) => (v === "" ? undefined : v)),
top_k: z
.union([z.literal(""), z.coerce.number().min(5).max(100)])
.transform((v) => (v === "" ? undefined : v)),
});
const uploadAvatar = async (avatar: File, assistantId: ObjectId): Promise<string> => {
const hash = await sha256(await avatar.text());
const upload = collections.bucket.openUploadStream(`${assistantId.toString()}`, {
metadata: { type: avatar.type, hash },
});
upload.write((await avatar.arrayBuffer()) as unknown as Buffer);
upload.end();
// only return the filename when upload throws a finish event or a 10s time out occurs
return new Promise((resolve, reject) => {
upload.once("finish", () => resolve(hash));
upload.once("error", reject);
setTimeout(() => reject(new Error("Upload timed out")), 10000);
});
};
export const actions: Actions = {
default: async ({ request, locals }) => {
const formData = Object.fromEntries(await request.formData());
const parse = newAsssistantSchema.safeParse(formData);
if (!parse.success) {
// Loop through the errors array and create a custom errors array
const errors = parse.error.errors.map((error) => {
return {
field: error.path[0],
message: error.message,
};
});
return fail(400, { error: true, errors });
}
// can only create assistants when logged in, IF login is setup
if (!locals.user && requiresUser) {
const errors = [{ field: "preprompt", message: "Must be logged in. Unauthorized" }];
return fail(400, { error: true, errors });
}
const createdById = locals.user?._id ?? locals.sessionId;
const assistantsCount = await collections.assistants.countDocuments({ createdById });
if (usageLimits?.assistants && assistantsCount > usageLimits.assistants) {
const errors = [
{
field: "preprompt",
message: "You have reached the maximum number of assistants. Delete some to continue.",
},
];
return fail(400, { error: true, errors });
}
const newAssistantId = new ObjectId();
const exampleInputs: string[] = [
parse?.data?.exampleInput1 ?? "",
parse?.data?.exampleInput2 ?? "",
parse?.data?.exampleInput3 ?? "",
parse?.data?.exampleInput4 ?? "",
].filter((input) => !!input);
let hash;
if (parse.data.avatar && parse.data.avatar.size > 0) {
let image;
try {
image = await sharp(await parse.data.avatar.arrayBuffer())
.resize(512, 512, { fit: "inside" })
.jpeg({ quality: 80 })
.toBuffer();
} catch (e) {
const errors = [{ field: "avatar", message: (e as Error).message }];
return fail(400, { error: true, errors });
}
hash = await uploadAvatar(new File([image], "avatar.jpg"), newAssistantId);
}
const { insertedId } = await collections.assistants.insertOne({
_id: newAssistantId,
createdById,
createdByName: locals.user?.username ?? locals.user?.name,
...parse.data,
exampleInputs,
avatar: hash,
createdAt: new Date(),
updatedAt: new Date(),
userCount: 1,
featured: false,
rag: {
allowedLinks: parse.data.ragLinkList,
allowedDomains: parse.data.ragDomainList,
allowAllDomains: parse.data.ragAllowAll,
},
dynamicPrompt: parse.data.dynamicPrompt,
searchTokens: generateSearchTokens(parse.data.name),
last24HoursCount: 0,
generateSettings: {
temperature: parse.data.temperature,
top_p: parse.data.top_p,
repetition_penalty: parse.data.repetition_penalty,
top_k: parse.data.top_k,
},
});
// add insertedId to user settings
await collections.settings.updateOne(authCondition(locals), {
$addToSet: { assistants: insertedId },
});
throw redirect(302, `${base}/settings/assistants/${insertedId}`);
},
};
|