feat: add pages to ChunkMethodModal (#143)
|
Before Width: | Height: | Size: 298 KiB After Width: | Height: | Size: 757 KiB |
|
Before Width: | Height: | Size: 660 KiB After Width: | Height: | Size: 545 KiB |
|
Before Width: | Height: | Size: 638 KiB |
|
Before Width: | Height: | Size: 902 KiB |
|
Before Width: | Height: | Size: 590 KiB After Width: | Height: | Size: 515 KiB |
|
Before Width: | Height: | Size: 342 KiB After Width: | Height: | Size: 390 KiB |
|
Before Width: | Height: | Size: 461 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 408 KiB After Width: | Height: | Size: 321 KiB |
79
web/src/assets/svg/chunk-method/one-01.svg
Normal file
|
After Width: | Height: | Size: 590 KiB |
79
web/src/assets/svg/chunk-method/one-02.svg
Normal file
|
After Width: | Height: | Size: 342 KiB |
80
web/src/assets/svg/chunk-method/one-03.svg
Normal file
|
After Width: | Height: | Size: 461 KiB |
79
web/src/assets/svg/chunk-method/one-04.svg
Normal file
|
After Width: | Height: | Size: 408 KiB |
|
Before Width: | Height: | Size: 444 KiB After Width: | Height: | Size: 393 KiB |
|
Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 152 KiB |
32
web/src/components/max-token-number.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
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;
|
||||
@ -1,4 +1,5 @@
|
||||
import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge';
|
||||
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
||||
import { api_host } from '@/utils/api';
|
||||
import { buildChunkHighlights } from '@/utils/documentUtils';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
@ -117,7 +118,11 @@ export const useSetDocumentParser = () => {
|
||||
const { knowledgeId } = useGetKnowledgeSearchParams();
|
||||
|
||||
const setDocumentParser = useCallback(
|
||||
(parserId: string, documentId: string) => {
|
||||
(
|
||||
parserId: string,
|
||||
documentId: string,
|
||||
parserConfig: IChangeParserConfigRequestBody,
|
||||
) => {
|
||||
try {
|
||||
return dispatch<any>({
|
||||
type: 'kFModel/document_change_parser',
|
||||
@ -125,6 +130,7 @@ export const useSetDocumentParser = () => {
|
||||
parser_id: parserId,
|
||||
doc_id: documentId,
|
||||
kb_id: knowledgeId,
|
||||
parser_config: parserConfig,
|
||||
},
|
||||
});
|
||||
} catch (errorInfo) {
|
||||
|
||||
@ -28,6 +28,12 @@ export interface Parserconfig {
|
||||
to_page: number;
|
||||
}
|
||||
|
||||
export interface IKnowledgeFileParserConfig {
|
||||
chunk_token_num: number;
|
||||
layout_recognize: boolean;
|
||||
pages: number[][];
|
||||
task_page_size: number;
|
||||
}
|
||||
export interface IKnowledgeFile {
|
||||
chunk_num: number;
|
||||
create_date: string;
|
||||
@ -51,6 +57,7 @@ export interface IKnowledgeFile {
|
||||
type: string;
|
||||
update_date: string;
|
||||
update_time: number;
|
||||
parser_config: IKnowledgeFileParserConfig;
|
||||
}
|
||||
|
||||
export interface ITenantInfo {
|
||||
|
||||
12
web/src/interfaces/request/document.ts
Normal file
@ -0,0 +1,12 @@
|
||||
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;
|
||||
}
|
||||
@ -1,10 +1,23 @@
|
||||
import { IModalManagerChildrenProps } from '@/components/modal-manager';
|
||||
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';
|
||||
|
||||
@ -12,41 +25,74 @@ const { CheckableTag } = Tag;
|
||||
|
||||
interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
|
||||
loading: boolean;
|
||||
onOk: (parserId: string) => void;
|
||||
onOk: (
|
||||
parserId: string,
|
||||
parserConfig: IChangeParserConfigRequestBody,
|
||||
) => void;
|
||||
showModal?(): void;
|
||||
parser_id: string;
|
||||
parserId: string;
|
||||
parserConfig: IKnowledgeFileParserConfig;
|
||||
documentType: string;
|
||||
}
|
||||
|
||||
const hidePagesChunkMethods = ['qa', 'table', 'picture', 'resume', 'one'];
|
||||
|
||||
const ChunkMethodModal: React.FC<IProps> = ({
|
||||
parser_id,
|
||||
parserId,
|
||||
onOk,
|
||||
hideModal,
|
||||
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 () => {
|
||||
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 (
|
||||
<Modal
|
||||
title="Chunk Method"
|
||||
open={visible}
|
||||
onOk={handleOk}
|
||||
onCancel={hideModal}
|
||||
afterClose={afterClose}
|
||||
>
|
||||
<Space size={[0, 8]} wrap>
|
||||
<div className={styles.tags}>
|
||||
@ -63,6 +109,138 @@ const ChunkMethodModal: React.FC<IProps> = ({
|
||||
})}
|
||||
</div>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -7,9 +7,13 @@ import {
|
||||
} from '@/hooks/documentHooks';
|
||||
import { useGetKnowledgeSearchParams } from '@/hooks/routeHook';
|
||||
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
||||
import { useFetchTenantInfo } from '@/hooks/userSettingHook';
|
||||
import {
|
||||
useFetchTenantInfo,
|
||||
useSelectParserList,
|
||||
} from '@/hooks/userSettingHook';
|
||||
import { Pagination } from '@/interfaces/common';
|
||||
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
||||
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
||||
import { PaginationProps } from 'antd';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useDispatch, useNavigate, useSelector } from 'umi';
|
||||
@ -222,8 +226,8 @@ export const useChangeDocumentParser = (documentId: string) => {
|
||||
]);
|
||||
|
||||
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) {
|
||||
hideChangeParserModal();
|
||||
}
|
||||
@ -239,3 +243,21 @@ export const useChangeDocumentParser = (documentId: string) => {
|
||||
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 };
|
||||
};
|
||||
|
||||
@ -34,3 +34,7 @@
|
||||
.tochunks {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pageInputNumber {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
@ -224,7 +224,9 @@ const KnowledgeFile = () => {
|
||||
onOk={onCreateOk}
|
||||
/>
|
||||
<ChunkMethodModal
|
||||
parser_id={currentRecord.parser_id}
|
||||
parserId={currentRecord.parser_id}
|
||||
parserConfig={currentRecord.parser_config}
|
||||
documentType={currentRecord.type}
|
||||
onOk={onChangeParserOk}
|
||||
visible={changeParserVisible}
|
||||
hideModal={hideChangeParserModal}
|
||||
|
||||
@ -7,10 +7,6 @@ import pick from 'lodash/pick';
|
||||
import { DvaModel } from 'umi';
|
||||
|
||||
export interface KFModelState extends BaseState {
|
||||
isShowCEFwModal: boolean;
|
||||
isShowTntModal: boolean;
|
||||
isShowSegmentSetModal: boolean;
|
||||
isShowRenameModal: boolean;
|
||||
tenantIfo: any;
|
||||
data: IKnowledgeFile[];
|
||||
total: number;
|
||||
@ -21,10 +17,6 @@ export interface KFModelState extends BaseState {
|
||||
const model: DvaModel<KFModelState> = {
|
||||
namespace: 'kFModel',
|
||||
state: {
|
||||
isShowCEFwModal: false,
|
||||
isShowTntModal: false,
|
||||
isShowSegmentSetModal: false,
|
||||
isShowRenameModal: false,
|
||||
tenantIfo: {},
|
||||
data: [],
|
||||
total: 0,
|
||||
@ -43,9 +35,7 @@ const model: DvaModel<KFModelState> = {
|
||||
...payload,
|
||||
};
|
||||
},
|
||||
setIsShowRenameModal(state, { payload }) {
|
||||
return { ...state, isShowRenameModal: payload };
|
||||
},
|
||||
|
||||
setCurrentRecord(state, { payload }) {
|
||||
return { ...state, currentRecord: payload };
|
||||
},
|
||||
@ -120,7 +110,7 @@ const model: DvaModel<KFModelState> = {
|
||||
const { retcode } = data;
|
||||
if (retcode === 0) {
|
||||
message.success('Modified!');
|
||||
put({
|
||||
yield put({
|
||||
type: 'getKfList',
|
||||
payload: { kb_id: payload.kb_id },
|
||||
});
|
||||
@ -148,10 +138,7 @@ const model: DvaModel<KFModelState> = {
|
||||
const { retcode } = data;
|
||||
if (retcode === 0) {
|
||||
message.success('rename success!');
|
||||
yield put({
|
||||
type: 'setIsShowRenameModal',
|
||||
payload: false,
|
||||
});
|
||||
|
||||
yield put({
|
||||
type: 'getKfList',
|
||||
payload: { kb_id: payload.kb_id },
|
||||
@ -164,16 +151,11 @@ const model: DvaModel<KFModelState> = {
|
||||
const { data } = yield call(kbService.document_create, payload);
|
||||
const { retcode } = data;
|
||||
if (retcode === 0) {
|
||||
put({
|
||||
yield put({
|
||||
type: 'getKfList',
|
||||
payload: { kb_id: payload.kb_id },
|
||||
});
|
||||
put({
|
||||
type: 'kFModel/updateState',
|
||||
payload: {
|
||||
isShowCEFwModal: false,
|
||||
},
|
||||
});
|
||||
|
||||
message.success('Created!');
|
||||
}
|
||||
return retcode;
|
||||
@ -202,16 +184,11 @@ const model: DvaModel<KFModelState> = {
|
||||
);
|
||||
const { retcode } = data;
|
||||
if (retcode === 0) {
|
||||
put({
|
||||
yield put({
|
||||
type: 'getKfList',
|
||||
payload: { kb_id: payload.kb_id },
|
||||
});
|
||||
put({
|
||||
type: 'updateState',
|
||||
payload: {
|
||||
isShowSegmentSetModal: false,
|
||||
},
|
||||
});
|
||||
|
||||
message.success('Modified!');
|
||||
}
|
||||
return retcode;
|
||||
|
||||
@ -1,22 +1,12 @@
|
||||
import { normFile } from '@/utils/fileUtil';
|
||||
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 {
|
||||
useFetchKnowledgeConfigurationOnMount,
|
||||
useSubmitKnowledgeConfiguration,
|
||||
} from './hooks';
|
||||
|
||||
import MaxTokenNumber from '@/components/max-token-number';
|
||||
import { FormInstance } from 'antd/lib';
|
||||
import styles from './index.less';
|
||||
|
||||
@ -121,35 +111,7 @@ const ConfigurationForm = ({ form }: { form: FormInstance }) => {
|
||||
const parserId = getFieldValue('parser_id');
|
||||
|
||||
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;
|
||||
}}
|
||||
|
||||
@ -5,7 +5,6 @@ import { DvaModel } from 'umi';
|
||||
|
||||
export interface KSModelState {
|
||||
isShowPSwModal: boolean;
|
||||
isShowTntModal: boolean;
|
||||
tenantIfo: any;
|
||||
knowledgeDetails: IKnowledge;
|
||||
}
|
||||
@ -14,7 +13,6 @@ const model: DvaModel<KSModelState> = {
|
||||
namespace: 'kSModel',
|
||||
state: {
|
||||
isShowPSwModal: false,
|
||||
isShowTntModal: false,
|
||||
tenantIfo: {},
|
||||
knowledgeDetails: {} as any,
|
||||
},
|
||||
|
||||
@ -5,9 +5,9 @@ const getImageName = (prefix: string, length: number) =>
|
||||
|
||||
export const ImageMap = {
|
||||
book: getImageName('book', 4),
|
||||
laws: getImageName('law', 4),
|
||||
laws: getImageName('law', 2),
|
||||
manual: getImageName('manual', 4),
|
||||
picture: getImageName('picture', 2),
|
||||
picture: getImageName('media', 2),
|
||||
naive: getImageName('naive', 2),
|
||||
paper: getImageName('paper', 2),
|
||||
presentation: getImageName('presentation', 2),
|
||||
@ -32,10 +32,13 @@ export const TextMap = {
|
||||
The chunk granularity is consistent with 'ARTICLE', and all the upper level text will be included in the chunk.
|
||||
</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.
|
||||
So, the figures and tables in the same section will not be sliced apart, and chunk size might be large.
|
||||
</p>` },
|
||||
</p>`,
|
||||
},
|
||||
naive: {
|
||||
title: '',
|
||||
description: `<p>Supported file formats are <b>DOCX, EXCEL, PPT, IMAGE, PDF, TXT</b>.</p>
|
||||
@ -100,19 +103,19 @@ export const TextMap = {
|
||||
</li>
|
||||
<li>Every row in table will be treated as a chunk.</li>
|
||||
</ul>`,
|
||||
},
|
||||
picture: {
|
||||
title: '',
|
||||
description: `
|
||||
},
|
||||
picture: {
|
||||
title: '',
|
||||
description: `
|
||||
<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.
|
||||
</p><p>
|
||||
If the text extracted by OCR is not enough, visual LLM is used to get the descriptions.
|
||||
</p>`,
|
||||
},
|
||||
one: {
|
||||
title: '',
|
||||
description: `
|
||||
one: {
|
||||
title: '',
|
||||
description: `
|
||||
<p>Supported file formats are <b>DOCX, EXCEL, PDF, TXT</b>.
|
||||
</p><p>
|
||||
For a document, it will be treated as an entire chunk, no split at all.
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { DvaModel } from 'umi';
|
||||
export interface kAModelState {
|
||||
isShowPSwModal: boolean;
|
||||
isShowTntModal: boolean;
|
||||
tenantIfo: any;
|
||||
id: string;
|
||||
doc_id: string;
|
||||
@ -11,7 +10,6 @@ const model: DvaModel<kAModelState> = {
|
||||
namespace: 'kAModel',
|
||||
state: {
|
||||
isShowPSwModal: false,
|
||||
isShowTntModal: false,
|
||||
tenantIfo: {},
|
||||
id: '',
|
||||
doc_id: '',
|
||||
|
||||
@ -1,78 +0,0 @@
|
||||
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;
|
||||
@ -1,146 +0,0 @@
|
||||
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;
|
||||
@ -1,66 +0,0 @@
|
||||
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;
|
||||
@ -1,144 +0,0 @@
|
||||
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;
|
||||
@ -1,65 +0,0 @@
|
||||
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;
|
||||
@ -1,49 +0,0 @@
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,98 +0,0 @@
|
||||
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;
|
||||
@ -1,151 +1,151 @@
|
||||
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;
|
||||
@ -52,10 +52,6 @@ const routes = [
|
||||
path: '/chat',
|
||||
component: '@/pages/chat',
|
||||
},
|
||||
{
|
||||
path: '/setting',
|
||||
component: '@/pages/setting',
|
||||
},
|
||||
{
|
||||
path: '/user-setting',
|
||||
component: '@/pages/user-setting',
|
||||
|
||||