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

269 lines
11 KiB
JavaScript
Raw Permalink 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点按天轮转查询池搜索AI开源项目(存量热门 stars≥1000 + 近12个月新项目 stars≥300,按 updated 排序并翻页),DeepSeek预评测后入库 PendingSkill 待审核",
config: { minStars: 1000, newMinStars: 300, queriesPerRun: 5, 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-v4-pro" },
},
{
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 2 * * *",
description: "每天凌晨2点扫描过去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: "30 22 * * 0",
description: "每周日22:30:①统计每个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: "0 23 * * 0",
description: "每周日23:00对每个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 * * *",
description: "每天早上6:30清理 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: 2000 },
},
{
taskKey: "bot-persona-experiment-run",
taskName: "Bot Persona A/B 调度",
enabled: true,
cronExpr: "0 * * * *",
description: "每小时:①采集最近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: "30 23 * * 0",
description: "每周日23:30:给每个专家bot选1篇过去7天由真人发布的高互动topic(真人reply+点赞高),LLM 提取\u201c为什么火\u201d的洞察(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 },
},
{
taskKey: "bot-roundtable",
taskName: "Bot 圆桌讨论",
enabled: true,
cronExpr: "0 20 * * 3,6",
description: "每周三、周六20:00:多个Bot围绕预定义话题扮演不同角色(主持人/支持者/挑战者/实践者/总结者)进行多轮圆桌讨论,在论坛创建主题帖+依次回复",
config: { maxBots: 5, minBots: 4 },
},
{
taskKey: "cleanup-logs",
taskName: "清理日志文件",
enabled: true,
cronExpr: "30 4 * * *",
description: "每天凌晨4:30清理/app/logs/下超过7天或超过10MB的.log文件(cron.log除外),防止日志文件占用过多磁盘",
config: { maxAgeDays: 7, maxSizeBytes: 10485760 },
},
{
taskKey: "weekly-recommend-email",
taskName: "每周推荐邮件",
enabled: true,
cronExpr: "30 10 * * 1",
description: "每周一上午10:30:分析每个活跃用户的兴趣(收藏、浏览历史、社区活动),基于兴趣类别匹配推荐AI工具,生成个性化HTML邮件输出到 data/emails/",
config: { maxUsers: 500, sections: { interest: 3, trending: 3, new: 2 }, weightFavorite: 3, weightBrowsing: 1, weightForum: 2 },
},
{
taskKey: "grant-freeze-cards",
taskName: "发放断签保护卡",
enabled: true,
cronExpr: "0 8 1 * *",
description: "每月1号早上8点:给近30天内有签到记录的活跃用户发放2张断签保护卡,卡片存储于SystemConfig表",
config: { cardsPerMonth: 2, maxCards: 2, activeWindowDays: 30 },
},
{
taskKey: "notification-digest",
taskName: "通知摘要生成",
enabled: true,
cronExpr: "0 9 * * *",
description: "每天早上9点:为启用每日/每周摘要模式的活跃用户生成通知摘要,汇总24小时内未读通知并创建DIGEST类型通知",
config: { activeWindowDays: 7, excludeTypes: ["DIGEST"] },
},
{
taskKey: "health-check",
taskName: "任务健康检查",
enabled: true,
cronExpr: "30 8 * * *",
description: "每天早上8:30审计所有定时任务最近一次成功率,检测Bot活跃度、发帖频率、失败任务详情",
config: { lookbackDays: 7 },
},
{
taskKey: "newsletter-generate",
taskName: "周刊生成",
enabled: true,
cronExpr: "0 10 * * 1",
description: "每周一10:00生成追光AI周刊:热门工具5+技能3+话题3,输出JSON+HTML+归档",
config: { sections: { tools: 5, skills: 3, topics: 3 } },
},
{
taskKey: "competitor-monitor",
taskName: "竞品监测",
enabled: true,
cronExpr: "0 9 * * 1",
description: "每周一9:00监测5家竞品AI导航站、3个GitHub仓库、5个Reddit子版块工具数据快照,周环比检测",
config: { competitors: ["taaft", "futurepedia", "aitoolsupdate", "toolify", "ai雷达"] },
},
{
taskKey: "trend-alert",
taskName: "行业趋势告警",
enabled: true,
cronExpr: "0 10 * * *",
description: "每天10:00扫HackerNews API AI话题,提取爆炸性标题+排名前10,入库趋势告警",
config: { sources: ["HackerNews"], minScore: 10, topN: 10 },
},
{
taskKey: "enrich-tool-data",
taskName: "工具数据补全",
enabled: true,
cronExpr: "0 4 * * 0",
description: "每周日04:00自动补全缺失的Logo/描述等工具元数据,通过LLM搜索补齐信息后更新数据库",
config: { batchSize: 20, maxPerRun: 100 },
},
];
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);
});