feat: 首次推送到Gitea - 完整项目代码 + 安全加固 + 知识库
This commit is contained in:
+27
-5
@@ -15,7 +15,7 @@ const prisma = new PrismaClient({ adapter });
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.DEEPSEEK_API_KEY,
|
||||
baseURL: "https://api.deepseek.com/v1",
|
||||
baseURL: "https://api.deepseek.com",
|
||||
timeout: 120000,
|
||||
maxRetries: 2,
|
||||
});
|
||||
@@ -290,7 +290,7 @@ async function generateDailyNews() {
|
||||
}
|
||||
|
||||
const newsDataText = newsResults
|
||||
.slice(0, 30)
|
||||
.slice(0, 14)
|
||||
.map((r, i) => `[${i + 1}] 标题: ${r.title}\n 内容: ${r.content || "(无摘要)"}\n 来源: ${r.url}\n 时间: ${r.pubDate || "未知"}`)
|
||||
.join("\n\n");
|
||||
|
||||
@@ -304,12 +304,18 @@ async function generateDailyNews() {
|
||||
model: process.env.DEEPSEEK_MODEL || "deepseek-v4-pro",
|
||||
messages: [{ role: "user", content: prompt }],
|
||||
temperature: 0.3,
|
||||
}, { signal: AbortSignal.timeout(120000) });
|
||||
// DeepSeek V4 reasoning token 计入 max_tokens 预算:预算不足会导致 content 为空(finish_reason=length)
|
||||
max_tokens: 16384,
|
||||
}, { signal: AbortSignal.timeout(180000) });
|
||||
}, { maxRetries: 3, label: "DeepSeek News API" });
|
||||
|
||||
const u = completion.usage;
|
||||
if (u) {
|
||||
console.log(` ℹ️ tokens: prompt=${u.prompt_tokens} completion=${u.completion_tokens} reasoning=${u.completion_tokens_details?.reasoning_tokens ?? "n/a"} finish=${completion.choices[0]?.finish_reason}`);
|
||||
}
|
||||
const content = completion.choices[0]?.message?.content;
|
||||
if (!content) {
|
||||
throw new Error("DeepSeek 返回内容为空");
|
||||
throw new Error(`DeepSeek 返回内容为空(finish_reason=${completion.choices[0]?.finish_reason},completion_tokens=${u?.completion_tokens},疑似 reasoning 占满 max_tokens)`);
|
||||
}
|
||||
|
||||
let parsed;
|
||||
@@ -367,13 +373,29 @@ async function generateDailyNews() {
|
||||
return report;
|
||||
}
|
||||
|
||||
async function generateWithRetry() {
|
||||
for (let attempt = 0; attempt < 2; attempt++) {
|
||||
try {
|
||||
return await generateDailyNews();
|
||||
} catch (e) {
|
||||
const msg = String(e.message || e);
|
||||
// 偶发中止/超时/上游 5xx 才重试;业务类错误直接抛出
|
||||
const retryable = /abort|timeout|ETIMEDOUT|ECONNRESET|socket|fetch failed|502|503|429/i.test(msg);
|
||||
if (!retryable || attempt === 1) throw e;
|
||||
console.warn(`⚠️ 日报生成中止(${msg.slice(0, 80)}),30s 后重试 (${attempt + 1}/2)...`);
|
||||
await new Promise((r) => setTimeout(r, 30000));
|
||||
}
|
||||
}
|
||||
throw new Error("unreachable");
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (!process.env.DEEPSEEK_API_KEY) throw new Error("缺少环境变量: DEEPSEEK_API_KEY");
|
||||
if (!process.env.DATABASE_URL) throw new Error("缺少环境变量: DATABASE_URL");
|
||||
|
||||
const startTime = new Date();
|
||||
try {
|
||||
const report = await generateDailyNews();
|
||||
const report = await generateWithRetry();
|
||||
const endTime = new Date();
|
||||
const duration = endTime.getTime() - startTime.getTime();
|
||||
await prisma.taskLog.create({
|
||||
|
||||
Reference in New Issue
Block a user