balibabu
commited on
Commit
·
ebf2bde
1
Parent(s):
7cad30e
feat: delete the added model #503 and display an error message when the requested file fails to parse #684 (#708)
Browse files### What problem does this PR solve?
feat: delete the added model #503
feat: display an error message when the requested file fails to parse
#684
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- web/.umirc.ts +1 -1
- web/package-lock.json +0 -0
- web/package.json +1 -1
- web/src/components/pdf-previewer/index.tsx +2 -2
- web/src/constants/common.ts +4 -2
- web/src/hooks/llmHooks.ts +22 -3
- web/src/interfaces/request/llm.ts +5 -0
- web/src/locales/en.ts +1 -0
- web/src/locales/zh-traditional.ts +1 -0
- web/src/locales/zh.ts +1 -0
- web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx +1 -1
- web/src/pages/chat/chat-overview-modal/index.tsx +4 -1
- web/src/pages/chat/embed-modal/index.tsx +2 -1
- web/src/pages/document-viewer/docx/index.less +281 -0
- web/src/pages/document-viewer/docx/index.tsx +25 -0
- web/src/pages/document-viewer/excel/index.tsx +12 -28
- web/src/pages/document-viewer/file-error/index.less +4 -0
- web/src/pages/document-viewer/file-error/index.tsx +15 -0
- web/src/pages/document-viewer/hooks.ts +78 -0
- web/src/pages/document-viewer/index.tsx +4 -11
- web/src/pages/document-viewer/pdf/index.tsx +6 -1
- web/src/pages/login/index.tsx +2 -1
- web/src/pages/user-setting/model.ts +11 -0
- web/src/pages/user-setting/setting-model/hooks.ts +17 -1
- web/src/pages/user-setting/setting-model/index.tsx +13 -1
- web/src/services/userService.ts +5 -0
- web/src/utils/api.ts +1 -0
- web/typings.d.ts +0 -1
web/.umirc.ts
CHANGED
@@ -27,7 +27,7 @@ export default defineConfig({
|
|
27 |
devtool: 'source-map',
|
28 |
proxy: {
|
29 |
'/v1': {
|
30 |
-
target: '
|
31 |
changeOrigin: true,
|
32 |
// pathRewrite: { '^/v1': '/v1' },
|
33 |
},
|
|
|
27 |
devtool: 'source-map',
|
28 |
proxy: {
|
29 |
'/v1': {
|
30 |
+
target: '',
|
31 |
changeOrigin: true,
|
32 |
// pathRewrite: { '^/v1': '/v1' },
|
33 |
},
|
web/package-lock.json
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
web/package.json
CHANGED
@@ -23,10 +23,10 @@
|
|
23 |
"js-base64": "^3.7.5",
|
24 |
"jsencrypt": "^3.3.2",
|
25 |
"lodash": "^4.17.21",
|
|
|
26 |
"rc-tween-one": "^3.0.6",
|
27 |
"react-chat-elements": "^12.0.13",
|
28 |
"react-copy-to-clipboard": "^5.1.0",
|
29 |
-
"react-file-viewer": "^1.2.1",
|
30 |
"react-i18next": "^14.0.0",
|
31 |
"react-infinite-scroll-component": "^6.1.0",
|
32 |
"react-markdown": "^9.0.1",
|
|
|
23 |
"js-base64": "^3.7.5",
|
24 |
"jsencrypt": "^3.3.2",
|
25 |
"lodash": "^4.17.21",
|
26 |
+
"mammoth": "^1.7.2",
|
27 |
"rc-tween-one": "^3.0.6",
|
28 |
"react-chat-elements": "^12.0.13",
|
29 |
"react-copy-to-clipboard": "^5.1.0",
|
|
|
30 |
"react-i18next": "^14.0.0",
|
31 |
"react-infinite-scroll-component": "^6.1.0",
|
32 |
"react-markdown": "^9.0.1",
|
web/src/components/pdf-previewer/index.tsx
CHANGED
@@ -34,7 +34,7 @@ const HighlightPopup = ({
|
|
34 |
) : null;
|
35 |
|
36 |
const DocumentPreviewer = ({ chunk, documentId, visible }: IProps) => {
|
37 |
-
const
|
38 |
const { highlights: state, setWidthAndHeight } = useGetChunkHighlights(chunk);
|
39 |
const ref = useRef<(highlight: IHighlight) => void>(() => {});
|
40 |
const [loaded, setLoaded] = useState(false);
|
@@ -55,7 +55,7 @@ const DocumentPreviewer = ({ chunk, documentId, visible }: IProps) => {
|
|
55 |
return (
|
56 |
<div className={styles.documentContainer}>
|
57 |
<PdfLoader
|
58 |
-
url={
|
59 |
beforeLoad={<Skeleton active />}
|
60 |
workerSrc="/pdfjs-dist/pdf.worker.min.js"
|
61 |
>
|
|
|
34 |
) : null;
|
35 |
|
36 |
const DocumentPreviewer = ({ chunk, documentId, visible }: IProps) => {
|
37 |
+
const getDocumentUrl = useGetDocumentUrl(documentId);
|
38 |
const { highlights: state, setWidthAndHeight } = useGetChunkHighlights(chunk);
|
39 |
const ref = useRef<(highlight: IHighlight) => void>(() => {});
|
40 |
const [loaded, setLoaded] = useState(false);
|
|
|
55 |
return (
|
56 |
<div className={styles.documentContainer}>
|
57 |
<PdfLoader
|
58 |
+
url={getDocumentUrl()}
|
59 |
beforeLoad={<Skeleton active />}
|
60 |
workerSrc="/pdfjs-dist/pdf.worker.min.js"
|
61 |
>
|
web/src/constants/common.ts
CHANGED
@@ -69,6 +69,8 @@ export const FileMimeTypeMap = {
|
|
69 |
mp4: 'video/mp4',
|
70 |
};
|
71 |
|
|
|
|
|
72 |
//#region file preview
|
73 |
export const Images = [
|
74 |
'jpg',
|
@@ -84,7 +86,7 @@ export const Images = [
|
|
84 |
];
|
85 |
|
86 |
// Without FileViewer
|
87 |
-
export const ExceptiveType = ['xlsx', 'xls', 'pdf', ...Images];
|
88 |
|
89 |
-
export const SupportedPreviewDocumentTypes = [
|
90 |
//#endregion
|
|
|
69 |
mp4: 'video/mp4',
|
70 |
};
|
71 |
|
72 |
+
export const Domain = 'demo.ragflow.io';
|
73 |
+
|
74 |
//#region file preview
|
75 |
export const Images = [
|
76 |
'jpg',
|
|
|
86 |
];
|
87 |
|
88 |
// Without FileViewer
|
89 |
+
export const ExceptiveType = ['xlsx', 'xls', 'pdf', 'docx', ...Images];
|
90 |
|
91 |
+
export const SupportedPreviewDocumentTypes = [...ExceptiveType];
|
92 |
//#endregion
|
web/src/hooks/llmHooks.ts
CHANGED
@@ -4,7 +4,10 @@ import {
|
|
4 |
IMyLlmValue,
|
5 |
IThirdOAIModelCollection,
|
6 |
} from '@/interfaces/database/llm';
|
7 |
-
import {
|
|
|
|
|
|
|
8 |
import { sortLLmFactoryListBySpecifiedOrder } from '@/utils/commonUtil';
|
9 |
import { useCallback, useEffect, useMemo } from 'react';
|
10 |
import { useDispatch, useSelector } from 'umi';
|
@@ -211,7 +214,7 @@ export const useSaveTenantInfo = () => {
|
|
211 |
export const useAddLlm = () => {
|
212 |
const dispatch = useDispatch();
|
213 |
|
214 |
-
const
|
215 |
(requestBody: IAddLlmRequestBody) => {
|
216 |
return dispatch<any>({
|
217 |
type: 'settingModel/add_llm',
|
@@ -221,5 +224,21 @@ export const useAddLlm = () => {
|
|
221 |
[dispatch],
|
222 |
);
|
223 |
|
224 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
};
|
|
|
4 |
IMyLlmValue,
|
5 |
IThirdOAIModelCollection,
|
6 |
} from '@/interfaces/database/llm';
|
7 |
+
import {
|
8 |
+
IAddLlmRequestBody,
|
9 |
+
IDeleteLlmRequestBody,
|
10 |
+
} from '@/interfaces/request/llm';
|
11 |
import { sortLLmFactoryListBySpecifiedOrder } from '@/utils/commonUtil';
|
12 |
import { useCallback, useEffect, useMemo } from 'react';
|
13 |
import { useDispatch, useSelector } from 'umi';
|
|
|
214 |
export const useAddLlm = () => {
|
215 |
const dispatch = useDispatch();
|
216 |
|
217 |
+
const addLlm = useCallback(
|
218 |
(requestBody: IAddLlmRequestBody) => {
|
219 |
return dispatch<any>({
|
220 |
type: 'settingModel/add_llm',
|
|
|
224 |
[dispatch],
|
225 |
);
|
226 |
|
227 |
+
return addLlm;
|
228 |
+
};
|
229 |
+
|
230 |
+
export const useDeleteLlm = () => {
|
231 |
+
const dispatch = useDispatch();
|
232 |
+
|
233 |
+
const deleteLlm = useCallback(
|
234 |
+
(requestBody: IDeleteLlmRequestBody) => {
|
235 |
+
return dispatch<any>({
|
236 |
+
type: 'settingModel/delete_llm',
|
237 |
+
payload: requestBody,
|
238 |
+
});
|
239 |
+
},
|
240 |
+
[dispatch],
|
241 |
+
);
|
242 |
+
|
243 |
+
return deleteLlm;
|
244 |
};
|
web/src/interfaces/request/llm.ts
CHANGED
@@ -4,3 +4,8 @@ export interface IAddLlmRequestBody {
|
|
4 |
model_type: string;
|
5 |
api_base?: string; // chat|embedding|speech2text|image2text
|
6 |
}
|
|
|
|
|
|
|
|
|
|
|
|
4 |
model_type: string;
|
5 |
api_base?: string; // chat|embedding|speech2text|image2text
|
6 |
}
|
7 |
+
|
8 |
+
export interface IDeleteLlmRequestBody {
|
9 |
+
llm_factory: string; // Ollama
|
10 |
+
llm_name: string;
|
11 |
+
}
|
web/src/locales/en.ts
CHANGED
@@ -506,6 +506,7 @@ export default {
|
|
506 |
local: 'Local uploads',
|
507 |
s3: 'S3 uploads',
|
508 |
preview: 'Preview',
|
|
|
509 |
},
|
510 |
footer: {
|
511 |
profile: 'All rights reserved @ React',
|
|
|
506 |
local: 'Local uploads',
|
507 |
s3: 'S3 uploads',
|
508 |
preview: 'Preview',
|
509 |
+
fileError: 'File error',
|
510 |
},
|
511 |
footer: {
|
512 |
profile: 'All rights reserved @ React',
|
web/src/locales/zh-traditional.ts
CHANGED
@@ -469,6 +469,7 @@ export default {
|
|
469 |
local: '本地上傳',
|
470 |
s3: 'S3 上傳',
|
471 |
preview: '預覽',
|
|
|
472 |
},
|
473 |
footer: {
|
474 |
profile: '“保留所有權利 @ react”',
|
|
|
469 |
local: '本地上傳',
|
470 |
s3: 'S3 上傳',
|
471 |
preview: '預覽',
|
472 |
+
fileError: '文件錯誤',
|
473 |
},
|
474 |
footer: {
|
475 |
profile: '“保留所有權利 @ react”',
|
web/src/locales/zh.ts
CHANGED
@@ -487,6 +487,7 @@ export default {
|
|
487 |
local: '本地上传',
|
488 |
s3: 'S3 上传',
|
489 |
preview: '预览',
|
|
|
490 |
},
|
491 |
footer: {
|
492 |
profile: 'All rights reserved @ React',
|
|
|
487 |
local: '本地上传',
|
488 |
s3: 'S3 上传',
|
489 |
preview: '预览',
|
490 |
+
fileError: '文件错误',
|
491 |
},
|
492 |
footer: {
|
493 |
profile: 'All rights reserved @ React',
|
web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx
CHANGED
@@ -55,7 +55,7 @@ const PopoverContent = ({ record }: IProps) => {
|
|
55 |
{
|
56 |
key: 'process_duation',
|
57 |
label: t('processDuration'),
|
58 |
-
children: record.process_duation
|
59 |
},
|
60 |
{
|
61 |
key: 'progress_msg',
|
|
|
55 |
{
|
56 |
key: 'process_duation',
|
57 |
label: t('processDuration'),
|
58 |
+
children: `${record.process_duation} s`,
|
59 |
},
|
60 |
{
|
61 |
key: 'progress_msg',
|
web/src/pages/chat/chat-overview-modal/index.tsx
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
import LineChart from '@/components/line-chart';
|
|
|
2 |
import { useSetModalState, useTranslate } from '@/hooks/commonHooks';
|
3 |
import { IModalProps } from '@/interfaces/common';
|
4 |
import { IDialog, IStats } from '@/interfaces/database/chat';
|
@@ -80,7 +81,9 @@ const ChatOverviewModal = ({
|
|
80 |
<Flex gap={8} vertical>
|
81 |
{t('serviceApiEndpoint')}
|
82 |
<Paragraph copyable className={styles.linkText}>
|
83 |
-
https://
|
|
|
|
|
84 |
</Paragraph>
|
85 |
</Flex>
|
86 |
<Space size={'middle'}>
|
|
|
1 |
import LineChart from '@/components/line-chart';
|
2 |
+
import { Domain } from '@/constants/common';
|
3 |
import { useSetModalState, useTranslate } from '@/hooks/commonHooks';
|
4 |
import { IModalProps } from '@/interfaces/common';
|
5 |
import { IDialog, IStats } from '@/interfaces/database/chat';
|
|
|
81 |
<Flex gap={8} vertical>
|
82 |
{t('serviceApiEndpoint')}
|
83 |
<Paragraph copyable className={styles.linkText}>
|
84 |
+
https://
|
85 |
+
{location.hostname === Domain ? Domain : '<YOUR_MACHINE_IP>'}
|
86 |
+
/v1/api/
|
87 |
</Paragraph>
|
88 |
</Flex>
|
89 |
<Space size={'middle'}>
|
web/src/pages/chat/embed-modal/index.tsx
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import CopyToClipboard from '@/components/copy-to-clipboard';
|
2 |
import HightLightMarkdown from '@/components/highlight-markdown';
|
|
|
3 |
import { useTranslate } from '@/hooks/commonHooks';
|
4 |
import { IModalProps } from '@/interfaces/common';
|
5 |
import { Card, Modal, Tabs, TabsProps } from 'antd';
|
@@ -15,7 +16,7 @@ const EmbedModal = ({
|
|
15 |
const text = `
|
16 |
~~~ html
|
17 |
<iframe
|
18 |
-
src="https
|
19 |
style="width: 100%; height: 100%; min-height: 600px"
|
20 |
frameborder="0"
|
21 |
>
|
|
|
1 |
import CopyToClipboard from '@/components/copy-to-clipboard';
|
2 |
import HightLightMarkdown from '@/components/highlight-markdown';
|
3 |
+
import { Domain } from '@/constants/common';
|
4 |
import { useTranslate } from '@/hooks/commonHooks';
|
5 |
import { IModalProps } from '@/interfaces/common';
|
6 |
import { Card, Modal, Tabs, TabsProps } from 'antd';
|
|
|
16 |
const text = `
|
17 |
~~~ html
|
18 |
<iframe
|
19 |
+
src="https://${Domain}/chat/share?shared_id=${token}"
|
20 |
style="width: 100%; height: 100%; min-height: 600px"
|
21 |
frameborder="0"
|
22 |
>
|
web/src/pages/document-viewer/docx/index.less
ADDED
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Copyright (c) 2017 PlanGrid, Inc.
|
2 |
+
|
3 |
+
.docxViewerWrapper {
|
4 |
+
overflow-y: scroll;
|
5 |
+
height: 100%;
|
6 |
+
width: 100%;
|
7 |
+
|
8 |
+
.box {
|
9 |
+
width: 100%;
|
10 |
+
height: 100%;
|
11 |
+
}
|
12 |
+
|
13 |
+
:global(.document-container) {
|
14 |
+
padding: 30px;
|
15 |
+
width: 700px;
|
16 |
+
background: white;
|
17 |
+
margin: auto;
|
18 |
+
}
|
19 |
+
|
20 |
+
html,
|
21 |
+
bodyaddress,
|
22 |
+
blockquote,
|
23 |
+
body,
|
24 |
+
dd,
|
25 |
+
div,
|
26 |
+
dl,
|
27 |
+
dt,
|
28 |
+
fieldset,
|
29 |
+
form,
|
30 |
+
frame,
|
31 |
+
frameset,
|
32 |
+
h1,
|
33 |
+
h2,
|
34 |
+
h3,
|
35 |
+
h4,
|
36 |
+
h5,
|
37 |
+
h6,
|
38 |
+
noframes,
|
39 |
+
ol,
|
40 |
+
p,
|
41 |
+
ul,
|
42 |
+
center,
|
43 |
+
dir,
|
44 |
+
hr,
|
45 |
+
menu,
|
46 |
+
pre {
|
47 |
+
display: block;
|
48 |
+
unicode-bidi: embed;
|
49 |
+
}
|
50 |
+
li {
|
51 |
+
display: list-item;
|
52 |
+
list-style-type: disc;
|
53 |
+
}
|
54 |
+
head {
|
55 |
+
display: none;
|
56 |
+
}
|
57 |
+
table {
|
58 |
+
display: table;
|
59 |
+
}
|
60 |
+
img {
|
61 |
+
width: 100%;
|
62 |
+
}
|
63 |
+
tr {
|
64 |
+
display: table-row;
|
65 |
+
}
|
66 |
+
thead {
|
67 |
+
display: table-header-group;
|
68 |
+
}
|
69 |
+
tbody {
|
70 |
+
display: table-row-group;
|
71 |
+
}
|
72 |
+
tfoot {
|
73 |
+
display: table-footer-group;
|
74 |
+
}
|
75 |
+
col {
|
76 |
+
display: table-column;
|
77 |
+
}
|
78 |
+
colgroup {
|
79 |
+
display: table-column-group;
|
80 |
+
}
|
81 |
+
th {
|
82 |
+
display: table-cell;
|
83 |
+
}
|
84 |
+
td {
|
85 |
+
display: table-cell;
|
86 |
+
border-bottom: 1px solid #ccc;
|
87 |
+
border-right: 1px solid #ccc;
|
88 |
+
padding: 0.2em 0.5em;
|
89 |
+
}
|
90 |
+
caption {
|
91 |
+
display: table-caption;
|
92 |
+
}
|
93 |
+
th {
|
94 |
+
font-weight: bolder;
|
95 |
+
text-align: center;
|
96 |
+
}
|
97 |
+
caption {
|
98 |
+
text-align: center;
|
99 |
+
}
|
100 |
+
body {
|
101 |
+
margin: 8px;
|
102 |
+
}
|
103 |
+
h1 {
|
104 |
+
font-size: 2em;
|
105 |
+
margin: 0.67em 0;
|
106 |
+
}
|
107 |
+
h2 {
|
108 |
+
font-size: 1.5em;
|
109 |
+
margin: 0.75em 0;
|
110 |
+
}
|
111 |
+
h3 {
|
112 |
+
font-size: 1.17em;
|
113 |
+
margin: 0.83em 0;
|
114 |
+
}
|
115 |
+
h4,
|
116 |
+
p,
|
117 |
+
blockquote,
|
118 |
+
ul,
|
119 |
+
fieldset,
|
120 |
+
form,
|
121 |
+
ol,
|
122 |
+
dl,
|
123 |
+
dir,
|
124 |
+
menu {
|
125 |
+
margin: 1.12em 0;
|
126 |
+
}
|
127 |
+
h5 {
|
128 |
+
font-size: 0.83em;
|
129 |
+
margin: 1.5em 0;
|
130 |
+
}
|
131 |
+
h6 {
|
132 |
+
font-size: 0.75em;
|
133 |
+
margin: 1.67em 0;
|
134 |
+
}
|
135 |
+
h1,
|
136 |
+
h2,
|
137 |
+
h3,
|
138 |
+
h4,
|
139 |
+
h5,
|
140 |
+
h6,
|
141 |
+
b,
|
142 |
+
strong {
|
143 |
+
font-weight: bolder;
|
144 |
+
}
|
145 |
+
blockquote {
|
146 |
+
margin-left: 40px;
|
147 |
+
margin-right: 40px;
|
148 |
+
}
|
149 |
+
i,
|
150 |
+
cite,
|
151 |
+
em,
|
152 |
+
var,
|
153 |
+
address {
|
154 |
+
font-style: italic;
|
155 |
+
}
|
156 |
+
pre,
|
157 |
+
tt,
|
158 |
+
code,
|
159 |
+
kbd,
|
160 |
+
samp {
|
161 |
+
font-family: monospace;
|
162 |
+
}
|
163 |
+
pre {
|
164 |
+
white-space: pre;
|
165 |
+
}
|
166 |
+
button,
|
167 |
+
textarea,
|
168 |
+
input,
|
169 |
+
select {
|
170 |
+
display: inline-block;
|
171 |
+
}
|
172 |
+
big {
|
173 |
+
font-size: 1.17em;
|
174 |
+
}
|
175 |
+
small,
|
176 |
+
sub,
|
177 |
+
sup {
|
178 |
+
font-size: 0.83em;
|
179 |
+
}
|
180 |
+
sub {
|
181 |
+
vertical-align: sub;
|
182 |
+
}
|
183 |
+
sup {
|
184 |
+
vertical-align: super;
|
185 |
+
}
|
186 |
+
table {
|
187 |
+
border-spacing: 2px;
|
188 |
+
}
|
189 |
+
thead,
|
190 |
+
tbody,
|
191 |
+
tfoot {
|
192 |
+
vertical-align: middle;
|
193 |
+
}
|
194 |
+
td,
|
195 |
+
th,
|
196 |
+
tr {
|
197 |
+
vertical-align: inherit;
|
198 |
+
}
|
199 |
+
s,
|
200 |
+
strike,
|
201 |
+
del {
|
202 |
+
text-decoration: line-through;
|
203 |
+
}
|
204 |
+
hr {
|
205 |
+
border: 1px inset;
|
206 |
+
}
|
207 |
+
ol,
|
208 |
+
ul,
|
209 |
+
dir,
|
210 |
+
menu,
|
211 |
+
dd {
|
212 |
+
margin-left: 40px;
|
213 |
+
}
|
214 |
+
ol {
|
215 |
+
list-style-type: decimal;
|
216 |
+
}
|
217 |
+
ol ul,
|
218 |
+
ol ul,
|
219 |
+
ul ol,
|
220 |
+
ul ol,
|
221 |
+
ul ul,
|
222 |
+
ul ul,
|
223 |
+
ol ol,
|
224 |
+
ol ol {
|
225 |
+
margin-top: 0;
|
226 |
+
margin-bottom: 0;
|
227 |
+
}
|
228 |
+
u,
|
229 |
+
ins {
|
230 |
+
text-decoration: underline;
|
231 |
+
}
|
232 |
+
br:before {
|
233 |
+
content: '\A';
|
234 |
+
white-space: pre-line;
|
235 |
+
}
|
236 |
+
center {
|
237 |
+
text-align: center;
|
238 |
+
}
|
239 |
+
:link,
|
240 |
+
:visited {
|
241 |
+
text-decoration: underline;
|
242 |
+
}
|
243 |
+
:focus {
|
244 |
+
outline: thin dotted invert;
|
245 |
+
}
|
246 |
+
/* Begin bidirectionality settings (do not change) */
|
247 |
+
BDO[DIR='ltr'] {
|
248 |
+
direction: ltr;
|
249 |
+
unicode-bidi: bidi-override;
|
250 |
+
}
|
251 |
+
BDO[DIR='rtl'] {
|
252 |
+
direction: rtl;
|
253 |
+
unicode-bidi: bidi-override;
|
254 |
+
}
|
255 |
+
*[DIR='ltr'] {
|
256 |
+
direction: ltr;
|
257 |
+
unicode-bidi: embed;
|
258 |
+
}
|
259 |
+
*[DIR='rtl'] {
|
260 |
+
direction: rtl;
|
261 |
+
unicode-bidi: embed;
|
262 |
+
}
|
263 |
+
@media print {
|
264 |
+
h1 {
|
265 |
+
page-break-before: always;
|
266 |
+
}
|
267 |
+
h1,
|
268 |
+
h2,
|
269 |
+
h3,
|
270 |
+
h4,
|
271 |
+
h5,
|
272 |
+
h6 {
|
273 |
+
page-break-after: avoid;
|
274 |
+
}
|
275 |
+
ul,
|
276 |
+
ol,
|
277 |
+
dl {
|
278 |
+
page-break-before: avoid;
|
279 |
+
}
|
280 |
+
}
|
281 |
+
}
|
web/src/pages/document-viewer/docx/index.tsx
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Spin } from 'antd';
|
2 |
+
import FileError from '../file-error';
|
3 |
+
|
4 |
+
import { useFetchDocx } from '../hooks';
|
5 |
+
import styles from './index.less';
|
6 |
+
|
7 |
+
const Docx = ({ filePath }: { filePath: string }) => {
|
8 |
+
const { succeed, containerRef } = useFetchDocx(filePath);
|
9 |
+
|
10 |
+
return (
|
11 |
+
<>
|
12 |
+
{succeed ? (
|
13 |
+
<section className={styles.docxViewerWrapper}>
|
14 |
+
<div id="docx" ref={containerRef} className={styles.box}>
|
15 |
+
<Spin />
|
16 |
+
</div>
|
17 |
+
</section>
|
18 |
+
) : (
|
19 |
+
<FileError></FileError>
|
20 |
+
)}
|
21 |
+
</>
|
22 |
+
);
|
23 |
+
};
|
24 |
+
|
25 |
+
export default Docx;
|
web/src/pages/document-viewer/excel/index.tsx
CHANGED
@@ -1,35 +1,19 @@
|
|
1 |
-
import jsPreviewExcel from '@js-preview/excel';
|
2 |
import '@js-preview/excel/lib/index.css';
|
3 |
-
import
|
|
|
4 |
|
5 |
const Excel = ({ filePath }: { filePath: string }) => {
|
6 |
-
const
|
7 |
-
const myExcelPreviewer = jsPreviewExcel.init(
|
8 |
-
document.getElementById('excel'),
|
9 |
-
);
|
10 |
-
const jsonFile = new XMLHttpRequest();
|
11 |
-
jsonFile.open('GET', filePath, true);
|
12 |
-
jsonFile.send();
|
13 |
-
jsonFile.responseType = 'arraybuffer';
|
14 |
-
jsonFile.onreadystatechange = () => {
|
15 |
-
if (jsonFile.readyState === 4 && jsonFile.status === 200) {
|
16 |
-
myExcelPreviewer
|
17 |
-
.preview(jsonFile.response)
|
18 |
-
.then((res: any) => {
|
19 |
-
console.log('succeed');
|
20 |
-
})
|
21 |
-
.catch((e) => {
|
22 |
-
console.log('failed', e);
|
23 |
-
});
|
24 |
-
}
|
25 |
-
};
|
26 |
-
};
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
33 |
};
|
34 |
|
35 |
export default Excel;
|
|
|
|
|
1 |
import '@js-preview/excel/lib/index.css';
|
2 |
+
import FileError from '../file-error';
|
3 |
+
import { useFetchExcel } from '../hooks';
|
4 |
|
5 |
const Excel = ({ filePath }: { filePath: string }) => {
|
6 |
+
const { status, containerRef } = useFetchExcel(filePath);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
+
return (
|
9 |
+
<div
|
10 |
+
id="excel"
|
11 |
+
ref={containerRef}
|
12 |
+
style={{ height: '100%', width: '100%' }}
|
13 |
+
>
|
14 |
+
{status || <FileError></FileError>}
|
15 |
+
</div>
|
16 |
+
);
|
17 |
};
|
18 |
|
19 |
export default Excel;
|
web/src/pages/document-viewer/file-error/index.less
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.errorWrapper {
|
2 |
+
width: 100%;
|
3 |
+
height: 100%;
|
4 |
+
}
|
web/src/pages/document-viewer/file-error/index.tsx
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Alert, Flex } from 'antd';
|
2 |
+
|
3 |
+
import { useTranslate } from '@/hooks/commonHooks';
|
4 |
+
import styles from './index.less';
|
5 |
+
|
6 |
+
const FileError = () => {
|
7 |
+
const { t } = useTranslate('fileManager');
|
8 |
+
return (
|
9 |
+
<Flex align="center" justify="center" className={styles.errorWrapper}>
|
10 |
+
<Alert type="error" message={<h1>{t('fileError')}</h1>}></Alert>
|
11 |
+
</Flex>
|
12 |
+
);
|
13 |
+
};
|
14 |
+
|
15 |
+
export default FileError;
|
web/src/pages/document-viewer/hooks.ts
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import jsPreviewExcel from '@js-preview/excel';
|
2 |
+
import axios from 'axios';
|
3 |
+
import mammoth from 'mammoth';
|
4 |
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
5 |
+
|
6 |
+
const useFetchDocument = () => {
|
7 |
+
const fetchDocument = useCallback((api: string) => {
|
8 |
+
return axios.get(api, { responseType: 'arraybuffer' });
|
9 |
+
}, []);
|
10 |
+
|
11 |
+
return fetchDocument;
|
12 |
+
};
|
13 |
+
|
14 |
+
export const useFetchExcel = (filePath: string) => {
|
15 |
+
const [status, setStatus] = useState(true);
|
16 |
+
const fetchDocument = useFetchDocument();
|
17 |
+
const containerRef = useRef<HTMLDivElement>(null);
|
18 |
+
|
19 |
+
const fetchDocumentAsync = useCallback(async () => {
|
20 |
+
let myExcelPreviewer;
|
21 |
+
if (containerRef.current) {
|
22 |
+
myExcelPreviewer = jsPreviewExcel.init(containerRef.current);
|
23 |
+
}
|
24 |
+
const jsonFile = await fetchDocument(filePath);
|
25 |
+
myExcelPreviewer
|
26 |
+
?.preview(jsonFile.data)
|
27 |
+
.then(() => {
|
28 |
+
console.log('succeed');
|
29 |
+
setStatus(true);
|
30 |
+
})
|
31 |
+
.catch((e) => {
|
32 |
+
console.warn('failed', e);
|
33 |
+
myExcelPreviewer.destroy();
|
34 |
+
setStatus(false);
|
35 |
+
});
|
36 |
+
}, [filePath, fetchDocument]);
|
37 |
+
|
38 |
+
useEffect(() => {
|
39 |
+
fetchDocumentAsync();
|
40 |
+
}, [fetchDocumentAsync]);
|
41 |
+
|
42 |
+
return { status, containerRef };
|
43 |
+
};
|
44 |
+
|
45 |
+
export const useFetchDocx = (filePath: string) => {
|
46 |
+
const [succeed, setSucceed] = useState(true);
|
47 |
+
const fetchDocument = useFetchDocument();
|
48 |
+
const containerRef = useRef<HTMLDivElement>(null);
|
49 |
+
|
50 |
+
const fetchDocumentAsync = useCallback(async () => {
|
51 |
+
const jsonFile = await fetchDocument(filePath);
|
52 |
+
mammoth
|
53 |
+
.convertToHtml(
|
54 |
+
{ arrayBuffer: jsonFile.data },
|
55 |
+
{ includeDefaultStyleMap: true },
|
56 |
+
)
|
57 |
+
.then((result) => {
|
58 |
+
setSucceed(true);
|
59 |
+
const docEl = document.createElement('div');
|
60 |
+
docEl.className = 'document-container';
|
61 |
+
docEl.innerHTML = result.value;
|
62 |
+
const container = containerRef.current;
|
63 |
+
if (container) {
|
64 |
+
container.innerHTML = docEl.outerHTML;
|
65 |
+
}
|
66 |
+
})
|
67 |
+
.catch((a) => {
|
68 |
+
setSucceed(false);
|
69 |
+
console.warn('alexei: something went wrong', a);
|
70 |
+
});
|
71 |
+
}, [filePath, fetchDocument]);
|
72 |
+
|
73 |
+
useEffect(() => {
|
74 |
+
fetchDocumentAsync();
|
75 |
+
}, [fetchDocumentAsync]);
|
76 |
+
|
77 |
+
return { succeed, containerRef };
|
78 |
+
};
|
web/src/pages/document-viewer/index.tsx
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
import {
|
2 |
import { api_host } from '@/utils/api';
|
3 |
import { Flex, Image } from 'antd';
|
4 |
-
import FileViewer from 'react-file-viewer';
|
5 |
import { useParams, useSearchParams } from 'umi';
|
|
|
6 |
import Excel from './excel';
|
7 |
import Pdf from './pdf';
|
8 |
|
@@ -10,18 +10,12 @@ import styles from './index.less';
|
|
10 |
|
11 |
// TODO: The interface returns an incorrect content-type for the SVG.
|
12 |
|
13 |
-
const isNotExceptiveType = (ext: string) => ExceptiveType.indexOf(ext) === -1;
|
14 |
-
|
15 |
const DocumentViewer = () => {
|
16 |
const { id: documentId } = useParams();
|
17 |
const api = `${api_host}/file/get/${documentId}`;
|
18 |
const [currentQueryParameters] = useSearchParams();
|
19 |
const ext = currentQueryParameters.get('ext');
|
20 |
|
21 |
-
const onError = (e: any) => {
|
22 |
-
console.error(e, 'error in file-viewer');
|
23 |
-
};
|
24 |
-
|
25 |
return (
|
26 |
<section className={styles.viewerWrapper}>
|
27 |
{Images.includes(ext!) && (
|
@@ -31,9 +25,8 @@ const DocumentViewer = () => {
|
|
31 |
)}
|
32 |
{ext === 'pdf' && <Pdf url={api}></Pdf>}
|
33 |
{(ext === 'xlsx' || ext === 'xls') && <Excel filePath={api}></Excel>}
|
34 |
-
|
35 |
-
|
36 |
-
)}
|
37 |
</section>
|
38 |
);
|
39 |
};
|
|
|
1 |
+
import { Images } from '@/constants/common';
|
2 |
import { api_host } from '@/utils/api';
|
3 |
import { Flex, Image } from 'antd';
|
|
|
4 |
import { useParams, useSearchParams } from 'umi';
|
5 |
+
import Docx from './docx';
|
6 |
import Excel from './excel';
|
7 |
import Pdf from './pdf';
|
8 |
|
|
|
10 |
|
11 |
// TODO: The interface returns an incorrect content-type for the SVG.
|
12 |
|
|
|
|
|
13 |
const DocumentViewer = () => {
|
14 |
const { id: documentId } = useParams();
|
15 |
const api = `${api_host}/file/get/${documentId}`;
|
16 |
const [currentQueryParameters] = useSearchParams();
|
17 |
const ext = currentQueryParameters.get('ext');
|
18 |
|
|
|
|
|
|
|
|
|
19 |
return (
|
20 |
<section className={styles.viewerWrapper}>
|
21 |
{Images.includes(ext!) && (
|
|
|
25 |
)}
|
26 |
{ext === 'pdf' && <Pdf url={api}></Pdf>}
|
27 |
{(ext === 'xlsx' || ext === 'xls') && <Excel filePath={api}></Excel>}
|
28 |
+
|
29 |
+
{ext === 'docx' && <Docx filePath={api}></Docx>}
|
|
|
30 |
</section>
|
31 |
);
|
32 |
};
|
web/src/pages/document-viewer/pdf/index.tsx
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import { Skeleton } from 'antd';
|
2 |
import { PdfHighlighter, PdfLoader } from 'react-pdf-highlighter';
|
|
|
3 |
|
4 |
interface IProps {
|
5 |
url: string;
|
@@ -9,11 +10,15 @@ const DocumentPreviewer = ({ url }: IProps) => {
|
|
9 |
const resetHash = () => {};
|
10 |
|
11 |
return (
|
12 |
-
<div style={{ width: '100%' }}>
|
13 |
<PdfLoader
|
14 |
url={url}
|
15 |
beforeLoad={<Skeleton active />}
|
16 |
workerSrc="/pdfjs-dist/pdf.worker.min.js"
|
|
|
|
|
|
|
|
|
17 |
>
|
18 |
{(pdfDocument) => {
|
19 |
return (
|
|
|
1 |
import { Skeleton } from 'antd';
|
2 |
import { PdfHighlighter, PdfLoader } from 'react-pdf-highlighter';
|
3 |
+
import FileError from '../file-error';
|
4 |
|
5 |
interface IProps {
|
6 |
url: string;
|
|
|
10 |
const resetHash = () => {};
|
11 |
|
12 |
return (
|
13 |
+
<div style={{ width: '100%', height: '100%' }}>
|
14 |
<PdfLoader
|
15 |
url={url}
|
16 |
beforeLoad={<Skeleton active />}
|
17 |
workerSrc="/pdfjs-dist/pdf.worker.min.js"
|
18 |
+
errorMessage={<FileError></FileError>}
|
19 |
+
onError={(e) => {
|
20 |
+
console.warn(e);
|
21 |
+
}}
|
22 |
>
|
23 |
{(pdfDocument) => {
|
24 |
return (
|
web/src/pages/login/index.tsx
CHANGED
@@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|
7 |
import { Icon, useNavigate } from 'umi';
|
8 |
import RightPanel from './right-panel';
|
9 |
|
|
|
10 |
import styles from './index.less';
|
11 |
|
12 |
const Login = () => {
|
@@ -167,7 +168,7 @@ const Login = () => {
|
|
167 |
Sign in with Google
|
168 |
</div>
|
169 |
</Button> */}
|
170 |
-
{location.host ===
|
171 |
<Button
|
172 |
block
|
173 |
size="large"
|
|
|
7 |
import { Icon, useNavigate } from 'umi';
|
8 |
import RightPanel from './right-panel';
|
9 |
|
10 |
+
import { Domain } from '@/constants/common';
|
11 |
import styles from './index.less';
|
12 |
|
13 |
const Login = () => {
|
|
|
168 |
Sign in with Google
|
169 |
</div>
|
170 |
</Button> */}
|
171 |
+
{location.host === Domain && (
|
172 |
<Button
|
173 |
block
|
174 |
size="large"
|
web/src/pages/user-setting/model.ts
CHANGED
@@ -167,6 +167,17 @@ const model: DvaModel<SettingModelState> = {
|
|
167 |
}
|
168 |
return retcode;
|
169 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
170 |
},
|
171 |
};
|
172 |
export default model;
|
|
|
167 |
}
|
168 |
return retcode;
|
169 |
},
|
170 |
+
*delete_llm({ payload = {} }, { call, put }) {
|
171 |
+
const { data } = yield call(userService.delete_llm, payload);
|
172 |
+
const { retcode } = data;
|
173 |
+
if (retcode === 0) {
|
174 |
+
message.success(i18n.t('message.deleted'));
|
175 |
+
|
176 |
+
yield put({ type: 'my_llm' });
|
177 |
+
yield put({ type: 'factories_list' });
|
178 |
+
}
|
179 |
+
return retcode;
|
180 |
+
},
|
181 |
},
|
182 |
};
|
183 |
export default model;
|
web/src/pages/user-setting/setting-model/hooks.ts
CHANGED
@@ -1,8 +1,9 @@
|
|
1 |
-
import { useSetModalState } from '@/hooks/commonHooks';
|
2 |
import {
|
3 |
IApiKeySavingParams,
|
4 |
ISystemModelSettingSavingParams,
|
5 |
useAddLlm,
|
|
|
6 |
useFetchLlmList,
|
7 |
useSaveApiKey,
|
8 |
useSaveTenantInfo,
|
@@ -164,3 +165,18 @@ export const useSubmitOllama = () => {
|
|
164 |
selectedLlmFactory,
|
165 |
};
|
166 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useSetModalState, useShowDeleteConfirm } from '@/hooks/commonHooks';
|
2 |
import {
|
3 |
IApiKeySavingParams,
|
4 |
ISystemModelSettingSavingParams,
|
5 |
useAddLlm,
|
6 |
+
useDeleteLlm,
|
7 |
useFetchLlmList,
|
8 |
useSaveApiKey,
|
9 |
useSaveTenantInfo,
|
|
|
165 |
selectedLlmFactory,
|
166 |
};
|
167 |
};
|
168 |
+
|
169 |
+
export const useHandleDeleteLlm = (llmFactory: string) => {
|
170 |
+
const deleteLlm = useDeleteLlm();
|
171 |
+
const showDeleteConfirm = useShowDeleteConfirm();
|
172 |
+
|
173 |
+
const handleDeleteLlm = (name: string) => () => {
|
174 |
+
showDeleteConfirm({
|
175 |
+
onOk: async () => {
|
176 |
+
deleteLlm({ llm_factory: llmFactory, llm_name: name });
|
177 |
+
},
|
178 |
+
});
|
179 |
+
};
|
180 |
+
|
181 |
+
return { handleDeleteLlm };
|
182 |
+
};
|
web/src/pages/user-setting/setting-model/index.tsx
CHANGED
@@ -6,7 +6,11 @@ import {
|
|
6 |
useFetchLlmFactoryListOnMount,
|
7 |
useFetchMyLlmListOnMount,
|
8 |
} from '@/hooks/llmHooks';
|
9 |
-
import {
|
|
|
|
|
|
|
|
|
10 |
import {
|
11 |
Avatar,
|
12 |
Button,
|
@@ -21,6 +25,7 @@ import {
|
|
21 |
Space,
|
22 |
Spin,
|
23 |
Tag,
|
|
|
24 |
Typography,
|
25 |
} from 'antd';
|
26 |
import { useCallback } from 'react';
|
@@ -28,6 +33,7 @@ import SettingTitle from '../components/setting-title';
|
|
28 |
import { isLocalLlmFactory } from '../utils';
|
29 |
import ApiKeyModal from './api-key-modal';
|
30 |
import {
|
|
|
31 |
useSelectModelProvidersLoading,
|
32 |
useSubmitApiKey,
|
33 |
useSubmitOllama,
|
@@ -67,6 +73,7 @@ interface IModelCardProps {
|
|
67 |
const ModelCard = ({ item, clickApiKey }: IModelCardProps) => {
|
68 |
const { visible, switchVisible } = useSetModalState();
|
69 |
const { t } = useTranslate('setting');
|
|
|
70 |
|
71 |
const handleApiKeyClick = () => {
|
72 |
clickApiKey(item.name);
|
@@ -113,6 +120,11 @@ const ModelCard = ({ item, clickApiKey }: IModelCardProps) => {
|
|
113 |
<List.Item>
|
114 |
<Space>
|
115 |
{item.name} <Tag color="#b8b8b8">{item.type}</Tag>
|
|
|
|
|
|
|
|
|
|
|
116 |
</Space>
|
117 |
</List.Item>
|
118 |
)}
|
|
|
6 |
useFetchLlmFactoryListOnMount,
|
7 |
useFetchMyLlmListOnMount,
|
8 |
} from '@/hooks/llmHooks';
|
9 |
+
import {
|
10 |
+
CloseCircleOutlined,
|
11 |
+
SettingOutlined,
|
12 |
+
UserOutlined,
|
13 |
+
} from '@ant-design/icons';
|
14 |
import {
|
15 |
Avatar,
|
16 |
Button,
|
|
|
25 |
Space,
|
26 |
Spin,
|
27 |
Tag,
|
28 |
+
Tooltip,
|
29 |
Typography,
|
30 |
} from 'antd';
|
31 |
import { useCallback } from 'react';
|
|
|
33 |
import { isLocalLlmFactory } from '../utils';
|
34 |
import ApiKeyModal from './api-key-modal';
|
35 |
import {
|
36 |
+
useHandleDeleteLlm,
|
37 |
useSelectModelProvidersLoading,
|
38 |
useSubmitApiKey,
|
39 |
useSubmitOllama,
|
|
|
73 |
const ModelCard = ({ item, clickApiKey }: IModelCardProps) => {
|
74 |
const { visible, switchVisible } = useSetModalState();
|
75 |
const { t } = useTranslate('setting');
|
76 |
+
const { handleDeleteLlm } = useHandleDeleteLlm(item.name);
|
77 |
|
78 |
const handleApiKeyClick = () => {
|
79 |
clickApiKey(item.name);
|
|
|
120 |
<List.Item>
|
121 |
<Space>
|
122 |
{item.name} <Tag color="#b8b8b8">{item.type}</Tag>
|
123 |
+
<Tooltip title={t('delete', { keyPrefix: 'common' })}>
|
124 |
+
<Button type={'text'} onClick={handleDeleteLlm(item.name)}>
|
125 |
+
<CloseCircleOutlined style={{ color: '#D92D20' }} />
|
126 |
+
</Button>
|
127 |
+
</Tooltip>
|
128 |
</Space>
|
129 |
</List.Item>
|
130 |
)}
|
web/src/services/userService.ts
CHANGED
@@ -15,6 +15,7 @@ const {
|
|
15 |
set_api_key,
|
16 |
set_tenant_info,
|
17 |
add_llm,
|
|
|
18 |
} = api;
|
19 |
|
20 |
const methods = {
|
@@ -66,6 +67,10 @@ const methods = {
|
|
66 |
url: add_llm,
|
67 |
method: 'post',
|
68 |
},
|
|
|
|
|
|
|
|
|
69 |
} as const;
|
70 |
|
71 |
const userService = registerServer<keyof typeof methods>(methods, request);
|
|
|
15 |
set_api_key,
|
16 |
set_tenant_info,
|
17 |
add_llm,
|
18 |
+
delete_llm,
|
19 |
} = api;
|
20 |
|
21 |
const methods = {
|
|
|
67 |
url: add_llm,
|
68 |
method: 'post',
|
69 |
},
|
70 |
+
delete_llm: {
|
71 |
+
url: delete_llm,
|
72 |
+
method: 'post',
|
73 |
+
},
|
74 |
} as const;
|
75 |
|
76 |
const userService = registerServer<keyof typeof methods>(methods, request);
|
web/src/utils/api.ts
CHANGED
@@ -18,6 +18,7 @@ export default {
|
|
18 |
my_llm: `${api_host}/llm/my_llms`,
|
19 |
set_api_key: `${api_host}/llm/set_api_key`,
|
20 |
add_llm: `${api_host}/llm/add_llm`,
|
|
|
21 |
|
22 |
// knowledge base
|
23 |
kb_list: `${api_host}/kb/list`,
|
|
|
18 |
my_llm: `${api_host}/llm/my_llms`,
|
19 |
set_api_key: `${api_host}/llm/set_api_key`,
|
20 |
add_llm: `${api_host}/llm/add_llm`,
|
21 |
+
delete_llm: `${api_host}/llm/delete_llm`,
|
22 |
|
23 |
// knowledge base
|
24 |
kb_list: `${api_host}/kb/list`,
|
web/typings.d.ts
CHANGED
@@ -10,7 +10,6 @@ import { LoginModelState } from '@/pages/login/model';
|
|
10 |
import { SettingModelState } from '@/pages/user-setting/model';
|
11 |
|
12 |
declare module 'lodash';
|
13 |
-
declare module 'react-file-viewer';
|
14 |
|
15 |
function useSelector<TState = RootState, TSelected = unknown>(
|
16 |
selector: (state: TState) => TSelected,
|
|
|
10 |
import { SettingModelState } from '@/pages/user-setting/model';
|
11 |
|
12 |
declare module 'lodash';
|
|
|
13 |
|
14 |
function useSelector<TState = RootState, TSelected = unknown>(
|
15 |
selector: (state: TState) => TSelected,
|