v0.11.1: 权限体系重构 + AI管线优化 + 内容整理

This commit is contained in:
sgp
2026-05-22 18:36:41 +08:00
parent 7955d11c52
commit b33fe1e8e1
397 changed files with 30940 additions and 161 deletions
+138
View File
@@ -0,0 +1,138 @@
import { PrismaClient } from "@prisma/client";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
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 openai = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: "https://api.deepseek.com/v1",
});
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) jsonStr = braceMatch[0];
return JSON.parse(jsonStr);
}
const LONG_ARTICLE_PROMPT = `你是AI工具评测专家。基于以下评测数据,撰写一篇800-1200字的深度评测文章。
项目:{name}
简介:{desc}
综合评分:{overall}/5
五维评分:能力{cap}/5 | 开发体验{dev}/5 | 成本许可{cost}/5 | 社区{comm}/5 | 性能{perf}/5
要求:
1. 标题醒目,20字以内
2. 开头用一句话概括项目核心价值
3. 分5个段落分别深入分析五个维度
4. 每段包含具体使用场景和优缺点
5. 结尾给出适用人群和推荐指数
6. 语言专业但易懂,避免空洞套话
返回纯文本,不要JSON格式。`;
const VIDEO_SCRIPT_PROMPT = `为GitHub开源AI项目{name}(⭐{stars} stars)创作一个60秒短视频脚本。
项目简介:{desc}
综合评分:{overall}/5
要求5个镜头:
- 镜头1:开场hook(5秒)
- 镜头2:项目定位(10秒)
- 镜头3:核心功能展示(20秒)
- 镜头4:使用场景(15秒)
- 镜头5:CTA号召(10秒)
每个镜头包含:[画面描述] + 旁白文案
返回纯文本格式。`;
async function generateLongArticle(review, skill) {
const prompt = LONG_ARTICLE_PROMPT
.replace("{name}", skill.name)
.replace("{desc}", skill.description || "暂无描述")
.replace("{overall}", review.overall.toString())
.replace("{cap}", review.capability.toString())
.replace("{dev}", review.devExp.toString())
.replace("{cost}", review.costLicense.toString())
.replace("{comm}", review.community.toString())
.replace("{perf}", review.performance.toString());
const { choices } = await openai.chat.completions.create({
model: "deepseek-v4-pro",
messages: [{ role: "user", content: prompt }],
temperature: 0.7,
});
return choices[0]?.message?.content || "";
}
async function generateVideoScript(review, skill) {
const reviewsData = review.reviews || {};
const prompt = VIDEO_SCRIPT_PROMPT
.replace("{name}", skill.name)
.replace("{desc}", skill.description || "暂无描述")
.replace("{overall}", review.overall.toString())
.replace("{stars}", String(reviewsData.stars || "N/A"));
const { choices } = await openai.chat.completions.create({
model: "deepseek-v4-pro",
messages: [{ role: "user", content: prompt }],
temperature: 0.7,
});
return choices[0]?.message?.content || "";
}
async function main() {
console.log("📝 批量生成评测内容\n");
const reviews = await prisma.skillReview.findMany({
where: { status: "PUBLISHED", longArticle: null },
include: { skill: { select: { id: true, name: true, description: true } } },
});
console.log(`找到 ${reviews.length} 个需要生成内容的评测\n`);
for (let i = 0; i < reviews.length; i++) {
const r = reviews[i];
console.log(`\n[${i + 1}/${reviews.length}] ${r.skill.name} (overall: ${r.overall})`);
try {
console.log(" 生成长文...");
const article = await generateLongArticle(r, r.skill);
console.log(` ✅ 长文: ${article.length}字`);
console.log(" 生成视频脚本...");
const script = await generateVideoScript(r, r.skill);
console.log(` ✅ 脚本: ${script.length}字`);
await prisma.skillReview.update({
where: { id: r.id },
data: {
longArticle: article,
videoScript: script,
},
});
console.log(" 💾 已保存");
if (i < reviews.length - 1) {
await new Promise((resolve) => setTimeout(resolve, 2000));
}
} catch (e) {
console.error(` ❌ 失败: ${e.message}`);
}
}
console.log("\n🏁 内容生成完成");
}
main()
.catch((e) => { console.error("💥", e.message); process.exit(1); })
.finally(() => prisma.$disconnect());