2026-05-25: 等级体系升级(20级)+论坛二级分类+会员空间

This commit is contained in:
ZhuiGuangAI Dev
2026-05-24 23:05:38 +08:00
parent 6c78c32157
commit 9bf3e7574a
118 changed files with 11842 additions and 3262 deletions
+228
View File
@@ -0,0 +1,228 @@
import { PrismaClient } from "@prisma/client";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
import { Octokit } from "octokit";
import OpenAI from "openai";
import "dotenv/config";
const base = process.env.DATABASE_URL || "mysql://localhost:3306/zhuiguang_ai?charset=utf8mb4";
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 octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
const openai = new OpenAI({ apiKey: process.env.DEEPSEEK_API_KEY, baseURL: "https://api.deepseek.com/v1" });
const REVIEW_PROMPT = `你是AI技术资深评测师。请对以下AI开源项目进行五维评测,每个维度1-5分。
评测维度:
- capability:场景与能力(功能覆盖度、场景适配性、输出质量)
- devExp:开发体验(安装便捷度、文档质量、API设计、调试友好度)
- costLicense:成本与许可(开源协议友好度、部署成本、资源消耗)
- community:社区健康(Stars趋势、贡献者数量、Issue响应速度、更新频率)
- performance:性能稳定(推理速度、并发能力、稳定性、可扩展性)
项目信息:
名称:{name}
描述:{description}
GitHub Stars:{stars}
README摘要:{readme}
返回纯JSON:
{
"capability": 4.5,
"devExp": 4.0,
"costLicense": 5.0,
"community": 4.5,
"performance": 4.0,
"overall": 4.4,
"reviews": {
"capability": {"score": 4.5, "summary": "一句话总结", "detail": "详细分析"},
"devExp": {"score": 4.0, "summary": "一句话总结", "detail": "详细分析"},
"costLicense": {"score": 5.0, "summary": "一句话总结", "detail": "详细分析"},
"community": {"score": 4.5, "summary": "一句话总结", "detail": "详细分析"},
"performance": {"score": 4.0, "summary": "一句话总结", "detail": "详细分析"}
},
"tags": ["标签1", "标签2"]
}`;
function extractJSON(str) {
const trimmed = str.trim();
const codeBlockMatch = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/);
let jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : trimmed;
const braceMatch = jsonStr.match(/\{[\s\S]*\}/);
if (braceMatch) { try { return JSON.parse(braceMatch[0]); } catch {} }
return JSON.parse(jsonStr);
}
function extractOwnerRepo(sourceUrl) {
const match = sourceUrl.match(/github\.com\/([^/]+)\/([^/]+)/);
if (!match) return null;
return { owner: match[1], repo: match[2].replace(/\.git$/, "") };
}
async function getReadme(owner, repo) {
try {
const { data } = await octokit.rest.repos.getReadme({ owner, repo });
const content = Buffer.from(data.content, "base64").toString("utf-8");
return content.substring(0, 3000);
} catch {
return "(无法获取README)";
}
}
async function main() {
const startTime = new Date();
const now = new Date();
const cnOffset = 8 * 60 * 60 * 1000;
const cnTime = new Date(now.getTime() + cnOffset);
const today = cnTime.toISOString().split("T")[0];
console.log(`🔥 [Task6] ${today} 评测最热工具...`);
const unreviewed = await prisma.skill.findMany({
where: {
status: "published",
sourceUrl: { contains: "github.com" },
skillReview: null,
},
orderBy: [{ githubStars: "desc" }, { viewCount: "desc" }],
take: 2,
select: { id: true, name: true, description: true, sourceUrl: true, githubStars: true },
});
if (unreviewed.length === 0) {
console.log(" 所有热门技能已有评测,跳过");
await prisma.taskLog.create({
data: {
taskKey: "task6-review-hot",
taskName: "评测热门技能",
status: "completed",
startedAt: startTime,
finishedAt: new Date(),
duration: new Date().getTime() - startTime.getTime(),
result: { reviewed: 0, message: "所有热门技能已有评测" },
},
});
await prisma.$disconnect();
return;
}
console.log(` 待评测: ${unreviewed.map((s) => s.name).join(", ")}`);
let reviewed = 0;
let failed = 0;
const errors = [];
for (const skill of unreviewed) {
console.log(`\n 📦 评测: ${skill.name} (${skill.githubStars}⭐)`);
const parsed = extractOwnerRepo(skill.sourceUrl);
let readme = "(无README)";
let stars = skill.githubStars;
if (parsed) {
readme = await getReadme(parsed.owner, parsed.repo);
try {
const { data } = await octokit.rest.repos.get({ owner: parsed.owner, repo: parsed.repo });
stars = data.stargazers_count;
} catch {}
}
const prompt = REVIEW_PROMPT
.replace("{name}", skill.name)
.replace("{description}", skill.description || "")
.replace("{stars}", String(stars))
.replace("{readme}", readme.substring(0, 2000));
try {
const completion = await openai.chat.completions.create({
model: "deepseek-v4-pro",
messages: [{ role: "user", content: prompt }],
temperature: 0.3,
});
const content = completion.choices[0]?.message?.content;
if (!content) throw new Error("DeepSeek返回为空");
const parsed_review = extractJSON(content);
const scores = [parsed_review.capability, parsed_review.devExp, parsed_review.costLicense, parsed_review.community, parsed_review.performance].filter((s) => typeof s === "number");
const overall = parsed_review.overall || (scores.length > 0 ? Math.round((scores.reduce((a, b) => a + b, 0) / scores.length) * 10) / 10 : 3.0);
await prisma.skillReview.create({
data: {
skillId: skill.id,
capability: parsed_review.capability || 3.0,
devExp: parsed_review.devExp || 3.0,
costLicense: parsed_review.costLicense || 3.0,
community: parsed_review.community || 3.0,
performance: parsed_review.performance || 3.0,
overall,
reviews: parsed_review.reviews || {},
tags: parsed_review.tags || [],
status: "PUBLISHED",
reviewedAt: new Date(),
},
});
await prisma.skill.update({
where: { id: skill.id },
data: { lastReviewedAt: new Date() },
});
reviewed++;
console.log(` ✅ 评测完成: overall=${overall}`);
} catch (e) {
failed++;
errors.push(`${skill.name}: ${e.message}`);
console.error(` ❌ 评测失败: ${e.message}`);
}
}
const endTime = new Date();
const duration = endTime.getTime() - startTime.getTime();
const result = {
total: unreviewed.length,
reviewed,
failed,
duration: `${(duration / 1000).toFixed(1)}s`,
};
console.log(`\n🏁 [Task6] 完成: 评测${reviewed}个, 失败${failed}个`);
await prisma.taskLog.create({
data: {
taskKey: "task6-review-hot",
taskName: "评测热门技能",
status: "completed",
startedAt: startTime,
finishedAt: endTime,
duration,
result,
error: errors.length > 0 ? errors.slice(0, 5).join("\n") : null,
},
});
await prisma.$disconnect();
}
main().catch(async (e) => {
console.error("❌ 任务六失败:", e.message);
if (prisma) {
try {
await prisma.taskLog.create({
data: {
taskKey: "task6-review-hot",
taskName: "评测热门技能",
status: "failed",
startedAt: new Date(),
finishedAt: new Date(),
duration: 0,
error: e.message,
},
});
} catch {}
await prisma.$disconnect();
}
process.exit(1);
});