89 lines
3.1 KiB
TypeScript
89 lines
3.1 KiB
TypeScript
import { NextResponse } from "next/server";
|
||
import { requireAdmin } from "@/lib/admin-auth";
|
||
import { extractJSON } from "@/lib/utils";
|
||
import OpenAI from "openai";
|
||
import { badRequest, notFound, serverError } from "@/lib/api-error";
|
||
|
||
// 必须 force-dynamic,否则 build 期的 page data collection 会触发模块求值
|
||
export const dynamic = "force-dynamic";
|
||
export const runtime = "nodejs";
|
||
|
||
// 懒加载 OpenAI client:build 期模块求值时不会触发 SDK 构造
|
||
let _openai: OpenAI | null = null;
|
||
function getOpenAI(): OpenAI {
|
||
if (!_openai) {
|
||
_openai = new OpenAI({
|
||
apiKey: process.env.DEEPSEEK_API_KEY,
|
||
baseURL: "https://api.deepseek.com",
|
||
});
|
||
}
|
||
return _openai;
|
||
}
|
||
|
||
const DAILY_PROMPT = `你是AI行业资深分析师。请为{date}生成一份AI日报,包含6-8条当日最重要的AI行业热点新闻。
|
||
|
||
要求:
|
||
1. 每条新闻必须有真实的新闻事件基础,不能编造
|
||
2. 每条新闻必须覆盖不同分类维度,确保多样性
|
||
3. 标题简洁有力(20字以内),摘要精炼(50字以内),详情深入(100-200字)
|
||
4. 优先关注中国AI行业动态,兼顾全球重要事件
|
||
5. 分类标注规则(必须使用以下key值):
|
||
- model:模型前沿(LLM/多模态新模型发布、架构创新、训练方法突破)
|
||
- product:产品落地(AI产品发布/更新、C端应用上线、B端解决方案、新功能)
|
||
- opensource:开源生态(开源项目动态、框架更新、开源社区大事件)
|
||
- business:商业产业(投融资、收购并购、财报营收、公司战略、行业趋势)
|
||
- policy:政策治理(AI法规政策、监管动态、伦理治理、国际AI治理)
|
||
- insight:深度洞察(行业领袖观点、深度分析报告、学术研究前沿)
|
||
|
||
返回纯JSON格式:
|
||
{
|
||
"title": "AI日报:{date} 核心要点概览",
|
||
"summary": "今日AI行业整体趋势概述(100字以内)",
|
||
"items": [
|
||
{
|
||
"category": "model",
|
||
"title": "新闻标题",
|
||
"summary": "一句话摘要",
|
||
"detail": "详细内容描述",
|
||
"sourceUrl": "",
|
||
"hotScore": 85
|
||
}
|
||
]
|
||
}
|
||
|
||
hotScore热度评分规则(0-100)`;
|
||
|
||
export async function POST(request: Request) {
|
||
const authCheck = await requireAdmin();
|
||
if (authCheck) return authCheck;
|
||
|
||
try {
|
||
const body = await request.json();
|
||
const date = body.date || new Date().toLocaleDateString("zh-CN");
|
||
|
||
const prompt = DAILY_PROMPT.replace(/\{date\}/g, date);
|
||
|
||
const completion = await getOpenAI().chat.completions.create({
|
||
model: "deepseek-v4-pro",
|
||
messages: [{ role: "user", content: prompt }],
|
||
temperature: 0.7,
|
||
});
|
||
|
||
const content = completion.choices[0]?.message?.content;
|
||
if (!content) {
|
||
return NextResponse.json({ error: "生成内容为空" }, { status: 500 });
|
||
}
|
||
|
||
let parsed;
|
||
try {
|
||
parsed = extractJSON(content);
|
||
} catch {
|
||
return NextResponse.json({ error: "无法解析AI返回的JSON", raw: content }, { status: 422 });
|
||
}
|
||
|
||
return NextResponse.json({ success: true, data: parsed });
|
||
} catch (error) {
|
||
return serverError(error);
|
||
}
|
||
}
|