Browse Source

feat: update feedback handling to support null values and enhance message retrieval with user feedback

feat/ai-sdk-v6-upgrade
npmrun 1 day ago
parent
commit
9742b6f094
  1. 7
      app/composables/useAgentChat.ts
  2. BIN
      packages/drizzle-pkg/db.sqlite
  3. 13
      server/api/agent/feedback.post.ts
  4. 2
      server/api/agent/sessions/[id]/messages.get.ts
  5. 45
      server/service/agent/session.ts
  6. 4
      server/service/agent/types.ts

7
app/composables/useAgentChat.ts

@ -503,14 +503,15 @@ export function useAgentChat(options: UseAgentChatOptions) {
async function sendFeedback(messageId: string, feedback: "like" | "dislike") { async function sendFeedback(messageId: string, feedback: "like" | "dislike") {
if (!auth.loggedIn.value) return; if (!auth.loggedIn.value) return;
const msg = messages.value.find((m) => m.id === messageId);
const newFeedback = msg?.feedback === feedback ? null : feedback;
try { try {
await $fetch("/api/agent/feedback", { await $fetch("/api/agent/feedback", {
method: "POST", method: "POST",
body: { messageId, feedback }, body: { messageId, feedback: newFeedback },
}); });
const msg = messages.value.find((m) => m.id === messageId);
if (msg) { if (msg) {
msg.feedback = msg.feedback === feedback ? null : feedback; msg.feedback = newFeedback;
} }
} catch { } catch {
} }

BIN
packages/drizzle-pkg/db.sqlite

Binary file not shown.

13
server/api/agent/feedback.post.ts

@ -15,11 +15,11 @@ export default defineWrappedResponseHandler(async (event) => {
const body = await readBody(event); const body = await readBody(event);
const { messageId, feedback, comment } = body as { const { messageId, feedback, comment } = body as {
messageId: string; messageId: string;
feedback: "like" | "dislike"; feedback: "like" | "dislike" | null;
comment?: string; comment?: string;
}; };
if (!messageId || !feedback || !["like", "dislike"].includes(feedback)) { if (!messageId || (feedback !== null && !["like", "dislike"].includes(feedback))) {
return R.error("参数无效", null); return R.error("参数无效", null);
} }
@ -39,6 +39,15 @@ export default defineWrappedResponseHandler(async (event) => {
.where(and(eq(agentMessageFeedback.messageId, messageId), eq(agentMessageFeedback.userId, user.id))) .where(and(eq(agentMessageFeedback.messageId, messageId), eq(agentMessageFeedback.userId, user.id)))
.limit(1); .limit(1);
if (feedback === null) {
if (existing) {
await dbGlobal
.delete(agentMessageFeedback)
.where(eq(agentMessageFeedback.id, existing.id));
}
return R.success({ messageId, feedback: null });
}
if (existing) { if (existing) {
await dbGlobal await dbGlobal
.update(agentMessageFeedback) .update(agentMessageFeedback)

2
server/api/agent/sessions/[id]/messages.get.ts

@ -19,6 +19,6 @@ export default defineWrappedResponseHandler(async (event) => {
const before = query.before ? Number(query.before) : undefined; const before = query.before ? Number(query.before) : undefined;
const limit = Number(query.limit) || 50; const limit = Number(query.limit) || 50;
const messages = await getMessagesBySession(id, { before, limit }); const messages = await getMessagesBySession(id, { before, limit, userId: identity.userId });
return R.success({ messages, hasMore: messages.length === limit }); return R.success({ messages, hasMore: messages.length === limit });
}); });

45
server/service/agent/session.ts

@ -1,7 +1,7 @@
import { dbGlobal } from "drizzle-pkg/lib/db"; import { dbGlobal } from "drizzle-pkg/lib/db";
import { agentSessions, agentMessages, agentMessageFeedback } from "drizzle-pkg/lib/schema/agent"; import { agentSessions, agentMessages, agentMessageFeedback } from "drizzle-pkg/lib/schema/agent";
import { eq, desc, asc, and, lt, isNull, sql, max } from "drizzle-orm"; import { eq, desc, asc, and, lt, isNull, sql, max } from "drizzle-orm";
import type { AgentSessionRow, AgentMessageRow } from "./types"; import type { AgentSessionRow, AgentMessageRow, AgentMessageWithFeedback } from "./types";
export async function createSession(params: { export async function createSession(params: {
userId?: number | null; userId?: number | null;
@ -118,28 +118,47 @@ export async function softDeleteSession(id: string): Promise<void> {
export async function getMessagesBySession( export async function getMessagesBySession(
sessionId: string, sessionId: string,
params?: { before?: number; limit?: number; latest?: boolean }, params?: { before?: number; limit?: number; latest?: boolean; userId?: number | null },
): Promise<AgentMessageRow[]> { ): Promise<AgentMessageWithFeedback[]> {
const { before, limit = 50, latest = false } = params ?? {}; const { before, limit = 50, latest = false, userId = null } = params ?? {};
const conditions = [eq(agentMessages.sessionId, sessionId)]; const conditions = [eq(agentMessages.sessionId, sessionId)];
if (before !== undefined) { if (before !== undefined) {
conditions.push(lt(agentMessages.sortOrder, before)); conditions.push(lt(agentMessages.sortOrder, before));
} }
if (latest) {
const rows = await dbGlobal const baseQuery = () =>
.select() dbGlobal
.select({
message: agentMessages,
feedback: agentMessageFeedback.feedback,
})
.from(agentMessages) .from(agentMessages)
.where(and(...conditions)) .leftJoin(
agentMessageFeedback,
and(
eq(agentMessageFeedback.messageId, agentMessages.id),
userId ? eq(agentMessageFeedback.userId, userId) : sql`false`,
),
)
.where(and(...conditions));
if (latest) {
const rows = await baseQuery()
.orderBy(desc(agentMessages.sortOrder)) .orderBy(desc(agentMessages.sortOrder))
.limit(limit); .limit(limit);
return rows.reverse(); const reversed = rows.reverse();
return reversed.map((r) => ({
...r.message,
feedback: (r.feedback ?? null) as "like" | "dislike" | null,
}));
} }
return dbGlobal const rows = await baseQuery()
.select()
.from(agentMessages)
.where(and(...conditions))
.orderBy(asc(agentMessages.sortOrder)) .orderBy(asc(agentMessages.sortOrder))
.limit(limit); .limit(limit);
return rows.map((r) => ({
...r.message,
feedback: (r.feedback ?? null) as "like" | "dislike" | null,
}));
} }
export async function getMaxSortOrder(sessionId: string): Promise<number> { export async function getMaxSortOrder(sessionId: string): Promise<number> {

4
server/service/agent/types.ts

@ -4,6 +4,10 @@ export type AgentSessionRow = typeof agentSessions.$inferSelect;
export type AgentMessageRow = typeof agentMessages.$inferSelect; export type AgentMessageRow = typeof agentMessages.$inferSelect;
export type AgentMessageFeedbackRow = typeof agentMessageFeedback.$inferSelect; export type AgentMessageFeedbackRow = typeof agentMessageFeedback.$inferSelect;
export interface AgentMessageWithFeedback extends AgentMessageRow {
feedback: "like" | "dislike" | null;
}
export interface AgentIdentity { export interface AgentIdentity {
userId: number | null; userId: number | null;
tempToken: string | null; tempToken: string | null;

Loading…
Cancel
Save