feat: AI 周末行程规划 — DeepSeek 智能排期 + 高德 POI + 多日翻页
- 接入 DeepSeek API,提交想法时自动 AI 打标(品类/时段/时长/搜索策略) - 新增行程规划 API:智能选取想法 → 高德 POI 搜索 → AI 生成最优行程 - 支持多日计划("整个周末"拆分周六/周日,并行 AI 调用) - 行程展示逐日翻页,时间线可滚动,操作按钮固定底部 - 分享卡适配多日格式,支持图片保存与原生分享 - Prisma schema 新增 WeekendPlan 模型及 BlindBoxIdea AI 标签字段 - Jenkinsfile 集成 DEEPSEEK_API_KEY 环境变量
This commit is contained in:
@@ -3,6 +3,9 @@ import { prisma } from "@/lib/prisma";
|
||||
import { requireMembership } from "@/lib/blindbox";
|
||||
import { apiHandler, ApiError, requireUserId } from "@/lib/api";
|
||||
import { validateIdeaContent, requireString } from "@/lib/validation";
|
||||
import { tagIdea } from "@/lib/ai";
|
||||
|
||||
const TAG_TIMEOUT_MS = 3000;
|
||||
|
||||
export const POST = apiHandler(async (req) => {
|
||||
const { roomId, userId, content } = await req.json();
|
||||
@@ -17,7 +20,29 @@ export const POST = apiHandler(async (req) => {
|
||||
data: { roomId, userId, content: trimmedContent },
|
||||
});
|
||||
|
||||
return NextResponse.json({ id: idea.id }, { status: 201 });
|
||||
const tags = await Promise.race([
|
||||
tagIdea(trimmedContent),
|
||||
new Promise<null>((resolve) => setTimeout(() => resolve(null), TAG_TIMEOUT_MS)),
|
||||
]);
|
||||
|
||||
if (tags) {
|
||||
await prisma.blindBoxIdea.update({
|
||||
where: { id: idea.id },
|
||||
data: {
|
||||
category: tags.category,
|
||||
timeSlot: tags.timeSlot,
|
||||
estimatedMinutes: tags.estimatedMinutes,
|
||||
outdoor: tags.outdoor,
|
||||
searchQuery: tags.searchQuery,
|
||||
searchType: tags.searchType,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ id: idea.id, ...tags && { tags } },
|
||||
{ status: 201 },
|
||||
);
|
||||
});
|
||||
|
||||
export const GET = apiHandler(async (req) => {
|
||||
@@ -33,7 +58,17 @@ export const GET = apiHandler(async (req) => {
|
||||
prisma.blindBoxIdea.findMany({
|
||||
where: { roomId, userId, status: "in_pool" },
|
||||
orderBy: { createdAt: "desc" },
|
||||
select: { id: true, content: true, createdAt: true },
|
||||
select: {
|
||||
id: true,
|
||||
content: true,
|
||||
createdAt: true,
|
||||
category: true,
|
||||
timeSlot: true,
|
||||
estimatedMinutes: true,
|
||||
outdoor: true,
|
||||
searchQuery: true,
|
||||
searchType: true,
|
||||
},
|
||||
}),
|
||||
prisma.blindBoxIdea.findMany({
|
||||
where: { roomId, status: "drawn" },
|
||||
@@ -62,7 +97,26 @@ export const PUT = apiHandler(async (req) => {
|
||||
|
||||
if (count === 0) throw new ApiError("想法不存在、已被抽中或无权编辑", 404);
|
||||
|
||||
return NextResponse.json({ id: ideaId, content: trimmedContent });
|
||||
const tags = await Promise.race([
|
||||
tagIdea(trimmedContent),
|
||||
new Promise<null>((resolve) => setTimeout(() => resolve(null), TAG_TIMEOUT_MS)),
|
||||
]);
|
||||
|
||||
if (tags) {
|
||||
await prisma.blindBoxIdea.updateMany({
|
||||
where: { id: ideaId, userId, status: "in_pool" },
|
||||
data: {
|
||||
category: tags.category,
|
||||
timeSlot: tags.timeSlot,
|
||||
estimatedMinutes: tags.estimatedMinutes,
|
||||
outdoor: tags.outdoor,
|
||||
searchQuery: tags.searchQuery,
|
||||
searchType: tags.searchType,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.json({ id: ideaId, content: trimmedContent, ...tags && { tags } });
|
||||
});
|
||||
|
||||
export const DELETE = apiHandler(async (req) => {
|
||||
|
||||
Reference in New Issue
Block a user