189 lines
7.8 KiB
JavaScript
189 lines
7.8 KiB
JavaScript
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);
|
||
}); |