File size: 3,686 Bytes
98051f8
 
 
3b05d51
98051f8
3b05d51
 
c202241
f13229f
6d03e59
 
725337f
8aab1a5
d7b4e1d
 
3b05d51
 
 
46db6ca
c554635
 
c85ac8f
4ae2179
c554635
46db6ca
 
 
06feee8
46db6ca
 
3b05d51
6d03e59
 
 
06feee8
6d03e59
 
361869e
c78cb53
 
06feee8
c78cb53
 
2a808d7
 
f13229f
2a808d7
32b059e
2a808d7
 
 
 
 
 
 
684165a
4ae2179
c554635
 
 
 
3b05d51
c554635
06feee8
3b05d51
c554635
7bf1507
 
c554635
2a808d7
c554635
df3243b
3b05d51
 
4a66e10
06feee8
4a66e10
 
725337f
c326265
725337f
c326265
 
 
725337f
 
 
32b059e
83b349f
 
 
 
8aab1a5
 
7bf1507
 
2a808d7
3b05d51
c554635
c78cb53
c326265
8aab1a5
 
780fd53
566c2fc
c554635
8aab1a5
 
 
 
98051f8
8aab1a5
98051f8
8aab1a5
 
a95d8a5
 
06feee8
a95d8a5
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
import type { RequestHandler } from "./$types";
import { collections } from "$lib/server/database";
import { ObjectId } from "mongodb";
import { error, redirect } from "@sveltejs/kit";
import { base } from "$app/paths";
import { z } from "zod";
import type { Message } from "$lib/types/Message";
import { models, validateModel } from "$lib/server/models";
import { v4 } from "uuid";
import { authCondition } from "$lib/server/auth";
import { usageLimits } from "$lib/server/usageLimits";
import { generatePersonaPrompt } from "$lib/types/Persona";

export const POST: RequestHandler = async ({ locals, request }) => {
	const body = await request.text();

	let title = "";

	const parsedBody = z
		.object({
			fromShare: z.string().optional(),
			model: validateModel(models),
			preprompt: z.string().optional(),
		})
		.safeParse(JSON.parse(body));

	if (!parsedBody.success) {
		error(400, "Invalid request");
	}
	const values = parsedBody.data;

	const convCount = await collections.conversations.countDocuments(authCondition(locals));

	if (usageLimits?.conversations && convCount > usageLimits?.conversations) {
		error(429, "You have reached the maximum number of conversations. Delete some to continue.");
	}

	const model = models.find((m) => (m.id || m.name) === values.model);

	if (!model) {
		error(400, "Invalid model");
	}

	let messages: Message[] = [
		{
			id: v4(),
			from: "system",
			content: values.preprompt ?? "",
			createdAt: new Date(),
			updatedAt: new Date(),
			children: [],
			ancestors: [],
		},
	];

	let rootMessageId: Message["id"] | undefined = undefined;

	if (values.fromShare) {
		const conversation = await collections.sharedConversations.findOne({
			_id: values.fromShare,
		});

		if (!conversation) {
			error(404, "Conversation not found");
		}

		// Strip <think> markers from imported titles
		title = conversation.title.replace(/<\/?think>/gi, "").trim();
		messages = conversation.messages;
		rootMessageId = conversation.rootMessageId ?? rootMessageId;
		values.model = conversation.model;
		values.preprompt = conversation.preprompt;
	}

	if (model.unlisted) {
		error(400, "Can't start a conversation with an unlisted model");
	}

	// Get user settings to retrieve active personas (use first one for conversation)
	const userSettings = await collections.settings.findOne(authCondition(locals));
	const activePersonaId = userSettings?.activePersonas?.[0] ?? "default-neutral";
	const activePersona = userSettings?.personas?.find((p) => p.id === activePersonaId);

	// Use persona prompt as preprompt, fall back to model preprompt or provided preprompt
	values.preprompt = activePersona
		? generatePersonaPrompt(activePersona)
		: (values.preprompt ?? model?.preprompt ?? "");

	if (messages && messages.length > 0 && messages[0].from === "system") {
		messages[0].content = values.preprompt;
	}

	const res = await collections.conversations.insertOne({
		_id: new ObjectId(),
		// Always store sanitized titles
		title: (title || "New Chat").replace(/<\/?think>/gi, "").trim(),
		rootMessageId,
		messages,
		model: values.model,
		preprompt: values.preprompt,
		personaId: activePersonaId, // Store persona reference
		createdAt: new Date(),
		updatedAt: new Date(),
		userAgent: request.headers.get("User-Agent") ?? undefined,
		...(locals.user ? { userId: locals.user._id } : { sessionId: locals.sessionId }),
		...(values.fromShare ? { meta: { fromShareId: values.fromShare } } : {}),
	});

	return new Response(
		JSON.stringify({
			conversationId: res.insertedId.toString(),
		}),
		{ headers: { "Content-Type": "application/json" } }
	);
};

export const GET: RequestHandler = async () => {
	redirect(302, `${base}/`);
};