feat: 异步沉淀主题摘要和成长档案
This commit is contained in:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user