balibabu
commited on
Commit
·
362ec6c
1
Parent(s):
96a1a44
feat: remove loading from model and use DvaModel instead of redundant types such as kAModelType (#47)
Browse files* feat: use DvaModel instead of redundant types such as kAModelType
* feat: set the type for registerServer
* feat: remove loading from model
- web/src/hooks/storeHooks.ts +11 -0
- web/src/pages/add-knowledge/components/knowledge-chunk/components/createModal.tsx +107 -93
- web/src/pages/add-knowledge/components/knowledge-chunk/components/editTag.tsx +124 -125
- web/src/pages/add-knowledge/components/knowledge-chunk/index.tsx +238 -181
- web/src/pages/add-knowledge/components/knowledge-chunk/model.ts +21 -54
- web/src/pages/add-knowledge/components/knowledge-file/createEFileModal.tsx +65 -71
- web/src/pages/add-knowledge/components/knowledge-file/index.tsx +254 -209
- web/src/pages/add-knowledge/components/knowledge-file/model.ts +46 -67
- web/src/pages/add-knowledge/components/knowledge-file/segmentSetModal.tsx +79 -83
- web/src/pages/add-knowledge/components/knowledge-file/upload.tsx +31 -25
- web/src/pages/add-knowledge/components/knowledge-search/index.tsx +210 -179
- web/src/pages/add-knowledge/components/knowledge-search/model.ts +76 -74
- web/src/pages/add-knowledge/components/knowledge-setting/index.tsx +140 -153
- web/src/pages/add-knowledge/components/knowledge-setting/model.ts +29 -47
- web/src/pages/add-knowledge/index.tsx +108 -111
- web/src/pages/add-knowledge/model.ts +14 -30
- web/src/pages/chat/index.tsx +5 -12
- web/src/pages/chat/model.ts +25 -39
- web/src/pages/file/index.tsx +45 -46
- web/src/pages/knowledge/index.tsx +15 -26
- web/src/pages/knowledge/model.ts +21 -49
- web/src/pages/login/index.tsx +30 -19
- web/src/pages/login/model.ts +16 -30
- web/src/pages/setting/model.ts +12 -30
- web/src/services/kbService.ts +78 -96
- web/src/services/userService.ts +55 -49
- web/src/utils/registerServer.ts +12 -5
- web/src/utils/request.ts +7 -7
- web/src/utils/stroreUtil.ts +9 -0
web/src/hooks/storeHooks.ts
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil';
|
2 |
+
import { useSelector } from 'umi';
|
3 |
+
|
4 |
+
// Get the loading status of given effects under a certain namespace
|
5 |
+
export const useOneNamespaceEffectsLoading = (
|
6 |
+
namespace: string,
|
7 |
+
effectNames: Array<string>,
|
8 |
+
) => {
|
9 |
+
const effects = useSelector((state: any) => state.loading.effects);
|
10 |
+
return getOneNamespaceEffectsLoading(namespace, effects, effectNames);
|
11 |
+
};
|
web/src/pages/add-knowledge/components/knowledge-chunk/components/createModal.tsx
CHANGED
@@ -1,102 +1,116 @@
|
|
1 |
-
import
|
2 |
-
import {
|
3 |
-
import
|
4 |
-
import {
|
5 |
-
import
|
6 |
-
import styles from './index.less';
|
7 |
-
import type { chunkModelState } from './model'
|
8 |
-
import EditTag from './editTag'
|
9 |
|
10 |
type FieldType = {
|
11 |
-
|
12 |
};
|
13 |
interface kFProps {
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
doc_id: string;
|
19 |
-
chunk_id: string
|
20 |
}
|
21 |
-
const Index: React.FC<kFProps> = ({ dispatch, getChunkList, doc_id, isShowCreateModal, chunk_id }) => {
|
22 |
-
// const { , chunkInfo } = chunkModel
|
23 |
-
const [important_kwd, setImportantKwd] = useState(['Unremovable', 'Tag 2', 'Tag 3']);
|
24 |
-
const { t } = useTranslation()
|
25 |
-
const handleCancel = () => {
|
26 |
-
dispatch({
|
27 |
-
type: 'chunkModel/updateState',
|
28 |
-
payload: {
|
29 |
-
isShowCreateModal: false
|
30 |
-
}
|
31 |
-
});
|
32 |
-
};
|
33 |
-
useEffect(() => {
|
34 |
-
console.log(chunk_id, isShowCreateModal)
|
35 |
-
if (chunk_id && isShowCreateModal) {
|
36 |
-
dispatch({
|
37 |
-
type: 'chunkModel/get_chunk',
|
38 |
-
payload: {
|
39 |
-
chunk_id
|
40 |
-
},
|
41 |
-
callback(info: any) {
|
42 |
-
console.log(info)
|
43 |
-
const { content_ltks, important_kwd = [] } = info
|
44 |
-
form.setFieldsValue({ content_ltks })
|
45 |
-
setImportantKwd(important_kwd)
|
46 |
-
}
|
47 |
-
});
|
48 |
-
}
|
49 |
-
}, [chunk_id, isShowCreateModal])
|
50 |
-
const [form] = Form.useForm()
|
51 |
-
const handleOk = async () => {
|
52 |
-
try {
|
53 |
-
const values = await form.validateFields();
|
54 |
-
dispatch({
|
55 |
-
type: 'chunkModel/create_hunk',
|
56 |
-
payload: {
|
57 |
-
content_ltks: values.content_ltks,
|
58 |
-
doc_id,
|
59 |
-
chunk_id,
|
60 |
-
important_kwd
|
61 |
-
},
|
62 |
-
callback: () => {
|
63 |
-
dispatch({
|
64 |
-
type: 'chunkModel/updateState',
|
65 |
-
payload: {
|
66 |
-
isShowCreateModal: false
|
67 |
-
}
|
68 |
-
});
|
69 |
-
getChunkList && getChunkList()
|
70 |
-
}
|
71 |
-
});
|
72 |
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
|
|
|
|
|
|
|
|
77 |
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
<Input.TextArea />
|
94 |
-
</Form.Item>
|
95 |
-
<EditTag tags={important_kwd} setTags={setImportantKwd} />
|
96 |
-
</Form>
|
97 |
-
</Modal >
|
98 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
-
|
101 |
-
}
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Form, Input, Modal } from 'antd';
|
2 |
+
import React, { useCallback, useEffect, useState } from 'react';
|
3 |
+
import { useTranslation } from 'react-i18next';
|
4 |
+
import { useDispatch } from 'umi';
|
5 |
+
import EditTag from './editTag';
|
|
|
|
|
|
|
6 |
|
7 |
type FieldType = {
|
8 |
+
content_ltks?: string;
|
9 |
};
|
10 |
interface kFProps {
|
11 |
+
getChunkList: () => void;
|
12 |
+
isShowCreateModal: boolean;
|
13 |
+
doc_id: string;
|
14 |
+
chunk_id: string;
|
|
|
|
|
15 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
+
const Index: React.FC<kFProps> = ({
|
18 |
+
getChunkList,
|
19 |
+
doc_id,
|
20 |
+
isShowCreateModal,
|
21 |
+
chunk_id,
|
22 |
+
}) => {
|
23 |
+
const dispatch = useDispatch();
|
24 |
+
const [form] = Form.useForm();
|
25 |
|
26 |
+
// const { , chunkInfo } = chunkModel
|
27 |
+
const [important_kwd, setImportantKwd] = useState([
|
28 |
+
'Unremovable',
|
29 |
+
'Tag 2',
|
30 |
+
'Tag 3',
|
31 |
+
]);
|
32 |
+
const { t } = useTranslation();
|
33 |
+
const handleCancel = () => {
|
34 |
+
dispatch({
|
35 |
+
type: 'chunkModel/updateState',
|
36 |
+
payload: {
|
37 |
+
isShowCreateModal: false,
|
38 |
+
},
|
39 |
+
});
|
40 |
+
};
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
+
const getChunk = useCallback(async () => {
|
43 |
+
if (chunk_id && isShowCreateModal) {
|
44 |
+
const data = await dispatch<any>({
|
45 |
+
type: 'chunkModel/get_chunk',
|
46 |
+
payload: {
|
47 |
+
chunk_id,
|
48 |
+
},
|
49 |
+
});
|
50 |
|
51 |
+
if (data?.retcode === 0) {
|
52 |
+
const { content_ltks, important_kwd = [] } = data.data;
|
53 |
+
form.setFieldsValue({ content_ltks });
|
54 |
+
setImportantKwd(important_kwd);
|
55 |
+
}
|
56 |
+
}
|
57 |
+
}, [chunk_id, isShowCreateModal]);
|
58 |
+
|
59 |
+
useEffect(() => {
|
60 |
+
getChunk();
|
61 |
+
}, [getChunk]);
|
62 |
+
|
63 |
+
const handleOk = async () => {
|
64 |
+
try {
|
65 |
+
const values = await form.validateFields();
|
66 |
+
dispatch({
|
67 |
+
type: 'chunkModel/create_hunk',
|
68 |
+
payload: {
|
69 |
+
content_ltks: values.content_ltks,
|
70 |
+
doc_id,
|
71 |
+
chunk_id,
|
72 |
+
important_kwd,
|
73 |
+
},
|
74 |
+
// callback: () => {
|
75 |
+
// dispatch({
|
76 |
+
// type: 'chunkModel/updateState',
|
77 |
+
// payload: {
|
78 |
+
// isShowCreateModal: false,
|
79 |
+
// },
|
80 |
+
// });
|
81 |
+
// getChunkList && getChunkList();
|
82 |
+
// },
|
83 |
+
});
|
84 |
+
} catch (errorInfo) {
|
85 |
+
console.log('Failed:', errorInfo);
|
86 |
+
}
|
87 |
+
};
|
88 |
+
|
89 |
+
return (
|
90 |
+
<Modal
|
91 |
+
title="Basic Modal"
|
92 |
+
open={isShowCreateModal}
|
93 |
+
onOk={handleOk}
|
94 |
+
onCancel={handleCancel}
|
95 |
+
>
|
96 |
+
<Form
|
97 |
+
form={form}
|
98 |
+
name="validateOnly"
|
99 |
+
labelCol={{ span: 5 }}
|
100 |
+
wrapperCol={{ span: 19 }}
|
101 |
+
style={{ maxWidth: 600 }}
|
102 |
+
autoComplete="off"
|
103 |
+
>
|
104 |
+
<Form.Item<FieldType>
|
105 |
+
label="chunk 内容"
|
106 |
+
name="content_ltks"
|
107 |
+
rules={[{ required: true, message: 'Please input value!' }]}
|
108 |
+
>
|
109 |
+
<Input.TextArea />
|
110 |
+
</Form.Item>
|
111 |
+
<EditTag tags={important_kwd} setTags={setImportantKwd} />
|
112 |
+
</Form>
|
113 |
+
</Modal>
|
114 |
+
);
|
115 |
+
};
|
116 |
+
export default Index;
|
web/src/pages/add-knowledge/components/knowledge-chunk/components/editTag.tsx
CHANGED
@@ -1,142 +1,141 @@
|
|
1 |
-
import React, { useEffect, useRef, useState } from 'react';
|
2 |
-
import { PlusOutlined } from '@ant-design/icons';
|
3 |
import type { InputRef } from 'antd';
|
4 |
-
import { Input, Space, Tag,
|
5 |
-
|
6 |
-
|
7 |
-
|
|
|
8 |
}
|
9 |
-
const
|
10 |
-
|
11 |
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
}
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
type="text"
|
126 |
-
size="small"
|
127 |
-
style={tagInputStyle}
|
128 |
-
value={inputValue}
|
129 |
-
onChange={handleInputChange}
|
130 |
-
onBlur={handleInputConfirm}
|
131 |
-
onPressEnter={handleInputConfirm}
|
132 |
-
/>
|
133 |
-
) : (
|
134 |
-
<Tag style={tagPlusStyle} onClick={showInput}>
|
135 |
-
添加关键词
|
136 |
-
</Tag>
|
137 |
-
)}
|
138 |
-
</Space>
|
139 |
-
);
|
140 |
};
|
141 |
|
142 |
-
export default
|
|
|
|
|
|
|
1 |
import type { InputRef } from 'antd';
|
2 |
+
import { Input, Space, Tag, Tooltip, theme } from 'antd';
|
3 |
+
import React, { useEffect, useRef, useState } from 'react';
|
4 |
+
interface EditTagsProps {
|
5 |
+
tags: any[];
|
6 |
+
setTags: (tags: any[]) => void;
|
7 |
}
|
8 |
+
const EditTag: React.FC<EditTagsProps> = ({ tags, setTags }) => {
|
9 |
+
const { token } = theme.useToken();
|
10 |
|
11 |
+
const [inputVisible, setInputVisible] = useState(false);
|
12 |
+
const [inputValue, setInputValue] = useState('');
|
13 |
+
const [editInputIndex, setEditInputIndex] = useState(-1);
|
14 |
+
const [editInputValue, setEditInputValue] = useState('');
|
15 |
+
const inputRef = useRef<InputRef>(null);
|
16 |
+
const editInputRef = useRef<InputRef>(null);
|
17 |
|
18 |
+
useEffect(() => {
|
19 |
+
if (inputVisible) {
|
20 |
+
inputRef.current?.focus();
|
21 |
+
}
|
22 |
+
}, [inputVisible]);
|
23 |
|
24 |
+
useEffect(() => {
|
25 |
+
editInputRef.current?.focus();
|
26 |
+
}, [editInputValue]);
|
27 |
|
28 |
+
const handleClose = (removedTag: string) => {
|
29 |
+
const newTags = tags.filter((tag) => tag !== removedTag);
|
30 |
+
console.log(newTags);
|
31 |
+
setTags(newTags);
|
32 |
+
};
|
33 |
|
34 |
+
const showInput = () => {
|
35 |
+
setInputVisible(true);
|
36 |
+
};
|
37 |
|
38 |
+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
39 |
+
setInputValue(e.target.value);
|
40 |
+
};
|
41 |
|
42 |
+
const handleInputConfirm = () => {
|
43 |
+
if (inputValue && !tags.includes(inputValue)) {
|
44 |
+
setTags([...tags, inputValue]);
|
45 |
+
}
|
46 |
+
setInputVisible(false);
|
47 |
+
setInputValue('');
|
48 |
+
};
|
49 |
|
50 |
+
const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
51 |
+
setEditInputValue(e.target.value);
|
52 |
+
};
|
53 |
|
54 |
+
const handleEditInputConfirm = () => {
|
55 |
+
const newTags = [...tags];
|
56 |
+
newTags[editInputIndex] = editInputValue;
|
57 |
+
setTags(newTags);
|
58 |
+
setEditInputIndex(-1);
|
59 |
+
setEditInputValue('');
|
60 |
+
};
|
61 |
|
62 |
+
const tagInputStyle: React.CSSProperties = {
|
63 |
+
width: 64,
|
64 |
+
height: 22,
|
65 |
+
marginInlineEnd: 8,
|
66 |
+
verticalAlign: 'top',
|
67 |
+
};
|
68 |
|
69 |
+
const tagPlusStyle: React.CSSProperties = {
|
70 |
+
height: 22,
|
71 |
+
background: token.colorBgContainer,
|
72 |
+
borderStyle: 'dashed',
|
73 |
+
};
|
74 |
|
75 |
+
return (
|
76 |
+
<Space size={[0, 8]} wrap>
|
77 |
+
{tags.map((tag, index) => {
|
78 |
+
if (editInputIndex === index) {
|
79 |
+
return (
|
80 |
+
<Input
|
81 |
+
ref={editInputRef}
|
82 |
+
key={tag}
|
83 |
+
size="small"
|
84 |
+
style={tagInputStyle}
|
85 |
+
value={editInputValue}
|
86 |
+
onChange={handleEditInputChange}
|
87 |
+
onBlur={handleEditInputConfirm}
|
88 |
+
onPressEnter={handleEditInputConfirm}
|
89 |
+
/>
|
90 |
+
);
|
91 |
+
}
|
92 |
+
const isLongTag = tag.length > 20;
|
93 |
+
const tagElem = (
|
94 |
+
<Tag
|
95 |
+
key={tag}
|
96 |
+
closable={index !== 0}
|
97 |
+
style={{ userSelect: 'none' }}
|
98 |
+
onClose={() => handleClose(tag)}
|
99 |
+
>
|
100 |
+
<span
|
101 |
+
onDoubleClick={(e) => {
|
102 |
+
if (index !== 0) {
|
103 |
+
setEditInputIndex(index);
|
104 |
+
setEditInputValue(tag);
|
105 |
+
e.preventDefault();
|
106 |
}
|
107 |
+
}}
|
108 |
+
>
|
109 |
+
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
|
110 |
+
</span>
|
111 |
+
</Tag>
|
112 |
+
);
|
113 |
+
return isLongTag ? (
|
114 |
+
<Tooltip title={tag} key={tag}>
|
115 |
+
{tagElem}
|
116 |
+
</Tooltip>
|
117 |
+
) : (
|
118 |
+
tagElem
|
119 |
+
);
|
120 |
+
})}
|
121 |
+
{inputVisible ? (
|
122 |
+
<Input
|
123 |
+
ref={inputRef}
|
124 |
+
type="text"
|
125 |
+
size="small"
|
126 |
+
style={tagInputStyle}
|
127 |
+
value={inputValue}
|
128 |
+
onChange={handleInputChange}
|
129 |
+
onBlur={handleInputConfirm}
|
130 |
+
onPressEnter={handleInputConfirm}
|
131 |
+
/>
|
132 |
+
) : (
|
133 |
+
<Tag style={tagPlusStyle} onClick={showInput}>
|
134 |
+
添加关键词
|
135 |
+
</Tag>
|
136 |
+
)}
|
137 |
+
</Space>
|
138 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
};
|
140 |
|
141 |
+
export default EditTag;
|
web/src/pages/add-knowledge/components/knowledge-chunk/index.tsx
CHANGED
@@ -1,225 +1,282 @@
|
|
1 |
-
import
|
2 |
-
import {
|
3 |
-
import {
|
4 |
-
import { MinusSquareOutlined, DeleteOutlined, } from '@ant-design/icons';
|
5 |
import type { PaginationProps } from 'antd';
|
6 |
-
import {
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
-
|
10 |
-
import styles from './index.less'
|
11 |
import { debounce } from 'lodash';
|
12 |
-
import
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
|
|
|
|
|
|
|
|
|
|
17 |
}
|
18 |
-
|
19 |
-
|
20 |
-
const
|
21 |
-
const
|
22 |
-
const [
|
|
|
|
|
|
|
23 |
// const [datas, setDatas] = useState(data)
|
24 |
-
const { data = [], total,
|
25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
const getChunkList = (value?: string) => {
|
27 |
-
|
28 |
-
type: 'chunkModel/updateState',
|
29 |
-
payload: {
|
30 |
-
loading: true
|
31 |
-
}
|
32 |
-
});
|
33 |
-
interface payloadType {
|
34 |
-
doc_id: string;
|
35 |
-
keywords?: string;
|
36 |
-
available_int?: number
|
37 |
-
}
|
38 |
-
const payload: payloadType = {
|
39 |
doc_id,
|
40 |
keywords: value || keywords,
|
41 |
-
available_int
|
42 |
-
}
|
43 |
if (payload.available_int === -1) {
|
44 |
-
delete payload.available_int
|
45 |
}
|
46 |
dispatch({
|
47 |
type: 'chunkModel/chunk_list',
|
48 |
payload: {
|
49 |
...payload,
|
50 |
-
...pagination
|
51 |
-
}
|
52 |
});
|
53 |
-
}
|
54 |
-
const confirm = (id: string) => {
|
55 |
-
|
56 |
-
dispatch({
|
57 |
type: 'chunkModel/rm_chunk',
|
58 |
payload: {
|
59 |
-
chunk_ids: [id]
|
60 |
},
|
61 |
-
callback: getChunkList
|
62 |
});
|
|
|
|
|
63 |
};
|
|
|
64 |
const handleEditchunk = (chunk_id?: string) => {
|
65 |
dispatch({
|
66 |
type: 'chunkModel/updateState',
|
67 |
payload: {
|
68 |
isShowCreateModal: true,
|
69 |
chunk_id,
|
70 |
-
doc_id
|
71 |
},
|
72 |
-
callback: getChunkList
|
73 |
});
|
74 |
-
|
75 |
-
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (page, size) => {
|
76 |
-
setPagination({ page, size })
|
77 |
};
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
|
|
|
|
86 |
type: 'chunkModel/switch_chunk',
|
87 |
payload: {
|
88 |
chunk_ids: [id],
|
89 |
available_int: Number(available_int),
|
90 |
-
doc_id
|
91 |
},
|
92 |
-
callback: getChunkList
|
93 |
});
|
94 |
-
|
|
|
|
|
95 |
|
96 |
useEffect(() => {
|
97 |
-
getChunkList()
|
98 |
-
}, [doc_id, available_int, pagination])
|
99 |
-
|
100 |
-
const
|
101 |
-
const
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
}
|
106 |
-
const handleSelectChange = (value: number) => {
|
107 |
-
setAvailableInt(value)
|
108 |
-
}
|
109 |
-
console.log('loading', loading)
|
110 |
-
return (<>
|
111 |
-
<div className={styles.chunkPage}>
|
112 |
-
<div className={styles.filter}>
|
113 |
-
<div>
|
114 |
-
<Input placeholder="搜索" style={{ width: 220 }} value={keywords} allowClear onChange={handleInputChange} />
|
115 |
-
<Select
|
116 |
-
showSearch
|
117 |
-
placeholder="是否启用"
|
118 |
-
optionFilterProp="children"
|
119 |
-
value={available_int}
|
120 |
-
onChange={handleSelectChange}
|
121 |
-
style={{ width: 220 }}
|
122 |
-
options={[
|
123 |
-
{
|
124 |
-
value: -1,
|
125 |
-
label: '全部',
|
126 |
-
},
|
127 |
-
{
|
128 |
-
value: 1,
|
129 |
-
label: '启用',
|
130 |
-
},
|
131 |
-
{
|
132 |
-
value: 0,
|
133 |
-
label: '未启用',
|
134 |
-
},
|
135 |
-
]}
|
136 |
-
/>
|
137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
</div>
|
139 |
-
<
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
|
|
|
|
149 |
>
|
150 |
-
<
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
>
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
</div>
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
total={total}
|
216 |
-
/>
|
217 |
</div>
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
|
|
|
|
|
|
223 |
};
|
224 |
|
225 |
-
export default
|
|
|
1 |
+
import { api_host } from '@/utils/api';
|
2 |
+
import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil';
|
3 |
+
import { DeleteOutlined, MinusSquareOutlined } from '@ant-design/icons';
|
|
|
4 |
import type { PaginationProps } from 'antd';
|
5 |
+
import {
|
6 |
+
Button,
|
7 |
+
Card,
|
8 |
+
Col,
|
9 |
+
Input,
|
10 |
+
Pagination,
|
11 |
+
Popconfirm,
|
12 |
+
Row,
|
13 |
+
Select,
|
14 |
+
Spin,
|
15 |
+
Switch,
|
16 |
+
} from 'antd';
|
17 |
+
import React, { useCallback, useEffect, useState } from 'react';
|
18 |
+
import { useDispatch, useNavigate, useSelector } from 'umi';
|
19 |
+
import CreateModal from './components/createModal';
|
20 |
|
|
|
|
|
21 |
import { debounce } from 'lodash';
|
22 |
+
import styles from './index.less';
|
23 |
+
|
24 |
+
interface PayloadType {
|
25 |
+
doc_id: string;
|
26 |
+
keywords?: string;
|
27 |
+
available_int?: number;
|
28 |
+
}
|
29 |
+
|
30 |
+
interface IProps {
|
31 |
+
doc_id: string;
|
32 |
}
|
33 |
+
|
34 |
+
const Chunk = ({ doc_id }: IProps) => {
|
35 |
+
const dispatch = useDispatch();
|
36 |
+
const chunkModel = useSelector((state: any) => state.chunkModel);
|
37 |
+
const [keywords, SetKeywords] = useState('');
|
38 |
+
const [available_int, setAvailableInt] = useState(-1);
|
39 |
+
const navigate = useNavigate();
|
40 |
+
const [pagination, setPagination] = useState({ page: 1, size: 30 });
|
41 |
// const [datas, setDatas] = useState(data)
|
42 |
+
const { data = [], total, chunk_id, isShowCreateModal } = chunkModel;
|
43 |
+
const effects = useSelector((state: any) => state.loading.effects);
|
44 |
+
const loading = getOneNamespaceEffectsLoading('chunkModel', effects, [
|
45 |
+
'create_hunk',
|
46 |
+
'chunk_list',
|
47 |
+
'switch_chunk',
|
48 |
+
]);
|
49 |
+
|
50 |
const getChunkList = (value?: string) => {
|
51 |
+
const payload: PayloadType = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
doc_id,
|
53 |
keywords: value || keywords,
|
54 |
+
available_int,
|
55 |
+
};
|
56 |
if (payload.available_int === -1) {
|
57 |
+
delete payload.available_int;
|
58 |
}
|
59 |
dispatch({
|
60 |
type: 'chunkModel/chunk_list',
|
61 |
payload: {
|
62 |
...payload,
|
63 |
+
...pagination,
|
64 |
+
},
|
65 |
});
|
66 |
+
};
|
67 |
+
const confirm = async (id: string) => {
|
68 |
+
const retcode = await dispatch<any>({
|
|
|
69 |
type: 'chunkModel/rm_chunk',
|
70 |
payload: {
|
71 |
+
chunk_ids: [id],
|
72 |
},
|
|
|
73 |
});
|
74 |
+
|
75 |
+
retcode === 0 && getChunkList();
|
76 |
};
|
77 |
+
|
78 |
const handleEditchunk = (chunk_id?: string) => {
|
79 |
dispatch({
|
80 |
type: 'chunkModel/updateState',
|
81 |
payload: {
|
82 |
isShowCreateModal: true,
|
83 |
chunk_id,
|
84 |
+
doc_id,
|
85 |
},
|
|
|
86 |
});
|
87 |
+
getChunkList();
|
|
|
|
|
88 |
};
|
89 |
+
|
90 |
+
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (
|
91 |
+
page,
|
92 |
+
size,
|
93 |
+
) => {
|
94 |
+
setPagination({ page, size });
|
95 |
+
};
|
96 |
+
|
97 |
+
const switchChunk = async (id: string, available_int: boolean) => {
|
98 |
+
const retcode = await dispatch<any>({
|
99 |
type: 'chunkModel/switch_chunk',
|
100 |
payload: {
|
101 |
chunk_ids: [id],
|
102 |
available_int: Number(available_int),
|
103 |
+
doc_id,
|
104 |
},
|
|
|
105 |
});
|
106 |
+
|
107 |
+
retcode === 0 && getChunkList();
|
108 |
+
};
|
109 |
|
110 |
useEffect(() => {
|
111 |
+
getChunkList();
|
112 |
+
}, [doc_id, available_int, pagination]);
|
113 |
+
|
114 |
+
const debounceChange = debounce(getChunkList, 300);
|
115 |
+
const debounceCallback = useCallback(
|
116 |
+
(value: string) => debounceChange(value),
|
117 |
+
[],
|
118 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
|
120 |
+
const handleInputChange = (
|
121 |
+
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
122 |
+
) => {
|
123 |
+
const value = e.target.value;
|
124 |
+
SetKeywords(value);
|
125 |
+
debounceCallback(value);
|
126 |
+
};
|
127 |
+
const handleSelectChange = (value: number) => {
|
128 |
+
setAvailableInt(value);
|
129 |
+
};
|
130 |
+
return (
|
131 |
+
<>
|
132 |
+
<div className={styles.chunkPage}>
|
133 |
+
<div className={styles.filter}>
|
134 |
+
<div>
|
135 |
+
<Input
|
136 |
+
placeholder="搜索"
|
137 |
+
style={{ width: 220 }}
|
138 |
+
value={keywords}
|
139 |
+
allowClear
|
140 |
+
onChange={handleInputChange}
|
141 |
+
/>
|
142 |
+
<Select
|
143 |
+
showSearch
|
144 |
+
placeholder="是否启用"
|
145 |
+
optionFilterProp="children"
|
146 |
+
value={available_int}
|
147 |
+
onChange={handleSelectChange}
|
148 |
+
style={{ width: 220 }}
|
149 |
+
options={[
|
150 |
+
{
|
151 |
+
value: -1,
|
152 |
+
label: '全部',
|
153 |
+
},
|
154 |
+
{
|
155 |
+
value: 1,
|
156 |
+
label: '启用',
|
157 |
+
},
|
158 |
+
{
|
159 |
+
value: 0,
|
160 |
+
label: '未启用',
|
161 |
+
},
|
162 |
+
]}
|
163 |
+
/>
|
164 |
+
</div>
|
165 |
+
<Button
|
166 |
+
onClick={() => {
|
167 |
+
handleEditchunk();
|
168 |
+
}}
|
169 |
+
type="link"
|
170 |
+
>
|
171 |
+
添加分段
|
172 |
+
</Button>
|
173 |
</div>
|
174 |
+
<div className={styles.pageContent}>
|
175 |
+
<Spin spinning={loading} className={styles.spin} size="large">
|
176 |
+
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24 }}>
|
177 |
+
{data.map((item: any) => {
|
178 |
+
return (
|
179 |
+
<Col
|
180 |
+
className="gutter-row"
|
181 |
+
key={item.chunk_id}
|
182 |
+
xs={24}
|
183 |
+
sm={12}
|
184 |
+
md={12}
|
185 |
+
lg={8}
|
186 |
>
|
187 |
+
<Card
|
188 |
+
className={styles.card}
|
189 |
+
onClick={() => {
|
190 |
+
handleEditchunk(item.chunk_id);
|
191 |
+
}}
|
192 |
+
>
|
193 |
+
<img
|
194 |
+
style={{ width: '50px' }}
|
195 |
+
src={`${api_host}/document/image/${item.img_id}`}
|
196 |
+
alt=""
|
197 |
+
/>
|
198 |
+
<div className={styles.container}>
|
199 |
+
<div className={styles.content}>
|
200 |
+
<span className={styles.context}>
|
201 |
+
{item.content_ltks}
|
202 |
+
</span>
|
203 |
+
<span className={styles.delete}>
|
204 |
+
<Switch
|
205 |
+
size="small"
|
206 |
+
defaultValue={item.available_int == '1'}
|
207 |
+
onChange={(checked: boolean, e: any) => {
|
208 |
+
e.stopPropagation();
|
209 |
+
e.nativeEvent.stopImmediatePropagation();
|
210 |
+
switchChunk(item.chunk_id, checked);
|
211 |
+
}}
|
212 |
+
/>
|
213 |
+
</span>
|
214 |
+
</div>
|
215 |
+
<div className={styles.footer}>
|
216 |
+
<span className={styles.text}>
|
217 |
+
<MinusSquareOutlined />
|
218 |
+
{item.doc_num}文档
|
219 |
+
</span>
|
220 |
+
<span className={styles.text}>
|
221 |
+
<MinusSquareOutlined />
|
222 |
+
{item.chunk_num}个
|
223 |
+
</span>
|
224 |
+
<span className={styles.text}>
|
225 |
+
<MinusSquareOutlined />
|
226 |
+
{item.token_num}千字符
|
227 |
+
</span>
|
228 |
+
<span style={{ float: 'right' }}>
|
229 |
+
<Popconfirm
|
230 |
+
title="Delete the task"
|
231 |
+
description="Are you sure to delete this task?"
|
232 |
+
onConfirm={(e: any) => {
|
233 |
+
e.stopPropagation();
|
234 |
+
e.nativeEvent.stopImmediatePropagation();
|
235 |
+
console.log(confirm);
|
236 |
+
confirm(item.chunk_id);
|
237 |
+
}}
|
238 |
+
okText="Yes"
|
239 |
+
cancelText="No"
|
240 |
+
>
|
241 |
+
<DeleteOutlined
|
242 |
+
onClick={(e) => {
|
243 |
+
e.stopPropagation();
|
244 |
+
e.nativeEvent.stopImmediatePropagation();
|
245 |
+
}}
|
246 |
+
/>
|
247 |
+
</Popconfirm>
|
248 |
+
</span>
|
249 |
+
</div>
|
250 |
</div>
|
251 |
+
</Card>
|
252 |
+
</Col>
|
253 |
+
);
|
254 |
+
})}
|
255 |
+
</Row>
|
256 |
+
</Spin>
|
257 |
+
</div>
|
258 |
+
<div className={styles.pageFooter}>
|
259 |
+
<Pagination
|
260 |
+
responsive
|
261 |
+
showLessItems
|
262 |
+
showQuickJumper
|
263 |
+
showSizeChanger
|
264 |
+
onChange={onShowSizeChange}
|
265 |
+
defaultPageSize={30}
|
266 |
+
pageSizeOptions={[30, 60, 90]}
|
267 |
+
defaultCurrent={pagination.page}
|
268 |
+
total={total}
|
269 |
+
/>
|
270 |
+
</div>
|
|
|
|
|
271 |
</div>
|
272 |
+
<CreateModal
|
273 |
+
doc_id={doc_id}
|
274 |
+
isShowCreateModal={isShowCreateModal}
|
275 |
+
chunk_id={chunk_id}
|
276 |
+
getChunkList={getChunkList}
|
277 |
+
/>
|
278 |
+
</>
|
279 |
+
);
|
280 |
};
|
281 |
|
282 |
+
export default Chunk;
|
web/src/pages/add-knowledge/components/knowledge-chunk/model.ts
CHANGED
@@ -1,8 +1,7 @@
|
|
1 |
import kbService from '@/services/kbService';
|
2 |
-
import {
|
3 |
|
4 |
-
export interface
|
5 |
-
loading: boolean;
|
6 |
data: any[];
|
7 |
total: number;
|
8 |
isShowCreateModal: boolean;
|
@@ -10,25 +9,10 @@ export interface chunkModelState {
|
|
10 |
doc_id: string;
|
11 |
chunkInfo: any;
|
12 |
}
|
13 |
-
|
14 |
-
|
15 |
-
state: chunkModelState;
|
16 |
-
effects: {
|
17 |
-
chunk_list: Effect;
|
18 |
-
get_chunk: Effect;
|
19 |
-
create_hunk: Effect;
|
20 |
-
switch_chunk: Effect;
|
21 |
-
rm_chunk: Effect;
|
22 |
-
};
|
23 |
-
reducers: {
|
24 |
-
updateState: Reducer<chunkModelState>;
|
25 |
-
};
|
26 |
-
// subscriptions: { setup: Subscription };
|
27 |
-
}
|
28 |
-
const Model: chunkgModelType = {
|
29 |
namespace: 'chunkModel',
|
30 |
state: {
|
31 |
-
loading: false,
|
32 |
data: [],
|
33 |
total: 0,
|
34 |
isShowCreateModal: false,
|
@@ -36,6 +20,14 @@ const Model: chunkgModelType = {
|
|
36 |
doc_id: '',
|
37 |
chunkInfo: {},
|
38 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
// subscriptions: {
|
40 |
// setup({ dispatch, history }) {
|
41 |
// history.listen(location => {
|
@@ -44,7 +36,7 @@ const Model: chunkgModelType = {
|
|
44 |
// }
|
45 |
// },
|
46 |
effects: {
|
47 |
-
*chunk_list({ payload = {}
|
48 |
const { data, response } = yield call(kbService.chunk_list, payload);
|
49 |
|
50 |
const { retcode, data: res, retmsg } = data;
|
@@ -55,28 +47,23 @@ const Model: chunkgModelType = {
|
|
55 |
payload: {
|
56 |
data: res.chunks,
|
57 |
total: res.total,
|
58 |
-
loading: false,
|
59 |
},
|
60 |
});
|
61 |
-
callback && callback();
|
62 |
}
|
63 |
},
|
64 |
-
*switch_chunk({ payload = {}
|
65 |
const { data, response } = yield call(kbService.switch_chunk, payload);
|
66 |
const { retcode, data: res, retmsg } = data;
|
67 |
-
|
68 |
-
callback && callback();
|
69 |
-
}
|
70 |
},
|
71 |
-
*rm_chunk({ payload = {}
|
72 |
console.log('shanchu');
|
73 |
const { data, response } = yield call(kbService.rm_chunk, payload);
|
74 |
const { retcode, data: res, retmsg } = data;
|
75 |
-
|
76 |
-
|
77 |
-
}
|
78 |
},
|
79 |
-
*get_chunk({ payload = {}
|
80 |
const { data, response } = yield call(kbService.get_chunk, payload);
|
81 |
const { retcode, data: res, retmsg } = data;
|
82 |
if (retcode === 0) {
|
@@ -86,28 +73,16 @@ const Model: chunkgModelType = {
|
|
86 |
chunkInfo: res,
|
87 |
},
|
88 |
});
|
89 |
-
callback && callback(res);
|
90 |
}
|
|
|
91 |
},
|
92 |
*create_hunk({ payload = {} }, { call, put }) {
|
93 |
-
yield put({
|
94 |
-
type: 'updateState',
|
95 |
-
payload: {
|
96 |
-
loading: true,
|
97 |
-
},
|
98 |
-
});
|
99 |
let service = kbService.create_chunk;
|
100 |
if (payload.chunk_id) {
|
101 |
service = kbService.set_chunk;
|
102 |
}
|
103 |
const { data, response } = yield call(service, payload);
|
104 |
const { retcode, data: res, retmsg } = data;
|
105 |
-
yield put({
|
106 |
-
type: 'updateState',
|
107 |
-
payload: {
|
108 |
-
loading: false,
|
109 |
-
},
|
110 |
-
});
|
111 |
if (retcode === 0) {
|
112 |
yield put({
|
113 |
type: 'updateState',
|
@@ -118,13 +93,5 @@ const Model: chunkgModelType = {
|
|
118 |
}
|
119 |
},
|
120 |
},
|
121 |
-
reducers: {
|
122 |
-
updateState(state, { payload }) {
|
123 |
-
return {
|
124 |
-
...state,
|
125 |
-
...payload,
|
126 |
-
};
|
127 |
-
},
|
128 |
-
},
|
129 |
};
|
130 |
-
export default
|
|
|
1 |
import kbService from '@/services/kbService';
|
2 |
+
import { DvaModel } from 'umi';
|
3 |
|
4 |
+
export interface ChunkModelState {
|
|
|
5 |
data: any[];
|
6 |
total: number;
|
7 |
isShowCreateModal: boolean;
|
|
|
9 |
doc_id: string;
|
10 |
chunkInfo: any;
|
11 |
}
|
12 |
+
|
13 |
+
const model: DvaModel<ChunkModelState> = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
namespace: 'chunkModel',
|
15 |
state: {
|
|
|
16 |
data: [],
|
17 |
total: 0,
|
18 |
isShowCreateModal: false,
|
|
|
20 |
doc_id: '',
|
21 |
chunkInfo: {},
|
22 |
},
|
23 |
+
reducers: {
|
24 |
+
updateState(state, { payload }) {
|
25 |
+
return {
|
26 |
+
...state,
|
27 |
+
...payload,
|
28 |
+
};
|
29 |
+
},
|
30 |
+
},
|
31 |
// subscriptions: {
|
32 |
// setup({ dispatch, history }) {
|
33 |
// history.listen(location => {
|
|
|
36 |
// }
|
37 |
// },
|
38 |
effects: {
|
39 |
+
*chunk_list({ payload = {} }, { call, put }) {
|
40 |
const { data, response } = yield call(kbService.chunk_list, payload);
|
41 |
|
42 |
const { retcode, data: res, retmsg } = data;
|
|
|
47 |
payload: {
|
48 |
data: res.chunks,
|
49 |
total: res.total,
|
|
|
50 |
},
|
51 |
});
|
|
|
52 |
}
|
53 |
},
|
54 |
+
*switch_chunk({ payload = {} }, { call, put }) {
|
55 |
const { data, response } = yield call(kbService.switch_chunk, payload);
|
56 |
const { retcode, data: res, retmsg } = data;
|
57 |
+
return retcode;
|
|
|
|
|
58 |
},
|
59 |
+
*rm_chunk({ payload = {} }, { call, put }) {
|
60 |
console.log('shanchu');
|
61 |
const { data, response } = yield call(kbService.rm_chunk, payload);
|
62 |
const { retcode, data: res, retmsg } = data;
|
63 |
+
|
64 |
+
return retcode;
|
|
|
65 |
},
|
66 |
+
*get_chunk({ payload = {} }, { call, put }) {
|
67 |
const { data, response } = yield call(kbService.get_chunk, payload);
|
68 |
const { retcode, data: res, retmsg } = data;
|
69 |
if (retcode === 0) {
|
|
|
73 |
chunkInfo: res,
|
74 |
},
|
75 |
});
|
|
|
76 |
}
|
77 |
+
return data;
|
78 |
},
|
79 |
*create_hunk({ payload = {} }, { call, put }) {
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
let service = kbService.create_chunk;
|
81 |
if (payload.chunk_id) {
|
82 |
service = kbService.set_chunk;
|
83 |
}
|
84 |
const { data, response } = yield call(service, payload);
|
85 |
const { retcode, data: res, retmsg } = data;
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
if (retcode === 0) {
|
87 |
yield put({
|
88 |
type: 'updateState',
|
|
|
93 |
}
|
94 |
},
|
95 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
};
|
97 |
+
export default model;
|
web/src/pages/add-knowledge/components/knowledge-file/createEFileModal.tsx
CHANGED
@@ -1,79 +1,73 @@
|
|
1 |
-
import
|
2 |
-
import
|
3 |
-
import
|
4 |
-
import {
|
5 |
-
import { Input, Modal, Form } from 'antd'
|
6 |
-
import styles from './index.less';
|
7 |
-
import type { kFModelState } from './model'
|
8 |
|
9 |
type FieldType = {
|
10 |
-
|
11 |
};
|
12 |
interface kFProps {
|
13 |
-
|
14 |
-
|
15 |
-
getKfList: () => void;
|
16 |
-
kb_id: string
|
17 |
}
|
18 |
-
const Index: React.FC<kFProps> = ({ kFModel, dispatch, getKfList, kb_id }) => {
|
19 |
-
const { isShowCEFwModal } = kFModel
|
20 |
-
const { t } = useTranslation()
|
21 |
-
const handleCancel = () => {
|
22 |
-
dispatch({
|
23 |
-
type: 'kFModel/updateState',
|
24 |
-
payload: {
|
25 |
-
isShowCEFwModal: false
|
26 |
-
}
|
27 |
-
});
|
28 |
-
};
|
29 |
-
const [form] = Form.useForm()
|
30 |
-
const handleOk = async () => {
|
31 |
-
try {
|
32 |
-
const values = await form.validateFields();
|
33 |
-
dispatch({
|
34 |
-
type: 'kFModel/document_create',
|
35 |
-
payload: {
|
36 |
-
name: values.name,
|
37 |
-
kb_id
|
38 |
-
},
|
39 |
-
callback: () => {
|
40 |
-
dispatch({
|
41 |
-
type: 'kFModel/updateState',
|
42 |
-
payload: {
|
43 |
-
isShowCEFwModal: false
|
44 |
-
}
|
45 |
-
});
|
46 |
-
getKfList && getKfList()
|
47 |
-
}
|
48 |
-
});
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
|
|
|
|
54 |
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
}
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Form, Input, Modal } from 'antd';
|
2 |
+
import React from 'react';
|
3 |
+
import { useTranslation } from 'react-i18next';
|
4 |
+
import { useDispatch, useSelector } from 'umi';
|
|
|
|
|
|
|
5 |
|
6 |
type FieldType = {
|
7 |
+
name?: string;
|
8 |
};
|
9 |
interface kFProps {
|
10 |
+
getKfList: () => void;
|
11 |
+
kb_id: string;
|
|
|
|
|
12 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
+
const FileCreatingModal: React.FC<kFProps> = ({ getKfList, kb_id }) => {
|
15 |
+
const dispatch = useDispatch();
|
16 |
+
const kFModel = useSelector((state: any) => state.kFModel);
|
17 |
+
const { isShowCEFwModal } = kFModel;
|
18 |
+
const [form] = Form.useForm();
|
19 |
+
const { t } = useTranslation();
|
20 |
|
21 |
+
const handleCancel = () => {
|
22 |
+
dispatch({
|
23 |
+
type: 'kFModel/updateState',
|
24 |
+
payload: {
|
25 |
+
isShowCEFwModal: false,
|
26 |
+
},
|
27 |
+
});
|
28 |
+
};
|
29 |
+
const handleOk = async () => {
|
30 |
+
try {
|
31 |
+
const values = await form.validateFields();
|
32 |
+
const retcode = await dispatch<any>({
|
33 |
+
type: 'kFModel/document_create',
|
34 |
+
payload: {
|
35 |
+
name: values.name,
|
36 |
+
kb_id,
|
37 |
+
},
|
38 |
+
});
|
39 |
+
if (retcode === 0) {
|
40 |
+
getKfList && getKfList();
|
41 |
+
}
|
42 |
+
} catch (errorInfo) {
|
43 |
+
console.log('Failed:', errorInfo);
|
44 |
+
}
|
45 |
+
};
|
46 |
|
47 |
+
return (
|
48 |
+
<Modal
|
49 |
+
title="Basic Modal"
|
50 |
+
open={isShowCEFwModal}
|
51 |
+
onOk={handleOk}
|
52 |
+
onCancel={handleCancel}
|
53 |
+
>
|
54 |
+
<Form
|
55 |
+
form={form}
|
56 |
+
name="validateOnly"
|
57 |
+
labelCol={{ span: 8 }}
|
58 |
+
wrapperCol={{ span: 16 }}
|
59 |
+
style={{ maxWidth: 600 }}
|
60 |
+
autoComplete="off"
|
61 |
+
>
|
62 |
+
<Form.Item<FieldType>
|
63 |
+
label="文件名"
|
64 |
+
name="name"
|
65 |
+
rules={[{ required: true, message: 'Please input value!' }]}
|
66 |
+
>
|
67 |
+
<Input />
|
68 |
+
</Form.Item>
|
69 |
+
</Form>
|
70 |
+
</Modal>
|
71 |
+
);
|
72 |
+
};
|
73 |
+
export default FileCreatingModal;
|
web/src/pages/add-knowledge/components/knowledge-file/index.tsx
CHANGED
@@ -1,228 +1,273 @@
|
|
1 |
-
import
|
2 |
-
import {
|
3 |
-
import { Space, Table, Input, Button, Switch, Dropdown, } from 'antd';
|
4 |
import type { MenuProps } from 'antd';
|
5 |
-
import {
|
6 |
-
import { debounce } from 'lodash';
|
7 |
import type { ColumnsType } from 'antd/es/table';
|
8 |
-
import
|
9 |
-
import
|
10 |
-
import
|
11 |
-
import
|
12 |
-
import
|
|
|
|
|
13 |
|
14 |
interface DataType {
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
}
|
24 |
|
25 |
-
interface
|
26 |
-
|
27 |
-
kFModel: kFModelState;
|
28 |
-
kb_id: string
|
29 |
}
|
30 |
|
31 |
-
const
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
}
|
45 |
-
dispatch({
|
46 |
-
type: 'kFModel/getKfList',
|
47 |
-
payload
|
48 |
-
});
|
49 |
-
}
|
50 |
-
useEffect(() => {
|
51 |
-
if (kb_id) {
|
52 |
-
getKfList()
|
53 |
-
}
|
54 |
-
}, [kb_id])
|
55 |
-
const debounceChange = debounce(getKfList, 300)
|
56 |
-
const debounceCallback = useCallback((value: string) => debounceChange(value), [])
|
57 |
-
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
58 |
-
const value = e.target.value
|
59 |
-
setInputValue(value)
|
60 |
-
debounceCallback(e.target.value)
|
61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
}
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
status: Number(e)
|
69 |
-
},
|
70 |
-
callback() {
|
71 |
-
getKfList()
|
72 |
-
}
|
73 |
-
});
|
74 |
-
}
|
75 |
-
const onRmDocument = () => {
|
76 |
-
dispatch({
|
77 |
-
type: 'kFModel/document_rm',
|
78 |
-
payload: {
|
79 |
-
doc_id
|
80 |
-
},
|
81 |
-
callback() {
|
82 |
-
getKfList()
|
83 |
-
}
|
84 |
-
});
|
85 |
|
|
|
|
|
|
|
86 |
}
|
87 |
-
|
88 |
-
dispatch({
|
89 |
-
type: 'kFModel/updateState',
|
90 |
-
payload: {
|
91 |
-
isShowCEFwModal: true
|
92 |
-
}
|
93 |
-
});
|
94 |
-
};
|
95 |
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
const
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
),
|
144 |
-
// disabled: true,
|
145 |
-
},
|
146 |
-
]
|
147 |
-
const toChunk = (id: string) => {
|
148 |
-
console.log(id)
|
149 |
-
navigate(`/knowledge/add/setting?activeKey=file&id=${kb_id}&doc_id=${id}`);
|
150 |
-
}
|
151 |
-
const columns: ColumnsType<DataType> = [
|
152 |
-
{
|
153 |
-
title: '名称',
|
154 |
-
dataIndex: 'name',
|
155 |
-
key: 'name',
|
156 |
-
render: (text: any, { id }) => <div className={styles.tochunks} onClick={() => toChunk(id)}><img className={styles.img} src='https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg' alt="" />{text}</div>,
|
157 |
-
className: `${styles.column}`
|
158 |
-
},
|
159 |
-
{
|
160 |
-
title: '数据总量',
|
161 |
-
dataIndex: 'chunk_num',
|
162 |
-
key: 'chunk_num',
|
163 |
-
className: `${styles.column}`
|
164 |
-
},
|
165 |
-
{
|
166 |
-
title: 'Tokens',
|
167 |
-
dataIndex: 'token_num',
|
168 |
-
key: 'token_num',
|
169 |
-
className: `${styles.column}`
|
170 |
-
},
|
171 |
-
{
|
172 |
-
title: '文件大小',
|
173 |
-
dataIndex: 'size',
|
174 |
-
key: 'size',
|
175 |
-
className: `${styles.column}`
|
176 |
-
},
|
177 |
-
{
|
178 |
-
title: '状态',
|
179 |
-
key: 'status',
|
180 |
-
dataIndex: 'status',
|
181 |
-
className: `${styles.column}`,
|
182 |
-
render: (_, { status: string, id }) => (
|
183 |
-
<>
|
184 |
-
<Switch defaultChecked={status === '1'} onChange={(e) => {
|
185 |
-
onChangeStatus(e, id)
|
186 |
-
}} />
|
187 |
-
</>
|
188 |
-
),
|
189 |
-
},
|
190 |
-
{
|
191 |
-
title: 'Action',
|
192 |
-
key: 'action',
|
193 |
-
className: `${styles.column}`,
|
194 |
-
render: (_, record) => (
|
195 |
-
<Space size="middle">
|
196 |
-
<Dropdown menu={{ items: chunkItems }} trigger={['click']}>
|
197 |
-
<a onClick={() => {
|
198 |
-
setDocId(record.id)
|
199 |
-
setParserId(record.parser_id)
|
200 |
-
}}>
|
201 |
-
分段设置 <DownOutlined />
|
202 |
-
</a>
|
203 |
-
</Dropdown>
|
204 |
-
</Space>
|
205 |
-
),
|
206 |
-
},
|
207 |
];
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
</div>
|
222 |
-
|
223 |
-
|
224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
</>
|
|
|
226 |
};
|
227 |
|
228 |
-
export default
|
|
|
1 |
+
import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil';
|
2 |
+
import { DownOutlined } from '@ant-design/icons';
|
|
|
3 |
import type { MenuProps } from 'antd';
|
4 |
+
import { Button, Dropdown, Input, Space, Switch, Table } from 'antd';
|
|
|
5 |
import type { ColumnsType } from 'antd/es/table';
|
6 |
+
import { debounce } from 'lodash';
|
7 |
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
8 |
+
import { useDispatch, useNavigate, useSelector } from 'umi';
|
9 |
+
import CreateEPModal from './createEFileModal';
|
10 |
+
import styles from './index.less';
|
11 |
+
import SegmentSetModal from './segmentSetModal';
|
12 |
+
import UploadFile from './upload';
|
13 |
|
14 |
interface DataType {
|
15 |
+
name: string;
|
16 |
+
chunk_num: string;
|
17 |
+
token_num: number;
|
18 |
+
update_date: string;
|
19 |
+
size: string;
|
20 |
+
status: string;
|
21 |
+
id: string;
|
22 |
+
parser_id: string;
|
23 |
}
|
24 |
|
25 |
+
interface KFProps {
|
26 |
+
kb_id: string;
|
|
|
|
|
27 |
}
|
28 |
|
29 |
+
const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => {
|
30 |
+
const dispatch = useDispatch();
|
31 |
+
const kFModel = useSelector((state: any) => state.kFModel);
|
32 |
+
const effects = useSelector((state: any) => state.loading.effects);
|
33 |
+
const { data } = kFModel;
|
34 |
+
const loading = getOneNamespaceEffectsLoading('kFModel', effects, [
|
35 |
+
'getKfList',
|
36 |
+
'updateDocumentStatus',
|
37 |
+
]);
|
38 |
+
const [inputValue, setInputValue] = useState('');
|
39 |
+
const [doc_id, setDocId] = useState('0');
|
40 |
+
const [parser_id, setParserId] = useState('0');
|
41 |
+
let navigate = useNavigate();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
+
const getKfList = (keywords?: string) => {
|
44 |
+
const payload = {
|
45 |
+
kb_id,
|
46 |
+
keywords,
|
47 |
+
};
|
48 |
+
if (!keywords) {
|
49 |
+
delete payload.keywords;
|
50 |
}
|
51 |
+
dispatch({
|
52 |
+
type: 'kFModel/getKfList',
|
53 |
+
payload,
|
54 |
+
});
|
55 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
+
useEffect(() => {
|
58 |
+
if (kb_id) {
|
59 |
+
getKfList();
|
60 |
}
|
61 |
+
}, [kb_id]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
|
63 |
+
const debounceChange = debounce(getKfList, 300);
|
64 |
+
const debounceCallback = useCallback(
|
65 |
+
(value: string) => debounceChange(value),
|
66 |
+
[],
|
67 |
+
);
|
68 |
+
const handleInputChange = (
|
69 |
+
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
70 |
+
) => {
|
71 |
+
const value = e.target.value;
|
72 |
+
setInputValue(value);
|
73 |
+
debounceCallback(e.target.value);
|
74 |
+
};
|
75 |
+
const onChangeStatus = (e: boolean, doc_id: string) => {
|
76 |
+
dispatch({
|
77 |
+
type: 'kFModel/updateDocumentStatus',
|
78 |
+
payload: {
|
79 |
+
doc_id,
|
80 |
+
status: Number(e),
|
81 |
+
kb_id,
|
82 |
+
},
|
83 |
+
});
|
84 |
+
};
|
85 |
+
const onRmDocument = () => {
|
86 |
+
dispatch({
|
87 |
+
type: 'kFModel/document_rm',
|
88 |
+
payload: {
|
89 |
+
doc_id,
|
90 |
+
kb_id,
|
91 |
+
},
|
92 |
+
});
|
93 |
+
};
|
94 |
+
const showCEFModal = () => {
|
95 |
+
dispatch({
|
96 |
+
type: 'kFModel/updateState',
|
97 |
+
payload: {
|
98 |
+
isShowCEFwModal: true,
|
99 |
+
},
|
100 |
+
});
|
101 |
+
};
|
102 |
|
103 |
+
const showSegmentSetModal = () => {
|
104 |
+
dispatch({
|
105 |
+
type: 'kFModel/updateState',
|
106 |
+
payload: {
|
107 |
+
isShowSegmentSetModal: true,
|
108 |
+
},
|
109 |
+
});
|
110 |
+
};
|
111 |
+
const actionItems: MenuProps['items'] = useMemo(() => {
|
112 |
+
return [
|
113 |
+
{
|
114 |
+
key: '1',
|
115 |
+
label: (
|
116 |
+
<div>
|
117 |
+
<UploadFile kb_id={kb_id} getKfList={getKfList} />
|
118 |
+
</div>
|
119 |
+
),
|
120 |
+
},
|
121 |
+
{
|
122 |
+
key: '2',
|
123 |
+
label: (
|
124 |
+
<div>
|
125 |
+
<Button type="link" onClick={showCEFModal}>
|
126 |
+
{' '}
|
127 |
+
导入虚拟文件
|
128 |
+
</Button>
|
129 |
+
</div>
|
130 |
+
),
|
131 |
+
// disabled: true,
|
132 |
+
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
];
|
134 |
+
}, [kb_id]);
|
135 |
+
const chunkItems: MenuProps['items'] = [
|
136 |
+
{
|
137 |
+
key: '1',
|
138 |
+
label: (
|
139 |
+
<div>
|
140 |
+
<Button type="link" onClick={showSegmentSetModal}>
|
141 |
+
{' '}
|
142 |
+
分段设置
|
143 |
+
</Button>
|
144 |
+
</div>
|
145 |
+
),
|
146 |
+
},
|
147 |
+
{
|
148 |
+
key: '2',
|
149 |
+
label: (
|
150 |
+
<div>
|
151 |
+
<Button type="link" onClick={onRmDocument}>
|
152 |
+
{' '}
|
153 |
+
删除
|
154 |
+
</Button>
|
155 |
+
</div>
|
156 |
+
),
|
157 |
+
// disabled: true,
|
158 |
+
},
|
159 |
+
];
|
160 |
+
const toChunk = (id: string) => {
|
161 |
+
console.log(id);
|
162 |
+
navigate(`/knowledge/add/setting?activeKey=file&id=${kb_id}&doc_id=${id}`);
|
163 |
+
};
|
164 |
+
const columns: ColumnsType<DataType> = [
|
165 |
+
{
|
166 |
+
title: '名称',
|
167 |
+
dataIndex: 'name',
|
168 |
+
key: 'name',
|
169 |
+
render: (text: any, { id }) => (
|
170 |
+
<div className={styles.tochunks} onClick={() => toChunk(id)}>
|
171 |
+
<img
|
172 |
+
className={styles.img}
|
173 |
+
src="https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg"
|
174 |
+
alt=""
|
175 |
+
/>
|
176 |
+
{text}
|
177 |
+
</div>
|
178 |
+
),
|
179 |
+
className: `${styles.column}`,
|
180 |
+
},
|
181 |
+
{
|
182 |
+
title: '数据总量',
|
183 |
+
dataIndex: 'chunk_num',
|
184 |
+
key: 'chunk_num',
|
185 |
+
className: `${styles.column}`,
|
186 |
+
},
|
187 |
+
{
|
188 |
+
title: 'Tokens',
|
189 |
+
dataIndex: 'token_num',
|
190 |
+
key: 'token_num',
|
191 |
+
className: `${styles.column}`,
|
192 |
+
},
|
193 |
+
{
|
194 |
+
title: '文件大小',
|
195 |
+
dataIndex: 'size',
|
196 |
+
key: 'size',
|
197 |
+
className: `${styles.column}`,
|
198 |
+
},
|
199 |
+
{
|
200 |
+
title: '状态',
|
201 |
+
key: 'status',
|
202 |
+
dataIndex: 'status',
|
203 |
+
className: `${styles.column}`,
|
204 |
+
render: (_, { status: string, id }) => (
|
205 |
+
<>
|
206 |
+
<Switch
|
207 |
+
defaultChecked={status === '1'}
|
208 |
+
onChange={(e) => {
|
209 |
+
onChangeStatus(e, id);
|
210 |
+
}}
|
211 |
+
/>
|
212 |
+
</>
|
213 |
+
),
|
214 |
+
},
|
215 |
+
{
|
216 |
+
title: 'Action',
|
217 |
+
key: 'action',
|
218 |
+
className: `${styles.column}`,
|
219 |
+
render: (_, record) => (
|
220 |
+
<Space size="middle">
|
221 |
+
<Dropdown menu={{ items: chunkItems }} trigger={['click']}>
|
222 |
+
<a
|
223 |
+
onClick={() => {
|
224 |
+
setDocId(record.id);
|
225 |
+
setParserId(record.parser_id);
|
226 |
+
}}
|
227 |
+
>
|
228 |
+
分段设置 <DownOutlined />
|
229 |
+
</a>
|
230 |
+
</Dropdown>
|
231 |
+
</Space>
|
232 |
+
),
|
233 |
+
},
|
234 |
+
];
|
235 |
+
return (
|
236 |
+
<>
|
237 |
+
<div className={styles.filter}>
|
238 |
+
<div className="search">
|
239 |
+
<Input
|
240 |
+
placeholder="搜索"
|
241 |
+
value={inputValue}
|
242 |
+
style={{ width: 220 }}
|
243 |
+
allowClear
|
244 |
+
onChange={handleInputChange}
|
245 |
+
/>
|
246 |
+
</div>
|
247 |
+
<div className="operate">
|
248 |
+
<Dropdown menu={{ items: actionItems }} trigger={['click']}>
|
249 |
+
<a>
|
250 |
+
导入文件 <DownOutlined />
|
251 |
+
</a>
|
252 |
+
</Dropdown>
|
253 |
</div>
|
254 |
+
</div>
|
255 |
+
<Table
|
256 |
+
rowKey="id"
|
257 |
+
columns={columns}
|
258 |
+
dataSource={data}
|
259 |
+
loading={loading}
|
260 |
+
pagination={false}
|
261 |
+
scroll={{ scrollToFirstRowOnChange: true, x: true }}
|
262 |
+
/>
|
263 |
+
<CreateEPModal getKfList={getKfList} kb_id={kb_id} />
|
264 |
+
<SegmentSetModal
|
265 |
+
getKfList={getKfList}
|
266 |
+
parser_id={parser_id}
|
267 |
+
doc_id={doc_id}
|
268 |
+
/>
|
269 |
</>
|
270 |
+
);
|
271 |
};
|
272 |
|
273 |
+
export default KnowledgeFile;
|
web/src/pages/add-knowledge/components/knowledge-file/model.ts
CHANGED
@@ -1,57 +1,47 @@
|
|
1 |
import kbService from '@/services/kbService';
|
2 |
import { message } from 'antd';
|
3 |
-
import
|
|
|
4 |
|
5 |
-
export interface
|
6 |
isShowCEFwModal: boolean;
|
7 |
isShowTntModal: boolean;
|
8 |
isShowSegmentSetModal: boolean;
|
9 |
-
loading: boolean;
|
10 |
tenantIfo: any;
|
11 |
data: any[];
|
12 |
}
|
13 |
-
|
14 |
-
|
15 |
-
state: kFModelState;
|
16 |
-
effects: {
|
17 |
-
createKf: Effect;
|
18 |
-
updateKf: Effect;
|
19 |
-
getKfDetail: Effect;
|
20 |
-
getKfList: Effect;
|
21 |
-
updateDocumentStatus: Effect;
|
22 |
-
document_rm: Effect;
|
23 |
-
document_create: Effect;
|
24 |
-
document_change_parser: Effect;
|
25 |
-
};
|
26 |
-
reducers: {
|
27 |
-
updateState: Reducer<kFModelState>;
|
28 |
-
};
|
29 |
-
subscriptions: { setup: Subscription };
|
30 |
-
}
|
31 |
-
const Model: kFModelType = {
|
32 |
namespace: 'kFModel',
|
33 |
state: {
|
34 |
isShowCEFwModal: false,
|
35 |
isShowTntModal: false,
|
36 |
isShowSegmentSetModal: false,
|
37 |
-
loading: false,
|
38 |
tenantIfo: {},
|
39 |
data: [],
|
40 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
subscriptions: {
|
42 |
setup({ dispatch, history }) {
|
43 |
history.listen((location) => {});
|
44 |
},
|
45 |
},
|
46 |
effects: {
|
47 |
-
*createKf({ payload = {}
|
48 |
const { data, response } = yield call(kbService.createKb, payload);
|
49 |
const { retcode, data: res, retmsg } = data;
|
50 |
if (retcode === 0) {
|
51 |
message.success('创建成功!');
|
52 |
}
|
53 |
},
|
54 |
-
*updateKf({ payload = {}
|
55 |
const { data, response } = yield call(kbService.updateKb, payload);
|
56 |
const { retcode, data: res, retmsg } = data;
|
57 |
if (retcode === 0) {
|
@@ -67,23 +57,12 @@ const Model: kFModelType = {
|
|
67 |
}
|
68 |
},
|
69 |
*getKfList({ payload = {} }, { call, put }) {
|
70 |
-
yield put({
|
71 |
-
type: 'updateState',
|
72 |
-
payload: {
|
73 |
-
loading: true,
|
74 |
-
},
|
75 |
-
});
|
76 |
const { data, response } = yield call(
|
77 |
kbService.get_document_list,
|
78 |
payload,
|
79 |
);
|
80 |
const { retcode, data: res, retmsg } = data;
|
81 |
-
|
82 |
-
type: 'updateState',
|
83 |
-
payload: {
|
84 |
-
loading: false,
|
85 |
-
},
|
86 |
-
});
|
87 |
if (retcode === 0) {
|
88 |
yield put({
|
89 |
type: 'updateState',
|
@@ -93,64 +72,64 @@ const Model: kFModelType = {
|
|
93 |
});
|
94 |
}
|
95 |
},
|
96 |
-
*updateDocumentStatus({ payload = {}
|
97 |
-
yield put({
|
98 |
-
type: 'updateState',
|
99 |
-
payload: {
|
100 |
-
loading: true,
|
101 |
-
},
|
102 |
-
});
|
103 |
const { data, response } = yield call(
|
104 |
kbService.document_change_status,
|
105 |
-
payload,
|
106 |
);
|
107 |
const { retcode, data: res, retmsg } = data;
|
108 |
if (retcode === 0) {
|
109 |
message.success('修改成功!');
|
110 |
-
|
111 |
-
type: '
|
112 |
-
payload: {
|
113 |
-
loading: false,
|
114 |
-
},
|
115 |
});
|
116 |
-
callback && callback();
|
117 |
}
|
118 |
},
|
119 |
-
*document_rm({ payload = {}
|
120 |
-
const { data, response } = yield call(kbService.document_rm,
|
|
|
|
|
121 |
const { retcode, data: res, retmsg } = data;
|
122 |
if (retcode === 0) {
|
123 |
message.success('删除成功!');
|
124 |
-
|
|
|
|
|
|
|
125 |
}
|
126 |
},
|
127 |
-
*document_create({ payload = {}
|
128 |
const { data, response } = yield call(kbService.document_create, payload);
|
129 |
const { retcode, data: res, retmsg } = data;
|
130 |
if (retcode === 0) {
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
message.success('创建成功!');
|
132 |
-
callback && callback();
|
133 |
}
|
|
|
134 |
},
|
135 |
-
*document_change_parser({ payload = {}
|
136 |
const { data, response } = yield call(
|
137 |
kbService.document_change_parser,
|
138 |
payload,
|
139 |
);
|
140 |
const { retcode, data: res, retmsg } = data;
|
141 |
if (retcode === 0) {
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
message.success('修改成功!');
|
143 |
-
callback && callback();
|
144 |
}
|
145 |
-
|
146 |
-
},
|
147 |
-
reducers: {
|
148 |
-
updateState(state, { payload }) {
|
149 |
-
return {
|
150 |
-
...state,
|
151 |
-
...payload,
|
152 |
-
};
|
153 |
},
|
154 |
},
|
155 |
};
|
156 |
-
export default
|
|
|
1 |
import kbService from '@/services/kbService';
|
2 |
import { message } from 'antd';
|
3 |
+
import pick from 'lodash/pick';
|
4 |
+
import { DvaModel } from 'umi';
|
5 |
|
6 |
+
export interface KFModelState {
|
7 |
isShowCEFwModal: boolean;
|
8 |
isShowTntModal: boolean;
|
9 |
isShowSegmentSetModal: boolean;
|
|
|
10 |
tenantIfo: any;
|
11 |
data: any[];
|
12 |
}
|
13 |
+
|
14 |
+
const model: DvaModel<KFModelState> = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
namespace: 'kFModel',
|
16 |
state: {
|
17 |
isShowCEFwModal: false,
|
18 |
isShowTntModal: false,
|
19 |
isShowSegmentSetModal: false,
|
|
|
20 |
tenantIfo: {},
|
21 |
data: [],
|
22 |
},
|
23 |
+
reducers: {
|
24 |
+
updateState(state, { payload }) {
|
25 |
+
return {
|
26 |
+
...state,
|
27 |
+
...payload,
|
28 |
+
};
|
29 |
+
},
|
30 |
+
},
|
31 |
subscriptions: {
|
32 |
setup({ dispatch, history }) {
|
33 |
history.listen((location) => {});
|
34 |
},
|
35 |
},
|
36 |
effects: {
|
37 |
+
*createKf({ payload = {} }, { call, put }) {
|
38 |
const { data, response } = yield call(kbService.createKb, payload);
|
39 |
const { retcode, data: res, retmsg } = data;
|
40 |
if (retcode === 0) {
|
41 |
message.success('创建成功!');
|
42 |
}
|
43 |
},
|
44 |
+
*updateKf({ payload = {} }, { call, put }) {
|
45 |
const { data, response } = yield call(kbService.updateKb, payload);
|
46 |
const { retcode, data: res, retmsg } = data;
|
47 |
if (retcode === 0) {
|
|
|
57 |
}
|
58 |
},
|
59 |
*getKfList({ payload = {} }, { call, put }) {
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
const { data, response } = yield call(
|
61 |
kbService.get_document_list,
|
62 |
payload,
|
63 |
);
|
64 |
const { retcode, data: res, retmsg } = data;
|
65 |
+
|
|
|
|
|
|
|
|
|
|
|
66 |
if (retcode === 0) {
|
67 |
yield put({
|
68 |
type: 'updateState',
|
|
|
72 |
});
|
73 |
}
|
74 |
},
|
75 |
+
*updateDocumentStatus({ payload = {} }, { call, put }) {
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
const { data, response } = yield call(
|
77 |
kbService.document_change_status,
|
78 |
+
pick(payload, ['doc_id', 'status']),
|
79 |
);
|
80 |
const { retcode, data: res, retmsg } = data;
|
81 |
if (retcode === 0) {
|
82 |
message.success('修改成功!');
|
83 |
+
put({
|
84 |
+
type: 'getKfList',
|
85 |
+
payload: { kb_id: payload.kb_id },
|
|
|
|
|
86 |
});
|
|
|
87 |
}
|
88 |
},
|
89 |
+
*document_rm({ payload = {} }, { call, put }) {
|
90 |
+
const { data, response } = yield call(kbService.document_rm, {
|
91 |
+
doc_id: payload.doc_id,
|
92 |
+
});
|
93 |
const { retcode, data: res, retmsg } = data;
|
94 |
if (retcode === 0) {
|
95 |
message.success('删除成功!');
|
96 |
+
put({
|
97 |
+
type: 'getKfList',
|
98 |
+
payload: { kb_id: payload.kb_id },
|
99 |
+
});
|
100 |
}
|
101 |
},
|
102 |
+
*document_create({ payload = {} }, { call, put }) {
|
103 |
const { data, response } = yield call(kbService.document_create, payload);
|
104 |
const { retcode, data: res, retmsg } = data;
|
105 |
if (retcode === 0) {
|
106 |
+
put({
|
107 |
+
type: 'kFModel/updateState',
|
108 |
+
payload: {
|
109 |
+
isShowCEFwModal: false,
|
110 |
+
},
|
111 |
+
});
|
112 |
message.success('创建成功!');
|
|
|
113 |
}
|
114 |
+
return retcode;
|
115 |
},
|
116 |
+
*document_change_parser({ payload = {} }, { call, put }) {
|
117 |
const { data, response } = yield call(
|
118 |
kbService.document_change_parser,
|
119 |
payload,
|
120 |
);
|
121 |
const { retcode, data: res, retmsg } = data;
|
122 |
if (retcode === 0) {
|
123 |
+
put({
|
124 |
+
type: 'updateState',
|
125 |
+
payload: {
|
126 |
+
isShowSegmentSetModal: false,
|
127 |
+
},
|
128 |
+
});
|
129 |
message.success('修改成功!');
|
|
|
130 |
}
|
131 |
+
return retcode;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
},
|
133 |
},
|
134 |
};
|
135 |
+
export default model;
|
web/src/pages/add-knowledge/components/knowledge-file/segmentSetModal.tsx
CHANGED
@@ -1,91 +1,87 @@
|
|
1 |
-
import
|
2 |
-
import {
|
3 |
-
import
|
4 |
-
import {
|
5 |
-
import { Modal, Tag, Space } from 'antd'
|
6 |
-
import { useEffect, useState } from 'react';
|
7 |
import styles from './index.less';
|
8 |
-
import type { kFModelState } from './model'
|
9 |
-
import type { settingModelState } from '@/pages/setting/model'
|
10 |
const { CheckableTag } = Tag;
|
11 |
interface kFProps {
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
getKfList: () => void;
|
16 |
-
parser_id: string;
|
17 |
-
doc_id: string;
|
18 |
}
|
19 |
-
const
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
const { t } = useTranslation()
|
33 |
-
const handleCancel = () => {
|
34 |
-
dispatch({
|
35 |
-
type: 'kFModel/updateState',
|
36 |
-
payload: {
|
37 |
-
isShowSegmentSetModal: false
|
38 |
-
}
|
39 |
-
});
|
40 |
-
};
|
41 |
-
const handleOk = () => {
|
42 |
-
console.log(1111, selectedTag)
|
43 |
-
dispatch({
|
44 |
-
type: 'kFModel/document_change_parser',
|
45 |
-
payload: {
|
46 |
-
parser_id: selectedTag,
|
47 |
-
doc_id
|
48 |
-
},
|
49 |
-
callback: () => {
|
50 |
-
dispatch({
|
51 |
-
type: 'kFModel/updateState',
|
52 |
-
payload: {
|
53 |
-
isShowSegmentSetModal: false
|
54 |
-
}
|
55 |
-
});
|
56 |
-
getKfList && getKfList()
|
57 |
-
}
|
58 |
-
});
|
59 |
-
};
|
60 |
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
checked={selectedTag === tag}
|
78 |
-
onChange={(checked) => handleChange(tag, checked)}
|
79 |
-
>
|
80 |
-
{tag}
|
81 |
-
</CheckableTag>)
|
82 |
-
})
|
83 |
-
}
|
84 |
-
</div>
|
85 |
-
</Space>
|
86 |
-
</Modal >
|
87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
|
89 |
-
);
|
90 |
-
}
|
91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Modal, Space, Tag } from 'antd';
|
2 |
+
import React, { useEffect, useState } from 'react';
|
3 |
+
import { useTranslation } from 'react-i18next';
|
4 |
+
import { useDispatch, useSelector } from 'umi';
|
|
|
|
|
5 |
import styles from './index.less';
|
|
|
|
|
6 |
const { CheckableTag } = Tag;
|
7 |
interface kFProps {
|
8 |
+
getKfList: () => void;
|
9 |
+
parser_id: string;
|
10 |
+
doc_id: string;
|
|
|
|
|
|
|
11 |
}
|
12 |
+
const SegmentSetModal: React.FC<kFProps> = ({
|
13 |
+
getKfList,
|
14 |
+
parser_id,
|
15 |
+
doc_id,
|
16 |
+
}) => {
|
17 |
+
const dispatch = useDispatch();
|
18 |
+
const kFModel = useSelector((state: any) => state.kFModel);
|
19 |
+
const settingModel = useSelector((state: any) => state.settingModel);
|
20 |
+
const [selectedTag, setSelectedTag] = useState('');
|
21 |
+
const { tenantIfo = {} } = settingModel;
|
22 |
+
const { parser_ids = '' } = tenantIfo;
|
23 |
+
const { isShowSegmentSetModal } = kFModel;
|
24 |
+
const { t } = useTranslation();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
+
useEffect(() => {
|
27 |
+
dispatch({
|
28 |
+
type: 'settingModel/getTenantInfo',
|
29 |
+
payload: {},
|
30 |
+
});
|
31 |
+
setSelectedTag(parser_id);
|
32 |
+
}, [parser_id]);
|
33 |
|
34 |
+
const handleCancel = () => {
|
35 |
+
dispatch({
|
36 |
+
type: 'kFModel/updateState',
|
37 |
+
payload: {
|
38 |
+
isShowSegmentSetModal: false,
|
39 |
+
},
|
40 |
+
});
|
41 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
+
const handleOk = async () => {
|
44 |
+
console.log(1111, selectedTag);
|
45 |
+
const retcode = await dispatch<any>({
|
46 |
+
type: 'kFModel/document_change_parser',
|
47 |
+
payload: {
|
48 |
+
parser_id: selectedTag,
|
49 |
+
doc_id,
|
50 |
+
},
|
51 |
+
});
|
52 |
|
53 |
+
retcode === 0 && getKfList && getKfList();
|
54 |
+
};
|
55 |
+
|
56 |
+
const handleChange = (tag: string, checked: boolean) => {
|
57 |
+
const nextSelectedTag = checked ? tag : selectedTag;
|
58 |
+
console.log('You are interested in: ', nextSelectedTag);
|
59 |
+
setSelectedTag(nextSelectedTag);
|
60 |
+
};
|
61 |
+
|
62 |
+
return (
|
63 |
+
<Modal
|
64 |
+
title="Basic Modal"
|
65 |
+
open={isShowSegmentSetModal}
|
66 |
+
onOk={handleOk}
|
67 |
+
onCancel={handleCancel}
|
68 |
+
>
|
69 |
+
<Space size={[0, 8]} wrap>
|
70 |
+
<div className={styles.tags}>
|
71 |
+
{parser_ids.split(',').map((tag: string) => {
|
72 |
+
return (
|
73 |
+
<CheckableTag
|
74 |
+
key={tag}
|
75 |
+
checked={selectedTag === tag}
|
76 |
+
onChange={(checked) => handleChange(tag, checked)}
|
77 |
+
>
|
78 |
+
{tag}
|
79 |
+
</CheckableTag>
|
80 |
+
);
|
81 |
+
})}
|
82 |
+
</div>
|
83 |
+
</Space>
|
84 |
+
</Modal>
|
85 |
+
);
|
86 |
+
};
|
87 |
+
export default SegmentSetModal;
|
web/src/pages/add-knowledge/components/knowledge-file/upload.tsx
CHANGED
@@ -1,33 +1,39 @@
|
|
1 |
-
import
|
2 |
-
import { connect } from 'umi'
|
3 |
import type { UploadProps } from 'antd';
|
4 |
import { Button, Upload } from 'antd';
|
5 |
-
import
|
6 |
interface PropsType {
|
7 |
-
|
8 |
-
|
9 |
}
|
|
|
10 |
type UploadRequestOption = Parameters<
|
11 |
-
|
12 |
>[0];
|
13 |
-
const Index: React.FC<PropsType> = ({ kb_id, getKfList }) => {
|
14 |
-
const createRequest: (props: UploadRequestOption) => void = async function ({ file, onSuccess, onError }) {
|
15 |
-
const { retcode, data } = await uploadService.uploadFile(file, kb_id);
|
16 |
-
if (retcode === 0) {
|
17 |
-
onSuccess && onSuccess(data, file);
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
-
export default
|
|
|
1 |
+
import uploadService from '@/services/uploadService';
|
|
|
2 |
import type { UploadProps } from 'antd';
|
3 |
import { Button, Upload } from 'antd';
|
4 |
+
import React from 'react';
|
5 |
interface PropsType {
|
6 |
+
kb_id: string;
|
7 |
+
getKfList: () => void;
|
8 |
}
|
9 |
+
|
10 |
type UploadRequestOption = Parameters<
|
11 |
+
NonNullable<UploadProps['customRequest']>
|
12 |
>[0];
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
+
const FileUpload: React.FC<PropsType> = ({ kb_id, getKfList }) => {
|
15 |
+
const createRequest: (props: UploadRequestOption) => void = async function ({
|
16 |
+
file,
|
17 |
+
onSuccess,
|
18 |
+
onError,
|
19 |
+
}) {
|
20 |
+
const { retcode, data } = await uploadService.uploadFile(file, kb_id);
|
21 |
+
if (retcode === 0) {
|
22 |
+
onSuccess && onSuccess(data, file);
|
23 |
+
} else {
|
24 |
+
onError && onError(data);
|
25 |
+
}
|
26 |
+
getKfList && getKfList();
|
27 |
+
};
|
28 |
+
const uploadProps: UploadProps = {
|
29 |
+
customRequest: createRequest,
|
30 |
+
showUploadList: false,
|
31 |
+
};
|
32 |
+
return (
|
33 |
+
<Upload {...uploadProps}>
|
34 |
+
<Button type="link">导入文件</Button>
|
35 |
+
</Upload>
|
36 |
+
);
|
37 |
+
};
|
38 |
|
39 |
+
export default FileUpload;
|
web/src/pages/add-knowledge/components/knowledge-search/index.tsx
CHANGED
@@ -1,247 +1,278 @@
|
|
1 |
-
import
|
2 |
-
import {
|
3 |
-
import { Card, Row, Col, Input, Select, Switch, Pagination, Spin, Button, Popconfirm } from 'antd';
|
4 |
-
import { MinusSquareOutlined, DeleteOutlined, } from '@ant-design/icons';
|
5 |
import type { PaginationProps } from 'antd';
|
6 |
-
import {
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
-
|
10 |
-
import styles from './index.less'
|
11 |
import { debounce } from 'lodash';
|
12 |
-
import
|
13 |
-
import type { chunkModelState } from '../knowledge-chunk/model'
|
14 |
interface chunkProps {
|
15 |
-
|
16 |
-
kSearchModel: kSearchModelState;
|
17 |
-
chunkModel: chunkModelState;
|
18 |
-
kb_id: string
|
19 |
}
|
20 |
-
const Index: React.FC<chunkProps> = ({ kSearchModel, chunkModel, dispatch, kb_id }) => {
|
21 |
|
22 |
-
|
23 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
const getChunkList = () => {
|
25 |
-
dispatch({
|
26 |
-
type: 'kSearchModel/updateState',
|
27 |
-
payload: {
|
28 |
-
loading: true
|
29 |
-
}
|
30 |
-
});
|
31 |
-
interface payloadType {
|
32 |
-
kb_id: string;
|
33 |
-
question?: string;
|
34 |
-
doc_ids: any[];
|
35 |
-
similarity_threshold?: number
|
36 |
-
}
|
37 |
-
const payload: payloadType = {
|
38 |
-
kb_id,
|
39 |
-
question,
|
40 |
-
doc_ids,
|
41 |
-
similarity_threshold: 0.1
|
42 |
-
}
|
43 |
dispatch({
|
44 |
type: 'kSearchModel/chunk_list',
|
45 |
payload: {
|
46 |
-
|
47 |
-
|
48 |
-
}
|
49 |
});
|
50 |
-
}
|
51 |
const confirm = (id: string) => {
|
52 |
-
console.log(id)
|
53 |
dispatch({
|
54 |
type: 'kSearchModel/rm_chunk',
|
55 |
payload: {
|
56 |
-
chunk_ids: [id]
|
|
|
57 |
},
|
58 |
-
callback: getChunkList
|
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 |
-
callback: getChunkList
|
71 |
});
|
72 |
-
|
73 |
-
|
|
|
|
|
|
|
|
|
74 |
dispatch({
|
75 |
type: 'kSearchModel/updateState',
|
76 |
payload: {
|
77 |
-
pagination: { page, size }
|
78 |
-
}
|
79 |
});
|
80 |
};
|
81 |
useEffect(() => {
|
82 |
dispatch({
|
83 |
type: 'kSearchModel/updateState',
|
84 |
payload: {
|
85 |
-
loading: false,
|
86 |
doc_ids: [],
|
87 |
-
question:
|
88 |
-
}
|
89 |
});
|
90 |
dispatch({
|
91 |
type: 'kSearchModel/getKfList',
|
92 |
payload: {
|
93 |
-
kb_id
|
94 |
-
}
|
95 |
-
|
96 |
});
|
97 |
-
}, [])
|
98 |
const switchChunk = (item: any, available_int: boolean) => {
|
99 |
-
const { chunk_id, doc_id } = item
|
100 |
-
|
101 |
-
type: 'kSearchModel/updateState',
|
102 |
-
payload: {
|
103 |
-
loading: true
|
104 |
-
}
|
105 |
-
});
|
106 |
dispatch({
|
107 |
type: 'kSearchModel/switch_chunk',
|
108 |
payload: {
|
109 |
chunk_ids: [chunk_id],
|
110 |
doc_id,
|
111 |
-
available_int
|
|
|
112 |
},
|
113 |
-
callback: getChunkList
|
114 |
});
|
115 |
-
}
|
116 |
-
|
117 |
|
118 |
useEffect(() => {
|
119 |
-
getChunkList()
|
120 |
-
}, [doc_ids, pagination, question])
|
121 |
const debounceChange = debounce((value) => {
|
122 |
dispatch({
|
123 |
type: 'kSearchModel/updateState',
|
124 |
payload: {
|
125 |
-
question: value
|
126 |
-
}
|
127 |
});
|
128 |
-
}, 300)
|
129 |
-
|
130 |
-
const
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
const
|
135 |
-
|
|
|
|
|
|
|
|
|
|
|
136 |
dispatch({
|
137 |
type: 'kSearchModel/updateState',
|
138 |
payload: {
|
139 |
-
doc_ids: value
|
140 |
-
}
|
141 |
});
|
142 |
-
}
|
143 |
-
console.log('loading', loading)
|
144 |
-
return (<>
|
145 |
-
<div className={styles.chunkPage}>
|
146 |
-
<div className={styles.filter}>
|
147 |
-
<Select
|
148 |
-
showSearch
|
149 |
-
placeholder="文件列表"
|
150 |
-
optionFilterProp="children"
|
151 |
-
onChange={handleSelectChange}
|
152 |
-
style={{ width: 300, marginBottom: 20 }}
|
153 |
-
options={d_list}
|
154 |
-
fieldNames={{ label: 'name', value: 'id' }}
|
155 |
-
mode='multiple'
|
156 |
-
/>
|
157 |
|
158 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
170 |
>
|
171 |
-
<
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
</div>
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
}}
|
205 |
-
okText="Yes"
|
206 |
-
cancelText="No"
|
207 |
-
>
|
208 |
-
<DeleteOutlined onClick={(e) => {
|
209 |
-
e.stopPropagation();
|
210 |
-
e.nativeEvent.stopImmediatePropagation()
|
211 |
-
}} />
|
212 |
-
</Popconfirm>
|
213 |
-
|
214 |
-
</span>
|
215 |
-
</div>
|
216 |
-
|
217 |
-
</div>
|
218 |
-
</Card>
|
219 |
-
</Col>)
|
220 |
-
})
|
221 |
-
}
|
222 |
-
</Row>
|
223 |
-
</Spin>
|
224 |
-
|
225 |
-
</div>
|
226 |
-
<div className={styles.pageFooter}>
|
227 |
-
<Pagination
|
228 |
-
responsive
|
229 |
-
showLessItems
|
230 |
-
showQuickJumper
|
231 |
-
showSizeChanger
|
232 |
-
onChange={onShowSizeChange}
|
233 |
-
defaultPageSize={30}
|
234 |
-
pageSizeOptions={[30, 60, 90]}
|
235 |
-
defaultCurrent={pagination.page}
|
236 |
-
total={total}
|
237 |
-
/>
|
238 |
</div>
|
239 |
</div>
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
|
|
|
|
|
|
245 |
};
|
246 |
|
247 |
-
export default
|
|
|
1 |
+
import { api_host } from '@/utils/api';
|
2 |
+
import { DeleteOutlined, MinusSquareOutlined } from '@ant-design/icons';
|
|
|
|
|
3 |
import type { PaginationProps } from 'antd';
|
4 |
+
import {
|
5 |
+
Card,
|
6 |
+
Col,
|
7 |
+
Input,
|
8 |
+
Pagination,
|
9 |
+
Popconfirm,
|
10 |
+
Row,
|
11 |
+
Select,
|
12 |
+
Spin,
|
13 |
+
Switch,
|
14 |
+
} from 'antd';
|
15 |
+
import React, { useCallback, useEffect } from 'react';
|
16 |
+
import { useDispatch, useSelector } from 'umi';
|
17 |
+
import CreateModal from '../knowledge-chunk/components/createModal';
|
18 |
|
19 |
+
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
|
|
20 |
import { debounce } from 'lodash';
|
21 |
+
import styles from './index.less';
|
|
|
22 |
interface chunkProps {
|
23 |
+
kb_id: string;
|
|
|
|
|
|
|
24 |
}
|
|
|
25 |
|
26 |
+
const KnowledgeSearching: React.FC<chunkProps> = ({ kb_id }) => {
|
27 |
+
const dispatch = useDispatch();
|
28 |
+
const kSearchModel = useSelector((state: any) => state.kSearchModel);
|
29 |
+
const chunkModel = useSelector((state: any) => state.chunkModel);
|
30 |
+
const loading = useOneNamespaceEffectsLoading('kSearchModel', [
|
31 |
+
'chunk_list',
|
32 |
+
'switch_chunk',
|
33 |
+
]);
|
34 |
+
|
35 |
+
const {
|
36 |
+
data = [],
|
37 |
+
total,
|
38 |
+
d_list = [],
|
39 |
+
question,
|
40 |
+
doc_ids,
|
41 |
+
pagination,
|
42 |
+
} = kSearchModel;
|
43 |
+
const { chunk_id, doc_id, isShowCreateModal } = chunkModel;
|
44 |
+
|
45 |
const getChunkList = () => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
dispatch({
|
47 |
type: 'kSearchModel/chunk_list',
|
48 |
payload: {
|
49 |
+
kb_id,
|
50 |
+
},
|
|
|
51 |
});
|
52 |
+
};
|
53 |
const confirm = (id: string) => {
|
|
|
54 |
dispatch({
|
55 |
type: 'kSearchModel/rm_chunk',
|
56 |
payload: {
|
57 |
+
chunk_ids: [id],
|
58 |
+
kb_id,
|
59 |
},
|
|
|
60 |
});
|
61 |
};
|
62 |
const handleEditchunk = (item: any) => {
|
63 |
+
const { chunk_id, doc_id } = item;
|
64 |
dispatch({
|
65 |
type: 'chunkModel/updateState',
|
66 |
payload: {
|
67 |
isShowCreateModal: true,
|
68 |
chunk_id,
|
69 |
+
doc_id,
|
70 |
},
|
|
|
71 |
});
|
72 |
+
getChunkList();
|
73 |
+
};
|
74 |
+
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (
|
75 |
+
page,
|
76 |
+
size,
|
77 |
+
) => {
|
78 |
dispatch({
|
79 |
type: 'kSearchModel/updateState',
|
80 |
payload: {
|
81 |
+
pagination: { page, size },
|
82 |
+
},
|
83 |
});
|
84 |
};
|
85 |
useEffect(() => {
|
86 |
dispatch({
|
87 |
type: 'kSearchModel/updateState',
|
88 |
payload: {
|
|
|
89 |
doc_ids: [],
|
90 |
+
question: '',
|
91 |
+
},
|
92 |
});
|
93 |
dispatch({
|
94 |
type: 'kSearchModel/getKfList',
|
95 |
payload: {
|
96 |
+
kb_id,
|
97 |
+
},
|
|
|
98 |
});
|
99 |
+
}, []);
|
100 |
const switchChunk = (item: any, available_int: boolean) => {
|
101 |
+
const { chunk_id, doc_id } = item;
|
102 |
+
|
|
|
|
|
|
|
|
|
|
|
103 |
dispatch({
|
104 |
type: 'kSearchModel/switch_chunk',
|
105 |
payload: {
|
106 |
chunk_ids: [chunk_id],
|
107 |
doc_id,
|
108 |
+
available_int,
|
109 |
+
kb_id,
|
110 |
},
|
|
|
111 |
});
|
112 |
+
};
|
|
|
113 |
|
114 |
useEffect(() => {
|
115 |
+
getChunkList();
|
116 |
+
}, [doc_ids, pagination, question]);
|
117 |
const debounceChange = debounce((value) => {
|
118 |
dispatch({
|
119 |
type: 'kSearchModel/updateState',
|
120 |
payload: {
|
121 |
+
question: value,
|
122 |
+
},
|
123 |
});
|
124 |
+
}, 300);
|
125 |
+
|
126 |
+
const debounceCallback = useCallback(
|
127 |
+
(value: string) => debounceChange(value),
|
128 |
+
[],
|
129 |
+
);
|
130 |
+
const handleInputChange = (
|
131 |
+
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
132 |
+
) => {
|
133 |
+
const value = e.target.value;
|
134 |
+
debounceCallback(value);
|
135 |
+
};
|
136 |
+
const handleSelectChange = (value: any[]) => {
|
137 |
dispatch({
|
138 |
type: 'kSearchModel/updateState',
|
139 |
payload: {
|
140 |
+
doc_ids: value,
|
141 |
+
},
|
142 |
});
|
143 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
|
145 |
+
return (
|
146 |
+
<>
|
147 |
+
<div className={styles.chunkPage}>
|
148 |
+
<div className={styles.filter}>
|
149 |
+
<Select
|
150 |
+
showSearch
|
151 |
+
placeholder="文件列表"
|
152 |
+
optionFilterProp="children"
|
153 |
+
onChange={handleSelectChange}
|
154 |
+
style={{ width: 300, marginBottom: 20 }}
|
155 |
+
options={d_list}
|
156 |
+
fieldNames={{ label: 'name', value: 'id' }}
|
157 |
+
mode="multiple"
|
158 |
+
/>
|
159 |
|
160 |
+
<Input.TextArea
|
161 |
+
autoSize={{ minRows: 6, maxRows: 6 }}
|
162 |
+
placeholder="搜索"
|
163 |
+
style={{ width: 300 }}
|
164 |
+
allowClear
|
165 |
+
onChange={handleInputChange}
|
166 |
+
/>
|
167 |
+
</div>
|
168 |
+
<div className={styles.pageContainer}>
|
169 |
+
<div className={styles.pageContent}>
|
170 |
+
<Spin spinning={loading} className={styles.spin} size="large">
|
171 |
+
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24 }}>
|
172 |
+
{data.map((item: any) => {
|
173 |
+
return (
|
174 |
+
<Col
|
175 |
+
className="gutter-row"
|
176 |
+
key={item.chunk_id}
|
177 |
+
xs={24}
|
178 |
+
sm={12}
|
179 |
+
md={12}
|
180 |
+
lg={8}
|
181 |
>
|
182 |
+
<Card
|
183 |
+
className={styles.card}
|
184 |
+
onClick={() => {
|
185 |
+
handleEditchunk(item);
|
186 |
+
}}
|
187 |
+
>
|
188 |
+
<img
|
189 |
+
style={{ width: '50px' }}
|
190 |
+
src={`${api_host}/document/image/${item.img_id}`}
|
191 |
+
alt=""
|
192 |
+
/>
|
193 |
+
<div className={styles.container}>
|
194 |
+
<div className={styles.content}>
|
195 |
+
<span className={styles.context}>
|
196 |
+
{item.content_ltks}
|
197 |
+
</span>
|
198 |
+
<span className={styles.delete}>
|
199 |
+
<Switch
|
200 |
+
size="small"
|
201 |
+
defaultValue={item.doc_ids == '1'}
|
202 |
+
onChange={(checked: boolean, e: any) => {
|
203 |
+
e.stopPropagation();
|
204 |
+
e.nativeEvent.stopImmediatePropagation();
|
205 |
+
switchChunk(item, checked);
|
206 |
+
}}
|
207 |
+
/>
|
208 |
+
</span>
|
209 |
+
</div>
|
210 |
+
<div className={styles.footer}>
|
211 |
+
<span className={styles.text}>
|
212 |
+
<MinusSquareOutlined />
|
213 |
+
{item.doc_num}文档
|
214 |
+
</span>
|
215 |
+
<span className={styles.text}>
|
216 |
+
<MinusSquareOutlined />
|
217 |
+
{item.chunk_num}个
|
218 |
+
</span>
|
219 |
+
<span className={styles.text}>
|
220 |
+
<MinusSquareOutlined />
|
221 |
+
{item.token_num}千字符
|
222 |
+
</span>
|
223 |
+
<span style={{ float: 'right' }}>
|
224 |
+
<Popconfirm
|
225 |
+
title="Delete the task"
|
226 |
+
description="Are you sure to delete this task?"
|
227 |
+
onConfirm={(e: any) => {
|
228 |
+
e.stopPropagation();
|
229 |
+
e.nativeEvent.stopImmediatePropagation();
|
230 |
+
console.log(confirm);
|
231 |
+
confirm(item.chunk_id);
|
232 |
+
}}
|
233 |
+
okText="Yes"
|
234 |
+
cancelText="No"
|
235 |
+
>
|
236 |
+
<DeleteOutlined
|
237 |
+
onClick={(e) => {
|
238 |
+
e.stopPropagation();
|
239 |
+
e.nativeEvent.stopImmediatePropagation();
|
240 |
+
}}
|
241 |
+
/>
|
242 |
+
</Popconfirm>
|
243 |
+
</span>
|
244 |
+
</div>
|
245 |
</div>
|
246 |
+
</Card>
|
247 |
+
</Col>
|
248 |
+
);
|
249 |
+
})}
|
250 |
+
</Row>
|
251 |
+
</Spin>
|
252 |
+
</div>
|
253 |
+
<div className={styles.pageFooter}>
|
254 |
+
<Pagination
|
255 |
+
responsive
|
256 |
+
showLessItems
|
257 |
+
showQuickJumper
|
258 |
+
showSizeChanger
|
259 |
+
onChange={onShowSizeChange}
|
260 |
+
defaultPageSize={30}
|
261 |
+
pageSizeOptions={[30, 60, 90]}
|
262 |
+
defaultCurrent={pagination.page}
|
263 |
+
total={total}
|
264 |
+
/>
|
265 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
266 |
</div>
|
267 |
</div>
|
268 |
+
<CreateModal
|
269 |
+
getChunkList={getChunkList}
|
270 |
+
isShowCreateModal={isShowCreateModal}
|
271 |
+
chunk_id={chunk_id}
|
272 |
+
doc_id={doc_id}
|
273 |
+
/>
|
274 |
+
</>
|
275 |
+
);
|
276 |
};
|
277 |
|
278 |
+
export default KnowledgeSearching;
|
web/src/pages/add-knowledge/components/knowledge-search/model.ts
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
import { Effect, Reducer, Subscription } from 'umi'
|
2 |
-
import { message } from 'antd';
|
3 |
import kbService from '@/services/kbService';
|
|
|
|
|
4 |
|
5 |
-
export interface
|
6 |
loading: boolean;
|
7 |
data: any[];
|
8 |
total: number;
|
@@ -13,26 +13,10 @@ export interface kSearchModelState {
|
|
13 |
question: string;
|
14 |
doc_ids: any[];
|
15 |
pagination: any;
|
16 |
-
doc_id: string
|
17 |
-
|
18 |
-
}
|
19 |
-
export interface chunkgModelType {
|
20 |
-
namespace: 'kSearchModel';
|
21 |
-
state: kSearchModelState;
|
22 |
-
effects: {
|
23 |
-
chunk_list: Effect;
|
24 |
-
get_chunk: Effect;
|
25 |
-
create_hunk: Effect;
|
26 |
-
switch_chunk: Effect;
|
27 |
-
rm_chunk: Effect;
|
28 |
-
getKfList: Effect;
|
29 |
-
};
|
30 |
-
reducers: {
|
31 |
-
updateState: Reducer<kSearchModelState>;
|
32 |
-
};
|
33 |
-
subscriptions: { setup: Subscription };
|
34 |
}
|
35 |
-
|
|
|
36 |
namespace: 'kSearchModel',
|
37 |
state: {
|
38 |
loading: false,
|
@@ -45,114 +29,132 @@ const Model: chunkgModelType = {
|
|
45 |
question: '',
|
46 |
doc_ids: [],
|
47 |
pagination: { page: 1, size: 30 },
|
48 |
-
doc_id: ''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
},
|
50 |
subscriptions: {
|
51 |
setup({ dispatch, history }) {
|
52 |
-
history.listen(location => {
|
53 |
-
console.log(location)
|
54 |
});
|
55 |
-
}
|
56 |
},
|
57 |
effects: {
|
58 |
*getKfList({ payload = {} }, { call, put }) {
|
59 |
-
const { data, response } = yield call(
|
|
|
|
|
|
|
60 |
|
61 |
-
const { retcode, data: res, retmsg } = data
|
62 |
if (retcode === 0) {
|
63 |
yield put({
|
64 |
type: 'updateState',
|
65 |
payload: {
|
66 |
-
d_list: res
|
67 |
-
}
|
68 |
});
|
69 |
}
|
70 |
},
|
71 |
-
*
|
72 |
-
const {
|
73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
if (retcode === 0) {
|
75 |
-
console.log(res)
|
76 |
yield put({
|
77 |
type: 'updateState',
|
78 |
payload: {
|
79 |
data: res.chunks,
|
80 |
total: res.total,
|
81 |
-
|
82 |
-
}
|
83 |
});
|
84 |
-
callback && callback()
|
85 |
-
|
86 |
}
|
87 |
},
|
88 |
-
*switch_chunk({ payload = {}
|
89 |
-
const { data
|
90 |
-
|
|
|
|
|
|
|
91 |
if (retcode === 0) {
|
92 |
-
|
93 |
-
|
|
|
|
|
|
|
|
|
94 |
}
|
95 |
},
|
96 |
-
*rm_chunk({ payload = {}
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
100 |
if (retcode === 0) {
|
101 |
-
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
103 |
}
|
104 |
},
|
105 |
-
*
|
106 |
const { data, response } = yield call(kbService.get_chunk, payload);
|
107 |
-
const { retcode, data: res, retmsg } = data
|
108 |
if (retcode === 0) {
|
109 |
-
|
110 |
yield put({
|
111 |
type: 'updateState',
|
112 |
payload: {
|
113 |
-
chunkInfo: res
|
114 |
-
}
|
115 |
});
|
116 |
-
callback && callback(res)
|
117 |
-
|
118 |
}
|
119 |
},
|
120 |
*create_hunk({ payload = {} }, { call, put }) {
|
121 |
yield put({
|
122 |
type: 'updateState',
|
123 |
payload: {
|
124 |
-
loading: true
|
125 |
-
}
|
126 |
});
|
127 |
-
let service = kbService.create_chunk
|
128 |
if (payload.chunk_id) {
|
129 |
-
service = kbService.set_chunk
|
130 |
}
|
131 |
const { data, response } = yield call(service, payload);
|
132 |
-
const { retcode, data: res, retmsg } = data
|
133 |
yield put({
|
134 |
type: 'updateState',
|
135 |
payload: {
|
136 |
-
loading: false
|
137 |
-
}
|
138 |
});
|
139 |
if (retcode === 0) {
|
140 |
yield put({
|
141 |
type: 'updateState',
|
142 |
payload: {
|
143 |
-
isShowCreateModal: false
|
144 |
-
}
|
145 |
});
|
146 |
}
|
147 |
},
|
148 |
},
|
149 |
-
reducers: {
|
150 |
-
updateState(state, { payload }) {
|
151 |
-
return {
|
152 |
-
...state,
|
153 |
-
...payload
|
154 |
-
};
|
155 |
-
}
|
156 |
-
}
|
157 |
};
|
158 |
-
export default
|
|
|
|
|
|
|
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;
|
|
|
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,
|
|
|
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, response } = yield call(service, payload);
|
142 |
+
const { retcode, data: res, retmsg } = 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/index.tsx
CHANGED
@@ -1,170 +1,157 @@
|
|
1 |
-
import
|
2 |
-
import {
|
3 |
-
import {
|
4 |
-
import
|
5 |
-
import type { settingModelState } from '@/pages/setting/model'
|
6 |
-
import styles from './index.less'
|
7 |
const { CheckableTag } = Tag;
|
8 |
const layout = {
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
};
|
13 |
-
const { Option } = Select
|
14 |
/* eslint-disable no-template-curly-in-string */
|
15 |
|
16 |
interface kSProps {
|
17 |
-
|
18 |
-
kSModel: kSModelState;
|
19 |
-
settingModel: settingModelState;
|
20 |
-
kb_id: string
|
21 |
}
|
22 |
-
const
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
|
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
});
|
48 |
-
}
|
49 |
-
|
50 |
-
}, [kb_id])
|
51 |
-
const [selectedTag, setSelectedTag] = useState('')
|
52 |
-
const values = Form.useWatch([], form);
|
53 |
-
console.log(values, '......变化')
|
54 |
-
const onFinish = () => {
|
55 |
-
form.validateFields().then(
|
56 |
-
() => {
|
57 |
-
if (kb_id) {
|
58 |
-
dispatch({
|
59 |
-
type: 'kSModel/updateKb',
|
60 |
-
payload: {
|
61 |
-
...values,
|
62 |
-
parser_id: selectedTag,
|
63 |
-
kb_id,
|
64 |
-
embd_id: undefined
|
65 |
-
}
|
66 |
-
});
|
67 |
-
} else {
|
68 |
-
dispatch({
|
69 |
-
type: 'kSModel/createKb',
|
70 |
-
payload: {
|
71 |
-
...values,
|
72 |
-
parser_id: selectedTag
|
73 |
-
},
|
74 |
-
callback(id: string) {
|
75 |
-
navigate(`/knowledge/add/setting?activeKey=file&id=${kb_id}`);
|
76 |
-
}
|
77 |
-
});
|
78 |
-
}
|
79 |
-
},
|
80 |
-
() => {
|
81 |
-
|
82 |
-
},
|
83 |
-
);
|
84 |
|
|
|
|
|
|
|
85 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
|
87 |
-
|
|
|
|
|
88 |
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
setSelectedTag(nextSelectedTag);
|
95 |
-
};
|
96 |
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
|
|
102 |
>
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
}
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
</Space>
|
149 |
-
<div className={styles.preset}>
|
150 |
-
<div className={styles.left}>
|
151 |
-
xxxxx文章
|
152 |
-
</div>
|
153 |
-
<div className={styles.right}>
|
154 |
-
预估份数
|
155 |
-
</div>
|
156 |
</div>
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
</Form>
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
|
170 |
-
export default
|
|
|
1 |
+
import { Button, Form, Input, Radio, Select, Space, Tag } from 'antd';
|
2 |
+
import React, { useCallback, useEffect, useState } from 'react';
|
3 |
+
import { useDispatch, useNavigate, useSelector } from 'umi';
|
4 |
+
import styles from './index.less';
|
|
|
|
|
5 |
const { CheckableTag } = Tag;
|
6 |
const layout = {
|
7 |
+
labelCol: { span: 8 },
|
8 |
+
wrapperCol: { span: 16 },
|
9 |
+
labelAlign: 'left' as const,
|
10 |
};
|
11 |
+
const { Option } = Select;
|
12 |
/* eslint-disable no-template-curly-in-string */
|
13 |
|
14 |
interface kSProps {
|
15 |
+
kb_id: string;
|
|
|
|
|
|
|
16 |
}
|
17 |
+
const KnowledgeSetting: React.FC<kSProps> = ({ kb_id }) => {
|
18 |
+
const dispatch = useDispatch();
|
19 |
+
const settingModel = useSelector((state: any) => state.settingModel);
|
20 |
+
let navigate = useNavigate();
|
21 |
+
const { tenantIfo = {} } = settingModel;
|
22 |
+
const { parser_ids = '', embd_id = '' } = tenantIfo;
|
23 |
+
const [form] = Form.useForm();
|
24 |
+
const [selectedTag, setSelectedTag] = useState('');
|
25 |
+
const values = Form.useWatch([], form);
|
26 |
|
27 |
+
const getTenantInfo = useCallback(async () => {
|
28 |
+
dispatch({
|
29 |
+
type: 'settingModel/getTenantInfo',
|
30 |
+
payload: {},
|
31 |
+
});
|
32 |
+
if (kb_id) {
|
33 |
+
const data = await dispatch<any>({
|
34 |
+
type: 'kSModel/getKbDetail',
|
35 |
+
payload: {
|
36 |
+
kb_id,
|
37 |
+
},
|
38 |
+
});
|
39 |
+
if (data.retcode === 0) {
|
40 |
+
const { description, name, permission, embd_id } = data.data;
|
41 |
+
form.setFieldsValue({ description, name, permission, embd_id });
|
42 |
+
setSelectedTag(data.data.parser_id);
|
43 |
+
}
|
44 |
+
}
|
45 |
+
}, [kb_id]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
+
const onFinish = async () => {
|
48 |
+
try {
|
49 |
+
await form.validateFields();
|
50 |
|
51 |
+
if (kb_id) {
|
52 |
+
dispatch({
|
53 |
+
type: 'kSModel/updateKb',
|
54 |
+
payload: {
|
55 |
+
...values,
|
56 |
+
parser_id: selectedTag,
|
57 |
+
kb_id,
|
58 |
+
embd_id: undefined,
|
59 |
+
},
|
60 |
+
});
|
61 |
+
} else {
|
62 |
+
const retcode = await dispatch<any>({
|
63 |
+
type: 'kSModel/createKb',
|
64 |
+
payload: {
|
65 |
+
...values,
|
66 |
+
parser_id: selectedTag,
|
67 |
+
},
|
68 |
+
});
|
69 |
+
retcode === 0 &&
|
70 |
+
navigate(`/knowledge/add/setting?activeKey=file&id=${kb_id}`);
|
71 |
+
}
|
72 |
+
} catch (error) {
|
73 |
+
console.warn(error);
|
74 |
+
}
|
75 |
+
};
|
76 |
|
77 |
+
useEffect(() => {
|
78 |
+
getTenantInfo();
|
79 |
+
}, [getTenantInfo]);
|
80 |
|
81 |
+
const handleChange = (tag: string, checked: boolean) => {
|
82 |
+
const nextSelectedTag = checked ? tag : selectedTag;
|
83 |
+
console.log('You are interested in: ', nextSelectedTag);
|
84 |
+
setSelectedTag(nextSelectedTag);
|
85 |
+
};
|
|
|
|
|
86 |
|
87 |
+
return (
|
88 |
+
<Form
|
89 |
+
{...layout}
|
90 |
+
form={form}
|
91 |
+
name="validateOnly"
|
92 |
+
style={{ maxWidth: 1000, padding: 14 }}
|
93 |
>
|
94 |
+
<Form.Item name="name" label="知识库名称" rules={[{ required: true }]}>
|
95 |
+
<Input />
|
96 |
+
</Form.Item>
|
97 |
+
<Form.Item name="description" label="知识库描述">
|
98 |
+
<Input.TextArea />
|
99 |
+
</Form.Item>
|
100 |
+
<Form.Item name="permission" label="可见权限">
|
101 |
+
<Radio.Group>
|
102 |
+
<Radio value="me">只有我</Radio>
|
103 |
+
<Radio value="team">所有团队成员</Radio>
|
104 |
+
</Radio.Group>
|
105 |
+
</Form.Item>
|
106 |
+
<Form.Item
|
107 |
+
name="embd_id"
|
108 |
+
label="Embedding 模型"
|
109 |
+
hasFeedback
|
110 |
+
rules={[{ required: true, message: 'Please select your country!' }]}
|
111 |
+
>
|
112 |
+
<Select placeholder="Please select a country">
|
113 |
+
{embd_id.split(',').map((item: string) => {
|
114 |
+
return (
|
115 |
+
<Option value={item} key={item}>
|
116 |
+
{item}
|
117 |
+
</Option>
|
118 |
+
);
|
119 |
+
})}
|
120 |
+
</Select>
|
121 |
+
</Form.Item>
|
122 |
+
<div style={{ marginTop: '5px' }}>
|
123 |
+
修改Embedding 模型,请去<span style={{ color: '#1677ff' }}>设置</span>
|
124 |
+
</div>
|
125 |
+
<Space size={[0, 8]} wrap>
|
126 |
+
<div className={styles.tags}>
|
127 |
+
{parser_ids.split(',').map((tag: string) => {
|
128 |
+
return (
|
129 |
+
<CheckableTag
|
130 |
+
key={tag}
|
131 |
+
checked={selectedTag === tag}
|
132 |
+
onChange={(checked) => handleChange(tag, checked)}
|
133 |
+
>
|
134 |
+
{tag}
|
135 |
+
</CheckableTag>
|
136 |
+
);
|
137 |
+
})}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
</div>
|
139 |
+
</Space>
|
140 |
+
<Space size={[0, 8]} wrap></Space>
|
141 |
+
<div className={styles.preset}>
|
142 |
+
<div className={styles.left}>xxxxx文章</div>
|
143 |
+
<div className={styles.right}>预估份数</div>
|
144 |
+
</div>
|
145 |
+
<Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 8 }}>
|
146 |
+
<Button type="primary" onClick={onFinish}>
|
147 |
+
保存并处理
|
148 |
+
</Button>
|
149 |
+
<Button htmlType="button" style={{ marginLeft: '20px' }}>
|
150 |
+
取消
|
151 |
+
</Button>
|
152 |
+
</Form.Item>
|
153 |
</Form>
|
154 |
+
);
|
155 |
+
};
|
|
|
156 |
|
157 |
+
export default KnowledgeSetting;
|
web/src/pages/add-knowledge/components/knowledge-setting/model.ts
CHANGED
@@ -1,72 +1,54 @@
|
|
1 |
-
import { message } from 'antd';
|
2 |
-
import { Effect, Reducer, Subscription } from 'umi'
|
3 |
import kbService from '@/services/kbService';
|
|
|
|
|
4 |
|
5 |
-
export interface
|
6 |
isShowPSwModal: boolean;
|
7 |
isShowTntModal: boolean;
|
8 |
-
|
9 |
-
tenantIfo: any
|
10 |
-
}
|
11 |
-
export interface kSModelType {
|
12 |
-
namespace: 'kSModel';
|
13 |
-
state: kSModelState;
|
14 |
-
effects: {
|
15 |
-
createKb: Effect;
|
16 |
-
updateKb: Effect;
|
17 |
-
getKbDetail: Effect;
|
18 |
-
};
|
19 |
-
reducers: {
|
20 |
-
updateState: Reducer<kSModelState>;
|
21 |
-
};
|
22 |
-
subscriptions: { setup: Subscription };
|
23 |
}
|
24 |
-
|
|
|
25 |
namespace: 'kSModel',
|
26 |
state: {
|
27 |
isShowPSwModal: false,
|
28 |
isShowTntModal: false,
|
29 |
-
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
},
|
32 |
subscriptions: {
|
33 |
setup({ dispatch, history }) {
|
34 |
-
history.listen(location => {
|
35 |
-
|
36 |
-
}
|
37 |
},
|
38 |
effects: {
|
39 |
-
*
|
40 |
-
const { data
|
41 |
-
const { retcode
|
42 |
if (retcode === 0) {
|
43 |
message.success('创建知识库成功!');
|
44 |
-
callback && callback(res.kb_id)
|
45 |
}
|
|
|
46 |
},
|
47 |
-
*
|
48 |
-
const { data
|
49 |
-
const { retcode, data: res, retmsg } = data
|
50 |
if (retcode === 0) {
|
51 |
message.success('更新知识库成功!');
|
52 |
}
|
53 |
},
|
54 |
-
*getKbDetail({ payload = {}
|
55 |
-
const { data
|
56 |
-
|
57 |
-
|
58 |
-
// localStorage.setItem('userInfo',res.)
|
59 |
-
callback && callback(res)
|
60 |
-
}
|
61 |
},
|
62 |
},
|
63 |
-
reducers: {
|
64 |
-
updateState(state, { payload }) {
|
65 |
-
return {
|
66 |
-
...state,
|
67 |
-
...payload
|
68 |
-
};
|
69 |
-
}
|
70 |
-
}
|
71 |
};
|
72 |
-
export default
|
|
|
|
|
|
|
1 |
import kbService from '@/services/kbService';
|
2 |
+
import { message } from 'antd';
|
3 |
+
import { DvaModel } from 'umi';
|
4 |
|
5 |
+
export interface KSModelState {
|
6 |
isShowPSwModal: boolean;
|
7 |
isShowTntModal: boolean;
|
8 |
+
tenantIfo: any;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
}
|
10 |
+
|
11 |
+
const model: DvaModel<KSModelState> = {
|
12 |
namespace: 'kSModel',
|
13 |
state: {
|
14 |
isShowPSwModal: false,
|
15 |
isShowTntModal: false,
|
16 |
+
tenantIfo: {},
|
17 |
+
},
|
18 |
+
reducers: {
|
19 |
+
updateState(state, { payload }) {
|
20 |
+
return {
|
21 |
+
...state,
|
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 retcode;
|
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 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
};
|
54 |
+
export default model;
|
web/src/pages/add-knowledge/index.tsx
CHANGED
@@ -1,123 +1,120 @@
|
|
1 |
-
import {
|
2 |
-
import
|
3 |
import type { MenuProps } from 'antd';
|
4 |
import { Menu } from 'antd';
|
5 |
-
import {
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
import
|
11 |
-
import
|
12 |
-
import Search from './components/knowledge-search'
|
13 |
-
import Chunk from './components/knowledge-chunk'
|
14 |
-
import styles from './index.less'
|
15 |
-
import { getWidth } from '@/utils'
|
16 |
-
import { kAModelState } from './model'
|
17 |
|
|
|
|
|
|
|
|
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
const Index: React.FC<kAProps> = ({ kAModel, dispatch }) => {
|
24 |
-
const [collapsed, setCollapsed] = useState(false);
|
25 |
-
const { id, activeKey, doc_id } = kAModel
|
26 |
-
const [windowWidth, setWindowWidth] = useState(getWidth());
|
27 |
-
let navigate = useNavigate();
|
28 |
-
const location = useLocation();
|
29 |
-
// 标记一下
|
30 |
-
console.log(doc_id, '>>>>>>>>>>>>>doc_id')
|
31 |
-
useEffect(() => {
|
32 |
-
const widthSize = () => {
|
33 |
-
const width = getWidth()
|
34 |
-
console.log(width)
|
35 |
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
}, []);
|
43 |
-
useEffect(() => {
|
44 |
-
console.log(location)
|
45 |
-
const search = location.search.slice(1)
|
46 |
-
const map = search.split('&').reduce((obj, cur) => {
|
47 |
-
const [key, value] = cur.split('=')
|
48 |
-
obj[key] = value
|
49 |
-
return obj
|
50 |
-
}, {})
|
51 |
-
dispatch({
|
52 |
-
type: 'kAModel/updateState',
|
53 |
-
payload: {
|
54 |
-
doc_id: undefined,
|
55 |
-
...map,
|
56 |
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
|
|
|
|
|
|
68 |
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
|
|
76 |
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
label,
|
83 |
-
type,
|
84 |
-
disabled
|
85 |
-
} as MenuItem;
|
86 |
-
}
|
87 |
-
const items: MenuItem[] = useMemo(() => {
|
88 |
-
const disabled = !id
|
89 |
-
return [
|
90 |
-
getItem('配置', 'setting', <ToolOutlined />),
|
91 |
-
getItem('知识库', 'file', <BarsOutlined />, disabled),
|
92 |
-
getItem('搜索测试', 'search', <SearchOutlined />, disabled),
|
93 |
-
]
|
94 |
-
}, [id]);
|
95 |
-
const handleSelect: MenuProps['onSelect'] = (e) => {
|
96 |
-
navigate(`/knowledge/add/setting?activeKey=${e.key}&id=${id}`);
|
97 |
}
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
<div className={styles.menu}>
|
102 |
-
<Menu
|
103 |
-
selectedKeys={[activeKey]}
|
104 |
-
mode="inline"
|
105 |
-
className={windowWidth.width > 957 ? styles.defaultWidth : styles.minWidth}
|
106 |
-
inlineCollapsed={collapsed}
|
107 |
-
items={items}
|
108 |
-
onSelect={handleSelect}
|
109 |
-
/>
|
110 |
-
</div>
|
111 |
-
<div className={styles.content}>
|
112 |
-
{activeKey === 'file' && !doc_id && <File kb_id={id} />}
|
113 |
-
{activeKey === 'setting' && <Setting kb_id={id} />}
|
114 |
-
{activeKey === 'search' && <Search kb_id={id} />}
|
115 |
-
{activeKey === 'file' && !!doc_id && <Chunk doc_id={doc_id} />}
|
116 |
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
};
|
122 |
|
123 |
-
export default
|
|
|
1 |
+
import { getWidth } from '@/utils';
|
2 |
+
import { BarsOutlined, SearchOutlined, ToolOutlined } from '@ant-design/icons';
|
3 |
import type { MenuProps } from 'antd';
|
4 |
import { Menu } from 'antd';
|
5 |
+
import React, { useEffect, useMemo, useState } from 'react';
|
6 |
+
import { useDispatch, useLocation, useNavigate, useSelector } from 'umi';
|
7 |
+
import Chunk from './components/knowledge-chunk';
|
8 |
+
import File from './components/knowledge-file';
|
9 |
+
import Search from './components/knowledge-search';
|
10 |
+
import Setting from './components/knowledge-setting';
|
11 |
+
import styles from './index.less';
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
+
const KnowledgeAdding = () => {
|
14 |
+
const dispatch = useDispatch();
|
15 |
+
const kAModel = useSelector((state: any) => state.kAModel);
|
16 |
+
const { id, activeKey, doc_id } = kAModel;
|
17 |
|
18 |
+
const [collapsed, setCollapsed] = useState(false);
|
19 |
+
const [windowWidth, setWindowWidth] = useState(getWidth());
|
20 |
+
let navigate = useNavigate();
|
21 |
+
const location = useLocation();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
+
// 标记一下
|
24 |
+
console.log(doc_id, '>>>>>>>>>>>>>doc_id');
|
25 |
+
useEffect(() => {
|
26 |
+
const widthSize = () => {
|
27 |
+
const width = getWidth();
|
28 |
+
console.log(width);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
+
setWindowWidth(width);
|
31 |
+
};
|
32 |
+
window.addEventListener('resize', widthSize);
|
33 |
+
return () => {
|
34 |
+
window.removeEventListener('resize', widthSize);
|
35 |
+
};
|
36 |
+
}, []);
|
37 |
+
useEffect(() => {
|
38 |
+
const search: string = location.search.slice(1);
|
39 |
+
const map = search.split('&').reduce<Record<string, string>>((obj, cur) => {
|
40 |
+
const [key, value] = cur.split('=');
|
41 |
+
obj[key] = value;
|
42 |
+
return obj;
|
43 |
+
}, {});
|
44 |
|
45 |
+
dispatch({
|
46 |
+
type: 'kAModel/updateState',
|
47 |
+
payload: {
|
48 |
+
doc_id: undefined,
|
49 |
+
...map,
|
50 |
+
},
|
51 |
+
});
|
52 |
+
}, [location]);
|
53 |
|
54 |
+
useEffect(() => {
|
55 |
+
if (windowWidth.width > 957) {
|
56 |
+
setCollapsed(false);
|
57 |
+
} else {
|
58 |
+
setCollapsed(true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
}
|
60 |
+
}, [windowWidth.width]);
|
61 |
+
|
62 |
+
type MenuItem = Required<MenuProps>['items'][number];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
|
64 |
+
function getItem(
|
65 |
+
label: React.ReactNode,
|
66 |
+
key: React.Key,
|
67 |
+
icon?: React.ReactNode,
|
68 |
+
disabled?: boolean,
|
69 |
+
children?: MenuItem[],
|
70 |
+
type?: 'group',
|
71 |
+
): MenuItem {
|
72 |
+
return {
|
73 |
+
key,
|
74 |
+
icon,
|
75 |
+
children,
|
76 |
+
label,
|
77 |
+
type,
|
78 |
+
disabled,
|
79 |
+
} as MenuItem;
|
80 |
+
}
|
81 |
+
const items: MenuItem[] = useMemo(() => {
|
82 |
+
const disabled = !id;
|
83 |
+
return [
|
84 |
+
getItem('配置', 'setting', <ToolOutlined />),
|
85 |
+
getItem('知识库', 'file', <BarsOutlined />, disabled),
|
86 |
+
getItem('搜索测试', 'search', <SearchOutlined />, disabled),
|
87 |
+
];
|
88 |
+
}, [id]);
|
89 |
+
|
90 |
+
const handleSelect: MenuProps['onSelect'] = (e) => {
|
91 |
+
navigate(`/knowledge/add/setting?activeKey=${e.key}&id=${id}`);
|
92 |
+
};
|
93 |
+
|
94 |
+
return (
|
95 |
+
<>
|
96 |
+
<div className={styles.container}>
|
97 |
+
<div className={styles.menu}>
|
98 |
+
<Menu
|
99 |
+
selectedKeys={[activeKey]}
|
100 |
+
mode="inline"
|
101 |
+
className={
|
102 |
+
windowWidth.width > 957 ? styles.defaultWidth : styles.minWidth
|
103 |
+
}
|
104 |
+
inlineCollapsed={collapsed}
|
105 |
+
items={items}
|
106 |
+
onSelect={handleSelect}
|
107 |
+
/>
|
108 |
+
</div>
|
109 |
+
<div className={styles.content}>
|
110 |
+
{activeKey === 'file' && !doc_id && <File kb_id={id} />}
|
111 |
+
{activeKey === 'setting' && <Setting kb_id={id} />}
|
112 |
+
{activeKey === 'search' && <Search kb_id={id} />}
|
113 |
+
{activeKey === 'file' && !!doc_id && <Chunk doc_id={doc_id} />}
|
114 |
+
</div>
|
115 |
+
</div>
|
116 |
+
</>
|
117 |
+
);
|
118 |
};
|
119 |
|
120 |
+
export default KnowledgeAdding;
|
web/src/pages/add-knowledge/model.ts
CHANGED
@@ -1,6 +1,4 @@
|
|
1 |
-
import {
|
2 |
-
import { message } from 'antd';
|
3 |
-
import kbService from '@/services/kbService';
|
4 |
export interface kAModelState {
|
5 |
isShowPSwModal: boolean;
|
6 |
isShowTntModal: boolean;
|
@@ -8,20 +6,10 @@ export interface kAModelState {
|
|
8 |
tenantIfo: any;
|
9 |
activeKey: string;
|
10 |
id: string;
|
11 |
-
doc_id: string
|
12 |
}
|
13 |
-
export interface kAModelType {
|
14 |
-
namespace: 'kAModel';
|
15 |
-
state: kAModelState;
|
16 |
-
effects: {
|
17 |
|
18 |
-
|
19 |
-
reducers: {
|
20 |
-
updateState: Reducer<kAModelState>;
|
21 |
-
};
|
22 |
-
subscriptions: { setup: Subscription };
|
23 |
-
}
|
24 |
-
const Model: kAModelType = {
|
25 |
namespace: 'kAModel',
|
26 |
state: {
|
27 |
isShowPSwModal: false,
|
@@ -30,25 +18,21 @@ const Model: kAModelType = {
|
|
30 |
tenantIfo: {},
|
31 |
activeKey: 'setting',
|
32 |
id: '',
|
33 |
-
doc_id: ''
|
34 |
-
|
35 |
-
},
|
36 |
-
subscriptions: {
|
37 |
-
setup({ dispatch, history }) {
|
38 |
-
history.listen(location => {
|
39 |
-
});
|
40 |
-
}
|
41 |
-
},
|
42 |
-
effects: {
|
43 |
-
|
44 |
},
|
45 |
reducers: {
|
46 |
updateState(state, { payload }) {
|
47 |
return {
|
48 |
...state,
|
49 |
-
...payload
|
50 |
};
|
51 |
-
}
|
52 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
};
|
54 |
-
export default
|
|
|
1 |
+
import { DvaModel } from 'umi';
|
|
|
|
|
2 |
export interface kAModelState {
|
3 |
isShowPSwModal: boolean;
|
4 |
isShowTntModal: boolean;
|
|
|
6 |
tenantIfo: any;
|
7 |
activeKey: string;
|
8 |
id: string;
|
9 |
+
doc_id: string;
|
10 |
}
|
|
|
|
|
|
|
|
|
11 |
|
12 |
+
const model: DvaModel<kAModelState> = {
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
namespace: 'kAModel',
|
14 |
state: {
|
15 |
isShowPSwModal: false,
|
|
|
18 |
tenantIfo: {},
|
19 |
activeKey: 'setting',
|
20 |
id: '',
|
21 |
+
doc_id: '',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
},
|
23 |
reducers: {
|
24 |
updateState(state, { payload }) {
|
25 |
return {
|
26 |
...state,
|
27 |
+
...payload,
|
28 |
};
|
29 |
+
},
|
30 |
+
},
|
31 |
+
subscriptions: {
|
32 |
+
setup({ dispatch, history }) {
|
33 |
+
history.listen((location) => {});
|
34 |
+
},
|
35 |
+
},
|
36 |
+
effects: {},
|
37 |
};
|
38 |
+
export default model;
|
web/src/pages/chat/index.tsx
CHANGED
@@ -1,15 +1,8 @@
|
|
1 |
-
import
|
2 |
-
import { connect, Dispatch } from 'umi';
|
3 |
-
import type { chatModelState } from './model'
|
4 |
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
}
|
9 |
-
|
10 |
-
const View: React.FC<chatProps> = ({ chatModel, dispatch }) => {
|
11 |
-
const { name } = chatModel;
|
12 |
-
return <div>chat:{name} </div>;
|
13 |
};
|
14 |
|
15 |
-
export default
|
|
|
1 |
+
import { useSelector } from 'umi';
|
|
|
|
|
2 |
|
3 |
+
const Chat = () => {
|
4 |
+
const { name } = useSelector((state: any) => state.chatModel);
|
5 |
+
return <div>chat:{name} </div>;
|
|
|
|
|
|
|
|
|
|
|
6 |
};
|
7 |
|
8 |
+
export default Chat;
|
web/src/pages/chat/model.ts
CHANGED
@@ -1,46 +1,32 @@
|
|
1 |
-
import {
|
2 |
|
3 |
-
export interface
|
4 |
-
|
5 |
}
|
6 |
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
}
|
18 |
-
|
19 |
-
const Model: chatModelType = {
|
20 |
-
namespace: 'chatModel',
|
21 |
-
state: {
|
22 |
-
name: 'kate',
|
23 |
-
},
|
24 |
-
|
25 |
-
effects: {
|
26 |
-
*query({ payload }, { call, put }) { },
|
27 |
-
},
|
28 |
-
reducers: {
|
29 |
-
save(state, action) {
|
30 |
-
return {
|
31 |
-
...state,
|
32 |
-
...action.payload,
|
33 |
-
};
|
34 |
-
},
|
35 |
},
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
},
|
43 |
},
|
|
|
|
|
|
|
|
|
44 |
};
|
45 |
|
46 |
-
export default
|
|
|
1 |
+
import { DvaModel } from 'umi';
|
2 |
|
3 |
+
export interface ChatModelState {
|
4 |
+
name: string;
|
5 |
}
|
6 |
|
7 |
+
const model: DvaModel<ChatModelState> = {
|
8 |
+
namespace: 'chatModel',
|
9 |
+
state: {
|
10 |
+
name: 'kate',
|
11 |
+
},
|
12 |
+
reducers: {
|
13 |
+
save(state, action) {
|
14 |
+
return {
|
15 |
+
...state,
|
16 |
+
...action.payload,
|
17 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
},
|
19 |
+
},
|
20 |
+
subscriptions: {
|
21 |
+
setup({ dispatch, history }) {
|
22 |
+
return history.listen((query) => {
|
23 |
+
console.log(query);
|
24 |
+
});
|
|
|
25 |
},
|
26 |
+
},
|
27 |
+
effects: {
|
28 |
+
*query({ payload }, { call, put }) {},
|
29 |
+
},
|
30 |
};
|
31 |
|
32 |
+
export default model;
|
web/src/pages/file/index.tsx
CHANGED
@@ -1,51 +1,50 @@
|
|
1 |
-
import React, { useEffect, useState } from 'react';
|
2 |
import { UploadOutlined } from '@ant-design/icons';
|
3 |
import { Button, Upload } from 'antd';
|
4 |
-
import
|
5 |
-
|
6 |
-
|
7 |
-
const App: React.FC = () => {
|
8 |
-
const [fileList, setFileList] = useState([{
|
9 |
-
uid: '0',
|
10 |
-
name: 'xxx.png',
|
11 |
-
status: 'uploading',
|
12 |
-
percent: 10,
|
13 |
-
}])
|
14 |
-
const obj = {
|
15 |
-
uid: '-1',
|
16 |
-
name: 'yyy.png',
|
17 |
-
status: 'done',
|
18 |
-
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
19 |
-
thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
20 |
-
}
|
21 |
-
useEffect(() => {
|
22 |
-
const timer = setInterval(() => {
|
23 |
-
setFileList((fileList: any) => {
|
24 |
-
const percent = fileList[0]?.percent
|
25 |
-
if (percent + 10 >= 100) {
|
26 |
-
clearInterval(timer)
|
27 |
-
return [obj]
|
28 |
-
}
|
29 |
-
const list = [{ ...fileList[0], percent: percent + 10 }]
|
30 |
-
console.log(list)
|
31 |
-
return list
|
32 |
-
|
33 |
-
})
|
34 |
-
}, 300)
|
35 |
-
}, [])
|
36 |
-
return (
|
37 |
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
};
|
50 |
|
51 |
-
export default
|
|
|
|
|
1 |
import { UploadOutlined } from '@ant-design/icons';
|
2 |
import { Button, Upload } from 'antd';
|
3 |
+
import React, { useEffect, useState } from 'react';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
+
const File: React.FC = () => {
|
6 |
+
const [fileList, setFileList] = useState([
|
7 |
+
{
|
8 |
+
uid: '0',
|
9 |
+
name: 'xxx.png',
|
10 |
+
status: 'uploading',
|
11 |
+
percent: 10,
|
12 |
+
},
|
13 |
+
]);
|
14 |
+
const obj = {
|
15 |
+
uid: '-1',
|
16 |
+
name: 'yyy.png',
|
17 |
+
status: 'done',
|
18 |
+
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
19 |
+
thumbUrl:
|
20 |
+
'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
21 |
+
};
|
22 |
+
useEffect(() => {
|
23 |
+
const timer = setInterval(() => {
|
24 |
+
setFileList((fileList: any) => {
|
25 |
+
const percent = fileList[0]?.percent;
|
26 |
+
if (percent + 10 >= 100) {
|
27 |
+
clearInterval(timer);
|
28 |
+
return [obj];
|
29 |
+
}
|
30 |
+
const list = [{ ...fileList[0], percent: percent + 10 }];
|
31 |
+
console.log(list);
|
32 |
+
return list;
|
33 |
+
});
|
34 |
+
}, 300);
|
35 |
+
}, []);
|
36 |
+
return (
|
37 |
+
<>
|
38 |
+
<Upload
|
39 |
+
action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188"
|
40 |
+
listType="picture"
|
41 |
+
fileList={[...fileList]}
|
42 |
+
multiple
|
43 |
+
>
|
44 |
+
<Button icon={<UploadOutlined />}>Upload</Button>
|
45 |
+
</Upload>
|
46 |
+
</>
|
47 |
+
);
|
48 |
};
|
49 |
|
50 |
+
export default File;
|
web/src/pages/knowledge/index.tsx
CHANGED
@@ -5,21 +5,22 @@ import {
|
|
5 |
PlusOutlined,
|
6 |
} from '@ant-design/icons';
|
7 |
import { Card, Col, FloatButton, Popconfirm, Row } from 'antd';
|
8 |
-
import
|
9 |
-
import {
|
10 |
import styles from './index.less';
|
11 |
-
|
12 |
-
|
13 |
-
dispatch
|
14 |
-
knowledgeModel:
|
15 |
-
}
|
16 |
-
const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => {
|
17 |
const navigate = useNavigate();
|
18 |
-
// const [datas, setDatas] = useState(data)
|
19 |
const { data = [] } = knowledgeModel;
|
20 |
-
console.log(knowledgeModel);
|
21 |
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
const confirm = (id: string) => {
|
25 |
dispatch({
|
@@ -27,12 +28,6 @@ const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => {
|
|
27 |
payload: {
|
28 |
kb_id: id,
|
29 |
},
|
30 |
-
callback: () => {
|
31 |
-
dispatch({
|
32 |
-
type: 'knowledgeModel/getList',
|
33 |
-
payload: {},
|
34 |
-
});
|
35 |
-
},
|
36 |
});
|
37 |
};
|
38 |
const handleAddKnowledge = () => {
|
@@ -42,11 +37,8 @@ const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => {
|
|
42 |
navigate(`add/setting?activeKey=file&id=${id}`);
|
43 |
};
|
44 |
useEffect(() => {
|
45 |
-
|
46 |
-
|
47 |
-
payload: {},
|
48 |
-
});
|
49 |
-
}, []);
|
50 |
return (
|
51 |
<>
|
52 |
<div className={styles.knowledge}>
|
@@ -125,7 +117,4 @@ const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => {
|
|
125 |
);
|
126 |
};
|
127 |
|
128 |
-
export default
|
129 |
-
knowledgeModel,
|
130 |
-
loading,
|
131 |
-
}))(Index);
|
|
|
5 |
PlusOutlined,
|
6 |
} from '@ant-design/icons';
|
7 |
import { Card, Col, FloatButton, Popconfirm, Row } from 'antd';
|
8 |
+
import { useCallback, useEffect } from 'react';
|
9 |
+
import { useDispatch, useNavigate, useSelector } from 'umi';
|
10 |
import styles from './index.less';
|
11 |
+
|
12 |
+
const Knowledge = () => {
|
13 |
+
const dispatch = useDispatch();
|
14 |
+
const knowledgeModel = useSelector((state: any) => state.knowledgeModel);
|
|
|
|
|
15 |
const navigate = useNavigate();
|
|
|
16 |
const { data = [] } = knowledgeModel;
|
|
|
17 |
|
18 |
+
const fetchList = useCallback(() => {
|
19 |
+
dispatch({
|
20 |
+
type: 'knowledgeModel/getList',
|
21 |
+
payload: {},
|
22 |
+
});
|
23 |
+
}, []);
|
24 |
|
25 |
const confirm = (id: string) => {
|
26 |
dispatch({
|
|
|
28 |
payload: {
|
29 |
kb_id: id,
|
30 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
});
|
32 |
};
|
33 |
const handleAddKnowledge = () => {
|
|
|
37 |
navigate(`add/setting?activeKey=file&id=${id}`);
|
38 |
};
|
39 |
useEffect(() => {
|
40 |
+
fetchList();
|
41 |
+
}, [fetchList]);
|
|
|
|
|
|
|
42 |
return (
|
43 |
<>
|
44 |
<div className={styles.knowledge}>
|
|
|
117 |
);
|
118 |
};
|
119 |
|
120 |
+
export default Knowledge;
|
|
|
|
|
|
web/src/pages/knowledge/model.ts
CHANGED
@@ -1,58 +1,38 @@
|
|
1 |
import kbService from '@/services/kbService';
|
2 |
-
import {
|
3 |
|
4 |
-
export interface
|
5 |
-
loading: boolean;
|
6 |
data: any[];
|
7 |
}
|
8 |
-
|
9 |
-
|
10 |
-
state: knowledgeModelState;
|
11 |
-
effects: {
|
12 |
-
rmKb: Effect;
|
13 |
-
getList: Effect;
|
14 |
-
};
|
15 |
-
reducers: {
|
16 |
-
updateState: Reducer<knowledgeModelState>;
|
17 |
-
};
|
18 |
-
// subscriptions: { setup: Subscription };
|
19 |
-
}
|
20 |
-
const Model: knowledgegModelType = {
|
21 |
namespace: 'knowledgeModel',
|
22 |
state: {
|
23 |
-
loading: false,
|
24 |
data: [],
|
25 |
},
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
33 |
effects: {
|
34 |
*rmKb({ payload = {}, callback }, { call, put }) {
|
35 |
-
const { data
|
36 |
-
const { retcode
|
37 |
if (retcode === 0) {
|
38 |
-
|
|
|
|
|
|
|
39 |
}
|
40 |
},
|
41 |
*getList({ payload = {} }, { call, put }) {
|
42 |
-
yield
|
43 |
-
type: 'updateState',
|
44 |
-
payload: {
|
45 |
-
loading: true,
|
46 |
-
},
|
47 |
-
});
|
48 |
-
const { data, response } = yield call(kbService.getList, payload);
|
49 |
const { retcode, data: res, retmsg } = data;
|
50 |
-
|
51 |
-
type: 'updateState',
|
52 |
-
payload: {
|
53 |
-
loading: false,
|
54 |
-
},
|
55 |
-
});
|
56 |
if (retcode === 0) {
|
57 |
yield put({
|
58 |
type: 'updateState',
|
@@ -63,13 +43,5 @@ const Model: knowledgegModelType = {
|
|
63 |
}
|
64 |
},
|
65 |
},
|
66 |
-
reducers: {
|
67 |
-
updateState(state, { payload }) {
|
68 |
-
return {
|
69 |
-
...state,
|
70 |
-
...payload,
|
71 |
-
};
|
72 |
-
},
|
73 |
-
},
|
74 |
};
|
75 |
-
export default
|
|
|
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 }) {
|
15 |
+
return {
|
16 |
+
...state,
|
17 |
+
...payload,
|
18 |
+
};
|
19 |
+
},
|
20 |
+
},
|
21 |
effects: {
|
22 |
*rmKb({ payload = {}, callback }, { call, put }) {
|
23 |
+
const { data } = yield call(kbService.rmKb, payload);
|
24 |
+
const { retcode } = data;
|
25 |
if (retcode === 0) {
|
26 |
+
yield put({
|
27 |
+
type: 'getList',
|
28 |
+
payload: {},
|
29 |
+
});
|
30 |
}
|
31 |
},
|
32 |
*getList({ payload = {} }, { call, put }) {
|
33 |
+
const { data } = yield call(kbService.getList, payload);
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
const { retcode, data: res, retmsg } = data;
|
35 |
+
|
|
|
|
|
|
|
|
|
|
|
36 |
if (retcode === 0) {
|
37 |
yield put({
|
38 |
type: 'updateState',
|
|
|
43 |
}
|
44 |
},
|
45 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
};
|
47 |
+
export default model;
|
web/src/pages/login/index.tsx
CHANGED
@@ -1,15 +1,20 @@
|
|
1 |
import { rsaPsw } from '@/utils';
|
2 |
import { Button, Checkbox, Form, Input } from 'antd';
|
3 |
-
import {
|
4 |
-
import {
|
5 |
import styles from './index.less';
|
6 |
|
7 |
-
|
8 |
-
dispatch: Dispatch;
|
9 |
-
}
|
10 |
-
const View: FC<LoginProps> = ({ dispatch }) => {
|
11 |
-
let navigate = useNavigate();
|
12 |
const [title, setTitle] = useState('login');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
const changeTitle = () => {
|
14 |
setTitle((title) => (title === 'login' ? 'register' : 'login'));
|
15 |
};
|
@@ -26,27 +31,29 @@ const View: FC<LoginProps> = ({ dispatch }) => {
|
|
26 |
|
27 |
var rsaPassWord = rsaPsw(params.password);
|
28 |
if (title === 'login') {
|
29 |
-
const
|
30 |
type: 'loginModel/login',
|
31 |
payload: {
|
32 |
email: params.email,
|
33 |
password: rsaPassWord,
|
34 |
},
|
35 |
});
|
36 |
-
|
37 |
-
|
|
|
38 |
} else {
|
39 |
-
|
|
|
40 |
type: 'loginModel/register',
|
41 |
payload: {
|
42 |
nickname: params.nickname,
|
43 |
email: params.email,
|
44 |
password: rsaPassWord,
|
45 |
},
|
46 |
-
callback() {
|
47 |
-
setTitle('login');
|
48 |
-
},
|
49 |
});
|
|
|
|
|
|
|
50 |
}
|
51 |
} catch (errorInfo) {
|
52 |
console.log('Failed:', errorInfo);
|
@@ -106,7 +113,7 @@ const View: FC<LoginProps> = ({ dispatch }) => {
|
|
106 |
label="Password"
|
107 |
rules={[{ required: true, message: 'Please input value' }]}
|
108 |
>
|
109 |
-
<Input size="large" placeholder="Please input value" />
|
110 |
</Form.Item>
|
111 |
{title === 'login' && (
|
112 |
<Form.Item name="remember" valuePropName="checked">
|
@@ -132,7 +139,13 @@ const View: FC<LoginProps> = ({ dispatch }) => {
|
|
132 |
</div>
|
133 |
)}
|
134 |
</div>
|
135 |
-
<Button
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
{title === 'login' ? 'Sign in' : 'Continue'}
|
137 |
</Button>
|
138 |
{title === 'login' && (
|
@@ -175,6 +188,4 @@ const View: FC<LoginProps> = ({ dispatch }) => {
|
|
175 |
);
|
176 |
};
|
177 |
|
178 |
-
export default
|
179 |
-
View,
|
180 |
-
);
|
|
|
1 |
import { rsaPsw } from '@/utils';
|
2 |
import { Button, Checkbox, Form, Input } from 'antd';
|
3 |
+
import { useEffect, useState } from 'react';
|
4 |
+
import { Icon, useDispatch, useNavigate, useSelector } from 'umi';
|
5 |
import styles from './index.less';
|
6 |
|
7 |
+
const Login = () => {
|
|
|
|
|
|
|
|
|
8 |
const [title, setTitle] = useState('login');
|
9 |
+
let navigate = useNavigate();
|
10 |
+
const dispatch = useDispatch();
|
11 |
+
const effectsLoading: any = useSelector<any>( // TODO: Type needs to be improved
|
12 |
+
(state) => state.loading.effects,
|
13 |
+
);
|
14 |
+
|
15 |
+
const signLoading =
|
16 |
+
effectsLoading['loginModel/login'] || effectsLoading['loginModel/register'];
|
17 |
+
|
18 |
const changeTitle = () => {
|
19 |
setTitle((title) => (title === 'login' ? 'register' : 'login'));
|
20 |
};
|
|
|
31 |
|
32 |
var rsaPassWord = rsaPsw(params.password);
|
33 |
if (title === 'login') {
|
34 |
+
const retcode = await dispatch<any>({
|
35 |
type: 'loginModel/login',
|
36 |
payload: {
|
37 |
email: params.email,
|
38 |
password: rsaPassWord,
|
39 |
},
|
40 |
});
|
41 |
+
if (retcode === 0) {
|
42 |
+
navigate('/knowledge');
|
43 |
+
}
|
44 |
} else {
|
45 |
+
// TODO: Type needs to be improved
|
46 |
+
const retcode = await dispatch<any>({
|
47 |
type: 'loginModel/register',
|
48 |
payload: {
|
49 |
nickname: params.nickname,
|
50 |
email: params.email,
|
51 |
password: rsaPassWord,
|
52 |
},
|
|
|
|
|
|
|
53 |
});
|
54 |
+
if (retcode === 0) {
|
55 |
+
setTitle('login');
|
56 |
+
}
|
57 |
}
|
58 |
} catch (errorInfo) {
|
59 |
console.log('Failed:', errorInfo);
|
|
|
113 |
label="Password"
|
114 |
rules={[{ required: true, message: 'Please input value' }]}
|
115 |
>
|
116 |
+
<Input.Password size="large" placeholder="Please input value" />
|
117 |
</Form.Item>
|
118 |
{title === 'login' && (
|
119 |
<Form.Item name="remember" valuePropName="checked">
|
|
|
139 |
</div>
|
140 |
)}
|
141 |
</div>
|
142 |
+
<Button
|
143 |
+
type="primary"
|
144 |
+
block
|
145 |
+
size="large"
|
146 |
+
onClick={onCheck}
|
147 |
+
loading={signLoading}
|
148 |
+
>
|
149 |
{title === 'login' ? 'Sign in' : 'Continue'}
|
150 |
</Button>
|
151 |
{title === 'login' && (
|
|
|
188 |
);
|
189 |
};
|
190 |
|
191 |
+
export default Login;
|
|
|
|
web/src/pages/login/model.ts
CHANGED
@@ -2,32 +2,29 @@ import { Authorization } from '@/constants/authorization';
|
|
2 |
import userService from '@/services/userService';
|
3 |
import authorizationUtil from '@/utils/authorizationUtil';
|
4 |
import { message } from 'antd';
|
5 |
-
import {
|
6 |
|
7 |
-
export interface
|
8 |
list: any[];
|
9 |
info: any;
|
10 |
visible: boolean;
|
11 |
}
|
12 |
-
|
13 |
-
|
14 |
-
state: loginModelState;
|
15 |
-
effects: {
|
16 |
-
login: Effect;
|
17 |
-
register: Effect;
|
18 |
-
};
|
19 |
-
reducers: {
|
20 |
-
updateState: Reducer<loginModelState>;
|
21 |
-
};
|
22 |
-
subscriptions: { setup: Subscription };
|
23 |
-
}
|
24 |
-
const Model: logingModelType = {
|
25 |
namespace: 'loginModel',
|
26 |
state: {
|
27 |
list: [],
|
28 |
info: {},
|
29 |
visible: false,
|
30 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
subscriptions: {
|
32 |
setup({ dispatch, history }) {
|
33 |
history.listen((location) => {});
|
@@ -53,29 +50,18 @@ const Model: logingModelType = {
|
|
53 |
userInfo: JSON.stringify(userInfo),
|
54 |
Token: token,
|
55 |
});
|
56 |
-
// setTimeout(() => {
|
57 |
-
// window.location.href = '/file';
|
58 |
-
// }, 300);
|
59 |
}
|
60 |
-
return
|
61 |
},
|
62 |
-
*register({ payload = {}
|
63 |
const { data, response } = yield call(userService.register, payload);
|
64 |
console.log();
|
65 |
const { retcode, data: res, retmsg } = data;
|
66 |
if (retcode === 0) {
|
67 |
message.success('注册成功!');
|
68 |
-
callback && callback();
|
69 |
}
|
70 |
-
|
71 |
-
},
|
72 |
-
reducers: {
|
73 |
-
updateState(state, { payload }) {
|
74 |
-
return {
|
75 |
-
...state,
|
76 |
-
...payload,
|
77 |
-
};
|
78 |
},
|
79 |
},
|
80 |
};
|
81 |
-
export default
|
|
|
2 |
import userService from '@/services/userService';
|
3 |
import authorizationUtil from '@/utils/authorizationUtil';
|
4 |
import { message } from 'antd';
|
5 |
+
import { DvaModel } from 'umi';
|
6 |
|
7 |
+
export interface LoginModelState {
|
8 |
list: any[];
|
9 |
info: any;
|
10 |
visible: boolean;
|
11 |
}
|
12 |
+
|
13 |
+
const model: DvaModel<LoginModelState> = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
namespace: 'loginModel',
|
15 |
state: {
|
16 |
list: [],
|
17 |
info: {},
|
18 |
visible: false,
|
19 |
},
|
20 |
+
reducers: {
|
21 |
+
updateState(state, { payload }) {
|
22 |
+
return {
|
23 |
+
...state,
|
24 |
+
...payload,
|
25 |
+
};
|
26 |
+
},
|
27 |
+
},
|
28 |
subscriptions: {
|
29 |
setup({ dispatch, history }) {
|
30 |
history.listen((location) => {});
|
|
|
50 |
userInfo: JSON.stringify(userInfo),
|
51 |
Token: token,
|
52 |
});
|
|
|
|
|
|
|
53 |
}
|
54 |
+
return retcode;
|
55 |
},
|
56 |
+
*register({ payload = {} }, { call, put }) {
|
57 |
const { data, response } = yield call(userService.register, payload);
|
58 |
console.log();
|
59 |
const { retcode, data: res, retmsg } = data;
|
60 |
if (retcode === 0) {
|
61 |
message.success('注册成功!');
|
|
|
62 |
}
|
63 |
+
return retcode;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
},
|
65 |
},
|
66 |
};
|
67 |
+
export default model;
|
web/src/pages/setting/model.ts
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
import userService from '@/services/userService';
|
2 |
import authorizationUtil from '@/utils/authorizationUtil';
|
3 |
import { message } from 'antd';
|
4 |
-
import {
|
5 |
|
6 |
-
export interface
|
7 |
isShowPSwModal: boolean;
|
8 |
isShowTntModal: boolean;
|
9 |
isShowSAKModal: boolean;
|
@@ -16,25 +16,7 @@ export interface settingModelState {
|
|
16 |
factoriesList: any[];
|
17 |
}
|
18 |
|
19 |
-
|
20 |
-
namespace: 'settingModel';
|
21 |
-
state: settingModelState;
|
22 |
-
effects: {
|
23 |
-
setting: Effect;
|
24 |
-
getUserInfo: Effect;
|
25 |
-
getTenantInfo: Effect;
|
26 |
-
set_tenant_info: Effect;
|
27 |
-
factories_list: Effect;
|
28 |
-
llm_list: Effect;
|
29 |
-
my_llm: Effect;
|
30 |
-
set_api_key: Effect;
|
31 |
-
};
|
32 |
-
reducers: {
|
33 |
-
updateState: Reducer<settingModelState>;
|
34 |
-
};
|
35 |
-
subscriptions: { setup: Subscription };
|
36 |
-
}
|
37 |
-
const Model: settingModelType = {
|
38 |
namespace: 'settingModel',
|
39 |
state: {
|
40 |
isShowPSwModal: false,
|
@@ -48,6 +30,14 @@ const Model: settingModelType = {
|
|
48 |
myLlm: [],
|
49 |
factoriesList: [],
|
50 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
subscriptions: {
|
52 |
setup({ dispatch, history }) {
|
53 |
history.listen((location) => {});
|
@@ -176,13 +166,5 @@ const Model: settingModelType = {
|
|
176 |
}
|
177 |
},
|
178 |
},
|
179 |
-
reducers: {
|
180 |
-
updateState(state, { payload }) {
|
181 |
-
return {
|
182 |
-
...state,
|
183 |
-
...payload,
|
184 |
-
};
|
185 |
-
},
|
186 |
-
},
|
187 |
};
|
188 |
-
export default
|
|
|
1 |
import userService from '@/services/userService';
|
2 |
import authorizationUtil from '@/utils/authorizationUtil';
|
3 |
import { message } from 'antd';
|
4 |
+
import { DvaModel } from 'umi';
|
5 |
|
6 |
+
export interface SettingModelState {
|
7 |
isShowPSwModal: boolean;
|
8 |
isShowTntModal: boolean;
|
9 |
isShowSAKModal: boolean;
|
|
|
16 |
factoriesList: any[];
|
17 |
}
|
18 |
|
19 |
+
const model: DvaModel<SettingModelState> = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
namespace: 'settingModel',
|
21 |
state: {
|
22 |
isShowPSwModal: false,
|
|
|
30 |
myLlm: [],
|
31 |
factoriesList: [],
|
32 |
},
|
33 |
+
reducers: {
|
34 |
+
updateState(state, { payload }) {
|
35 |
+
return {
|
36 |
+
...state,
|
37 |
+
...payload,
|
38 |
+
};
|
39 |
+
},
|
40 |
+
},
|
41 |
subscriptions: {
|
42 |
setup({ dispatch, history }) {
|
43 |
history.listen((location) => {});
|
|
|
166 |
}
|
167 |
},
|
168 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
};
|
170 |
+
export default model;
|
web/src/services/kbService.ts
CHANGED
@@ -19,101 +19,83 @@ const {
|
|
19 |
get_chunk,
|
20 |
switch_chunk,
|
21 |
rm_chunk,
|
22 |
-
retrieval_test
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
{
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
url: get_chunk,
|
101 |
-
method: 'get'
|
102 |
-
},
|
103 |
-
switch_chunk: {
|
104 |
-
url: switch_chunk,
|
105 |
-
method: 'post'
|
106 |
-
},
|
107 |
-
rm_chunk: {
|
108 |
-
url: rm_chunk,
|
109 |
-
method: 'post'
|
110 |
-
},
|
111 |
-
retrieval_test: {
|
112 |
-
url: retrieval_test,
|
113 |
-
method: 'post'
|
114 |
-
},
|
115 |
-
},
|
116 |
-
request
|
117 |
-
);
|
118 |
|
119 |
export default kbService;
|
|
|
19 |
get_chunk,
|
20 |
switch_chunk,
|
21 |
rm_chunk,
|
22 |
+
retrieval_test,
|
23 |
+
} = api;
|
24 |
+
|
25 |
+
const methods = {
|
26 |
+
// 知识库管理
|
27 |
+
createKb: {
|
28 |
+
url: create_kb,
|
29 |
+
method: 'post',
|
30 |
+
},
|
31 |
+
updateKb: {
|
32 |
+
url: update_kb,
|
33 |
+
method: 'post',
|
34 |
+
},
|
35 |
+
rmKb: {
|
36 |
+
url: rm_kb,
|
37 |
+
method: 'post',
|
38 |
+
},
|
39 |
+
get_kb_detail: {
|
40 |
+
url: get_kb_detail,
|
41 |
+
method: 'get',
|
42 |
+
},
|
43 |
+
getList: {
|
44 |
+
url: kb_list,
|
45 |
+
method: 'get',
|
46 |
+
},
|
47 |
+
// 文件管理
|
48 |
+
get_document_list: {
|
49 |
+
url: get_document_list,
|
50 |
+
method: 'get',
|
51 |
+
},
|
52 |
+
document_change_status: {
|
53 |
+
url: document_change_status,
|
54 |
+
method: 'post',
|
55 |
+
},
|
56 |
+
document_rm: {
|
57 |
+
url: document_rm,
|
58 |
+
method: 'post',
|
59 |
+
},
|
60 |
+
document_create: {
|
61 |
+
url: document_create,
|
62 |
+
method: 'post',
|
63 |
+
},
|
64 |
+
document_change_parser: {
|
65 |
+
url: document_change_parser,
|
66 |
+
method: 'post',
|
67 |
+
},
|
68 |
+
// chunk管理
|
69 |
+
chunk_list: {
|
70 |
+
url: chunk_list,
|
71 |
+
method: 'post',
|
72 |
+
},
|
73 |
+
create_chunk: {
|
74 |
+
url: create_chunk,
|
75 |
+
method: 'post',
|
76 |
+
},
|
77 |
+
set_chunk: {
|
78 |
+
url: set_chunk,
|
79 |
+
method: 'post',
|
80 |
+
},
|
81 |
+
get_chunk: {
|
82 |
+
url: get_chunk,
|
83 |
+
method: 'get',
|
84 |
+
},
|
85 |
+
switch_chunk: {
|
86 |
+
url: switch_chunk,
|
87 |
+
method: 'post',
|
88 |
+
},
|
89 |
+
rm_chunk: {
|
90 |
+
url: rm_chunk,
|
91 |
+
method: 'post',
|
92 |
+
},
|
93 |
+
retrieval_test: {
|
94 |
+
url: retrieval_test,
|
95 |
+
method: 'post',
|
96 |
+
},
|
97 |
+
};
|
98 |
+
|
99 |
+
const kbService = registerServer<keyof typeof methods>(methods, request);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
|
101 |
export default kbService;
|
web/src/services/userService.ts
CHANGED
@@ -3,55 +3,61 @@ import registerServer from '@/utils/registerServer';
|
|
3 |
import request from '@/utils/request';
|
4 |
|
5 |
const {
|
6 |
-
login,
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
15 |
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
|
|
|
|
|
|
|
|
56 |
|
57 |
export default userService;
|
|
|
3 |
import request from '@/utils/request';
|
4 |
|
5 |
const {
|
6 |
+
login,
|
7 |
+
register,
|
8 |
+
setting,
|
9 |
+
user_info,
|
10 |
+
tenant_info,
|
11 |
+
factories_list,
|
12 |
+
llm_list,
|
13 |
+
my_llm,
|
14 |
+
set_api_key,
|
15 |
+
set_tenant_info,
|
16 |
+
} = api;
|
17 |
|
18 |
+
const methods = {
|
19 |
+
login: {
|
20 |
+
url: login,
|
21 |
+
method: 'post',
|
22 |
+
},
|
23 |
+
register: {
|
24 |
+
url: register,
|
25 |
+
method: 'post',
|
26 |
+
},
|
27 |
+
setting: {
|
28 |
+
url: setting,
|
29 |
+
method: 'post',
|
30 |
+
},
|
31 |
+
user_info: {
|
32 |
+
url: user_info,
|
33 |
+
method: 'get',
|
34 |
+
},
|
35 |
+
get_tenant_info: {
|
36 |
+
url: tenant_info,
|
37 |
+
method: 'get',
|
38 |
+
},
|
39 |
+
set_tenant_info: {
|
40 |
+
url: set_tenant_info,
|
41 |
+
method: 'post',
|
42 |
+
},
|
43 |
+
factories_list: {
|
44 |
+
url: factories_list,
|
45 |
+
method: 'get',
|
46 |
+
},
|
47 |
+
llm_list: {
|
48 |
+
url: llm_list,
|
49 |
+
method: 'get',
|
50 |
+
},
|
51 |
+
my_llm: {
|
52 |
+
url: my_llm,
|
53 |
+
method: 'get',
|
54 |
+
},
|
55 |
+
set_api_key: {
|
56 |
+
url: set_api_key,
|
57 |
+
method: 'post',
|
58 |
+
},
|
59 |
+
} as const;
|
60 |
+
|
61 |
+
const userService = registerServer<keyof typeof methods>(methods, request);
|
62 |
|
63 |
export default userService;
|
web/src/utils/registerServer.ts
CHANGED
@@ -1,17 +1,24 @@
|
|
1 |
-
|
2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
for (let key in opt) {
|
4 |
-
server[key] = (params
|
5 |
if (opt[key].method === 'post' || opt[key].method === 'POST') {
|
6 |
return request(opt[key].url, {
|
7 |
method: opt[key].method,
|
8 |
-
data: params
|
9 |
});
|
10 |
}
|
11 |
|
12 |
if (opt[key].method === 'get' || opt[key].method === 'GET') {
|
13 |
return request.get(opt[key].url, {
|
14 |
-
params
|
15 |
});
|
16 |
}
|
17 |
};
|
|
|
1 |
+
import { RequestMethod } from 'umi-request';
|
2 |
+
|
3 |
+
type Service<T extends string> = Record<T, (params: any) => any>;
|
4 |
+
|
5 |
+
const registerServer = <T extends string>(
|
6 |
+
opt: Record<T, { url: string; method: string }>,
|
7 |
+
request: RequestMethod,
|
8 |
+
) => {
|
9 |
+
const server: Service<T> = {} as Service<T>;
|
10 |
for (let key in opt) {
|
11 |
+
server[key] = (params) => {
|
12 |
if (opt[key].method === 'post' || opt[key].method === 'POST') {
|
13 |
return request(opt[key].url, {
|
14 |
method: opt[key].method,
|
15 |
+
data: params,
|
16 |
});
|
17 |
}
|
18 |
|
19 |
if (opt[key].method === 'get' || opt[key].method === 'GET') {
|
20 |
return request.get(opt[key].url, {
|
21 |
+
params,
|
22 |
});
|
23 |
}
|
24 |
};
|
web/src/utils/request.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { message, notification } from 'antd';
|
2 |
-
import { extend } from 'umi-request';
|
3 |
|
4 |
import { Authorization } from '@/constants/authorization';
|
5 |
import api from '@/utils/api';
|
@@ -9,7 +9,7 @@ const { login } = api;
|
|
9 |
|
10 |
const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message
|
11 |
|
12 |
-
const
|
13 |
200: '服务器成功返回请求的数据。',
|
14 |
201: '新建或修改数据成功。',
|
15 |
202: '一个请求已经进入后台排队(异步任务)。',
|
@@ -26,7 +26,7 @@ const retcodeMessage = {
|
|
26 |
503: '服务不可用,服务器暂时过载或维护。',
|
27 |
504: '网关超时。',
|
28 |
};
|
29 |
-
type
|
30 |
| 200
|
31 |
| 201
|
32 |
| 202
|
@@ -45,7 +45,7 @@ type retcode =
|
|
45 |
/**
|
46 |
* 异常处理程序
|
47 |
*/
|
48 |
-
interface
|
49 |
retcode: number;
|
50 |
data: any;
|
51 |
retmsg: string;
|
@@ -62,7 +62,7 @@ const errorHandler = (error: {
|
|
62 |
} else {
|
63 |
if (response && response.status) {
|
64 |
const errorText =
|
65 |
-
|
66 |
const { status, url } = response;
|
67 |
notification.error({
|
68 |
message: `请求错误 ${status}: ${url}`,
|
@@ -81,7 +81,7 @@ const errorHandler = (error: {
|
|
81 |
/**
|
82 |
* 配置request请求时的默认参数
|
83 |
*/
|
84 |
-
const request = extend({
|
85 |
errorHandler, // 默认错误处理
|
86 |
timeout: 3000000,
|
87 |
getResponse: true,
|
@@ -108,7 +108,7 @@ request.interceptors.request.use((url: string, options: any) => {
|
|
108 |
|
109 |
request.interceptors.response.use(async (response: any, request) => {
|
110 |
console.log(response, request);
|
111 |
-
const data:
|
112 |
// response 拦截
|
113 |
|
114 |
if (data.retcode === 401 || data.retcode === 401) {
|
|
|
1 |
import { message, notification } from 'antd';
|
2 |
+
import { RequestMethod, extend } from 'umi-request';
|
3 |
|
4 |
import { Authorization } from '@/constants/authorization';
|
5 |
import api from '@/utils/api';
|
|
|
9 |
|
10 |
const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message
|
11 |
|
12 |
+
const RetcodeMessage = {
|
13 |
200: '服务器成功返回请求的数据。',
|
14 |
201: '新建或修改数据成功。',
|
15 |
202: '一个请求已经进入后台排队(异步任务)。',
|
|
|
26 |
503: '服务不可用,服务器暂时过载或维护。',
|
27 |
504: '网关超时。',
|
28 |
};
|
29 |
+
type ResultCode =
|
30 |
| 200
|
31 |
| 201
|
32 |
| 202
|
|
|
45 |
/**
|
46 |
* 异常处理程序
|
47 |
*/
|
48 |
+
interface ResponseType {
|
49 |
retcode: number;
|
50 |
data: any;
|
51 |
retmsg: string;
|
|
|
62 |
} else {
|
63 |
if (response && response.status) {
|
64 |
const errorText =
|
65 |
+
RetcodeMessage[response.status as ResultCode] || response.statusText;
|
66 |
const { status, url } = response;
|
67 |
notification.error({
|
68 |
message: `请求错误 ${status}: ${url}`,
|
|
|
81 |
/**
|
82 |
* 配置request请求时的默认参数
|
83 |
*/
|
84 |
+
const request: RequestMethod = extend({
|
85 |
errorHandler, // 默认错误处理
|
86 |
timeout: 3000000,
|
87 |
getResponse: true,
|
|
|
108 |
|
109 |
request.interceptors.response.use(async (response: any, request) => {
|
110 |
console.log(response, request);
|
111 |
+
const data: ResponseType = await response.clone().json();
|
112 |
// response 拦截
|
113 |
|
114 |
if (data.retcode === 401 || data.retcode === 401) {
|
web/src/utils/stroreUtil.ts
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export const getOneNamespaceEffectsLoading = (
|
2 |
+
namespace: string,
|
3 |
+
effects: Record<string, boolean>,
|
4 |
+
effectNames: Array<string>,
|
5 |
+
) => {
|
6 |
+
return effectNames.some(
|
7 |
+
(effectName) => effects[`${namespace}/${effectName}`],
|
8 |
+
);
|
9 |
+
};
|