balibabu commited on
Commit
f3d0ebd
·
1 Parent(s): 53be70c

feat: remove KnowledgeSearching and add knowledge configuration page and add a run button to the document (#64)

Browse files

* feat: add a run button to the document

* feat: add knowledge configuration page

* feat: remove KnowledgeSearching

web/src/assets/svg/refresh.svg ADDED
web/src/assets/svg/run.svg ADDED
web/src/constants/knowledge.ts CHANGED
@@ -2,13 +2,12 @@ export enum KnowledgeRouteKey {
2
  Dataset = 'dataset',
3
  Testing = 'testing',
4
  Configuration = 'configuration',
5
- TempTesting = 'tempTesting',
6
  }
7
 
8
  export enum RunningStatus {
9
- UNSTART = '0',
10
- RUNNING = '1',
11
- CANCEL = '2',
12
- DONE = '3',
13
- FAIL = '4',
14
  }
 
2
  Dataset = 'dataset',
3
  Testing = 'testing',
4
  Configuration = 'configuration',
 
5
  }
6
 
7
  export enum RunningStatus {
8
+ UNSTART = '0', // need to run
9
+ RUNNING = '1', // need to cancel
10
+ CANCEL = '2', // need to refresh
11
+ DONE = '3', // need to refresh
12
+ FAIL = '4', // need to refresh
13
  }
web/src/hooks/knowledgeHook.ts CHANGED
@@ -1,6 +1,6 @@
1
  import showDeleteConfirm from '@/components/deleting-confirm';
2
- import { IKnowledge } from '@/interfaces/database/knowledge';
3
- import { useCallback } from 'react';
4
  import { useDispatch, useSearchParams, useSelector } from 'umi';
5
 
6
  export const useKnowledgeBaseId = (): string => {
@@ -77,3 +77,50 @@ export const useDeleteChunkByIds = (): {
77
  removeChunk: onRemoveChunk,
78
  };
79
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import showDeleteConfirm from '@/components/deleting-confirm';
2
+ import { IKnowledge, ITenantInfo } from '@/interfaces/database/knowledge';
3
+ import { useCallback, useEffect, useMemo } from 'react';
4
  import { useDispatch, useSearchParams, useSelector } from 'umi';
5
 
6
  export const useKnowledgeBaseId = (): string => {
 
77
  removeChunk: onRemoveChunk,
78
  };
79
  };
80
+
81
+ export const useSelectParserList = (): Array<{
82
+ value: string;
83
+ label: string;
84
+ }> => {
85
+ const tenantIfo: Nullable<ITenantInfo> = useSelector(
86
+ (state: any) => state.settingModel.tenantIfo,
87
+ );
88
+
89
+ const parserList = useMemo(() => {
90
+ const parserArray: Array<string> = tenantIfo?.parser_ids.split(',') ?? [];
91
+ return parserArray.map((x) => {
92
+ const arr = x.split(':');
93
+ return { value: arr[0], label: arr[1] };
94
+ });
95
+ }, [tenantIfo]);
96
+
97
+ return parserList;
98
+ };
99
+
100
+ export const useFetchParserList = () => {
101
+ const dispatch = useDispatch();
102
+
103
+ useEffect(() => {
104
+ dispatch({
105
+ type: 'settingModel/getTenantInfo',
106
+ });
107
+ }, [dispatch]);
108
+ };
109
+
110
+ export const useFetchKnowledgeBaseConfiguration = () => {
111
+ const dispatch = useDispatch();
112
+ const knowledgeBaseId = useKnowledgeBaseId();
113
+
114
+ const fetchKnowledgeBaseConfiguration = useCallback(() => {
115
+ dispatch({
116
+ type: 'kSModel/getKbDetail',
117
+ payload: {
118
+ kb_id: knowledgeBaseId,
119
+ },
120
+ });
121
+ }, [dispatch, knowledgeBaseId]);
122
+
123
+ useEffect(() => {
124
+ fetchKnowledgeBaseConfiguration();
125
+ }, [fetchKnowledgeBaseConfiguration]);
126
+ };
web/src/interfaces/database/llm.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export interface IThirdOAIModel {
2
+ available: boolean;
3
+ create_date: string;
4
+ create_time: number;
5
+ fid: string;
6
+ id: number;
7
+ llm_name: string;
8
+ max_tokens: number;
9
+ model_type: string;
10
+ status: string;
11
+ tags: string;
12
+ update_date: string;
13
+ update_time: number;
14
+ }
15
+
16
+ export type IThirdOAIModelCollection = Record<string, IThirdOAIModel[]>;
web/src/pages/add-knowledge/components/knowledge-chunk/index.less CHANGED
@@ -26,6 +26,7 @@
26
  .chunkContainer {
27
  height: calc(100vh - 320px);
28
  overflow: auto;
 
29
  }
30
 
31
  .pageFooter {
 
26
  .chunkContainer {
27
  height: calc(100vh - 320px);
28
  overflow: auto;
29
+ width: 100%;
30
  }
31
 
32
  .pageFooter {
web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.tsx CHANGED
@@ -2,10 +2,11 @@ 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
  useGetDocumentDefaultParser,
6
  useKnowledgeBaseId,
 
7
  } from '@/hooks/knowledgeHook';
8
- import { ITenantInfo } from '@/interfaces/database/knowledge';
9
  import uploadService from '@/services/uploadService';
10
  import {
11
  ArrowLeftOutlined,
@@ -28,9 +29,8 @@ import {
28
  UploadProps,
29
  } from 'antd';
30
  import classNames from 'classnames';
31
- import { ReactElement, useEffect, useMemo, useRef, useState } from 'react';
32
- import { Nullable } from 'typings';
33
- import { Link, useDispatch, useNavigate, useSelector } from 'umi';
34
 
35
  import { KnowledgeRouteKey } from '@/constants/knowledge';
36
  import styles from './index.less';
@@ -45,13 +45,11 @@ const UploaderItem = ({
45
  file,
46
  actions,
47
  isUpload,
48
- parserArray,
49
  }: {
50
  isUpload: boolean;
51
  originNode: ReactElement;
52
  file: UploadFile;
53
  fileList: object[];
54
- parserArray: string[];
55
  actions: { download: Function; preview: Function; remove: any };
56
  }) => {
57
  const { parserConfig, defaultParserId } = useGetDocumentDefaultParser(
@@ -63,12 +61,7 @@ const UploaderItem = ({
63
 
64
  const documentId = file?.response?.id;
65
 
66
- const parserList = useMemo(() => {
67
- return parserArray.map((x) => {
68
- const arr = x.split(':');
69
- return { value: arr[0], label: arr[1] };
70
- });
71
- }, [parserArray]);
72
 
73
  const saveParser = (parserId: string) => {
74
  dispatch({
@@ -154,14 +147,10 @@ const KnowledgeUploadFile = () => {
154
  const knowledgeBaseId = useKnowledgeBaseId();
155
  const [isUpload, setIsUpload] = useState(true);
156
  const dispatch = useDispatch();
157
- const tenantIfo: Nullable<ITenantInfo> = useSelector(
158
- (state: any) => state.settingModel.tenantIfo,
159
- );
160
  const navigate = useNavigate();
161
  const fileListRef = useRef<UploadFile[]>([]);
162
 
163
- const parserArray = tenantIfo?.parser_ids.split(',') ?? [];
164
-
165
  const createRequest: (props: UploadRequestOption) => void = async function ({
166
  file,
167
  onSuccess,
@@ -170,9 +159,13 @@ const KnowledgeUploadFile = () => {
170
  }) {
171
  const { data } = await uploadService.uploadFile(file, knowledgeBaseId);
172
  if (data.retcode === 0) {
173
- onSuccess && onSuccess(data.data);
 
 
174
  } else {
175
- onError && onError(data.data);
 
 
176
  }
177
  };
178
 
@@ -188,7 +181,6 @@ const KnowledgeUploadFile = () => {
188
  fileList={fileList}
189
  originNode={originNode}
190
  actions={actions}
191
- parserArray={parserArray}
192
  ></UploaderItem>
193
  );
194
  },
@@ -215,11 +207,7 @@ const KnowledgeUploadFile = () => {
215
  }
216
  };
217
 
218
- useEffect(() => {
219
- dispatch({
220
- type: 'settingModel/getTenantInfo',
221
- });
222
- }, []);
223
 
224
  return (
225
  <div className={styles.uploadWrapper}>
 
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
  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';
 
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(
 
61
 
62
  const documentId = file?.response?.id;
63
 
64
+ const parserList = useSelectParserList();
 
 
 
 
 
65
 
66
  const saveParser = (parserId: string) => {
67
  dispatch({
 
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,
 
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
 
 
181
  fileList={fileList}
182
  originNode={originNode}
183
  actions={actions}
 
184
  ></UploaderItem>
185
  );
186
  },
 
207
  }
208
  };
209
 
210
+ useFetchParserList();
 
 
 
 
211
 
212
  return (
213
  <div className={styles.uploadWrapper}>
web/src/pages/add-knowledge/components/knowledge-file/index.tsx CHANGED
@@ -1,8 +1,5 @@
1
  import { KnowledgeRouteKey } from '@/constants/knowledge';
2
- import {
3
- useDeleteDocumentById,
4
- useKnowledgeBaseId,
5
- } from '@/hooks/knowledgeHook';
6
  import { Pagination } from '@/interfaces/common';
7
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
8
  import { getOneNamespaceEffectsLoading } from '@/utils/storeUtil';
@@ -40,7 +37,6 @@ const KnowledgeFile = () => {
40
  const effects = useSelector((state: any) => state.loading.effects);
41
  const { data, total } = kFModel;
42
  const knowledgeBaseId = useKnowledgeBaseId();
43
- const { removeDocument } = useDeleteDocumentById();
44
 
45
  const loading = getOneNamespaceEffectsLoading('kFModel', effects, [
46
  'getKfList',
@@ -132,9 +128,7 @@ const KnowledgeFile = () => {
132
  },
133
  });
134
  };
135
- const onRmDocument = () => {
136
- removeDocument(doc_id);
137
- };
138
  const showCEFModal = () => {
139
  dispatch({
140
  type: 'kFModel/updateState',
@@ -144,15 +138,6 @@ const KnowledgeFile = () => {
144
  });
145
  };
146
 
147
- const showSegmentSetModal = () => {
148
- dispatch({
149
- type: 'kFModel/updateState',
150
- payload: {
151
- isShowSegmentSetModal: true,
152
- },
153
- });
154
- };
155
-
156
  const actionItems: MenuProps['items'] = useMemo(() => {
157
  return [
158
  {
@@ -185,31 +170,6 @@ const KnowledgeFile = () => {
185
  },
186
  ];
187
  }, []);
188
- const chunkItems: MenuProps['items'] = [
189
- {
190
- key: '1',
191
- label: (
192
- <div>
193
- <Button type="link" onClick={showSegmentSetModal}>
194
- {' '}
195
- 分段设置
196
- </Button>
197
- </div>
198
- ),
199
- },
200
- {
201
- key: '2',
202
- label: (
203
- <div>
204
- <Button type="link" onClick={onRmDocument}>
205
- {' '}
206
- Delete
207
- </Button>
208
- </div>
209
- ),
210
- // disabled: true,
211
- },
212
- ];
213
 
214
  const toChunk = (id: string) => {
215
  navigate(
 
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';
 
37
  const effects = useSelector((state: any) => state.loading.effects);
38
  const { data, total } = kFModel;
39
  const knowledgeBaseId = useKnowledgeBaseId();
 
40
 
41
  const loading = getOneNamespaceEffectsLoading('kFModel', effects, [
42
  'getKfList',
 
128
  },
129
  });
130
  };
131
+
 
 
132
  const showCEFModal = () => {
133
  dispatch({
134
  type: 'kFModel/updateState',
 
138
  });
139
  };
140
 
 
 
 
 
 
 
 
 
 
141
  const actionItems: MenuProps['items'] = useMemo(() => {
142
  return [
143
  {
 
170
  },
171
  ];
172
  }, []);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
  const toChunk = (id: string) => {
175
  navigate(
web/src/pages/add-knowledge/components/knowledge-file/model.ts CHANGED
@@ -55,33 +55,23 @@ const model: DvaModel<KFModelState> = {
55
  return { ...state, pagination: { ...state.pagination, ...payload } };
56
  },
57
  },
58
- subscriptions: {
59
- setup({ dispatch, history }) {
60
- history.listen((location) => {});
61
- },
62
- },
63
  effects: {
64
- *createKf({ payload = {} }, { call, put }) {
65
- const { data, response } = yield call(kbService.createKb, payload);
66
- const { retcode, data: res, retmsg } = data;
67
  if (retcode === 0) {
68
  message.success('创建成功!');
69
  }
70
  },
71
- *updateKf({ payload = {} }, { call, put }) {
72
- const { data, response } = yield call(kbService.updateKb, payload);
73
- const { retcode, data: res, retmsg } = data;
74
  if (retcode === 0) {
75
  message.success('修改成功!');
76
  }
77
  },
78
- *getKfDetail({ payload = {}, callback }, { call, put }) {
79
- const { data, response } = yield call(kbService.get_kb_detail, payload);
80
- const { retcode, data: res, retmsg } = data;
81
- if (retcode === 0) {
82
- // localStorage.setItem('userInfo',res.)
83
- callback && callback(res);
84
- }
85
  },
86
  *getKfList({ payload = {} }, { call, put, select }) {
87
  const state: KFModelState = yield select((state: any) => state.kFModel);
@@ -119,11 +109,11 @@ const model: DvaModel<KFModelState> = {
119
  { type: 'poll', delay: 5000 }, // TODO: Provide type support for this effect
120
  ],
121
  *updateDocumentStatus({ payload = {} }, { call, put }) {
122
- const { data, response } = yield call(
123
  kbService.document_change_status,
124
  pick(payload, ['doc_id', 'status']),
125
  );
126
- const { retcode, data: res, retmsg } = data;
127
  if (retcode === 0) {
128
  message.success('修改成功!');
129
  put({
@@ -133,10 +123,10 @@ const model: DvaModel<KFModelState> = {
133
  }
134
  },
135
  *document_rm({ payload = {} }, { call, put }) {
136
- const { data, response } = yield call(kbService.document_rm, {
137
  doc_id: payload.doc_id,
138
  });
139
- const { retcode, data: res, retmsg } = data;
140
  if (retcode === 0) {
141
  message.success('删除成功!');
142
  yield put({
@@ -151,7 +141,7 @@ const model: DvaModel<KFModelState> = {
151
  kbService.document_rename,
152
  omit(payload, ['kb_id']),
153
  );
154
- const { retcode, data: res, retmsg } = data;
155
  if (retcode === 0) {
156
  message.success('rename success!');
157
  yield put({
@@ -168,7 +158,7 @@ const model: DvaModel<KFModelState> = {
168
  },
169
  *document_create({ payload = {} }, { call, put }) {
170
  const { data } = yield call(kbService.document_create, payload);
171
- const { retcode, data: res } = data;
172
  if (retcode === 0) {
173
  put({
174
  type: 'kFModel/updateState',
@@ -181,19 +171,25 @@ const model: DvaModel<KFModelState> = {
181
  return retcode;
182
  },
183
  *document_run({ payload = {} }, { call, put }) {
184
- const { data } = yield call(kbService.document_run, payload);
 
 
 
185
  const { retcode } = data;
186
  if (retcode === 0) {
187
- message.success('Run successfully !');
 
 
 
 
 
 
188
  }
189
  return retcode;
190
  },
191
  *document_change_parser({ payload = {} }, { call, put }) {
192
- const { data, response } = yield call(
193
- kbService.document_change_parser,
194
- payload,
195
- );
196
- const { retcode, data: res, retmsg } = data;
197
  if (retcode === 0) {
198
  put({
199
  type: 'updateState',
 
55
  return { ...state, pagination: { ...state.pagination, ...payload } };
56
  },
57
  },
 
 
 
 
 
58
  effects: {
59
+ *createKf({ payload = {} }, { call }) {
60
+ const { data } = yield call(kbService.createKb, payload);
61
+ const { retcode } = data;
62
  if (retcode === 0) {
63
  message.success('创建成功!');
64
  }
65
  },
66
+ *updateKf({ payload = {} }, { call }) {
67
+ const { data } = yield call(kbService.updateKb, payload);
68
+ const { retcode } = data;
69
  if (retcode === 0) {
70
  message.success('修改成功!');
71
  }
72
  },
73
+ *getKfDetail({ payload = {} }, { call }) {
74
+ const { data } = yield call(kbService.get_kb_detail, payload);
 
 
 
 
 
75
  },
76
  *getKfList({ payload = {} }, { call, put, select }) {
77
  const state: KFModelState = yield select((state: any) => state.kFModel);
 
109
  { type: 'poll', delay: 5000 }, // TODO: Provide type support for this effect
110
  ],
111
  *updateDocumentStatus({ payload = {} }, { call, put }) {
112
+ const { data } = yield call(
113
  kbService.document_change_status,
114
  pick(payload, ['doc_id', 'status']),
115
  );
116
+ const { retcode } = data;
117
  if (retcode === 0) {
118
  message.success('修改成功!');
119
  put({
 
123
  }
124
  },
125
  *document_rm({ payload = {} }, { call, put }) {
126
+ const { data } = yield call(kbService.document_rm, {
127
  doc_id: payload.doc_id,
128
  });
129
+ const { retcode } = data;
130
  if (retcode === 0) {
131
  message.success('删除成功!');
132
  yield put({
 
141
  kbService.document_rename,
142
  omit(payload, ['kb_id']),
143
  );
144
+ const { retcode } = data;
145
  if (retcode === 0) {
146
  message.success('rename success!');
147
  yield put({
 
158
  },
159
  *document_create({ payload = {} }, { call, put }) {
160
  const { data } = yield call(kbService.document_create, payload);
161
+ const { retcode } = data;
162
  if (retcode === 0) {
163
  put({
164
  type: 'kFModel/updateState',
 
171
  return retcode;
172
  },
173
  *document_run({ payload = {} }, { call, put }) {
174
+ const { data } = yield call(
175
+ kbService.document_run,
176
+ omit(payload, ['knowledgeBaseId']),
177
+ );
178
  const { retcode } = data;
179
  if (retcode === 0) {
180
+ if (payload.knowledgeBaseId) {
181
+ yield put({
182
+ type: 'getKfList',
183
+ payload: { kb_id: payload.knowledgeBaseId },
184
+ });
185
+ }
186
+ message.success('Operation successfully !');
187
  }
188
  return retcode;
189
  },
190
  *document_change_parser({ payload = {} }, { call, put }) {
191
+ const { data } = yield call(kbService.document_change_parser, payload);
192
+ const { retcode } = data;
 
 
 
193
  if (retcode === 0) {
194
  put({
195
  type: 'updateState',
web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.less CHANGED
@@ -1,3 +1,12 @@
1
  .popover-content {
2
  width: 300px;
3
  }
 
 
 
 
 
 
 
 
 
 
1
  .popover-content {
2
  width: 300px;
3
  }
4
+
5
+ .operationIcon {
6
+ text-align: center;
7
+ margin-right: 20%;
8
+ width: 20px;
9
+ &:hover {
10
+ cursor: pointer;
11
+ }
12
+ }
web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx CHANGED
@@ -1,9 +1,21 @@
 
 
1
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
2
  import { Badge, DescriptionsProps, Flex, Popover, Space, Tag } from 'antd';
3
  import { RunningStatus, RunningStatusMap } from '../constant';
4
 
 
 
5
  import styles from './index.less';
6
 
 
 
 
 
 
 
 
 
7
  interface IProps {
8
  record: IKnowledgeFile;
9
  }
@@ -31,7 +43,7 @@ const PopoverContent = ({ record }: IProps) => {
31
  <Flex vertical className={styles['popover-content']}>
32
  {items.map((x) => {
33
  return (
34
- <div>
35
  <b>{x.label}:</b>
36
  <p>{x.children}</p>
37
  </div>
@@ -42,27 +54,46 @@ const PopoverContent = ({ record }: IProps) => {
42
  };
43
 
44
  export const ParsingStatusCell = ({ record }: IProps) => {
 
45
  const text = record.run;
46
  const runningStatus = RunningStatusMap[text];
47
 
48
  const isRunning = text === RunningStatus.RUNNING;
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  return (
51
- <Popover
52
- content={isRunning && <PopoverContent record={record}></PopoverContent>}
53
- >
54
- <Tag color={runningStatus.color}>
55
- {isRunning ? (
56
- <Space>
57
- <Badge color={runningStatus.color} />
58
- {runningStatus.label}
59
- <span>{record.progress * 100}%</span>
60
- </Space>
61
- ) : (
62
- runningStatus.label
63
- )}
64
- </Tag>
65
- </Popover>
 
 
 
 
 
66
  );
67
  };
68
 
 
1
+ import { ReactComponent as RefreshIcon } from '@/assets/svg/refresh.svg';
2
+ import { ReactComponent as RunIcon } from '@/assets/svg/run.svg';
3
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
4
  import { Badge, DescriptionsProps, Flex, Popover, Space, Tag } from 'antd';
5
  import { RunningStatus, RunningStatusMap } from '../constant';
6
 
7
+ import { CloseCircleOutlined } from '@ant-design/icons';
8
+ import { useDispatch } from 'umi';
9
  import styles from './index.less';
10
 
11
+ const iconMap = {
12
+ [RunningStatus.UNSTART]: RunIcon,
13
+ [RunningStatus.RUNNING]: CloseCircleOutlined,
14
+ [RunningStatus.CANCEL]: RefreshIcon,
15
+ [RunningStatus.DONE]: RefreshIcon,
16
+ [RunningStatus.FAIL]: RefreshIcon,
17
+ };
18
+
19
  interface IProps {
20
  record: IKnowledgeFile;
21
  }
 
43
  <Flex vertical className={styles['popover-content']}>
44
  {items.map((x) => {
45
  return (
46
+ <div key={x.key}>
47
  <b>{x.label}:</b>
48
  <p>{x.children}</p>
49
  </div>
 
54
  };
55
 
56
  export const ParsingStatusCell = ({ record }: IProps) => {
57
+ const dispatch = useDispatch();
58
  const text = record.run;
59
  const runningStatus = RunningStatusMap[text];
60
 
61
  const isRunning = text === RunningStatus.RUNNING;
62
 
63
+ const OperationIcon = iconMap[text];
64
+
65
+ const handleOperationIconClick = () => {
66
+ dispatch({
67
+ type: 'kFModel/document_run',
68
+ payload: {
69
+ doc_ids: [record.id],
70
+ run: isRunning ? 2 : 1,
71
+ knowledgeBaseId: record.kb_id,
72
+ },
73
+ });
74
+ };
75
+
76
  return (
77
+ <Flex justify={'space-between'}>
78
+ <Popover
79
+ content={isRunning && <PopoverContent record={record}></PopoverContent>}
80
+ >
81
+ <Tag color={runningStatus.color}>
82
+ {isRunning ? (
83
+ <Space>
84
+ <Badge color={runningStatus.color} />
85
+ {runningStatus.label}
86
+ <span>{(record.progress * 100).toFixed(2)}%</span>
87
+ </Space>
88
+ ) : (
89
+ runningStatus.label
90
+ )}
91
+ </Tag>
92
+ </Popover>
93
+ <div onClick={handleOperationIconClick} className={styles.operationIcon}>
94
+ <OperationIcon />
95
+ </div>
96
+ </Flex>
97
  );
98
  };
99
 
web/src/pages/add-knowledge/components/knowledge-search/index.less DELETED
@@ -1,79 +0,0 @@
1
- .chunkPage {
2
- padding: 24px;
3
- display: flex;
4
- height: calc(100vh - 112px);
5
- // flex-direction: column;
6
-
7
- .filter {
8
- margin-right: 20px;
9
- display: flex;
10
- height: 32px;
11
- width: 300px;
12
- flex-wrap: wrap;
13
- justify-content: space-between;
14
- }
15
-
16
- .pageContainer {
17
- flex: 1;
18
- display: flex;
19
- flex-direction: column;
20
-
21
- .pageContent {
22
- flex: 1;
23
- width: 100%;
24
- padding-right: 12px;
25
- overflow-y: auto;
26
-
27
- .spin {
28
- min-height: 400px;
29
- }
30
- }
31
-
32
- .pageFooter {
33
- height: 32px;
34
- float: right;
35
- }
36
- }
37
-
38
- }
39
-
40
- .container {
41
- height: 100px;
42
- display: flex;
43
- flex-direction: column;
44
- justify-content: space-between;
45
-
46
- .content {
47
- display: flex;
48
- justify-content: space-between;
49
-
50
- .context {
51
- flex: 1;
52
- // width: 207px;
53
- height: 88px;
54
- overflow: hidden;
55
- }
56
- }
57
-
58
- .footer {
59
- height: 20px;
60
-
61
- .text {
62
- margin-left: 10px;
63
- }
64
- }
65
- }
66
-
67
- .card {
68
- :global {
69
- .ant-card-body {
70
- padding: 10px;
71
- margin: 0;
72
- }
73
-
74
- margin-bottom: 10px;
75
- }
76
-
77
- cursor: pointer;
78
-
79
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
web/src/pages/add-knowledge/components/knowledge-search/index.tsx DELETED
@@ -1,276 +0,0 @@
1
- import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
2
- import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
3
- import { api_host } from '@/utils/api';
4
- import { DeleteOutlined, MinusSquareOutlined } from '@ant-design/icons';
5
- import type { PaginationProps } from 'antd';
6
- import {
7
- Card,
8
- Col,
9
- Input,
10
- Pagination,
11
- Popconfirm,
12
- Row,
13
- Select,
14
- Spin,
15
- Switch,
16
- } from 'antd';
17
- import { debounce } from 'lodash';
18
- import React, { useCallback, useEffect } from 'react';
19
- import { useDispatch, useSelector } from 'umi';
20
- import CreateModal from '../knowledge-chunk/components/chunk-creating-modal';
21
-
22
- import styles from './index.less';
23
-
24
- const KnowledgeSearching = () => {
25
- const dispatch = useDispatch();
26
- const kSearchModel = useSelector((state: any) => state.kSearchModel);
27
- const chunkModel = useSelector((state: any) => state.chunkModel);
28
- const loading = useOneNamespaceEffectsLoading('kSearchModel', [
29
- 'chunk_list',
30
- 'switch_chunk',
31
- ]);
32
- const knowledgeBaseId = useKnowledgeBaseId();
33
-
34
- const {
35
- data = [],
36
- total,
37
- d_list = [],
38
- question,
39
- doc_ids,
40
- pagination,
41
- } = kSearchModel;
42
- const { chunk_id, doc_id, isShowCreateModal } = chunkModel;
43
-
44
- const getChunkList = () => {
45
- dispatch({
46
- type: 'kSearchModel/chunk_list',
47
- payload: {
48
- kb_id: knowledgeBaseId,
49
- },
50
- });
51
- };
52
- const confirm = (id: string) => {
53
- dispatch({
54
- type: 'kSearchModel/rm_chunk',
55
- payload: {
56
- chunk_ids: [id],
57
- kb_id: knowledgeBaseId,
58
- },
59
- });
60
- };
61
- const handleEditchunk = (item: any) => {
62
- const { chunk_id, doc_id } = item;
63
- dispatch({
64
- type: 'chunkModel/updateState',
65
- payload: {
66
- isShowCreateModal: true,
67
- chunk_id,
68
- doc_id,
69
- },
70
- });
71
- getChunkList();
72
- };
73
- const onShowSizeChange: PaginationProps['onShowSizeChange'] = (
74
- page,
75
- size,
76
- ) => {
77
- dispatch({
78
- type: 'kSearchModel/updateState',
79
- payload: {
80
- pagination: { page, size },
81
- },
82
- });
83
- };
84
- useEffect(() => {
85
- dispatch({
86
- type: 'kSearchModel/updateState',
87
- payload: {
88
- doc_ids: [],
89
- question: '',
90
- },
91
- });
92
- dispatch({
93
- type: 'kSearchModel/getKfList',
94
- payload: {
95
- kb_id: knowledgeBaseId,
96
- },
97
- });
98
- }, []);
99
- const switchChunk = (item: any, available_int: boolean) => {
100
- const { chunk_id, doc_id } = item;
101
-
102
- dispatch({
103
- type: 'kSearchModel/switch_chunk',
104
- payload: {
105
- chunk_ids: [chunk_id],
106
- doc_id,
107
- available_int,
108
- kb_id: knowledgeBaseId,
109
- },
110
- });
111
- };
112
-
113
- useEffect(() => {
114
- getChunkList();
115
- }, [doc_ids, pagination, question]);
116
- const debounceChange = debounce((value) => {
117
- dispatch({
118
- type: 'kSearchModel/updateState',
119
- payload: {
120
- question: value,
121
- },
122
- });
123
- }, 300);
124
-
125
- const debounceCallback = useCallback(
126
- (value: string) => debounceChange(value),
127
- [],
128
- );
129
- const handleInputChange = (
130
- e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
131
- ) => {
132
- const value = e.target.value;
133
- debounceCallback(value);
134
- };
135
- const handleSelectChange = (value: any[]) => {
136
- dispatch({
137
- type: 'kSearchModel/updateState',
138
- payload: {
139
- doc_ids: value,
140
- },
141
- });
142
- };
143
-
144
- return (
145
- <>
146
- <div className={styles.chunkPage}>
147
- <div className={styles.filter}>
148
- <Select
149
- showSearch
150
- placeholder="文件列表"
151
- optionFilterProp="children"
152
- onChange={handleSelectChange}
153
- style={{ width: 300, marginBottom: 20 }}
154
- options={d_list}
155
- fieldNames={{ label: 'name', value: 'id' }}
156
- mode="multiple"
157
- />
158
-
159
- <Input.TextArea
160
- autoSize={{ minRows: 6, maxRows: 6 }}
161
- placeholder="搜索"
162
- style={{ width: 300 }}
163
- allowClear
164
- onChange={handleInputChange}
165
- />
166
- </div>
167
- <div className={styles.pageContainer}>
168
- <div className={styles.pageContent}>
169
- <Spin spinning={loading} className={styles.spin} size="large">
170
- <Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24 }}>
171
- {data.map((item: any) => {
172
- return (
173
- <Col
174
- className="gutter-row"
175
- key={item.chunk_id}
176
- xs={24}
177
- sm={12}
178
- md={12}
179
- lg={8}
180
- >
181
- <Card
182
- className={styles.card}
183
- onClick={() => {
184
- handleEditchunk(item);
185
- }}
186
- >
187
- <img
188
- style={{ width: '50px' }}
189
- src={`${api_host}/document/image/${item.img_id}`}
190
- alt=""
191
- />
192
- <div className={styles.container}>
193
- <div className={styles.content}>
194
- <span className={styles.context}>
195
- {item.content_ltks}
196
- </span>
197
- <span className={styles.delete}>
198
- <Switch
199
- size="small"
200
- defaultValue={item.doc_ids == '1'}
201
- onChange={(checked: boolean, e: any) => {
202
- e.stopPropagation();
203
- e.nativeEvent.stopImmediatePropagation();
204
- switchChunk(item, checked);
205
- }}
206
- />
207
- </span>
208
- </div>
209
- <div className={styles.footer}>
210
- <span className={styles.text}>
211
- <MinusSquareOutlined />
212
- {item.doc_num}文档
213
- </span>
214
- <span className={styles.text}>
215
- <MinusSquareOutlined />
216
- {item.chunk_num}个
217
- </span>
218
- <span className={styles.text}>
219
- <MinusSquareOutlined />
220
- {item.token_num}千字符
221
- </span>
222
- <span style={{ float: 'right' }}>
223
- <Popconfirm
224
- title="Delete the task"
225
- description="Are you sure to delete this task?"
226
- onConfirm={(e: any) => {
227
- e.stopPropagation();
228
- e.nativeEvent.stopImmediatePropagation();
229
- console.log(confirm);
230
- confirm(item.chunk_id);
231
- }}
232
- okText="Yes"
233
- cancelText="No"
234
- >
235
- <DeleteOutlined
236
- onClick={(e) => {
237
- e.stopPropagation();
238
- e.nativeEvent.stopImmediatePropagation();
239
- }}
240
- />
241
- </Popconfirm>
242
- </span>
243
- </div>
244
- </div>
245
- </Card>
246
- </Col>
247
- );
248
- })}
249
- </Row>
250
- </Spin>
251
- </div>
252
- <div className={styles.pageFooter}>
253
- <Pagination
254
- responsive
255
- showLessItems
256
- showQuickJumper
257
- showSizeChanger
258
- onChange={onShowSizeChange}
259
- defaultPageSize={30}
260
- pageSizeOptions={[30, 60, 90]}
261
- defaultCurrent={pagination.page}
262
- total={total}
263
- />
264
- </div>
265
- </div>
266
- </div>
267
- <CreateModal
268
- isShowCreateModal={isShowCreateModal}
269
- chunk_id={chunk_id}
270
- doc_id={doc_id}
271
- />
272
- </>
273
- );
274
- };
275
-
276
- export default KnowledgeSearching;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
web/src/pages/add-knowledge/components/knowledge-search/model.ts DELETED
@@ -1,160 +0,0 @@
1
- import kbService from '@/services/kbService';
2
- import omit from 'lodash/omit';
3
- import { DvaModel } from 'umi';
4
-
5
- export interface KSearchModelState {
6
- loading: boolean;
7
- data: any[];
8
- total: number;
9
- isShowCreateModal: boolean;
10
- chunk_id: string;
11
- chunkInfo: any;
12
- d_list: any[];
13
- question: string;
14
- doc_ids: any[];
15
- pagination: any;
16
- doc_id: string;
17
- }
18
-
19
- const model: DvaModel<KSearchModelState> = {
20
- namespace: 'kSearchModel',
21
- state: {
22
- loading: false,
23
- data: [],
24
- total: 0,
25
- isShowCreateModal: false,
26
- chunk_id: '',
27
- chunkInfo: {},
28
- d_list: [],
29
- question: '',
30
- doc_ids: [],
31
- pagination: { page: 1, size: 30 },
32
- doc_id: '',
33
- },
34
- reducers: {
35
- updateState(state, { payload }) {
36
- return {
37
- ...state,
38
- ...payload,
39
- };
40
- },
41
- },
42
- subscriptions: {
43
- setup({ dispatch, history }) {
44
- history.listen((location) => {
45
- console.log(location);
46
- });
47
- },
48
- },
49
- effects: {
50
- *getKfList({ payload = {} }, { call, put }) {
51
- const { data, response } = yield call(
52
- kbService.get_document_list,
53
- payload,
54
- );
55
-
56
- const { retcode, data: res, retmsg } = data;
57
- if (retcode === 0) {
58
- yield put({
59
- type: 'updateState',
60
- payload: {
61
- d_list: res,
62
- },
63
- });
64
- }
65
- },
66
- *chunk_list({ payload = {} }, { call, put, select }) {
67
- const { question, doc_ids, pagination }: KSearchModelState = yield select(
68
- (state: any) => state.kSearchModel,
69
- );
70
- const { data } = yield call(kbService.retrieval_test, {
71
- ...payload,
72
- ...pagination,
73
- question,
74
- doc_ids,
75
- similarity_threshold: 0.1,
76
- });
77
- const { retcode, data: res, retmsg } = data;
78
- if (retcode === 0) {
79
- yield put({
80
- type: 'updateState',
81
- payload: {
82
- data: res.chunks,
83
- total: res.total,
84
- },
85
- });
86
- }
87
- },
88
- *switch_chunk({ payload = {} }, { call, put }) {
89
- const { data } = yield call(
90
- kbService.switch_chunk,
91
- omit(payload, ['kb_id']),
92
- );
93
- const { retcode } = data;
94
- if (retcode === 0) {
95
- yield put({
96
- type: 'chunk_list',
97
- payload: {
98
- kb_id: payload.kb_id,
99
- },
100
- });
101
- }
102
- },
103
- *rm_chunk({ payload = {} }, { call, put }) {
104
- const { data } = yield call(kbService.rm_chunk, {
105
- chunk_ids: payload.chunk_ids,
106
- });
107
- const { retcode, data: res, retmsg } = data;
108
- if (retcode === 0) {
109
- // TODO: Can be extracted
110
- yield put({
111
- type: 'chunk_list',
112
- payload: {
113
- kb_id: payload.kb_id,
114
- },
115
- });
116
- }
117
- },
118
- *get_chunk({ payload = {} }, { call, put }) {
119
- const { data, response } = yield call(kbService.get_chunk, payload);
120
- const { retcode, data: res, retmsg } = data;
121
- if (retcode === 0) {
122
- yield put({
123
- type: 'updateState',
124
- payload: {
125
- chunkInfo: res,
126
- },
127
- });
128
- }
129
- },
130
- *create_hunk({ payload = {} }, { call, put }) {
131
- yield put({
132
- type: 'updateState',
133
- payload: {
134
- loading: true,
135
- },
136
- });
137
- let service = kbService.create_chunk;
138
- if (payload.chunk_id) {
139
- service = kbService.set_chunk;
140
- }
141
- const { data } = yield call(service, payload);
142
- const { retcode } = data;
143
- yield put({
144
- type: 'updateState',
145
- payload: {
146
- loading: false,
147
- },
148
- });
149
- if (retcode === 0) {
150
- yield put({
151
- type: 'updateState',
152
- payload: {
153
- isShowCreateModal: false,
154
- },
155
- });
156
- }
157
- },
158
- },
159
- };
160
- export default model;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ useFetchKnowledgeBaseConfiguration,
3
+ useFetchParserList,
4
+ useKnowledgeBaseId,
5
+ useSelectParserList,
6
+ } from '@/hooks/knowledgeHook';
7
+ import {
8
+ Button,
9
+ Divider,
10
+ Form,
11
+ Input,
12
+ Radio,
13
+ Select,
14
+ Space,
15
+ Typography,
16
+ Upload,
17
+ UploadFile,
18
+ } from 'antd';
19
+ import pick from 'lodash/pick';
20
+ import { useCallback, useEffect, useMemo } from 'react';
21
+ import { useDispatch, useSelector } from 'umi';
22
+
23
+ import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
24
+ import { IKnowledge } from '@/interfaces/database/knowledge';
25
+ import { IThirdOAIModelCollection } from '@/interfaces/database/llm';
26
+ import { PlusOutlined } from '@ant-design/icons';
27
+ import styles from './index.less';
28
+
29
+ const { Title } = Typography;
30
+ const { Option } = Select;
31
+
32
+ const Configuration = () => {
33
+ const [form] = Form.useForm();
34
+ const dispatch = useDispatch();
35
+ const knowledgeBaseId = useKnowledgeBaseId();
36
+ const loading = useOneNamespaceEffectsLoading('kSModel', ['updateKb']);
37
+
38
+ const llmInfo: IThirdOAIModelCollection = useSelector(
39
+ (state: any) => state.settingModel.llmInfo,
40
+ );
41
+ const knowledgeDetails: IKnowledge = useSelector(
42
+ (state: any) => state.kSModel.knowledgeDetails,
43
+ );
44
+
45
+ const normFile = (e: any) => {
46
+ if (Array.isArray(e)) {
47
+ return e;
48
+ }
49
+ return e?.fileList;
50
+ };
51
+
52
+ const parserList = useSelectParserList();
53
+
54
+ const embeddingModelOptions = useMemo(() => {
55
+ return Object.entries(llmInfo).map(([key, value]) => {
56
+ return {
57
+ label: key,
58
+ options: value.map((x) => ({
59
+ label: x.llm_name,
60
+ value: x.llm_name,
61
+ })),
62
+ };
63
+ });
64
+ }, [llmInfo]);
65
+
66
+ const onFinish = async (values: any) => {
67
+ console.info(values);
68
+ const fileList = values.avatar;
69
+ let avatar;
70
+
71
+ if (Array.isArray(fileList)) {
72
+ avatar = fileList[0].thumbUrl;
73
+ }
74
+
75
+ dispatch({
76
+ type: 'kSModel/updateKb',
77
+ payload: {
78
+ ...values,
79
+ avatar,
80
+ kb_id: knowledgeBaseId,
81
+ },
82
+ });
83
+ };
84
+
85
+ const onFinishFailed = (errorInfo: any) => {
86
+ console.log('Failed:', errorInfo);
87
+ };
88
+
89
+ const fetchLlmList = useCallback(() => {
90
+ dispatch({
91
+ type: 'settingModel/llm_list',
92
+ payload: { model_type: 'embedding' },
93
+ });
94
+ }, [dispatch]);
95
+
96
+ useEffect(() => {
97
+ const avatar = knowledgeDetails.avatar;
98
+ let fileList: UploadFile[] = [];
99
+
100
+ if (avatar) {
101
+ fileList = [{ uid: '1', name: 'file', thumbUrl: avatar, status: 'done' }];
102
+ }
103
+ form.setFieldsValue({
104
+ ...pick(knowledgeDetails, [
105
+ 'description',
106
+ 'name',
107
+ 'permission',
108
+ 'embd_id',
109
+ 'parser_id',
110
+ ]),
111
+ avatar: fileList,
112
+ });
113
+ }, [form, knowledgeDetails]);
114
+
115
+ useFetchParserList();
116
+ useFetchKnowledgeBaseConfiguration();
117
+
118
+ useEffect(() => {
119
+ fetchLlmList();
120
+ }, [fetchLlmList]);
121
+
122
+ return (
123
+ <div className={styles.configurationWrapper}>
124
+ <Title level={5}>Configuration</Title>
125
+ <p>Update your knowledge base details especially parsing method here.</p>
126
+ <Divider></Divider>
127
+ <Form
128
+ form={form}
129
+ name="validateOnly"
130
+ layout="vertical"
131
+ autoComplete="off"
132
+ onFinish={onFinish}
133
+ onFinishFailed={onFinishFailed}
134
+ >
135
+ <Form.Item
136
+ name="name"
137
+ label="Knowledge base name"
138
+ rules={[{ required: true }]}
139
+ >
140
+ <Input />
141
+ </Form.Item>
142
+ <Form.Item
143
+ name="avatar"
144
+ label="Knowledge base photo"
145
+ valuePropName="fileList"
146
+ getValueFromEvent={normFile}
147
+ >
148
+ <Upload
149
+ listType="picture-card"
150
+ maxCount={1}
151
+ showUploadList={{ showPreviewIcon: false, showRemoveIcon: false }}
152
+ >
153
+ <button style={{ border: 0, background: 'none' }} type="button">
154
+ <PlusOutlined />
155
+ <div style={{ marginTop: 8 }}>Upload</div>
156
+ </button>
157
+ </Upload>
158
+ </Form.Item>
159
+ <Form.Item name="description" label="Knowledge base bio">
160
+ <Input />
161
+ </Form.Item>
162
+ <Form.Item
163
+ name="permission"
164
+ label="Permissions"
165
+ rules={[{ required: true }]}
166
+ >
167
+ <Radio.Group>
168
+ <Radio value="me">Only me</Radio>
169
+ <Radio value="team">Team</Radio>
170
+ </Radio.Group>
171
+ </Form.Item>
172
+ <Form.Item
173
+ name="embd_id"
174
+ label="Embedding Model"
175
+ rules={[{ required: true }]}
176
+ >
177
+ <Select
178
+ placeholder="Please select a country"
179
+ options={embeddingModelOptions}
180
+ ></Select>
181
+ </Form.Item>
182
+ <Form.Item
183
+ name="parser_id"
184
+ label="Knowledge base category"
185
+ rules={[{ required: true }]}
186
+ >
187
+ <Select placeholder="Please select a country">
188
+ {parserList.map((x) => (
189
+ <Option value={x.value} key={x.value}>
190
+ {x.label}
191
+ </Option>
192
+ ))}
193
+ </Select>
194
+ </Form.Item>
195
+ <Form.Item>
196
+ <div className={styles.buttonWrapper}>
197
+ <Space>
198
+ <Button htmlType="reset" size={'middle'}>
199
+ Cancel
200
+ </Button>
201
+ <Button
202
+ htmlType="submit"
203
+ type="primary"
204
+ size={'middle'}
205
+ loading={loading}
206
+ >
207
+ Save
208
+ </Button>
209
+ </Space>
210
+ </div>
211
+ </Form.Item>
212
+ </Form>
213
+ </div>
214
+ );
215
+ };
216
+
217
+ export default Configuration;
web/src/pages/add-knowledge/components/knowledge-setting/index.less CHANGED
@@ -1,24 +1,30 @@
1
  .tags {
2
- margin-bottom: 24px;
3
  }
4
 
5
  .preset {
6
- display: flex;
7
- height: 80px;
8
- background-color: rgba(0, 0, 0, 0.1);
9
- border-radius: 5px;
10
- padding: 5px;
11
- margin-bottom: 24px;
12
 
13
- .left {
14
- flex: 1;
 
15
 
16
- }
 
 
 
 
 
 
17
 
18
- .right {
19
- width: 100px;
20
- border-left: 1px solid rgba(0, 0, 0, 0.4);
21
- margin: 10px 0px;
22
- padding: 5px;
23
- }
24
- }
 
1
  .tags {
2
+ margin-bottom: 24px;
3
  }
4
 
5
  .preset {
6
+ display: flex;
7
+ height: 80px;
8
+ background-color: rgba(0, 0, 0, 0.1);
9
+ border-radius: 5px;
10
+ padding: 5px;
11
+ margin-bottom: 24px;
12
 
13
+ .left {
14
+ flex: 1;
15
+ }
16
 
17
+ .right {
18
+ width: 100px;
19
+ border-left: 1px solid rgba(0, 0, 0, 0.4);
20
+ margin: 10px 0px;
21
+ padding: 5px;
22
+ }
23
+ }
24
 
25
+ .configurationWrapper {
26
+ padding: 0 52px;
27
+ .buttonWrapper {
28
+ text-align: right;
29
+ }
30
+ }
 
web/src/pages/add-knowledge/components/knowledge-setting/index.tsx CHANGED
@@ -3,6 +3,8 @@ 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 styles from './index.less';
7
 
8
  const { CheckableTag } = Tag;
@@ -12,7 +14,6 @@ const layout = {
12
  labelAlign: 'left' as const,
13
  };
14
  const { Option } = Select;
15
- /* eslint-disable no-template-curly-in-string */
16
 
17
  const KnowledgeSetting = () => {
18
  const dispatch = useDispatch();
@@ -44,7 +45,7 @@ const KnowledgeSetting = () => {
44
  setSelectedTag(data.data.parser_id);
45
  }
46
  }
47
- }, [knowledgeBaseId]);
48
 
49
  const onFinish = async () => {
50
  try {
@@ -68,10 +69,11 @@ const KnowledgeSetting = () => {
68
  parser_id: selectedTag,
69
  },
70
  });
71
- retcode === 0 &&
72
  navigate(
73
  `/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeBaseId}`,
74
  );
 
75
  }
76
  } catch (error) {
77
  console.warn(error);
@@ -158,4 +160,6 @@ const KnowledgeSetting = () => {
158
  );
159
  };
160
 
161
- export default KnowledgeSetting;
 
 
 
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;
 
14
  labelAlign: 'left' as const,
15
  };
16
  const { Option } = Select;
 
17
 
18
  const KnowledgeSetting = () => {
19
  const dispatch = useDispatch();
 
45
  setSelectedTag(data.data.parser_id);
46
  }
47
  }
48
+ }, [knowledgeBaseId, dispatch, form]);
49
 
50
  const onFinish = async () => {
51
  try {
 
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);
 
160
  );
161
  };
162
 
163
+ // export default KnowledgeSetting;
164
+
165
+ export default Configuration;
web/src/pages/add-knowledge/components/knowledge-setting/model.ts CHANGED
@@ -1,3 +1,4 @@
 
1
  import kbService from '@/services/kbService';
2
  import { message } from 'antd';
3
  import { DvaModel } from 'umi';
@@ -6,6 +7,7 @@ export interface KSModelState {
6
  isShowPSwModal: boolean;
7
  isShowTntModal: boolean;
8
  tenantIfo: any;
 
9
  }
10
 
11
  const model: DvaModel<KSModelState> = {
@@ -14,6 +16,7 @@ const model: DvaModel<KSModelState> = {
14
  isShowPSwModal: false,
15
  isShowTntModal: false,
16
  tenantIfo: {},
 
17
  },
18
  reducers: {
19
  updateState(state, { payload }) {
@@ -22,31 +25,32 @@ const model: DvaModel<KSModelState> = {
22
  ...payload,
23
  };
24
  },
25
- },
26
- subscriptions: {
27
- setup({ dispatch, history }) {
28
- history.listen((location) => {});
29
  },
30
  },
31
  effects: {
32
- *createKb({ payload = {} }, { call, put }) {
33
  const { data } = yield call(kbService.createKb, payload);
34
  const { retcode } = data;
35
  if (retcode === 0) {
36
- message.success('创建知识库成功!');
37
  }
38
  return data;
39
  },
40
  *updateKb({ payload = {} }, { call, put }) {
41
  const { data } = yield call(kbService.updateKb, payload);
42
- const { retcode, data: res, retmsg } = data;
43
  if (retcode === 0) {
44
- message.success('更新知识库成功!');
 
45
  }
46
  },
47
  *getKbDetail({ payload = {} }, { call, put }) {
48
  const { data } = yield call(kbService.get_kb_detail, payload);
49
-
 
 
50
  return data;
51
  },
52
  },
 
1
+ import { IKnowledge } from '@/interfaces/database/knowledge';
2
  import kbService from '@/services/kbService';
3
  import { message } from 'antd';
4
  import { DvaModel } from 'umi';
 
7
  isShowPSwModal: boolean;
8
  isShowTntModal: boolean;
9
  tenantIfo: any;
10
+ knowledgeDetails: IKnowledge;
11
  }
12
 
13
  const model: DvaModel<KSModelState> = {
 
16
  isShowPSwModal: false,
17
  isShowTntModal: false,
18
  tenantIfo: {},
19
+ knowledgeDetails: {} as any,
20
  },
21
  reducers: {
22
  updateState(state, { payload }) {
 
25
  ...payload,
26
  };
27
  },
28
+ setKnowledgeDetails(state, { payload }) {
29
+ return { ...state, knowledgeDetails: payload };
 
 
30
  },
31
  },
32
  effects: {
33
+ *createKb({ payload = {} }, { call }) {
34
  const { data } = yield call(kbService.createKb, payload);
35
  const { retcode } = data;
36
  if (retcode === 0) {
37
+ message.success('Created successfully!');
38
  }
39
  return data;
40
  },
41
  *updateKb({ payload = {} }, { call, put }) {
42
  const { data } = yield call(kbService.updateKb, payload);
43
+ const { retcode } = data;
44
  if (retcode === 0) {
45
+ yield put({ type: 'getKbDetail', payload: { kb_id: payload.kb_id } });
46
+ message.success('Updated successfully!');
47
  }
48
  },
49
  *getKbDetail({ payload = {} }, { call, put }) {
50
  const { data } = yield call(kbService.get_kb_detail, payload);
51
+ if (data.retcode === 0) {
52
+ yield put({ type: 'setKnowledgeDetails', payload: data.data });
53
+ }
54
  return data;
55
  },
56
  },
web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx CHANGED
@@ -1,9 +1,10 @@
1
- import { ReactComponent as ConfigrationIcon } from '@/assets/svg/knowledge-configration.svg';
2
  import { ReactComponent as DatasetIcon } from '@/assets/svg/knowledge-dataset.svg';
3
  import { ReactComponent as TestingIcon } from '@/assets/svg/knowledge-testing.svg';
 
4
  import { useSecondPathName } from '@/hooks/routeHook';
 
5
  import { getWidth } from '@/utils';
6
- import { AntDesignOutlined } from '@ant-design/icons';
7
  import { Avatar, Menu, MenuProps, Space } from 'antd';
8
  import classNames from 'classnames';
9
  import { useCallback, useEffect, useMemo, useState } from 'react';
@@ -16,6 +17,9 @@ const KnowledgeSidebar = () => {
16
  const { id } = kAModel;
17
  let navigate = useNavigate();
18
  const activeKey = useSecondPathName();
 
 
 
19
 
20
  const [windowWidth, setWindowWidth] = useState(getWidth());
21
  const [collapsed, setCollapsed] = useState(false);
@@ -62,12 +66,7 @@ const KnowledgeSidebar = () => {
62
  getItem(
63
  routeMap[KnowledgeRouteKey.Configuration],
64
  KnowledgeRouteKey.Configuration,
65
- <ConfigrationIcon />,
66
- ),
67
- getItem(
68
- routeMap[KnowledgeRouteKey.TempTesting],
69
- KnowledgeRouteKey.TempTesting,
70
- <TestingIcon />,
71
  ),
72
  ];
73
  }, [getItem]);
@@ -93,16 +92,17 @@ const KnowledgeSidebar = () => {
93
  };
94
  }, []);
95
 
 
 
96
  return (
97
  <div className={styles.sidebarWrapper}>
98
  <div className={styles.sidebarTop}>
99
  <Space size={8} direction="vertical">
100
- <Avatar size={64} icon={<AntDesignOutlined />} />
101
- <div className={styles.knowledgeTitle}>Cloud Computing</div>
102
  </Space>
103
  <p className={styles.knowledgeDescription}>
104
- A scalable, secure cloud-based database optimized for high-performance
105
- computing and data storage.
106
  </p>
107
  </div>
108
  <div className={styles.divider}></div>
 
1
+ import { ReactComponent as ConfigurationIcon } from '@/assets/svg/knowledge-configration.svg';
2
  import { ReactComponent as DatasetIcon } from '@/assets/svg/knowledge-dataset.svg';
3
  import { ReactComponent as TestingIcon } from '@/assets/svg/knowledge-testing.svg';
4
+ import { useFetchKnowledgeBaseConfiguration } from '@/hooks/knowledgeHook';
5
  import { useSecondPathName } from '@/hooks/routeHook';
6
+ import { IKnowledge } from '@/interfaces/database/knowledge';
7
  import { getWidth } from '@/utils';
 
8
  import { Avatar, Menu, MenuProps, Space } from 'antd';
9
  import classNames from 'classnames';
10
  import { useCallback, useEffect, useMemo, useState } from 'react';
 
17
  const { id } = kAModel;
18
  let navigate = useNavigate();
19
  const activeKey = useSecondPathName();
20
+ const knowledgeDetails: IKnowledge = useSelector(
21
+ (state: any) => state.kSModel.knowledgeDetails,
22
+ );
23
 
24
  const [windowWidth, setWindowWidth] = useState(getWidth());
25
  const [collapsed, setCollapsed] = useState(false);
 
66
  getItem(
67
  routeMap[KnowledgeRouteKey.Configuration],
68
  KnowledgeRouteKey.Configuration,
69
+ <ConfigurationIcon />,
 
 
 
 
 
70
  ),
71
  ];
72
  }, [getItem]);
 
92
  };
93
  }, []);
94
 
95
+ useFetchKnowledgeBaseConfiguration();
96
+
97
  return (
98
  <div className={styles.sidebarWrapper}>
99
  <div className={styles.sidebarTop}>
100
  <Space size={8} direction="vertical">
101
+ <Avatar size={64} src={knowledgeDetails.avatar} />
102
+ <div className={styles.knowledgeTitle}>{knowledgeDetails.name}</div>
103
  </Space>
104
  <p className={styles.knowledgeDescription}>
105
+ {knowledgeDetails.description}
 
106
  </p>
107
  </div>
108
  <div className={styles.divider}></div>
web/src/pages/setting/model.ts CHANGED
@@ -1,4 +1,5 @@
1
  import { ITenantInfo } from '@/interfaces/database/knowledge';
 
2
  import userService from '@/services/userService';
3
  import authorizationUtil from '@/utils/authorizationUtil';
4
  import { message } from 'antd';
@@ -12,7 +13,7 @@ export interface SettingModelState {
12
  isShowSSModal: boolean;
13
  llm_factory: string;
14
  tenantIfo: Nullable<ITenantInfo>;
15
- llmInfo: any;
16
  myLlm: any[];
17
  factoriesList: any[];
18
  }
@@ -126,8 +127,8 @@ const model: DvaModel<SettingModelState> = {
126
  }
127
  },
128
  *llm_list({ payload = {} }, { call, put }) {
129
- const { data, response } = yield call(userService.llm_list, payload);
130
- const { retcode, data: res, retmsg } = data;
131
  if (retcode === 0) {
132
  yield put({
133
  type: 'updateState',
 
1
  import { ITenantInfo } from '@/interfaces/database/knowledge';
2
+ import { IThirdOAIModelCollection as IThirdAiModelCollection } from '@/interfaces/database/llm';
3
  import userService from '@/services/userService';
4
  import authorizationUtil from '@/utils/authorizationUtil';
5
  import { message } from 'antd';
 
13
  isShowSSModal: boolean;
14
  llm_factory: string;
15
  tenantIfo: Nullable<ITenantInfo>;
16
+ llmInfo: IThirdAiModelCollection;
17
  myLlm: any[];
18
  factoriesList: any[];
19
  }
 
127
  }
128
  },
129
  *llm_list({ payload = {} }, { call, put }) {
130
+ const { data } = yield call(userService.llm_list, payload);
131
+ const { retcode, data: res } = data;
132
  if (retcode === 0) {
133
  yield put({
134
  type: 'updateState',
web/src/routes.ts CHANGED
@@ -44,10 +44,6 @@ const routes = [
44
  },
45
  {
46
  path: '/knowledge/testing',
47
- component: '@/pages/add-knowledge/components/knowledge-search',
48
- },
49
- {
50
- path: '/knowledge/tempTesting',
51
  component: '@/pages/add-knowledge/components/knowledge-testing',
52
  },
53
  ],
 
44
  },
45
  {
46
  path: '/knowledge/testing',
 
 
 
 
47
  component: '@/pages/add-knowledge/components/knowledge-testing',
48
  },
49
  ],
web/src/utils/fileUtil.ts ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export const transformFile2Base64 = (val: any): Promise<any> => {
2
+ return new Promise((resolve, reject) => {
3
+ const reader = new FileReader();
4
+ reader.readAsDataURL(val);
5
+ reader.onload = (): void => {
6
+ resolve(reader.result);
7
+ };
8
+ reader.onerror = reject;
9
+ });
10
+ };
11
+
12
+ export const transformBase64ToFile = (
13
+ dataUrl: string,
14
+ filename: string = 'file',
15
+ ) => {
16
+ let arr = dataUrl.split(','),
17
+ bstr = atob(arr[1]),
18
+ n = bstr.length,
19
+ u8arr = new Uint8Array(n);
20
+
21
+ const mime = arr[0].match(/:(.*?);/);
22
+ const mimeType = mime ? mime[1] : 'image/png';
23
+
24
+ while (n--) {
25
+ u8arr[n] = bstr.charCodeAt(n);
26
+ }
27
+ return new File([u8arr], filename, { type: mimeType });
28
+ };