* feat: modify routing to nested mode * feat: rename documenttags/v0.1.0
| @@ -0,0 +1,28 @@ | |||
| import { ExclamationCircleFilled } from '@ant-design/icons'; | |||
| import { Modal } from 'antd'; | |||
| const { confirm } = Modal; | |||
| interface IProps { | |||
| onOk?: (...args: any[]) => any; | |||
| onCancel?: (...args: any[]) => any; | |||
| } | |||
| export const showDeleteConfirm = ({ onOk, onCancel }: IProps) => { | |||
| confirm({ | |||
| title: 'Are you sure delete this item?', | |||
| icon: <ExclamationCircleFilled />, | |||
| content: 'Some descriptions', | |||
| okText: 'Yes', | |||
| okType: 'danger', | |||
| cancelText: 'No', | |||
| onOk() { | |||
| onOk?.(); | |||
| }, | |||
| onCancel() { | |||
| onCancel?.(); | |||
| }, | |||
| }); | |||
| }; | |||
| export default showDeleteConfirm; | |||
| @@ -0,0 +1,24 @@ | |||
| import { useState } from 'react'; | |||
| interface IProps { | |||
| children: (props: { | |||
| showModal(): void; | |||
| hideModal(): void; | |||
| visible: boolean; | |||
| }) => React.ReactNode; | |||
| } | |||
| const ModalManager = ({ children }: IProps) => { | |||
| const [visible, setVisible] = useState(false); | |||
| const showModal = () => { | |||
| setVisible(true); | |||
| }; | |||
| const hideModal = () => { | |||
| setVisible(false); | |||
| }; | |||
| return children({ visible, showModal, hideModal }); | |||
| }; | |||
| export default ModalManager; | |||
| @@ -1,5 +1,13 @@ | |||
| export enum KnowledgeRouteKey { | |||
| Dataset = 'dataset', | |||
| Testing = 'testing', | |||
| Configration = 'configration', | |||
| Configuration = 'configuration', | |||
| } | |||
| export enum RunningStatus { | |||
| UNSTART = '0', | |||
| RUNNING = '1', | |||
| CANCEL = '2', | |||
| DONE = '3', | |||
| FAIL = '4', | |||
| } | |||
| @@ -0,0 +1,8 @@ | |||
| import { useSearchParams } from 'umi'; | |||
| export const useKnowledgeBaseId = (): string => { | |||
| const [searchParams] = useSearchParams(); | |||
| const knowledgeBaseId = searchParams.get('id'); | |||
| return knowledgeBaseId || ''; | |||
| }; | |||
| @@ -0,0 +1,21 @@ | |||
| import { useLocation } from 'umi'; | |||
| export enum SegmentIndex { | |||
| Second = '2', | |||
| Third = '3', | |||
| } | |||
| export const useSegmentedPathName = (index: SegmentIndex) => { | |||
| const { pathname } = useLocation(); | |||
| const pathArray = pathname.split('/'); | |||
| return pathArray[index] || ''; | |||
| }; | |||
| export const useSecondPathName = () => { | |||
| return useSegmentedPathName(SegmentIndex.Second); | |||
| }; | |||
| export const useThirdPathName = () => { | |||
| return useSegmentedPathName(SegmentIndex.Third); | |||
| }; | |||
| @@ -0,0 +1,26 @@ | |||
| import { RunningStatus } from '@/constants/knowledge'; | |||
| export interface IKnowledgeFile { | |||
| chunk_num: number; | |||
| create_date: string; | |||
| create_time: number; | |||
| created_by: string; | |||
| id: string; | |||
| kb_id: string; | |||
| location: string; | |||
| name: string; | |||
| parser_id: string; | |||
| process_begin_at?: any; | |||
| process_duation: number; | |||
| progress: number; // parsing process | |||
| progress_msg: string; // parsing log | |||
| run: RunningStatus; // parsing status | |||
| size: number; | |||
| source_type: string; | |||
| status: string; // enabled | |||
| thumbnail?: any; // base64 | |||
| token_num: number; | |||
| type: string; | |||
| update_date: string; | |||
| update_time: number; | |||
| } | |||
| @@ -14,11 +14,11 @@ import { | |||
| Spin, | |||
| Switch, | |||
| } from 'antd'; | |||
| import { debounce } from 'lodash'; | |||
| import React, { useCallback, useEffect, useState } from 'react'; | |||
| import { useDispatch, useNavigate, useSelector } from 'umi'; | |||
| import { useDispatch, useSearchParams, useSelector } from 'umi'; | |||
| import CreateModal from './components/createModal'; | |||
| import { debounce } from 'lodash'; | |||
| import styles from './index.less'; | |||
| interface PayloadType { | |||
| @@ -27,18 +27,13 @@ interface PayloadType { | |||
| available_int?: number; | |||
| } | |||
| interface IProps { | |||
| doc_id: string; | |||
| } | |||
| const Chunk = ({ doc_id }: IProps) => { | |||
| const Chunk = () => { | |||
| const dispatch = useDispatch(); | |||
| const chunkModel = useSelector((state: any) => state.chunkModel); | |||
| const [keywords, SetKeywords] = useState(''); | |||
| const [available_int, setAvailableInt] = useState(-1); | |||
| const navigate = useNavigate(); | |||
| const [searchParams] = useSearchParams(); | |||
| const [pagination, setPagination] = useState({ page: 1, size: 30 }); | |||
| // const [datas, setDatas] = useState(data) | |||
| const { data = [], total, chunk_id, isShowCreateModal } = chunkModel; | |||
| const effects = useSelector((state: any) => state.loading.effects); | |||
| const loading = getOneNamespaceEffectsLoading('chunkModel', effects, [ | |||
| @@ -46,10 +41,11 @@ const Chunk = ({ doc_id }: IProps) => { | |||
| 'chunk_list', | |||
| 'switch_chunk', | |||
| ]); | |||
| const documentId: string = searchParams.get('doc_id') || ''; | |||
| const getChunkList = (value?: string) => { | |||
| const payload: PayloadType = { | |||
| doc_id, | |||
| doc_id: documentId, | |||
| keywords: value || keywords, | |||
| available_int, | |||
| }; | |||
| @@ -81,7 +77,7 @@ const Chunk = ({ doc_id }: IProps) => { | |||
| payload: { | |||
| isShowCreateModal: true, | |||
| chunk_id, | |||
| doc_id, | |||
| doc_id: documentId, | |||
| }, | |||
| }); | |||
| getChunkList(); | |||
| @@ -100,7 +96,7 @@ const Chunk = ({ doc_id }: IProps) => { | |||
| payload: { | |||
| chunk_ids: [id], | |||
| available_int: Number(available_int), | |||
| doc_id, | |||
| doc_id: documentId, | |||
| }, | |||
| }); | |||
| @@ -109,7 +105,7 @@ const Chunk = ({ doc_id }: IProps) => { | |||
| useEffect(() => { | |||
| getChunkList(); | |||
| }, [doc_id, available_int, pagination]); | |||
| }, [documentId, available_int, pagination]); | |||
| const debounceChange = debounce(getChunkList, 300); | |||
| const debounceCallback = useCallback( | |||
| @@ -270,7 +266,7 @@ const Chunk = ({ doc_id }: IProps) => { | |||
| </div> | |||
| </div> | |||
| <CreateModal | |||
| doc_id={doc_id} | |||
| doc_id={documentId} | |||
| isShowCreateModal={isShowCreateModal} | |||
| chunk_id={chunk_id} | |||
| getChunkList={getChunkList} | |||
| @@ -0,0 +1,7 @@ | |||
| import { Outlet } from 'umi'; | |||
| export const KnowledgeDataset = () => { | |||
| return <Outlet></Outlet>; | |||
| }; | |||
| export default KnowledgeDataset; | |||
| @@ -0,0 +1,5 @@ | |||
| const KnowledgeUploadFile = () => { | |||
| return <div>KnowledgeUploadFile</div>; | |||
| }; | |||
| export default KnowledgeUploadFile; | |||
| @@ -0,0 +1,17 @@ | |||
| import { RunningStatus } from '@/constants/knowledge'; | |||
| export const RunningStatusMap = { | |||
| [RunningStatus.UNSTART]: { | |||
| label: 'UNSTART', | |||
| color: 'cyan', | |||
| }, | |||
| [RunningStatus.RUNNING]: { | |||
| label: 'Parsing', | |||
| color: 'blue', | |||
| }, | |||
| [RunningStatus.CANCEL]: { label: 'CANCEL', color: 'orange' }, | |||
| [RunningStatus.DONE]: { label: 'SUCCESS', color: 'geekblue' }, | |||
| [RunningStatus.FAIL]: { label: 'FAIL', color: 'red' }, | |||
| }; | |||
| export * from '@/constants/knowledge'; | |||
| @@ -13,9 +13,9 @@ interface kFProps { | |||
| const FileCreatingModal: React.FC<kFProps> = ({ getKfList, kb_id }) => { | |||
| const dispatch = useDispatch(); | |||
| const [form] = Form.useForm(); | |||
| const kFModel = useSelector((state: any) => state.kFModel); | |||
| const { isShowCEFwModal } = kFModel; | |||
| const [form] = Form.useForm(); | |||
| const { t } = useTranslation(); | |||
| const handleCancel = () => { | |||
| @@ -26,7 +26,8 @@ const FileCreatingModal: React.FC<kFProps> = ({ getKfList, kb_id }) => { | |||
| }, | |||
| }); | |||
| }; | |||
| const handleOk = async () => { | |||
| const createDocument = async () => { | |||
| try { | |||
| const values = await form.validateFields(); | |||
| const retcode = await dispatch<any>({ | |||
| @@ -44,9 +45,13 @@ const FileCreatingModal: React.FC<kFProps> = ({ getKfList, kb_id }) => { | |||
| } | |||
| }; | |||
| const handleOk = async () => { | |||
| createDocument(); | |||
| }; | |||
| return ( | |||
| <Modal | |||
| title="Basic Modal" | |||
| title="File Name" | |||
| open={isShowCEFwModal} | |||
| onOk={handleOk} | |||
| onCancel={handleCancel} | |||
| @@ -54,15 +59,15 @@ const FileCreatingModal: React.FC<kFProps> = ({ getKfList, kb_id }) => { | |||
| <Form | |||
| form={form} | |||
| name="validateOnly" | |||
| labelCol={{ span: 8 }} | |||
| wrapperCol={{ span: 16 }} | |||
| labelCol={{ span: 4 }} | |||
| wrapperCol={{ span: 20 }} | |||
| style={{ maxWidth: 600 }} | |||
| autoComplete="off" | |||
| > | |||
| <Form.Item<FieldType> | |||
| label="文件名" | |||
| label="File Name" | |||
| name="name" | |||
| rules={[{ required: true, message: 'Please input value!' }]} | |||
| rules={[{ required: true, message: 'Please input name!' }]} | |||
| > | |||
| <Input /> | |||
| </Form.Item> | |||
| @@ -1,28 +1,34 @@ | |||
| .datasetWrapper { | |||
| padding: 30px; | |||
| flex: 1; | |||
| } | |||
| .filter { | |||
| height: 32px; | |||
| display: flex; | |||
| margin: 10px 0; | |||
| justify-content: space-between; | |||
| height: 32px; | |||
| display: flex; | |||
| margin: 10px 0; | |||
| justify-content: space-between; | |||
| padding: 24px 20px; | |||
| .search { | |||
| flex: 1; | |||
| } | |||
| // .search { | |||
| // flex: 1; | |||
| // } | |||
| .operate { | |||
| width: 200px; | |||
| } | |||
| // .operate { | |||
| // width: 200px; | |||
| // } | |||
| } | |||
| .img { | |||
| height: 16px; | |||
| width: 16px; | |||
| margin-right: 6px; | |||
| height: 16px; | |||
| width: 16px; | |||
| margin-right: 6px; | |||
| } | |||
| .column { | |||
| min-width: 200px | |||
| min-width: 200px; | |||
| } | |||
| .tochunks { | |||
| cursor: pointer; | |||
| } | |||
| cursor: pointer; | |||
| } | |||
| @@ -1,37 +1,38 @@ | |||
| import { KnowledgeRouteKey } from '@/constants/knowledge'; | |||
| import { useKnowledgeBaseId } from '@/hooks/knowledgeHook'; | |||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||
| import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil'; | |||
| import { DownOutlined } from '@ant-design/icons'; | |||
| import { PlusOutlined, SearchOutlined } from '@ant-design/icons'; | |||
| import type { MenuProps } from 'antd'; | |||
| import { Button, Dropdown, Input, Space, Switch, Table } from 'antd'; | |||
| import { | |||
| Button, | |||
| Divider, | |||
| Dropdown, | |||
| Input, | |||
| Space, | |||
| Switch, | |||
| Table, | |||
| Tag, | |||
| } from 'antd'; | |||
| import type { ColumnsType } from 'antd/es/table'; | |||
| import { debounce } from 'lodash'; | |||
| import React, { useCallback, useEffect, useMemo, useState } from 'react'; | |||
| import { useDispatch, useNavigate, useSelector } from 'umi'; | |||
| import CreateEPModal from './createEFileModal'; | |||
| import styles from './index.less'; | |||
| import ParsingActionCell from './parsing-action-cell'; | |||
| import ParsingStatusCell from './parsing-status-cell'; | |||
| import RenameModal from './rename-modal'; | |||
| import SegmentSetModal from './segmentSetModal'; | |||
| import UploadFile from './upload'; | |||
| interface DataType { | |||
| name: string; | |||
| chunk_num: string; | |||
| token_num: number; | |||
| update_date: string; | |||
| size: string; | |||
| status: string; | |||
| id: string; | |||
| parser_id: string; | |||
| } | |||
| interface KFProps { | |||
| kb_id: string; | |||
| } | |||
| const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| const KnowledgeFile = () => { | |||
| const dispatch = useDispatch(); | |||
| const kFModel = useSelector((state: any) => state.kFModel); | |||
| const effects = useSelector((state: any) => state.loading.effects); | |||
| const { data } = kFModel; | |||
| const knowledgeBaseId = useKnowledgeBaseId(); | |||
| const loading = getOneNamespaceEffectsLoading('kFModel', effects, [ | |||
| 'getKfList', | |||
| 'updateDocumentStatus', | |||
| @@ -43,7 +44,7 @@ const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| const getKfList = (keywords?: string) => { | |||
| const payload = { | |||
| kb_id, | |||
| kb_id: knowledgeBaseId, | |||
| keywords, | |||
| }; | |||
| if (!keywords) { | |||
| @@ -56,10 +57,10 @@ const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| }; | |||
| useEffect(() => { | |||
| if (kb_id) { | |||
| if (knowledgeBaseId) { | |||
| getKfList(); | |||
| } | |||
| }, [kb_id]); | |||
| }, [knowledgeBaseId]); | |||
| const debounceChange = debounce(getKfList, 300); | |||
| const debounceCallback = useCallback( | |||
| @@ -79,7 +80,7 @@ const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| payload: { | |||
| doc_id, | |||
| status: Number(e), | |||
| kb_id, | |||
| kb_id: knowledgeBaseId, | |||
| }, | |||
| }); | |||
| }; | |||
| @@ -88,7 +89,7 @@ const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| type: 'kFModel/document_rm', | |||
| payload: { | |||
| doc_id, | |||
| kb_id, | |||
| kb_id: knowledgeBaseId, | |||
| }, | |||
| }); | |||
| }; | |||
| @@ -109,13 +110,14 @@ const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| }, | |||
| }); | |||
| }; | |||
| const actionItems: MenuProps['items'] = useMemo(() => { | |||
| return [ | |||
| { | |||
| key: '1', | |||
| label: ( | |||
| <div> | |||
| <UploadFile kb_id={kb_id} getKfList={getKfList} /> | |||
| <UploadFile kb_id={knowledgeBaseId} getKfList={getKfList} /> | |||
| </div> | |||
| ), | |||
| }, | |||
| @@ -132,7 +134,7 @@ const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| // disabled: true, | |||
| }, | |||
| ]; | |||
| }, [kb_id]); | |||
| }, [knowledgeBaseId]); | |||
| const chunkItems: MenuProps['items'] = [ | |||
| { | |||
| key: '1', | |||
| @@ -158,14 +160,21 @@ const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| // disabled: true, | |||
| }, | |||
| ]; | |||
| const toChunk = (id: string) => { | |||
| navigate( | |||
| `/knowledge/${KnowledgeRouteKey.Dataset}?id=${kb_id}&doc_id=${id}`, | |||
| `/knowledge/${KnowledgeRouteKey.Dataset}/chunk?id=${knowledgeBaseId}&doc_id=${id}`, | |||
| ); | |||
| }; | |||
| const columns: ColumnsType<DataType> = [ | |||
| const setDocumentAndParserId = (record: IKnowledgeFile) => () => { | |||
| setDocId(record.id); | |||
| setParserId(record.parser_id); | |||
| }; | |||
| const columns: ColumnsType<IKnowledgeFile> = [ | |||
| { | |||
| title: '名称', | |||
| title: 'Name', | |||
| dataIndex: 'name', | |||
| key: 'name', | |||
| render: (text: any, { id }) => ( | |||
| @@ -178,32 +187,30 @@ const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| {text} | |||
| </div> | |||
| ), | |||
| className: `${styles.column}`, | |||
| }, | |||
| { | |||
| title: '数据总量', | |||
| title: 'Chunk Number', | |||
| dataIndex: 'chunk_num', | |||
| key: 'chunk_num', | |||
| className: `${styles.column}`, | |||
| }, | |||
| { | |||
| title: 'Tokens', | |||
| dataIndex: 'token_num', | |||
| key: 'token_num', | |||
| className: `${styles.column}`, | |||
| title: 'Upload Date', | |||
| dataIndex: 'create_date', | |||
| key: 'create_date', | |||
| }, | |||
| { | |||
| title: '文件大小', | |||
| dataIndex: 'size', | |||
| key: 'size', | |||
| className: `${styles.column}`, | |||
| title: 'Parsing Status', | |||
| dataIndex: 'run', | |||
| key: 'run', | |||
| render: (text, record) => { | |||
| return <ParsingStatusCell record={record}></ParsingStatusCell>; | |||
| }, | |||
| }, | |||
| { | |||
| title: '状态', | |||
| title: 'Enabled', | |||
| key: 'status', | |||
| dataIndex: 'status', | |||
| className: `${styles.column}`, | |||
| render: (_, { status: string, id }) => ( | |||
| render: (_, { status, id }) => ( | |||
| <> | |||
| <Switch | |||
| defaultChecked={status === '1'} | |||
| @@ -217,58 +224,65 @@ const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => { | |||
| { | |||
| title: 'Action', | |||
| key: 'action', | |||
| className: `${styles.column}`, | |||
| render: (_, record) => ( | |||
| <Space size="middle"> | |||
| <Dropdown menu={{ items: chunkItems }} trigger={['click']}> | |||
| <a | |||
| onClick={() => { | |||
| setDocId(record.id); | |||
| setParserId(record.parser_id); | |||
| }} | |||
| > | |||
| 分段设置 <DownOutlined /> | |||
| </a> | |||
| </Dropdown> | |||
| </Space> | |||
| <ParsingActionCell | |||
| documentId={doc_id} | |||
| knowledgeBaseId={knowledgeBaseId} | |||
| setDocumentAndParserId={setDocumentAndParserId(record)} | |||
| record={record} | |||
| ></ParsingActionCell> | |||
| ), | |||
| }, | |||
| ]; | |||
| const finalColumns = columns.map((x) => ({ | |||
| ...x, | |||
| className: `${styles.column}`, | |||
| })); | |||
| return ( | |||
| <> | |||
| <div className={styles.datasetWrapper}> | |||
| <h3>Dataset</h3> | |||
| <p>Hey, don't forget to adjust the chunk after adding the dataset! 😉</p> | |||
| <Divider></Divider> | |||
| <div className={styles.filter}> | |||
| <div className="search"> | |||
| <Space> | |||
| <h3>Total</h3> | |||
| <Tag color="purple">100 files</Tag> | |||
| </Space> | |||
| <Space> | |||
| <Input | |||
| placeholder="搜索" | |||
| placeholder="Seach your files" | |||
| value={inputValue} | |||
| style={{ width: 220 }} | |||
| allowClear | |||
| onChange={handleInputChange} | |||
| prefix={<SearchOutlined />} | |||
| /> | |||
| </div> | |||
| <div className="operate"> | |||
| <Dropdown menu={{ items: actionItems }} trigger={['click']}> | |||
| <a> | |||
| 导入文件 <DownOutlined /> | |||
| </a> | |||
| <Button type="primary" icon={<PlusOutlined />}> | |||
| Add file | |||
| </Button> | |||
| </Dropdown> | |||
| </div> | |||
| </Space> | |||
| </div> | |||
| <Table | |||
| rowKey="id" | |||
| columns={columns} | |||
| columns={finalColumns} | |||
| dataSource={data} | |||
| loading={loading} | |||
| pagination={false} | |||
| scroll={{ scrollToFirstRowOnChange: true, x: true }} | |||
| scroll={{ scrollToFirstRowOnChange: true, x: true, y: 'fill' }} | |||
| /> | |||
| <CreateEPModal getKfList={getKfList} kb_id={kb_id} /> | |||
| <CreateEPModal getKfList={getKfList} kb_id={knowledgeBaseId} /> | |||
| <SegmentSetModal | |||
| getKfList={getKfList} | |||
| parser_id={parser_id} | |||
| doc_id={doc_id} | |||
| /> | |||
| </> | |||
| <RenameModal></RenameModal> | |||
| </div> | |||
| ); | |||
| }; | |||
| @@ -1,14 +1,19 @@ | |||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||
| import kbService from '@/services/kbService'; | |||
| import { message } from 'antd'; | |||
| import omit from 'lodash/omit'; | |||
| import pick from 'lodash/pick'; | |||
| import { Nullable } from 'typings'; | |||
| import { DvaModel } from 'umi'; | |||
| export interface KFModelState { | |||
| isShowCEFwModal: boolean; | |||
| isShowTntModal: boolean; | |||
| isShowSegmentSetModal: boolean; | |||
| isShowRenameModal: boolean; | |||
| tenantIfo: any; | |||
| data: any[]; | |||
| data: IKnowledgeFile[]; | |||
| currentRecord: Nullable<IKnowledgeFile>; | |||
| } | |||
| const model: DvaModel<KFModelState> = { | |||
| @@ -17,8 +22,10 @@ const model: DvaModel<KFModelState> = { | |||
| isShowCEFwModal: false, | |||
| isShowTntModal: false, | |||
| isShowSegmentSetModal: false, | |||
| isShowRenameModal: false, | |||
| tenantIfo: {}, | |||
| data: [], | |||
| currentRecord: null, | |||
| }, | |||
| reducers: { | |||
| updateState(state, { payload }) { | |||
| @@ -27,6 +34,12 @@ const model: DvaModel<KFModelState> = { | |||
| ...payload, | |||
| }; | |||
| }, | |||
| setIsShowRenameModal(state, { payload }) { | |||
| return { ...state, isShowRenameModal: payload }; | |||
| }, | |||
| setCurrentRecord(state, { payload }) { | |||
| return { ...state, currentRecord: payload }; | |||
| }, | |||
| }, | |||
| subscriptions: { | |||
| setup({ dispatch, history }) { | |||
| @@ -99,6 +112,26 @@ const model: DvaModel<KFModelState> = { | |||
| }); | |||
| } | |||
| }, | |||
| *document_rename({ payload = {} }, { call, put }) { | |||
| const { data } = yield call( | |||
| kbService.document_rename, | |||
| omit(payload, ['kb_id']), | |||
| ); | |||
| const { retcode, data: res, retmsg } = data; | |||
| if (retcode === 0) { | |||
| message.success('rename success!'); | |||
| yield put({ | |||
| type: 'setIsShowRenameModal', | |||
| payload: false, | |||
| }); | |||
| yield put({ | |||
| type: 'getKfList', | |||
| payload: { kb_id: payload.kb_id }, | |||
| }); | |||
| } | |||
| return retcode; | |||
| }, | |||
| *document_create({ payload = {} }, { call, put }) { | |||
| const { data, response } = yield call(kbService.document_create, payload); | |||
| const { retcode, data: res, retmsg } = data; | |||
| @@ -0,0 +1,88 @@ | |||
| import showDeleteConfirm from '@/components/deleting-confirm'; | |||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||
| import { DeleteOutlined, EditOutlined, ToolOutlined } from '@ant-design/icons'; | |||
| import { Button, Dropdown, MenuProps, Space, Tooltip } from 'antd'; | |||
| import { useDispatch } from 'umi'; | |||
| interface IProps { | |||
| documentId: string; | |||
| knowledgeBaseId: string; | |||
| record: IKnowledgeFile; | |||
| setDocumentAndParserId: () => void; | |||
| } | |||
| const ParsingActionCell = ({ | |||
| documentId, | |||
| knowledgeBaseId, | |||
| record, | |||
| setDocumentAndParserId, | |||
| }: IProps) => { | |||
| const dispatch = useDispatch(); | |||
| const removeDocument = () => { | |||
| dispatch({ | |||
| type: 'kFModel/document_rm', | |||
| payload: { | |||
| doc_id: documentId, | |||
| kb_id: knowledgeBaseId, | |||
| }, | |||
| }); | |||
| }; | |||
| const onRmDocument = () => { | |||
| showDeleteConfirm({ onOk: removeDocument }); | |||
| }; | |||
| const setCurrentRecord = () => { | |||
| dispatch({ | |||
| type: 'kFModel/setCurrentRecord', | |||
| payload: record, | |||
| }); | |||
| }; | |||
| const showSegmentSetModal = () => { | |||
| dispatch({ | |||
| type: 'kFModel/updateState', | |||
| payload: { | |||
| isShowSegmentSetModal: true, | |||
| }, | |||
| }); | |||
| }; | |||
| const showRenameModal = () => { | |||
| setCurrentRecord(); | |||
| dispatch({ | |||
| type: 'kFModel/setIsShowRenameModal', | |||
| payload: true, | |||
| }); | |||
| }; | |||
| const onRename = () => {}; | |||
| const chunkItems: MenuProps['items'] = [ | |||
| { | |||
| key: '1', | |||
| label: ( | |||
| <div> | |||
| <Button type="link" onClick={showSegmentSetModal}> | |||
| 分段设置 | |||
| </Button> | |||
| </div> | |||
| ), | |||
| }, | |||
| ]; | |||
| return ( | |||
| <Space size={'middle'}> | |||
| <Dropdown menu={{ items: chunkItems }} trigger={['click']}> | |||
| <ToolOutlined size={20} onClick={setDocumentAndParserId} /> | |||
| </Dropdown> | |||
| <Tooltip title="Rename"> | |||
| <EditOutlined size={20} onClick={showRenameModal} /> | |||
| </Tooltip> | |||
| <DeleteOutlined size={20} onClick={onRmDocument} /> | |||
| </Space> | |||
| ); | |||
| }; | |||
| export default ParsingActionCell; | |||
| @@ -0,0 +1,3 @@ | |||
| .popover-content { | |||
| width: 300px; | |||
| } | |||
| @@ -0,0 +1,68 @@ | |||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||
| import { Badge, DescriptionsProps, Flex, Popover, Space, Tag } from 'antd'; | |||
| import { RunningStatus, RunningStatusMap } from '../constant'; | |||
| import styles from './index.less'; | |||
| interface IProps { | |||
| record: IKnowledgeFile; | |||
| } | |||
| const PopoverContent = ({ record }: IProps) => { | |||
| const items: DescriptionsProps['items'] = [ | |||
| { | |||
| key: 'process_begin_at', | |||
| label: 'Process Begin At', | |||
| children: record.process_begin_at, | |||
| }, | |||
| { | |||
| key: 'process_duation', | |||
| label: 'Process Duration', | |||
| children: record.process_duation, | |||
| }, | |||
| { | |||
| key: 'progress_msg', | |||
| label: 'Progress Msg', | |||
| children: record.progress_msg, | |||
| }, | |||
| ]; | |||
| return ( | |||
| <Flex vertical className={styles['popover-content']}> | |||
| {items.map((x) => { | |||
| return ( | |||
| <div> | |||
| <b>{x.label}:</b> | |||
| <p>{x.children}</p> | |||
| </div> | |||
| ); | |||
| })} | |||
| </Flex> | |||
| ); | |||
| }; | |||
| export const ParsingStatusCell = ({ record }: IProps) => { | |||
| const text = record.run; | |||
| const runningStatus = RunningStatusMap[text]; | |||
| const isRunning = text === RunningStatus.RUNNING; | |||
| return ( | |||
| <Popover | |||
| content={isRunning && <PopoverContent record={record}></PopoverContent>} | |||
| > | |||
| <Tag color={runningStatus.color}> | |||
| {isRunning ? ( | |||
| <Space> | |||
| <Badge color={runningStatus.color} /> | |||
| `${runningStatus.label}${record.progress * 100}%` | |||
| </Space> | |||
| ) : ( | |||
| runningStatus.label | |||
| )} | |||
| </Tag> | |||
| </Popover> | |||
| ); | |||
| }; | |||
| export default ParsingStatusCell; | |||
| @@ -0,0 +1,88 @@ | |||
| import { useKnowledgeBaseId } from '@/hooks/knowledgeHook'; | |||
| import { Form, Input, Modal } from 'antd'; | |||
| import { useEffect } from 'react'; | |||
| import { useDispatch, useSelector } from 'umi'; | |||
| const RenameModal = () => { | |||
| const [form] = Form.useForm(); | |||
| const dispatch = useDispatch(); | |||
| const kFModel = useSelector((state: any) => state.kFModel); | |||
| const loading = useSelector( | |||
| (state: any) => state.loading.effects['kFModel/document_rename'], | |||
| ); | |||
| const knowledgeBaseId = useKnowledgeBaseId(); | |||
| const isModalOpen = kFModel.isShowRenameModal; | |||
| const initialName = kFModel.currentRecord?.name; | |||
| const documentId = kFModel.currentRecord?.id; | |||
| type FieldType = { | |||
| name?: string; | |||
| }; | |||
| const closeModal = () => { | |||
| dispatch({ | |||
| type: 'kFModel/setIsShowRenameModal', | |||
| payload: false, | |||
| }); | |||
| }; | |||
| const handleOk = async () => { | |||
| const ret = await form.validateFields(); | |||
| dispatch({ | |||
| type: 'kFModel/document_rename', | |||
| payload: { | |||
| doc_id: documentId, | |||
| name: ret.name, | |||
| kb_id: knowledgeBaseId, | |||
| }, | |||
| }); | |||
| }; | |||
| const handleCancel = () => { | |||
| closeModal(); | |||
| }; | |||
| const onFinish = (values: any) => { | |||
| console.log('Success:', values); | |||
| }; | |||
| const onFinishFailed = (errorInfo: any) => { | |||
| console.log('Failed:', errorInfo); | |||
| }; | |||
| useEffect(() => { | |||
| form.setFieldValue('name', initialName); | |||
| }, [initialName, documentId]); | |||
| return ( | |||
| <Modal | |||
| title="Rename" | |||
| open={isModalOpen} | |||
| onOk={handleOk} | |||
| onCancel={handleCancel} | |||
| okButtonProps={{ loading }} | |||
| > | |||
| <Form | |||
| name="basic" | |||
| labelCol={{ span: 4 }} | |||
| wrapperCol={{ span: 20 }} | |||
| style={{ maxWidth: 600 }} | |||
| onFinish={onFinish} | |||
| onFinishFailed={onFinishFailed} | |||
| autoComplete="off" | |||
| form={form} | |||
| > | |||
| <Form.Item<FieldType> | |||
| label="Name" | |||
| name="name" | |||
| rules={[{ required: true, message: 'Please input name!' }]} | |||
| > | |||
| <Input /> | |||
| </Form.Item> | |||
| </Form> | |||
| </Modal> | |||
| ); | |||
| }; | |||
| export default RenameModal; | |||
| @@ -41,7 +41,6 @@ const SegmentSetModal: React.FC<kFProps> = ({ | |||
| }; | |||
| const handleOk = async () => { | |||
| console.log(1111, selectedTag); | |||
| const retcode = await dispatch<any>({ | |||
| type: 'kFModel/document_change_parser', | |||
| payload: { | |||
| @@ -1,3 +1,5 @@ | |||
| import { useKnowledgeBaseId } from '@/hooks/knowledgeHook'; | |||
| import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; | |||
| import { api_host } from '@/utils/api'; | |||
| import { DeleteOutlined, MinusSquareOutlined } from '@ant-design/icons'; | |||
| import type { PaginationProps } from 'antd'; | |||
| @@ -12,18 +14,14 @@ import { | |||
| Spin, | |||
| Switch, | |||
| } from 'antd'; | |||
| import { debounce } from 'lodash'; | |||
| import React, { useCallback, useEffect } from 'react'; | |||
| import { useDispatch, useSelector } from 'umi'; | |||
| import CreateModal from '../knowledge-chunk/components/createModal'; | |||
| import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; | |||
| import { debounce } from 'lodash'; | |||
| import styles from './index.less'; | |||
| interface chunkProps { | |||
| kb_id: string; | |||
| } | |||
| const KnowledgeSearching: React.FC<chunkProps> = ({ kb_id }) => { | |||
| const KnowledgeSearching = () => { | |||
| const dispatch = useDispatch(); | |||
| const kSearchModel = useSelector((state: any) => state.kSearchModel); | |||
| const chunkModel = useSelector((state: any) => state.chunkModel); | |||
| @@ -31,6 +29,7 @@ const KnowledgeSearching: React.FC<chunkProps> = ({ kb_id }) => { | |||
| 'chunk_list', | |||
| 'switch_chunk', | |||
| ]); | |||
| const knowledgeBaseId = useKnowledgeBaseId(); | |||
| const { | |||
| data = [], | |||
| @@ -46,7 +45,7 @@ const KnowledgeSearching: React.FC<chunkProps> = ({ kb_id }) => { | |||
| dispatch({ | |||
| type: 'kSearchModel/chunk_list', | |||
| payload: { | |||
| kb_id, | |||
| kb_id: knowledgeBaseId, | |||
| }, | |||
| }); | |||
| }; | |||
| @@ -55,7 +54,7 @@ const KnowledgeSearching: React.FC<chunkProps> = ({ kb_id }) => { | |||
| type: 'kSearchModel/rm_chunk', | |||
| payload: { | |||
| chunk_ids: [id], | |||
| kb_id, | |||
| kb_id: knowledgeBaseId, | |||
| }, | |||
| }); | |||
| }; | |||
| @@ -93,7 +92,7 @@ const KnowledgeSearching: React.FC<chunkProps> = ({ kb_id }) => { | |||
| dispatch({ | |||
| type: 'kSearchModel/getKfList', | |||
| payload: { | |||
| kb_id, | |||
| kb_id: knowledgeBaseId, | |||
| }, | |||
| }); | |||
| }, []); | |||
| @@ -106,7 +105,7 @@ const KnowledgeSearching: React.FC<chunkProps> = ({ kb_id }) => { | |||
| chunk_ids: [chunk_id], | |||
| doc_id, | |||
| available_int, | |||
| kb_id, | |||
| kb_id: knowledgeBaseId, | |||
| }, | |||
| }); | |||
| }; | |||
| @@ -1,6 +1,7 @@ | |||
| import { KnowledgeRouteKey } from '@/constants/knowledge'; | |||
| import { useKnowledgeBaseId } from '@/hooks/knowledgeHook'; | |||
| import { Button, Form, Input, Radio, Select, Space, Tag } from 'antd'; | |||
| import React, { useCallback, useEffect, useState } from 'react'; | |||
| import { useCallback, useEffect, useState } from 'react'; | |||
| import { useDispatch, useNavigate, useSelector } from 'umi'; | |||
| import styles from './index.less'; | |||
| @@ -13,10 +14,7 @@ const layout = { | |||
| const { Option } = Select; | |||
| /* eslint-disable no-template-curly-in-string */ | |||
| interface kSProps { | |||
| kb_id: string; | |||
| } | |||
| const KnowledgeSetting: React.FC<kSProps> = ({ kb_id }) => { | |||
| const KnowledgeSetting = () => { | |||
| const dispatch = useDispatch(); | |||
| const settingModel = useSelector((state: any) => state.settingModel); | |||
| let navigate = useNavigate(); | |||
| @@ -25,17 +23,18 @@ const KnowledgeSetting: React.FC<kSProps> = ({ kb_id }) => { | |||
| const [form] = Form.useForm(); | |||
| const [selectedTag, setSelectedTag] = useState(''); | |||
| const values = Form.useWatch([], form); | |||
| const knowledgeBaseId = useKnowledgeBaseId(); | |||
| const getTenantInfo = useCallback(async () => { | |||
| dispatch({ | |||
| type: 'settingModel/getTenantInfo', | |||
| payload: {}, | |||
| }); | |||
| if (kb_id) { | |||
| if (knowledgeBaseId) { | |||
| const data = await dispatch<any>({ | |||
| type: 'kSModel/getKbDetail', | |||
| payload: { | |||
| kb_id, | |||
| kb_id: knowledgeBaseId, | |||
| }, | |||
| }); | |||
| if (data.retcode === 0) { | |||
| @@ -44,19 +43,19 @@ const KnowledgeSetting: React.FC<kSProps> = ({ kb_id }) => { | |||
| setSelectedTag(data.data.parser_id); | |||
| } | |||
| } | |||
| }, [kb_id]); | |||
| }, [knowledgeBaseId]); | |||
| const onFinish = async () => { | |||
| try { | |||
| await form.validateFields(); | |||
| if (kb_id) { | |||
| if (knowledgeBaseId) { | |||
| dispatch({ | |||
| type: 'kSModel/updateKb', | |||
| payload: { | |||
| ...values, | |||
| parser_id: selectedTag, | |||
| kb_id, | |||
| kb_id: knowledgeBaseId, | |||
| embd_id: undefined, | |||
| }, | |||
| }); | |||
| @@ -69,7 +68,9 @@ const KnowledgeSetting: React.FC<kSProps> = ({ kb_id }) => { | |||
| }, | |||
| }); | |||
| retcode === 0 && | |||
| navigate(`/knowledge/${KnowledgeRouteKey.Dataset}?id=${kb_id}`); | |||
| navigate( | |||
| `/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeBaseId}`, | |||
| ); | |||
| } | |||
| } catch (error) { | |||
| console.warn(error); | |||
| @@ -1,12 +1,13 @@ | |||
| import { ReactComponent as ConfigrationIcon } from '@/assets/svg/knowledge-configration.svg'; | |||
| import { ReactComponent as DatasetIcon } from '@/assets/svg/knowledge-dataset.svg'; | |||
| import { ReactComponent as TestingIcon } from '@/assets/svg/knowledge-testing.svg'; | |||
| import { useSecondPathName } from '@/hooks/routeHook'; | |||
| import { getWidth } from '@/utils'; | |||
| import { AntDesignOutlined } from '@ant-design/icons'; | |||
| import { Avatar, Menu, MenuProps, Space } from 'antd'; | |||
| import classNames from 'classnames'; | |||
| import { useEffect, useMemo, useState } from 'react'; | |||
| import { useNavigate, useParams, useSelector } from 'umi'; | |||
| import { useNavigate, useSelector } from 'umi'; | |||
| import { KnowledgeRouteKey, routeMap } from '../../constant'; | |||
| import styles from './index.less'; | |||
| @@ -14,8 +15,7 @@ const KnowledgeSidebar = () => { | |||
| const kAModel = useSelector((state: any) => state.kAModel); | |||
| const { id } = kAModel; | |||
| let navigate = useNavigate(); | |||
| const params = useParams(); | |||
| const activeKey = params.module || KnowledgeRouteKey.Dataset; | |||
| const activeKey = useSecondPathName(); | |||
| const [windowWidth, setWindowWidth] = useState(getWidth()); | |||
| const [collapsed, setCollapsed] = useState(false); | |||
| @@ -56,8 +56,8 @@ const KnowledgeSidebar = () => { | |||
| <TestingIcon />, | |||
| ), | |||
| getItem( | |||
| routeMap[KnowledgeRouteKey.Configration], | |||
| KnowledgeRouteKey.Configration, | |||
| routeMap[KnowledgeRouteKey.Configuration], | |||
| KnowledgeRouteKey.Configuration, | |||
| <ConfigrationIcon />, | |||
| ), | |||
| ]; | |||
| @@ -3,7 +3,17 @@ import { KnowledgeRouteKey } from '@/constants/knowledge'; | |||
| export const routeMap = { | |||
| [KnowledgeRouteKey.Dataset]: 'Dataset', | |||
| [KnowledgeRouteKey.Testing]: 'Retrieval testing', | |||
| [KnowledgeRouteKey.Configration]: 'Configuration', | |||
| [KnowledgeRouteKey.Configuration]: 'Configuration', | |||
| }; | |||
| export enum KnowledgeDatasetRouteKey { | |||
| Chunk = 'chunk', | |||
| File = 'file', | |||
| } | |||
| export const datasetRouteMap = { | |||
| [KnowledgeDatasetRouteKey.Chunk]: 'Chunk', | |||
| [KnowledgeDatasetRouteKey.File]: 'File Upload', | |||
| }; | |||
| export * from '@/constants/knowledge'; | |||
| @@ -7,9 +7,12 @@ | |||
| height: 100%; | |||
| background-color: rgba(247, 248, 250, 1); | |||
| padding: 16px 20px 28px 40px; | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| .content { | |||
| background-color: white; | |||
| margin-top: 16px; | |||
| // flex: 1; | |||
| } | |||
| } | |||
| @@ -1,45 +1,60 @@ | |||
| import { useKnowledgeBaseId } from '@/hooks/knowledgeHook'; | |||
| import { useSecondPathName, useThirdPathName } from '@/hooks/routeHook'; | |||
| import { Breadcrumb } from 'antd'; | |||
| import { ItemType } from 'antd/es/breadcrumb/Breadcrumb'; | |||
| import { useEffect, useMemo } from 'react'; | |||
| import { | |||
| useDispatch, | |||
| useLocation, | |||
| useNavigate, | |||
| useParams, | |||
| useSelector, | |||
| } from 'umi'; | |||
| import Chunk from './components/knowledge-chunk'; | |||
| import File from './components/knowledge-file'; | |||
| import Search from './components/knowledge-search'; | |||
| import Setting from './components/knowledge-setting'; | |||
| import { Link, Outlet, useDispatch, useLocation, useNavigate } from 'umi'; | |||
| import Siderbar from './components/knowledge-sidebar'; | |||
| import { KnowledgeRouteKey, routeMap } from './constant'; | |||
| import { | |||
| KnowledgeDatasetRouteKey, | |||
| KnowledgeRouteKey, | |||
| datasetRouteMap, | |||
| routeMap, | |||
| } from './constant'; | |||
| import styles from './index.less'; | |||
| const KnowledgeAdding = () => { | |||
| const dispatch = useDispatch(); | |||
| const kAModel = useSelector((state: any) => state.kAModel); | |||
| const navigate = useNavigate(); | |||
| const { id, doc_id } = kAModel; | |||
| const knowledgeBaseId = useKnowledgeBaseId(); | |||
| const location = useLocation(); | |||
| const params = useParams(); | |||
| const activeKey: KnowledgeRouteKey = | |||
| (params.module as KnowledgeRouteKey) || KnowledgeRouteKey.Dataset; | |||
| (useSecondPathName() as KnowledgeRouteKey) || KnowledgeRouteKey.Dataset; | |||
| const datasetActiveKey: KnowledgeDatasetRouteKey = | |||
| useThirdPathName() as KnowledgeDatasetRouteKey; | |||
| const gotoList = () => { | |||
| navigate('/knowledge'); | |||
| }; | |||
| const breadcrumbItems = useMemo(() => { | |||
| return [ | |||
| const breadcrumbItems: ItemType[] = useMemo(() => { | |||
| const items: ItemType[] = [ | |||
| { | |||
| title: <a onClick={gotoList}>Knowledge Base</a>, | |||
| }, | |||
| { | |||
| title: routeMap[activeKey], | |||
| title: datasetActiveKey ? ( | |||
| <Link | |||
| to={`/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeBaseId}`} | |||
| > | |||
| {routeMap[activeKey]} | |||
| </Link> | |||
| ) : ( | |||
| routeMap[activeKey] | |||
| ), | |||
| }, | |||
| ]; | |||
| }, [activeKey]); | |||
| if (datasetActiveKey) { | |||
| items.push({ | |||
| title: datasetRouteMap[datasetActiveKey], | |||
| }); | |||
| } | |||
| return items; | |||
| }, [activeKey, datasetActiveKey]); | |||
| useEffect(() => { | |||
| const search: string = location.search.slice(1); | |||
| @@ -65,16 +80,7 @@ const KnowledgeAdding = () => { | |||
| <div className={styles.contentWrapper}> | |||
| <Breadcrumb items={breadcrumbItems} /> | |||
| <div className={styles.content}> | |||
| {activeKey === KnowledgeRouteKey.Dataset && !doc_id && ( | |||
| <File kb_id={id} /> | |||
| )} | |||
| {activeKey === KnowledgeRouteKey.Configration && ( | |||
| <Setting kb_id={id} /> | |||
| )} | |||
| {activeKey === KnowledgeRouteKey.Testing && <Search kb_id={id} />} | |||
| {activeKey === KnowledgeRouteKey.Dataset && !!doc_id && ( | |||
| <Chunk doc_id={doc_id} /> | |||
| )} | |||
| <Outlet></Outlet> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -1,6 +1,7 @@ | |||
| import { ReactComponent as FilterIcon } from '@/assets/filter.svg'; | |||
| import { KnowledgeRouteKey } from '@/constants/knowledge'; | |||
| import { PlusOutlined } from '@ant-design/icons'; | |||
| import { Button, Col, Row, Space } from 'antd'; | |||
| import { Button, Flex, Space } from 'antd'; | |||
| import { useCallback, useEffect } from 'react'; | |||
| import { useDispatch, useNavigate, useSelector } from 'umi'; | |||
| import styles from './index.less'; | |||
| @@ -20,7 +21,7 @@ const Knowledge = () => { | |||
| }, []); | |||
| const handleAddKnowledge = () => { | |||
| navigate(`add/setting`); | |||
| navigate(`/knowledge/${KnowledgeRouteKey.Configuration}`); | |||
| }; | |||
| useEffect(() => { | |||
| @@ -50,7 +51,7 @@ const Knowledge = () => { | |||
| </Button> | |||
| </Space> | |||
| </div> | |||
| <Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}> | |||
| {/* <Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}> | |||
| {data.map((item: any) => { | |||
| return ( | |||
| <Col | |||
| @@ -58,14 +59,19 @@ const Knowledge = () => { | |||
| key={item.name} | |||
| xs={24} | |||
| sm={12} | |||
| md={8} | |||
| lg={6} | |||
| md={10} | |||
| lg={8} | |||
| > | |||
| <KnowledgeCard item={item}></KnowledgeCard> | |||
| </Col> | |||
| ); | |||
| })} | |||
| </Row> | |||
| </Row> */} | |||
| <Flex gap="large" wrap="wrap"> | |||
| {data.map((item: any) => { | |||
| return <KnowledgeCard item={item} key={item.name}></KnowledgeCard>; | |||
| })} | |||
| </Flex> | |||
| </div> | |||
| ); | |||
| }; | |||
| @@ -26,7 +26,7 @@ | |||
| border: 1px solid rgba(234, 236, 240, 1); | |||
| box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05); | |||
| padding: 24px; | |||
| min-width: 300px; | |||
| max-width: 300px; | |||
| cursor: pointer; | |||
| .titleWrapper { | |||
| @@ -16,8 +16,37 @@ const routes = [ | |||
| component: '@/pages/knowledge', | |||
| }, | |||
| { | |||
| path: '/knowledge/:module', | |||
| path: '/knowledge', | |||
| component: '@/pages/add-knowledge', | |||
| routes: [ | |||
| { | |||
| path: '/knowledge/dataset', | |||
| component: '@/pages/add-knowledge/components/knowledge-dataset', | |||
| routes: [ | |||
| { | |||
| path: '/knowledge/dataset', | |||
| component: '@/pages/add-knowledge/components/knowledge-file', | |||
| }, | |||
| { | |||
| path: '/knowledge/dataset/upload', | |||
| component: | |||
| '@/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file', | |||
| }, | |||
| { | |||
| path: '/knowledge/dataset/chunk', | |||
| component: '@/pages/add-knowledge/components/knowledge-chunk', | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| path: '/knowledge/configuration', | |||
| component: '@/pages/add-knowledge/components/knowledge-setting', | |||
| }, | |||
| { | |||
| path: '/knowledge/testing', | |||
| component: '@/pages/add-knowledge/components/knowledge-search', | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| path: '/chat', | |||
| @@ -20,6 +20,7 @@ const { | |||
| switch_chunk, | |||
| rm_chunk, | |||
| retrieval_test, | |||
| document_rename, | |||
| } = api; | |||
| const methods = { | |||
| @@ -57,6 +58,10 @@ const methods = { | |||
| url: document_rm, | |||
| method: 'post', | |||
| }, | |||
| document_rename: { | |||
| url: document_rename, | |||
| method: 'post', | |||
| }, | |||
| document_create: { | |||
| url: document_create, | |||
| method: 'post', | |||
| @@ -33,11 +33,12 @@ export default { | |||
| rm_chunk: `${api_host}/chunk/rm`, | |||
| retrieval_test: `${api_host}/chunk/retrieval_test`, | |||
| // 上传 | |||
| // 文件管理 | |||
| upload: `${api_host}/document/upload`, | |||
| get_document_list: `${api_host}/document/list`, | |||
| document_change_status: `${api_host}/document/change_status`, | |||
| document_rm: `${api_host}/document/rm`, | |||
| document_rename: `${api_host}/document/rename`, | |||
| document_create: `${api_host}/document/create`, | |||
| document_change_parser: `${api_host}/document/change_parser`, | |||
| }; | |||
| @@ -1,2 +1,4 @@ | |||
| import 'umi/typings'; | |||
| declare module 'lodash' | |||
| declare module 'lodash'; | |||
| export type Nullable<T> = T | null; | |||