mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-05-16 19:46:53 +08:00
feat: support DeepSeek (#667)
### What problem does this PR solve? #666 feat: support DeepSeek feat: preview word and excel ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
eb27a4309e
commit
a553dc8dbd
1827
web/package-lock.json
generated
1827
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@
|
||||
"author": "zhaofengchao <13723060510@163.com>",
|
||||
"scripts": {
|
||||
"build": "umi build",
|
||||
"dev": "cross-env PORT=9000 umi dev",
|
||||
"dev": "cross-env PORT=9200 umi dev",
|
||||
"postinstall": "umi setup",
|
||||
"lint": "umi lint --eslint-only",
|
||||
"setup": "umi setup",
|
||||
@ -13,6 +13,7 @@
|
||||
"@ant-design/icons": "^5.2.6",
|
||||
"@ant-design/pro-components": "^2.6.46",
|
||||
"@ant-design/pro-layout": "^7.17.16",
|
||||
"@js-preview/excel": "^1.7.8",
|
||||
"ahooks": "^3.7.10",
|
||||
"antd": "^5.12.7",
|
||||
"axios": "^1.6.3",
|
||||
@ -25,6 +26,7 @@
|
||||
"rc-tween-one": "^3.0.6",
|
||||
"react-chat-elements": "^12.0.13",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-file-viewer": "^1.2.1",
|
||||
"react-i18next": "^14.0.0",
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
|
6
web/src/assets/svg/llm/deepseek.svg
Normal file
6
web/src/assets/svg/llm/deepseek.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg t="1715133624982" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4263"
|
||||
width="200" height="200">
|
||||
<path
|
||||
d="M320.512 804.864C46.08 676.864 77.824 274.432 362.496 274.432c34.816 0 86.016-7.168 114.688-14.336 59.392-16.384 99.328-10.24 69.632 10.24-9.216 7.168-15.36 19.456-13.312 28.672 5.12 20.48 158.72 161.792 177.152 161.792 27.648 0 27.648-32.768 1.024-57.344-43.008-38.912-55.296-90.112-35.84-141.312l9.216-26.624 54.272 52.224c35.84 34.816 58.368 49.152 68.608 44.032 9.216-4.096 30.72-9.216 49.152-12.288 18.432-2.048 38.912-10.24 45.056-18.432 19.456-23.552 43.008-17.408 35.84 9.216-3.072 12.288-6.144 27.648-6.144 34.816 0 23.552-62.464 83.968-92.16 90.112-23.552 5.12-30.72 12.288-30.72 30.72 0 46.08-38.912 148.48-75.776 198.656l-37.888 51.2 36.864 15.36c56.32 23.552 40.96 41.984-37.888 43.008-43.008 1.024-75.776 7.168-92.16 18.432-68.608 45.056-198.656 50.176-281.6 12.288z m251.904-86.016c-24.576-27.648-66.56-79.872-93.184-117.76-69.632-98.304-158.72-150.528-256-150.528-37.888 0-38.912 1.024-38.912 34.816 0 94.208 99.328 240.64 175.104 257.024 38.912 9.216 59.392-7.168 39.936-29.696-7.168-9.216-10.24-23.552-6.144-31.744 5.12-14.336 9.216-14.336 38.912 1.024 18.432 9.216 50.176 29.696 69.632 45.056 35.84 27.648 58.368 37.888 96.256 39.936 14.336 1.024 9.216-10.24-25.6-48.128z m88.064-145.408c8.192-13.312-31.744-78.848-56.32-92.16-10.24-6.144-26.624-10.24-34.816-10.24-23.552 0-20.48 27.648 4.096 33.792 13.312 3.072 20.48 14.336 20.48 29.696 0 13.312 5.12 29.696 12.288 36.864 15.36 15.36 46.08 16.384 54.272 2.048z"
|
||||
fill="#4D6BFE" p-id="4264"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -46,3 +46,25 @@ export const LanguageTranslationMap = {
|
||||
Chinese: 'zh',
|
||||
'Traditional Chinese': 'zh-TRADITIONAL',
|
||||
};
|
||||
|
||||
export const FileMimeTypeMap = {
|
||||
bmp: 'image/bmp',
|
||||
csv: 'text/csv',
|
||||
odt: 'application/vnd.oasis.opendocument.text',
|
||||
doc: 'application/msword',
|
||||
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
gif: 'image/gif',
|
||||
htm: 'text/htm',
|
||||
html: 'text/html',
|
||||
jpg: 'image/jpg',
|
||||
jpeg: 'image/jpeg',
|
||||
pdf: 'application/pdf',
|
||||
png: 'image/png',
|
||||
ppt: 'application/vnd.ms-powerpoint',
|
||||
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
tiff: 'image/tiff',
|
||||
txt: 'text/plain',
|
||||
xls: 'application/vnd.ms-excel',
|
||||
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
mp4: 'video/mp4',
|
||||
};
|
||||
|
35
web/src/pages/document-viewer/excel/index.tsx
Normal file
35
web/src/pages/document-viewer/excel/index.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import jsPreviewExcel from '@js-preview/excel';
|
||||
import '@js-preview/excel/lib/index.css';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const Excel = ({ filePath }: { filePath: string }) => {
|
||||
const fetchDocument = async () => {
|
||||
const myExcelPreviewer = jsPreviewExcel.init(
|
||||
document.getElementById('excel'),
|
||||
);
|
||||
const jsonFile = new XMLHttpRequest();
|
||||
jsonFile.open('GET', filePath, true);
|
||||
jsonFile.send();
|
||||
jsonFile.responseType = 'arraybuffer';
|
||||
jsonFile.onreadystatechange = () => {
|
||||
if (jsonFile.readyState === 4 && jsonFile.status === 200) {
|
||||
myExcelPreviewer
|
||||
.preview(jsonFile.response)
|
||||
.then((res: any) => {
|
||||
console.log('succeed');
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log('failed', e);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchDocument();
|
||||
}, []);
|
||||
|
||||
return <div id="excel" style={{ height: '100%' }}></div>;
|
||||
};
|
||||
|
||||
export default Excel;
|
8
web/src/pages/document-viewer/index.less
Normal file
8
web/src/pages/document-viewer/index.less
Normal file
@ -0,0 +1,8 @@
|
||||
.viewerWrapper {
|
||||
width: 100%;
|
||||
:global {
|
||||
.pdf-canvas {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
28
web/src/pages/document-viewer/index.tsx
Normal file
28
web/src/pages/document-viewer/index.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { api_host } from '@/utils/api';
|
||||
import FileViewer from 'react-file-viewer';
|
||||
import { useParams, useSearchParams } from 'umi';
|
||||
import Excel from './excel';
|
||||
|
||||
import styles from './index.less';
|
||||
|
||||
const DocumentViewer = () => {
|
||||
const { id: documentId } = useParams();
|
||||
const api = `${api_host}/file/get/${documentId}`;
|
||||
const [currentQueryParameters] = useSearchParams();
|
||||
const ext = currentQueryParameters.get('ext');
|
||||
|
||||
const onError = (e: any) => {
|
||||
console.error(e, 'error in file-viewer');
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={styles.viewerWrapper}>
|
||||
{ext === 'xlsx' && <Excel filePath={api}></Excel>}
|
||||
{ext !== 'xlsx' && (
|
||||
<FileViewer fileType={ext} filePath={api} onError={onError} />
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocumentViewer;
|
@ -9,7 +9,7 @@ import {
|
||||
LinkOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { Button, Space, Tooltip } from 'antd';
|
||||
import { useHandleDeleteFile } from '../hooks';
|
||||
import { useHandleDeleteFile, useNavigateToDocument } from '../hooks';
|
||||
|
||||
import styles from './index.less';
|
||||
|
||||
@ -35,6 +35,7 @@ const ActionCell = ({
|
||||
[documentId],
|
||||
setSelectedRowKeys,
|
||||
);
|
||||
const navigateToDocument = useNavigateToDocument(record.id, record.name);
|
||||
|
||||
const onDownloadDocument = () => {
|
||||
downloadFile({
|
||||
@ -58,6 +59,15 @@ const ActionCell = ({
|
||||
|
||||
return (
|
||||
<Space size={0}>
|
||||
{/* <Tooltip title={t('addToKnowledge')}>
|
||||
<Button
|
||||
type="text"
|
||||
className={styles.iconButton}
|
||||
onClick={navigateToDocument}
|
||||
>
|
||||
<EyeOutlined size={20} />
|
||||
</Button>
|
||||
</Tooltip> */}
|
||||
<Tooltip title={t('addToKnowledge')}>
|
||||
<Button
|
||||
type="text"
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
import { useGetPagination, useSetPagination } from '@/hooks/logicHooks';
|
||||
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
||||
import { IFile } from '@/interfaces/database/file-manager';
|
||||
import { getExtension } from '@/utils/documentUtils';
|
||||
import { PaginationProps } from 'antd';
|
||||
import { UploadFile } from 'antd/lib';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
@ -338,3 +339,12 @@ export const useHandleBreadcrumbClick = () => {
|
||||
|
||||
return { handleBreadcrumbClick };
|
||||
};
|
||||
|
||||
export const useNavigateToDocument = (documentId: string, name: string) => {
|
||||
const navigate = useNavigate();
|
||||
const navigateToDocument = () => {
|
||||
navigate(`/document/${documentId}?ext=${getExtension(name)}`);
|
||||
};
|
||||
|
||||
return navigateToDocument;
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useSelectFileList } from '@/hooks/fileManagerHooks';
|
||||
import { IFile } from '@/interfaces/database/file-manager';
|
||||
import { formatDate } from '@/utils/date';
|
||||
import { Button, Flex, Space, Table, Tag } from 'antd';
|
||||
import { Button, Flex, Space, Table, Tag, Typography } from 'antd';
|
||||
import { ColumnsType } from 'antd/es/table';
|
||||
import ActionCell from './action-cell';
|
||||
import FileToolbar from './file-toolbar';
|
||||
@ -26,6 +26,8 @@ import ConnectToKnowledgeModal from './connect-to-knowledge-modal';
|
||||
import FolderCreateModal from './folder-create-modal';
|
||||
import styles from './index.less';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
const FileManager = () => {
|
||||
const { t } = useTranslate('fileManager');
|
||||
const fileList = useSelectFileList();
|
||||
@ -69,6 +71,7 @@ const FileManager = () => {
|
||||
title: t('name'),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
fixed: 'left',
|
||||
render(value, record) {
|
||||
return (
|
||||
<Flex gap={10} align="center">
|
||||
@ -82,10 +85,10 @@ const FileManager = () => {
|
||||
className={styles.linkButton}
|
||||
onClick={() => navigateToOtherFolder(record.id)}
|
||||
>
|
||||
{value}
|
||||
<Text ellipsis={{ tooltip: value }}>{value}</Text>
|
||||
</Button>
|
||||
) : (
|
||||
value
|
||||
<Text ellipsis={{ tooltip: value }}>{value}</Text>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
@ -160,6 +163,7 @@ const FileManager = () => {
|
||||
rowSelection={rowSelection}
|
||||
loading={loading}
|
||||
pagination={pagination}
|
||||
scroll={{ scrollToFirstRowOnChange: true, x: '100%' }}
|
||||
/>
|
||||
<RenameModal
|
||||
visible={fileRenameVisible}
|
||||
|
@ -2,7 +2,9 @@ import { paginationModel } from '@/base';
|
||||
import { BaseState } from '@/interfaces/common';
|
||||
import { IFile, IFolder } from '@/interfaces/database/file-manager';
|
||||
import i18n from '@/locales/config';
|
||||
import fileManagerService from '@/services/fileManagerService';
|
||||
import fileManagerService, {
|
||||
getDocumentFile,
|
||||
} from '@/services/fileManagerService';
|
||||
import { message } from 'antd';
|
||||
import omit from 'lodash/omit';
|
||||
import { DvaModel } from 'umi';
|
||||
@ -139,6 +141,11 @@ const model: DvaModel<FileManagerModelState> = {
|
||||
}
|
||||
return data.retcode;
|
||||
},
|
||||
*getDocumentFile({ payload = {} }, { call }) {
|
||||
const ret = yield call(getDocumentFile, payload);
|
||||
|
||||
return ret;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -45,6 +45,7 @@ const IconMap = {
|
||||
文心一言: 'wenxin',
|
||||
Ollama: 'ollama',
|
||||
Xinference: 'xinference',
|
||||
DeepSeek: 'deepseek',
|
||||
};
|
||||
|
||||
const LlmIcon = ({ name }: { name: string }) => {
|
||||
|
@ -88,6 +88,10 @@ const routes = [
|
||||
path: '/flow',
|
||||
component: '@/pages/flow',
|
||||
},
|
||||
{
|
||||
path: 'document/:id',
|
||||
component: '@/pages/document-viewer',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
import api from '@/utils/api';
|
||||
import registerServer from '@/utils/registerServer';
|
||||
import request from '@/utils/request';
|
||||
import pureRequest from 'axios';
|
||||
|
||||
const {
|
||||
listFile,
|
||||
@ -10,6 +11,8 @@ const {
|
||||
getAllParentFolder,
|
||||
createFolder,
|
||||
connectFileToKnowledge,
|
||||
get_document_file,
|
||||
getFile,
|
||||
} = api;
|
||||
|
||||
const methods = {
|
||||
@ -41,6 +44,11 @@ const methods = {
|
||||
url: connectFileToKnowledge,
|
||||
method: 'post',
|
||||
},
|
||||
getDocumentFile: {
|
||||
url: getFile,
|
||||
method: 'get',
|
||||
responseType: 'blob',
|
||||
},
|
||||
} as const;
|
||||
|
||||
const fileManagerService = registerServer<keyof typeof methods>(
|
||||
@ -49,3 +57,45 @@ const fileManagerService = registerServer<keyof typeof methods>(
|
||||
);
|
||||
|
||||
export default fileManagerService;
|
||||
|
||||
export const getDocumentFile = (documentId: string) => {
|
||||
return pureRequest(getFile + '/' + documentId, {
|
||||
responseType: 'blob',
|
||||
method: 'get',
|
||||
// headers: {
|
||||
// 'content-type':
|
||||
// 'text/plain;charset=UTF-8, application/vnd.openxmlformats-officeddocument.spreadsheetml.sheet;charset=UTF-8',
|
||||
// },
|
||||
|
||||
// parseResponse: false,
|
||||
// getResponse: true,
|
||||
})
|
||||
.then((res) => {
|
||||
const x = res?.headers?.get('content-disposition');
|
||||
const y = res?.headers?.get('Content-Type');
|
||||
console.info(res);
|
||||
console.info(x);
|
||||
console.info('Content-Type', y);
|
||||
return res;
|
||||
})
|
||||
.then((res) => {
|
||||
// const objectURL = URL.createObjectURL(res);
|
||||
|
||||
// let btn = document.createElement('a');
|
||||
|
||||
// btn.download = '文件名.pdf';
|
||||
|
||||
// btn.href = objectURL;
|
||||
|
||||
// btn.click();
|
||||
|
||||
// URL.revokeObjectURL(objectURL);
|
||||
|
||||
// btn = null;
|
||||
|
||||
return res;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.info(err);
|
||||
});
|
||||
};
|
||||
|
@ -75,4 +75,5 @@ export default {
|
||||
getAllParentFolder: `${api_host}/file/all_parent_folder`,
|
||||
createFolder: `${api_host}/file/create`,
|
||||
connectFileToKnowledge: `${api_host}/file2document/convert`,
|
||||
getFile: `${api_host}/file/get`,
|
||||
};
|
||||
|
@ -1,3 +1,4 @@
|
||||
import omit from 'lodash/omit';
|
||||
import { RequestMethod } from 'umi-request';
|
||||
|
||||
type Service<T extends string> = Record<T, (params: any) => any>;
|
||||
@ -10,6 +11,7 @@ const registerServer = <T extends string>(
|
||||
for (let key in opt) {
|
||||
server[key] = (params: any, urlAppendix?: string) => {
|
||||
let url = opt[key].url;
|
||||
const requestOptions = opt[key];
|
||||
if (urlAppendix) {
|
||||
url = url + '/' + urlAppendix;
|
||||
}
|
||||
@ -22,6 +24,7 @@ const registerServer = <T extends string>(
|
||||
|
||||
if (opt[key].method === 'get' || opt[key].method === 'GET') {
|
||||
return request.get(url, {
|
||||
...omit(requestOptions, ['method', 'url']),
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
1
web/typings.d.ts
vendored
1
web/typings.d.ts
vendored
@ -10,6 +10,7 @@ import { LoginModelState } from '@/pages/login/model';
|
||||
import { SettingModelState } from '@/pages/user-setting/model';
|
||||
|
||||
declare module 'lodash';
|
||||
declare module 'react-file-viewer';
|
||||
|
||||
function useSelector<TState = RootState, TSelected = unknown>(
|
||||
selector: (state: TState) => TSelected,
|
||||
|
Loading…
x
Reference in New Issue
Block a user