Spaces:
Sleeping
Sleeping
File size: 9,177 Bytes
98051f8 220c723 c202241 566c2fc a8a9533 df3243b 0c3e3b2 2e21e16 0c3e3b2 69c6804 5290cbb 2f4d50b 5290cbb 220c723 911412b d7b4e1d 220c723 c202241 df3243b c202241 1f36355 c202241 4a66e10 a8a9533 df3243b 256631f a1a6daf df3243b 9d36148 5290cbb df3243b dbf722e 9d36148 df3243b a8a9533 17605e5 7bcf4d9 17605e5 7bcf4d9 17605e5 2e21e16 0c3e3b2 256631f 0c3e3b2 256631f 0c3e3b2 2f4d50b 9d36148 575fe85 9d36148 911412b 4f76934 a8a9533 c7a65c3 a8a9533 037df62 4f76934 e99e7c2 911412b 566c2fc cde6ab6 e99e7c2 11983d2 dbf722e 0c3e3b2 d3e9153 821697c 911412b 01b06a3 c85ac8f 01b06a3 95af686 ff934bb 01b06a3 95af686 01b06a3 7a3250d 3c216a4 b1253fd 01b06a3 11983d2 241ba68 aa59751 dc6961c 4a66e10 cdc7abc 01b06a3 c202241 0c3e3b2 b104edb a1a6daf 0c3e3b2 eb4ddb7 69c6804 eb4ddb7 9d36148 018a142 df3243b 018a142 f61126a 3e99a64 0ab6df0 018a142 256631f df3243b a8a9533 6a5e4c9 cc38b64 2f4d50b |
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 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
import type { LayoutServerLoad } from "./$types";
import { collections } from "$lib/server/database";
import type { Conversation } from "$lib/types/Conversation";
import { UrlDependency } from "$lib/types/UrlDependency";
import { defaultModel, models, oldModels, validateModel } from "$lib/server/models";
import { authCondition, requiresUser } from "$lib/server/auth";
import { DEFAULT_SETTINGS } from "$lib/types/Settings";
import { env } from "$env/dynamic/private";
import { ObjectId } from "mongodb";
import type { ConvSidebar } from "$lib/types/ConvSidebar";
import { toolFromConfigs } from "$lib/server/tools";
import { MetricsServer } from "$lib/server/metrics";
import type { ToolFront, ToolInputFile } from "$lib/types/Tool";
import { ReviewStatus } from "$lib/types/Review";
import { base } from "$app/paths";
export const load: LayoutServerLoad = async ({ locals, depends, fetch }) => {
depends(UrlDependency.ConversationList);
const settings = await collections.settings.findOne(authCondition(locals));
// If the active model in settings is not valid, set it to the default model. This can happen if model was disabled.
if (
settings &&
!validateModel(models).safeParse(settings?.activeModel).success &&
!settings.assistants?.map((el) => el.toString())?.includes(settings?.activeModel)
) {
settings.activeModel = defaultModel.id;
await collections.settings.updateOne(authCondition(locals), {
$set: { activeModel: defaultModel.id },
});
}
// if the model is unlisted, set the active model to the default model
if (
settings?.activeModel &&
models.find((m) => m.id === settings?.activeModel)?.unlisted === true
) {
settings.activeModel = defaultModel.id;
await collections.settings.updateOne(authCondition(locals), {
$set: { activeModel: defaultModel.id },
});
}
const enableAssistants = env.ENABLE_ASSISTANTS === "true";
const assistantActive = !models.map(({ id }) => id).includes(settings?.activeModel ?? "");
const assistant = assistantActive
? await collections.assistants.findOne({
_id: new ObjectId(settings?.activeModel),
})
: null;
const nConversations = await collections.conversations.countDocuments(authCondition(locals));
const conversations =
nConversations === 0
? Promise.resolve([])
: fetch(`${base}/api/conversations`)
.then((res) => res.json())
.then(
(
convs: Pick<Conversation, "_id" | "title" | "updatedAt" | "model" | "assistantId">[]
) =>
convs.map((conv) => ({
...conv,
updatedAt: new Date(conv.updatedAt),
}))
);
const userAssistants = settings?.assistants?.map((assistantId) => assistantId.toString()) ?? [];
const userAssistantsSet = new Set(userAssistants);
const assistants = conversations.then((conversations) =>
collections.assistants
.find({
_id: {
$in: [
...userAssistants.map((el) => new ObjectId(el)),
...(conversations.map((conv) => conv.assistantId).filter((el) => !!el) as ObjectId[]),
],
},
})
.toArray()
);
const messagesBeforeLogin = env.MESSAGES_BEFORE_LOGIN ? parseInt(env.MESSAGES_BEFORE_LOGIN) : 0;
let loginRequired = false;
if (requiresUser && !locals.user) {
if (messagesBeforeLogin === 0) {
loginRequired = true;
} else if (nConversations >= messagesBeforeLogin) {
loginRequired = true;
} else {
// get the number of messages where `from === "assistant"` across all conversations.
const totalMessages =
(
await collections.conversations
.aggregate([
{ $match: { ...authCondition(locals), "messages.from": "assistant" } },
{ $project: { messages: 1 } },
{ $limit: messagesBeforeLogin + 1 },
{ $unwind: "$messages" },
{ $match: { "messages.from": "assistant" } },
{ $count: "messages" },
])
.toArray()
)[0]?.messages ?? 0;
loginRequired = totalMessages >= messagesBeforeLogin;
}
}
const toolUseDuration = (await MetricsServer.getMetrics().tool.toolUseDuration.get()).values;
const configToolIds = toolFromConfigs.map((el) => el._id.toString());
let activeCommunityToolIds = (settings?.tools ?? []).filter(
(key) => !configToolIds.includes(key)
);
if (assistant) {
activeCommunityToolIds = [...activeCommunityToolIds, ...(assistant.tools ?? [])];
}
const communityTools = await collections.tools
.find({ _id: { $in: activeCommunityToolIds.map((el) => new ObjectId(el)) } })
.toArray()
.then((tools) =>
tools.map((tool) => ({
...tool,
isHidden: false,
isOnByDefault: true,
isLocked: true,
}))
);
return {
nConversations,
conversations: await conversations.then(
async (convs) =>
await Promise.all(
convs.map(async (conv) => {
if (settings?.hideEmojiOnSidebar) {
conv.title = conv.title.replace(/\p{Emoji}/gu, "");
}
// remove invalid unicode and trim whitespaces
conv.title = conv.title.replace(/\uFFFD/gu, "").trimStart();
let avatarUrl: string | undefined = undefined;
if (conv.assistantId) {
const hash = (
await collections.assistants.findOne({
_id: new ObjectId(conv.assistantId),
})
)?.avatar;
if (hash) {
avatarUrl = `/settings/assistants/${conv.assistantId}/avatar.jpg?hash=${hash}`;
}
}
return {
id: conv._id.toString(),
title: conv.title,
model: conv.model ?? defaultModel,
updatedAt: conv.updatedAt,
assistantId: conv.assistantId?.toString(),
avatarUrl,
} satisfies ConvSidebar;
})
)
),
settings: {
searchEnabled: !!(
env.SERPAPI_KEY ||
env.SERPER_API_KEY ||
env.SERPSTACK_API_KEY ||
env.SEARCHAPI_KEY ||
env.YDC_API_KEY ||
env.USE_LOCAL_WEBSEARCH ||
env.SEARXNG_QUERY_URL ||
env.BING_SUBSCRIPTION_KEY
),
ethicsModalAccepted: !!settings?.ethicsModalAcceptedAt,
ethicsModalAcceptedAt: settings?.ethicsModalAcceptedAt ?? null,
activeModel: settings?.activeModel ?? DEFAULT_SETTINGS.activeModel,
hideEmojiOnSidebar: settings?.hideEmojiOnSidebar ?? false,
shareConversationsWithModelAuthors:
settings?.shareConversationsWithModelAuthors ??
DEFAULT_SETTINGS.shareConversationsWithModelAuthors,
customPrompts: settings?.customPrompts ?? {},
assistants: userAssistants,
tools:
settings?.tools ??
toolFromConfigs
.filter((el) => !el.isHidden && el.isOnByDefault)
.map((el) => el._id.toString()),
disableStream: settings?.disableStream ?? DEFAULT_SETTINGS.disableStream,
directPaste: settings?.directPaste ?? DEFAULT_SETTINGS.directPaste,
},
models: models.map((model) => ({
id: model.id,
name: model.name,
websiteUrl: model.websiteUrl,
modelUrl: model.modelUrl,
tokenizer: model.tokenizer,
datasetName: model.datasetName,
datasetUrl: model.datasetUrl,
displayName: model.displayName,
description: model.description,
reasoning: !!model.reasoning,
logoUrl: model.logoUrl,
promptExamples: model.promptExamples,
parameters: model.parameters,
preprompt: model.preprompt,
multimodal: model.multimodal,
multimodalAcceptedMimetypes: model.multimodalAcceptedMimetypes,
tools: model.tools,
unlisted: model.unlisted,
hasInferenceAPI: model.hasInferenceAPI,
})),
oldModels,
tools: [...toolFromConfigs, ...communityTools]
.filter((tool) => !tool?.isHidden)
.map(
(tool) =>
({
_id: tool._id.toString(),
type: tool.type,
displayName: tool.displayName,
name: tool.name,
description: tool.description,
mimeTypes: (tool.inputs ?? [])
.filter((input): input is ToolInputFile => input.type === "file")
.map((input) => (input as ToolInputFile).mimeTypes)
.flat(),
isOnByDefault: tool.isOnByDefault ?? true,
isLocked: tool.isLocked ?? true,
timeToUseMS:
toolUseDuration.find(
(el) => el.labels.tool === tool._id.toString() && el.labels.quantile === 0.9
)?.value ?? 15_000,
color: tool.color,
icon: tool.icon,
}) satisfies ToolFront
),
communityToolCount: await collections.tools.countDocuments({
type: "community",
review: ReviewStatus.APPROVED,
}),
assistants: assistants.then((assistants) =>
assistants
.filter((el) => userAssistantsSet.has(el._id.toString()))
.map((el) => ({
...el,
_id: el._id.toString(),
createdById: undefined,
createdByMe:
el.createdById.toString() === (locals.user?._id ?? locals.sessionId).toString(),
}))
),
user: locals.user && {
id: locals.user._id.toString(),
username: locals.user.username,
avatarUrl: locals.user.avatarUrl,
email: locals.user.email,
logoutDisabled: locals.user.logoutDisabled,
isAdmin: locals.user.isAdmin ?? false,
isEarlyAccess: locals.user.isEarlyAccess ?? false,
},
assistant: assistant ? JSON.parse(JSON.stringify(assistant)) : null,
enableAssistants,
enableAssistantsRAG: env.ENABLE_ASSISTANTS_RAG === "true",
enableCommunityTools: env.COMMUNITY_TOOLS === "true",
loginRequired,
loginEnabled: requiresUser,
guestMode: requiresUser && messagesBeforeLogin > 0,
};
};
|