From b6837d4ca6f4476bc72eadc31990aaf2d00f0d57 Mon Sep 17 00:00:00 2001 From: balibabu <cike8899@users.noreply.github.com> Date: Thu, 28 Mar 2024 16:18:16 +0800 Subject: [PATCH] feat: add corresponding icons to files (#164) --- web/src/components/new-document-link.tsx | 8 +- web/src/hooks/knowledgeHook.ts | 23 +++++ .../components/knowledge-chunk/index.less | 1 + .../components/knowledge-file/index.less | 1 - .../components/knowledge-file/index.tsx | 21 +++-- .../components/knowledge-testing/index.tsx | 17 ++-- .../testing-control/index.tsx | 7 +- .../testing-result/index.less | 10 ++- .../testing-result/index.tsx | 2 +- .../testing-result/select-files.tsx | 5 +- web/src/pages/chat/chat-container/index.less | 3 + web/src/pages/chat/chat-container/index.tsx | 90 +++++++++++++------ web/src/utils/documentUtils.ts | 4 + 13 files changed, 137 insertions(+), 55 deletions(-) diff --git a/web/src/components/new-document-link.tsx b/web/src/components/new-document-link.tsx index 84c0c93..e64ef14 100644 --- a/web/src/components/new-document-link.tsx +++ b/web/src/components/new-document-link.tsx @@ -3,12 +3,18 @@ import React from 'react'; interface IProps extends React.PropsWithChildren { documentId: string; + preventDefault?: boolean; } -const NewDocumentLink = ({ children, documentId }: IProps) => { +const NewDocumentLink = ({ + children, + documentId, + preventDefault = false, +}: IProps) => { return ( <a target="_blank" + onClick={!preventDefault ? undefined : (e) => e.preventDefault()} href={`${api_host}/document/get/${documentId}`} rel="noreferrer" > diff --git a/web/src/hooks/knowledgeHook.ts b/web/src/hooks/knowledgeHook.ts index 1ef5167..8a0f7a3 100644 --- a/web/src/hooks/knowledgeHook.ts +++ b/web/src/hooks/knowledgeHook.ts @@ -206,3 +206,26 @@ export const useSelectKnowledgeDetails = () => { return knowledgeDetails; }; //#endregion + +//#region Retrieval testing + +export const useTestChunkRetrieval = () => { + const dispatch = useDispatch(); + const knowledgeBaseId = useKnowledgeBaseId(); + + const testChunk = useCallback( + (values: any) => { + dispatch({ + type: 'testingModel/testDocumentChunk', + payload: { + ...values, + kb_id: knowledgeBaseId, + }, + }); + }, + [dispatch, knowledgeBaseId], + ); + + return testChunk; +}; +//#endregion diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/index.less b/web/src/pages/add-knowledge/components/knowledge-chunk/index.less index b7380ed..a41a35a 100644 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/index.less +++ b/web/src/pages/add-knowledge/components/knowledge-chunk/index.less @@ -37,6 +37,7 @@ } .chunkContainer { + display: flex; height: calc(100vh - 332px); } 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 05614a1..d78737b 100644 --- a/web/src/pages/add-knowledge/components/knowledge-file/index.less +++ b/web/src/pages/add-knowledge/components/knowledge-file/index.less @@ -22,7 +22,6 @@ .img { height: 24px; width: 24px; - margin-right: 10px; display: inline-block; vertical-align: middle; } 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 73200c2..6fa7f20 100644 --- a/web/src/pages/add-knowledge/components/knowledge-file/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-file/index.tsx @@ -1,9 +1,12 @@ +import ChunkMethodModal from '@/components/chunk-method-modal'; +import SvgIcon from '@/components/svg-icon'; import { useSelectDocumentList, useSetDocumentStatus, } from '@/hooks/documentHooks'; import { useSelectParserList } from '@/hooks/userSettingHook'; import { IKnowledgeFile } from '@/interfaces/database/knowledge'; +import { getExtension } from '@/utils/documentUtils'; import { FileOutlined, FileTextOutlined, @@ -15,6 +18,7 @@ import { Button, Divider, Dropdown, + Flex, Input, Space, Switch, @@ -38,8 +42,6 @@ import ParsingActionCell from './parsing-action-cell'; import ParsingStatusCell from './parsing-status-cell'; import RenameModal from './rename-modal'; -import ChunkMethodModal from '@/components/chunk-method-modal'; -import { getExtension } from '@/utils/documentUtils'; import styles from './index.less'; const KnowledgeFile = () => { @@ -114,10 +116,19 @@ const KnowledgeFile = () => { dataIndex: 'name', key: 'name', fixed: 'left', - render: (text: any, { id, thumbnail }) => ( + render: (text: any, { id, thumbnail, name }) => ( <div className={styles.tochunks} onClick={() => toChunk(id)}> - <img className={styles.img} src={thumbnail} alt="" /> - {text} + <Flex gap={10} align="center"> + {thumbnail ? ( + <img className={styles.img} src={thumbnail} alt="" /> + ) : ( + <SvgIcon + name={`file-icon/${getExtension(name)}`} + width={24} + ></SvgIcon> + )} + {text} + </Flex> </div> ), }, diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx index 4b449f2..4716861 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx @@ -1,28 +1,21 @@ +import { useTestChunkRetrieval } from '@/hooks/knowledgeHook'; import { Flex, Form } from 'antd'; +import { useEffect } from 'react'; +import { useDispatch } from 'umi'; import TestingControl from './testing-control'; import TestingResult from './testing-result'; -import { useKnowledgeBaseId } from '@/hooks/knowledgeHook'; -import { useEffect } from 'react'; -import { useDispatch } from 'umi'; import styles from './index.less'; const KnowledgeTesting = () => { const [form] = Form.useForm(); + const testChunk = useTestChunkRetrieval(); const dispatch = useDispatch(); - const knowledgeBaseId = useKnowledgeBaseId(); const handleTesting = async () => { const values = await form.validateFields(); - console.info(values); - dispatch({ - type: 'testingModel/testDocumentChunk', - payload: { - ...values, - kb_id: knowledgeBaseId, - }, - }); + testChunk(values); }; useEffect(() => { diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx index 4630e2e..a2d915b 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx @@ -2,10 +2,9 @@ import SimilaritySlider from '@/components/similarity-slider'; import { Button, Card, Divider, Flex, Form, Input, Slider, Tag } from 'antd'; import { FormInstance } from 'antd/lib'; +import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; import styles from './index.less'; -const list = [1, 2, 3]; - type FieldType = { similarity_threshold?: number; vector_similarity_weight?: number; @@ -20,6 +19,9 @@ interface IProps { const TestingControl = ({ form, handleTesting }: IProps) => { const question = Form.useWatch('question', { form, preserve: true }); + const loading = useOneNamespaceEffectsLoading('testingModel', [ + 'testDocumentChunk', + ]); const buttonDisabled = !question || (typeof question === 'string' && question.trim() === ''); @@ -65,6 +67,7 @@ const TestingControl = ({ form, handleTesting }: IProps) => { size="small" onClick={handleTesting} disabled={buttonDisabled} + loading={loading} > Testing </Button> diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less index 1059af5..464d306 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less @@ -35,9 +35,11 @@ } .image { width: 100px; + object-fit: contain; } - .imagePreview { - display: block; - width: 260px; - } +} +.imagePreview { + display: block; + max-width: 45vw; + max-height: 40vh; } diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx index 9277418..1dd4b5f 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx @@ -104,7 +104,7 @@ const TestingResult = ({ handleTesting }: IProps) => { <Flex gap={'middle'}> {x.img_id && ( <Popover - placement="topRight" + placement="left" content={ <Image id={x.img_id} diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx index cb80d01..a0e2816 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx @@ -1,6 +1,7 @@ import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg'; import NewDocumentLink from '@/components/new-document-link'; import { ITestingDocument } from '@/interfaces/database/knowledge'; +import { isPdf } from '@/utils/documentUtils'; import { Table, TableProps } from 'antd'; import { useDispatch, useSelector } from 'umi'; @@ -33,8 +34,8 @@ const SelectFiles = ({ handleTesting }: IProps) => { title: 'View', key: 'view', width: 50, - render: (_, { doc_id }) => ( - <NewDocumentLink documentId={doc_id}> + render: (_, { doc_id, doc_name }) => ( + <NewDocumentLink documentId={doc_id} preventDefault={!isPdf(doc_name)}> <NavigationPointerIcon /> </NewDocumentLink> ), diff --git a/web/src/pages/chat/chat-container/index.less b/web/src/pages/chat/chat-container/index.less index e13b72d..b521e4b 100644 --- a/web/src/pages/chat/chat-container/index.less +++ b/web/src/pages/chat/chat-container/index.less @@ -64,3 +64,6 @@ max-height: 45vh; overflow-y: auto; } +.documentLink { + padding: 0; +} diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx index a927121..887e92f 100644 --- a/web/src/pages/chat/chat-container/index.tsx +++ b/web/src/pages/chat/chat-container/index.tsx @@ -36,6 +36,8 @@ import { useSendMessage, } from '../hooks'; +import SvgIcon from '@/components/svg-icon'; +import { getExtension, isPdf } from '@/utils/documentUtils'; import styles from './index.less'; const reg = /(#{2}\d+\${2})/g; @@ -74,7 +76,10 @@ const MessageItem = ({ const isAssistant = item.role === MessageType.Assistant; const handleDocumentButtonClick = useCallback( - (documentId: string, chunk: IChunk) => () => { + (documentId: string, chunk: IChunk, isPdf: boolean) => () => { + if (!isPdf) { + return; + } clickDocumentButton(documentId, chunk); }, [clickDocumentButton], @@ -88,26 +93,31 @@ const MessageItem = ({ (x) => x?.doc_id === chunkItem?.doc_id, ); const documentId = document?.doc_id; + const fileThumbnail = documentId ? fileThumbnails[documentId] : ''; + const fileExtension = documentId ? getExtension(document?.doc_name) : ''; + const imageId = chunkItem?.img_id; return ( <Flex key={chunkItem?.chunk_id} gap={10} className={styles.referencePopoverWrapper} > - <Popover - placement="left" - content={ + {imageId && ( + <Popover + placement="left" + content={ + <Image + id={imageId} + className={styles.referenceImagePreview} + ></Image> + } + > <Image - id={chunkItem?.img_id} - className={styles.referenceImagePreview} + id={imageId} + className={styles.referenceChunkImage} ></Image> - } - > - <Image - id={chunkItem?.img_id} - className={styles.referenceChunkImage} - ></Image> - </Popover> + </Popover> + )} <Space direction={'vertical'}> <div dangerouslySetInnerHTML={{ @@ -116,11 +126,23 @@ const MessageItem = ({ className={styles.chunkContentText} ></div> {documentId && ( - <Flex gap={'middle'}> - <img src={fileThumbnails[documentId]} alt="" /> + <Flex gap={'small'}> + {fileThumbnail ? ( + <img src={fileThumbnail} alt="" /> + ) : ( + <SvgIcon + name={`file-icon/${fileExtension}`} + width={24} + ></SvgIcon> + )} <Button type="link" - onClick={handleDocumentButtonClick(documentId, chunkItem)} + className={styles.documentLink} + onClick={handleDocumentButtonClick( + documentId, + chunkItem, + fileExtension === 'pdf', + )} > {document?.doc_name} </Button> @@ -224,17 +246,31 @@ const MessageItem = ({ <List bordered dataSource={referenceDocumentList} - renderItem={(item) => ( - <List.Item> - {/* <SvgIcon name={getFileIcon(item.doc_name)}></SvgIcon> */} - <Flex gap={'middle'}> - <img src={fileThumbnails[item.doc_id]}></img> - <NewDocumentLink documentId={item.doc_id}> - {item.doc_name} - </NewDocumentLink> - </Flex> - </List.Item> - )} + renderItem={(item) => { + const fileThumbnail = fileThumbnails[item.doc_id]; + const fileExtension = getExtension(item.doc_name); + return ( + <List.Item> + <Flex gap={'small'} align="center"> + {fileThumbnail ? ( + <img src={fileThumbnail}></img> + ) : ( + <SvgIcon + name={`file-icon/${fileExtension}`} + width={24} + ></SvgIcon> + )} + + <NewDocumentLink + documentId={item.doc_id} + preventDefault={!isPdf(item.doc_name)} + > + {item.doc_name} + </NewDocumentLink> + </Flex> + </List.Item> + ); + }} /> )} </Flex> diff --git a/web/src/utils/documentUtils.ts b/web/src/utils/documentUtils.ts index 27e9964..f99d005 100644 --- a/web/src/utils/documentUtils.ts +++ b/web/src/utils/documentUtils.ts @@ -38,3 +38,7 @@ export const isFileUploadDone = (file: UploadFile) => file.status === 'done'; export const getExtension = (name: string) => name?.slice(name.lastIndexOf('.') + 1).toLowerCase() ?? ''; + +export const isPdf = (name: string) => { + return getExtension(name) === 'pdf'; +}; -- GitLab