From afeb7fddc3f1c14ec4f90267b0e2c2984bea3db3 Mon Sep 17 00:00:00 2001 From: billchen Date: Wed, 28 Feb 2024 13:35:47 +0800 Subject: [PATCH] feat: fetch file thumbnails --- web/src/hooks/knowledgeHook.ts | 31 ++++++++++ .../components/knowledge-file/index.less | 8 ++- .../components/knowledge-file/index.tsx | 62 ++++++++++--------- .../components/knowledge-file/model.ts | 11 ++++ web/src/pages/chat/chat-container/index.tsx | 39 +++++------- web/src/pages/chat/hooks.ts | 2 +- web/src/pages/chat/model.ts | 7 +++ web/src/pages/chat/utils.ts | 18 ++++++ web/src/services/kbService.ts | 5 ++ web/src/utils/api.ts | 1 + 10 files changed, 128 insertions(+), 56 deletions(-) diff --git a/web/src/hooks/knowledgeHook.ts b/web/src/hooks/knowledgeHook.ts index 9ad41f5a7..21678152b 100644 --- a/web/src/hooks/knowledgeHook.ts +++ b/web/src/hooks/knowledgeHook.ts @@ -150,3 +150,34 @@ export const useFetchKnowledgeList = ( return list; }; + +export const useSelectFileThumbnails = () => { + const fileThumbnails: Record = useSelector( + (state: any) => state.kFModel.fileThumbnails, + ); + + return fileThumbnails; +}; + +export const useFetchFileThumbnails = (docIds?: Array) => { + const dispatch = useDispatch(); + const fileThumbnails = useSelectFileThumbnails(); + + const fetchFileThumbnails = useCallback( + (docIds: Array) => { + dispatch({ + type: 'kFModel/fetch_document_thumbnails', + payload: { doc_ids: docIds.join(',') }, + }); + }, + [dispatch], + ); + + useEffect(() => { + if (docIds) { + fetchFileThumbnails(docIds); + } + }, [docIds, fetchFileThumbnails]); + + return { fileThumbnails, fetchFileThumbnails }; +}; diff --git a/web/src/pages/add-knowledge/components/knowledge-file/index.less b/web/src/pages/add-knowledge/components/knowledge-file/index.less index 52e895597..402299745 100644 --- a/web/src/pages/add-knowledge/components/knowledge-file/index.less +++ b/web/src/pages/add-knowledge/components/knowledge-file/index.less @@ -20,9 +20,11 @@ } .img { - height: 16px; - width: 16px; - margin-right: 6px; + height: 24px; + width: 24px; + margin-right: 10px; + display: inline-block; + vertical-align: middle; } .column { diff --git a/web/src/pages/add-knowledge/components/knowledge-file/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/index.tsx index a61d8fc54..eafed785e 100644 --- a/web/src/pages/add-knowledge/components/knowledge-file/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-file/index.tsx @@ -22,7 +22,7 @@ import { } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { PaginationProps } from 'antd/lib'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Link, useDispatch, useNavigate, useSelector } from 'umi'; import CreateEPModal from './createEFileModal'; import styles from './index.less'; @@ -46,7 +46,7 @@ const KnowledgeFile = () => { const [parser_id, setParserId] = useState('0'); let navigate = useNavigate(); - const getKfList = () => { + const getKfList = useCallback(() => { const payload = { kb_id: knowledgeBaseId, }; @@ -55,7 +55,7 @@ const KnowledgeFile = () => { type: 'kFModel/getKfList', payload, }); - }; + }, [dispatch, knowledgeBaseId]); const throttledGetDocumentList = () => { dispatch({ @@ -64,23 +64,29 @@ const KnowledgeFile = () => { }); }; - const setPagination = (pageNumber = 1, pageSize?: number) => { - const pagination: Pagination = { - current: pageNumber, - } as Pagination; - if (pageSize) { - pagination.pageSize = pageSize; - } - dispatch({ - type: 'kFModel/setPagination', - payload: pagination, - }); - }; + const setPagination = useCallback( + (pageNumber = 1, pageSize?: number) => { + const pagination: Pagination = { + current: pageNumber, + } as Pagination; + if (pageSize) { + pagination.pageSize = pageSize; + } + dispatch({ + type: 'kFModel/setPagination', + payload: pagination, + }); + }, + [dispatch], + ); - const onPageChange: PaginationProps['onChange'] = (pageNumber, pageSize) => { - setPagination(pageNumber, pageSize); - getKfList(); - }; + const onPageChange: PaginationProps['onChange'] = useCallback( + (pageNumber: number, pageSize: number) => { + setPagination(pageNumber, pageSize); + getKfList(); + }, + [getKfList, setPagination], + ); const pagination: PaginationProps = useMemo(() => { return { @@ -92,7 +98,7 @@ const KnowledgeFile = () => { pageSizeOptions: [1, 2, 10, 20, 50, 100], onChange: onPageChange, }; - }, [total, kFModel.pagination]); + }, [total, kFModel.pagination, onPageChange]); useEffect(() => { if (knowledgeBaseId) { @@ -107,7 +113,7 @@ const KnowledgeFile = () => { type: 'kFModel/pollGetDocumentList-stop', }); }; - }, [knowledgeBaseId]); + }, [knowledgeBaseId, dispatch, getKfList]); const handleInputChange = ( e: React.ChangeEvent, @@ -129,14 +135,14 @@ const KnowledgeFile = () => { }); }; - const showCEFModal = () => { + const showCEFModal = useCallback(() => { dispatch({ type: 'kFModel/updateState', payload: { isShowCEFwModal: true, }, }); - }; + }, [dispatch]); const actionItems: MenuProps['items'] = useMemo(() => { return [ @@ -169,7 +175,7 @@ const KnowledgeFile = () => { // disabled: true, }, ]; - }, []); + }, [knowledgeBaseId, showCEFModal]); const toChunk = (id: string) => { navigate( @@ -187,13 +193,9 @@ const KnowledgeFile = () => { title: 'Name', dataIndex: 'name', key: 'name', - render: (text: any, { id }) => ( + render: (text: any, { id, thumbnail }) => (
toChunk(id)}> - + {text}
), diff --git a/web/src/pages/add-knowledge/components/knowledge-file/model.ts b/web/src/pages/add-knowledge/components/knowledge-file/model.ts index ac7f0e38c..53f11679f 100644 --- a/web/src/pages/add-knowledge/components/knowledge-file/model.ts +++ b/web/src/pages/add-knowledge/components/knowledge-file/model.ts @@ -16,6 +16,7 @@ export interface KFModelState extends BaseState { data: IKnowledgeFile[]; total: number; currentRecord: Nullable; + fileThumbnails: Record; } const model: DvaModel = { @@ -34,6 +35,7 @@ const model: DvaModel = { current: 1, pageSize: 10, }, + fileThumbnails: {} as Record, }, reducers: { updateState(state, { payload }) { @@ -54,6 +56,9 @@ const model: DvaModel = { setPagination(state, { payload }) { return { ...state, pagination: { ...state.pagination, ...payload } }; }, + setFileThumbnails(state, { payload }) { + return { ...state, fileThumbnails: payload }; + }, }, effects: { *createKf({ payload = {} }, { call }) { @@ -201,6 +206,12 @@ const model: DvaModel = { } return retcode; }, + *fetch_document_thumbnails({ payload = {} }, { call, put }) { + const { data } = yield call(kbService.document_thumbnails, payload); + if (data.retcode === 0) { + yield put({ type: 'setFileThumbnails', payload: data.data }); + } + }, }, }; export default model; diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx index 4c0704f7b..b3d70ca52 100644 --- a/web/src/pages/chat/chat-container/index.tsx +++ b/web/src/pages/chat/chat-container/index.tsx @@ -3,16 +3,7 @@ import { MessageType } from '@/constants/chat'; import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; import { useSelectUserInfo } from '@/hooks/userSettingHook'; import { IReference, Message } from '@/interfaces/database/chat'; -import { - Avatar, - Button, - Flex, - Input, - List, - Popover, - Space, - Typography, -} from 'antd'; +import { Avatar, Button, Flex, Input, List, Popover, Space } from 'antd'; import classNames from 'classnames'; import { ChangeEventHandler, useCallback, useMemo, useState } from 'react'; import reactStringReplace from 'react-string-replace'; @@ -26,6 +17,7 @@ import { IClientConversation } from '../interface'; import Image from '@/components/image'; import NewDocumentLink from '@/components/new-document-link'; +import { useSelectFileThumbnails } from '@/hooks/knowledgeHook'; import { InfoCircleOutlined } from '@ant-design/icons'; import Markdown from 'react-markdown'; import { visitParents } from 'unist-util-visit-parents'; @@ -56,11 +48,10 @@ const MessageItem = ({ reference: IReference; }) => { const userInfo = useSelectUserInfo(); + const fileThumbnails = useSelectFileThumbnails(); const isAssistant = item.role === MessageType.Assistant; - const getFileIcon = useGetFileIcon(); - const getPopoverContent = useCallback( (chunkIndex: number) => { const chunks = reference?.chunks ?? []; @@ -82,15 +73,18 @@ const MessageItem = ({
{chunkItem?.content_with_weight}
{documentId && ( - - {document?.doc_name} - + + + + {document?.doc_name} + + )}
); }, - [reference], + [reference, fileThumbnails], ); const renderReference = useCallback( @@ -163,12 +157,13 @@ const MessageItem = ({ dataSource={referenceDocumentList} renderItem={(item) => ( - - {/* */} - - - {item.doc_name} - + {/* */} + + + + {item.doc_name} + + )} /> diff --git a/web/src/pages/chat/hooks.ts b/web/src/pages/chat/hooks.ts index a3edde05c..8efa3209c 100644 --- a/web/src/pages/chat/hooks.ts +++ b/web/src/pages/chat/hooks.ts @@ -384,7 +384,7 @@ export const useFetchConversation = () => { const fetchConversation = useCallback(() => { if (isConversationIdNotExist(conversationId)) { - dispatch({ + dispatch({ type: 'chatModel/getConversation', payload: { conversation_id: conversationId, diff --git a/web/src/pages/chat/model.ts b/web/src/pages/chat/model.ts index 040959ff7..52894adb7 100644 --- a/web/src/pages/chat/model.ts +++ b/web/src/pages/chat/model.ts @@ -4,6 +4,7 @@ import { message } from 'antd'; import { DvaModel } from 'umi'; import { v4 as uuid } from 'uuid'; import { IClientConversation, IMessage } from './interface'; +import { getDocumentIdsFromConversionReference } from './utils'; export interface ChatModelState { name: string; @@ -111,6 +112,12 @@ const model: DvaModel = { *getConversation({ payload }, { call, put }) { const { data } = yield call(chatService.getConversation, payload); if (data.retcode === 0) { + yield put({ + type: 'kFModel/fetch_document_thumbnails', + payload: { + doc_ids: getDocumentIdsFromConversionReference(data.data), + }, + }); yield put({ type: 'setCurrentConversation', payload: data.data }); } return data.retcode; diff --git a/web/src/pages/chat/utils.ts b/web/src/pages/chat/utils.ts index cbec9e2c7..76744df65 100644 --- a/web/src/pages/chat/utils.ts +++ b/web/src/pages/chat/utils.ts @@ -1,3 +1,4 @@ +import { IConversation, IReference } from '@/interfaces/database/chat'; import { EmptyConversationId, variableEnabledFieldMap } from './constants'; export const excludeUnEnabledVariables = (values: any) => { @@ -14,3 +15,20 @@ export const excludeUnEnabledVariables = (values: any) => { export const isConversationIdNotExist = (conversationId: string) => { return conversationId !== EmptyConversationId && conversationId !== ''; }; + +export const getDocumentIdsFromConversionReference = (data: IConversation) => { + const documentIds = data.reference.reduce( + (pre: Array, cur: IReference) => { + cur.doc_aggs + .map((x) => x.doc_id) + .forEach((x) => { + if (pre.every((y) => y !== x)) { + pre.push(x); + } + }); + return pre; + }, + [], + ); + return documentIds.join(','); +}; diff --git a/web/src/services/kbService.ts b/web/src/services/kbService.ts index ca25bc44f..bf2b0eb8e 100644 --- a/web/src/services/kbService.ts +++ b/web/src/services/kbService.ts @@ -13,6 +13,7 @@ const { document_rm, document_create, document_change_parser, + document_thumbnails, chunk_list, create_chunk, set_chunk, @@ -75,6 +76,10 @@ const methods = { url: document_change_parser, method: 'post', }, + document_thumbnails: { + url: document_thumbnails, + method: 'get', + }, // chunk管理 chunk_list: { url: chunk_list, diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts index 777c413fe..3a1169e94 100644 --- a/web/src/utils/api.ts +++ b/web/src/utils/api.ts @@ -42,6 +42,7 @@ export default { document_create: `${api_host}/document/create`, document_run: `${api_host}/document/run`, document_change_parser: `${api_host}/document/change_parser`, + document_thumbnails: `${api_host}/document/thumbnails`, setDialog: `${api_host}/dialog/set`, getDialog: `${api_host}/dialog/get`,