feat(assets): 优化移动端分析体验并记录 AI 提问日志

This commit is contained in:
shishengliang
2026-10-13 16:24:28 +08:00
parent 39ecde55d4
commit 4dec824285
28 changed files with 781 additions and 86 deletions
+27 -1
View File
@@ -21,6 +21,7 @@ import {
} from "./session.js";
import { resultScope, followupSuggestions } from "./presentation.js";
import { gapStore } from "./gaps.js";
import { questionLog, questionOutcome, finishQuestionLog } from "./question-log.js";
import {
CATEGORY_LABELS,
GAP_STATUSES,
@@ -99,6 +100,10 @@ router.post("/feedback", async (c) => {
const session = getSession(c.get("user"), body.subject, body.sessionId),
node = getNode(session, body.resultId)!;
if (!node.flagged) {
const logId = await questionLog.start(c.get("user"), { message: node.question || node.demand,
subject: body.subject, sessionId: session.id, baseResultId: node.id }, "feedback");
const saved = await finishQuestionLog(logId, { outcome: "feedback", reason: "unsatisfied", resultId: node.id });
if (!saved) return c.json({ error: "反馈已接收,处理状态暂未保存,请稍后重试。" }, 503);
await gapStore.record(c.get("user").userId, node.demand, "unsatisfied");
node.flagged = true;
}
@@ -220,15 +225,24 @@ router.post("/ask", async (c) => {
)
return c.json({ error: "请输入有效问题或选择分析操作。" }, 400);
const input: AssistantRequest = { ...raw, subject: raw.subject || null };
let logId: string;
try {
logId = await questionLog.start(user, input);
} catch {
return c.json({ error: "提问记录暂不可用,本次查询未执行,请稍后重试。" }, 503);
}
const release = acquire(user.userId);
if (!release)
if (!release) {
await finishQuestionLog(logId, { outcome: "rejected", reason: "busy" });
return c.json({ error: "上一条查询仍在执行,请稍后重试。" }, 429);
}
let session, base;
try {
session = getSession(user, input.subject, input.sessionId);
base = getNode(session, input.baseResultId);
} catch {
release();
await finishQuestionLog(logId, { outcome: "rejected", reason: "session_expired" });
return c.json({ error: "会话已过期或范围已变化,请新建对话。" }, 409);
}
const currentSession = session,
@@ -238,6 +252,7 @@ router.post("/ask", async (c) => {
stream.onAbort(() => controller.abort());
const emit = (event: object) =>
stream.writeSSE({ data: JSON.stringify(event) });
let logFinished = false;
let demand = "查询执行",
reason: GapReason | undefined;
try {
@@ -516,8 +531,17 @@ router.post("/ask", async (c) => {
type: "step",
label: "分析完成",
});
logFinished = true;
const saved = await finishQuestionLog(logId, { outcome: questionOutcome(result, gapReason),
reason: gapReason, sessionId: currentSession.id, result });
if (!saved) result.warning = [result.warning, "提问已记录,处理结果暂未保存。"].filter(Boolean).join(" ");
await emit({ type: "result", result });
} catch {
if (!logFinished) {
logFinished = true;
await finishQuestionLog(logId, { outcome: controller.signal.aborted ? "cancelled" : "failed",
reason: controller.signal.aborted ? "client_aborted" : "generation", sessionId: currentSession.id });
}
if (!controller.signal.aborted) {
let recorded = false;
try {
@@ -534,6 +558,8 @@ router.post("/ask", async (c) => {
});
}
} finally {
if (!logFinished) await finishQuestionLog(logId, { outcome: controller.signal.aborted ? "cancelled" : "failed",
reason: controller.signal.aborted ? "client_aborted" : "unfinished", sessionId: currentSession.id });
release();
}
});