balibabu commited on
Commit
b0b89da
·
1 Parent(s): 8ee4f9f

feat: add corresponding icons to files (#164)

Browse files
web/src/components/new-document-link.tsx CHANGED
@@ -3,12 +3,18 @@ import React from 'react';
3
 
4
  interface IProps extends React.PropsWithChildren {
5
  documentId: string;
 
6
  }
7
 
8
- const NewDocumentLink = ({ children, documentId }: IProps) => {
 
 
 
 
9
  return (
10
  <a
11
  target="_blank"
 
12
  href={`${api_host}/document/get/${documentId}`}
13
  rel="noreferrer"
14
  >
 
3
 
4
  interface IProps extends React.PropsWithChildren {
5
  documentId: string;
6
+ preventDefault?: boolean;
7
  }
8
 
9
+ const NewDocumentLink = ({
10
+ children,
11
+ documentId,
12
+ preventDefault = false,
13
+ }: IProps) => {
14
  return (
15
  <a
16
  target="_blank"
17
+ onClick={!preventDefault ? undefined : (e) => e.preventDefault()}
18
  href={`${api_host}/document/get/${documentId}`}
19
  rel="noreferrer"
20
  >
web/src/hooks/knowledgeHook.ts CHANGED
@@ -206,3 +206,26 @@ export const useSelectKnowledgeDetails = () => {
206
  return knowledgeDetails;
207
  };
208
  //#endregion
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  return knowledgeDetails;
207
  };
208
  //#endregion
209
+
210
+ //#region Retrieval testing
211
+
212
+ export const useTestChunkRetrieval = () => {
213
+ const dispatch = useDispatch();
214
+ const knowledgeBaseId = useKnowledgeBaseId();
215
+
216
+ const testChunk = useCallback(
217
+ (values: any) => {
218
+ dispatch({
219
+ type: 'testingModel/testDocumentChunk',
220
+ payload: {
221
+ ...values,
222
+ kb_id: knowledgeBaseId,
223
+ },
224
+ });
225
+ },
226
+ [dispatch, knowledgeBaseId],
227
+ );
228
+
229
+ return testChunk;
230
+ };
231
+ //#endregion
web/src/pages/add-knowledge/components/knowledge-chunk/index.less CHANGED
@@ -37,6 +37,7 @@
37
  }
38
 
39
  .chunkContainer {
 
40
  height: calc(100vh - 332px);
41
  }
42
 
 
37
  }
38
 
39
  .chunkContainer {
40
+ display: flex;
41
  height: calc(100vh - 332px);
42
  }
43
 
web/src/pages/add-knowledge/components/knowledge-file/index.less CHANGED
@@ -22,7 +22,6 @@
22
  .img {
23
  height: 24px;
24
  width: 24px;
25
- margin-right: 10px;
26
  display: inline-block;
27
  vertical-align: middle;
28
  }
 
22
  .img {
23
  height: 24px;
24
  width: 24px;
 
25
  display: inline-block;
26
  vertical-align: middle;
27
  }
web/src/pages/add-knowledge/components/knowledge-file/index.tsx CHANGED
@@ -1,9 +1,12 @@
 
 
1
  import {
2
  useSelectDocumentList,
3
  useSetDocumentStatus,
4
  } from '@/hooks/documentHooks';
5
  import { useSelectParserList } from '@/hooks/userSettingHook';
6
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
 
7
  import {
8
  FileOutlined,
9
  FileTextOutlined,
@@ -15,6 +18,7 @@ import {
15
  Button,
16
  Divider,
17
  Dropdown,
 
18
  Input,
19
  Space,
20
  Switch,
@@ -38,8 +42,6 @@ import ParsingActionCell from './parsing-action-cell';
38
  import ParsingStatusCell from './parsing-status-cell';
39
  import RenameModal from './rename-modal';
40
 
41
- import ChunkMethodModal from '@/components/chunk-method-modal';
42
- import { getExtension } from '@/utils/documentUtils';
43
  import styles from './index.less';
44
 
45
  const KnowledgeFile = () => {
@@ -114,10 +116,19 @@ const KnowledgeFile = () => {
114
  dataIndex: 'name',
115
  key: 'name',
116
  fixed: 'left',
117
- render: (text: any, { id, thumbnail }) => (
118
  <div className={styles.tochunks} onClick={() => toChunk(id)}>
119
- <img className={styles.img} src={thumbnail} alt="" />
120
- {text}
 
 
 
 
 
 
 
 
 
121
  </div>
122
  ),
123
  },
 
1
+ import ChunkMethodModal from '@/components/chunk-method-modal';
2
+ import SvgIcon from '@/components/svg-icon';
3
  import {
4
  useSelectDocumentList,
5
  useSetDocumentStatus,
6
  } from '@/hooks/documentHooks';
7
  import { useSelectParserList } from '@/hooks/userSettingHook';
8
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
9
+ import { getExtension } from '@/utils/documentUtils';
10
  import {
11
  FileOutlined,
12
  FileTextOutlined,
 
18
  Button,
19
  Divider,
20
  Dropdown,
21
+ Flex,
22
  Input,
23
  Space,
24
  Switch,
 
42
  import ParsingStatusCell from './parsing-status-cell';
43
  import RenameModal from './rename-modal';
44
 
 
 
45
  import styles from './index.less';
46
 
47
  const KnowledgeFile = () => {
 
116
  dataIndex: 'name',
117
  key: 'name',
118
  fixed: 'left',
119
+ render: (text: any, { id, thumbnail, name }) => (
120
  <div className={styles.tochunks} onClick={() => toChunk(id)}>
121
+ <Flex gap={10} align="center">
122
+ {thumbnail ? (
123
+ <img className={styles.img} src={thumbnail} alt="" />
124
+ ) : (
125
+ <SvgIcon
126
+ name={`file-icon/${getExtension(name)}`}
127
+ width={24}
128
+ ></SvgIcon>
129
+ )}
130
+ {text}
131
+ </Flex>
132
  </div>
133
  ),
134
  },
web/src/pages/add-knowledge/components/knowledge-testing/index.tsx CHANGED
@@ -1,28 +1,21 @@
 
1
  import { Flex, Form } from 'antd';
 
 
2
  import TestingControl from './testing-control';
3
  import TestingResult from './testing-result';
4
 
5
- import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
6
- import { useEffect } from 'react';
7
- import { useDispatch } from 'umi';
8
  import styles from './index.less';
9
 
10
  const KnowledgeTesting = () => {
11
  const [form] = Form.useForm();
 
12
 
13
  const dispatch = useDispatch();
14
- const knowledgeBaseId = useKnowledgeBaseId();
15
 
16
  const handleTesting = async () => {
17
  const values = await form.validateFields();
18
- console.info(values);
19
- dispatch({
20
- type: 'testingModel/testDocumentChunk',
21
- payload: {
22
- ...values,
23
- kb_id: knowledgeBaseId,
24
- },
25
- });
26
  };
27
 
28
  useEffect(() => {
 
1
+ import { useTestChunkRetrieval } from '@/hooks/knowledgeHook';
2
  import { Flex, Form } from 'antd';
3
+ import { useEffect } from 'react';
4
+ import { useDispatch } from 'umi';
5
  import TestingControl from './testing-control';
6
  import TestingResult from './testing-result';
7
 
 
 
 
8
  import styles from './index.less';
9
 
10
  const KnowledgeTesting = () => {
11
  const [form] = Form.useForm();
12
+ const testChunk = useTestChunkRetrieval();
13
 
14
  const dispatch = useDispatch();
 
15
 
16
  const handleTesting = async () => {
17
  const values = await form.validateFields();
18
+ testChunk(values);
 
 
 
 
 
 
 
19
  };
20
 
21
  useEffect(() => {
web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx CHANGED
@@ -2,10 +2,9 @@ import SimilaritySlider from '@/components/similarity-slider';
2
  import { Button, Card, Divider, Flex, Form, Input, Slider, Tag } from 'antd';
3
  import { FormInstance } from 'antd/lib';
4
 
 
5
  import styles from './index.less';
6
 
7
- const list = [1, 2, 3];
8
-
9
  type FieldType = {
10
  similarity_threshold?: number;
11
  vector_similarity_weight?: number;
@@ -20,6 +19,9 @@ interface IProps {
20
 
21
  const TestingControl = ({ form, handleTesting }: IProps) => {
22
  const question = Form.useWatch('question', { form, preserve: true });
 
 
 
23
 
24
  const buttonDisabled =
25
  !question || (typeof question === 'string' && question.trim() === '');
@@ -65,6 +67,7 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
65
  size="small"
66
  onClick={handleTesting}
67
  disabled={buttonDisabled}
 
68
  >
69
  Testing
70
  </Button>
 
2
  import { Button, Card, Divider, Flex, Form, Input, Slider, Tag } from 'antd';
3
  import { FormInstance } from 'antd/lib';
4
 
5
+ import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
6
  import styles from './index.less';
7
 
 
 
8
  type FieldType = {
9
  similarity_threshold?: number;
10
  vector_similarity_weight?: number;
 
19
 
20
  const TestingControl = ({ form, handleTesting }: IProps) => {
21
  const question = Form.useWatch('question', { form, preserve: true });
22
+ const loading = useOneNamespaceEffectsLoading('testingModel', [
23
+ 'testDocumentChunk',
24
+ ]);
25
 
26
  const buttonDisabled =
27
  !question || (typeof question === 'string' && question.trim() === '');
 
67
  size="small"
68
  onClick={handleTesting}
69
  disabled={buttonDisabled}
70
+ loading={loading}
71
  >
72
  Testing
73
  </Button>
web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less CHANGED
@@ -35,9 +35,11 @@
35
  }
36
  .image {
37
  width: 100px;
 
38
  }
39
- .imagePreview {
40
- display: block;
41
- width: 260px;
42
- }
 
43
  }
 
35
  }
36
  .image {
37
  width: 100px;
38
+ object-fit: contain;
39
  }
40
+ }
41
+ .imagePreview {
42
+ display: block;
43
+ max-width: 45vw;
44
+ max-height: 40vh;
45
  }
web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx CHANGED
@@ -104,7 +104,7 @@ const TestingResult = ({ handleTesting }: IProps) => {
104
  <Flex gap={'middle'}>
105
  {x.img_id && (
106
  <Popover
107
- placement="topRight"
108
  content={
109
  <Image
110
  id={x.img_id}
 
104
  <Flex gap={'middle'}>
105
  {x.img_id && (
106
  <Popover
107
+ placement="left"
108
  content={
109
  <Image
110
  id={x.img_id}
web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx CHANGED
@@ -1,6 +1,7 @@
1
  import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg';
2
  import NewDocumentLink from '@/components/new-document-link';
3
  import { ITestingDocument } from '@/interfaces/database/knowledge';
 
4
  import { Table, TableProps } from 'antd';
5
  import { useDispatch, useSelector } from 'umi';
6
 
@@ -33,8 +34,8 @@ const SelectFiles = ({ handleTesting }: IProps) => {
33
  title: 'View',
34
  key: 'view',
35
  width: 50,
36
- render: (_, { doc_id }) => (
37
- <NewDocumentLink documentId={doc_id}>
38
  <NavigationPointerIcon />
39
  </NewDocumentLink>
40
  ),
 
1
  import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg';
2
  import NewDocumentLink from '@/components/new-document-link';
3
  import { ITestingDocument } from '@/interfaces/database/knowledge';
4
+ import { isPdf } from '@/utils/documentUtils';
5
  import { Table, TableProps } from 'antd';
6
  import { useDispatch, useSelector } from 'umi';
7
 
 
34
  title: 'View',
35
  key: 'view',
36
  width: 50,
37
+ render: (_, { doc_id, doc_name }) => (
38
+ <NewDocumentLink documentId={doc_id} preventDefault={!isPdf(doc_name)}>
39
  <NavigationPointerIcon />
40
  </NewDocumentLink>
41
  ),
web/src/pages/chat/chat-container/index.less CHANGED
@@ -64,3 +64,6 @@
64
  max-height: 45vh;
65
  overflow-y: auto;
66
  }
 
 
 
 
64
  max-height: 45vh;
65
  overflow-y: auto;
66
  }
67
+ .documentLink {
68
+ padding: 0;
69
+ }
web/src/pages/chat/chat-container/index.tsx CHANGED
@@ -36,6 +36,8 @@ import {
36
  useSendMessage,
37
  } from '../hooks';
38
 
 
 
39
  import styles from './index.less';
40
 
41
  const reg = /(#{2}\d+\${2})/g;
@@ -74,7 +76,10 @@ const MessageItem = ({
74
  const isAssistant = item.role === MessageType.Assistant;
75
 
76
  const handleDocumentButtonClick = useCallback(
77
- (documentId: string, chunk: IChunk) => () => {
 
 
 
78
  clickDocumentButton(documentId, chunk);
79
  },
80
  [clickDocumentButton],
@@ -88,26 +93,31 @@ const MessageItem = ({
88
  (x) => x?.doc_id === chunkItem?.doc_id,
89
  );
90
  const documentId = document?.doc_id;
 
 
 
91
  return (
92
  <Flex
93
  key={chunkItem?.chunk_id}
94
  gap={10}
95
  className={styles.referencePopoverWrapper}
96
  >
97
- <Popover
98
- placement="left"
99
- content={
 
 
 
 
 
 
 
100
  <Image
101
- id={chunkItem?.img_id}
102
- className={styles.referenceImagePreview}
103
  ></Image>
104
- }
105
- >
106
- <Image
107
- id={chunkItem?.img_id}
108
- className={styles.referenceChunkImage}
109
- ></Image>
110
- </Popover>
111
  <Space direction={'vertical'}>
112
  <div
113
  dangerouslySetInnerHTML={{
@@ -116,11 +126,23 @@ const MessageItem = ({
116
  className={styles.chunkContentText}
117
  ></div>
118
  {documentId && (
119
- <Flex gap={'middle'}>
120
- <img src={fileThumbnails[documentId]} alt="" />
 
 
 
 
 
 
 
121
  <Button
122
  type="link"
123
- onClick={handleDocumentButtonClick(documentId, chunkItem)}
 
 
 
 
 
124
  >
125
  {document?.doc_name}
126
  </Button>
@@ -224,17 +246,31 @@ const MessageItem = ({
224
  <List
225
  bordered
226
  dataSource={referenceDocumentList}
227
- renderItem={(item) => (
228
- <List.Item>
229
- {/* <SvgIcon name={getFileIcon(item.doc_name)}></SvgIcon> */}
230
- <Flex gap={'middle'}>
231
- <img src={fileThumbnails[item.doc_id]}></img>
232
- <NewDocumentLink documentId={item.doc_id}>
233
- {item.doc_name}
234
- </NewDocumentLink>
235
- </Flex>
236
- </List.Item>
237
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  />
239
  )}
240
  </Flex>
 
36
  useSendMessage,
37
  } from '../hooks';
38
 
39
+ import SvgIcon from '@/components/svg-icon';
40
+ import { getExtension, isPdf } from '@/utils/documentUtils';
41
  import styles from './index.less';
42
 
43
  const reg = /(#{2}\d+\${2})/g;
 
76
  const isAssistant = item.role === MessageType.Assistant;
77
 
78
  const handleDocumentButtonClick = useCallback(
79
+ (documentId: string, chunk: IChunk, isPdf: boolean) => () => {
80
+ if (!isPdf) {
81
+ return;
82
+ }
83
  clickDocumentButton(documentId, chunk);
84
  },
85
  [clickDocumentButton],
 
93
  (x) => x?.doc_id === chunkItem?.doc_id,
94
  );
95
  const documentId = document?.doc_id;
96
+ const fileThumbnail = documentId ? fileThumbnails[documentId] : '';
97
+ const fileExtension = documentId ? getExtension(document?.doc_name) : '';
98
+ const imageId = chunkItem?.img_id;
99
  return (
100
  <Flex
101
  key={chunkItem?.chunk_id}
102
  gap={10}
103
  className={styles.referencePopoverWrapper}
104
  >
105
+ {imageId && (
106
+ <Popover
107
+ placement="left"
108
+ content={
109
+ <Image
110
+ id={imageId}
111
+ className={styles.referenceImagePreview}
112
+ ></Image>
113
+ }
114
+ >
115
  <Image
116
+ id={imageId}
117
+ className={styles.referenceChunkImage}
118
  ></Image>
119
+ </Popover>
120
+ )}
 
 
 
 
 
121
  <Space direction={'vertical'}>
122
  <div
123
  dangerouslySetInnerHTML={{
 
126
  className={styles.chunkContentText}
127
  ></div>
128
  {documentId && (
129
+ <Flex gap={'small'}>
130
+ {fileThumbnail ? (
131
+ <img src={fileThumbnail} alt="" />
132
+ ) : (
133
+ <SvgIcon
134
+ name={`file-icon/${fileExtension}`}
135
+ width={24}
136
+ ></SvgIcon>
137
+ )}
138
  <Button
139
  type="link"
140
+ className={styles.documentLink}
141
+ onClick={handleDocumentButtonClick(
142
+ documentId,
143
+ chunkItem,
144
+ fileExtension === 'pdf',
145
+ )}
146
  >
147
  {document?.doc_name}
148
  </Button>
 
246
  <List
247
  bordered
248
  dataSource={referenceDocumentList}
249
+ renderItem={(item) => {
250
+ const fileThumbnail = fileThumbnails[item.doc_id];
251
+ const fileExtension = getExtension(item.doc_name);
252
+ return (
253
+ <List.Item>
254
+ <Flex gap={'small'} align="center">
255
+ {fileThumbnail ? (
256
+ <img src={fileThumbnail}></img>
257
+ ) : (
258
+ <SvgIcon
259
+ name={`file-icon/${fileExtension}`}
260
+ width={24}
261
+ ></SvgIcon>
262
+ )}
263
+
264
+ <NewDocumentLink
265
+ documentId={item.doc_id}
266
+ preventDefault={!isPdf(item.doc_name)}
267
+ >
268
+ {item.doc_name}
269
+ </NewDocumentLink>
270
+ </Flex>
271
+ </List.Item>
272
+ );
273
+ }}
274
  />
275
  )}
276
  </Flex>
web/src/utils/documentUtils.ts CHANGED
@@ -38,3 +38,7 @@ export const isFileUploadDone = (file: UploadFile) => file.status === 'done';
38
 
39
  export const getExtension = (name: string) =>
40
  name?.slice(name.lastIndexOf('.') + 1).toLowerCase() ?? '';
 
 
 
 
 
38
 
39
  export const getExtension = (name: string) =>
40
  name?.slice(name.lastIndexOf('.') + 1).toLowerCase() ?? '';
41
+
42
+ export const isPdf = (name: string) => {
43
+ return getExtension(name) === 'pdf';
44
+ };