balibabu
commited on
Commit
·
af3ef26
1
Parent(s):
362ec6c
feat: layout the knowledge list page and modify the page switching button in the header (#48)
Browse files* feat: remove unnecessary 'loading' fields from other files
* feat: layout the knowledge list page
* feat: modify the page switching button in the header
- web/.umirc.ts +5 -0
- web/src/assets/filter.svg +3 -0
- web/src/assets/svg/chat-star.svg +12 -0
- web/src/assets/svg/logo.svg +5 -0
- web/src/assets/svg/more.svg +11 -0
- web/src/layouts/components/header/index.less +46 -0
- web/src/layouts/components/header/index.tsx +74 -0
- web/src/layouts/index.less +2 -12
- web/src/layouts/index.tsx +8 -56
- web/src/less/variable.less +1 -0
- web/src/pages/404.jsx +0 -1
- web/src/pages/add-knowledge/model.ts +0 -2
- web/src/pages/knowledge/index.less +32 -29
- web/src/pages/knowledge/index.tsx +44 -91
- web/src/pages/knowledge/knowledge-card/index.less +73 -0
- web/src/pages/knowledge/knowledge-card/index.tsx +123 -0
- web/src/pages/knowledge/model.ts +1 -1
- web/src/pages/login/index.tsx +2 -0
- web/src/pages/login/model.ts +1 -3
- web/src/pages/setting/CPwModal.tsx +71 -85
- web/src/pages/setting/List.tsx +132 -182
- web/src/pages/setting/SAKModal.tsx +59 -76
- web/src/pages/setting/SSModal.tsx +135 -143
- web/src/pages/setting/TntModal.tsx +57 -50
- web/src/pages/setting/index.tsx +10 -17
- web/src/pages/setting/model.ts +27 -20
- web/src/utils/api.ts +1 -13
- web/src/utils/date.ts +2 -2
- web/src/utils/request.ts +1 -1
web/.umirc.ts
CHANGED
@@ -16,6 +16,11 @@ export default defineConfig({
|
|
16 |
},
|
17 |
plugins: ['@react-dev-inspector/umi4-plugin', '@umijs/plugins/dist/dva'],
|
18 |
dva: {},
|
|
|
|
|
|
|
|
|
|
|
19 |
// proxy: {
|
20 |
// '/v1': {
|
21 |
// 'target': 'http://54.80.112.79:9380/',
|
|
|
16 |
},
|
17 |
plugins: ['@react-dev-inspector/umi4-plugin', '@umijs/plugins/dist/dva'],
|
18 |
dva: {},
|
19 |
+
lessLoader: {
|
20 |
+
modifyVars: {
|
21 |
+
hack: `true; @import "~@/less/variable.less";`,
|
22 |
+
},
|
23 |
+
},
|
24 |
// proxy: {
|
25 |
// '/v1': {
|
26 |
// 'target': 'http://54.80.112.79:9380/',
|
web/src/assets/filter.svg
ADDED
|
web/src/assets/svg/chat-star.svg
ADDED
|
web/src/assets/svg/logo.svg
ADDED
|
web/src/assets/svg/more.svg
ADDED
|
web/src/layouts/components/header/index.less
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.tag {
|
2 |
+
height: 40px;
|
3 |
+
padding: 0 30px;
|
4 |
+
margin: 0 5px;
|
5 |
+
border: 1px solid #000;
|
6 |
+
border-radius: 10px;
|
7 |
+
cursor: pointer;
|
8 |
+
}
|
9 |
+
|
10 |
+
.checked {
|
11 |
+
color: #1677ff;
|
12 |
+
border-color: #1677ff;
|
13 |
+
}
|
14 |
+
|
15 |
+
.appIcon {
|
16 |
+
vertical-align: middle;
|
17 |
+
}
|
18 |
+
|
19 |
+
.appName {
|
20 |
+
vertical-align: middle;
|
21 |
+
font-family: Inter;
|
22 |
+
font-size: 14px;
|
23 |
+
font-style: normal;
|
24 |
+
font-weight: 400;
|
25 |
+
line-height: 20px;
|
26 |
+
}
|
27 |
+
|
28 |
+
.radioGroup {
|
29 |
+
background: rgba(249, 249, 249, 1) !important;
|
30 |
+
& > label {
|
31 |
+
border: 0 !important;
|
32 |
+
&::before {
|
33 |
+
display: none !important;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
:global(.ant-radio-button-wrapper-checked) {
|
37 |
+
border-radius: 6px !important;
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
.ant-radio-button-wrapper-checked {
|
42 |
+
border-radius: 6px !important;
|
43 |
+
}
|
44 |
+
.radioButtonIcon {
|
45 |
+
vertical-align: middle;
|
46 |
+
}
|
web/src/layouts/components/header/index.tsx
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ReactComponent as StarIon } from '@/assets/svg/chat-star.svg';
|
2 |
+
import { ReactComponent as Logo } from '@/assets/svg/logo.svg';
|
3 |
+
import { Layout, Radio, Space, theme } from 'antd';
|
4 |
+
|
5 |
+
import styles from './index.less';
|
6 |
+
|
7 |
+
import { useMemo } from 'react';
|
8 |
+
import { useLocation, useNavigate } from 'umi';
|
9 |
+
import User from '../user';
|
10 |
+
|
11 |
+
const { Header } = Layout;
|
12 |
+
|
13 |
+
const RagHeader = () => {
|
14 |
+
const {
|
15 |
+
token: { colorBgContainer },
|
16 |
+
} = theme.useToken();
|
17 |
+
const navigate = useNavigate();
|
18 |
+
const { pathname } = useLocation();
|
19 |
+
|
20 |
+
const tagsData = [
|
21 |
+
{ path: '/knowledge', name: 'knowledge' },
|
22 |
+
{ path: '/chat', name: 'chat' },
|
23 |
+
{ path: '/file', name: 'file' },
|
24 |
+
];
|
25 |
+
|
26 |
+
const currentPath = useMemo(() => {
|
27 |
+
return tagsData.find((x) => x.path === pathname)?.name || 'knowledge';
|
28 |
+
}, [pathname]);
|
29 |
+
|
30 |
+
const handleChange = (path: string) => {
|
31 |
+
navigate(path);
|
32 |
+
};
|
33 |
+
|
34 |
+
return (
|
35 |
+
<Header
|
36 |
+
style={{
|
37 |
+
padding: '0 16px',
|
38 |
+
background: colorBgContainer,
|
39 |
+
display: 'flex',
|
40 |
+
justifyContent: 'space-between',
|
41 |
+
alignItems: 'center',
|
42 |
+
height: '72px',
|
43 |
+
}}
|
44 |
+
>
|
45 |
+
<Space size={12}>
|
46 |
+
<Logo className={styles.appIcon}></Logo>
|
47 |
+
<label className={styles.appName}>Infinity flow</label>
|
48 |
+
</Space>
|
49 |
+
<Space size={[0, 8]} wrap>
|
50 |
+
<Radio.Group
|
51 |
+
defaultValue="a"
|
52 |
+
buttonStyle="solid"
|
53 |
+
className={styles.radioGroup}
|
54 |
+
value={currentPath}
|
55 |
+
>
|
56 |
+
{tagsData.map((item) => (
|
57 |
+
<Radio.Button
|
58 |
+
value={item.name}
|
59 |
+
onClick={() => handleChange(item.path)}
|
60 |
+
>
|
61 |
+
<Space>
|
62 |
+
<StarIon className={styles.radioButtonIcon}></StarIon>
|
63 |
+
{item.name}
|
64 |
+
</Space>
|
65 |
+
</Radio.Button>
|
66 |
+
))}
|
67 |
+
</Radio.Group>
|
68 |
+
</Space>
|
69 |
+
<User></User>
|
70 |
+
</Header>
|
71 |
+
);
|
72 |
+
};
|
73 |
+
|
74 |
+
export default RagHeader;
|
web/src/layouts/index.less
CHANGED
@@ -18,16 +18,6 @@ body {
|
|
18 |
margin: 0;
|
19 |
}
|
20 |
|
21 |
-
.
|
22 |
-
|
23 |
-
padding: 0 30px;
|
24 |
-
margin: 0 5px;
|
25 |
-
border: 1px solid #000;
|
26 |
-
border-radius: 10px;
|
27 |
-
cursor: pointer;
|
28 |
}
|
29 |
-
|
30 |
-
.checked {
|
31 |
-
color: #1677ff;
|
32 |
-
border-color: #1677ff;
|
33 |
-
}
|
|
|
18 |
margin: 0;
|
19 |
}
|
20 |
|
21 |
+
.divider {
|
22 |
+
margin: 0;
|
|
|
|
|
|
|
|
|
|
|
23 |
}
|
|
|
|
|
|
|
|
|
|
web/src/layouts/index.tsx
CHANGED
@@ -1,74 +1,26 @@
|
|
1 |
-
import
|
2 |
-
import
|
3 |
-
import classnames from 'classnames';
|
4 |
-
import React, { useEffect, useState } from 'react';
|
5 |
import { useTranslation } from 'react-i18next';
|
6 |
-
import { Outlet
|
7 |
import '../locales/config';
|
8 |
-
import
|
9 |
import styles from './index.less';
|
10 |
|
11 |
-
const {
|
12 |
|
13 |
-
const App: React.FC = (
|
14 |
const { t } = useTranslation();
|
15 |
-
const navigate = useNavigate();
|
16 |
const {
|
17 |
token: { colorBgContainer, borderRadiusLG },
|
18 |
} = theme.useToken();
|
19 |
-
const [current, setCurrent] = useState('knowledge');
|
20 |
-
|
21 |
-
const location = useLocation();
|
22 |
-
useEffect(() => {
|
23 |
-
if (location.pathname !== '/') {
|
24 |
-
const path = location.pathname.split('/');
|
25 |
-
// setCurrent(path[1]);
|
26 |
-
}
|
27 |
-
console.log(location.pathname.split('/'));
|
28 |
-
}, [location.pathname]);
|
29 |
-
|
30 |
-
const handleChange = (path: string) => {
|
31 |
-
// setCurrent(path)
|
32 |
-
navigate(path);
|
33 |
-
};
|
34 |
-
const tagsData = [
|
35 |
-
{ path: '/knowledge', name: 'knowledge' },
|
36 |
-
{ path: '/chat', name: 'chat' },
|
37 |
-
{ path: '/file', name: 'file' },
|
38 |
-
];
|
39 |
|
40 |
return (
|
41 |
<Layout className={styles.layout}>
|
42 |
<Layout>
|
43 |
-
<Header
|
44 |
-
|
45 |
-
padding: '0 8px',
|
46 |
-
background: colorBgContainer,
|
47 |
-
display: 'flex',
|
48 |
-
justifyContent: 'space-between',
|
49 |
-
alignItems: 'center',
|
50 |
-
}}
|
51 |
-
>
|
52 |
-
<img src={logo} alt="" style={{ height: 30, width: 30 }} />
|
53 |
-
<Space size={[0, 8]} wrap>
|
54 |
-
{tagsData.map((item) => (
|
55 |
-
<span
|
56 |
-
key={item.name}
|
57 |
-
className={classnames(styles['tag'], {
|
58 |
-
[styles['checked']]: current === item.name,
|
59 |
-
})}
|
60 |
-
onClick={() => handleChange(item.path)}
|
61 |
-
>
|
62 |
-
{item.name}
|
63 |
-
</span>
|
64 |
-
))}
|
65 |
-
</Space>
|
66 |
-
<User></User>
|
67 |
-
</Header>
|
68 |
<Content
|
69 |
style={{
|
70 |
-
margin: '24px 16px',
|
71 |
-
|
72 |
minHeight: 280,
|
73 |
background: colorBgContainer,
|
74 |
borderRadius: borderRadiusLG,
|
|
|
1 |
+
import { Divider, Layout, theme } from 'antd';
|
2 |
+
import React from 'react';
|
|
|
|
|
3 |
import { useTranslation } from 'react-i18next';
|
4 |
+
import { Outlet } from 'umi';
|
5 |
import '../locales/config';
|
6 |
+
import Header from './components/header';
|
7 |
import styles from './index.less';
|
8 |
|
9 |
+
const { Content } = Layout;
|
10 |
|
11 |
+
const App: React.FC = () => {
|
12 |
const { t } = useTranslation();
|
|
|
13 |
const {
|
14 |
token: { colorBgContainer, borderRadiusLG },
|
15 |
} = theme.useToken();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
return (
|
18 |
<Layout className={styles.layout}>
|
19 |
<Layout>
|
20 |
+
<Header></Header>
|
21 |
+
<Divider orientationMargin={0} className={styles.divider} />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
<Content
|
23 |
style={{
|
|
|
|
|
24 |
minHeight: 280,
|
25 |
background: colorBgContainer,
|
26 |
borderRadius: borderRadiusLG,
|
web/src/less/variable.less
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
@fontWeight600: 600;
|
web/src/pages/404.jsx
CHANGED
@@ -1,5 +1,4 @@
|
|
1 |
import { Button, Result } from 'antd';
|
2 |
-
import React from 'react';
|
3 |
import { history } from 'umi';
|
4 |
|
5 |
const NoFoundPage = () => {
|
|
|
1 |
import { Button, Result } from 'antd';
|
|
|
2 |
import { history } from 'umi';
|
3 |
|
4 |
const NoFoundPage = () => {
|
web/src/pages/add-knowledge/model.ts
CHANGED
@@ -2,7 +2,6 @@ import { DvaModel } from 'umi';
|
|
2 |
export interface kAModelState {
|
3 |
isShowPSwModal: boolean;
|
4 |
isShowTntModal: boolean;
|
5 |
-
loading: boolean;
|
6 |
tenantIfo: any;
|
7 |
activeKey: string;
|
8 |
id: string;
|
@@ -14,7 +13,6 @@ const model: DvaModel<kAModelState> = {
|
|
14 |
state: {
|
15 |
isShowPSwModal: false,
|
16 |
isShowTntModal: false,
|
17 |
-
loading: false,
|
18 |
tenantIfo: {},
|
19 |
activeKey: 'setting',
|
20 |
id: '',
|
|
|
2 |
export interface kAModelState {
|
3 |
isShowPSwModal: boolean;
|
4 |
isShowTntModal: boolean;
|
|
|
5 |
tenantIfo: any;
|
6 |
activeKey: string;
|
7 |
id: string;
|
|
|
13 |
state: {
|
14 |
isShowPSwModal: false,
|
15 |
isShowTntModal: false,
|
|
|
16 |
tenantIfo: {},
|
17 |
activeKey: 'setting',
|
18 |
id: '',
|
web/src/pages/knowledge/index.less
CHANGED
@@ -1,40 +1,43 @@
|
|
|
|
|
|
1 |
.knowledge {
|
2 |
-
padding:
|
3 |
}
|
4 |
|
5 |
-
.
|
6 |
-
height: 100px;
|
7 |
display: flex;
|
8 |
-
flex-direction: column;
|
9 |
justify-content: space-between;
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
|
|
|
|
18 |
}
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
}
|
27 |
-
}
|
28 |
-
|
29 |
-
.card {
|
30 |
-
:global {
|
31 |
-
.ant-card-body {
|
32 |
-
padding: 10px;
|
33 |
-
margin: 0;
|
34 |
-
}
|
35 |
|
36 |
-
|
|
|
|
|
|
|
|
|
|
|
37 |
}
|
38 |
|
39 |
-
|
|
|
|
|
|
|
|
|
40 |
}
|
|
|
1 |
+
// @import '~@/less/variable.less';
|
2 |
+
|
3 |
.knowledge {
|
4 |
+
padding: 48px 60px;
|
5 |
}
|
6 |
|
7 |
+
.topWrapper {
|
|
|
8 |
display: flex;
|
|
|
9 |
justify-content: space-between;
|
10 |
+
align-items: flex-start;
|
11 |
+
padding-bottom: 72px;
|
12 |
+
|
13 |
+
.title {
|
14 |
+
font-family: Inter;
|
15 |
+
font-size: 30px;
|
16 |
+
font-style: normal;
|
17 |
+
font-weight: @fontWeight600;
|
18 |
+
line-height: 38px;
|
19 |
+
color: rgba(16, 24, 40, 1);
|
20 |
}
|
21 |
+
.description {
|
22 |
+
font-family: Inter;
|
23 |
+
font-size: 16px;
|
24 |
+
font-style: normal;
|
25 |
+
font-weight: 400;
|
26 |
+
line-height: 24px;
|
27 |
+
color: rgba(71, 84, 103, 1);
|
28 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
+
.topButton {
|
31 |
+
font-family: Inter;
|
32 |
+
font-size: 14px;
|
33 |
+
font-style: normal;
|
34 |
+
font-weight: @fontWeight600;
|
35 |
+
line-height: 20px;
|
36 |
}
|
37 |
|
38 |
+
.filterButton {
|
39 |
+
display: flex;
|
40 |
+
align-items: center;
|
41 |
+
.topButton();
|
42 |
+
}
|
43 |
}
|
web/src/pages/knowledge/index.tsx
CHANGED
@@ -1,13 +1,10 @@
|
|
1 |
-
import {
|
2 |
-
import {
|
3 |
-
|
4 |
-
MinusSquareOutlined,
|
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();
|
@@ -22,98 +19,54 @@ const Knowledge = () => {
|
|
22 |
});
|
23 |
}, []);
|
24 |
|
25 |
-
const confirm = (id: string) => {
|
26 |
-
dispatch({
|
27 |
-
type: 'knowledgeModel/rmKb',
|
28 |
-
payload: {
|
29 |
-
kb_id: id,
|
30 |
-
},
|
31 |
-
});
|
32 |
-
};
|
33 |
const handleAddKnowledge = () => {
|
34 |
navigate(`add/setting?activeKey=setting`);
|
35 |
};
|
36 |
-
|
37 |
-
navigate(`add/setting?activeKey=file&id=${id}`);
|
38 |
-
};
|
39 |
useEffect(() => {
|
40 |
fetchList();
|
41 |
}, [fetchList]);
|
|
|
42 |
return (
|
43 |
-
|
44 |
-
<div className={styles.
|
45 |
-
<
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
<
|
52 |
-
{
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
onClick={() => {
|
65 |
-
handleEditKnowledge(item.id);
|
66 |
-
}}
|
67 |
-
>
|
68 |
-
<div className={styles.container}>
|
69 |
-
<div className={styles.content}>
|
70 |
-
<span className={styles.context}>{item.name}</span>
|
71 |
-
<span className={styles.delete}>
|
72 |
-
<Popconfirm
|
73 |
-
title="Delete the task"
|
74 |
-
description="Are you sure to delete this task?"
|
75 |
-
onConfirm={(e: any) => {
|
76 |
-
e.stopPropagation();
|
77 |
-
e.nativeEvent.stopImmediatePropagation();
|
78 |
-
confirm(item.id);
|
79 |
-
}}
|
80 |
-
okText="Yes"
|
81 |
-
cancelText="No"
|
82 |
-
>
|
83 |
-
<DeleteOutlined
|
84 |
-
onClick={(e) => {
|
85 |
-
e.stopPropagation();
|
86 |
-
e.nativeEvent.stopImmediatePropagation();
|
87 |
-
}}
|
88 |
-
/>
|
89 |
-
</Popconfirm>
|
90 |
-
</span>
|
91 |
-
</div>
|
92 |
-
<div className={styles.footer}>
|
93 |
-
<span className={styles.text}>
|
94 |
-
<MinusSquareOutlined />
|
95 |
-
{item.doc_num}文档
|
96 |
-
</span>
|
97 |
-
<span className={styles.text}>
|
98 |
-
<MinusSquareOutlined />
|
99 |
-
{item.chunk_num}个
|
100 |
-
</span>
|
101 |
-
<span className={styles.text}>
|
102 |
-
<MinusSquareOutlined />
|
103 |
-
{item.token_num}千字符
|
104 |
-
</span>
|
105 |
-
<span style={{ float: 'right' }}>
|
106 |
-
{formatDate(item.update_date)}
|
107 |
-
</span>
|
108 |
-
</div>
|
109 |
-
</div>
|
110 |
-
</Card>
|
111 |
-
</Col>
|
112 |
-
);
|
113 |
-
})}
|
114 |
-
</Row>
|
115 |
</div>
|
116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
);
|
118 |
};
|
119 |
|
|
|
1 |
+
import { ReactComponent as FilterIcon } from '@/assets/filter.svg';
|
2 |
+
import { PlusOutlined } from '@ant-design/icons';
|
3 |
+
import { Button, Col, Row, Space } from 'antd';
|
|
|
|
|
|
|
|
|
4 |
import { useCallback, useEffect } from 'react';
|
5 |
import { useDispatch, useNavigate, useSelector } from 'umi';
|
6 |
import styles from './index.less';
|
7 |
+
import KnowledgeCard from './knowledge-card';
|
8 |
|
9 |
const Knowledge = () => {
|
10 |
const dispatch = useDispatch();
|
|
|
19 |
});
|
20 |
}, []);
|
21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
const handleAddKnowledge = () => {
|
23 |
navigate(`add/setting?activeKey=setting`);
|
24 |
};
|
25 |
+
|
|
|
|
|
26 |
useEffect(() => {
|
27 |
fetchList();
|
28 |
}, [fetchList]);
|
29 |
+
|
30 |
return (
|
31 |
+
<div className={styles.knowledge}>
|
32 |
+
<div className={styles.topWrapper}>
|
33 |
+
<div>
|
34 |
+
<span className={styles.title}>Welcome back, Zing</span>
|
35 |
+
<p className={styles.description}>
|
36 |
+
Which database are we going to use today?
|
37 |
+
</p>
|
38 |
+
</div>
|
39 |
+
<Space size={'large'}>
|
40 |
+
<Button icon={<FilterIcon />} className={styles.filterButton}>
|
41 |
+
Filters
|
42 |
+
</Button>
|
43 |
+
<Button
|
44 |
+
type="primary"
|
45 |
+
icon={<PlusOutlined />}
|
46 |
+
onClick={handleAddKnowledge}
|
47 |
+
className={styles.topButton}
|
48 |
+
>
|
49 |
+
Create knowledge base
|
50 |
+
</Button>
|
51 |
+
</Space>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
</div>
|
53 |
+
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
|
54 |
+
{data.map((item: any) => {
|
55 |
+
return (
|
56 |
+
<Col
|
57 |
+
className="gutter-row"
|
58 |
+
key={item.name}
|
59 |
+
xs={24}
|
60 |
+
sm={12}
|
61 |
+
md={8}
|
62 |
+
lg={6}
|
63 |
+
>
|
64 |
+
<KnowledgeCard item={item}></KnowledgeCard>
|
65 |
+
</Col>
|
66 |
+
);
|
67 |
+
})}
|
68 |
+
</Row>
|
69 |
+
</div>
|
70 |
);
|
71 |
};
|
72 |
|
web/src/pages/knowledge/knowledge-card/index.less
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.container {
|
2 |
+
height: 251px;
|
3 |
+
display: flex;
|
4 |
+
flex-direction: column;
|
5 |
+
justify-content: space-between;
|
6 |
+
|
7 |
+
.content {
|
8 |
+
display: flex;
|
9 |
+
justify-content: space-between;
|
10 |
+
|
11 |
+
.context {
|
12 |
+
flex: 1;
|
13 |
+
}
|
14 |
+
}
|
15 |
+
|
16 |
+
.footer {
|
17 |
+
// text-align: left;
|
18 |
+
}
|
19 |
+
.footerTop {
|
20 |
+
padding-bottom: 2px;
|
21 |
+
}
|
22 |
+
}
|
23 |
+
|
24 |
+
.card {
|
25 |
+
border-radius: 12px;
|
26 |
+
border: 1px solid rgba(234, 236, 240, 1);
|
27 |
+
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
|
28 |
+
padding: 24px;
|
29 |
+
min-width: 300px;
|
30 |
+
cursor: pointer;
|
31 |
+
|
32 |
+
.titleWrapper {
|
33 |
+
// flex: 1;
|
34 |
+
.title {
|
35 |
+
font-size: 24px;
|
36 |
+
line-height: 32px;
|
37 |
+
font-weight: 600;
|
38 |
+
color: rgba(0, 0, 0, 0.88);
|
39 |
+
}
|
40 |
+
.description {
|
41 |
+
font-size: 12px;
|
42 |
+
font-weight: 600;
|
43 |
+
line-height: 20px;
|
44 |
+
color: rgba(0, 0, 0, 0.45);
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
:global {
|
49 |
+
.ant-card-body {
|
50 |
+
padding: 0;
|
51 |
+
margin: 0;
|
52 |
+
}
|
53 |
+
}
|
54 |
+
.bottom {
|
55 |
+
display: flex;
|
56 |
+
align-items: center;
|
57 |
+
justify-content: space-between;
|
58 |
+
}
|
59 |
+
.bottomLeft {
|
60 |
+
vertical-align: middle;
|
61 |
+
}
|
62 |
+
.leftIcon {
|
63 |
+
margin-right: 10px;
|
64 |
+
font-size: 18px;
|
65 |
+
vertical-align: middle;
|
66 |
+
}
|
67 |
+
.rightText {
|
68 |
+
font-size: 12px;
|
69 |
+
font-weight: 600;
|
70 |
+
color: rgba(0, 0, 0, 0.65);
|
71 |
+
vertical-align: middle;
|
72 |
+
}
|
73 |
+
}
|
web/src/pages/knowledge/knowledge-card/index.tsx
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ReactComponent as MoreIcon } from '@/assets/svg/more.svg';
|
2 |
+
import { formatDate } from '@/utils/date';
|
3 |
+
import {
|
4 |
+
AntDesignOutlined,
|
5 |
+
CalendarOutlined,
|
6 |
+
DeleteOutlined,
|
7 |
+
FileTextOutlined,
|
8 |
+
UserOutlined,
|
9 |
+
} from '@ant-design/icons';
|
10 |
+
import { Avatar, Card, Dropdown, MenuProps, Space, Tooltip } from 'antd';
|
11 |
+
import { MouseEvent } from 'react';
|
12 |
+
import { useDispatch, useNavigate } from 'umi';
|
13 |
+
|
14 |
+
import styles from './index.less';
|
15 |
+
|
16 |
+
interface IProps {
|
17 |
+
item: any;
|
18 |
+
}
|
19 |
+
|
20 |
+
const KnowledgeCard = ({ item }: IProps) => {
|
21 |
+
const navigate = useNavigate();
|
22 |
+
const dispatch = useDispatch();
|
23 |
+
|
24 |
+
const handleDelete = (e: MouseEvent<HTMLButtonElement>) => {
|
25 |
+
e.stopPropagation();
|
26 |
+
};
|
27 |
+
|
28 |
+
const items: MenuProps['items'] = [
|
29 |
+
{
|
30 |
+
key: '1',
|
31 |
+
label: (
|
32 |
+
<Space>
|
33 |
+
删除
|
34 |
+
<DeleteOutlined onClick={handleDelete} />
|
35 |
+
</Space>
|
36 |
+
),
|
37 |
+
},
|
38 |
+
];
|
39 |
+
|
40 |
+
const confirm = (id: string) => {
|
41 |
+
dispatch({
|
42 |
+
type: 'knowledgeModel/rmKb',
|
43 |
+
payload: {
|
44 |
+
kb_id: id,
|
45 |
+
},
|
46 |
+
});
|
47 |
+
};
|
48 |
+
|
49 |
+
const handleCardClick = () => {
|
50 |
+
navigate(`add/setting?activeKey=file&id=${item.id}`);
|
51 |
+
};
|
52 |
+
|
53 |
+
const onConfirmDelete = (e?: MouseEvent<HTMLElement>) => {
|
54 |
+
e?.stopPropagation();
|
55 |
+
e?.nativeEvent.stopImmediatePropagation();
|
56 |
+
confirm(item.id);
|
57 |
+
};
|
58 |
+
|
59 |
+
return (
|
60 |
+
<Card className={styles.card} onClick={handleCardClick}>
|
61 |
+
<div className={styles.container}>
|
62 |
+
<div className={styles.content}>
|
63 |
+
<Avatar size={34} icon={<UserOutlined />} />
|
64 |
+
|
65 |
+
<span className={styles.delete}>
|
66 |
+
{/* <Popconfirm
|
67 |
+
title="Delete the task"
|
68 |
+
description="Are you sure to delete this task?"
|
69 |
+
onConfirm={onConfirmDelete}
|
70 |
+
okText="Yes"
|
71 |
+
cancelText="No"
|
72 |
+
>
|
73 |
+
<DeleteOutlined onClick={handleDelete} />
|
74 |
+
</Popconfirm> */}
|
75 |
+
<Dropdown menu={{ items }}>
|
76 |
+
<MoreIcon />
|
77 |
+
</Dropdown>
|
78 |
+
</span>
|
79 |
+
</div>
|
80 |
+
<div className={styles.titleWrapper}>
|
81 |
+
<span className={styles.title}>{item.name}</span>
|
82 |
+
<p>A comprehensive knowledge base for crafting effective resumes.</p>
|
83 |
+
</div>
|
84 |
+
<div className={styles.footer}>
|
85 |
+
<div className={styles.footerTop}>
|
86 |
+
<div className={styles.bottomLeft}>
|
87 |
+
<FileTextOutlined className={styles.leftIcon} />
|
88 |
+
<span className={styles.rightText}>
|
89 |
+
<Space>{item.doc_num}文档</Space>
|
90 |
+
</span>
|
91 |
+
</div>
|
92 |
+
</div>
|
93 |
+
<div className={styles.bottom}>
|
94 |
+
<div className={styles.bottomLeft}>
|
95 |
+
<CalendarOutlined className={styles.leftIcon} />
|
96 |
+
<span className={styles.rightText}>
|
97 |
+
{formatDate(item.update_date)}
|
98 |
+
</span>
|
99 |
+
</div>
|
100 |
+
<Avatar.Group size={25}>
|
101 |
+
<Avatar src="https://api.dicebear.com/7.x/miniavs/svg?seed=1" />
|
102 |
+
<a href="https://ant.design">
|
103 |
+
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
|
104 |
+
</a>
|
105 |
+
<Tooltip title="Ant User" placement="top">
|
106 |
+
<Avatar
|
107 |
+
style={{ backgroundColor: '#87d068' }}
|
108 |
+
icon={<UserOutlined />}
|
109 |
+
/>
|
110 |
+
</Tooltip>
|
111 |
+
<Avatar
|
112 |
+
style={{ backgroundColor: '#1677ff' }}
|
113 |
+
icon={<AntDesignOutlined />}
|
114 |
+
/>
|
115 |
+
</Avatar.Group>
|
116 |
+
</div>
|
117 |
+
</div>
|
118 |
+
</div>
|
119 |
+
</Card>
|
120 |
+
);
|
121 |
+
};
|
122 |
+
|
123 |
+
export default KnowledgeCard;
|
web/src/pages/knowledge/model.ts
CHANGED
@@ -19,7 +19,7 @@ const model: DvaModel<KnowledgeModelState> = {
|
|
19 |
},
|
20 |
},
|
21 |
effects: {
|
22 |
-
*rmKb({ payload = {}
|
23 |
const { data } = yield call(kbService.rmKb, payload);
|
24 |
const { retcode } = data;
|
25 |
if (retcode === 0) {
|
|
|
19 |
},
|
20 |
},
|
21 |
effects: {
|
22 |
+
*rmKb({ payload = {} }, { call, put }) {
|
23 |
const { data } = yield call(kbService.rmKb, payload);
|
24 |
const { retcode } = data;
|
25 |
if (retcode === 0) {
|
web/src/pages/login/index.tsx
CHANGED
@@ -12,6 +12,8 @@ const Login = () => {
|
|
12 |
(state) => state.loading.effects,
|
13 |
);
|
14 |
|
|
|
|
|
15 |
const signLoading =
|
16 |
effectsLoading['loginModel/login'] || effectsLoading['loginModel/register'];
|
17 |
|
|
|
12 |
(state) => state.loading.effects,
|
13 |
);
|
14 |
|
15 |
+
// TODO: When the server address request is not accessible, the value of dva-loading always remains true.
|
16 |
+
|
17 |
const signLoading =
|
18 |
effectsLoading['loginModel/login'] || effectsLoading['loginModel/register'];
|
19 |
|
web/src/pages/login/model.ts
CHANGED
@@ -32,10 +32,8 @@ const model: DvaModel<LoginModelState> = {
|
|
32 |
},
|
33 |
effects: {
|
34 |
*login({ payload = {} }, { call, put }) {
|
35 |
-
console.log(111, payload);
|
36 |
const { data, response } = yield call(userService.login, payload);
|
37 |
-
const { retcode, data: res
|
38 |
-
console.log();
|
39 |
const authorization = response.headers.get(Authorization);
|
40 |
if (retcode === 0) {
|
41 |
message.success('登录成功!');
|
|
|
32 |
},
|
33 |
effects: {
|
34 |
*login({ payload = {} }, { call, put }) {
|
|
|
35 |
const { data, response } = yield call(userService.login, payload);
|
36 |
+
const { retcode, data: res } = data;
|
|
|
37 |
const authorization = response.headers.get(Authorization);
|
38 |
if (retcode === 0) {
|
39 |
message.success('登录成功!');
|
web/src/pages/setting/CPwModal.tsx
CHANGED
@@ -1,92 +1,78 @@
|
|
1 |
-
import {
|
2 |
-
import
|
3 |
-
import { useTranslation
|
4 |
-
import {
|
5 |
-
import { rsaPsw } from '@/utils'
|
6 |
-
import styles from './index.less';
|
7 |
-
import { FC } from 'react';
|
8 |
|
9 |
type FieldType = {
|
10 |
-
|
11 |
-
|
12 |
};
|
13 |
-
interface CPwModalProps {
|
14 |
-
dispatch: Dispatch;
|
15 |
-
settingModel: any
|
16 |
-
}
|
17 |
-
const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
|
18 |
-
const { isShowPSwModal } = settingModel
|
19 |
-
const { t } = useTranslation()
|
20 |
-
const handleCancel = () => {
|
21 |
-
dispatch({
|
22 |
-
type: 'settingModel/updateState',
|
23 |
-
payload: {
|
24 |
-
isShowPSwModal: false
|
25 |
-
}
|
26 |
-
});
|
27 |
-
};
|
28 |
-
const [form] = Form.useForm()
|
29 |
-
const handleOk = async () => {
|
30 |
-
try {
|
31 |
-
const values = await form.validateFields();
|
32 |
-
var password = rsaPsw(values.password)
|
33 |
-
var new_password = rsaPsw(values.newPassword)
|
34 |
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
callback: () => {
|
42 |
-
dispatch({
|
43 |
-
type: 'settingModel/updateState',
|
44 |
-
payload: {
|
45 |
-
isShowPSwModal: false
|
46 |
-
}
|
47 |
-
});
|
48 |
-
dispatch({
|
49 |
-
type: 'settingModel/getUserInfo',
|
50 |
-
payload: {
|
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 |
-
|
|
|
|
|
|
|
|
|
|
1 |
+
import { rsaPsw } from '@/utils';
|
2 |
+
import { Form, Input, Modal } from 'antd';
|
3 |
+
import { useTranslation } from 'react-i18next';
|
4 |
+
import { useDispatch, useSelector } from 'umi';
|
|
|
|
|
|
|
5 |
|
6 |
type FieldType = {
|
7 |
+
newPassword?: string;
|
8 |
+
password?: string;
|
9 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
+
const CpwModal = () => {
|
12 |
+
const dispatch = useDispatch();
|
13 |
+
const settingModel = useSelector((state: any) => state.settingModel);
|
14 |
+
const { isShowPSwModal } = settingModel;
|
15 |
+
const { t } = useTranslation();
|
16 |
+
const [form] = Form.useForm();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
|
18 |
+
const handleCancel = () => {
|
19 |
+
dispatch({
|
20 |
+
type: 'settingModel/updateState',
|
21 |
+
payload: {
|
22 |
+
isShowPSwModal: false,
|
23 |
+
},
|
24 |
+
});
|
25 |
+
};
|
26 |
+
const handleOk = async () => {
|
27 |
+
try {
|
28 |
+
const values = await form.validateFields();
|
29 |
+
var password = rsaPsw(values.password);
|
30 |
+
var new_password = rsaPsw(values.newPassword);
|
31 |
|
32 |
+
dispatch({
|
33 |
+
type: 'settingModel/setting',
|
34 |
+
payload: {
|
35 |
+
password,
|
36 |
+
new_password,
|
37 |
+
},
|
38 |
+
});
|
39 |
+
} catch (errorInfo) {
|
40 |
+
console.log('Failed:', errorInfo);
|
41 |
+
}
|
42 |
+
};
|
43 |
|
44 |
+
return (
|
45 |
+
<Modal
|
46 |
+
title="Basic Modal"
|
47 |
+
open={isShowPSwModal}
|
48 |
+
onOk={handleOk}
|
49 |
+
onCancel={handleCancel}
|
50 |
+
>
|
51 |
+
<Form
|
52 |
+
form={form}
|
53 |
+
labelCol={{ span: 8 }}
|
54 |
+
wrapperCol={{ span: 16 }}
|
55 |
+
style={{ maxWidth: 600 }}
|
56 |
+
autoComplete="off"
|
57 |
+
>
|
58 |
+
<Form.Item<FieldType>
|
59 |
+
label="旧密码"
|
60 |
+
name="password"
|
61 |
+
rules={[{ required: true, message: 'Please input value' }]}
|
62 |
+
>
|
63 |
+
<Input.Password />
|
64 |
+
</Form.Item>
|
65 |
+
<Form.Item<FieldType>
|
66 |
+
label="新密码"
|
67 |
+
name="newPassword"
|
68 |
+
rules={[
|
69 |
+
{ required: true, message: 'Please input your newPassword!' },
|
70 |
+
]}
|
71 |
+
>
|
72 |
+
<Input.Password />
|
73 |
+
</Form.Item>
|
74 |
+
</Form>
|
75 |
+
</Modal>
|
76 |
+
);
|
77 |
+
};
|
78 |
+
export default CpwModal;
|
web/src/pages/setting/List.tsx
CHANGED
@@ -1,196 +1,146 @@
|
|
1 |
-
import {
|
2 |
-
import i18n from 'i18next';
|
3 |
-
import { useTranslation, Trans } from 'react-i18next'
|
4 |
|
|
|
5 |
import styles from './index.less';
|
6 |
-
import type { ColumnsType } from 'antd/es/table';
|
7 |
-
import { useEffect, useState, FC } from 'react';
|
8 |
|
9 |
import { RadarChartOutlined } from '@ant-design/icons';
|
10 |
import { ProCard } from '@ant-design/pro-components';
|
11 |
-
import { Button,
|
12 |
-
|
13 |
|
14 |
interface DataType {
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
}
|
21 |
-
interface ListProps {
|
22 |
-
dispatch: Dispatch;
|
23 |
-
settingModel: any
|
24 |
}
|
25 |
-
const Index: FC<ListProps> = ({ settingModel, dispatch }) => {
|
26 |
-
const { llmInfo = {}, factoriesList, myLlm = [] } = settingModel
|
27 |
-
const { OpenAI = [], tongyi = [] } = llmInfo
|
28 |
-
console.log(OpenAI)
|
29 |
-
const [collapsed, setCollapsed] = useState(true);
|
30 |
-
const { t } = useTranslation()
|
31 |
-
const columns: ColumnsType<DataType> = [
|
32 |
-
{ title: 'Name', dataIndex: 'name', key: 'name' },
|
33 |
-
{ title: 'Age', dataIndex: 'age', key: 'age' },
|
34 |
-
{
|
35 |
-
title: 'Action',
|
36 |
-
dataIndex: '',
|
37 |
-
key: 'x',
|
38 |
-
render: () => <a>Delete</a>,
|
39 |
-
},
|
40 |
-
];
|
41 |
-
useEffect(() => {
|
42 |
-
dispatch({
|
43 |
-
type: 'settingModel/factories_list',
|
44 |
-
payload: {
|
45 |
-
},
|
46 |
-
});
|
47 |
-
dispatch({
|
48 |
-
type: 'settingModel/llm_list',
|
49 |
-
payload: {
|
50 |
-
},
|
51 |
-
});
|
52 |
-
dispatch({
|
53 |
-
type: 'settingModel/my_llm',
|
54 |
-
payload: {
|
55 |
-
},
|
56 |
-
});
|
57 |
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
|
66 |
-
},
|
67 |
-
{
|
68 |
-
key: 2,
|
69 |
-
name: 'Jim Green',
|
70 |
-
age: 42,
|
71 |
-
address: 'London No. 1 Lake Park',
|
72 |
-
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
|
73 |
-
},
|
74 |
-
{
|
75 |
-
key: 3,
|
76 |
-
name: 'Not Expandable',
|
77 |
-
age: 29,
|
78 |
-
address: 'Jiangsu No. 1 Lake Park',
|
79 |
-
description: 'This not expandable',
|
80 |
-
},
|
81 |
-
{
|
82 |
-
key: 4,
|
83 |
-
name: 'Joe Black',
|
84 |
-
age: 32,
|
85 |
-
address: 'Sydney No. 1 Lake Park',
|
86 |
-
description: 'My name is Joe Black, I am 32 years old, living in Sydney No. 1 Lake Park.',
|
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 |
-
buildInCollapsed ? <span>显示{OpenAI.length}个模型</span> : <span>收起{OpenAI.length}个模型 </span>
|
117 |
-
}
|
118 |
-
</div>)
|
119 |
-
}}
|
120 |
-
extra={
|
121 |
-
<Button
|
122 |
-
size="small"
|
123 |
-
type='link'
|
124 |
-
onClick={(e) => {
|
125 |
-
e.stopPropagation();
|
126 |
-
dispatch({
|
127 |
-
type: 'settingModel/updateState',
|
128 |
-
payload: {
|
129 |
-
llm_factory: item.llm_factory,
|
130 |
-
isShowSAKModal: true
|
131 |
-
}
|
132 |
-
});
|
133 |
-
}}
|
134 |
-
>
|
135 |
-
设置
|
136 |
-
</Button>
|
137 |
-
}
|
138 |
-
style={{ marginBlockStart: 16 }}
|
139 |
-
headerBordered
|
140 |
-
collapsible
|
141 |
-
defaultCollapsed
|
142 |
-
>
|
143 |
-
{/* <ul>
|
144 |
-
{OpenAI.map(item => {
|
145 |
-
return <li key={item.llm_name}>
|
146 |
-
<span>{item.llm_name}</span>
|
147 |
-
<span className={styles[item.available ? 'statusAvailable' : 'statusDisaabled']}>
|
148 |
-
</span>
|
149 |
-
</li>
|
150 |
-
})}
|
151 |
-
</ul> */}
|
152 |
-
</ProCard>)
|
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 |
-
<div>
|
182 |
-
{
|
183 |
-
item.tags.split(',').map((d: string) => {
|
184 |
-
return <Tag key={d}>{d}</Tag>
|
185 |
-
})
|
186 |
-
}
|
187 |
-
</div>
|
188 |
-
</Card>
|
189 |
-
</Col>)
|
190 |
-
})
|
191 |
}
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
}
|
196 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useTranslation } from 'react-i18next';
|
|
|
|
|
2 |
|
3 |
+
import { useEffect, useState } from 'react';
|
4 |
import styles from './index.less';
|
|
|
|
|
5 |
|
6 |
import { RadarChartOutlined } from '@ant-design/icons';
|
7 |
import { ProCard } from '@ant-design/pro-components';
|
8 |
+
import { Button, Card, Col, Row, Tag } from 'antd';
|
9 |
+
import { useDispatch, useSelector } from 'umi';
|
10 |
|
11 |
interface DataType {
|
12 |
+
key: React.Key;
|
13 |
+
name: string;
|
14 |
+
age: number;
|
15 |
+
address: string;
|
16 |
+
description: string;
|
|
|
|
|
|
|
|
|
17 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
+
const SettingList = () => {
|
20 |
+
const dispatch = useDispatch();
|
21 |
+
const settingModel = useSelector((state: any) => state.settingModel);
|
22 |
+
const { llmInfo = {}, factoriesList, myLlm = [] } = settingModel;
|
23 |
+
const { OpenAI = [], tongyi = [] } = llmInfo;
|
24 |
+
const [collapsed, setCollapsed] = useState(true);
|
25 |
+
const { t } = useTranslation();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
|
27 |
+
useEffect(() => {
|
28 |
+
dispatch({
|
29 |
+
type: 'settingModel/factories_list',
|
30 |
+
payload: {},
|
31 |
+
});
|
32 |
+
dispatch({
|
33 |
+
type: 'settingModel/llm_list',
|
34 |
+
payload: {},
|
35 |
+
});
|
36 |
+
dispatch({
|
37 |
+
type: 'settingModel/my_llm',
|
38 |
+
payload: {},
|
39 |
+
});
|
40 |
+
}, []);
|
41 |
+
|
42 |
+
return (
|
43 |
+
<div
|
44 |
+
className={styles.list}
|
45 |
+
style={{
|
46 |
+
display: 'flex',
|
47 |
+
flexDirection: 'column',
|
48 |
+
padding: 24,
|
49 |
+
gap: 12,
|
50 |
+
}}
|
51 |
+
>
|
52 |
+
{myLlm.map((item: any) => {
|
53 |
+
return (
|
54 |
+
<ProCard
|
55 |
+
key={item.llm_factory}
|
56 |
+
// title={<div>可折叠-图标自定义</div>}
|
57 |
+
collapsibleIconRender={({
|
58 |
+
collapsed: buildInCollapsed,
|
59 |
+
}: {
|
60 |
+
collapsed: boolean;
|
61 |
+
}) => {
|
62 |
+
return (
|
63 |
+
<div>
|
64 |
+
<h3>
|
65 |
+
<RadarChartOutlined />
|
66 |
+
{item.llm_factory}
|
67 |
+
</h3>
|
68 |
+
<div>
|
69 |
+
{item.tags.split(',').map((d: string) => {
|
70 |
+
return <Tag key={d}>{d}</Tag>;
|
71 |
+
})}
|
72 |
+
</div>
|
73 |
+
{buildInCollapsed ? (
|
74 |
+
<span>显示{OpenAI.length}个模型</span>
|
75 |
+
) : (
|
76 |
+
<span>收起{OpenAI.length}个模型 </span>
|
77 |
+
)}
|
78 |
+
</div>
|
79 |
+
);
|
80 |
}}
|
81 |
+
extra={
|
82 |
+
<Button
|
83 |
+
size="small"
|
84 |
+
type="link"
|
85 |
+
onClick={(e) => {
|
86 |
+
e.stopPropagation();
|
87 |
+
dispatch({
|
88 |
+
type: 'settingModel/updateState',
|
89 |
+
payload: {
|
90 |
+
llm_factory: item.llm_factory,
|
91 |
+
isShowSAKModal: true,
|
92 |
+
},
|
93 |
+
});
|
94 |
+
}}
|
95 |
+
>
|
96 |
+
设置
|
97 |
+
</Button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
}
|
99 |
+
style={{ marginBlockStart: 16 }}
|
100 |
+
headerBordered
|
101 |
+
collapsible
|
102 |
+
defaultCollapsed
|
103 |
+
></ProCard>
|
104 |
+
);
|
105 |
+
})}
|
106 |
|
107 |
+
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
|
108 |
+
{factoriesList.map((item: any) => {
|
109 |
+
return (
|
110 |
+
<Col key={item.name} xs={24} sm={12} md={8} lg={6}>
|
111 |
+
<Card
|
112 |
+
title={item.name}
|
113 |
+
bordered={false}
|
114 |
+
extra={
|
115 |
+
<Button
|
116 |
+
size="small"
|
117 |
+
type="link"
|
118 |
+
onClick={(e) => {
|
119 |
+
e.stopPropagation();
|
120 |
+
dispatch({
|
121 |
+
type: 'settingModel/updateState',
|
122 |
+
payload: {
|
123 |
+
llm_factory: item.name,
|
124 |
+
isShowSAKModal: true,
|
125 |
+
},
|
126 |
+
});
|
127 |
+
}}
|
128 |
+
>
|
129 |
+
设置
|
130 |
+
</Button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
}
|
132 |
+
>
|
133 |
+
<div>
|
134 |
+
{item.tags.split(',').map((d: string) => {
|
135 |
+
return <Tag key={d}>{d}</Tag>;
|
136 |
+
})}
|
137 |
+
</div>
|
138 |
+
</Card>
|
139 |
+
</Col>
|
140 |
+
);
|
141 |
+
})}
|
142 |
+
</Row>
|
143 |
+
</div>
|
144 |
+
);
|
145 |
+
};
|
146 |
+
export default SettingList;
|
web/src/pages/setting/SAKModal.tsx
CHANGED
@@ -1,83 +1,66 @@
|
|
1 |
-
import {
|
2 |
-
import
|
3 |
-
import {
|
4 |
-
import { useTranslation, Trans } from 'react-i18next'
|
5 |
-
import { Input, Modal, Form } from 'antd'
|
6 |
-
import styles from './index.less';
|
7 |
|
8 |
type FieldType = {
|
9 |
-
|
10 |
};
|
11 |
-
interface SAKModalProps {
|
12 |
-
dispatch: Dispatch;
|
13 |
-
settingModel: any
|
14 |
-
}
|
15 |
-
const Index: FC<SAKModalProps> = ({ settingModel, dispatch }) => {
|
16 |
-
const { isShowSAKModal, llm_factory } = settingModel
|
17 |
-
console.log(llm_factory)
|
18 |
-
const { t } = useTranslation()
|
19 |
-
const handleCancel = () => {
|
20 |
-
dispatch({
|
21 |
-
type: 'settingModel/updateState',
|
22 |
-
payload: {
|
23 |
-
isShowSAKModal: false
|
24 |
-
}
|
25 |
-
});
|
26 |
-
};
|
27 |
-
const [form] = Form.useForm()
|
28 |
-
const handleOk = async () => {
|
29 |
-
try {
|
30 |
-
const values = await form.validateFields();
|
31 |
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
callback: () => {
|
39 |
-
dispatch({
|
40 |
-
type: 'settingModel/updateState',
|
41 |
-
payload: {
|
42 |
-
isShowSAKModal: false
|
43 |
-
}
|
44 |
-
});
|
45 |
-
// dispatch({
|
46 |
-
// type: 'settingModel/getUserInfo',
|
47 |
-
// payload: {
|
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 |
-
|
|
|
|
|
|
1 |
+
import { Form, Input, Modal } from 'antd';
|
2 |
+
import { useTranslation } from 'react-i18next';
|
3 |
+
import { useDispatch, useSelector } from 'umi';
|
|
|
|
|
|
|
4 |
|
5 |
type FieldType = {
|
6 |
+
api_key?: string;
|
7 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
+
const SakModal = () => {
|
10 |
+
const dispatch = useDispatch();
|
11 |
+
const settingModel = useSelector((state: any) => state.settingModel);
|
12 |
+
const { isShowSAKModal, llm_factory } = settingModel;
|
13 |
+
const { t } = useTranslation();
|
14 |
+
const [form] = Form.useForm();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
+
const handleCancel = () => {
|
17 |
+
dispatch({
|
18 |
+
type: 'settingModel/updateState',
|
19 |
+
payload: {
|
20 |
+
isShowSAKModal: false,
|
21 |
+
},
|
22 |
+
});
|
23 |
+
};
|
24 |
+
const handleOk = async () => {
|
25 |
+
try {
|
26 |
+
const values = await form.validateFields();
|
27 |
|
28 |
+
dispatch({
|
29 |
+
type: 'settingModel/set_api_key',
|
30 |
+
payload: {
|
31 |
+
api_key: values.api_key,
|
32 |
+
llm_factory: llm_factory,
|
33 |
+
},
|
34 |
+
});
|
35 |
+
} catch (errorInfo) {
|
36 |
+
console.log('Failed:', errorInfo);
|
37 |
+
}
|
38 |
+
};
|
39 |
|
40 |
+
return (
|
41 |
+
<Modal
|
42 |
+
title="Basic Modal"
|
43 |
+
open={isShowSAKModal}
|
44 |
+
onOk={handleOk}
|
45 |
+
onCancel={handleCancel}
|
46 |
+
>
|
47 |
+
<Form
|
48 |
+
form={form}
|
49 |
+
name="validateOnly"
|
50 |
+
labelCol={{ span: 8 }}
|
51 |
+
wrapperCol={{ span: 16 }}
|
52 |
+
style={{ maxWidth: 600 }}
|
53 |
+
autoComplete="off"
|
54 |
+
>
|
55 |
+
<Form.Item<FieldType>
|
56 |
+
label="API Key"
|
57 |
+
name="api_key"
|
58 |
+
rules={[{ required: true, message: 'Please input ' }]}
|
59 |
+
>
|
60 |
+
<Input />
|
61 |
+
</Form.Item>
|
62 |
+
</Form>
|
63 |
+
</Modal>
|
64 |
+
);
|
65 |
+
};
|
66 |
+
export default SakModal;
|
web/src/pages/setting/SSModal.tsx
CHANGED
@@ -1,152 +1,144 @@
|
|
1 |
-
import {
|
2 |
-
import {
|
3 |
-
import
|
4 |
-
import { useTranslation, Trans } from 'react-i18next'
|
5 |
-
import { Input, Modal, Form, Select } from 'antd'
|
6 |
-
import styles from './index.less';
|
7 |
|
8 |
type FieldType = {
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
};
|
14 |
-
interface SSModalProps {
|
15 |
-
dispatch: Dispatch;
|
16 |
-
settingModel: any
|
17 |
-
}
|
18 |
-
const Index: FC<SSModalProps> = ({ settingModel, dispatch }) => {
|
19 |
-
const { isShowSSModal, llmInfo = {}, tenantIfo } = settingModel
|
20 |
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
}
|
28 |
-
});
|
29 |
-
};
|
30 |
-
const [form] = Form.useForm()
|
31 |
-
const handleOk = async () => {
|
32 |
-
try {
|
33 |
-
const values = await form.validateFields();
|
34 |
-
console.log(values)
|
35 |
-
dispatch({
|
36 |
-
type: 'settingModel/set_tenant_info',
|
37 |
-
payload: {
|
38 |
-
...values,
|
39 |
-
tenant_id: tenantIfo.tenant_id,
|
40 |
-
},
|
41 |
-
callback: () => {
|
42 |
-
dispatch({
|
43 |
-
type: 'settingModel/updateState',
|
44 |
-
payload: {
|
45 |
-
isShowSSModal: false
|
46 |
-
}
|
47 |
-
});
|
48 |
-
// dispatch({
|
49 |
-
// type: 'settingModel/getUserInfo',
|
50 |
-
// payload: {
|
51 |
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
};
|
61 |
-
const handleChange = () => {
|
62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
}
|
|
|
64 |
|
65 |
-
|
66 |
-
<Modal title="Basic Modal" open={isShowSSModal} onOk={handleOk} onCancel={handleCancel}>
|
67 |
-
<Form
|
68 |
-
form={form}
|
69 |
-
name="validateOnly"
|
70 |
-
// labelCol={{ span: 8 }}
|
71 |
-
// wrapperCol={{ span: 16 }}
|
72 |
-
style={{ maxWidth: 600 }}
|
73 |
-
autoComplete="off"
|
74 |
-
layout="vertical"
|
75 |
-
>
|
76 |
-
<Form.Item<FieldType>
|
77 |
-
label="embedding 模型"
|
78 |
-
name="embd_id"
|
79 |
-
rules={[{ required: true, message: 'Please input value' }]}
|
80 |
-
initialValue={tenantIfo.embd_id}
|
81 |
-
|
82 |
-
>
|
83 |
-
<Select
|
84 |
-
// style={{ width: 200 }}
|
85 |
-
onChange={handleChange}
|
86 |
-
// fieldNames={label:}
|
87 |
-
options={Object.keys(llmInfo).map(t => {
|
88 |
-
const options = llmInfo[t].filter((d: any) => d.model_type === 'embedding').map((d: any) => ({ label: d.llm_name, value: d.llm_name, }))
|
89 |
-
return { label: t, options }
|
90 |
-
})}
|
91 |
-
/>
|
92 |
-
</Form.Item>
|
93 |
-
<Form.Item<FieldType>
|
94 |
-
label="chat 模型"
|
95 |
-
name="llm_id"
|
96 |
-
rules={[{ required: true, message: 'Please input value' }]}
|
97 |
-
initialValue={tenantIfo.llm_id}
|
98 |
-
|
99 |
-
>
|
100 |
-
<Select
|
101 |
-
// style={{ width: 200 }}
|
102 |
-
onChange={handleChange}
|
103 |
-
// fieldNames={label:}
|
104 |
-
options={Object.keys(llmInfo).map(t => {
|
105 |
-
const options = llmInfo[t].filter((d: any) => d.model_type === 'chat').map((d: any) => ({ label: d.llm_name, value: d.llm_name, }))
|
106 |
-
return { label: t, options }
|
107 |
-
})}
|
108 |
-
/>
|
109 |
-
</Form.Item>
|
110 |
-
<Form.Item<FieldType>
|
111 |
-
label="image2text 模型"
|
112 |
-
name="img2txt_id"
|
113 |
-
rules={[{ required: true, message: 'Please input value' }]}
|
114 |
-
initialValue={tenantIfo.img2txt_id}
|
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 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Form, Modal, Select } from 'antd';
|
2 |
+
import { useTranslation } from 'react-i18next';
|
3 |
+
import { useDispatch, useSelector } from 'umi';
|
|
|
|
|
|
|
4 |
|
5 |
type FieldType = {
|
6 |
+
embd_id?: string;
|
7 |
+
img2txt_id?: string;
|
8 |
+
llm_id?: string;
|
9 |
+
asr_id?: string;
|
10 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
+
const SsModal = () => {
|
13 |
+
const dispatch = useDispatch();
|
14 |
+
const settingModel = useSelector((state: any) => state.settingModel);
|
15 |
+
const { isShowSSModal, llmInfo = {}, tenantIfo } = settingModel;
|
16 |
+
const [form] = Form.useForm();
|
17 |
+
const { t } = useTranslation();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
+
const handleCancel = () => {
|
20 |
+
dispatch({
|
21 |
+
type: 'settingModel/updateState',
|
22 |
+
payload: {
|
23 |
+
isShowSSModal: false,
|
24 |
+
},
|
25 |
+
});
|
26 |
+
};
|
|
|
|
|
27 |
|
28 |
+
const handleOk = async () => {
|
29 |
+
try {
|
30 |
+
const values = await form.validateFields();
|
31 |
+
const retcode = await dispatch<any>({
|
32 |
+
type: 'settingModel/set_tenant_info',
|
33 |
+
payload: {
|
34 |
+
...values,
|
35 |
+
tenant_id: tenantIfo.tenant_id,
|
36 |
+
},
|
37 |
+
});
|
38 |
+
retcode === 0 &&
|
39 |
+
dispatch({
|
40 |
+
type: 'settingModel/updateState',
|
41 |
+
payload: {
|
42 |
+
isShowSSModal: false,
|
43 |
+
},
|
44 |
+
});
|
45 |
+
} catch (errorInfo) {
|
46 |
+
console.log('Failed:', errorInfo);
|
47 |
}
|
48 |
+
};
|
49 |
|
50 |
+
const handleChange = () => {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
+
return (
|
53 |
+
<Modal
|
54 |
+
title="Basic Modal"
|
55 |
+
open={isShowSSModal}
|
56 |
+
onOk={handleOk}
|
57 |
+
onCancel={handleCancel}
|
58 |
+
>
|
59 |
+
<Form
|
60 |
+
form={form}
|
61 |
+
name="validateOnly"
|
62 |
+
// labelCol={{ span: 8 }}
|
63 |
+
// wrapperCol={{ span: 16 }}
|
64 |
+
style={{ maxWidth: 600 }}
|
65 |
+
autoComplete="off"
|
66 |
+
layout="vertical"
|
67 |
+
>
|
68 |
+
<Form.Item<FieldType>
|
69 |
+
label="embedding 模型"
|
70 |
+
name="embd_id"
|
71 |
+
rules={[{ required: true, message: 'Please input value' }]}
|
72 |
+
initialValue={tenantIfo.embd_id}
|
73 |
+
>
|
74 |
+
<Select
|
75 |
+
// style={{ width: 200 }}
|
76 |
+
onChange={handleChange}
|
77 |
+
// fieldNames={label:}
|
78 |
+
options={Object.keys(llmInfo).map((t) => {
|
79 |
+
const options = llmInfo[t]
|
80 |
+
.filter((d: any) => d.model_type === 'embedding')
|
81 |
+
.map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
|
82 |
+
return { label: t, options };
|
83 |
+
})}
|
84 |
+
/>
|
85 |
+
</Form.Item>
|
86 |
+
<Form.Item<FieldType>
|
87 |
+
label="chat 模型"
|
88 |
+
name="llm_id"
|
89 |
+
rules={[{ required: true, message: 'Please input value' }]}
|
90 |
+
initialValue={tenantIfo.llm_id}
|
91 |
+
>
|
92 |
+
<Select
|
93 |
+
// style={{ width: 200 }}
|
94 |
+
onChange={handleChange}
|
95 |
+
// fieldNames={label:}
|
96 |
+
options={Object.keys(llmInfo).map((t) => {
|
97 |
+
const options = llmInfo[t]
|
98 |
+
.filter((d: any) => d.model_type === 'chat')
|
99 |
+
.map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
|
100 |
+
return { label: t, options };
|
101 |
+
})}
|
102 |
+
/>
|
103 |
+
</Form.Item>
|
104 |
+
<Form.Item<FieldType>
|
105 |
+
label="image2text 模型"
|
106 |
+
name="img2txt_id"
|
107 |
+
rules={[{ required: true, message: 'Please input value' }]}
|
108 |
+
initialValue={tenantIfo.img2txt_id}
|
109 |
+
>
|
110 |
+
<Select
|
111 |
+
// style={{ width: 200 }}
|
112 |
+
onChange={handleChange}
|
113 |
+
// fieldNames={label:}
|
114 |
+
options={Object.keys(llmInfo).map((t) => {
|
115 |
+
const options = llmInfo[t]
|
116 |
+
.filter((d: any) => d.model_type === 'image2text')
|
117 |
+
.map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
|
118 |
+
return { label: t, options };
|
119 |
+
})}
|
120 |
+
/>
|
121 |
+
</Form.Item>
|
122 |
+
<Form.Item<FieldType>
|
123 |
+
label="speech2text 模型"
|
124 |
+
name="asr_id"
|
125 |
+
rules={[{ required: true, message: 'Please input value' }]}
|
126 |
+
initialValue={tenantIfo.asr_id}
|
127 |
+
>
|
128 |
+
<Select
|
129 |
+
// style={{ width: 200 }}
|
130 |
+
onChange={handleChange}
|
131 |
+
// fieldNames={label:}
|
132 |
+
options={Object.keys(llmInfo).map((t) => {
|
133 |
+
const options = llmInfo[t]
|
134 |
+
.filter((d: any) => d.model_type === 'speech2text')
|
135 |
+
.map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
|
136 |
+
return { label: t, options };
|
137 |
+
})}
|
138 |
+
/>
|
139 |
+
</Form.Item>
|
140 |
+
</Form>
|
141 |
+
</Modal>
|
142 |
+
);
|
143 |
+
};
|
144 |
+
export default SsModal;
|
web/src/pages/setting/TntModal.tsx
CHANGED
@@ -1,58 +1,65 @@
|
|
1 |
-
import {
|
2 |
-
import {
|
3 |
-
import
|
4 |
-
import { useTranslation
|
5 |
-
import {
|
6 |
import styles from './index.less';
|
7 |
-
import type { ColumnsType } from 'antd/es/table';
|
8 |
-
|
9 |
|
10 |
interface DataType {
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
}
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
}
|
|
|
|
|
|
|
|
|
21 |
|
22 |
-
const
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
type: 'settingModel/updateState',
|
28 |
-
payload: {
|
29 |
-
isShowTntModal: false
|
30 |
-
}
|
31 |
-
});
|
32 |
-
};
|
33 |
-
console.log(tenantIfo)
|
34 |
-
const handleOk = async () => {
|
35 |
-
dispatch({
|
36 |
-
type: 'settingModel/updateState',
|
37 |
-
payload: {
|
38 |
-
isShowTntModal: false
|
39 |
-
}
|
40 |
-
});
|
41 |
-
};
|
42 |
-
const columns: ColumnsType<DataType> = [
|
43 |
-
{ title: '姓名', dataIndex: 'name', key: 'name' },
|
44 |
-
{ title: '活动时间', dataIndex: 'update_date', key: 'update_date' },
|
45 |
-
{ title: '角色', dataIndex: 'role', key: 'age' },
|
46 |
|
47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
2 |
+
import { Modal, Table } from 'antd';
|
3 |
+
import { ColumnsType } from 'antd/es/table';
|
4 |
+
import { useTranslation } from 'react-i18next';
|
5 |
+
import { useDispatch, useSelector } from 'umi';
|
6 |
import styles from './index.less';
|
|
|
|
|
7 |
|
8 |
interface DataType {
|
9 |
+
key: React.Key;
|
10 |
+
name: string;
|
11 |
+
role: string;
|
12 |
+
time: string;
|
13 |
}
|
14 |
|
15 |
+
const TntModal = () => {
|
16 |
+
const dispatch = useDispatch();
|
17 |
+
const settingModel = useSelector((state: any) => state.settingModel);
|
18 |
+
const { isShowTntModal, tenantIfo, factoriesList } = settingModel;
|
19 |
+
const { t } = useTranslation();
|
20 |
+
const loading = useOneNamespaceEffectsLoading('settingModel', [
|
21 |
+
'getTenantInfo',
|
22 |
+
]);
|
23 |
|
24 |
+
const columns: ColumnsType<DataType> = [
|
25 |
+
{ title: '姓名', dataIndex: 'name', key: 'name' },
|
26 |
+
{ title: '活动时间', dataIndex: 'update_date', key: 'update_date' },
|
27 |
+
{ title: '角色', dataIndex: 'role', key: 'age' },
|
28 |
+
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
+
const handleCancel = () => {
|
31 |
+
dispatch({
|
32 |
+
type: 'settingModel/updateState',
|
33 |
+
payload: {
|
34 |
+
isShowTntModal: false,
|
35 |
+
},
|
36 |
+
});
|
37 |
+
};
|
38 |
|
39 |
+
const handleOk = async () => {
|
40 |
+
dispatch({
|
41 |
+
type: 'settingModel/updateState',
|
42 |
+
payload: {
|
43 |
+
isShowTntModal: false,
|
44 |
+
},
|
45 |
+
});
|
46 |
+
};
|
47 |
+
|
48 |
+
return (
|
49 |
+
<Modal
|
50 |
+
title="用户"
|
51 |
+
open={isShowTntModal}
|
52 |
+
onOk={handleOk}
|
53 |
+
onCancel={handleCancel}
|
54 |
+
>
|
55 |
+
<div className={styles.tenantIfo}>{tenantIfo.name}</div>
|
56 |
+
<Table
|
57 |
+
rowKey="name"
|
58 |
+
loading={loading}
|
59 |
+
columns={columns}
|
60 |
+
dataSource={factoriesList}
|
61 |
+
/>
|
62 |
+
</Modal>
|
63 |
+
);
|
64 |
+
};
|
65 |
+
export default TntModal;
|
web/src/pages/setting/index.tsx
CHANGED
@@ -1,34 +1,35 @@
|
|
1 |
import { Button, FloatButton } from 'antd';
|
2 |
import i18n from 'i18next';
|
3 |
import { useTranslation } from 'react-i18next';
|
4 |
-
import { Dispatch, connect } from 'umi';
|
5 |
|
6 |
import authorizationUtil from '@/utils/authorizationUtil';
|
7 |
-
import {
|
|
|
8 |
import CPwModal from './CPwModal';
|
9 |
import List from './List';
|
10 |
import SAKModal from './SAKModal';
|
11 |
import SSModal from './SSModal';
|
12 |
import TntModal from './TntModal';
|
13 |
import styles from './index.less';
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
|
19 |
-
// const [llm_factory, set_llm_factory] = useState('')
|
20 |
const { t } = useTranslation();
|
21 |
const userInfo = authorizationUtil.getUserInfoObject();
|
|
|
22 |
const changeLang = (val: string) => {
|
23 |
// 改变状态里的 语言 进行切换
|
24 |
i18n.changeLanguage(val);
|
25 |
};
|
|
|
26 |
useEffect(() => {
|
27 |
dispatch({
|
28 |
type: 'settingModel/getTenantInfo',
|
29 |
payload: {},
|
30 |
});
|
31 |
}, []);
|
|
|
32 |
const showCPwModal = () => {
|
33 |
dispatch({
|
34 |
type: 'settingModel/updateState',
|
@@ -52,11 +53,6 @@ const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
|
|
52 |
isShowSSModal: true,
|
53 |
},
|
54 |
});
|
55 |
-
// dispatch({
|
56 |
-
// type: 'settingModel/getTenantInfo',
|
57 |
-
// payload: {
|
58 |
-
// }
|
59 |
-
// });
|
60 |
};
|
61 |
return (
|
62 |
<div className={styles.settingPage}>
|
@@ -99,7 +95,4 @@ const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
|
|
99 |
</div>
|
100 |
);
|
101 |
};
|
102 |
-
export default
|
103 |
-
settingModel,
|
104 |
-
loading,
|
105 |
-
}))(Index);
|
|
|
1 |
import { Button, FloatButton } from 'antd';
|
2 |
import i18n from 'i18next';
|
3 |
import { useTranslation } from 'react-i18next';
|
|
|
4 |
|
5 |
import authorizationUtil from '@/utils/authorizationUtil';
|
6 |
+
import { useEffect } from 'react';
|
7 |
+
import { useDispatch, useSelector } from 'umi';
|
8 |
import CPwModal from './CPwModal';
|
9 |
import List from './List';
|
10 |
import SAKModal from './SAKModal';
|
11 |
import SSModal from './SSModal';
|
12 |
import TntModal from './TntModal';
|
13 |
import styles from './index.less';
|
14 |
+
|
15 |
+
const Setting = () => {
|
16 |
+
const dispatch = useDispatch();
|
17 |
+
const settingModel = useSelector((state: any) => state.settingModel);
|
|
|
|
|
18 |
const { t } = useTranslation();
|
19 |
const userInfo = authorizationUtil.getUserInfoObject();
|
20 |
+
|
21 |
const changeLang = (val: string) => {
|
22 |
// 改变状态里的 语言 进行切换
|
23 |
i18n.changeLanguage(val);
|
24 |
};
|
25 |
+
|
26 |
useEffect(() => {
|
27 |
dispatch({
|
28 |
type: 'settingModel/getTenantInfo',
|
29 |
payload: {},
|
30 |
});
|
31 |
}, []);
|
32 |
+
|
33 |
const showCPwModal = () => {
|
34 |
dispatch({
|
35 |
type: 'settingModel/updateState',
|
|
|
53 |
isShowSSModal: true,
|
54 |
},
|
55 |
});
|
|
|
|
|
|
|
|
|
|
|
56 |
};
|
57 |
return (
|
58 |
<div className={styles.settingPage}>
|
|
|
95 |
</div>
|
96 |
);
|
97 |
};
|
98 |
+
export default Setting;
|
|
|
|
|
|
web/src/pages/setting/model.ts
CHANGED
@@ -9,7 +9,6 @@ export interface SettingModelState {
|
|
9 |
isShowSAKModal: boolean;
|
10 |
isShowSSModal: boolean;
|
11 |
llm_factory: string;
|
12 |
-
loading: boolean;
|
13 |
tenantIfo: any;
|
14 |
llmInfo: any;
|
15 |
myLlm: any[];
|
@@ -24,7 +23,6 @@ const model: DvaModel<SettingModelState> = {
|
|
24 |
isShowSAKModal: false,
|
25 |
isShowSSModal: false,
|
26 |
llm_factory: '',
|
27 |
-
loading: false,
|
28 |
tenantIfo: {},
|
29 |
llmInfo: {},
|
30 |
myLlm: [],
|
@@ -44,12 +42,21 @@ const model: DvaModel<SettingModelState> = {
|
|
44 |
},
|
45 |
},
|
46 |
effects: {
|
47 |
-
*setting({ payload = {}
|
48 |
-
const { data
|
49 |
-
const { retcode
|
50 |
if (retcode === 0) {
|
51 |
message.success('密码修改成功!');
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
}
|
54 |
},
|
55 |
*getUserInfo({ payload = {} }, { call, put }) {
|
@@ -72,11 +79,8 @@ const model: DvaModel<SettingModelState> = {
|
|
72 |
loading: true,
|
73 |
},
|
74 |
});
|
75 |
-
const { data
|
76 |
-
|
77 |
-
payload,
|
78 |
-
);
|
79 |
-
const { retcode, data: res, retmsg } = data;
|
80 |
// llm_id 对应chat_id
|
81 |
// asr_id 对应speech2txt
|
82 |
|
@@ -98,11 +102,8 @@ const model: DvaModel<SettingModelState> = {
|
|
98 |
}
|
99 |
},
|
100 |
*set_tenant_info({ payload = {} }, { call, put }) {
|
101 |
-
const { data
|
102 |
-
|
103 |
-
payload,
|
104 |
-
);
|
105 |
-
const { retcode, data: res, retmsg } = data;
|
106 |
// llm_id 对应chat_id
|
107 |
// asr_id 对应speech2txt
|
108 |
if (retcode === 0) {
|
@@ -116,6 +117,7 @@ const model: DvaModel<SettingModelState> = {
|
|
116 |
type: 'getTenantInfo',
|
117 |
});
|
118 |
}
|
|
|
119 |
},
|
120 |
|
121 |
*factories_list({ payload = {} }, { call, put }) {
|
@@ -157,12 +159,17 @@ const model: DvaModel<SettingModelState> = {
|
|
157 |
});
|
158 |
}
|
159 |
},
|
160 |
-
*set_api_key({ payload = {}
|
161 |
-
const { data
|
162 |
-
const { retcode
|
163 |
if (retcode === 0) {
|
164 |
message.success('设置API KEY成功!');
|
165 |
-
|
|
|
|
|
|
|
|
|
|
|
166 |
}
|
167 |
},
|
168 |
},
|
|
|
9 |
isShowSAKModal: boolean;
|
10 |
isShowSSModal: boolean;
|
11 |
llm_factory: string;
|
|
|
12 |
tenantIfo: any;
|
13 |
llmInfo: any;
|
14 |
myLlm: any[];
|
|
|
23 |
isShowSAKModal: false,
|
24 |
isShowSSModal: false,
|
25 |
llm_factory: '',
|
|
|
26 |
tenantIfo: {},
|
27 |
llmInfo: {},
|
28 |
myLlm: [],
|
|
|
42 |
},
|
43 |
},
|
44 |
effects: {
|
45 |
+
*setting({ payload = {} }, { call, put }) {
|
46 |
+
const { data } = yield call(userService.setting, payload);
|
47 |
+
const { retcode } = data;
|
48 |
if (retcode === 0) {
|
49 |
message.success('密码修改成功!');
|
50 |
+
yield put({
|
51 |
+
type: 'updateState',
|
52 |
+
payload: {
|
53 |
+
isShowPSwModal: false,
|
54 |
+
},
|
55 |
+
});
|
56 |
+
yield put({
|
57 |
+
type: 'getUserInfo',
|
58 |
+
payload: {},
|
59 |
+
});
|
60 |
}
|
61 |
},
|
62 |
*getUserInfo({ payload = {} }, { call, put }) {
|
|
|
79 |
loading: true,
|
80 |
},
|
81 |
});
|
82 |
+
const { data } = yield call(userService.get_tenant_info, payload);
|
83 |
+
const { retcode, data: res } = data;
|
|
|
|
|
|
|
84 |
// llm_id 对应chat_id
|
85 |
// asr_id 对应speech2txt
|
86 |
|
|
|
102 |
}
|
103 |
},
|
104 |
*set_tenant_info({ payload = {} }, { call, put }) {
|
105 |
+
const { data } = yield call(userService.set_tenant_info, payload);
|
106 |
+
const { retcode } = data;
|
|
|
|
|
|
|
107 |
// llm_id 对应chat_id
|
108 |
// asr_id 对应speech2txt
|
109 |
if (retcode === 0) {
|
|
|
117 |
type: 'getTenantInfo',
|
118 |
});
|
119 |
}
|
120 |
+
return retcode;
|
121 |
},
|
122 |
|
123 |
*factories_list({ payload = {} }, { call, put }) {
|
|
|
159 |
});
|
160 |
}
|
161 |
},
|
162 |
+
*set_api_key({ payload = {} }, { call, put }) {
|
163 |
+
const { data } = yield call(userService.set_api_key, payload);
|
164 |
+
const { retcode } = data;
|
165 |
if (retcode === 0) {
|
166 |
message.success('设置API KEY成功!');
|
167 |
+
yield put({
|
168 |
+
type: 'updateState',
|
169 |
+
payload: {
|
170 |
+
isShowSAKModal: false,
|
171 |
+
},
|
172 |
+
});
|
173 |
}
|
174 |
},
|
175 |
},
|
web/src/utils/api.ts
CHANGED
@@ -1,14 +1,8 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
let api_host = `http://54.80.112.79:9380/v1`;
|
5 |
-
|
6 |
|
7 |
export { api_host };
|
8 |
|
9 |
export default {
|
10 |
-
|
11 |
-
|
12 |
// 用户
|
13 |
login: `${api_host}/user/login`,
|
14 |
register: `${api_host}/user/register`,
|
@@ -23,8 +17,6 @@ export default {
|
|
23 |
my_llm: `${api_host}/llm/my_llms`,
|
24 |
set_api_key: `${api_host}/llm/set_api_key`,
|
25 |
|
26 |
-
|
27 |
-
|
28 |
//知识库管理
|
29 |
kb_list: `${api_host}/kb/list`,
|
30 |
create_kb: `${api_host}/kb/create`,
|
@@ -41,9 +33,6 @@ export default {
|
|
41 |
rm_chunk: `${api_host}/chunk/rm`,
|
42 |
retrieval_test: `${api_host}/chunk/retrieval_test`,
|
43 |
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
// 上传
|
48 |
upload: `${api_host}/document/upload`,
|
49 |
get_document_list: `${api_host}/document/list`,
|
@@ -51,5 +40,4 @@ export default {
|
|
51 |
document_rm: `${api_host}/document/rm`,
|
52 |
document_create: `${api_host}/document/create`,
|
53 |
document_change_parser: `${api_host}/document/change_parser`,
|
54 |
-
|
55 |
};
|
|
|
1 |
+
let api_host = `http://223.111.148.200:9380/v1`;
|
|
|
|
|
|
|
|
|
2 |
|
3 |
export { api_host };
|
4 |
|
5 |
export default {
|
|
|
|
|
6 |
// 用户
|
7 |
login: `${api_host}/user/login`,
|
8 |
register: `${api_host}/user/register`,
|
|
|
17 |
my_llm: `${api_host}/llm/my_llms`,
|
18 |
set_api_key: `${api_host}/llm/set_api_key`,
|
19 |
|
|
|
|
|
20 |
//知识库管理
|
21 |
kb_list: `${api_host}/kb/list`,
|
22 |
create_kb: `${api_host}/kb/create`,
|
|
|
33 |
rm_chunk: `${api_host}/chunk/rm`,
|
34 |
retrieval_test: `${api_host}/chunk/retrieval_test`,
|
35 |
|
|
|
|
|
|
|
36 |
// 上传
|
37 |
upload: `${api_host}/document/upload`,
|
38 |
get_document_list: `${api_host}/document/list`,
|
|
|
40 |
document_rm: `${api_host}/document/rm`,
|
41 |
document_create: `${api_host}/document/create`,
|
42 |
document_change_parser: `${api_host}/document/change_parser`,
|
|
|
43 |
};
|
web/src/utils/date.ts
CHANGED
@@ -12,9 +12,9 @@ export function lastWeek() {
|
|
12 |
return formatDate(moment().subtract(1, 'weeks'));
|
13 |
}
|
14 |
|
15 |
-
export function formatDate(date) {
|
16 |
if (!date) {
|
17 |
return '';
|
18 |
}
|
19 |
-
return moment(date).format('YYYY
|
20 |
}
|
|
|
12 |
return formatDate(moment().subtract(1, 'weeks'));
|
13 |
}
|
14 |
|
15 |
+
export function formatDate(date: any) {
|
16 |
if (!date) {
|
17 |
return '';
|
18 |
}
|
19 |
+
return moment(date).format('DD/MM/YYYY');
|
20 |
}
|
web/src/utils/request.ts
CHANGED
@@ -83,7 +83,7 @@ const errorHandler = (error: {
|
|
83 |
*/
|
84 |
const request: RequestMethod = extend({
|
85 |
errorHandler, // 默认错误处理
|
86 |
-
timeout:
|
87 |
getResponse: true,
|
88 |
});
|
89 |
|
|
|
83 |
*/
|
84 |
const request: RequestMethod = extend({
|
85 |
errorHandler, // 默认错误处理
|
86 |
+
timeout: 300000,
|
87 |
getResponse: true,
|
88 |
});
|
89 |
|