From 4e58dd42cc775c407dadf0fb8ee259f12170fe9a Mon Sep 17 00:00:00 2001 From: wizardchen Date: Thu, 28 May 2026 15:24:55 +0800 Subject: [PATCH] feat(knowledge-base): integrate trace availability checks and enhance UI interactions This commit introduces a new utility function, `knowledgeSpansPayloadHasTrace`, to determine if the knowledge spans data contains a valid trace. Key changes include: 1. Updated the `KnowledgeBase` component to utilize the new trace availability checks, improving the logic for displaying trace-related UI elements. 2. Enhanced the `fetchSpans` function in the `knowledge-processing-timeline` component to emit trace availability based on the new utility. 3. Implemented caching for trace availability to optimize performance and reduce unnecessary API calls. These changes aim to improve user experience by providing accurate trace information and enhancing the overall responsiveness of the UI. --- .../knowledge-processing-timeline.vue | 4 +- frontend/src/utils/knowledgeTrace.ts | 7 +++ .../src/views/knowledge/KnowledgeBase.vue | 57 ++++++++++++++++++- 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 frontend/src/utils/knowledgeTrace.ts diff --git a/frontend/src/components/knowledge-processing-timeline.vue b/frontend/src/components/knowledge-processing-timeline.vue index c9ec7a75..667acec1 100644 --- a/frontend/src/components/knowledge-processing-timeline.vue +++ b/frontend/src/components/knowledge-processing-timeline.vue @@ -3,6 +3,7 @@ import { ref, reactive, onMounted, onBeforeUnmount, watch, computed, nextTick } import { MessagePlugin } from 'tdesign-vue-next' import { useI18n } from 'vue-i18n' import { getKnowledgeSpans, reparseKnowledge } from '@/api/knowledge-base/index' +import { knowledgeSpansPayloadHasTrace } from '@/utils/knowledgeTrace' interface SpanNode { span_id?: string @@ -355,8 +356,7 @@ async function fetchSpans(opts: { manual?: boolean } = {}) { const traceStatus = data.value.trace?.status || data.value.parse_status || 'running' attemptStatuses.set(data.value.attempt, traceStatus) ensureAttemptStatuses() - const hasSpans = !!(data.value.trace && (data.value.trace.span_id || (data.value.current_attempt ?? 0) > 0)) - emit('update:hasSpans', hasSpans) + emit('update:hasSpans', knowledgeSpansPayloadHasTrace(data.value)) } else { emit('update:hasSpans', false) } diff --git a/frontend/src/utils/knowledgeTrace.ts b/frontend/src/utils/knowledgeTrace.ts new file mode 100644 index 00000000..89189d6a --- /dev/null +++ b/frontend/src/utils/knowledgeTrace.ts @@ -0,0 +1,7 @@ +/** Whether GET /knowledge/:id/spans returned a real trace (not legacy placeholder-only). */ +export function knowledgeSpansPayloadHasTrace( + data: { trace?: { span_id?: string }; current_attempt?: number } | null | undefined, +): boolean { + if (!data?.trace) return false + return !!(data.trace.span_id || (data.current_attempt ?? 0) > 0) +} diff --git a/frontend/src/views/knowledge/KnowledgeBase.vue b/frontend/src/views/knowledge/KnowledgeBase.vue index 3aed2c56..86630a53 100644 --- a/frontend/src/views/knowledge/KnowledgeBase.vue +++ b/frontend/src/views/knowledge/KnowledgeBase.vue @@ -32,7 +32,9 @@ import { listKnowledgeBases, reparseKnowledge, batchDeleteKnowledge, + getKnowledgeSpans, } from "@/api/knowledge-base/index"; +import { knowledgeSpansPayloadHasTrace } from '@/utils/knowledgeTrace'; import FAQEntryManager from './components/FAQEntryManager.vue'; import DocumentListView from './components/DocumentListView.vue'; import DocumentBatchBar from './components/DocumentBatchBar.vue'; @@ -291,6 +293,51 @@ const onVisibleChange = (visible: boolean) => { moveMenuMode.value = 'normal'; } }; + +/** Per-knowledge cache: whether /spans has a real trace (see knowledgeSpansPayloadHasTrace). */ +const traceAvailableById = reactive>({}); +const traceProbeInflight = new Set(); + +function clearTraceAvailabilityCache() { + for (const key of Object.keys(traceAvailableById)) { + delete traceAvailableById[key]; + } + traceProbeInflight.clear(); +} + +function isTraceMenuVisible(item: KnowledgeCard): boolean { + if (!item?.id) return false; + if (item.parse_status === 'pending' || item.parse_status === 'processing') { + return true; + } + return traceAvailableById[item.id] === true; +} + +async function probeTraceAvailable(item: KnowledgeCard) { + const id = item.id; + if (!id || traceProbeInflight.has(id)) return; + if (item.parse_status === 'pending' || item.parse_status === 'processing') { + traceAvailableById[id] = true; + return; + } + if (Object.prototype.hasOwnProperty.call(traceAvailableById, id)) return; + traceProbeInflight.add(id); + try { + const res: any = await getKnowledgeSpans(id); + traceAvailableById[id] = !!(res?.success && knowledgeSpansPayloadHasTrace(res.data)); + } catch { + traceAvailableById[id] = false; + } finally { + traceProbeInflight.delete(id); + } +} + +const onCardMoreVisibleChange = (visible: boolean, item: KnowledgeCard) => { + onVisibleChange(visible); + if (visible) { + probeTraceAvailable(item); + } +}; let isCardDetails = ref(false); let timeout: ReturnType | null = null; let delDialog = ref(false) @@ -814,6 +861,7 @@ watch(activeKbTab, (tab) => { watch(() => kbId.value, (newKbId, oldKbId) => { if (newKbId && newKbId !== oldKbId) { + clearTraceAvailabilityCache(); cardList.value = []; total.value = 0; docListLoading.value = true; @@ -1043,6 +1091,7 @@ const updateStatus = (analyzeList: KnowledgeCard[]) => { cardList.value[index].parse_status = item.parse_status; cardList.value[index].summary_status = item.summary_status; cardList.value[index].description = item.description; + delete traceAvailableById[item.id]; hasChanges = true; } }); @@ -1741,6 +1790,8 @@ const rebuildConfirm = async () => { if (!item?.id) return; try { await reparseKnowledge(item.id); + delete traceAvailableById[item.id]; + traceAvailableById[item.id] = true; MessagePlugin.success(t('knowledgeBase.rebuildSubmitted')); resetPage(); // Reset page counter when reloading files after reparse loadKnowledgeFiles(kbId.value); @@ -2281,7 +2332,8 @@ async function createNewSession(value: string): Promise { {{ item.file_name }}
@@ -2295,7 +2347,8 @@ async function createNewSession(value: string): Promise { {{ t('knowledgeBase.editDocument') }}
-
+
{{ t('knowledgeStages.viewTrace') }}