feat: add corresponding icons to files (#164)

This commit is contained in:
balibabu
2024-03-28 16:18:16 +08:00
committed by GitHub
parent a5384446e3
commit b6837d4ca6
13 changed files with 137 additions and 55 deletions

View File

@ -3,12 +3,18 @@ import React from 'react';
interface IProps extends React.PropsWithChildren { interface IProps extends React.PropsWithChildren {
documentId: string; documentId: string;
preventDefault?: boolean;
} }
const NewDocumentLink = ({ children, documentId }: IProps) => { const NewDocumentLink = ({
children,
documentId,
preventDefault = false,
}: IProps) => {
return ( return (
<a <a
target="_blank" target="_blank"
onClick={!preventDefault ? undefined : (e) => e.preventDefault()}
href={`${api_host}/document/get/${documentId}`} href={`${api_host}/document/get/${documentId}`}
rel="noreferrer" rel="noreferrer"
> >

View File

@ -206,3 +206,26 @@ export const useSelectKnowledgeDetails = () => {
return knowledgeDetails; return knowledgeDetails;
}; };
//#endregion //#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

View File

@ -37,6 +37,7 @@
} }
.chunkContainer { .chunkContainer {
display: flex;
height: calc(100vh - 332px); height: calc(100vh - 332px);
} }

View File

@ -22,7 +22,6 @@
.img { .img {
height: 24px; height: 24px;
width: 24px; width: 24px;
margin-right: 10px;
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
} }

View File

@ -1,9 +1,12 @@
import ChunkMethodModal from '@/components/chunk-method-modal';
import SvgIcon from '@/components/svg-icon';
import { import {
useSelectDocumentList, useSelectDocumentList,
useSetDocumentStatus, useSetDocumentStatus,
} from '@/hooks/documentHooks'; } from '@/hooks/documentHooks';
import { useSelectParserList } from '@/hooks/userSettingHook'; import { useSelectParserList } from '@/hooks/userSettingHook';
import { IKnowledgeFile } from '@/interfaces/database/knowledge'; import { IKnowledgeFile } from '@/interfaces/database/knowledge';
import { getExtension } from '@/utils/documentUtils';
import { import {
FileOutlined, FileOutlined,
FileTextOutlined, FileTextOutlined,
@ -15,6 +18,7 @@ import {
Button, Button,
Divider, Divider,
Dropdown, Dropdown,
Flex,
Input, Input,
Space, Space,
Switch, Switch,
@ -38,8 +42,6 @@ import ParsingActionCell from './parsing-action-cell';
import ParsingStatusCell from './parsing-status-cell'; import ParsingStatusCell from './parsing-status-cell';
import RenameModal from './rename-modal'; import RenameModal from './rename-modal';
import ChunkMethodModal from '@/components/chunk-method-modal';
import { getExtension } from '@/utils/documentUtils';
import styles from './index.less'; import styles from './index.less';
const KnowledgeFile = () => { const KnowledgeFile = () => {
@ -114,10 +116,19 @@ const KnowledgeFile = () => {
dataIndex: 'name', dataIndex: 'name',
key: 'name', key: 'name',
fixed: 'left', fixed: 'left',
render: (text: any, { id, thumbnail }) => ( render: (text: any, { id, thumbnail, name }) => (
<div className={styles.tochunks} onClick={() => toChunk(id)}> <div className={styles.tochunks} onClick={() => toChunk(id)}>
<Flex gap={10} align="center">
{thumbnail ? (
<img className={styles.img} src={thumbnail} alt="" /> <img className={styles.img} src={thumbnail} alt="" />
) : (
<SvgIcon
name={`file-icon/${getExtension(name)}`}
width={24}
></SvgIcon>
)}
{text} {text}
</Flex>
</div> </div>
), ),
}, },

View File

@ -1,28 +1,21 @@
import { useTestChunkRetrieval } from '@/hooks/knowledgeHook';
import { Flex, Form } from 'antd'; import { Flex, Form } from 'antd';
import { useEffect } from 'react';
import { useDispatch } from 'umi';
import TestingControl from './testing-control'; import TestingControl from './testing-control';
import TestingResult from './testing-result'; import TestingResult from './testing-result';
import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
import { useEffect } from 'react';
import { useDispatch } from 'umi';
import styles from './index.less'; import styles from './index.less';
const KnowledgeTesting = () => { const KnowledgeTesting = () => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const testChunk = useTestChunkRetrieval();
const dispatch = useDispatch(); const dispatch = useDispatch();
const knowledgeBaseId = useKnowledgeBaseId();
const handleTesting = async () => { const handleTesting = async () => {
const values = await form.validateFields(); const values = await form.validateFields();
console.info(values); testChunk(values);
dispatch({
type: 'testingModel/testDocumentChunk',
payload: {
...values,
kb_id: knowledgeBaseId,
},
});
}; };
useEffect(() => { useEffect(() => {

View File

@ -2,10 +2,9 @@ import SimilaritySlider from '@/components/similarity-slider';
import { Button, Card, Divider, Flex, Form, Input, Slider, Tag } from 'antd'; import { Button, Card, Divider, Flex, Form, Input, Slider, Tag } from 'antd';
import { FormInstance } from 'antd/lib'; import { FormInstance } from 'antd/lib';
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
import styles from './index.less'; import styles from './index.less';
const list = [1, 2, 3];
type FieldType = { type FieldType = {
similarity_threshold?: number; similarity_threshold?: number;
vector_similarity_weight?: number; vector_similarity_weight?: number;
@ -20,6 +19,9 @@ interface IProps {
const TestingControl = ({ form, handleTesting }: IProps) => { const TestingControl = ({ form, handleTesting }: IProps) => {
const question = Form.useWatch('question', { form, preserve: true }); const question = Form.useWatch('question', { form, preserve: true });
const loading = useOneNamespaceEffectsLoading('testingModel', [
'testDocumentChunk',
]);
const buttonDisabled = const buttonDisabled =
!question || (typeof question === 'string' && question.trim() === ''); !question || (typeof question === 'string' && question.trim() === '');
@ -65,6 +67,7 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
size="small" size="small"
onClick={handleTesting} onClick={handleTesting}
disabled={buttonDisabled} disabled={buttonDisabled}
loading={loading}
> >
Testing Testing
</Button> </Button>

View File

@ -35,9 +35,11 @@
} }
.image { .image {
width: 100px; width: 100px;
} object-fit: contain;
.imagePreview {
display: block;
width: 260px;
} }
} }
.imagePreview {
display: block;
max-width: 45vw;
max-height: 40vh;
}

View File

@ -104,7 +104,7 @@ const TestingResult = ({ handleTesting }: IProps) => {
<Flex gap={'middle'}> <Flex gap={'middle'}>
{x.img_id && ( {x.img_id && (
<Popover <Popover
placement="topRight" placement="left"
content={ content={
<Image <Image
id={x.img_id} id={x.img_id}

View File

@ -1,6 +1,7 @@
import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg'; import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg';
import NewDocumentLink from '@/components/new-document-link'; import NewDocumentLink from '@/components/new-document-link';
import { ITestingDocument } from '@/interfaces/database/knowledge'; import { ITestingDocument } from '@/interfaces/database/knowledge';
import { isPdf } from '@/utils/documentUtils';
import { Table, TableProps } from 'antd'; import { Table, TableProps } from 'antd';
import { useDispatch, useSelector } from 'umi'; import { useDispatch, useSelector } from 'umi';
@ -33,8 +34,8 @@ const SelectFiles = ({ handleTesting }: IProps) => {
title: 'View', title: 'View',
key: 'view', key: 'view',
width: 50, width: 50,
render: (_, { doc_id }) => ( render: (_, { doc_id, doc_name }) => (
<NewDocumentLink documentId={doc_id}> <NewDocumentLink documentId={doc_id} preventDefault={!isPdf(doc_name)}>
<NavigationPointerIcon /> <NavigationPointerIcon />
</NewDocumentLink> </NewDocumentLink>
), ),

View File

@ -64,3 +64,6 @@
max-height: 45vh; max-height: 45vh;
overflow-y: auto; overflow-y: auto;
} }
.documentLink {
padding: 0;
}

View File

@ -36,6 +36,8 @@ import {
useSendMessage, useSendMessage,
} from '../hooks'; } from '../hooks';
import SvgIcon from '@/components/svg-icon';
import { getExtension, isPdf } from '@/utils/documentUtils';
import styles from './index.less'; import styles from './index.less';
const reg = /(#{2}\d+\${2})/g; const reg = /(#{2}\d+\${2})/g;
@ -74,7 +76,10 @@ const MessageItem = ({
const isAssistant = item.role === MessageType.Assistant; const isAssistant = item.role === MessageType.Assistant;
const handleDocumentButtonClick = useCallback( const handleDocumentButtonClick = useCallback(
(documentId: string, chunk: IChunk) => () => { (documentId: string, chunk: IChunk, isPdf: boolean) => () => {
if (!isPdf) {
return;
}
clickDocumentButton(documentId, chunk); clickDocumentButton(documentId, chunk);
}, },
[clickDocumentButton], [clickDocumentButton],
@ -88,26 +93,31 @@ const MessageItem = ({
(x) => x?.doc_id === chunkItem?.doc_id, (x) => x?.doc_id === chunkItem?.doc_id,
); );
const documentId = document?.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 ( return (
<Flex <Flex
key={chunkItem?.chunk_id} key={chunkItem?.chunk_id}
gap={10} gap={10}
className={styles.referencePopoverWrapper} className={styles.referencePopoverWrapper}
> >
{imageId && (
<Popover <Popover
placement="left" placement="left"
content={ content={
<Image <Image
id={chunkItem?.img_id} id={imageId}
className={styles.referenceImagePreview} className={styles.referenceImagePreview}
></Image> ></Image>
} }
> >
<Image <Image
id={chunkItem?.img_id} id={imageId}
className={styles.referenceChunkImage} className={styles.referenceChunkImage}
></Image> ></Image>
</Popover> </Popover>
)}
<Space direction={'vertical'}> <Space direction={'vertical'}>
<div <div
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
@ -116,11 +126,23 @@ const MessageItem = ({
className={styles.chunkContentText} className={styles.chunkContentText}
></div> ></div>
{documentId && ( {documentId && (
<Flex gap={'middle'}> <Flex gap={'small'}>
<img src={fileThumbnails[documentId]} alt="" /> {fileThumbnail ? (
<img src={fileThumbnail} alt="" />
) : (
<SvgIcon
name={`file-icon/${fileExtension}`}
width={24}
></SvgIcon>
)}
<Button <Button
type="link" type="link"
onClick={handleDocumentButtonClick(documentId, chunkItem)} className={styles.documentLink}
onClick={handleDocumentButtonClick(
documentId,
chunkItem,
fileExtension === 'pdf',
)}
> >
{document?.doc_name} {document?.doc_name}
</Button> </Button>
@ -224,17 +246,31 @@ const MessageItem = ({
<List <List
bordered bordered
dataSource={referenceDocumentList} dataSource={referenceDocumentList}
renderItem={(item) => ( renderItem={(item) => {
const fileThumbnail = fileThumbnails[item.doc_id];
const fileExtension = getExtension(item.doc_name);
return (
<List.Item> <List.Item>
{/* <SvgIcon name={getFileIcon(item.doc_name)}></SvgIcon> */} <Flex gap={'small'} align="center">
<Flex gap={'middle'}> {fileThumbnail ? (
<img src={fileThumbnails[item.doc_id]}></img> <img src={fileThumbnail}></img>
<NewDocumentLink documentId={item.doc_id}> ) : (
<SvgIcon
name={`file-icon/${fileExtension}`}
width={24}
></SvgIcon>
)}
<NewDocumentLink
documentId={item.doc_id}
preventDefault={!isPdf(item.doc_name)}
>
{item.doc_name} {item.doc_name}
</NewDocumentLink> </NewDocumentLink>
</Flex> </Flex>
</List.Item> </List.Item>
)} );
}}
/> />
)} )}
</Flex> </Flex>

View File

@ -38,3 +38,7 @@ export const isFileUploadDone = (file: UploadFile) => file.status === 'done';
export const getExtension = (name: string) => export const getExtension = (name: string) =>
name?.slice(name.lastIndexOf('.') + 1).toLowerCase() ?? ''; name?.slice(name.lastIndexOf('.') + 1).toLowerCase() ?? '';
export const isPdf = (name: string) => {
return getExtension(name) === 'pdf';
};