This commit is contained in:
2026-07-29 11:42:41 +08:00
commit 48b7391365
71 changed files with 28910 additions and 0 deletions

120
src/app/api/chat/route.ts Normal file
View File

@ -0,0 +1,120 @@
import { apiError } from "@/lib/api";
import { startChatRun } from "@/lib/chat-runs";
import {
createChatRunWithMessages,
getActiveChatRun,
getConversation,
getConversationContinuation,
getDefaultConversation,
getSkill,
listMessages,
} from "@/lib/db";
import { hasDeepSeekApiKey } from "@/lib/deepseek";
import type { ChatMessage, Skill } from "@/lib/types";
import { createId } from "@/lib/utils";
import { chatRequestSchema } from "@/lib/validation";
export const runtime = "nodejs";
export const maxDuration = 120;
export async function GET() {
try {
const conversation = getDefaultConversation();
const continuation = getConversationContinuation(conversation.id);
return Response.json({
conversation,
messages: listMessages(conversation.id),
activeRun: getActiveChatRun(conversation.id),
retainedSkillIds: continuation.skillIds,
continuation,
apiConfigured: hasDeepSeekApiKey(),
});
} catch (error) {
return apiError(error, "无法读取聊天记录");
}
}
export async function POST(request: Request) {
try {
const input = chatRequestSchema.parse(await request.json());
if (!getConversation(input.conversationId)) {
return Response.json({ error: "会话不存在" }, { status: 404 });
}
const existingMessages = listMessages(input.conversationId);
const continuation = getConversationContinuation(
input.conversationId,
);
const selectedSkills = [...new Set(input.selectedSkillIds)]
.map((id) => getSkill(id))
.filter(
(skill): skill is Skill => skill?.status === "active",
);
const userMessageId = createId("message");
const assistantMessageId = createId("message");
const runId = createId("run");
const now = new Date().toISOString();
const creation = createChatRunWithMessages({
conversationId: input.conversationId,
userMessage: {
id: userMessageId,
role: "user",
content: input.message,
selectedSkillIds: selectedSkills.map((skill) => skill.id),
usedSkillIds: [],
status: "complete",
createdAt: now,
},
assistantMessage: {
id: assistantMessageId,
role: "assistant",
content: "",
selectedSkillIds: selectedSkills.map((skill) => skill.id),
usedSkillIds: [],
status: "streaming",
createdAt: new Date(Date.now() + 1).toISOString(),
},
run: {
id: runId,
clientRequestId: input.clientRequestId,
userMessageId,
assistantMessageId,
},
});
if (creation.outcome === "existing") {
return Response.json({ run: creation.run });
}
if (creation.outcome === "active_conflict") {
return Response.json(
{ error: "当前已有一轮回答正在进行", run: creation.run },
{ status: 409 },
);
}
const run = creation.run;
const history = existingMessages
.filter((message) => message.status !== "error")
.slice(-20)
.map((message) => ({
role: message.role,
content: message.content,
})) satisfies Array<{
role: ChatMessage["role"];
content: string;
}>;
startChatRun({
runId,
conversationId: input.conversationId,
userMessage: input.message,
selectedSkills,
continuation,
history,
});
return Response.json({ run }, { status: 202 });
} catch (error) {
return apiError(error, "无法发送消息");
}
}