Files
zhuiguang-ai/scripts/seed-task-configs.mjs
T

189 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { PrismaClient } from "@prisma/client";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
import "dotenv/config";
const base = (process.env.DATABASE_URL || "mysql://localhost:3306/zhuiguang_ai?charset=utf8mb4").replace("mysql://", "mariadb://");
const sep = base.includes("?") ? "&" : "?";
const connectionString = `${base}${sep}connection_limit=20&pool_timeout=30`;
const adapter = new PrismaMariaDb(connectionString);
const prisma = new PrismaClient({ adapter });
const TASK_DEFS = [
{
taskKey: "task1-discover-tools",
taskName: "发现AI工具",
enabled: true,
cronExpr: "0 6 * * *",
description: "每天早上6点从36kr/IT之家/开源中国RSS抓取新闻,由DeepSeek提取AI工具信息并入库待审核",
config: { sources: ["36kr", "IT之家", "开源中国"], model: "deepseek-v4-pro" },
},
{
taskKey: "task3-check-tools",
taskName: "工具巡检",
enabled: true,
cronExpr: "0 3 * * *",
description: "每天凌晨3点检查所有已发布工具的网站可访问性和Logo有效性,自动发布通过检查的待审核工具",
config: { checkWebsite: true, checkLogo: true, autoPublish: true },
},
{
taskKey: "task4-discover-skills",
taskName: "发现AI技能",
enabled: true,
cronExpr: "0 5 * * *",
description: "每天凌晨5点从GitHub搜索高星AI项目(stars≥1000),DeepSeek预评测后入库PendingSkill待审核",
config: { minStars: 1000, dailyLimit: 30, model: "deepseek-v4-pro" },
},
{
taskKey: "task5-update-stars",
taskName: "更新技能星值",
enabled: true,
cronExpr: "0 1 * * *",
description: "每天凌晨1点更新所有GitHub技能的最新Stars数,记录日/周/月变化趋势",
config: { updateAll: true, historyDays: 90 },
},
{
taskKey: "task6-review-hot",
taskName: "评测热门技能",
enabled: true,
cronExpr: "0 4 * * *",
description: "每天凌晨4点对2个最热门且未评测的GitHub技能进行五维深度评测,自动生成SkillReview",
config: { dailyLimit: 2, model: "deepseek-v4-pro" },
},
{
taskKey: "daily-news",
taskName: "AI日报生成",
enabled: true,
cronExpr: "30 7 * * *",
description: "每天早上7:30从多源RSS搜索真实AI新闻,由DeepSeek整理格式生成当日日报",
config: { sources: ["36kr", "IT之家", "开源中国", "GoogleNews", "HackerNews"], model: "deepseek-v4-pro" },
},
{
taskKey: "bot-activity",
taskName: "Bot活动引擎",
enabled: true,
cronExpr: "0 9-23 * * *",
description: "每小时(9-23点)调度行业论坛Bot发言:4个专家板块+4个路人板块(每个路人板块最多2帖),按活跃时段过滤bot,按最近发帖加权去重",
config: { expertForumsPerRun: 4, passerbyForumsPerRun: 4, passerbyTopicsPerForum: 2, model: "deepseek-chat" },
},
{
taskKey: "bot-feedback-loop",
taskName: "Bot反馈循环",
enabled: true,
cronExpr: "0 */3 * * *",
description: "每3小时扫描Bot自己帖子下的新回复,存为反馈记忆并按概率触发二次回复",
config: { followUpProbability: 0.6, maxPerRun: 3, lookbackHours: 24 },
},
{
taskKey: "bot-skill-crystallize",
taskName: "Bot技能沉淀",
enabled: true,
cronExpr: "0 */12 * * *",
description: "每12小时扫描过去14天高互动Bot话题(回复≥5或真人≥1或点赞≥3),DeepSeek解构共性后入库BotSkill;末尾回收7天前成熟技能的实际表现,更新successRate/avgReplies,<30%且使用≥3次自动降级",
config: { lookbackDays: 14, minReplies: 5, minHumanReplies: 1, minLikes: 3, maxTopicsPerBot: 8, recycleAfterDays: 7, minSuccessRate: 0.3 },
},
{
taskKey: "bot-affinity-update",
taskName: "Bot亲和度与画像",
enabled: true,
cronExpr: "0 */6 * * *",
description: "每6小时:①统计每个Bot话题收到的跨板块真人互动,刷BotCrossForumAffinity(affinity=min(1, samples/total/4))②扫过去30天发言,刷BotPersona(avgReplyLength/questionRatio/stanceKeywords/topHumanUsers/topTopicTypes/lastTopicTitles)",
config: { affinityLookbackDays: 14, personaLookbackDays: 30, minAffinity: 0.1 },
},
{
taskKey: "bot-weekly-review",
taskName: "Bot周度复盘",
enabled: true,
cronExpr: "30 2 * * 1",
description: "每周一凌晨2:30对每个Bot算engagementScore(回复/帖子比+真人占比+点赞对数),生成REFLECTION记忆并决定下周配额tier(high/medium/low)",
config: { weights: { replyPerTopic: 0.4, humanRatio: 0.3, likesLog: 0.3 }, thresholds: { high: 1.0, medium: 0.5 } },
},
{
taskKey: "task7-news-to-community",
taskName: "新闻分发到社区",
enabled: true,
cronExpr: "0 8 * * *",
description: "每天早上8点把当日AI日报条目自动分发到社区对应板块创建话题",
config: { sourceTask: "daily-news", maxPerDay: 12 },
},
{
taskKey: "cleanup-task-logs",
taskName: "清理任务日志",
enabled: true,
cronExpr: "30 6 * * 0",
description: "每周日凌晨清理 30 天前的 task_log 数据,避免表无限膨胀",
config: { retentionDays: 30 },
},
{
taskKey: "reconcile-like-counts",
taskName: "点赞数对齐巡检",
enabled: true,
cronExpr: "15 */6 * * *",
description: "每6小时对齐 forumTopic.likeCount / forumPost.likeCount 与真实 Like 表的计数,确保 Redis 缓存 + UI 显示与真实点赞一致(drift 自动修正)",
config: { scope: "both", botOnly: false, autoFix: true, limit: 5000 },
},
{
taskKey: "bot-persona-experiment-run",
taskName: "Bot Persona A/B 调度",
enabled: true,
cronExpr: "45 */4 * * *",
description: "每4小时:①采集最近7天 bot_persona_assignments 的真实互动数据(reply/like/humanReplies)回填到 bot_persona_metrics ②对每个bot的变体做双比例z检验(p<0.1, 样本≥20)③winner变体权重自动提到0.85,其他降到0.075,标记experiment=completed",
config: { lookbackDays: 7, minSamplesPerArm: 20, significanceLevel: 0.1 },
},
{
taskKey: "bot-adversarial-learning-run",
taskName: "Bot 对抗学习(真人高赞帖)",
enabled: true,
cronExpr: "0 23 * * 0",
description: "每周日23:00:给每个专家bot选1篇过去7天由真人发布的高互动topic(真人reply+点赞高),LLM 提取“为什么火”的洞察(hook/story/data/question/contrarian/empathy/practical),写入 bot_adversarial_learnings(unique bot+weekKey)+ BotMemory,bot下次发帖时可注入到 prompt",
config: { lookbackDays: 7, expireDays: 7, minReplies: 3, minLikes: 5, minHumanReplies: 1 },
},
];
async function main() {
console.log("🌱 初始化任务配置种子数据...\n");
let created = 0;
let updated = 0;
for (const def of TASK_DEFS) {
const existing = await prisma.taskConfig.findUnique({
where: { taskKey: def.taskKey },
});
if (existing) {
await prisma.taskConfig.update({
where: { taskKey: def.taskKey },
data: {
taskName: def.taskName,
cronExpr: def.cronExpr,
description: def.description,
config: def.config,
},
});
updated++;
console.log(` 🔄 更新: ${def.taskName} (${def.taskKey})`);
} else {
await prisma.taskConfig.create({
data: {
taskKey: def.taskKey,
taskName: def.taskName,
enabled: def.enabled,
cronExpr: def.cronExpr,
description: def.description,
config: def.config,
},
});
created++;
console.log(` ✅ 创建: ${def.taskName} (${def.taskKey})`);
}
}
console.log(`\n🏁 完成: 创建${created}个, 更新${updated}个`);
await prisma.$disconnect();
}
main().catch(async (e) => {
console.error("❌ 种子数据初始化失败:", e.message);
if (prisma) await prisma.$disconnect();
process.exit(1);
});