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") {
if (!auth.loggedIn.value) return;
const msg = messages.value.find((m) => m.id === messageId);
const newFeedback = msg?.feedback === feedback ? null : feedback;
try {
await $fetch("/api/agent/feedback", {
method: "POST",
body: { messageId, feedback },
body: { messageId, feedback: newFeedback },
});
const msg = messages.value.find((m) => m.id === messageId);
if (msg) {
msg.feedback = msg.feedback === feedback ? null : feedback;
msg.feedback = newFeedback;
}
} 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 { messageId, feedback, comment } = body as {
messageId: string;
feedback: "like" | "dislike";
feedback: "like" | "dislike" | null;
comment?: string;
};
if (!messageId || !feedback || !["like", "dislike"].includes(feedback)) {
if (!messageId || (feedback !== null && !["like", "dislike"].includes(feedback))) {
return R.error("参数无效", null);
}
@ -39,6 +39,15 @@ export default defineWrappedResponseHandler(async (event) => {
.where(and(eq(agentMessageFeedback.messageId, messageId), eq(agentMessageFeedback.userId, user.id)))
.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) {
await dbGlobal
.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 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 });
});

45
server/service/agent/session.ts

@ -1,7 +1,7 @@
import { dbGlobal } from "drizzle-pkg/lib/db";
import { agentSessions, agentMessages, agentMessageFeedback } from "drizzle-pkg/lib/schema/agent";
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: {
userId?: number | null;
@ -118,28 +118,47 @@ export async function softDeleteSession(id: string): Promise<void> {
export async function getMessagesBySession(
sessionId: string,
params?: { before?: number; limit?: number; latest?: boolean },
): Promise<AgentMessageRow[]> {
const { before, limit = 50, latest = false } = params ?? {};
params?: { before?: number; limit?: number; latest?: boolean; userId?: number | null },
): Promise<AgentMessageWithFeedback[]> {
const { before, limit = 50, latest = false, userId = null } = params ?? {};
const conditions = [eq(agentMessages.sessionId, sessionId)];
if (before !== undefined) {
conditions.push(lt(agentMessages.sortOrder, before));
}
if (latest) {
const rows = await dbGlobal
.select()
const baseQuery = () =>
dbGlobal
.select({
message: agentMessages,
feedback: agentMessageFeedback.feedback,
})
.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))
.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
.select()
.from(agentMessages)
.where(and(...conditions))
const rows = await baseQuery()
.orderBy(asc(agentMessages.sortOrder))
.limit(limit);
return rows.map((r) => ({
...r.message,
feedback: (r.feedback ?? null) as "like" | "dislike" | null,
}));
}
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 AgentMessageFeedbackRow = typeof agentMessageFeedback.$inferSelect;
export interface AgentMessageWithFeedback extends AgentMessageRow {
feedback: "like" | "dislike" | null;
}
export interface AgentIdentity {
userId: number | null;
tempToken: string | null;

Loading…
Cancel
Save