balibabu commited on
Commit
4086c42
·
1 Parent(s): 64350e9

feat: fetch knowledge detail on KnowledgeUploadFile mount and add category column to chunk table and set initial value for the model field of chat setting (#104)

Browse files

* feat: set initial value for the model field of chat setting

* feat: add category column to chunk table

* feat: fetch knowledge detail on KnowledgeUploadFile mount

web/src/hooks/knowledgeHook.ts CHANGED
@@ -1,6 +1,6 @@
1
  import showDeleteConfirm from '@/components/deleting-confirm';
2
  import { KnowledgeSearchParams } from '@/constants/knowledge';
3
- import { IKnowledge, ITenantInfo } from '@/interfaces/database/knowledge';
4
  import { useCallback, useEffect, useMemo } from 'react';
5
  import { useDispatch, useSearchParams, useSelector } from 'umi';
6
 
@@ -11,6 +11,17 @@ export const useKnowledgeBaseId = (): string => {
11
  return knowledgeBaseId || '';
12
  };
13
 
 
 
 
 
 
 
 
 
 
 
 
14
  export const useDeleteDocumentById = (): {
15
  removeDocument: (documentId: string) => Promise<number>;
16
  } => {
@@ -36,12 +47,37 @@ export const useDeleteDocumentById = (): {
36
  };
37
  };
38
 
39
- export const useGetDocumentDefaultParser = (knowledgeBaseId: string) => {
40
- const data: IKnowledge[] = useSelector(
41
- (state: any) => state.knowledgeModel.data,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  );
43
 
44
- const item = data.find((x) => x.id === knowledgeBaseId);
 
 
 
 
45
 
46
  return {
47
  defaultParserId: item?.parser_id ?? '',
@@ -79,35 +115,6 @@ export const useDeleteChunkByIds = (): {
79
  };
80
  };
81
 
82
- export const useSelectParserList = (): Array<{
83
- value: string;
84
- label: string;
85
- }> => {
86
- const tenantIfo: Nullable<ITenantInfo> = useSelector(
87
- (state: any) => state.settingModel.tenantIfo,
88
- );
89
-
90
- const parserList = useMemo(() => {
91
- const parserArray: Array<string> = tenantIfo?.parser_ids.split(',') ?? [];
92
- return parserArray.map((x) => {
93
- const arr = x.split(':');
94
- return { value: arr[0], label: arr[1] };
95
- });
96
- }, [tenantIfo]);
97
-
98
- return parserList;
99
- };
100
-
101
- export const useFetchParserList = () => {
102
- const dispatch = useDispatch();
103
-
104
- useEffect(() => {
105
- dispatch({
106
- type: 'settingModel/getTenantInfo',
107
- });
108
- }, [dispatch]);
109
- };
110
-
111
  export const useFetchKnowledgeBaseConfiguration = () => {
112
  const dispatch = useDispatch();
113
  const knowledgeBaseId = useKnowledgeBaseId();
@@ -182,14 +189,3 @@ export const useFetchFileThumbnails = (docIds?: Array<string>) => {
182
 
183
  return { fileThumbnails, fetchFileThumbnails };
184
  };
185
-
186
- export const useGetKnowledgeSearchParams = () => {
187
- const [currentQueryParameters] = useSearchParams();
188
-
189
- return {
190
- documentId:
191
- currentQueryParameters.get(KnowledgeSearchParams.DocumentId) || '',
192
- knowledgeId:
193
- currentQueryParameters.get(KnowledgeSearchParams.KnowledgeId) || '',
194
- };
195
- };
 
1
  import showDeleteConfirm from '@/components/deleting-confirm';
2
  import { KnowledgeSearchParams } from '@/constants/knowledge';
3
+ import { IKnowledge } from '@/interfaces/database/knowledge';
4
  import { useCallback, useEffect, useMemo } from 'react';
5
  import { useDispatch, useSearchParams, useSelector } from 'umi';
6
 
 
11
  return knowledgeBaseId || '';
12
  };
13
 
14
+ export const useGetKnowledgeSearchParams = () => {
15
+ const [currentQueryParameters] = useSearchParams();
16
+
17
+ return {
18
+ documentId:
19
+ currentQueryParameters.get(KnowledgeSearchParams.DocumentId) || '',
20
+ knowledgeId:
21
+ currentQueryParameters.get(KnowledgeSearchParams.KnowledgeId) || '',
22
+ };
23
+ };
24
+
25
  export const useDeleteDocumentById = (): {
26
  removeDocument: (documentId: string) => Promise<number>;
27
  } => {
 
47
  };
48
  };
49
 
50
+ export const useFetchKnowledgeDetail = () => {
51
+ const dispatch = useDispatch();
52
+ const { knowledgeId } = useGetKnowledgeSearchParams();
53
+
54
+ const fetchKnowledgeDetail = useCallback(
55
+ (knowledgeId: string) => {
56
+ dispatch({
57
+ type: 'knowledgeModel/getKnowledgeDetail',
58
+ payload: { kb_id: knowledgeId },
59
+ });
60
+ },
61
+ [dispatch],
62
+ );
63
+
64
+ useEffect(() => {
65
+ fetchKnowledgeDetail(knowledgeId);
66
+ }, [fetchKnowledgeDetail, knowledgeId]);
67
+
68
+ return fetchKnowledgeDetail;
69
+ };
70
+
71
+ export const useSelectKnowledgeDetail = () => {
72
+ const knowledge: IKnowledge = useSelector(
73
+ (state: any) => state.knowledgeModel.knowledge,
74
  );
75
 
76
+ return knowledge;
77
+ };
78
+
79
+ export const useGetDocumentDefaultParser = () => {
80
+ const item = useSelectKnowledgeDetail();
81
 
82
  return {
83
  defaultParserId: item?.parser_id ?? '',
 
115
  };
116
  };
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  export const useFetchKnowledgeBaseConfiguration = () => {
119
  const dispatch = useDispatch();
120
  const knowledgeBaseId = useKnowledgeBaseId();
 
189
 
190
  return { fileThumbnails, fetchFileThumbnails };
191
  };
 
 
 
 
 
 
 
 
 
 
 
web/src/hooks/userSettingHook.ts CHANGED
@@ -1,5 +1,6 @@
 
1
  import { IUserInfo } from '@/interfaces/database/userSetting';
2
- import { useCallback, useEffect } from 'react';
3
  import { useDispatch, useSelector } from 'umi';
4
 
5
  export const useFetchUserInfo = () => {
@@ -20,3 +21,46 @@ export const useSelectUserInfo = () => {
20
 
21
  return userInfo;
22
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITenantInfo } from '@/interfaces/database/knowledge';
2
  import { IUserInfo } from '@/interfaces/database/userSetting';
3
+ import { useCallback, useEffect, useMemo } from 'react';
4
  import { useDispatch, useSelector } from 'umi';
5
 
6
  export const useFetchUserInfo = () => {
 
21
 
22
  return userInfo;
23
  };
24
+
25
+ export const useSelectTenantInfo = () => {
26
+ const tenantInfo: ITenantInfo = useSelector(
27
+ (state: any) => state.settingModel.tenantIfo,
28
+ );
29
+
30
+ return tenantInfo;
31
+ };
32
+
33
+ export const useFetchTenantInfo = (isOnMountFetching: boolean = true) => {
34
+ const dispatch = useDispatch();
35
+
36
+ const fetchTenantInfo = useCallback(() => {
37
+ dispatch({
38
+ type: 'settingModel/getTenantInfo',
39
+ });
40
+ }, [dispatch]);
41
+
42
+ useEffect(() => {
43
+ if (isOnMountFetching) {
44
+ fetchTenantInfo();
45
+ }
46
+ }, [fetchTenantInfo, isOnMountFetching]);
47
+
48
+ return fetchTenantInfo;
49
+ };
50
+
51
+ export const useSelectParserList = (): Array<{
52
+ value: string;
53
+ label: string;
54
+ }> => {
55
+ const tenantInfo: ITenantInfo = useSelectTenantInfo();
56
+
57
+ const parserList = useMemo(() => {
58
+ const parserArray: Array<string> = tenantInfo?.parser_ids.split(',') ?? [];
59
+ return parserArray.map((x) => {
60
+ const arr = x.split(':');
61
+ return { value: arr[0], label: arr[1] };
62
+ });
63
+ }, [tenantInfo]);
64
+
65
+ return parserList;
66
+ };
web/src/layouts/components/user/index.tsx CHANGED
@@ -23,19 +23,13 @@ const App: React.FC = () => {
23
  return [
24
  {
25
  key: '1',
26
- label: (
27
- <Button type="text" onClick={logout}>
28
- {t('header.logout')}
29
- </Button>
30
- ),
31
  },
32
  {
33
  key: '2',
34
- label: (
35
- <Button type="text" onClick={toSetting}>
36
- {t('header.setting')}
37
- </Button>
38
- ),
39
  },
40
  ];
41
  }, [t]);
 
23
  return [
24
  {
25
  key: '1',
26
+ onClick: logout,
27
+ label: <Button type="text">{t('header.logout')}</Button>,
 
 
 
28
  },
29
  {
30
  key: '2',
31
+ onClick: toSetting,
32
+ label: <Button type="text">{t('header.setting')}</Button>,
 
 
 
33
  },
34
  ];
35
  }, [t]);
web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.tsx CHANGED
@@ -2,11 +2,15 @@ import { ReactComponent as SelectFilesEndIcon } from '@/assets/svg/select-files-
2
  import { ReactComponent as SelectFilesStartIcon } from '@/assets/svg/select-files-start.svg';
3
  import {
4
  useDeleteDocumentById,
5
- useFetchParserList,
6
  useGetDocumentDefaultParser,
7
  useKnowledgeBaseId,
8
- useSelectParserList,
9
  } from '@/hooks/knowledgeHook';
 
 
 
 
 
10
  import uploadService from '@/services/uploadService';
11
  import {
12
  ArrowLeftOutlined,
@@ -29,10 +33,18 @@ import {
29
  UploadProps,
30
  } from 'antd';
31
  import classNames from 'classnames';
32
- import { ReactElement, useEffect, useRef, useState } from 'react';
 
 
 
 
 
 
 
33
  import { Link, useDispatch, useNavigate } from 'umi';
34
 
35
  import { KnowledgeRouteKey } from '@/constants/knowledge';
 
36
  import styles from './index.less';
37
 
38
  const { Dragger } = Upload;
@@ -43,18 +55,16 @@ type UploadRequestOption = Parameters<
43
 
44
  const UploaderItem = ({
45
  file,
46
- actions,
47
  isUpload,
 
48
  }: {
49
  isUpload: boolean;
50
  originNode: ReactElement;
51
  file: UploadFile;
52
  fileList: object[];
53
- actions: { download: Function; preview: Function; remove: any };
54
  }) => {
55
- const { parserConfig, defaultParserId } = useGetDocumentDefaultParser(
56
- file?.response?.kb_id,
57
- );
58
  const { removeDocument } = useDeleteDocumentById();
59
  const [value, setValue] = useState(defaultParserId);
60
  const dispatch = useDispatch();
@@ -97,9 +107,13 @@ const UploaderItem = ({
97
  );
98
 
99
  const handleRemove = async () => {
100
- const ret: any = await removeDocument(documentId);
101
- if (ret === 0) {
102
- actions?.remove();
 
 
 
 
103
  }
104
  };
105
 
@@ -147,40 +161,67 @@ const KnowledgeUploadFile = () => {
147
  const knowledgeBaseId = useKnowledgeBaseId();
148
  const [isUpload, setIsUpload] = useState(true);
149
  const dispatch = useDispatch();
150
-
151
- const navigate = useNavigate();
152
  const fileListRef = useRef<UploadFile[]>([]);
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
  const createRequest: (props: UploadRequestOption) => void = async function ({
155
  file,
156
  onSuccess,
157
  onError,
158
- onProgress,
159
  }) {
160
- const { data } = await uploadService.uploadFile(file, knowledgeBaseId);
161
- if (data.retcode === 0) {
 
 
 
 
162
  if (onSuccess) {
163
  onSuccess(data.data);
164
  }
165
  } else {
166
  if (onError) {
167
- onError(data.data);
168
  }
169
  }
170
  };
171
 
 
 
 
 
 
 
172
  const props: UploadProps = {
173
  name: 'file',
174
  multiple: true,
175
  itemRender(originNode, file, fileList, actions) {
176
  fileListRef.current = fileList;
 
 
 
 
 
 
177
  return (
178
  <UploaderItem
179
  isUpload={isUpload}
180
  file={file}
181
  fileList={fileList}
182
  originNode={originNode}
183
- actions={actions}
184
  ></UploaderItem>
185
  );
186
  },
@@ -207,7 +248,8 @@ const KnowledgeUploadFile = () => {
207
  }
208
  };
209
 
210
- useFetchParserList();
 
211
 
212
  return (
213
  <div className={styles.uploadWrapper}>
@@ -263,8 +305,9 @@ const KnowledgeUploadFile = () => {
263
  <section className={styles.footer}>
264
  <Button
265
  type="primary"
266
- className={styles.nextButton}
267
  onClick={handleNextClick}
 
268
  >
269
  Next
270
  </Button>
 
2
  import { ReactComponent as SelectFilesStartIcon } from '@/assets/svg/select-files-start.svg';
3
  import {
4
  useDeleteDocumentById,
5
+ useFetchKnowledgeDetail,
6
  useGetDocumentDefaultParser,
7
  useKnowledgeBaseId,
 
8
  } from '@/hooks/knowledgeHook';
9
+ import {
10
+ useFetchTenantInfo,
11
+ useSelectParserList,
12
+ } from '@/hooks/userSettingHook';
13
+
14
  import uploadService from '@/services/uploadService';
15
  import {
16
  ArrowLeftOutlined,
 
33
  UploadProps,
34
  } from 'antd';
35
  import classNames from 'classnames';
36
+ import {
37
+ ReactElement,
38
+ useCallback,
39
+ useEffect,
40
+ useMemo,
41
+ useRef,
42
+ useState,
43
+ } from 'react';
44
  import { Link, useDispatch, useNavigate } from 'umi';
45
 
46
  import { KnowledgeRouteKey } from '@/constants/knowledge';
47
+ import { isFileUploadDone } from '@/utils/documentUtils';
48
  import styles from './index.less';
49
 
50
  const { Dragger } = Upload;
 
55
 
56
  const UploaderItem = ({
57
  file,
 
58
  isUpload,
59
+ remove,
60
  }: {
61
  isUpload: boolean;
62
  originNode: ReactElement;
63
  file: UploadFile;
64
  fileList: object[];
65
+ remove: (id: string) => void;
66
  }) => {
67
+ const { parserConfig, defaultParserId } = useGetDocumentDefaultParser();
 
 
68
  const { removeDocument } = useDeleteDocumentById();
69
  const [value, setValue] = useState(defaultParserId);
70
  const dispatch = useDispatch();
 
107
  );
108
 
109
  const handleRemove = async () => {
110
+ if (file.status === 'error') {
111
+ remove(documentId);
112
+ } else {
113
+ const ret: any = await removeDocument(documentId);
114
+ if (ret === 0) {
115
+ remove(documentId);
116
+ }
117
  }
118
  };
119
 
 
161
  const knowledgeBaseId = useKnowledgeBaseId();
162
  const [isUpload, setIsUpload] = useState(true);
163
  const dispatch = useDispatch();
164
+ const [uploadedFileIds, setUploadedFileIds] = useState<string[]>([]);
 
165
  const fileListRef = useRef<UploadFile[]>([]);
166
+ const navigate = useNavigate();
167
+
168
+ const enabled = useMemo(() => {
169
+ if (isUpload) {
170
+ return (
171
+ uploadedFileIds.length > 0 &&
172
+ fileListRef.current.filter((x) => isFileUploadDone(x)).length ===
173
+ uploadedFileIds.length
174
+ );
175
+ }
176
+ return true;
177
+ }, [uploadedFileIds, isUpload]);
178
 
179
  const createRequest: (props: UploadRequestOption) => void = async function ({
180
  file,
181
  onSuccess,
182
  onError,
183
+ // onProgress,
184
  }) {
185
+ const ret = await uploadService.uploadFile(file, knowledgeBaseId);
186
+ const data = ret?.data;
187
+ if (data?.retcode === 0) {
188
+ setUploadedFileIds((pre) => {
189
+ return pre.concat(data.data.id);
190
+ });
191
  if (onSuccess) {
192
  onSuccess(data.data);
193
  }
194
  } else {
195
  if (onError) {
196
+ onError(data?.data);
197
  }
198
  }
199
  };
200
 
201
+ const removeIdFromUploadedIds = useCallback((id: string) => {
202
+ setUploadedFileIds((pre) => {
203
+ return pre.filter((x) => x !== id);
204
+ });
205
+ }, []);
206
+
207
  const props: UploadProps = {
208
  name: 'file',
209
  multiple: true,
210
  itemRender(originNode, file, fileList, actions) {
211
  fileListRef.current = fileList;
212
+ const remove = (id: string) => {
213
+ if (isFileUploadDone(file)) {
214
+ removeIdFromUploadedIds(id);
215
+ }
216
+ actions.remove();
217
+ };
218
  return (
219
  <UploaderItem
220
  isUpload={isUpload}
221
  file={file}
222
  fileList={fileList}
223
  originNode={originNode}
224
+ remove={remove}
225
  ></UploaderItem>
226
  );
227
  },
 
248
  }
249
  };
250
 
251
+ useFetchTenantInfo();
252
+ useFetchKnowledgeDetail();
253
 
254
  return (
255
  <div className={styles.uploadWrapper}>
 
305
  <section className={styles.footer}>
306
  <Button
307
  type="primary"
308
+ // className={styles.nextButton}
309
  onClick={handleNextClick}
310
+ disabled={!enabled}
311
  >
312
  Next
313
  </Button>
web/src/pages/add-knowledge/components/knowledge-file/index.tsx CHANGED
@@ -1,5 +1,9 @@
1
  import { KnowledgeRouteKey } from '@/constants/knowledge';
2
  import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
 
 
 
 
3
  import { Pagination } from '@/interfaces/common';
4
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
5
  import { getOneNamespaceEffectsLoading } from '@/utils/storeUtil';
@@ -45,6 +49,7 @@ const KnowledgeFile = () => {
45
  const [doc_id, setDocId] = useState('0');
46
  const [parser_id, setParserId] = useState('0');
47
  let navigate = useNavigate();
 
48
 
49
  const getKfList = useCallback(() => {
50
  const payload = {
@@ -214,6 +219,14 @@ const KnowledgeFile = () => {
214
  dataIndex: 'create_date',
215
  key: 'create_date',
216
  },
 
 
 
 
 
 
 
 
217
  {
218
  title: 'Parsing Status',
219
  dataIndex: 'run',
@@ -255,6 +268,8 @@ const KnowledgeFile = () => {
255
  className: `${styles.column}`,
256
  }));
257
 
 
 
258
  return (
259
  <div className={styles.datasetWrapper}>
260
  <h3>Dataset</h3>
 
1
  import { KnowledgeRouteKey } from '@/constants/knowledge';
2
  import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
3
+ import {
4
+ useFetchTenantInfo,
5
+ useSelectParserList,
6
+ } from '@/hooks/userSettingHook';
7
  import { Pagination } from '@/interfaces/common';
8
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
9
  import { getOneNamespaceEffectsLoading } from '@/utils/storeUtil';
 
49
  const [doc_id, setDocId] = useState('0');
50
  const [parser_id, setParserId] = useState('0');
51
  let navigate = useNavigate();
52
+ const parserList = useSelectParserList();
53
 
54
  const getKfList = useCallback(() => {
55
  const payload = {
 
219
  dataIndex: 'create_date',
220
  key: 'create_date',
221
  },
222
+ {
223
+ title: 'Category',
224
+ dataIndex: 'parser_id',
225
+ key: 'parser_id',
226
+ render: (text) => {
227
+ return parserList.find((x) => x.value === text)?.label;
228
+ },
229
+ },
230
  {
231
  title: 'Parsing Status',
232
  dataIndex: 'run',
 
268
  className: `${styles.column}`,
269
  }));
270
 
271
+ useFetchTenantInfo();
272
+
273
  return (
274
  <div className={styles.datasetWrapper}>
275
  <h3>Dataset</h3>
web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx CHANGED
@@ -62,7 +62,7 @@ const ParsingActionCell = ({
62
  label: (
63
  <div>
64
  <Button type="link" onClick={showSegmentSetModal}>
65
- Parser type
66
  </Button>
67
  </div>
68
  ),
 
62
  label: (
63
  <div>
64
  <Button type="link" onClick={showSegmentSetModal}>
65
+ Category
66
  </Button>
67
  </div>
68
  ),
web/src/pages/add-knowledge/components/knowledge-file/segmentSetModal.tsx CHANGED
@@ -1,4 +1,7 @@
1
- import { useFetchParserList, useSelectParserList } from '@/hooks/knowledgeHook';
 
 
 
2
  import { Modal, Space, Tag } from 'antd';
3
  import React, { useEffect, useState } from 'react';
4
  import { useDispatch, useSelector } from 'umi';
@@ -20,7 +23,7 @@ const SegmentSetModal: React.FC<kFProps> = ({
20
  const { isShowSegmentSetModal } = kFModel;
21
  const parserList = useSelectParserList();
22
 
23
- useFetchParserList();
24
 
25
  useEffect(() => {
26
  setSelectedTag(parser_id);
@@ -57,7 +60,7 @@ const SegmentSetModal: React.FC<kFProps> = ({
57
 
58
  return (
59
  <Modal
60
- title="Parser Type"
61
  open={isShowSegmentSetModal}
62
  onOk={handleOk}
63
  onCancel={handleCancel}
 
1
+ import {
2
+ useFetchTenantInfo,
3
+ useSelectParserList,
4
+ } from '@/hooks/userSettingHook';
5
  import { Modal, Space, Tag } from 'antd';
6
  import React, { useEffect, useState } from 'react';
7
  import { useDispatch, useSelector } from 'umi';
 
23
  const { isShowSegmentSetModal } = kFModel;
24
  const parserList = useSelectParserList();
25
 
26
+ useFetchTenantInfo();
27
 
28
  useEffect(() => {
29
  setSelectedTag(parser_id);
 
60
 
61
  return (
62
  <Modal
63
+ title="Category"
64
  open={isShowSegmentSetModal}
65
  onOk={handleOk}
66
  onCancel={handleCancel}
web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx CHANGED
@@ -1,9 +1,12 @@
1
  import {
2
  useFetchKnowledgeBaseConfiguration,
3
- useFetchParserList,
4
  useKnowledgeBaseId,
5
- useSelectParserList,
6
  } from '@/hooks/knowledgeHook';
 
 
 
 
 
7
  import {
8
  Button,
9
  Divider,
@@ -93,7 +96,7 @@ const Configuration = () => {
93
  });
94
  }, [form, knowledgeDetails]);
95
 
96
- useFetchParserList();
97
  useFetchKnowledgeBaseConfiguration();
98
 
99
  useFetchLlmList(LlmModelType.Embedding);
 
1
  import {
2
  useFetchKnowledgeBaseConfiguration,
 
3
  useKnowledgeBaseId,
 
4
  } from '@/hooks/knowledgeHook';
5
+ import {
6
+ useFetchTenantInfo,
7
+ useSelectParserList,
8
+ } from '@/hooks/userSettingHook';
9
+
10
  import {
11
  Button,
12
  Divider,
 
96
  });
97
  }, [form, knowledgeDetails]);
98
 
99
+ useFetchTenantInfo();
100
  useFetchKnowledgeBaseConfiguration();
101
 
102
  useFetchLlmList(LlmModelType.Embedding);
web/src/pages/add-knowledge/components/knowledge-setting/index.tsx CHANGED
@@ -1,165 +1,3 @@
1
- import { KnowledgeRouteKey } from '@/constants/knowledge';
2
- import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
3
- import { Button, Form, Input, Radio, Select, Space, Tag } from 'antd';
4
- import { useCallback, useEffect, useState } from 'react';
5
- import { useDispatch, useNavigate, useSelector } from 'umi';
6
  import Configuration from './configuration';
7
 
8
- import styles from './index.less';
9
-
10
- const { CheckableTag } = Tag;
11
- const layout = {
12
- labelCol: { span: 8 },
13
- wrapperCol: { span: 16 },
14
- labelAlign: 'left' as const,
15
- };
16
- const { Option } = Select;
17
-
18
- const KnowledgeSetting = () => {
19
- const dispatch = useDispatch();
20
- const settingModel = useSelector((state: any) => state.settingModel);
21
- let navigate = useNavigate();
22
- const { tenantIfo = {} } = settingModel;
23
- const parser_ids = tenantIfo?.parser_ids ?? '';
24
- const embd_id = tenantIfo?.embd_id ?? '';
25
- const [form] = Form.useForm();
26
- const [selectedTag, setSelectedTag] = useState('');
27
- const values = Form.useWatch([], form);
28
- const knowledgeBaseId = useKnowledgeBaseId();
29
-
30
- const getTenantInfo = useCallback(async () => {
31
- dispatch({
32
- type: 'settingModel/getTenantInfo',
33
- payload: {},
34
- });
35
- if (knowledgeBaseId) {
36
- const data = await dispatch<any>({
37
- type: 'kSModel/getKbDetail',
38
- payload: {
39
- kb_id: knowledgeBaseId,
40
- },
41
- });
42
- if (data.retcode === 0) {
43
- const { description, name, permission, embd_id } = data.data;
44
- form.setFieldsValue({ description, name, permission, embd_id });
45
- setSelectedTag(data.data.parser_id);
46
- }
47
- }
48
- }, [knowledgeBaseId, dispatch, form]);
49
-
50
- const onFinish = async () => {
51
- try {
52
- await form.validateFields();
53
-
54
- if (knowledgeBaseId) {
55
- dispatch({
56
- type: 'kSModel/updateKb',
57
- payload: {
58
- ...values,
59
- parser_id: selectedTag,
60
- kb_id: knowledgeBaseId,
61
- embd_id: undefined,
62
- },
63
- });
64
- } else {
65
- const retcode = await dispatch<any>({
66
- type: 'kSModel/createKb',
67
- payload: {
68
- ...values,
69
- parser_id: selectedTag,
70
- },
71
- });
72
- if (retcode === 0) {
73
- navigate(
74
- `/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeBaseId}`,
75
- );
76
- }
77
- }
78
- } catch (error) {
79
- console.warn(error);
80
- }
81
- };
82
-
83
- useEffect(() => {
84
- getTenantInfo();
85
- }, [getTenantInfo]);
86
-
87
- const handleChange = (tag: string, checked: boolean) => {
88
- const nextSelectedTag = checked ? tag : selectedTag;
89
- console.log('You are interested in: ', nextSelectedTag);
90
- setSelectedTag(nextSelectedTag);
91
- };
92
-
93
- return (
94
- <Form
95
- {...layout}
96
- form={form}
97
- name="validateOnly"
98
- style={{ maxWidth: 1000, padding: 14 }}
99
- >
100
- <Form.Item name="name" label="知识库名称" rules={[{ required: true }]}>
101
- <Input />
102
- </Form.Item>
103
- <Form.Item name="description" label="知识库描述">
104
- <Input.TextArea />
105
- </Form.Item>
106
- <Form.Item name="permission" label="可见权限">
107
- <Radio.Group>
108
- <Radio value="me">只有我</Radio>
109
- <Radio value="team">所有团队成员</Radio>
110
- </Radio.Group>
111
- </Form.Item>
112
- <Form.Item
113
- name="embd_id"
114
- label="Embedding 模型"
115
- hasFeedback
116
- rules={[{ required: true, message: 'Please select your country!' }]}
117
- >
118
- <Select placeholder="Please select a country">
119
- {embd_id.split(',').map((item: string) => {
120
- return (
121
- <Option value={item} key={item}>
122
- {item}
123
- </Option>
124
- );
125
- })}
126
- </Select>
127
- </Form.Item>
128
- <div style={{ marginTop: '5px' }}>
129
- 修改Embedding 模型,请去<span style={{ color: '#1677ff' }}>设置</span>
130
- </div>
131
- <Space size={[0, 8]} wrap>
132
- <div className={styles.tags}>
133
- {parser_ids.split(',').map((tag: string) => {
134
- return (
135
- <CheckableTag
136
- key={tag}
137
- checked={selectedTag === tag}
138
- onChange={(checked) => handleChange(tag, checked)}
139
- >
140
- {tag}
141
- </CheckableTag>
142
- );
143
- })}
144
- </div>
145
- </Space>
146
- <Space size={[0, 8]} wrap></Space>
147
- <div className={styles.preset}>
148
- <div className={styles.left}>xxxxx文章</div>
149
- <div className={styles.right}>预估份数</div>
150
- </div>
151
- <Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 8 }}>
152
- <Button type="primary" onClick={onFinish}>
153
- 保存并处理
154
- </Button>
155
- <Button htmlType="button" style={{ marginLeft: '20px' }}>
156
- 取消
157
- </Button>
158
- </Form.Item>
159
- </Form>
160
- );
161
- };
162
-
163
- // export default KnowledgeSetting;
164
-
165
  export default Configuration;
 
 
 
 
 
 
1
  import Configuration from './configuration';
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  export default Configuration;
web/src/pages/chat/chat-configuration-modal/hooks.ts ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ useFetchTenantInfo,
3
+ useSelectTenantInfo,
4
+ } from '@/hooks/userSettingHook';
5
+ import { useEffect } from 'react';
6
+
7
+ export const useFetchModelId = (visible: boolean) => {
8
+ const fetchTenantInfo = useFetchTenantInfo(false);
9
+ const tenantInfo = useSelectTenantInfo();
10
+
11
+ useEffect(() => {
12
+ if (visible) {
13
+ fetchTenantInfo();
14
+ }
15
+ }, [visible, fetchTenantInfo]);
16
+
17
+ return tenantInfo?.llm_id ?? '';
18
+ };
web/src/pages/chat/chat-configuration-modal/index.tsx CHANGED
@@ -13,6 +13,7 @@ import { variableEnabledFieldMap } from '../constants';
13
  import { useFetchDialog, useResetCurrentDialog, useSetDialog } from '../hooks';
14
  import { IPromptConfigParameters } from '../interface';
15
  import { excludeUnEnabledVariables } from '../utils';
 
16
  import styles from './index.less';
17
 
18
  enum ConfigurationSegmented {
@@ -54,6 +55,7 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
54
  );
55
  const promptEngineRef = useRef<Array<IPromptConfigParameters>>([]);
56
  const loading = useOneNamespaceEffectsLoading('chatModel', ['setDialog']);
 
57
 
58
  const setDialog = useSetDialog();
59
  const currentDialog = useFetchDialog(id, visible);
@@ -128,9 +130,13 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
128
  if (icon) {
129
  fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }];
130
  }
131
- form.setFieldsValue({ ...currentDialog, icon: fileList });
 
 
 
 
132
  }
133
- }, [currentDialog, form, visible]);
134
 
135
  return (
136
  <Modal
 
13
  import { useFetchDialog, useResetCurrentDialog, useSetDialog } from '../hooks';
14
  import { IPromptConfigParameters } from '../interface';
15
  import { excludeUnEnabledVariables } from '../utils';
16
+ import { useFetchModelId } from './hooks';
17
  import styles from './index.less';
18
 
19
  enum ConfigurationSegmented {
 
55
  );
56
  const promptEngineRef = useRef<Array<IPromptConfigParameters>>([]);
57
  const loading = useOneNamespaceEffectsLoading('chatModel', ['setDialog']);
58
+ const modelId = useFetchModelId(visible);
59
 
60
  const setDialog = useSetDialog();
61
  const currentDialog = useFetchDialog(id, visible);
 
130
  if (icon) {
131
  fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }];
132
  }
133
+ form.setFieldsValue({
134
+ ...currentDialog,
135
+ icon: fileList,
136
+ llm_id: currentDialog.llm_id ?? modelId,
137
+ });
138
  }
139
+ }, [currentDialog, form, visible, modelId]);
140
 
141
  return (
142
  <Modal
web/src/pages/chat/hooks.ts CHANGED
@@ -10,7 +10,7 @@ import omit from 'lodash/omit';
10
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
11
  import { useDispatch, useSearchParams, useSelector } from 'umi';
12
  import { v4 as uuid } from 'uuid';
13
- import { ChatSearchParams, EmptyConversationId } from './constants';
14
  import {
15
  IClientConversation,
16
  IMessage,
@@ -233,75 +233,6 @@ export const useHandleItemHover = () => {
233
 
234
  //#region conversation
235
 
236
- export const useCreateTemporaryConversation = () => {
237
- const dispatch = useDispatch();
238
- const { dialogId } = useGetChatSearchParams();
239
- const { handleClickConversation } = useClickConversationCard();
240
- let chatModel = useSelector((state: any) => state.chatModel);
241
-
242
- const currentConversation: Pick<
243
- IClientConversation,
244
- 'id' | 'message' | 'name' | 'dialog_id'
245
- > = chatModel.currentConversation;
246
-
247
- const conversationList: IClientConversation[] = chatModel.conversationList;
248
- const currentDialog: IDialog = chatModel.currentDialog;
249
-
250
- const setCurrentConversation = useSetCurrentConversation();
251
-
252
- const createTemporaryConversation = useCallback(() => {
253
- const firstConversation = conversationList[0];
254
- const messages = [...(firstConversation?.message ?? [])];
255
- if (messages.some((x) => x.id === EmptyConversationId)) {
256
- return;
257
- }
258
- messages.push({
259
- id: EmptyConversationId,
260
- content: currentDialog?.prompt_config?.prologue ?? '',
261
- role: MessageType.Assistant,
262
- });
263
-
264
- let nextCurrentConversation = currentConversation;
265
-
266
- // It’s the back-end data.
267
- if ('id' in currentConversation) {
268
- nextCurrentConversation = { ...currentConversation, message: messages };
269
- } else {
270
- // client data
271
- nextCurrentConversation = {
272
- id: EmptyConversationId,
273
- name: 'New conversation',
274
- dialog_id: dialogId,
275
- message: messages,
276
- };
277
- }
278
-
279
- const nextConversationList = [...conversationList];
280
-
281
- nextConversationList.unshift(
282
- nextCurrentConversation as IClientConversation,
283
- );
284
-
285
- setCurrentConversation(nextCurrentConversation as IClientConversation);
286
-
287
- dispatch({
288
- type: 'chatModel/setConversationList',
289
- payload: nextConversationList,
290
- });
291
- handleClickConversation(EmptyConversationId);
292
- }, [
293
- dispatch,
294
- currentConversation,
295
- dialogId,
296
- setCurrentConversation,
297
- handleClickConversation,
298
- conversationList,
299
- currentDialog,
300
- ]);
301
-
302
- return { createTemporaryConversation };
303
- };
304
-
305
  export const useFetchConversationList = () => {
306
  const dispatch = useDispatch();
307
  const conversationList: any[] = useSelector(
@@ -412,7 +343,7 @@ export const useSelectCurrentConversation = () => {
412
  (state: any) => state.chatModel.currentConversation,
413
  );
414
  const dialog = useSelectCurrentDialog();
415
- const { conversationId } = useGetChatSearchParams();
416
 
417
  const addNewestConversation = useCallback((message: string) => {
418
  setCurrentConversation((pre) => {
@@ -448,12 +379,12 @@ export const useSelectCurrentConversation = () => {
448
 
449
  setCurrentConversation({
450
  id: '',
451
- dialog_id: dialog.id,
452
  reference: [],
453
  message: [nextMessage],
454
  } as any);
455
  }
456
- }, [conversationId, dialog]);
457
 
458
  useEffect(() => {
459
  addPrologue();
 
10
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
11
  import { useDispatch, useSearchParams, useSelector } from 'umi';
12
  import { v4 as uuid } from 'uuid';
13
+ import { ChatSearchParams } from './constants';
14
  import {
15
  IClientConversation,
16
  IMessage,
 
233
 
234
  //#region conversation
235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  export const useFetchConversationList = () => {
237
  const dispatch = useDispatch();
238
  const conversationList: any[] = useSelector(
 
343
  (state: any) => state.chatModel.currentConversation,
344
  );
345
  const dialog = useSelectCurrentDialog();
346
+ const { conversationId, dialogId } = useGetChatSearchParams();
347
 
348
  const addNewestConversation = useCallback((message: string) => {
349
  setCurrentConversation((pre) => {
 
379
 
380
  setCurrentConversation({
381
  id: '',
382
+ dialog_id: dialogId,
383
  reference: [],
384
  message: [nextMessage],
385
  } as any);
386
  }
387
+ }, [conversationId, dialog, dialogId]);
388
 
389
  useEffect(() => {
390
  addPrologue();
web/src/pages/knowledge/model.ts CHANGED
@@ -1,14 +1,17 @@
 
1
  import kbService from '@/services/kbService';
2
  import { DvaModel } from 'umi';
3
 
4
  export interface KnowledgeModelState {
5
  data: any[];
 
6
  }
7
 
8
  const model: DvaModel<KnowledgeModelState> = {
9
  namespace: 'knowledgeModel',
10
  state: {
11
  data: [],
 
12
  },
13
  reducers: {
14
  updateState(state, { payload }) {
@@ -17,6 +20,12 @@ const model: DvaModel<KnowledgeModelState> = {
17
  ...payload,
18
  };
19
  },
 
 
 
 
 
 
20
  },
21
  effects: {
22
  *rmKb({ payload = {} }, { call, put }) {
@@ -42,6 +51,13 @@ const model: DvaModel<KnowledgeModelState> = {
42
  });
43
  }
44
  },
 
 
 
 
 
 
 
45
  },
46
  };
47
  export default model;
 
1
+ import { IKnowledge } from '@/interfaces/database/knowledge';
2
  import kbService from '@/services/kbService';
3
  import { DvaModel } from 'umi';
4
 
5
  export interface KnowledgeModelState {
6
  data: any[];
7
+ knowledge: IKnowledge;
8
  }
9
 
10
  const model: DvaModel<KnowledgeModelState> = {
11
  namespace: 'knowledgeModel',
12
  state: {
13
  data: [],
14
+ knowledge: {} as IKnowledge,
15
  },
16
  reducers: {
17
  updateState(state, { payload }) {
 
20
  ...payload,
21
  };
22
  },
23
+ setKnowledge(state, { payload }) {
24
+ return {
25
+ ...state,
26
+ knowledge: payload,
27
+ };
28
+ },
29
  },
30
  effects: {
31
  *rmKb({ payload = {} }, { call, put }) {
 
51
  });
52
  }
53
  },
54
+ *getKnowledgeDetail({ payload = {} }, { call, put }) {
55
+ const { data } = yield call(kbService.get_kb_detail, payload);
56
+ if (data.retcode === 0) {
57
+ yield put({ type: 'setKnowledge', payload: data.data });
58
+ }
59
+ return data.retcode;
60
+ },
61
  },
62
  };
63
  export default model;
web/src/utils/documentUtils.ts CHANGED
@@ -1,4 +1,5 @@
1
  import { IChunk } from '@/interfaces/database/knowledge';
 
2
  import { v4 as uuid } from 'uuid';
3
 
4
  export const buildChunkHighlights = (selectedChunk: IChunk) => {
@@ -32,3 +33,5 @@ export const buildChunkHighlights = (selectedChunk: IChunk) => {
32
  })
33
  : [];
34
  };
 
 
 
1
  import { IChunk } from '@/interfaces/database/knowledge';
2
+ import { UploadFile } from 'antd';
3
  import { v4 as uuid } from 'uuid';
4
 
5
  export const buildChunkHighlights = (selectedChunk: IChunk) => {
 
33
  })
34
  : [];
35
  };
36
+
37
+ export const isFileUploadDone = (file: UploadFile) => file.status === 'done';