// 给所有 bot 初始化 A/B 测试变体 // 用法:node scripts/seed-persona-variants.mjs [--bot=] // - 默认跑所有 bot // - --bot=laochen 只为老陈创建/更新变体 import { PrismaClient } from "@prisma/client"; import { PrismaMariaDb } from "@prisma/adapter-mariadb"; import { readFileSync } from "fs"; import { resolve, dirname } from "path"; import { fileURLToPath } from "url"; import "dotenv/config"; import { ensureBotVariants, ensureExperiment, disconnectBotExperiment, } from "./lib/bot-persona-experiment.mjs"; const __dirname = dirname(fileURLToPath(import.meta.url)); const base = process.env.DATABASE_URL.replace("mysql://", "mariadb://"); const sep = base.includes("?") ? "&" : "?"; const connectionString = `${base}${sep}connection_limit=2&pool_timeout=10`; const adapter = new PrismaMariaDb(connectionString); const prisma = new PrismaClient({ adapter }); const BOT_DATA_PATH = resolve(__dirname, "..", "data", "bot-characters.json"); function ts() { return `[${new Date().toISOString()}]`; } function parseArgs() { const args = process.argv.slice(2); const out = { bot: null }; for (const a of args) { if (a.startsWith("--bot=")) out.bot = a.split("=")[1]; } return out; } async function main() { const args = parseArgs(); console.log(`${ts()} Seed persona variants starting${args.bot ? ` (bot=${args.bot})` : ""}...`); const { characters } = JSON.parse(readFileSync(BOT_DATA_PATH, "utf-8")); let botChars = characters.filter((c) => !c.role || c.role !== "passerby"); if (args.bot) { botChars = botChars.filter((c) => c.key === args.bot); if (botChars.length === 0) { console.error(`${ts()} Bot "${args.bot}" not found in bot-characters.json`); process.exit(1); } } let variantCreated = 0; let experimentCreated = 0; for (const c of botChars) { const botUser = await prisma.user.findFirst({ where: { email: `bot_${c.key}@zhuiguang.ai` } }); if (!botUser) { console.warn(`${ts()} bot user not found for key=${c.key}, skipping.`); continue; } const botConfig = await prisma.botConfig.findUnique({ where: { userId: botUser.id } }); if (!botConfig) { console.warn(`${ts()} botConfig not found for key=${c.key}, skipping.`); continue; } const { variants, created } = await ensureBotVariants(botConfig.id, botUser.id); variantCreated += created; console.log(`${ts()} ${c.displayName}: variants=${variants.length} (created=${created})`); const exp = await ensureExperiment(botConfig.id); if (exp) { experimentCreated++; console.log(`${ts()} exp#${exp.id} status=${exp.status}`); } } await prisma.taskLog.create({ data: { taskKey: "seed-persona-variants", taskName: "Bot 人设 A/B 变体初始化", status: "success", startedAt: new Date(), finishedAt: new Date(), triggerBy: "manual", result: { botCount: botChars.length, variantCreated, experimentCreated }, }, }); console.log( `${ts()} Done. bots=${botChars.length} variants_created=${variantCreated} experiments=${experimentCreated}` ); } main() .catch(async (e) => { console.error(`${ts()} Fatal:`, e); try { await prisma.taskLog.create({ data: { taskKey: "seed-persona-variants", taskName: "Bot 人设 A/B 变体初始化", status: "failed", startedAt: new Date(), finishedAt: new Date(), triggerBy: "manual", error: (e && e.message ? e.message : String(e)).slice(0, 1000), }, }); } catch {} process.exit(1); }) .finally(async () => { await prisma.$disconnect(); await disconnectBotExperiment(); });