feat(knowledge): add configuration components and refactor general form
feat(hooks): add llm-related hooks and constants docs: add architecture analysis for reference projects
This commit is contained in:
@@ -1,172 +1,163 @@
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { useForm, type UseFormReturn } from 'react-hook-form';
|
||||
import { useForm, FormProvider, useWatch, Form } from 'react-hook-form';
|
||||
import {
|
||||
Box,
|
||||
Container,
|
||||
Typography,
|
||||
Paper,
|
||||
Tabs,
|
||||
Tab,
|
||||
Fab,
|
||||
Snackbar,
|
||||
Alert,
|
||||
Button,
|
||||
} from '@mui/material';
|
||||
import {
|
||||
ArrowBack as ArrowBackIcon,
|
||||
} from '@mui/icons-material';
|
||||
import { useKnowledgeDetail, useKnowledgeOperations } from '@/hooks/knowledge-hooks';
|
||||
import GeneralForm, { type BasicFormData } from './components/GeneralForm';
|
||||
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 TabPanelProps {
|
||||
children?: React.ReactNode;
|
||||
index: number;
|
||||
value: number;
|
||||
}
|
||||
|
||||
function TabPanel(props: TabPanelProps) {
|
||||
const { children, value, index, ...other } = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
role="tabpanel"
|
||||
hidden={value !== index}
|
||||
id={`setting-tabpanel-${index}`}
|
||||
aria-labelledby={`setting-tab-${index}`}
|
||||
{...other}
|
||||
>
|
||||
{value === index && (
|
||||
<Box sx={{ p: 3 }}>
|
||||
{children}
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function a11yProps(index: number) {
|
||||
return {
|
||||
id: `setting-tab-${index}`,
|
||||
'aria-controls': `setting-tabpanel-${index}`,
|
||||
};
|
||||
// 统一表单数据类型
|
||||
interface BaseFormData {
|
||||
name: string;
|
||||
description: string;
|
||||
permission: string;
|
||||
avatar?: string;
|
||||
}
|
||||
|
||||
function KnowledgeBaseSetting() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
const [tabValue, setTabValue] = useState(0);
|
||||
const [tabValue, setTabValue] = useState<'generalForm' | 'chunkMethodForm'>('generalForm');
|
||||
|
||||
// 获取知识库详情
|
||||
const { knowledge, loading: detailLoading, refresh } = useKnowledgeDetail(id || '');
|
||||
const { showMessage } = useSnackbar();
|
||||
|
||||
|
||||
// 知识库操作hooks
|
||||
const {
|
||||
updateKnowledgeBasicInfo,
|
||||
updateKnowledgeModelConfig,
|
||||
loading: operationLoading
|
||||
const {
|
||||
updateKnowledgeBasicInfo,
|
||||
updateKnowledgeModelConfig,
|
||||
loading: operationLoading
|
||||
} = useKnowledgeOperations();
|
||||
|
||||
// 基础信息表单
|
||||
const basicForm = useForm<BasicFormData>({
|
||||
// 统一表单管理
|
||||
const form = useForm<any>({
|
||||
defaultValues: {
|
||||
name: '',
|
||||
description: '',
|
||||
permission: 'me',
|
||||
avatar: undefined,
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// 解析配置表单
|
||||
const configForm = useForm<ConfigFormData>({
|
||||
defaultValues: {
|
||||
parser_id: 'naive',
|
||||
chunk_token_count: 512,
|
||||
layout_recognize: false,
|
||||
task_page_size: 0,
|
||||
},
|
||||
// 监听parser_id变化
|
||||
const parserId = useWatch({
|
||||
control: form.control,
|
||||
name: 'parser_id',
|
||||
});
|
||||
|
||||
// 当知识库数据加载完成时,更新表单默认值
|
||||
useEffect(() => {
|
||||
if (knowledge) {
|
||||
basicForm.reset({
|
||||
form.reset({
|
||||
name: knowledge.name || '',
|
||||
description: knowledge.description || '',
|
||||
permission: knowledge.permission || 'me',
|
||||
avatar: knowledge.avatar,
|
||||
});
|
||||
|
||||
configForm.reset({
|
||||
// parser_id: knowledge.parser_id || 'naive',
|
||||
// chunk_token_count: knowledge.chunk_token_count || 512,
|
||||
// layout_recognize: knowledge.layout_recognize || false,
|
||||
// task_page_size: knowledge.task_page_size || 0,
|
||||
parser_id: knowledge.parser_id || DOCUMENT_PARSER_TYPES.Naive,
|
||||
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, basicForm, configForm]);
|
||||
}, [knowledge, form]);
|
||||
|
||||
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
|
||||
const handleTabChange = (event: React.SyntheticEvent, newValue: 'generalForm' | 'chunkMethodForm') => {
|
||||
setTabValue(newValue);
|
||||
};
|
||||
|
||||
const handleBasicInfoSubmit = async (data: BasicFormData) => {
|
||||
const handleSubmit = async ({data}: {data: any}) => {
|
||||
if (!knowledge) return;
|
||||
|
||||
console.log('提交数据:', data);
|
||||
|
||||
try {
|
||||
const kb = {
|
||||
...data,
|
||||
// parser_id: knowledge.parser_id,
|
||||
kb_id: knowledge.id,
|
||||
} as any;
|
||||
// 分别处理基础信息和配置信息
|
||||
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(kb);
|
||||
showMessage.success('基础信息更新成功');
|
||||
await updateKnowledgeBasicInfo(basicData);
|
||||
showMessage.success('基础信息更新成功');
|
||||
} 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('解析配置更新成功');
|
||||
}
|
||||
|
||||
// 刷新知识库详情
|
||||
refresh();
|
||||
} catch (error) {
|
||||
// showMessage.error('基础信息更新失败');
|
||||
showMessage.error(`${tabValue === 'generalForm' ? '基础信息' : '解析配置'}更新失败`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfigSubmit = async (data: ConfigFormData) => {
|
||||
if (!id) return;
|
||||
|
||||
try {
|
||||
await updateKnowledgeModelConfig({
|
||||
id,
|
||||
parser_id: data.parser_id,
|
||||
// 可以根据需要添加更多配置字段
|
||||
});
|
||||
showMessage.success('解析配置更新成功');
|
||||
// 刷新知识库详情
|
||||
refresh();
|
||||
} catch (error) {
|
||||
// showMessage.error('解析配置更新失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleBackToDetail = () => {
|
||||
const handleNavigateBack = () => {
|
||||
navigate(`/knowledge/${id}`);
|
||||
};
|
||||
|
||||
if (detailLoading) {
|
||||
return (
|
||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||
<MainContainer>
|
||||
<Typography>加载中...</Typography>
|
||||
</Container>
|
||||
</MainContainer>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||
<MainContainer>
|
||||
{/* 面包屑导航 */}
|
||||
<KnowledgeBreadcrumbs knowledge={knowledge} />
|
||||
|
||||
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
知识库设置
|
||||
@@ -176,40 +167,37 @@ function KnowledgeBaseSetting() {
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Paper sx={{ width: '100%' }}>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<Tabs value={tabValue} onChange={handleTabChange} aria-label="设置选项卡">
|
||||
<Tab label="基础信息" {...a11yProps(0)} />
|
||||
<Tab label="解析配置" {...a11yProps(1)} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
<FormProvider {...form}>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<Tabs value={tabValue} onChange={handleTabChange} aria-label="设置选项卡">
|
||||
<Tab label="基础信息" value="generalForm" />
|
||||
<Tab label="解析配置" value="chunkMethodForm" />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
<TabPanel value={tabValue} index={0}>
|
||||
<GeneralForm
|
||||
form={basicForm}
|
||||
onSubmit={handleBasicInfoSubmit}
|
||||
isSubmitting={operationLoading}
|
||||
submitButtonText="保存基础信息"
|
||||
disabled={detailLoading}
|
||||
/>
|
||||
</TabPanel>
|
||||
<Box sx={{ mt: 3 }}>
|
||||
{tabValue === 'generalForm' && (
|
||||
<GeneralForm />
|
||||
)}
|
||||
{tabValue === 'chunkMethodForm' && (
|
||||
<ChunkMethodForm />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<TabPanel value={tabValue} index={1}>
|
||||
<ChunkMethodForm
|
||||
form={configForm as any}
|
||||
onSubmit={handleConfigSubmit}
|
||||
isSubmitting={operationLoading}
|
||||
submitButtonText="保存解析配置"
|
||||
disabled={detailLoading}
|
||||
/>
|
||||
</TabPanel>
|
||||
</Paper>
|
||||
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<Button type="submit" variant="contained">
|
||||
保存
|
||||
</Button>
|
||||
</Box>
|
||||
</Form>
|
||||
</FormProvider>
|
||||
|
||||
{/* 返回按钮 */}
|
||||
<Fab
|
||||
color="primary"
|
||||
aria-label="返回知识库详情"
|
||||
onClick={handleBackToDetail}
|
||||
onClick={handleNavigateBack}
|
||||
sx={{
|
||||
position: 'fixed',
|
||||
bottom: 128,
|
||||
@@ -218,7 +206,7 @@ function KnowledgeBaseSetting() {
|
||||
>
|
||||
<ArrowBackIcon />
|
||||
</Fab>
|
||||
</Container>
|
||||
</MainContainer>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user