refactor(knowledge): restructure knowledge creation form and hooks
feat(knowledge): add GeneralForm and ChunkMethodForm components
This commit is contained in:
@@ -15,7 +15,7 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
|||||||
import LogoutIcon from '@mui/icons-material/Logout';
|
import LogoutIcon from '@mui/icons-material/Logout';
|
||||||
import PersonIcon from '@mui/icons-material/Person';
|
import PersonIcon from '@mui/icons-material/Person';
|
||||||
import LanguageSwitcher from '../LanguageSwitcher';
|
import LanguageSwitcher from '../LanguageSwitcher';
|
||||||
import { useAuth } from '@/hooks/login_hooks';
|
import { useAuth } from '@/hooks/login-hooks';
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
const { userInfo, logout } = useAuth();
|
const { userInfo, logout } = useAuth();
|
||||||
|
|||||||
@@ -103,11 +103,14 @@ const DialogComponent: React.FC<DialogComponentProps> = ({ dialog, onClose }) =>
|
|||||||
onClose={handleBackdropClick}
|
onClose={handleBackdropClick}
|
||||||
maxWidth="sm"
|
maxWidth="sm"
|
||||||
fullWidth
|
fullWidth
|
||||||
PaperProps={{
|
slotProps={{
|
||||||
|
paper: {
|
||||||
sx: {
|
sx: {
|
||||||
width: config.width || 'auto',
|
width: config.width || 'auto',
|
||||||
|
minWidth: config.width || '300px',
|
||||||
maxWidth: config.width || '500px',
|
maxWidth: config.width || '500px',
|
||||||
},
|
}
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* 标题栏 */}
|
{/* 标题栏 */}
|
||||||
|
|||||||
294
src/pages/knowledge/components/ChunkMethodForm.tsx
Normal file
294
src/pages/knowledge/components/ChunkMethodForm.tsx
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { type UseFormReturn } from 'react-hook-form';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
Select,
|
||||||
|
MenuItem,
|
||||||
|
Grid,
|
||||||
|
TextField,
|
||||||
|
FormHelperText,
|
||||||
|
Button,
|
||||||
|
CircularProgress,
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
Save as SaveIcon,
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
import { DOCUMENT_PARSER_TYPES, type DocumentParserType } from '@/constants/knowledge';
|
||||||
|
|
||||||
|
// 解析器选项配置
|
||||||
|
const parserOptions = [
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Naive, label: '通用解析器', description: '适用于大多数文档类型' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Qa, label: 'Q&A解析器', description: '适用于问答格式文档' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Resume, label: '简历解析器', description: '专门用于解析简历文档' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Manual, label: '手册解析器', description: '适用于技术手册和说明书' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Table, label: '表格解析器', description: '专门处理表格数据' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Paper, label: '论文解析器', description: '适用于学术论文' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Book, label: '书籍解析器', description: '适用于书籍和长文档' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Laws, label: '法律解析器', description: '专门处理法律文档' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Presentation, label: '演示文稿解析器', description: '适用于PPT等演示文档' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Picture, label: '图片解析器', description: '处理图片中的文字内容' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.One, label: '整体解析器', description: '将整个文档作为一个块处理' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Audio, label: '音频解析器', description: '处理音频文件转录' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Email, label: '邮件解析器', description: '专门处理邮件格式' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.Tag, label: '标签解析器', description: '基于标签的文档解析' },
|
||||||
|
{ value: DOCUMENT_PARSER_TYPES.KnowledgeGraph, label: '知识图谱解析器', description: '构建知识图谱结构' },
|
||||||
|
];
|
||||||
|
|
||||||
|
interface ConfigFormData {
|
||||||
|
parser_id: DocumentParserType;
|
||||||
|
chunk_token_count?: number;
|
||||||
|
layout_recognize?: boolean;
|
||||||
|
task_page_size?: number;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChunkMethodFormProps {
|
||||||
|
form: UseFormReturn<ConfigFormData>;
|
||||||
|
onSubmit: (data: ConfigFormData) => void;
|
||||||
|
isSubmitting?: boolean;
|
||||||
|
onCancel?: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
submitButtonText?: string;
|
||||||
|
cancelButtonText?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ChunkMethodForm({
|
||||||
|
form,
|
||||||
|
onSubmit,
|
||||||
|
isSubmitting = false,
|
||||||
|
onCancel,
|
||||||
|
disabled = false,
|
||||||
|
submitButtonText = '提交',
|
||||||
|
cancelButtonText = '取消'
|
||||||
|
}: ChunkMethodFormProps) {
|
||||||
|
const selectedParser: DocumentParserType = form.watch('parser_id');
|
||||||
|
|
||||||
|
// 根据选择的解析器显示不同的配置选项
|
||||||
|
const renderParserSpecificConfig = () => {
|
||||||
|
switch (selectedParser) {
|
||||||
|
case DOCUMENT_PARSER_TYPES.Naive:
|
||||||
|
return (
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid size={{xs:12,sm:6}}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
type="number"
|
||||||
|
label="分块大小"
|
||||||
|
placeholder="512"
|
||||||
|
disabled={disabled}
|
||||||
|
{...form.register('chunk_token_num', {
|
||||||
|
valueAsNumber: true,
|
||||||
|
min: {
|
||||||
|
value: 50,
|
||||||
|
message: '分块大小不能小于50',
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
value: 2048,
|
||||||
|
message: '分块大小不能超过2048',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
error={!!form.formState.errors.chunk_token_num}
|
||||||
|
helperText={form.formState.errors.chunk_token_num?.message?.toString() || '设置每个文本块的最大token数量'}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{xs:12,sm:6}}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="分隔符"
|
||||||
|
placeholder="\\n"
|
||||||
|
disabled={disabled}
|
||||||
|
{...form.register('delimiter')}
|
||||||
|
helperText="用于分割文本的分隔符"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
|
||||||
|
case DOCUMENT_PARSER_TYPES.Table:
|
||||||
|
return (
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid size={12}>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
表格解析器会自动处理表格结构,无需额外配置。
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
|
||||||
|
case DOCUMENT_PARSER_TYPES.KnowledgeGraph:
|
||||||
|
return (
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid size={12}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="实体类型"
|
||||||
|
placeholder="person,organization,location"
|
||||||
|
disabled={disabled}
|
||||||
|
{...form.register('entity_types')}
|
||||||
|
helperText="指定要提取的实体类型,用逗号分隔"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
|
||||||
|
case DOCUMENT_PARSER_TYPES.Picture:
|
||||||
|
return (
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid size={12}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
rows={3}
|
||||||
|
label="系统提示词"
|
||||||
|
placeholder="请描述图片中的内容..."
|
||||||
|
disabled={disabled}
|
||||||
|
{...form.register('system_prompt')}
|
||||||
|
helperText="用于指导AI理解图片内容的提示词"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid size={12}>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
该解析器使用默认配置,无需额外设置。
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Typography variant="h6" gutterBottom>
|
||||||
|
解析配置
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
{/* 解析器选择 */}
|
||||||
|
<Grid size={12}>
|
||||||
|
<FormControl fullWidth disabled={disabled}>
|
||||||
|
<InputLabel>解析器类型</InputLabel>
|
||||||
|
<Select
|
||||||
|
label="解析器类型"
|
||||||
|
defaultValue={DOCUMENT_PARSER_TYPES.Naive}
|
||||||
|
{...form.register('parser_id')}
|
||||||
|
value={form.watch('parser_id') || DOCUMENT_PARSER_TYPES.Naive}
|
||||||
|
>
|
||||||
|
{parserOptions.map((option) => (
|
||||||
|
<MenuItem key={option.value} value={option.value}>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="body1">{option.label}</Typography>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
{option.description}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>
|
||||||
|
选择适合您文档类型的解析器
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 解析器特定配置 */}
|
||||||
|
<Grid size={12}>
|
||||||
|
<Box sx={{ mt: 2 }}>
|
||||||
|
<Typography variant="subtitle2" gutterBottom>
|
||||||
|
解析器配置
|
||||||
|
</Typography>
|
||||||
|
{renderParserSpecificConfig()}
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 通用配置 */}
|
||||||
|
<Grid size={12}>
|
||||||
|
<Box sx={{ mt: 2 }}>
|
||||||
|
<Typography variant="subtitle2" gutterBottom>
|
||||||
|
通用配置
|
||||||
|
</Typography>
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid size={{xs:12,sm:6}}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
type="number"
|
||||||
|
label="自动关键词数量"
|
||||||
|
placeholder="0"
|
||||||
|
disabled={disabled}
|
||||||
|
{...form.register('auto_keywords', {
|
||||||
|
valueAsNumber: true,
|
||||||
|
min: {
|
||||||
|
value: 0,
|
||||||
|
message: '关键词数量不能小于0',
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
value: 10,
|
||||||
|
message: '关键词数量不能超过10',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
error={!!form.formState.errors.auto_keywords}
|
||||||
|
helperText={form.formState.errors.auto_keywords?.message?.toString() || '自动提取的关键词数量,0表示不提取'}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{xs:12,sm:6}}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
type="number"
|
||||||
|
label="自动问题数量"
|
||||||
|
placeholder="0"
|
||||||
|
disabled={disabled}
|
||||||
|
{...form.register('auto_questions', {
|
||||||
|
valueAsNumber: true,
|
||||||
|
min: {
|
||||||
|
value: 0,
|
||||||
|
message: '问题数量不能小于0',
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
value: 10,
|
||||||
|
message: '问题数量不能超过10',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
error={!!form.formState.errors.auto_questions}
|
||||||
|
helperText={form.formState.errors.auto_questions?.message?.toString() || '自动生成的问题数量,0表示不生成'}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 操作按钮 */}
|
||||||
|
<Grid size={12}>
|
||||||
|
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'flex-end', mt: 2 }}>
|
||||||
|
{onCancel && (
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={onCancel}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{cancelButtonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={form.handleSubmit(onSubmit)}
|
||||||
|
disabled={disabled || isSubmitting}
|
||||||
|
startIcon={isSubmitting ? <CircularProgress size={20} /> : <SaveIcon />}
|
||||||
|
>
|
||||||
|
{submitButtonText}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChunkMethodForm;
|
||||||
226
src/pages/knowledge/components/GeneralForm.tsx
Normal file
226
src/pages/knowledge/components/GeneralForm.tsx
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
import React, { useRef } from 'react';
|
||||||
|
import { type UseFormReturn } from 'react-hook-form';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
TextField,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
Select,
|
||||||
|
MenuItem,
|
||||||
|
Grid,
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
IconButton,
|
||||||
|
CircularProgress,
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
PhotoCamera as PhotoCameraIcon,
|
||||||
|
Delete as DeleteIcon,
|
||||||
|
Save as SaveIcon,
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
|
||||||
|
interface BasicFormData {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
permission: string;
|
||||||
|
avatar?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeneralFormProps {
|
||||||
|
form: UseFormReturn<BasicFormData>;
|
||||||
|
onSubmit: (data: BasicFormData) => void;
|
||||||
|
isSubmitting?: boolean;
|
||||||
|
onCancel?: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
submitButtonText?: string;
|
||||||
|
cancelButtonText?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GeneralForm({
|
||||||
|
form,
|
||||||
|
onSubmit,
|
||||||
|
isSubmitting = false,
|
||||||
|
onCancel,
|
||||||
|
disabled = false,
|
||||||
|
submitButtonText = '提交',
|
||||||
|
cancelButtonText = '取消'
|
||||||
|
}: GeneralFormProps) {
|
||||||
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
// 处理头像上传
|
||||||
|
const handleAvatarUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const file = event.target.files?.[0];
|
||||||
|
if (file) {
|
||||||
|
// 检查文件类型
|
||||||
|
if (!file.type.startsWith('image/')) {
|
||||||
|
alert('请选择图片文件');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查文件大小 (限制为 2MB)
|
||||||
|
if (file.size > 2 * 1024 * 1024) {
|
||||||
|
alert('图片大小不能超过 2MB');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
const base64String = e.target?.result as string;
|
||||||
|
form.setValue('avatar', base64String);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除头像
|
||||||
|
const handleAvatarDelete = () => {
|
||||||
|
form.setValue('avatar', undefined);
|
||||||
|
if (fileInputRef.current) {
|
||||||
|
fileInputRef.current.value = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const avatarValue = form.watch('avatar');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Typography variant="h6" gutterBottom>
|
||||||
|
基础信息
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
{/* 头像上传 */}
|
||||||
|
<Grid size={12}>
|
||||||
|
<Typography variant="subtitle2" gutterBottom>
|
||||||
|
头像
|
||||||
|
</Typography>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||||
|
<Avatar
|
||||||
|
src={avatarValue}
|
||||||
|
sx={{ width: 80, height: 80 }}
|
||||||
|
>
|
||||||
|
{!avatarValue && form.watch('name')?.charAt(0)?.toUpperCase()}
|
||||||
|
</Avatar>
|
||||||
|
<Box>
|
||||||
|
<input
|
||||||
|
ref={fileInputRef}
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
onChange={handleAvatarUpload}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<PhotoCameraIcon />}
|
||||||
|
onClick={() => fileInputRef.current?.click()}
|
||||||
|
disabled={disabled}
|
||||||
|
size="small"
|
||||||
|
sx={{ mr: 1 }}
|
||||||
|
>
|
||||||
|
选择图片
|
||||||
|
</Button>
|
||||||
|
{avatarValue && (
|
||||||
|
<IconButton
|
||||||
|
onClick={handleAvatarDelete}
|
||||||
|
disabled={disabled}
|
||||||
|
size="small"
|
||||||
|
color="error"
|
||||||
|
>
|
||||||
|
<DeleteIcon />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
支持 PNG、JPG 格式,文件大小不超过 2MB
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 知识库名称 */}
|
||||||
|
<Grid size={12}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="知识库名称"
|
||||||
|
placeholder="请输入知识库名称"
|
||||||
|
disabled={disabled}
|
||||||
|
{...form.register('name', {
|
||||||
|
required: '请输入知识库名称',
|
||||||
|
minLength: {
|
||||||
|
value: 2,
|
||||||
|
message: '知识库名称至少需要2个字符',
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: 50,
|
||||||
|
message: '知识库名称不能超过50个字符',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
error={!!form.formState.errors.name}
|
||||||
|
helperText={form.formState.errors.name?.message?.toString() || '请输入知识库名称'}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 描述 */}
|
||||||
|
<Grid size={12}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
rows={4}
|
||||||
|
label="描述"
|
||||||
|
placeholder="请输入知识库描述"
|
||||||
|
disabled={disabled}
|
||||||
|
{...form.register('description', {
|
||||||
|
maxLength: {
|
||||||
|
value: 500,
|
||||||
|
message: '描述不能超过500个字符',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
error={!!form.formState.errors.description}
|
||||||
|
helperText={form.formState.errors.description?.message?.toString() || '请输入知识库描述'}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 权限设置 */}
|
||||||
|
<Grid size={{xs:12,sm:6}}>
|
||||||
|
<FormControl fullWidth disabled={disabled}>
|
||||||
|
<InputLabel>权限设置</InputLabel>
|
||||||
|
<Select
|
||||||
|
label="权限设置"
|
||||||
|
{...form.register('permission')}
|
||||||
|
value={form.watch('permission') || 'me'}
|
||||||
|
>
|
||||||
|
<MenuItem value="me">仅自己</MenuItem>
|
||||||
|
<MenuItem value="team">团队可见</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 操作按钮 */}
|
||||||
|
<Grid size={12}>
|
||||||
|
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'flex-end', mt: 2 }}>
|
||||||
|
{onCancel && (
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={onCancel}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{cancelButtonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={form.handleSubmit(onSubmit)}
|
||||||
|
disabled={disabled || isSubmitting}
|
||||||
|
startIcon={isSubmitting ? <CircularProgress size={20} /> : <SaveIcon />}
|
||||||
|
>
|
||||||
|
{submitButtonText}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GeneralForm;
|
||||||
@@ -1,38 +1,28 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm, type UseFormReturn } from 'react-hook-form';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Typography,
|
Typography,
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
TextField,
|
|
||||||
Button,
|
Button,
|
||||||
FormControl,
|
|
||||||
InputLabel,
|
|
||||||
Select,
|
|
||||||
MenuItem,
|
|
||||||
Alert,
|
Alert,
|
||||||
Grid,
|
|
||||||
Divider,
|
Divider,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
Stepper,
|
Stepper,
|
||||||
Step,
|
Step,
|
||||||
StepLabel,
|
StepLabel,
|
||||||
Switch,
|
|
||||||
FormControlLabel,
|
|
||||||
Slider,
|
|
||||||
Chip,
|
|
||||||
Stack,
|
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import {
|
import {
|
||||||
ArrowBack as ArrowBackIcon,
|
ArrowBack as ArrowBackIcon,
|
||||||
Save as SaveIcon,
|
|
||||||
Settings as SettingsIcon,
|
Settings as SettingsIcon,
|
||||||
CheckCircle as CheckCircleIcon,
|
CheckCircle as CheckCircleIcon,
|
||||||
SkipNext as SkipNextIcon,
|
SkipNext as SkipNextIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import knowledgeService from '@/services/knowledge_service';
|
import { useKnowledgeOperations } from '@/hooks/knowledge-hooks';
|
||||||
|
import GeneralForm from './components/GeneralForm';
|
||||||
|
import ChunkMethodForm from './components/ChunkMethodForm';
|
||||||
|
|
||||||
// 基础信息表单数据
|
// 基础信息表单数据
|
||||||
interface BasicFormData {
|
interface BasicFormData {
|
||||||
@@ -42,21 +32,21 @@ interface BasicFormData {
|
|||||||
avatar?: string;
|
avatar?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置设置表单数据
|
// 配置表单数据
|
||||||
interface ConfigFormData {
|
interface ConfigFormData {
|
||||||
parser_id: string;
|
parser_id: string;
|
||||||
embd_id: string;
|
embd_id?: string;
|
||||||
chunk_token_num: number;
|
chunk_token_num?: number;
|
||||||
layout_recognize: string;
|
layout_recognize?: string;
|
||||||
delimiter: string;
|
delimiter?: string;
|
||||||
auto_keywords: number;
|
auto_keywords?: number;
|
||||||
auto_questions: number;
|
auto_questions?: number;
|
||||||
html4excel: boolean;
|
html4excel?: boolean;
|
||||||
topn_tags: number;
|
topn_tags?: number;
|
||||||
use_raptor: boolean;
|
use_raptor?: boolean;
|
||||||
use_graphrag: boolean;
|
use_graphrag?: boolean;
|
||||||
graphrag_method: string;
|
graphrag_method?: string;
|
||||||
pagerank: number;
|
pagerank?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const steps = ['基础信息', '配置设置'];
|
const steps = ['基础信息', '配置设置'];
|
||||||
@@ -64,10 +54,16 @@ const steps = ['基础信息', '配置设置'];
|
|||||||
function KnowledgeBaseCreate() {
|
function KnowledgeBaseCreate() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [activeStep, setActiveStep] = useState(0);
|
const [activeStep, setActiveStep] = useState(0);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [createdKbId, setCreatedKbId] = useState<string | null>(null);
|
||||||
const [error, setError] = useState<string>('');
|
|
||||||
const [success, setSuccess] = useState<string>('');
|
// 使用知识库操作 hooks
|
||||||
const [createdKbId, setCreatedKbId] = useState<string>('');
|
const {
|
||||||
|
loading: isSubmitting,
|
||||||
|
error,
|
||||||
|
createKnowledge,
|
||||||
|
updateKnowledgeModelConfig,
|
||||||
|
clearError
|
||||||
|
} = useKnowledgeOperations();
|
||||||
|
|
||||||
// 基础信息表单
|
// 基础信息表单
|
||||||
const basicForm = useForm<BasicFormData>({
|
const basicForm = useForm<BasicFormData>({
|
||||||
@@ -75,145 +71,80 @@ function KnowledgeBaseCreate() {
|
|||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
permission: 'me',
|
permission: 'me',
|
||||||
avatar: undefined,
|
avatar: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 配置设置表单
|
// 配置表单
|
||||||
const configForm = useForm<ConfigFormData>({
|
const configForm = useForm<ConfigFormData>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
parser_id: 'naive',
|
parser_id: 'naive',
|
||||||
embd_id: 'text-embedding-v3@Tongyi-Qianwen',
|
embd_id: 'text-embedding-v3@Tongyi-Qianwen',
|
||||||
chunk_token_num: 512,
|
chunk_token_num: 512,
|
||||||
layout_recognize: 'DeepDOC',
|
layout_recognize: 'DeepDOC',
|
||||||
delimiter: '\n',
|
delimiter: '\n!?。;!?',
|
||||||
auto_keywords: 0,
|
auto_keywords: 5,
|
||||||
auto_questions: 0,
|
auto_questions: 3,
|
||||||
html4excel: false,
|
html4excel: false,
|
||||||
topn_tags: 3,
|
topn_tags: 10,
|
||||||
use_raptor: false,
|
use_raptor: false,
|
||||||
use_graphrag: false,
|
use_graphrag: false,
|
||||||
graphrag_method: 'light',
|
graphrag_method: 'light',
|
||||||
pagerank: 0,
|
pagerank: 0.3,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 第一步:创建基础知识库
|
// 处理基础信息提交
|
||||||
const handleBasicSubmit = async (data: BasicFormData) => {
|
const handleBasicSubmit = async (data: BasicFormData) => {
|
||||||
setIsSubmitting(true);
|
clearError();
|
||||||
setError('');
|
|
||||||
setSuccess('');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 只发送基础字段到 create API
|
const result = await createKnowledge(data);
|
||||||
const basicData = {
|
setCreatedKbId(result.kb_id);
|
||||||
name: data.name,
|
setActiveStep(1);
|
||||||
avatar: data.avatar,
|
} catch (err) {
|
||||||
description: data.description,
|
|
||||||
permission: data.permission,
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await knowledgeService.createKnowledge(basicData);
|
|
||||||
|
|
||||||
// 假设 API 返回包含 kb_id 的响应
|
|
||||||
const kbId = response.data?.kb_id;
|
|
||||||
setCreatedKbId(kbId);
|
|
||||||
|
|
||||||
setSuccess('知识库创建成功!您可以继续配置解析设置,或直接跳过。');
|
|
||||||
setActiveStep(1); // 进入第二步
|
|
||||||
|
|
||||||
} catch (err: any) {
|
|
||||||
console.error('创建知识库失败:', err);
|
console.error('创建知识库失败:', err);
|
||||||
setError(err.response?.data?.message || err.message || '创建知识库失败,请重试');
|
|
||||||
} finally {
|
|
||||||
setIsSubmitting(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 第二步:更新配置设置
|
// 处理配置提交
|
||||||
const handleConfigSubmit = async (data: ConfigFormData) => {
|
const handleConfigSubmit = async (data: ConfigFormData) => {
|
||||||
if (!createdKbId) {
|
if (!createdKbId) return;
|
||||||
setError('未找到知识库ID,请重新创建');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsSubmitting(true);
|
clearError();
|
||||||
setError('');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 构建 update API 的数据结构
|
await updateKnowledgeModelConfig({
|
||||||
const updateData:any = {
|
id: createdKbId,
|
||||||
kb_id: createdKbId,
|
...data,
|
||||||
name: basicForm.getValues('name'),
|
});
|
||||||
description: basicForm.getValues('description'),
|
|
||||||
permission: basicForm.getValues('permission'),
|
|
||||||
parser_id: data.parser_id,
|
|
||||||
embd_id: data.embd_id,
|
|
||||||
parser_config: {
|
|
||||||
layout_recognize: data.layout_recognize,
|
|
||||||
chunk_token_num: data.chunk_token_num,
|
|
||||||
delimiter: data.delimiter,
|
|
||||||
auto_keywords: data.auto_keywords,
|
|
||||||
auto_questions: data.auto_questions,
|
|
||||||
html4excel: data.html4excel,
|
|
||||||
topn_tags: data.topn_tags,
|
|
||||||
raptor: {
|
|
||||||
use_raptor: data.use_raptor,
|
|
||||||
},
|
|
||||||
graphrag: {
|
|
||||||
use_graphrag: data.use_graphrag,
|
|
||||||
entity_types: ["organization", "person", "geo", "event", "category"],
|
|
||||||
method: data.graphrag_method,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pagerank: data.pagerank,
|
|
||||||
};
|
|
||||||
|
|
||||||
await knowledgeService.updateKnowledge(updateData);
|
|
||||||
|
|
||||||
setSuccess('知识库配置更新成功!');
|
|
||||||
|
|
||||||
// 延迟跳转到知识库列表页面
|
|
||||||
setTimeout(() => {
|
|
||||||
navigate('/knowledge');
|
navigate('/knowledge');
|
||||||
}, 1500);
|
} catch (err) {
|
||||||
|
console.error('配置知识库失败:', err);
|
||||||
} catch (err: any) {
|
|
||||||
console.error('更新知识库配置失败:', err);
|
|
||||||
setError(err.response?.data?.message || err.message || '更新配置失败,请重试');
|
|
||||||
} finally {
|
|
||||||
setIsSubmitting(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// 跳过配置
|
||||||
// 跳过配置设置
|
|
||||||
const handleSkipConfig = () => {
|
const handleSkipConfig = () => {
|
||||||
setSuccess('知识库创建完成!');
|
|
||||||
setTimeout(() => {
|
|
||||||
navigate('/knowledge');
|
navigate('/knowledge');
|
||||||
}, 1000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 返回上一步
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
if (activeStep === 0) {
|
|
||||||
navigate('/knowledge');
|
|
||||||
} else {
|
|
||||||
setActiveStep(0);
|
setActiveStep(0);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ p: 3, maxWidth: 900, mx: 'auto' }}>
|
<Box sx={{ maxWidth: 800, mx: 'auto', p: 3 }}>
|
||||||
{/* 页面标题 */}
|
{/* 页面标题 */}
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3 }}>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<ArrowBackIcon />}
|
startIcon={<ArrowBackIcon />}
|
||||||
onClick={handleBack}
|
onClick={() => navigate('/knowledge')}
|
||||||
sx={{ mr: 2 }}
|
sx={{ mr: 2 }}
|
||||||
>
|
>
|
||||||
{activeStep === 0 ? '返回' : '上一步'}
|
返回
|
||||||
</Button>
|
</Button>
|
||||||
<Typography variant="h4" component="h1" fontWeight={600}>
|
<Typography variant="h4" component="h1">
|
||||||
创建知识库
|
创建知识库
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -227,114 +158,30 @@ function KnowledgeBaseCreate() {
|
|||||||
))}
|
))}
|
||||||
</Stepper>
|
</Stepper>
|
||||||
|
|
||||||
{/* 表单卡片 */}
|
{/* 错误提示 */}
|
||||||
<Card>
|
|
||||||
<CardContent sx={{ p: 4 }}>
|
|
||||||
{/* 错误和成功提示 */}
|
|
||||||
{error && (
|
{error && (
|
||||||
<Alert severity="error" sx={{ mb: 3 }}>
|
<Alert severity="error" sx={{ mb: 3 }}>
|
||||||
{error}
|
{error}
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{success && (
|
<Card>
|
||||||
<Alert severity="success" sx={{ mb: 3 }}>
|
<CardContent>
|
||||||
{success}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 第一步:基础信息 */}
|
{/* 第一步:基础信息 */}
|
||||||
{activeStep === 0 && (
|
{activeStep === 0 && (
|
||||||
<Box component="form" onSubmit={basicForm.handleSubmit(handleBasicSubmit)} noValidate>
|
<GeneralForm
|
||||||
<Typography variant="h6" gutterBottom>
|
form={basicForm}
|
||||||
基础信息
|
onSubmit={handleBasicSubmit}
|
||||||
</Typography>
|
isSubmitting={isSubmitting}
|
||||||
<Divider sx={{ mb: 3 }} />
|
onCancel={() => navigate('/knowledge')}
|
||||||
|
submitButtonText="下一步"
|
||||||
<Grid container spacing={3}>
|
cancelButtonText="取消"
|
||||||
{/* 知识库名称 */}
|
|
||||||
<Grid size={12}>
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="知识库名称"
|
|
||||||
placeholder="请输入知识库名称"
|
|
||||||
{...basicForm.register('name', {
|
|
||||||
required: '请输入知识库名称',
|
|
||||||
minLength: {
|
|
||||||
value: 2,
|
|
||||||
message: '知识库名称至少需要2个字符',
|
|
||||||
},
|
|
||||||
maxLength: {
|
|
||||||
value: 50,
|
|
||||||
message: '知识库名称不能超过50个字符',
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
error={!!basicForm.formState.errors.name}
|
|
||||||
helperText={basicForm.formState.errors.name?.message}
|
|
||||||
/>
|
/>
|
||||||
</Grid>
|
|
||||||
|
|
||||||
{/* 描述 */}
|
|
||||||
<Grid size={12}>
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
multiline
|
|
||||||
rows={4}
|
|
||||||
label="描述"
|
|
||||||
placeholder="请输入知识库描述"
|
|
||||||
{...basicForm.register('description', {
|
|
||||||
maxLength: {
|
|
||||||
value: 500,
|
|
||||||
message: '描述不能超过500个字符',
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
error={!!basicForm.formState.errors.description}
|
|
||||||
helperText={basicForm.formState.errors.description?.message}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
{/* 权限设置 */}
|
|
||||||
<Grid size={{xs:12, sm:6}}>
|
|
||||||
<FormControl fullWidth>
|
|
||||||
<InputLabel>权限设置</InputLabel>
|
|
||||||
<Select
|
|
||||||
label="权限设置"
|
|
||||||
{...basicForm.register('permission')}
|
|
||||||
>
|
|
||||||
<MenuItem value="me">仅自己</MenuItem>
|
|
||||||
<MenuItem value="team">团队可见</MenuItem>
|
|
||||||
<MenuItem value="public">公开</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
{/* 提交按钮 */}
|
|
||||||
<Grid size={{xs:12}}>
|
|
||||||
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'flex-end', mt: 3 }}>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
onClick={() => navigate('/knowledge')}
|
|
||||||
disabled={isSubmitting}
|
|
||||||
>
|
|
||||||
取消
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
variant="contained"
|
|
||||||
startIcon={isSubmitting ? <CircularProgress size={20} /> : <SaveIcon />}
|
|
||||||
disabled={isSubmitting}
|
|
||||||
>
|
|
||||||
{isSubmitting ? '创建中...' : '创建知识库'}
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Box>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 第二步:配置设置 */}
|
{/* 第二步:配置设置 */}
|
||||||
{activeStep === 1 && (
|
{activeStep === 1 && (
|
||||||
<Box component="form" onSubmit={configForm.handleSubmit(handleConfigSubmit)} noValidate>
|
<Box>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
||||||
<CheckCircleIcon color="success" sx={{ mr: 1 }} />
|
<CheckCircleIcon color="success" sx={{ mr: 1 }} />
|
||||||
<Typography variant="h6">
|
<Typography variant="h6">
|
||||||
@@ -346,152 +193,26 @@ function KnowledgeBaseCreate() {
|
|||||||
</Typography>
|
</Typography>
|
||||||
<Divider sx={{ mb: 3 }} />
|
<Divider sx={{ mb: 3 }} />
|
||||||
|
|
||||||
<Grid container spacing={3}>
|
<ChunkMethodForm
|
||||||
{/* 解析器设置 */}
|
form={configForm as any}
|
||||||
<Grid size={{xs:12}}>
|
onSubmit={(data) => handleConfigSubmit(data as any)}
|
||||||
<Typography variant="subtitle1" gutterBottom>
|
isSubmitting={isSubmitting}
|
||||||
解析器设置
|
onCancel={handleBack}
|
||||||
</Typography>
|
submitButtonText="完成配置"
|
||||||
</Grid>
|
cancelButtonText="返回上一步"
|
||||||
|
|
||||||
<Grid size={{xs:12,sm:6}}>
|
|
||||||
<FormControl fullWidth>
|
|
||||||
<InputLabel>解析器类型</InputLabel>
|
|
||||||
<Select
|
|
||||||
label="解析器类型"
|
|
||||||
{...configForm.register('parser_id')}
|
|
||||||
>
|
|
||||||
<MenuItem value="naive">基础解析器</MenuItem>
|
|
||||||
<MenuItem value="advanced">高级解析器</MenuItem>
|
|
||||||
<MenuItem value="custom">自定义解析器</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid size={{xs:12,sm:6}}>
|
|
||||||
<FormControl fullWidth>
|
|
||||||
<InputLabel>嵌入模型</InputLabel>
|
|
||||||
<Select
|
|
||||||
label="嵌入模型"
|
|
||||||
{...configForm.register('embd_id')}
|
|
||||||
>
|
|
||||||
<MenuItem value="text-embedding-v3@Tongyi-Qianwen">通义千问 v3</MenuItem>
|
|
||||||
<MenuItem value="text-embedding-v2@Tongyi-Qianwen">通义千问 v2</MenuItem>
|
|
||||||
<MenuItem value="openai-embedding">OpenAI Embedding</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
{/* 分块设置 */}
|
|
||||||
<Grid size={{xs:12}}>
|
|
||||||
<Typography variant="subtitle1" gutterBottom sx={{ mt: 2 }}>
|
|
||||||
分块设置
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid size={{xs:12,sm:6}}>
|
|
||||||
<Typography gutterBottom>分块大小: {configForm.watch('chunk_token_num')}</Typography>
|
|
||||||
<Slider
|
|
||||||
{...configForm.register('chunk_token_num')}
|
|
||||||
value={configForm.watch('chunk_token_num')}
|
|
||||||
onChange={(_, value) => configForm.setValue('chunk_token_num', value as number)}
|
|
||||||
min={128}
|
|
||||||
max={2048}
|
|
||||||
step={128}
|
|
||||||
marks={[
|
|
||||||
{ value: 128, label: '128' },
|
|
||||||
{ value: 512, label: '512' },
|
|
||||||
{ value: 1024, label: '1024' },
|
|
||||||
{ value: 2048, label: '2048' },
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid size={{xs:12,sm:6}}>
|
{/* 跳过配置按钮 */}
|
||||||
<FormControl fullWidth>
|
<Box sx={{ display: 'flex', justifyContent: 'center', mt: 2 }}>
|
||||||
<InputLabel>布局识别</InputLabel>
|
|
||||||
<Select
|
|
||||||
label="布局识别"
|
|
||||||
{...configForm.register('layout_recognize')}
|
|
||||||
>
|
|
||||||
<MenuItem value="DeepDOC">DeepDOC</MenuItem>
|
|
||||||
<MenuItem value="OCR">OCR</MenuItem>
|
|
||||||
<MenuItem value="None">无</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
{/* 高级功能 */}
|
|
||||||
<Grid size={{xs:12}}>
|
|
||||||
<Typography variant="subtitle1" gutterBottom sx={{ mt: 2 }}>
|
|
||||||
高级功能
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid size={{xs:12,sm:6}}>
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Switch
|
|
||||||
{...configForm.register('use_raptor')}
|
|
||||||
checked={configForm.watch('use_raptor')}
|
|
||||||
onChange={(e) => configForm.setValue('use_raptor', e.target.checked)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="启用 Raptor"
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid size={{xs:12,sm:6}}>
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Switch
|
|
||||||
{...configForm.register('use_graphrag')}
|
|
||||||
checked={configForm.watch('use_graphrag')}
|
|
||||||
onChange={(e) => configForm.setValue('use_graphrag', e.target.checked)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="启用 GraphRAG"
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
{configForm.watch('use_graphrag') && (
|
|
||||||
<Grid size={{xs:12,sm:6}}>
|
|
||||||
<FormControl fullWidth>
|
|
||||||
<InputLabel>GraphRAG 方法</InputLabel>
|
|
||||||
<Select
|
|
||||||
label="GraphRAG 方法"
|
|
||||||
{...configForm.register('graphrag_method')}
|
|
||||||
>
|
|
||||||
<MenuItem value="light">轻量级</MenuItem>
|
|
||||||
<MenuItem value="standard">标准</MenuItem>
|
|
||||||
<MenuItem value="advanced">高级</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 操作按钮 */}
|
|
||||||
<Grid size={{xs:12}}>
|
|
||||||
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'flex-end', mt: 3 }}>
|
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="text"
|
||||||
startIcon={<SkipNextIcon />}
|
startIcon={<SkipNextIcon />}
|
||||||
onClick={handleSkipConfig}
|
onClick={handleSkipConfig}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
>
|
>
|
||||||
跳过配置
|
跳过配置,稍后设置
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
variant="contained"
|
|
||||||
startIcon={isSubmitting ? <CircularProgress size={20} /> : <SettingsIcon />}
|
|
||||||
disabled={isSubmitting}
|
|
||||||
>
|
|
||||||
{isSubmitting ? '配置中...' : '完成配置'}
|
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
Refresh as RefreshIcon,
|
Refresh as RefreshIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useKnowledgeList, useKnowledgeOperations } from '@/hooks/knowledge_hooks';
|
import { useKnowledgeList, useKnowledgeOperations } from '@/hooks/knowledge-hooks';
|
||||||
import { useUserData } from '@/hooks/useUserData';
|
import { useUserData } from '@/hooks/useUserData';
|
||||||
import KnowledgeGridView from '@/components/knowledge/KnowledgeGridView';
|
import KnowledgeGridView from '@/components/knowledge/KnowledgeGridView';
|
||||||
import type { IKnowledge } from '@/interfaces/database/knowledge';
|
import type { IKnowledge } from '@/interfaces/database/knowledge';
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
Tab
|
Tab
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import LanguageSwitcher from '../../components/LanguageSwitcher';
|
import LanguageSwitcher from '../../components/LanguageSwitcher';
|
||||||
import { useLoginPage } from '../../hooks/login_hooks';
|
import { useLoginPage } from '../../hooks/login-hooks';
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|||||||
Reference in New Issue
Block a user