File size: 3,544 Bytes
2e4269d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { authCondition } from "$lib/server/auth.js";
import { requiresUser } from "$lib/server/auth.js";
import { asssistantSchema } from "./utils.js";
import { uploadAssistantAvatar } from "./utils.js";
import { collections } from "$lib/server/database.js";
import { ObjectId } from "mongodb";
import sharp from "sharp";
import { generateSearchTokens } from "$lib/utils/searchTokens";
import { usageLimits } from "$lib/server/usageLimits.js";
import { ReviewStatus } from "$lib/types/Review.js";

export async function POST({ request, locals }) {
	const formData = await request.formData();
	const parse = await asssistantSchema.safeParseAsync(Object.fromEntries(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 new Response(JSON.stringify({ error: true, errors }), { status: 400 });
	}

	// 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 new Response(JSON.stringify({ error: true, errors }), { status: 400 });
	}

	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 new Response(JSON.stringify({ error: true, errors }), { status: 400 });
	}

	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 instanceof File && 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 new Response(JSON.stringify({ error: true, errors }), { status: 400 });
		}

		hash = await uploadAssistantAvatar(new File([image], "avatar.jpg"), newAssistantId);
	}

	const { insertedId } = await collections.assistants.insertOne({
		_id: newAssistantId,
		createdById,
		createdByName: locals.user?.username ?? locals.user?.name,
		...parse.data,
		tools: parse.data.tools,
		exampleInputs,
		avatar: hash,
		createdAt: new Date(),
		updatedAt: new Date(),
		userCount: 1,
		review: ReviewStatus.PRIVATE,
		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 },
	});

	return new Response(JSON.stringify({ success: true, assistantId: insertedId }), { status: 200 });
}