feat(knowledge-config): enhance knowledge configuration form with accordion sections

- Add accordion sections for general, page rank, RAPTOR, and GraphRAG configurations
- Implement detailed form controls for each configuration section
- Update parser config interfaces to support new configuration options
This commit is contained in:
2025-10-14 19:15:32 +08:00
parent 9f6785672f
commit 486815d83e
3 changed files with 597 additions and 208 deletions

View File

@@ -3,6 +3,54 @@ import knowledgeService from '@/services/knowledge_service';
import type { IKnowledge, IKnowledgeResult } from '@/interfaces/database/knowledge';
import type { IFetchKnowledgeListRequestParams } from '@/interfaces/request/knowledge';
/**
{
"avatar": "data:image/png;base64,iVBORw0K
"chunk_num": 1180,
"create_time": 1759986452748,
"description": " 213213",
"doc_num": 16,
"embd_id": "",
"id": "dcc2871aa4cd11f08d4116ac85b1de0a",
"language": "English",
"name": "k1123",
"pagerank": 0,
"parser_config": {
"auto_keywords": 0,
"auto_questions": 0,
"chunk_token_num": 512,
"delimiter": "\n",
"graphrag": {
"entity_types": [
"organization",
"person",
"geo",
"event",
"category"
],
"method": "light",
"use_graphrag": true
},
"html4excel": false,
"layout_recognize": "Plain Text",
"raptor": {
"max_cluster": 64,
"max_token": 256,
"prompt": "\u8bf7\u603b\u7ed3\u4ee5\u4e0b\u6bb5\u843d\u3002 \u5c0f\u5fc3\u6570\u5b57\uff0c\u4e0d\u8981\u7f16\u9020\u3002 \u6bb5\u843d\u5982\u4e0b\uff1a\n {cluster_content}\n\u4ee5\u4e0a\u5c31\u662f\u4f60\u9700\u8981\u603b\u7ed3\u7684\u5185\u5bb9\u3002",
"random_seed": 0,
"threshold": 0.1,
"use_raptor": false
},
"topn_tags": 3
},
"parser_id": "naive",
"permission": "team",
"size": 56819092,
"token_num": 293067,
"update_time": 1760436169574
}
*/
// 知识库列表Hook状态接口
export interface UseKnowledgeListState {
knowledgeBases: IKnowledge[];

View File

@@ -1,5 +1,56 @@
import type { RunningStatus } from '@/constants/knowledge';
/**
{
"avatar": "data:image/png;base64,iVBORw0K
"chunk_num": 1180,
"create_time": 1759986452748,
"description": " 213213",
"doc_num": 16,
"embd_id": "",
"id": "dcc2871aa4cd11f08d4116ac85b1de0a",
"language": "English",
"name": "k1123",
"pagerank": 0,
"parser_config": {
"auto_keywords": 0,
"auto_questions": 0,
"chunk_token_num": 512,
"delimiter": "\n",
"graphrag": {
"entity_types": [
"organization",
"person",
"geo",
"event",
"category"
],
"method": "light",
"use_graphrag": true
},
"html4excel": false,
"layout_recognize": "Plain Text",
"raptor": {
"max_cluster": 64,
"max_token": 256,
"prompt": "\u8bf7\u603b\u7ed3\u4ee5\u4e0b\u6bb5\u843d\u3002 \u5c0f\u5fc3\u6570\u5b57\uff0c\u4e0d\u8981\u7f16\u9020\u3002 \u6bb5\u843d\u5982\u4e0b\uff1a\n {cluster_content}\n\u4ee5\u4e0a\u5c31\u662f\u4f60\u9700\u8981\u603b\u7ed3\u7684\u5185\u5bb9\u3002",
"random_seed": 0,
"threshold": 0.1,
"use_raptor": false
},
"topn_tags": 3
},
"parser_id": "naive",
"permission": "team",
"size": 56819092,
"token_num": 293067,
"update_time": 1760436169574
}
*/
/**
* 知识库接口定义
* 包含知识库的基本信息、配置和状态
@@ -26,7 +77,7 @@ export interface IKnowledge {
/** 知识库名称 */
name: string;
/** 解析器配置 */
parser_config: ParserConfig;
parser_config: IParserConfig;
/** 解析器ID */
parser_id: string;
/** 管道ID */
@@ -83,17 +134,60 @@ export interface IKnowledgeResult {
/**
* Raptor配置接口
* 用于配置是否启用Raptor功能
{
"max_cluster": 64,
"max_token": 256,
"prompt": "\u8bf7\u603b\u7ed3\u4ee5\u4e0b\u6bb5\u843d\u3002
\u5c0f\u5fc3\u6570\u5b57\uff0c\u4e0d\u8981\u7f16\u9020\u3002 \u6bb5\u843d\u5982\u4e0b\uff1a\n
{cluster_content}\n\u4ee5\u4e0a\u5c31\u662f\u4f60\u9700\u8981\u603b\u7ed3\u7684\u5185\u5bb9\u3002",
"random_seed": 0,
"threshold": 0.1,
"use_raptor": false
}
*/
export interface Raptor {
export interface IRaptor {
/** 是否使用Raptor */
use_raptor: boolean;
/** 最大集群数,可选 */
max_cluster?: number;
/** 最大令牌数,可选 */
max_token?: number;
/** 提示模板,可选 */
prompt?: string;
/** 随机种子,可选 */
random_seed?: number;
/** 阈值,可选 */
threshold?: number;
}
/**
* GraphRAG配置接口
* 用于配置是否启用GraphRAG功能
{
"entity_types": [
"organization",
"person",
"geo",
"event",
"category"
],
"method": "light",
"use_graphrag": true
}
*/
export interface IGraphrag {
use_graphrag: boolean;
/** 实体类型列表,可选 */
entity_types?: string[];
/** 方法,可选 */
method?: string;
}
/**
* 解析器配置接口
* 定义文档解析的各种参数和选项
*/
export interface ParserConfig {
export interface IParserConfig {
/** 起始页码,可选 */
from_page?: number;
/** 结束页码,可选 */
@@ -111,13 +205,13 @@ export interface ParserConfig {
/** 是否启用布局识别,可选 */
layout_recognize?: boolean;
/** Raptor配置可选 */
raptor?: Raptor;
raptor?: IRaptor;
/** 标签知识库ID列表可选 */
tag_kb_ids?: string[];
/** 顶部标签数量,可选 */
topn_tags?: number;
/** GraphRAG配置可选 */
graphrag?: { use_graphrag?: boolean };
graphrag?: IGraphrag;
}
/**

View File

@@ -12,11 +12,62 @@ import {
FormHelperText,
Button,
CircularProgress,
Switch,
FormControlLabel,
Chip,
Slider,
Accordion,
AccordionSummary,
AccordionDetails,
} from '@mui/material';
import {
Save as SaveIcon,
ExpandMore as ExpandMoreIcon,
Add as AddIcon,
} from '@mui/icons-material';
import { DOCUMENT_PARSER_TYPES, type DocumentParserType } from '@/constants/knowledge';
import { type IParserConfig } from '@/interfaces/database/knowledge';
/**
{
"kb_id": "dcc2871aa4cd11f08d4116ac85b1de0a",
"name": "k1123",
"description": " 213213",
"permission": "team",
"parser_id": "naive",
"embd_id": "",
"parser_config": {
"layout_recognize": "Plain Text",
"chunk_token_num": 512,
"delimiter": "\n",
"auto_keywords": 0,
"auto_questions": 0,
"html4excel": false,
"topn_tags": 3,
"raptor": {
"use_raptor": true,
"prompt": "请总结以下段落。 小心数字,不要编造。 段落如下:\n {cluster_content}\n以上就是你需要总结的内容。",
"max_token": 256,
"threshold": 0.1,
"max_cluster": 64,
"random_seed": 0
},
"graphrag": {
"use_graphrag": true,
"entity_types": [
"organization",
"person",
"geo",
"event",
"category"
],
"method": "light"
}
},
"pagerank": 0
}
*/
// 解析器选项配置
const parserOptions = [
@@ -37,12 +88,8 @@ const parserOptions = [
{ value: DOCUMENT_PARSER_TYPES.KnowledgeGraph, label: '知识图谱解析器', description: '构建知识图谱结构' },
];
export interface ConfigFormData {
export interface ConfigFormData extends IParserConfig {
parser_id: DocumentParserType;
chunk_token_count?: number;
layout_recognize?: boolean;
task_page_size?: number;
[key: string]: any;
}
interface ChunkMethodFormProps {
@@ -61,232 +108,432 @@ function ChunkMethodForm({
isSubmitting = false,
onCancel,
disabled = false,
submitButtonText = '提交',
submitButtonText = '保存',
cancelButtonText = '取消'
}: ChunkMethodFormProps) {
const selectedParser: DocumentParserType = form.watch('parser_id');
const [entityTypes, setEntityTypes] = React.useState<string[]>(['organization', 'person', 'geo', 'event', 'category']);
// 根据选择的解析器显示不同的配置选项
const renderParserSpecificConfig = () => {
switch (selectedParser) {
case DOCUMENT_PARSER_TYPES.Naive:
return (
<Grid container spacing={3}>
<Grid size={{xs:12,sm:6}}>
// 通用配置部分
const renderGeneralConfig = () => (
<Accordion defaultExpanded>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6"></Typography>
</AccordionSummary>
<AccordionDetails>
<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>
{/* PDF解析器 */}
<Grid size={12}>
<FormControl fullWidth disabled={disabled}>
<InputLabel>PDF解析器</InputLabel>
<Select
label="PDF解析器"
defaultValue="Naive"
disabled={disabled}
>
<MenuItem value="Naive">Naive</MenuItem>
</Select>
</FormControl>
</Grid>
{/* 嵌入模型 */}
<Grid size={12}>
<FormControl fullWidth disabled={disabled}>
<InputLabel></InputLabel>
<Select
label="嵌入模型"
defaultValue=""
disabled={disabled}
>
<MenuItem value=""></MenuItem>
</Select>
</FormControl>
</Grid>
{/* 建议文本块大小 */}
<Grid size={12}>
<Typography gutterBottom></Typography>
<Box sx={{ px: 2 }}>
<Slider
defaultValue={512}
min={50}
max={2048}
step={1}
valueLabelDisplay="on"
disabled={disabled}
{...form.register('chunk_token_num', { valueAsNumber: true })}
/>
</Box>
<Typography variant="caption" color="text.secondary" sx={{ ml: 2 }}>
512
</Typography>
</Grid>
{/* 文本分段标识符 */}
<Grid size={12}>
<TextField
fullWidth
label="文本分段标识符"
placeholder="\\n"
disabled={disabled}
{...form.register('delimiter')}
helperText="用于分割文本的分隔符"
/>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
);
// 页面排名配置部分
const renderPageRankConfig = () => (
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6"></Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={3}>
{/* 页面排名 */}
<Grid size={12}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Typography></Typography>
<Switch disabled={disabled} />
<TextField
fullWidth
type="number"
label="分块大小"
placeholder="512"
size="small"
defaultValue={0}
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数量'}
sx={{ width: 100 }}
/>
</Grid>
<Grid size={{xs:12,sm:6}}>
</Box>
</Grid>
{/* 自动关键词提取 */}
<Grid size={12}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Typography></Typography>
<Switch disabled={disabled} />
<TextField
fullWidth
label="分隔符"
placeholder="\\n"
type="number"
size="small"
defaultValue={0}
disabled={disabled}
{...form.register('delimiter')}
helperText="用于分割文本的分隔符"
sx={{ width: 100 }}
{...form.register('auto_keywords', { valueAsNumber: true })}
/>
</Grid>
</Box>
</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}>
{/* 自动问题提取 */}
<Grid size={12}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Typography></Typography>
<Switch disabled={disabled} />
<TextField
fullWidth
label="实体类型"
placeholder="person,organization,location"
type="number"
size="small"
defaultValue={0}
disabled={disabled}
{...form.register('entity_types')}
helperText="指定要提取的实体类型,用逗号分隔"
sx={{ width: 100 }}
{...form.register('auto_questions', { valueAsNumber: true })}
/>
</Grid>
</Box>
</Grid>
);
case DOCUMENT_PARSER_TYPES.Picture:
return (
<Grid container spacing={3}>
<Grid size={12}>
<TextField
fullWidth
multiline
rows={3}
label="系统提示词"
placeholder="请描述图片中的内容..."
{/* 表格转HTML */}
<Grid size={12}>
<FormControlLabel
control={
<Switch
disabled={disabled}
{...form.register('html4excel')}
/>
}
label="表格转HTML"
/>
</Grid>
{/* 标签集 */}
<Grid size={12}>
<FormControl fullWidth disabled={disabled}>
<InputLabel></InputLabel>
<Select
label="标签集"
defaultValue=""
disabled={disabled}
{...form.register('system_prompt')}
helperText="用于指导AI理解图片内容的提示词"
/>
</Grid>
>
<MenuItem value=""></MenuItem>
</Select>
</FormControl>
</Grid>
);
</Grid>
</AccordionDetails>
</Accordion>
);
default:
return (
<Grid container spacing={3}>
<Grid size={12}>
<Typography variant="body2" color="text.secondary">
使
</Typography>
</Grid>
// RAPTOR集成配置部分
const renderRaptorConfig = () => (
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">使RAPTOR集成</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={3}>
{/* 启用RAPTOR */}
<Grid size={12}>
<FormControlLabel
control={
<Switch
disabled={disabled}
{...form.register('raptor.use_raptor')}
/>
}
label="使用召回增强RAPTOR集成"
/>
</Grid>
);
}
};
{/* 提示词 */}
<Grid size={12}>
<TextField
fullWidth
multiline
rows={4}
label="提示词"
placeholder="请总结以下段落。小心数字,不要编造。段落如下:&#10; {cluster_content}&#10;以上就是你需要总结的内容。"
disabled={disabled}
{...form.register('raptor.prompt')}
helperText="用于RAPTOR集成的提示词模板"
/>
</Grid>
{/* 最大token数 */}
<Grid size={{xs:12,sm:6}}>
<Typography gutterBottom>token数</Typography>
<Box sx={{ px: 2 }}>
<Slider
defaultValue={256}
min={50}
max={1000}
step={1}
valueLabelDisplay="on"
disabled={disabled}
{...form.register('raptor.max_token', { valueAsNumber: true })}
/>
</Box>
<Typography variant="caption" color="text.secondary" sx={{ ml: 2 }}>
256
</Typography>
</Grid>
{/* 阈值 */}
<Grid size={{xs:12,sm:6}}>
<Typography gutterBottom></Typography>
<Box sx={{ px: 2 }}>
<Slider
defaultValue={0.1}
min={0 as number}
max={1}
step={0.01}
valueLabelDisplay="on"
disabled={disabled}
{...form.register('raptor.threshold', { valueAsNumber: true })}
/>
</Box>
<Typography variant="caption" color="text.secondary" sx={{ ml: 2 }}>
0.1
</Typography>
</Grid>
{/* 最大聚类数 */}
<Grid size={{xs:12,sm:6}}>
<Typography gutterBottom></Typography>
<Box sx={{ px: 2 }}>
<Slider
defaultValue={64}
min={1}
max={200 as number}
step={1}
valueLabelDisplay="on"
disabled={disabled}
{...form.register('raptor.max_cluster', { valueAsNumber: true })}
/>
</Box>
<Typography variant="caption" color="text.secondary" sx={{ ml: 2 }}>
64
</Typography>
</Grid>
{/* 随机种子 */}
<Grid size={{xs:12,sm:6}}>
<TextField
fullWidth
type="number"
label="随机种子"
defaultValue={0}
disabled={disabled}
{...form.register('raptor.random_seed', { valueAsNumber: true })}
InputProps={{
endAdornment: (
<Button size="small" disabled={disabled}>
+
</Button>
)
}}
/>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
);
// 提取知识图谱配置部分
const renderGraphRagConfig = () => (
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6"></Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={3}>
{/* 启用知识图谱 */}
<Grid size={12}>
<FormControlLabel
control={
<Switch
disabled={disabled}
{...form.register('graphrag.use_graphrag')}
/>
}
label="提取知识图谱"
/>
</Grid>
{/* 添加实体类型 */}
<Grid size={12}>
<Button
startIcon={<AddIcon />}
variant="outlined"
size="small"
disabled={disabled}
onClick={() => {
// 添加新实体类型的逻辑
}}
>
+
</Button>
</Grid>
{/* 实体类型标签 */}
<Grid size={12}>
<Typography variant="subtitle2" gutterBottom></Typography>
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
{entityTypes.map((type, index) => (
<Chip
key={index}
label={type}
onDelete={disabled ? undefined : () => {
setEntityTypes(prev => prev.filter((_, i) => i !== index));
}}
disabled={disabled}
/>
))}
</Box>
</Grid>
{/* 方法 */}
<Grid size={12}>
<FormControl fullWidth disabled={disabled}>
<InputLabel></InputLabel>
<Select
label="方法"
defaultValue="Light"
{...form.register('graphrag.method')}
>
<MenuItem value="Light">Light</MenuItem>
</Select>
</FormControl>
</Grid>
{/* 实体归一化 */}
<Grid size={12}>
<FormControlLabel
control={<Switch disabled={disabled} />}
label="实体归一化"
/>
</Grid>
{/* 社区报告生成 */}
<Grid size={12}>
<FormControlLabel
control={<Switch disabled={disabled} />}
label="社区报告生成"
/>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
);
return (
<Box>
<Typography variant="h6" gutterBottom>
<Typography variant="h5" gutterBottom>
</Typography>
<Typography variant="body2" color="text.secondary" gutterBottom sx={{ mb: 3 }}>
</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>
<Box sx={{ mb: 3 }}>
{renderGeneralConfig()}
{renderPageRankConfig()}
{renderRaptorConfig()}
{renderGraphRagConfig()}
</Box>
{/* 解析器特定配置 */}
<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 sx={{ display: 'flex', gap: 2, justifyContent: 'flex-end' }}>
{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>
</Box>
);
}