demo
This commit is contained in:
120
src/app/api/chat/route.ts
Normal file
120
src/app/api/chat/route.ts
Normal 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, "无法发送消息");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user