feat: 异步沉淀主题摘要和成长档案

This commit is contained in:
2026-08-03 11:35:58 +08:00
parent a3946013f5
commit d2e08ab36c
24 changed files with 825 additions and 58 deletions

View File

@@ -43,6 +43,7 @@ const followingOutput = ref(true);
const messageList = ref<InstanceType<typeof MessageList> | null>(null);
const activeAbortController = ref<AbortController | null>(null);
let toastTimer: number | null = null;
let settlementPollVersion = 0;
onMounted(async () => {
if (!getToken()) {
@@ -62,6 +63,7 @@ onMounted(async () => {
});
onBeforeUnmount(() => {
settlementPollVersion += 1;
activeAbortController.value?.abort();
if (toastTimer) window.clearTimeout(toastTimer);
document.body.classList.remove("drawer-open");
@@ -215,7 +217,12 @@ async function finishCurrentTopic() {
finishingTopic.value = true;
try {
const result = await api.finishTopic(activeSessionId.value);
showToast(result.growthProfileEnabled ? "本主题已沉淀,并更新了你的成长档案" : "本主题已沉淀");
if (result.settlementStatus === "success" || result.settlementStatus === "fallback") {
showToast(result.growthProfileEnabled ? "本主题已沉淀,并更新了你的成长档案" : "本主题已沉淀");
} else {
showToast("主题已结束,实修记录正在后台沉淀,可以继续使用其他功能");
void watchTopicSettlement(result.summary.id);
}
await refreshSessionList();
await refreshProfile();
} catch (error) {
@@ -225,6 +232,38 @@ async function finishCurrentTopic() {
}
}
async function watchTopicSettlement(summaryId: number) {
const version = ++settlementPollVersion;
for (let attempt = 0; attempt < 40; attempt += 1) {
await new Promise((resolve) => window.setTimeout(resolve, 3000));
if (version !== settlementPollVersion || !user.value) return;
try {
const result = await api.topicSettlement(summaryId);
if (result.settlementStatus === "success" || result.settlementStatus === "fallback") {
showToast(result.growthProfileEnabled ? "实修记录已沉淀,并更新了成长档案" : "实修记录已沉淀完成");
await refreshProfile();
return;
}
if (result.settlementStatus === "failed") {
showToast("实修记录暂时沉淀失败,系统已保留对话,可稍后重试");
return;
}
} catch {
// 轮询失败不影响聊天;下一轮继续查询持久化任务状态。
}
}
}
function settlementStatusLabel(status: string) {
return {
pending: "等待沉淀",
running: "沉淀中",
success: "已完成",
fallback: "已降级完成",
failed: "沉淀失败",
}[status] || status;
}
async function generateHelpCard() {
if (!activeSessionId.value || sending.value || generatingHelpCard.value) return;
generatingHelpCard.value = true;
@@ -490,8 +529,10 @@ async function copyText(text: string) {
<div v-if="growthProfile?.recentSummaries.length" class="recent-topic-summaries">
<h3>最近主题沉淀</h3>
<article v-for="item in growthProfile.recentSummaries" :key="item.id">
<time>{{ item.generatedAt }}</time>
<p>{{ item.summary }}</p>
<time>{{ item.generatedAt }} · {{ settlementStatusLabel(item.status) }}</time>
<p v-if="item.status === 'success' || item.status === 'fallback'">{{ item.summary }}</p>
<p v-else-if="item.status === 'failed'">沉淀暂时失败对话内容仍已保留</p>
<p v-else>正在后台整理本主题的实修记录可以先关闭页面或继续聊天</p>
</article>
</div>
<div v-if="reportHistory.length" class="recent-topic-summaries periodic-report-list">