| import readline from "readline"; |
| import minimist from "minimist"; |
|
|
| |
| import { env } from "$env/dynamic/private"; |
|
|
| import { faker } from "@faker-js/faker"; |
| import { ObjectId } from "mongodb"; |
|
|
| |
| import { collections } from "$lib/server/database"; |
| import { models } from "../src/lib/server/models.ts"; |
| import type { User } from "../src/lib/types/User"; |
| import type { Assistant } from "../src/lib/types/Assistant"; |
| import type { Conversation } from "../src/lib/types/Conversation"; |
| import type { Settings } from "../src/lib/types/Settings"; |
| import { defaultEmbeddingModel } from "../src/lib/server/embeddingModels.ts"; |
| import { Message } from "../src/lib/types/Message.ts"; |
|
|
| import { addChildren } from "../src/lib/utils/tree/addChildren.ts"; |
| import { generateSearchTokens } from "../src/lib/utils/searchTokens.ts"; |
|
|
| const rl = readline.createInterface({ |
| input: process.stdin, |
| output: process.stdout, |
| }); |
|
|
| rl.on("close", function () { |
| process.exit(0); |
| }); |
|
|
| const possibleFlags = ["reset", "all", "users", "settings", "assistants", "conversations"]; |
| const argv = minimist(process.argv.slice(2)); |
| const flags = argv["_"].filter((flag) => possibleFlags.includes(flag)); |
|
|
| async function generateMessages(preprompt?: string): Promise<Message[]> { |
| const isLinear = faker.datatype.boolean(0.5); |
| const isInterrupted = faker.datatype.boolean(0.05); |
|
|
| const messages: Message[] = []; |
|
|
| messages.push({ |
| id: crypto.randomUUID(), |
| from: "system", |
| content: preprompt ?? "", |
| createdAt: faker.date.recent({ days: 30 }), |
| updatedAt: faker.date.recent({ days: 30 }), |
| }); |
|
|
| let isUser = true; |
| let lastId = messages[0].id; |
| if (isLinear) { |
| const convLength = faker.number.int({ min: 1, max: 25 }) * 2; |
|
|
| for (let i = 0; i < convLength; i++) { |
| lastId = addChildren( |
| { |
| messages, |
| rootMessageId: messages[0].id, |
| }, |
| { |
| from: isUser ? "user" : "assistant", |
| content: faker.lorem.sentence({ |
| min: 10, |
| max: isUser ? 50 : 200, |
| }), |
| createdAt: faker.date.recent({ days: 30 }), |
| updatedAt: faker.date.recent({ days: 30 }), |
| interrupted: i === convLength - 1 && isInterrupted, |
| }, |
| lastId |
| ); |
| isUser = !isUser; |
| } |
| } else { |
| const convLength = faker.number.int({ min: 2, max: 200 }); |
|
|
| for (let i = 0; i < convLength; i++) { |
| addChildren( |
| { |
| messages, |
| rootMessageId: messages[0].id, |
| }, |
| { |
| from: isUser ? "user" : "assistant", |
| content: faker.lorem.sentence({ |
| min: 10, |
| max: isUser ? 50 : 200, |
| }), |
| createdAt: faker.date.recent({ days: 30 }), |
| updatedAt: faker.date.recent({ days: 30 }), |
| interrupted: i === convLength - 1 && isInterrupted, |
| }, |
| faker.helpers.arrayElement([ |
| messages[0].id, |
| ...messages.filter((m) => m.from === (isUser ? "assistant" : "user")).map((m) => m.id), |
| ]) |
| ); |
|
|
| isUser = !isUser; |
| } |
| } |
| return messages; |
| } |
|
|
| async function seed() { |
| console.log("Seeding..."); |
| const modelIds = models.map((model) => model.id); |
|
|
| if (flags.includes("reset")) { |
| console.log("Starting reset of DB"); |
| await collections.users.deleteMany({}); |
| await collections.settings.deleteMany({}); |
| await collections.assistants.deleteMany({}); |
| await collections.conversations.deleteMany({}); |
| console.log("Reset done"); |
| } |
|
|
| if (flags.includes("users") || flags.includes("all")) { |
| console.log("Creating 100 new users"); |
| const newUsers: User[] = Array.from({ length: 100 }, () => ({ |
| _id: new ObjectId(), |
| createdAt: faker.date.recent({ days: 30 }), |
| updatedAt: faker.date.recent({ days: 30 }), |
| username: faker.internet.userName(), |
| name: faker.person.fullName(), |
| hfUserId: faker.string.alphanumeric(24), |
| avatarUrl: faker.image.avatar(), |
| })); |
|
|
| await collections.users.insertMany(newUsers); |
| console.log("Done creating users."); |
| } |
|
|
| const users = await collections.users.find().toArray(); |
| if (flags.includes("settings") || flags.includes("all")) { |
| console.log("Updating settings for all users"); |
| users.forEach(async (user) => { |
| const settings: Settings = { |
| userId: user._id, |
| shareConversationsWithModelAuthors: faker.datatype.boolean(0.25), |
| hideEmojiOnSidebar: faker.datatype.boolean(0.25), |
| ethicsModalAcceptedAt: faker.date.recent({ days: 30 }), |
| activeModel: faker.helpers.arrayElement(modelIds), |
| createdAt: faker.date.recent({ days: 30 }), |
| updatedAt: faker.date.recent({ days: 30 }), |
| customPrompts: {}, |
| assistants: [], |
| }; |
| await collections.settings.updateOne( |
| { userId: user._id }, |
| { $set: { ...settings } }, |
| { upsert: true } |
| ); |
| }); |
| console.log("Done updating settings."); |
| } |
|
|
| if (flags.includes("assistants") || flags.includes("all")) { |
| console.log("Creating assistants for all users"); |
| await Promise.all( |
| users.map(async (user) => { |
| const name = faker.animal.insect(); |
| const assistants = faker.helpers.multiple<Assistant>( |
| () => ({ |
| _id: new ObjectId(), |
| name, |
| createdById: user._id, |
| createdByName: user.username, |
| createdAt: faker.date.recent({ days: 30 }), |
| updatedAt: faker.date.recent({ days: 30 }), |
| userCount: faker.number.int({ min: 1, max: 100000 }), |
| featured: faker.datatype.boolean(0.25), |
| modelId: faker.helpers.arrayElement(modelIds), |
| description: faker.lorem.sentence(), |
| preprompt: faker.hacker.phrase(), |
| exampleInputs: faker.helpers.multiple(() => faker.lorem.sentence(), { |
| count: faker.number.int({ min: 0, max: 4 }), |
| }), |
| searchTokens: generateSearchTokens(name), |
| last24HoursCount: faker.number.int({ min: 0, max: 1000 }), |
| }), |
| { count: faker.number.int({ min: 3, max: 10 }) } |
| ); |
| await collections.assistants.insertMany(assistants); |
| await collections.settings.updateOne( |
| { userId: user._id }, |
| { $set: { assistants: assistants.map((a) => a._id.toString()) } }, |
| { upsert: true } |
| ); |
| }) |
| ); |
| console.log("Done creating assistants."); |
| } |
|
|
| if (flags.includes("conversations") || flags.includes("all")) { |
| console.log("Creating conversations for all users"); |
| await Promise.all( |
| users.map(async (user) => { |
| const conversations = faker.helpers.multiple( |
| async () => { |
| const settings = await collections.settings.findOne<Settings>({ userId: user._id }); |
|
|
| const assistantId = |
| settings?.assistants && settings.assistants.length > 0 && faker.datatype.boolean(0.1) |
| ? faker.helpers.arrayElement<ObjectId>(settings.assistants) |
| : undefined; |
|
|
| const preprompt = |
| (assistantId |
| ? await collections.assistants |
| .findOne({ _id: assistantId }) |
| .then((assistant: Assistant) => assistant?.preprompt ?? "") |
| : faker.helpers.maybe(() => faker.hacker.phrase(), { probability: 0.5 })) ?? ""; |
|
|
| const messages = await generateMessages(preprompt); |
|
|
| const conv = { |
| _id: new ObjectId(), |
| userId: user._id, |
| assistantId, |
| preprompt, |
| createdAt: faker.date.recent({ days: 145 }), |
| updatedAt: faker.date.recent({ days: 145 }), |
| model: faker.helpers.arrayElement(modelIds), |
| title: faker.internet.emoji() + " " + faker.hacker.phrase(), |
| embeddingModel: defaultEmbeddingModel.id, |
| messages, |
| rootMessageId: messages[0].id, |
| } satisfies Conversation; |
|
|
| return conv; |
| }, |
| { count: faker.number.int({ min: 10, max: 200 }) } |
| ); |
|
|
| await collections.conversations.insertMany(await Promise.all(conversations)); |
| }) |
| ); |
| console.log("Done creating conversations."); |
| } |
| } |
|
|
| |
| (async () => { |
| try { |
| rl.question( |
| "You're about to run a seeding script on the following MONGODB_URL: \x1b[31m" + |
| env.MONGODB_URL + |
| "\x1b[0m\n\n With the following flags: \x1b[31m" + |
| flags.join("\x1b[0m , \x1b[31m") + |
| "\x1b[0m\n \n\n Are you sure you want to continue? (yes/no): ", |
| async (confirm) => { |
| if (confirm !== "yes") { |
| console.log("Not 'yes', exiting."); |
| rl.close(); |
| process.exit(0); |
| } |
| console.log("Starting seeding..."); |
| await seed(); |
| console.log("Seeding done."); |
| rl.close(); |
| } |
| ); |
| } catch (e) { |
| console.error(e); |
| process.exit(1); |
| } |
| })(); |
|
|