| import { Flex, Form, InputNumber, Slider } from 'antd'; | |||||
| const MaxTokenNumber = () => { | |||||
| return ( | |||||
| <Form.Item | |||||
| label="Token number" | |||||
| tooltip="It determine the token number of a chunk approximately." | |||||
| > | |||||
| <Flex gap={20} align="center"> | |||||
| <Flex flex={1}> | |||||
| <Form.Item | |||||
| name={['parser_config', 'chunk_token_num']} | |||||
| noStyle | |||||
| initialValue={128} | |||||
| rules={[{ required: true, message: 'Province is required' }]} | |||||
| > | |||||
| <Slider max={2048} style={{ width: '100%' }} /> | |||||
| </Form.Item> | |||||
| </Flex> | |||||
| <Form.Item | |||||
| name={['parser_config', 'chunk_token_num']} | |||||
| noStyle | |||||
| rules={[{ required: true, message: 'Street is required' }]} | |||||
| > | |||||
| <InputNumber max={2048} min={0} /> | |||||
| </Form.Item> | |||||
| </Flex> | |||||
| </Form.Item> | |||||
| ); | |||||
| }; | |||||
| export default MaxTokenNumber; |
| import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge'; | import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge'; | ||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||||
| import { api_host } from '@/utils/api'; | import { api_host } from '@/utils/api'; | ||||
| import { buildChunkHighlights } from '@/utils/documentUtils'; | import { buildChunkHighlights } from '@/utils/documentUtils'; | ||||
| import { useCallback, useMemo } from 'react'; | import { useCallback, useMemo } from 'react'; | ||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | const { knowledgeId } = useGetKnowledgeSearchParams(); | ||||
| const setDocumentParser = useCallback( | const setDocumentParser = useCallback( | ||||
| (parserId: string, documentId: string) => { | |||||
| ( | |||||
| parserId: string, | |||||
| documentId: string, | |||||
| parserConfig: IChangeParserConfigRequestBody, | |||||
| ) => { | |||||
| try { | try { | ||||
| return dispatch<any>({ | return dispatch<any>({ | ||||
| type: 'kFModel/document_change_parser', | type: 'kFModel/document_change_parser', | ||||
| parser_id: parserId, | parser_id: parserId, | ||||
| doc_id: documentId, | doc_id: documentId, | ||||
| kb_id: knowledgeId, | kb_id: knowledgeId, | ||||
| parser_config: parserConfig, | |||||
| }, | }, | ||||
| }); | }); | ||||
| } catch (errorInfo) { | } catch (errorInfo) { |
| to_page: number; | to_page: number; | ||||
| } | } | ||||
| export interface IKnowledgeFileParserConfig { | |||||
| chunk_token_num: number; | |||||
| layout_recognize: boolean; | |||||
| pages: number[][]; | |||||
| task_page_size: number; | |||||
| } | |||||
| export interface IKnowledgeFile { | export interface IKnowledgeFile { | ||||
| chunk_num: number; | chunk_num: number; | ||||
| create_date: string; | create_date: string; | ||||
| type: string; | type: string; | ||||
| update_date: string; | update_date: string; | ||||
| update_time: number; | update_time: number; | ||||
| parser_config: IKnowledgeFileParserConfig; | |||||
| } | } | ||||
| export interface ITenantInfo { | export interface ITenantInfo { |
| export interface IChangeParserConfigRequestBody { | |||||
| pages: number[][]; | |||||
| chunk_token_num: number; | |||||
| layout_recognize: boolean; | |||||
| task_page_size: number; | |||||
| } | |||||
| export interface IChangeParserRequestBody { | |||||
| parser_id: string; | |||||
| doc_id: string; | |||||
| parser_config: IChangeParserConfigRequestBody; | |||||
| } |
| import { IModalManagerChildrenProps } from '@/components/modal-manager'; | import { IModalManagerChildrenProps } from '@/components/modal-manager'; | ||||
| import { | import { | ||||
| useFetchTenantInfo, | |||||
| useSelectParserList, | |||||
| } from '@/hooks/userSettingHook'; | |||||
| import { Modal, Space, Tag } from 'antd'; | |||||
| import React, { useEffect, useState } from 'react'; | |||||
| Button, | |||||
| Divider, | |||||
| Form, | |||||
| InputNumber, | |||||
| Modal, | |||||
| Space, | |||||
| Switch, | |||||
| Tag, | |||||
| } from 'antd'; | |||||
| import React, { useEffect, useMemo } from 'react'; | |||||
| import MaxTokenNumber from '@/components/max-token-number'; | |||||
| import { IKnowledgeFileParserConfig } from '@/interfaces/database/knowledge'; | |||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||||
| import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; | |||||
| import omit from 'lodash/omit'; | |||||
| import {} from 'module'; | |||||
| import { useFetchParserListOnMount } from './hooks'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> { | interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> { | ||||
| loading: boolean; | loading: boolean; | ||||
| onOk: (parserId: string) => void; | |||||
| onOk: ( | |||||
| parserId: string, | |||||
| parserConfig: IChangeParserConfigRequestBody, | |||||
| ) => void; | |||||
| showModal?(): void; | showModal?(): void; | ||||
| parser_id: string; | |||||
| parserId: string; | |||||
| parserConfig: IKnowledgeFileParserConfig; | |||||
| documentType: string; | |||||
| } | } | ||||
| const hidePagesChunkMethods = ['qa', 'table', 'picture', 'resume', 'one']; | |||||
| const ChunkMethodModal: React.FC<IProps> = ({ | const ChunkMethodModal: React.FC<IProps> = ({ | ||||
| parser_id, | |||||
| parserId, | |||||
| onOk, | onOk, | ||||
| hideModal, | hideModal, | ||||
| visible, | visible, | ||||
| documentType, | |||||
| parserConfig, | |||||
| }) => { | }) => { | ||||
| const [selectedTag, setSelectedTag] = useState(''); | |||||
| const parserList = useSelectParserList(); | |||||
| useFetchTenantInfo(); | |||||
| useEffect(() => { | |||||
| setSelectedTag(parser_id); | |||||
| }, [parser_id]); | |||||
| const { parserList, handleChange, selectedTag } = | |||||
| useFetchParserListOnMount(parserId); | |||||
| const [form] = Form.useForm(); | |||||
| const handleOk = async () => { | const handleOk = async () => { | ||||
| onOk(selectedTag); | |||||
| const values = await form.validateFields(); | |||||
| console.info(values); | |||||
| const parser_config = { | |||||
| ...values.parser_config, | |||||
| pages: values.pages?.map((x: any) => [x.from, x.to]) ?? [], | |||||
| }; | |||||
| console.info(parser_config); | |||||
| onOk(selectedTag, parser_config); | |||||
| }; | }; | ||||
| const handleChange = (tag: string, checked: boolean) => { | |||||
| const nextSelectedTag = checked ? tag : selectedTag; | |||||
| setSelectedTag(nextSelectedTag); | |||||
| const showPages = useMemo(() => { | |||||
| return ( | |||||
| documentType === 'pdf' && | |||||
| hidePagesChunkMethods.every((x) => x !== selectedTag) | |||||
| ); | |||||
| }, [documentType, selectedTag]); | |||||
| const showOne = useMemo(() => { | |||||
| return showPages || selectedTag === 'one'; | |||||
| }, [showPages, selectedTag]); | |||||
| const afterClose = () => { | |||||
| form.resetFields(); | |||||
| }; | }; | ||||
| useEffect(() => { | |||||
| if (visible) { | |||||
| const pages = | |||||
| parserConfig.pages?.map((x) => ({ from: x[0], to: x[1] })) ?? []; | |||||
| form.setFieldsValue({ | |||||
| pages: pages.length > 0 ? pages : [{ from: 1, to: 1024 }], | |||||
| parser_config: omit(parserConfig, 'pages'), | |||||
| }); | |||||
| } | |||||
| }, [form, parserConfig, visible]); | |||||
| return ( | return ( | ||||
| <Modal | <Modal | ||||
| title="Chunk Method" | title="Chunk Method" | ||||
| open={visible} | open={visible} | ||||
| onOk={handleOk} | onOk={handleOk} | ||||
| onCancel={hideModal} | onCancel={hideModal} | ||||
| afterClose={afterClose} | |||||
| > | > | ||||
| <Space size={[0, 8]} wrap> | <Space size={[0, 8]} wrap> | ||||
| <div className={styles.tags}> | <div className={styles.tags}> | ||||
| })} | })} | ||||
| </div> | </div> | ||||
| </Space> | </Space> | ||||
| <Divider></Divider> | |||||
| { | |||||
| <Form name="dynamic_form_nest_item" autoComplete="off" form={form}> | |||||
| {showPages && ( | |||||
| <> | |||||
| <Form.List name="pages"> | |||||
| {(fields, { add, remove }) => ( | |||||
| <> | |||||
| {fields.map(({ key, name, ...restField }) => ( | |||||
| <Space | |||||
| key={key} | |||||
| style={{ | |||||
| display: 'flex', | |||||
| }} | |||||
| align="baseline" | |||||
| > | |||||
| <Form.Item | |||||
| {...restField} | |||||
| name={[name, 'from']} | |||||
| dependencies={name > 0 ? [name - 1, 'to'] : []} | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: 'Missing start page number', | |||||
| }, | |||||
| ({ getFieldValue }) => ({ | |||||
| validator(_, value) { | |||||
| if ( | |||||
| name === 0 || | |||||
| !value || | |||||
| getFieldValue(['pages', name - 1, 'to']) < | |||||
| value | |||||
| ) { | |||||
| return Promise.resolve(); | |||||
| } | |||||
| return Promise.reject( | |||||
| new Error( | |||||
| 'The current value must be greater than the previous to!', | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| }), | |||||
| ]} | |||||
| > | |||||
| <InputNumber | |||||
| placeholder="from" | |||||
| min={0} | |||||
| precision={0} | |||||
| className={styles.pageInputNumber} | |||||
| /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| {...restField} | |||||
| name={[name, 'to']} | |||||
| dependencies={[name, 'from']} | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: 'Missing end page number(excluding)', | |||||
| }, | |||||
| ({ getFieldValue }) => ({ | |||||
| validator(_, value) { | |||||
| if ( | |||||
| !value || | |||||
| getFieldValue(['pages', name, 'from']) < value | |||||
| ) { | |||||
| return Promise.resolve(); | |||||
| } | |||||
| return Promise.reject( | |||||
| new Error( | |||||
| 'The current value must be greater than to!', | |||||
| ), | |||||
| ); | |||||
| }, | |||||
| }), | |||||
| ]} | |||||
| > | |||||
| <InputNumber | |||||
| placeholder="to" | |||||
| min={0} | |||||
| precision={0} | |||||
| className={styles.pageInputNumber} | |||||
| /> | |||||
| </Form.Item> | |||||
| {name > 0 && ( | |||||
| <MinusCircleOutlined onClick={() => remove(name)} /> | |||||
| )} | |||||
| </Space> | |||||
| ))} | |||||
| <Form.Item> | |||||
| <Button | |||||
| type="dashed" | |||||
| onClick={() => add()} | |||||
| block | |||||
| icon={<PlusOutlined />} | |||||
| > | |||||
| Add page | |||||
| </Button> | |||||
| </Form.Item> | |||||
| </> | |||||
| )} | |||||
| </Form.List> | |||||
| <Form.Item | |||||
| name={['parser_config', 'task_page_size']} | |||||
| label="Task page size" | |||||
| tooltip={'coming soon'} | |||||
| initialValue={2} | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: 'Please input your task page size!', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <InputNumber min={1} max={128} /> | |||||
| </Form.Item> | |||||
| </> | |||||
| )} | |||||
| {showOne && ( | |||||
| <Form.Item | |||||
| name={['parser_config', 'layout_recognize']} | |||||
| label="Layout recognize" | |||||
| initialValue={true} | |||||
| valuePropName="checked" | |||||
| tooltip={'coming soon'} | |||||
| > | |||||
| <Switch /> | |||||
| </Form.Item> | |||||
| )} | |||||
| {selectedTag === 'naive' && <MaxTokenNumber></MaxTokenNumber>} | |||||
| </Form> | |||||
| } | |||||
| </Modal> | </Modal> | ||||
| ); | ); | ||||
| }; | }; |
| } from '@/hooks/documentHooks'; | } from '@/hooks/documentHooks'; | ||||
| import { useGetKnowledgeSearchParams } from '@/hooks/routeHook'; | import { useGetKnowledgeSearchParams } from '@/hooks/routeHook'; | ||||
| import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; | import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; | ||||
| import { useFetchTenantInfo } from '@/hooks/userSettingHook'; | |||||
| import { | |||||
| useFetchTenantInfo, | |||||
| useSelectParserList, | |||||
| } from '@/hooks/userSettingHook'; | |||||
| import { Pagination } from '@/interfaces/common'; | import { Pagination } from '@/interfaces/common'; | ||||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | ||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||||
| import { PaginationProps } from 'antd'; | import { PaginationProps } from 'antd'; | ||||
| import { useCallback, useEffect, useMemo, useState } from 'react'; | import { useCallback, useEffect, useMemo, useState } from 'react'; | ||||
| import { useDispatch, useNavigate, useSelector } from 'umi'; | import { useDispatch, useNavigate, useSelector } from 'umi'; | ||||
| ]); | ]); | ||||
| const onChangeParserOk = useCallback( | const onChangeParserOk = useCallback( | ||||
| async (parserId: string) => { | |||||
| const ret = await setDocumentParser(parserId, documentId); | |||||
| async (parserId: string, parserConfig: IChangeParserConfigRequestBody) => { | |||||
| const ret = await setDocumentParser(parserId, documentId, parserConfig); | |||||
| if (ret === 0) { | if (ret === 0) { | ||||
| hideChangeParserModal(); | hideChangeParserModal(); | ||||
| } | } | ||||
| showChangeParserModal, | showChangeParserModal, | ||||
| }; | }; | ||||
| }; | }; | ||||
| export const useFetchParserListOnMount = (parserId: string) => { | |||||
| const [selectedTag, setSelectedTag] = useState(''); | |||||
| const parserList = useSelectParserList(); | |||||
| useFetchTenantInfo(); | |||||
| useEffect(() => { | |||||
| setSelectedTag(parserId); | |||||
| }, [parserId]); | |||||
| const handleChange = (tag: string, checked: boolean) => { | |||||
| const nextSelectedTag = checked ? tag : selectedTag; | |||||
| setSelectedTag(nextSelectedTag); | |||||
| }; | |||||
| return { parserList, handleChange, selectedTag }; | |||||
| }; |
| .tochunks { | .tochunks { | ||||
| cursor: pointer; | cursor: pointer; | ||||
| } | } | ||||
| .pageInputNumber { | |||||
| width: 220px; | |||||
| } |
| onOk={onCreateOk} | onOk={onCreateOk} | ||||
| /> | /> | ||||
| <ChunkMethodModal | <ChunkMethodModal | ||||
| parser_id={currentRecord.parser_id} | |||||
| parserId={currentRecord.parser_id} | |||||
| parserConfig={currentRecord.parser_config} | |||||
| documentType={currentRecord.type} | |||||
| onOk={onChangeParserOk} | onOk={onChangeParserOk} | ||||
| visible={changeParserVisible} | visible={changeParserVisible} | ||||
| hideModal={hideChangeParserModal} | hideModal={hideChangeParserModal} |
| import { DvaModel } from 'umi'; | import { DvaModel } from 'umi'; | ||||
| export interface KFModelState extends BaseState { | export interface KFModelState extends BaseState { | ||||
| isShowCEFwModal: boolean; | |||||
| isShowTntModal: boolean; | |||||
| isShowSegmentSetModal: boolean; | |||||
| isShowRenameModal: boolean; | |||||
| tenantIfo: any; | tenantIfo: any; | ||||
| data: IKnowledgeFile[]; | data: IKnowledgeFile[]; | ||||
| total: number; | total: number; | ||||
| const model: DvaModel<KFModelState> = { | const model: DvaModel<KFModelState> = { | ||||
| namespace: 'kFModel', | namespace: 'kFModel', | ||||
| state: { | state: { | ||||
| isShowCEFwModal: false, | |||||
| isShowTntModal: false, | |||||
| isShowSegmentSetModal: false, | |||||
| isShowRenameModal: false, | |||||
| tenantIfo: {}, | tenantIfo: {}, | ||||
| data: [], | data: [], | ||||
| total: 0, | total: 0, | ||||
| ...payload, | ...payload, | ||||
| }; | }; | ||||
| }, | }, | ||||
| setIsShowRenameModal(state, { payload }) { | |||||
| return { ...state, isShowRenameModal: payload }; | |||||
| }, | |||||
| setCurrentRecord(state, { payload }) { | setCurrentRecord(state, { payload }) { | ||||
| return { ...state, currentRecord: payload }; | return { ...state, currentRecord: payload }; | ||||
| }, | }, | ||||
| const { retcode } = data; | const { retcode } = data; | ||||
| if (retcode === 0) { | if (retcode === 0) { | ||||
| message.success('Modified!'); | message.success('Modified!'); | ||||
| put({ | |||||
| yield put({ | |||||
| type: 'getKfList', | type: 'getKfList', | ||||
| payload: { kb_id: payload.kb_id }, | payload: { kb_id: payload.kb_id }, | ||||
| }); | }); | ||||
| const { retcode } = data; | const { retcode } = data; | ||||
| if (retcode === 0) { | if (retcode === 0) { | ||||
| message.success('rename success!'); | message.success('rename success!'); | ||||
| yield put({ | |||||
| type: 'setIsShowRenameModal', | |||||
| payload: false, | |||||
| }); | |||||
| yield put({ | yield put({ | ||||
| type: 'getKfList', | type: 'getKfList', | ||||
| payload: { kb_id: payload.kb_id }, | payload: { kb_id: payload.kb_id }, | ||||
| const { data } = yield call(kbService.document_create, payload); | const { data } = yield call(kbService.document_create, payload); | ||||
| const { retcode } = data; | const { retcode } = data; | ||||
| if (retcode === 0) { | if (retcode === 0) { | ||||
| put({ | |||||
| yield put({ | |||||
| type: 'getKfList', | type: 'getKfList', | ||||
| payload: { kb_id: payload.kb_id }, | payload: { kb_id: payload.kb_id }, | ||||
| }); | }); | ||||
| put({ | |||||
| type: 'kFModel/updateState', | |||||
| payload: { | |||||
| isShowCEFwModal: false, | |||||
| }, | |||||
| }); | |||||
| message.success('Created!'); | message.success('Created!'); | ||||
| } | } | ||||
| return retcode; | return retcode; | ||||
| ); | ); | ||||
| const { retcode } = data; | const { retcode } = data; | ||||
| if (retcode === 0) { | if (retcode === 0) { | ||||
| put({ | |||||
| yield put({ | |||||
| type: 'getKfList', | type: 'getKfList', | ||||
| payload: { kb_id: payload.kb_id }, | payload: { kb_id: payload.kb_id }, | ||||
| }); | }); | ||||
| put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| isShowSegmentSetModal: false, | |||||
| }, | |||||
| }); | |||||
| message.success('Modified!'); | message.success('Modified!'); | ||||
| } | } | ||||
| return retcode; | return retcode; |
| import { normFile } from '@/utils/fileUtil'; | import { normFile } from '@/utils/fileUtil'; | ||||
| import { PlusOutlined } from '@ant-design/icons'; | import { PlusOutlined } from '@ant-design/icons'; | ||||
| import { | |||||
| Button, | |||||
| Flex, | |||||
| Form, | |||||
| Input, | |||||
| InputNumber, | |||||
| Radio, | |||||
| Select, | |||||
| Slider, | |||||
| Space, | |||||
| Upload, | |||||
| } from 'antd'; | |||||
| import { Button, Form, Input, Radio, Select, Space, Upload } from 'antd'; | |||||
| import { | import { | ||||
| useFetchKnowledgeConfigurationOnMount, | useFetchKnowledgeConfigurationOnMount, | ||||
| useSubmitKnowledgeConfiguration, | useSubmitKnowledgeConfiguration, | ||||
| } from './hooks'; | } from './hooks'; | ||||
| import MaxTokenNumber from '@/components/max-token-number'; | |||||
| import { FormInstance } from 'antd/lib'; | import { FormInstance } from 'antd/lib'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const parserId = getFieldValue('parser_id'); | const parserId = getFieldValue('parser_id'); | ||||
| if (parserId === 'naive') { | if (parserId === 'naive') { | ||||
| return ( | |||||
| <Form.Item label="Token number" tooltip="It determine the token number of a chunk approximately."> | |||||
| <Flex gap={20} align="center"> | |||||
| <Flex flex={1}> | |||||
| <Form.Item | |||||
| name={['parser_config', 'chunk_token_num']} | |||||
| noStyle | |||||
| initialValue={128} | |||||
| rules={[ | |||||
| { required: true, message: 'Province is required' }, | |||||
| ]} | |||||
| > | |||||
| <Slider className={styles.variableSlider} max={2048} /> | |||||
| </Form.Item> | |||||
| </Flex> | |||||
| <Form.Item | |||||
| name={['parser_config', 'chunk_token_num']} | |||||
| noStyle | |||||
| rules={[{ required: true, message: 'Street is required' }]} | |||||
| > | |||||
| <InputNumber | |||||
| className={styles.sliderInputNumber} | |||||
| max={2048} | |||||
| min={0} | |||||
| /> | |||||
| </Form.Item> | |||||
| </Flex> | |||||
| </Form.Item> | |||||
| ); | |||||
| return <MaxTokenNumber></MaxTokenNumber>; | |||||
| } | } | ||||
| return null; | return null; | ||||
| }} | }} |
| export interface KSModelState { | export interface KSModelState { | ||||
| isShowPSwModal: boolean; | isShowPSwModal: boolean; | ||||
| isShowTntModal: boolean; | |||||
| tenantIfo: any; | tenantIfo: any; | ||||
| knowledgeDetails: IKnowledge; | knowledgeDetails: IKnowledge; | ||||
| } | } | ||||
| namespace: 'kSModel', | namespace: 'kSModel', | ||||
| state: { | state: { | ||||
| isShowPSwModal: false, | isShowPSwModal: false, | ||||
| isShowTntModal: false, | |||||
| tenantIfo: {}, | tenantIfo: {}, | ||||
| knowledgeDetails: {} as any, | knowledgeDetails: {} as any, | ||||
| }, | }, |
| export const ImageMap = { | export const ImageMap = { | ||||
| book: getImageName('book', 4), | book: getImageName('book', 4), | ||||
| laws: getImageName('law', 4), | |||||
| laws: getImageName('law', 2), | |||||
| manual: getImageName('manual', 4), | manual: getImageName('manual', 4), | ||||
| picture: getImageName('picture', 2), | |||||
| picture: getImageName('media', 2), | |||||
| naive: getImageName('naive', 2), | naive: getImageName('naive', 2), | ||||
| paper: getImageName('paper', 2), | paper: getImageName('paper', 2), | ||||
| presentation: getImageName('presentation', 2), | presentation: getImageName('presentation', 2), | ||||
| The chunk granularity is consistent with 'ARTICLE', and all the upper level text will be included in the chunk. | The chunk granularity is consistent with 'ARTICLE', and all the upper level text will be included in the chunk. | ||||
| </p>`, | </p>`, | ||||
| }, | }, | ||||
| manual: { title: '', description: `<p>Only <b>PDF</b> is supported.</p><p> | |||||
| manual: { | |||||
| title: '', | |||||
| description: `<p>Only <b>PDF</b> is supported.</p><p> | |||||
| We assume manual has hierarchical section structure. We use the lowest section titles as pivots to slice documents. | We assume manual has hierarchical section structure. We use the lowest section titles as pivots to slice documents. | ||||
| So, the figures and tables in the same section will not be sliced apart, and chunk size might be large. | So, the figures and tables in the same section will not be sliced apart, and chunk size might be large. | ||||
| </p>` }, | |||||
| </p>`, | |||||
| }, | |||||
| naive: { | naive: { | ||||
| title: '', | title: '', | ||||
| description: `<p>Supported file formats are <b>DOCX, EXCEL, PPT, IMAGE, PDF, TXT</b>.</p> | description: `<p>Supported file formats are <b>DOCX, EXCEL, PPT, IMAGE, PDF, TXT</b>.</p> | ||||
| </li> | </li> | ||||
| <li>Every row in table will be treated as a chunk.</li> | <li>Every row in table will be treated as a chunk.</li> | ||||
| </ul>`, | </ul>`, | ||||
| }, | |||||
| picture: { | |||||
| title: '', | |||||
| description: ` | |||||
| }, | |||||
| picture: { | |||||
| title: '', | |||||
| description: ` | |||||
| <p>Image files are supported. Video is coming soon.</p><p> | <p>Image files are supported. Video is coming soon.</p><p> | ||||
| If the picture has text in it, OCR is applied to extract the text as its text description. | If the picture has text in it, OCR is applied to extract the text as its text description. | ||||
| </p><p> | </p><p> | ||||
| If the text extracted by OCR is not enough, visual LLM is used to get the descriptions. | If the text extracted by OCR is not enough, visual LLM is used to get the descriptions. | ||||
| </p>`, | </p>`, | ||||
| }, | }, | ||||
| one: { | |||||
| title: '', | |||||
| description: ` | |||||
| one: { | |||||
| title: '', | |||||
| description: ` | |||||
| <p>Supported file formats are <b>DOCX, EXCEL, PDF, TXT</b>. | <p>Supported file formats are <b>DOCX, EXCEL, PDF, TXT</b>. | ||||
| </p><p> | </p><p> | ||||
| For a document, it will be treated as an entire chunk, no split at all. | For a document, it will be treated as an entire chunk, no split at all. |
| import { DvaModel } from 'umi'; | import { DvaModel } from 'umi'; | ||||
| export interface kAModelState { | export interface kAModelState { | ||||
| isShowPSwModal: boolean; | isShowPSwModal: boolean; | ||||
| isShowTntModal: boolean; | |||||
| tenantIfo: any; | tenantIfo: any; | ||||
| id: string; | id: string; | ||||
| doc_id: string; | doc_id: string; | ||||
| namespace: 'kAModel', | namespace: 'kAModel', | ||||
| state: { | state: { | ||||
| isShowPSwModal: false, | isShowPSwModal: false, | ||||
| isShowTntModal: false, | |||||
| tenantIfo: {}, | tenantIfo: {}, | ||||
| id: '', | id: '', | ||||
| doc_id: '', | doc_id: '', |
| import { rsaPsw } from '@/utils'; | |||||
| import { Form, Input, Modal } from 'antd'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { useDispatch, useSelector } from 'umi'; | |||||
| type FieldType = { | |||||
| newPassword?: string; | |||||
| password?: string; | |||||
| }; | |||||
| const CpwModal = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const settingModel = useSelector((state: any) => state.settingModel); | |||||
| const { isShowPSwModal } = settingModel; | |||||
| const { t } = useTranslation(); | |||||
| const [form] = Form.useForm(); | |||||
| const handleCancel = () => { | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| isShowPSwModal: false, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const handleOk = async () => { | |||||
| try { | |||||
| const values = await form.validateFields(); | |||||
| var password = rsaPsw(values.password); | |||||
| var new_password = rsaPsw(values.newPassword); | |||||
| dispatch({ | |||||
| type: 'settingModel/setting', | |||||
| payload: { | |||||
| password, | |||||
| new_password, | |||||
| }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| } | |||||
| }; | |||||
| return ( | |||||
| <Modal | |||||
| title="Basic Modal" | |||||
| open={isShowPSwModal} | |||||
| onOk={handleOk} | |||||
| onCancel={handleCancel} | |||||
| > | |||||
| <Form | |||||
| form={form} | |||||
| labelCol={{ span: 8 }} | |||||
| wrapperCol={{ span: 16 }} | |||||
| style={{ maxWidth: 600 }} | |||||
| autoComplete="off" | |||||
| > | |||||
| <Form.Item<FieldType> | |||||
| label="旧密码" | |||||
| name="password" | |||||
| rules={[{ required: true, message: 'Please input value' }]} | |||||
| > | |||||
| <Input.Password /> | |||||
| </Form.Item> | |||||
| <Form.Item<FieldType> | |||||
| label="新密码" | |||||
| name="newPassword" | |||||
| rules={[ | |||||
| { required: true, message: 'Please input your newPassword!' }, | |||||
| ]} | |||||
| > | |||||
| <Input.Password /> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </Modal> | |||||
| ); | |||||
| }; | |||||
| export default CpwModal; |
| import { useTranslation } from 'react-i18next'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import styles from './index.less'; | |||||
| import { RadarChartOutlined } from '@ant-design/icons'; | |||||
| import { ProCard } from '@ant-design/pro-components'; | |||||
| import { Button, Card, Col, Row, Tag } from 'antd'; | |||||
| import { useDispatch, useSelector } from 'umi'; | |||||
| interface DataType { | |||||
| key: React.Key; | |||||
| name: string; | |||||
| age: number; | |||||
| address: string; | |||||
| description: string; | |||||
| } | |||||
| const SettingList = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const settingModel = useSelector((state: any) => state.settingModel); | |||||
| const { llmInfo = {}, factoriesList, myLlm = [] } = settingModel; | |||||
| const { OpenAI = [], tongyi = [] } = llmInfo; | |||||
| const [collapsed, setCollapsed] = useState(true); | |||||
| const { t } = useTranslation(); | |||||
| useEffect(() => { | |||||
| dispatch({ | |||||
| type: 'settingModel/factories_list', | |||||
| payload: {}, | |||||
| }); | |||||
| dispatch({ | |||||
| type: 'settingModel/llm_list', | |||||
| payload: {}, | |||||
| }); | |||||
| dispatch({ | |||||
| type: 'settingModel/my_llm', | |||||
| payload: {}, | |||||
| }); | |||||
| }, [dispatch]); | |||||
| return ( | |||||
| <div | |||||
| className={styles.list} | |||||
| style={{ | |||||
| display: 'flex', | |||||
| flexDirection: 'column', | |||||
| padding: 24, | |||||
| gap: 12, | |||||
| }} | |||||
| > | |||||
| {myLlm.map((item: any) => { | |||||
| return ( | |||||
| <ProCard | |||||
| key={item.llm_factory} | |||||
| // title={<div>可折叠-图标自定义</div>} | |||||
| collapsibleIconRender={({ | |||||
| collapsed: buildInCollapsed, | |||||
| }: { | |||||
| collapsed: boolean; | |||||
| }) => { | |||||
| return ( | |||||
| <div> | |||||
| <h3> | |||||
| <RadarChartOutlined /> | |||||
| {item.llm_factory} | |||||
| </h3> | |||||
| <div> | |||||
| {item.tags.split(',').map((d: string) => { | |||||
| return <Tag key={d}>{d}</Tag>; | |||||
| })} | |||||
| </div> | |||||
| {buildInCollapsed ? ( | |||||
| <span>显示{OpenAI.length}个模型</span> | |||||
| ) : ( | |||||
| <span>收起{OpenAI.length}个模型 </span> | |||||
| )} | |||||
| </div> | |||||
| ); | |||||
| }} | |||||
| extra={ | |||||
| <Button | |||||
| size="small" | |||||
| type="link" | |||||
| onClick={(e) => { | |||||
| e.stopPropagation(); | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| llm_factory: item.llm_factory, | |||||
| isShowSAKModal: true, | |||||
| }, | |||||
| }); | |||||
| }} | |||||
| > | |||||
| 设置 | |||||
| </Button> | |||||
| } | |||||
| style={{ marginBlockStart: 16 }} | |||||
| headerBordered | |||||
| collapsible | |||||
| defaultCollapsed | |||||
| ></ProCard> | |||||
| ); | |||||
| })} | |||||
| <Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}> | |||||
| {factoriesList.map((item: any) => { | |||||
| return ( | |||||
| <Col key={item.name} xs={24} sm={12} md={8} lg={6}> | |||||
| <Card | |||||
| title={item.name} | |||||
| bordered={false} | |||||
| extra={ | |||||
| <Button | |||||
| size="small" | |||||
| type="link" | |||||
| onClick={(e) => { | |||||
| e.stopPropagation(); | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| llm_factory: item.name, | |||||
| isShowSAKModal: true, | |||||
| }, | |||||
| }); | |||||
| }} | |||||
| > | |||||
| 设置 | |||||
| </Button> | |||||
| } | |||||
| > | |||||
| <div> | |||||
| {item.tags.split(',').map((d: string) => { | |||||
| return <Tag key={d}>{d}</Tag>; | |||||
| })} | |||||
| </div> | |||||
| </Card> | |||||
| </Col> | |||||
| ); | |||||
| })} | |||||
| </Row> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| export default SettingList; |
| import { Form, Input, Modal } from 'antd'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { useDispatch, useSelector } from 'umi'; | |||||
| type FieldType = { | |||||
| api_key?: string; | |||||
| }; | |||||
| const SakModal = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const settingModel = useSelector((state: any) => state.settingModel); | |||||
| const { isShowSAKModal, llm_factory } = settingModel; | |||||
| const { t } = useTranslation(); | |||||
| const [form] = Form.useForm(); | |||||
| const handleCancel = () => { | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| isShowSAKModal: false, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const handleOk = async () => { | |||||
| try { | |||||
| const values = await form.validateFields(); | |||||
| dispatch({ | |||||
| type: 'settingModel/set_api_key', | |||||
| payload: { | |||||
| api_key: values.api_key, | |||||
| llm_factory: llm_factory, | |||||
| }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| } | |||||
| }; | |||||
| return ( | |||||
| <Modal | |||||
| title="Basic Modal" | |||||
| open={isShowSAKModal} | |||||
| onOk={handleOk} | |||||
| onCancel={handleCancel} | |||||
| > | |||||
| <Form | |||||
| form={form} | |||||
| name="validateOnly" | |||||
| labelCol={{ span: 8 }} | |||||
| wrapperCol={{ span: 16 }} | |||||
| style={{ maxWidth: 600 }} | |||||
| autoComplete="off" | |||||
| > | |||||
| <Form.Item<FieldType> | |||||
| label="API Key" | |||||
| name="api_key" | |||||
| rules={[{ required: true, message: 'Please input ' }]} | |||||
| > | |||||
| <Input /> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </Modal> | |||||
| ); | |||||
| }; | |||||
| export default SakModal; |
| import { Form, Modal, Select } from 'antd'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { useDispatch, useSelector } from 'umi'; | |||||
| type FieldType = { | |||||
| embd_id?: string; | |||||
| img2txt_id?: string; | |||||
| llm_id?: string; | |||||
| asr_id?: string; | |||||
| }; | |||||
| const SsModal = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const settingModel = useSelector((state: any) => state.settingModel); | |||||
| const { isShowSSModal, llmInfo = {}, tenantIfo } = settingModel; | |||||
| const [form] = Form.useForm(); | |||||
| const { t } = useTranslation(); | |||||
| const handleCancel = () => { | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| isShowSSModal: false, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const handleOk = async () => { | |||||
| try { | |||||
| const values = await form.validateFields(); | |||||
| const retcode = await dispatch<any>({ | |||||
| type: 'settingModel/set_tenant_info', | |||||
| payload: { | |||||
| ...values, | |||||
| tenant_id: tenantIfo.tenant_id, | |||||
| }, | |||||
| }); | |||||
| retcode === 0 && | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| isShowSSModal: false, | |||||
| }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| } | |||||
| }; | |||||
| const handleChange = () => {}; | |||||
| return ( | |||||
| <Modal | |||||
| title="Basic Modal" | |||||
| open={isShowSSModal} | |||||
| onOk={handleOk} | |||||
| onCancel={handleCancel} | |||||
| > | |||||
| <Form | |||||
| form={form} | |||||
| name="validateOnly" | |||||
| // labelCol={{ span: 8 }} | |||||
| // wrapperCol={{ span: 16 }} | |||||
| style={{ maxWidth: 600 }} | |||||
| autoComplete="off" | |||||
| layout="vertical" | |||||
| > | |||||
| <Form.Item<FieldType> | |||||
| label="embedding 模型" | |||||
| name="embd_id" | |||||
| rules={[{ required: true, message: 'Please input value' }]} | |||||
| initialValue={tenantIfo.embd_id} | |||||
| > | |||||
| <Select | |||||
| // style={{ width: 200 }} | |||||
| onChange={handleChange} | |||||
| // fieldNames={label:} | |||||
| options={Object.keys(llmInfo).map((t) => { | |||||
| const options = llmInfo[t] | |||||
| .filter((d: any) => d.model_type === 'embedding') | |||||
| .map((d: any) => ({ label: d.llm_name, value: d.llm_name })); | |||||
| return { label: t, options }; | |||||
| })} | |||||
| /> | |||||
| </Form.Item> | |||||
| <Form.Item<FieldType> | |||||
| label="chat 模型" | |||||
| name="llm_id" | |||||
| rules={[{ required: true, message: 'Please input value' }]} | |||||
| initialValue={tenantIfo.llm_id} | |||||
| > | |||||
| <Select | |||||
| // style={{ width: 200 }} | |||||
| onChange={handleChange} | |||||
| // fieldNames={label:} | |||||
| options={Object.keys(llmInfo).map((t) => { | |||||
| const options = llmInfo[t] | |||||
| .filter((d: any) => d.model_type === 'chat') | |||||
| .map((d: any) => ({ label: d.llm_name, value: d.llm_name })); | |||||
| return { label: t, options }; | |||||
| })} | |||||
| /> | |||||
| </Form.Item> | |||||
| <Form.Item<FieldType> | |||||
| label="image2text 模型" | |||||
| name="img2txt_id" | |||||
| rules={[{ required: true, message: 'Please input value' }]} | |||||
| initialValue={tenantIfo.img2txt_id} | |||||
| > | |||||
| <Select | |||||
| // style={{ width: 200 }} | |||||
| onChange={handleChange} | |||||
| // fieldNames={label:} | |||||
| options={Object.keys(llmInfo).map((t) => { | |||||
| const options = llmInfo[t] | |||||
| .filter((d: any) => d.model_type === 'image2text') | |||||
| .map((d: any) => ({ label: d.llm_name, value: d.llm_name })); | |||||
| return { label: t, options }; | |||||
| })} | |||||
| /> | |||||
| </Form.Item> | |||||
| <Form.Item<FieldType> | |||||
| label="speech2text 模型" | |||||
| name="asr_id" | |||||
| rules={[{ required: true, message: 'Please input value' }]} | |||||
| initialValue={tenantIfo.asr_id} | |||||
| > | |||||
| <Select | |||||
| // style={{ width: 200 }} | |||||
| onChange={handleChange} | |||||
| // fieldNames={label:} | |||||
| options={Object.keys(llmInfo).map((t) => { | |||||
| const options = llmInfo[t] | |||||
| .filter((d: any) => d.model_type === 'speech2text') | |||||
| .map((d: any) => ({ label: d.llm_name, value: d.llm_name })); | |||||
| return { label: t, options }; | |||||
| })} | |||||
| /> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </Modal> | |||||
| ); | |||||
| }; | |||||
| export default SsModal; |
| import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; | |||||
| import { Modal, Table } from 'antd'; | |||||
| import { ColumnsType } from 'antd/es/table'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { useDispatch, useSelector } from 'umi'; | |||||
| import styles from './index.less'; | |||||
| interface DataType { | |||||
| key: React.Key; | |||||
| name: string; | |||||
| role: string; | |||||
| time: string; | |||||
| } | |||||
| const TntModal = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const settingModel = useSelector((state: any) => state.settingModel); | |||||
| const { isShowTntModal, tenantIfo, factoriesList } = settingModel; | |||||
| const { t } = useTranslation(); | |||||
| const loading = useOneNamespaceEffectsLoading('settingModel', [ | |||||
| 'getTenantInfo', | |||||
| ]); | |||||
| const columns: ColumnsType<DataType> = [ | |||||
| { title: '姓名', dataIndex: 'name', key: 'name' }, | |||||
| { title: '活动时间', dataIndex: 'update_date', key: 'update_date' }, | |||||
| { title: '角色', dataIndex: 'role', key: 'age' }, | |||||
| ]; | |||||
| const handleCancel = () => { | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| isShowTntModal: false, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const handleOk = async () => { | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| isShowTntModal: false, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| return ( | |||||
| <Modal | |||||
| title="用户" | |||||
| open={isShowTntModal} | |||||
| onOk={handleOk} | |||||
| onCancel={handleCancel} | |||||
| > | |||||
| <div className={styles.tenantIfo}>{tenantIfo.name}</div> | |||||
| <Table | |||||
| rowKey="name" | |||||
| loading={loading} | |||||
| columns={columns} | |||||
| dataSource={factoriesList} | |||||
| /> | |||||
| </Modal> | |||||
| ); | |||||
| }; | |||||
| export default TntModal; |
| .settingPage { | |||||
| padding: 10px; | |||||
| } | |||||
| .avatar { | |||||
| display: flex; | |||||
| justify-content: center; | |||||
| } | |||||
| .tenantIfo { | |||||
| height: 50px; | |||||
| background-color: #f4dfdf; | |||||
| margin-bottom: 10px; | |||||
| padding: 5px; | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| .list { | |||||
| :global { | |||||
| .ant-pro-card-header { | |||||
| height: 150px; | |||||
| background-color: rgb(229, 231, 235); | |||||
| } | |||||
| } | |||||
| } | |||||
| ul { | |||||
| li { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| margin-bottom: 5px; | |||||
| .statusDisaabled { | |||||
| width: 10px; | |||||
| height: 10px; | |||||
| border-radius: 40%; | |||||
| background: rgba(0, 0, 0, 0.4); | |||||
| } | |||||
| .statusAvailable { | |||||
| width: 10px; | |||||
| height: 10px; | |||||
| border-radius: 50%; | |||||
| background: green; | |||||
| } | |||||
| } | |||||
| } |
| import { Button, FloatButton } from 'antd'; | |||||
| import i18n from 'i18next'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import authorizationUtil from '@/utils/authorizationUtil'; | |||||
| import { useEffect } from 'react'; | |||||
| import { useDispatch, useSelector } from 'umi'; | |||||
| import CPwModal from './CPwModal'; | |||||
| import List from './List'; | |||||
| import SAKModal from './SAKModal'; | |||||
| import SSModal from './SSModal'; | |||||
| import TntModal from './TntModal'; | |||||
| import styles from './index.less'; | |||||
| const Setting = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const settingModel = useSelector((state: any) => state.settingModel); | |||||
| const { t } = useTranslation(); | |||||
| const userInfo = authorizationUtil.getUserInfoObject(); | |||||
| const changeLang = (val: string) => { | |||||
| // 改变状态里的 语言 进行切换 | |||||
| i18n.changeLanguage(val); | |||||
| }; | |||||
| useEffect(() => { | |||||
| dispatch({ | |||||
| type: 'settingModel/getTenantInfo', | |||||
| payload: {}, | |||||
| }); | |||||
| }, []); | |||||
| const showCPwModal = () => { | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| isShowPSwModal: true, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const showTntModal = () => { | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| isShowTntModal: true, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const showSSModal = () => { | |||||
| dispatch({ | |||||
| type: 'settingModel/updateState', | |||||
| payload: { | |||||
| isShowSSModal: true, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| return ( | |||||
| <div className={styles.settingPage}> | |||||
| <div className={styles.avatar}> | |||||
| <img | |||||
| style={{ width: 50, marginRight: 5 }} | |||||
| src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" | |||||
| alt="" | |||||
| /> | |||||
| <div> | |||||
| <div>账号:{userInfo.name}</div> | |||||
| <div> | |||||
| <span>密码:******</span> | |||||
| <Button type="link" onClick={showCPwModal}> | |||||
| 修改密码 | |||||
| </Button> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div> | |||||
| <Button type="link" onClick={showTntModal}> | |||||
| 租户 | |||||
| </Button> | |||||
| <Button type="link" onClick={showSSModal}> | |||||
| 系统模型设置 | |||||
| </Button> | |||||
| <List /> | |||||
| </div> | |||||
| <CPwModal /> | |||||
| <SAKModal /> | |||||
| <SSModal /> | |||||
| <TntModal /> | |||||
| <FloatButton | |||||
| shape="square" | |||||
| description={t('setting.btn')} | |||||
| onClick={() => i18n.changeLanguage(i18n.language == 'en' ? 'zh' : 'en')} | |||||
| type="default" | |||||
| style={{ right: 94, fontSize: 14 }} | |||||
| /> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| export default Setting; |
| import { ITenantInfo } from '@/interfaces/database/knowledge'; | |||||
| import { | |||||
| IFactory, | |||||
| IMyLlmValue, | |||||
| IThirdOAIModelCollection as IThirdAiModelCollection, | |||||
| } from '@/interfaces/database/llm'; | |||||
| import { IUserInfo } from '@/interfaces/database/userSetting'; | |||||
| import userService from '@/services/userService'; | |||||
| import { message } from 'antd'; | |||||
| import { DvaModel } from 'umi'; | |||||
| export interface SettingModelState { | |||||
| llm_factory: string; | |||||
| tenantIfo: Nullable<ITenantInfo>; | |||||
| llmInfo: IThirdAiModelCollection; | |||||
| myLlmList: Record<string, IMyLlmValue>; | |||||
| factoryList: IFactory[]; | |||||
| userInfo: IUserInfo; | |||||
| } | |||||
| const model: DvaModel<SettingModelState> = { | |||||
| namespace: 'settingModel', | |||||
| state: { | |||||
| llm_factory: '', | |||||
| tenantIfo: null, | |||||
| llmInfo: {}, | |||||
| myLlmList: {}, | |||||
| factoryList: [], | |||||
| userInfo: {} as IUserInfo, | |||||
| }, | |||||
| reducers: { | |||||
| updateState(state, { payload }) { | |||||
| return { | |||||
| ...state, | |||||
| ...payload, | |||||
| }; | |||||
| }, | |||||
| setUserInfo(state, { payload }) { | |||||
| return { | |||||
| ...state, | |||||
| userInfo: payload, | |||||
| }; | |||||
| }, | |||||
| }, | |||||
| effects: { | |||||
| *setting({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.setting, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success('Modified!'); | |||||
| yield put({ | |||||
| type: 'getUserInfo', | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *getUserInfo({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.user_info, payload); | |||||
| const { retcode, data: res } = data; | |||||
| // const userInfo = { | |||||
| // avatar: res.avatar, | |||||
| // name: res.nickname, | |||||
| // email: res.email, | |||||
| // }; | |||||
| // authorizationUtil.setUserInfo(userInfo); | |||||
| if (retcode === 0) { | |||||
| yield put({ type: 'setUserInfo', payload: res }); | |||||
| // localStorage.setItem('userInfo',res.) | |||||
| } | |||||
| }, | |||||
| *getTenantInfo({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.get_tenant_info, payload); | |||||
| const { retcode, data: res } = data; | |||||
| // llm_id 对应chat_id | |||||
| // asr_id 对应speech2txt | |||||
| if (retcode === 0) { | |||||
| res.chat_id = res.llm_id; | |||||
| res.speech2text_id = res.asr_id; | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| tenantIfo: res, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *set_tenant_info({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.set_tenant_info, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success('Modified!'); | |||||
| yield put({ | |||||
| type: 'getTenantInfo', | |||||
| }); | |||||
| } | |||||
| return retcode; | |||||
| }, | |||||
| *factories_list({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.factories_list); | |||||
| const { retcode, data: res } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| factoryList: res, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *llm_list({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.llm_list, payload); | |||||
| const { retcode, data: res } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| llmInfo: res, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *my_llm({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.my_llm); | |||||
| const { retcode, data: res } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| myLlmList: res, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *set_api_key({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.set_api_key, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success('Modified!'); | |||||
| yield put({ type: 'my_llm' }); | |||||
| yield put({ type: 'factories_list' }); | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| }); | |||||
| } | |||||
| return retcode; | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| export default model; | |||||
| import { ITenantInfo } from '@/interfaces/database/knowledge'; | |||||
| import { | |||||
| IFactory, | |||||
| IMyLlmValue, | |||||
| IThirdOAIModelCollection as IThirdAiModelCollection, | |||||
| } from '@/interfaces/database/llm'; | |||||
| import { IUserInfo } from '@/interfaces/database/userSetting'; | |||||
| import userService from '@/services/userService'; | |||||
| import { message } from 'antd'; | |||||
| import { DvaModel } from 'umi'; | |||||
| export interface SettingModelState { | |||||
| llm_factory: string; | |||||
| tenantIfo: Nullable<ITenantInfo>; | |||||
| llmInfo: IThirdAiModelCollection; | |||||
| myLlmList: Record<string, IMyLlmValue>; | |||||
| factoryList: IFactory[]; | |||||
| userInfo: IUserInfo; | |||||
| } | |||||
| const model: DvaModel<SettingModelState> = { | |||||
| namespace: 'settingModel', | |||||
| state: { | |||||
| llm_factory: '', | |||||
| tenantIfo: null, | |||||
| llmInfo: {}, | |||||
| myLlmList: {}, | |||||
| factoryList: [], | |||||
| userInfo: {} as IUserInfo, | |||||
| }, | |||||
| reducers: { | |||||
| updateState(state, { payload }) { | |||||
| return { | |||||
| ...state, | |||||
| ...payload, | |||||
| }; | |||||
| }, | |||||
| setUserInfo(state, { payload }) { | |||||
| return { | |||||
| ...state, | |||||
| userInfo: payload, | |||||
| }; | |||||
| }, | |||||
| }, | |||||
| effects: { | |||||
| *setting({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.setting, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success('Modified!'); | |||||
| yield put({ | |||||
| type: 'getUserInfo', | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *getUserInfo({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.user_info, payload); | |||||
| const { retcode, data: res } = data; | |||||
| // const userInfo = { | |||||
| // avatar: res.avatar, | |||||
| // name: res.nickname, | |||||
| // email: res.email, | |||||
| // }; | |||||
| // authorizationUtil.setUserInfo(userInfo); | |||||
| if (retcode === 0) { | |||||
| yield put({ type: 'setUserInfo', payload: res }); | |||||
| // localStorage.setItem('userInfo',res.) | |||||
| } | |||||
| }, | |||||
| *getTenantInfo({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.get_tenant_info, payload); | |||||
| const { retcode, data: res } = data; | |||||
| // llm_id 对应chat_id | |||||
| // asr_id 对应speech2txt | |||||
| if (retcode === 0) { | |||||
| res.chat_id = res.llm_id; | |||||
| res.speech2text_id = res.asr_id; | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| tenantIfo: res, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *set_tenant_info({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.set_tenant_info, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success('Modified!'); | |||||
| yield put({ | |||||
| type: 'getTenantInfo', | |||||
| }); | |||||
| } | |||||
| return retcode; | |||||
| }, | |||||
| *factories_list({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.factories_list); | |||||
| const { retcode, data: res } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| factoryList: res, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *llm_list({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.llm_list, payload); | |||||
| const { retcode, data: res } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| llmInfo: res, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *my_llm({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.my_llm); | |||||
| const { retcode, data: res } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| myLlmList: res, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *set_api_key({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(userService.set_api_key, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success('Modified!'); | |||||
| yield put({ type: 'my_llm' }); | |||||
| yield put({ type: 'factories_list' }); | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| }); | |||||
| } | |||||
| return retcode; | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| export default model; |
| path: '/chat', | path: '/chat', | ||||
| component: '@/pages/chat', | component: '@/pages/chat', | ||||
| }, | }, | ||||
| { | |||||
| path: '/setting', | |||||
| component: '@/pages/setting', | |||||
| }, | |||||
| { | { | ||||
| path: '/user-setting', | path: '/user-setting', | ||||
| component: '@/pages/user-setting', | component: '@/pages/user-setting', |