From 395e2972d98d358636eaa5edda7889ec40576500 Mon Sep 17 00:00:00 2001 From: shaohuzhang1 Date: Wed, 11 Nov 2026 18:29:43 +0800 Subject: [PATCH] feat: Data sources for conversation support --- ui/package.json | 1 + ui/src/api/API_README.md | 2 + ui/src/api/types/chat-log.ts | 31 ++- ui/src/components/COMPONENT_README.md | 18 ++ .../components/log-message-footer/index.vue | 13 +- .../components/log-message-list/index.ts | 2 +- .../components/message-footer/index.vue | 13 +- .../components/message-list/index.ts | 2 +- ui/src/conversation-panel/core/types.ts | 8 +- .../right-sidebar/execution-detail/index.ts | 32 +-- .../right-sidebar/execution-detail/index.vue | 5 +- .../conversation-panel/right-sidebar/index.ts | 61 ++++++ .../right-sidebar/index.vue | 15 ++ .../document-preview/index.ts | 192 ++++++++++++++++++ .../document-preview/index.vue | 85 ++++++++ .../right-sidebar/knowledge-source/index.ts | 127 ++++++++++++ .../right-sidebar/knowledge-source/index.vue | 78 +++++++ ui/src/conversation-panel/view/chat/index.ts | 6 +- ui/src/conversation-panel/view/chat/index.vue | 12 +- ui/src/conversation-panel/view/debug/index.ts | 6 +- .../conversation-panel/view/debug/index.vue | 12 +- ui/src/conversation-panel/view/log/index.vue | 16 +- .../conversation-panel/view/portal/index.vue | 12 +- .../view/simple-debug/index.vue | 20 +- ui/src/conversation-panel/view/types.ts | 4 +- 25 files changed, 684 insertions(+), 89 deletions(-) create mode 100644 ui/src/conversation-panel/right-sidebar/index.ts create mode 100644 ui/src/conversation-panel/right-sidebar/index.vue create mode 100644 ui/src/conversation-panel/right-sidebar/knowledge-source/document-preview/index.ts create mode 100644 ui/src/conversation-panel/right-sidebar/knowledge-source/document-preview/index.vue create mode 100644 ui/src/conversation-panel/right-sidebar/knowledge-source/index.ts create mode 100644 ui/src/conversation-panel/right-sidebar/knowledge-source/index.vue diff --git a/ui/package.json b/ui/package.json index 19086723a51..0a7a93ed283 100644 --- a/ui/package.json +++ b/ui/package.json @@ -46,6 +46,7 @@ "mitt": "^3.0.1", "nanoid": "^6.0.1", "nprogress": "^0.2.0", + "pdfjs-dist": "^6.5.438", "pinia": "^3.0.4", "prettier": "3.8.4", "recorder-core": "^1.3.26070800", diff --git a/ui/src/api/API_README.md b/ui/src/api/API_README.md index 43ed27c5c2b..7f18b849b99 100644 --- a/ui/src/api/API_README.md +++ b/ui/src/api/API_README.md @@ -507,6 +507,8 @@ Chat 协议及认证接口见 [chat/README.md](chat/README.md)。 历史消息和流式聚合复用 `@/api/types` 的 `ChatContent`,定义在 `types/chat-log.ts`; `ChatLogRecord.question` 与 `messages` 使用该内容项类型,扩展字段保留为 `unknown`。 +`paragraph_list` 为 `ChatParagraphSource[]`,后端仅在开启「显示知识来源」或调试、日志时返回; +其 `meta` 在历史快照中可能是 JSON 字符串,使用方需兼容字符串与对象。 Chat、Workspace 调试和 System 调试的记录分页及详情均声明 `ChatLogRecord` 返回类型, 消息列表依赖从 `ConversationApiAdapter` 选取对应接口约定。 `conversation-panel/core/stream.ts` 的 `ConversationStream` 通过回调推断分片类型, diff --git a/ui/src/api/types/chat-log.ts b/ui/src/api/types/chat-log.ts index 1cb7c54dd33..fa059c8dbc9 100644 --- a/ui/src/api/types/chat-log.ts +++ b/ui/src/api/types/chat-log.ts @@ -1,5 +1,7 @@ import type { CHAT_LOG_SOURCE } from '@/api/enums' import type { Dict } from './common' +import type { DocumentResourceType } from './document' +import type { KnowledgeHitTestAsset } from './knowledge' export type ChatLogSource = (typeof CHAT_LOG_SOURCE)[keyof typeof CHAT_LOG_SOURCE] @@ -56,10 +58,37 @@ export interface ChatLogRecord extends Partial { answer_tokens?: number run_time?: number improve_paragraph_id_list?: string[] - paragraph_list?: Dict[] + paragraph_list?: ChatParagraphSource[] execution_details?: Dict[] } +/** 回答引用的知识库分段,来自检索与重排节点,仅在开启「显示知识来源」时返回。 */ +export interface ChatParagraphSource { + id: string + title?: string + /** 分段正文,Markdown */ + content?: string + similarity?: number + is_active?: boolean + document_id?: string + document_name?: string + document_resource_type?: DocumentResourceType | null + document_image_id?: string | null + hit_asset?: KnowledgeHitTestAsset | null + knowledge_id?: string + knowledge_name?: string + knowledge_type?: string + /** 历史快照中可能为 JSON 字符串 */ + meta?: ChatParagraphSourceMeta | string | null +} + +/** 分段来源文档的元数据。 */ +export interface ChatParagraphSourceMeta { + source_file_id?: string + source_url?: string + allow_download?: boolean +} + /** 对话反馈:-1 未评价,0 满意,1 不满意。 */ export interface ChatFeedback { vote_status: '-1' | '0' | '1' diff --git a/ui/src/components/COMPONENT_README.md b/ui/src/components/COMPONENT_README.md index aff214e72d9..5cbcc088bd6 100644 --- a/ui/src/components/COMPONENT_README.md +++ b/ui/src/components/COMPONENT_README.md @@ -996,6 +996,24 @@ Chat、Portal 和 Display 面板直接放置消息列表,并以当前会话 ID 同目录 `QuestionEditor.vue` 接收 `content`、`disabled`,维护本次编辑草稿,通过 `cancel` 和 `send(question)` 通知入口组件;进入时挂载并聚焦,退出时卸载。入口组件负责发送能力与附件传递。 +### RightSidebar(对话模块) + +`conversation-panel/right-sidebar/index.vue` 放在视图布局的 `#right` 插槽,按当前面板展示执行详情或知识来源, +两者共用右侧位置,后打开的替换当前面板;挤压与抽屉由 `ConversationLayout` 按视图模式处理,面板自身不使用抽屉。 +每类面板各自有 `index.ts` 与 `index.vue`:`index.ts` 维护本面板数据,`index.vue` 只负责展示。 +`right-sidebar/index.ts` 的 `createRightSidebarStore()` 维护当前面板与右侧开合,并组合 +`execution-detail` 与 `knowledge-source` 的面板 store;由各视图创建并 provide `RIGHT_SIDEBAR_KEY`, +组件通过 `useRightSidebarStore()` 获取,面板经其 `executionDetail`、`knowledgeSource` 读取数据。消息底部的执行详情入口调用 `showExecutionDetail`, +知识来源入口在记录含分段(`ChatRecordMeta.paragraphList`)时显示并调用 `showKnowledgeSource`。 +`knowledge-source/` 面板与执行详情结构一致:标题栏显示分段数量与关闭,内容区展示分段卡片; +其 `index.ts` 的 `createKnowledgeSourceStore()` 保存分段及正在预览的文档,按相似度从高到低整理分段,兼容字符串 `meta`, +提供召回图片与来源文档的打开方式:知识库文件中的 PDF 在知识来源内预览,其他文件以下载方式获取, +网页来源仅接受 http(s) 地址并在新窗口打开,无可用地址时按下载权限提示;来源文件不交给浏览器原生打开或预览。 +文档预览是知识来源的下一级,位于 `knowledge-source/document-preview/`,覆盖在分段列表之上显示, +列表仅隐藏不卸载以便返回时保留滚动位置,打开新的知识来源时回到列表。预览以 pdf.js 把 PDF 逐页绘制为 canvas,不创建文本层与注释层,关闭 XFA, +避免原生预览执行文件内脚本;pdf.js 在首次预览时按需加载,支持返回知识来源、全屏及按宽度重绘; +预览区预留滚动条位置,重绘在后台完成后整体替换并保持滚动比例,不清空已显示页面。 + ### 分享选择(对话模块) 正式对话的 `message-list` 根据会话 Store 的 `isShared` 展示分享选择态,同轮提问与回答同步选择, diff --git a/ui/src/conversation-panel/components/log-message-footer/index.vue b/ui/src/conversation-panel/components/log-message-footer/index.vue index af487caa5ea..044c69d3fa4 100644 --- a/ui/src/conversation-panel/components/log-message-footer/index.vue +++ b/ui/src/conversation-panel/components/log-message-footer/index.vue @@ -8,7 +8,7 @@ import type { ChatContent } from '@/api/types' import { copyText } from '@/utils/clipboard' import { datetimeFormat } from '@/utils/time' import type { ChatMessage, ChatRecordMeta } from '../../core/types' -import { useExecutionDetailStore } from '../../right-sidebar/execution-detail/index' +import { useRightSidebarStore } from '../../right-sidebar/index' const props = defineProps<{ api: Pick @@ -17,13 +17,13 @@ const props = defineProps<{ message: ChatMessage }>() -const detail = useExecutionDetailStore() +const rightSidebar = useRightSidebarStore() const EMPTY: ChatRecordMeta = { messageTokens: 0, answerTokens: 0, runTime: 0, - knowledgeCount: 0, + paragraphList: [], executionDetails: [], } const meta = computed(() => props.message.record || EMPTY) @@ -43,7 +43,7 @@ function collectAnswerText(contents: ChatContent[]): string { const answerText = computed(() => collectAnswerText(props.message.content)) const openExecutionDetail = () => { - detail.showExecutionDetail(meta.value.executionDetails || []) + rightSidebar.showExecutionDetail(meta.value.executionDetails || []) } @@ -53,9 +53,10 @@ const openExecutionDetail = () => {