Files
TERES_web_frontend/src/pages/knowledge/setting.tsx

232 lines
7.4 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useForm, FormProvider, useWatch, Form } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import {
Box,
Typography,
Paper,
Tabs,
Tab,
Fab,
Button,
} from '@mui/material';
import {
ArrowBack as ArrowBackIcon,
} from '@mui/icons-material';
import { useKnowledgeDetail, useKnowledgeOperations } from '@/hooks/knowledge-hooks';
import GeneralForm from './components/GeneralForm';
import ChunkMethodForm, { type ConfigFormData } from './components/ChunkMethodForm';
import KnowledgeBreadcrumbs from './components/KnowledgeBreadcrumbs';
import { useSnackbar } from '@/components/Provider/SnackbarProvider';
import { DOCUMENT_PARSER_TYPES } from '@/constants/knowledge';
import { MainContainer } from './configuration';
// 统一表单数据类型
interface BaseFormData {
name: string;
description: string;
permission: string;
avatar?: string;
}
function KnowledgeBaseSetting() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const { t } = useTranslation();
const [tabValue, setTabValue] = useState<'generalForm' | 'chunkMethodForm'>('generalForm');
// 获取知识库详情
const { knowledge, loading: detailLoading, refresh } = useKnowledgeDetail(id || '');
const { showMessage } = useSnackbar();
// 知识库操作hooks
const {
updateKnowledgeBasicInfo,
updateKnowledgeModelConfig,
loading: operationLoading
} = useKnowledgeOperations();
// 统一表单管理
const form = useForm<any>({
defaultValues: {
name: '',
description: '',
permission: 'me',
avatar: undefined,
}
});
// 监听parser_id变化
const parserId = useWatch({
control: form.control,
name: 'parser_id',
});
// 当知识库数据加载完成时,更新表单默认值
useEffect(() => {
if (knowledge) {
form.reset({
name: knowledge.name || '',
description: knowledge.description || '',
permission: knowledge.permission || 'me',
avatar: knowledge.avatar,
parser_id: knowledge.parser_id || DOCUMENT_PARSER_TYPES.Naive,
embd_id: knowledge.embd_id || '',
parser_config: {
chunk_token_num: knowledge.parser_config?.chunk_token_num || 512,
delimiter: knowledge.parser_config?.delimiter || '\n',
auto_keywords: knowledge.parser_config?.auto_keywords || 0,
auto_questions: knowledge.parser_config?.auto_questions || 0,
html4excel: knowledge.parser_config?.html4excel || false,
topn_tags: knowledge.parser_config?.topn_tags || 3,
raptor: {
use_raptor: knowledge.parser_config?.raptor?.use_raptor || false,
prompt: knowledge.parser_config?.raptor?.prompt || '请总结以下段落。小心数字,不要编造。段落如下:\n {cluster_content}\n以上就是你需要总结的内容。',
max_token: knowledge.parser_config?.raptor?.max_token || 256,
threshold: knowledge.parser_config?.raptor?.threshold || 0.1,
max_cluster: knowledge.parser_config?.raptor?.max_cluster || 64,
random_seed: knowledge.parser_config?.raptor?.random_seed || 0,
},
graphrag: {
use_graphrag: knowledge.parser_config?.graphrag?.use_graphrag || false,
entity_types: knowledge.parser_config?.graphrag?.entity_types || ['organization', 'person', 'geo', 'event', 'category'],
method: knowledge.parser_config?.graphrag?.method || 'light',
},
},
});
}
}, [knowledge, form]);
const handleTabChange = (event: React.SyntheticEvent, newValue: 'generalForm' | 'chunkMethodForm') => {
setTabValue(newValue);
};
const handleSubmit = async ({data}: {data: any}) => {
if (!knowledge) return;
console.log(t('knowledgeSettings.submitData'), data);
try {
// 分别处理基础信息和配置信息
if (tabValue === 'generalForm') {
const basicData = {
name: data.name,
description: data.description,
permission: data.permission,
avatar: data.avatar,
kb_id: knowledge.id,
parser_id: knowledge.parser_id,
} as any;
await updateKnowledgeBasicInfo(basicData);
showMessage.success(t('knowledgeSettings.basicInfoUpdateSuccess'));
} else {
const configData = {
kb_id: knowledge.id,
name: knowledge.name,
description: knowledge.description,
permission: knowledge.permission,
avatar: knowledge.avatar,
parser_id: data.parser_id,
embd_id: data.embd_id,
parser_config: data.parser_config,
};
await updateKnowledgeModelConfig(configData);
showMessage.success(t('knowledgeSettings.parseConfigUpdateSuccess'));
}
// 刷新知识库详情
refresh();
} catch (error) {
showMessage.error(t('knowledgeSettings.updateFailed', {
type: tabValue === 'generalForm' ? t('knowledgeSettings.basicInfo') : t('knowledgeSettings.parseConfig')
}));
}
};
const handleNavigateBack = () => {
navigate(`/knowledge/${id}`);
};
if (detailLoading) {
return (
<MainContainer>
<Typography>{t('common.loading')}</Typography>
</MainContainer>
);
}
return (
<MainContainer>
{/* 面包屑导航 */}
<KnowledgeBreadcrumbs
kbItems={[
{
label: t('knowledgeSettings.knowledgeBase'),
path: '/knowledge'
},
{
label: knowledge?.name || t('knowledgeSettings.knowledgeBaseDetail'),
path: `/knowledge/${id}`
},
{
label: t('knowledgeSettings.settings')
}
]}
/>
<Box sx={{ mb: 3 }}>
<Typography variant="h4" gutterBottom>
{t('knowledgeSettings.knowledgeBaseSettings')}
</Typography>
<Typography variant="subtitle1" color="text.secondary">
{knowledge?.name}
</Typography>
</Box>
<FormProvider {...form}>
<Form onSubmit={handleSubmit}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs value={tabValue} onChange={handleTabChange} aria-label={t('knowledgeSettings.settingsTabs')}>
<Tab label={t('knowledgeSettings.basicInfo')} value="generalForm" />
<Tab label={t('knowledgeSettings.parseConfig')} value="chunkMethodForm" />
</Tabs>
</Box>
<Box sx={{ mt: 3 }}>
{tabValue === 'generalForm' && (
<GeneralForm />
)}
{tabValue === 'chunkMethodForm' && (
<ChunkMethodForm />
)}
</Box>
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'flex-end' }}>
<Button type="submit" variant="contained">
{t('common.save')}
</Button>
</Box>
</Form>
</FormProvider>
{/* 返回按钮 */}
<Fab
color="primary"
aria-label={t('knowledgeSettings.backToKnowledgeDetail')}
onClick={handleNavigateBack}
sx={{
position: 'fixed',
bottom: 128,
right: 64,
}}
>
<ArrowBackIcon />
</Fab>
</MainContainer>
);
}
export default KnowledgeBaseSetting;