feat(form): add form field components and configuration updates

refactor(knowledge): restructure configuration components to use common items
This commit is contained in:
2025-10-15 18:48:48 +08:00
parent fe8747983e
commit fd4309582d
36 changed files with 1869 additions and 1001 deletions

3
.gitignore vendored
View File

@@ -24,4 +24,5 @@ dist-ssr
*.sw?
# rag core
rag_web_core
rag_web_core_v0.20.5
rag_web_core_deprecated

View File

@@ -19,6 +19,5 @@ export default defineConfig([
ecmaVersion: 2020,
globals: globals.browser,
},
ignores: ['rag_web_core/**'],
},
])

View File

@@ -15,6 +15,7 @@
"@mui/icons-material": "^7.3.4",
"@mui/material": "^7.3.4",
"@mui/x-data-grid": "^8.14.0",
"@mui/x-date-pickers": "^8.14.0",
"ahooks": "^3.9.5",
"axios": "^1.12.2",
"dayjs": "^1.11.18",

60
pnpm-lock.yaml generated
View File

@@ -23,6 +23,9 @@ importers:
'@mui/x-data-grid':
specifier: ^8.14.0
version: 8.14.0(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@7.3.3(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mui/x-date-pickers':
specifier: ^8.14.0
version: 8.14.0(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@7.3.3(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(dayjs@1.11.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
ahooks:
specifier: ^3.9.5
version: 3.9.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -588,6 +591,43 @@ packages:
'@emotion/styled':
optional: true
'@mui/x-date-pickers@8.14.0':
resolution: {integrity: sha512-fz8z1hoi1tbG1QUcZAkQdiO3GsCOpUeRfyANXDDzDN88L4VqwNEyrv0wmzmCfIX2sgur4gWwWJzMuCvauMgXRw==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@emotion/react': ^11.9.0
'@emotion/styled': ^11.8.1
'@mui/material': ^5.15.14 || ^6.0.0 || ^7.0.0
'@mui/system': ^5.15.14 || ^6.0.0 || ^7.0.0
date-fns: ^2.25.0 || ^3.2.0 || ^4.0.0
date-fns-jalali: ^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0
dayjs: ^1.10.7
luxon: ^3.0.2
moment: ^2.29.4
moment-hijri: ^2.1.2 || ^3.0.0
moment-jalaali: ^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0
react: ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta:
'@emotion/react':
optional: true
'@emotion/styled':
optional: true
date-fns:
optional: true
date-fns-jalali:
optional: true
dayjs:
optional: true
luxon:
optional: true
moment:
optional: true
moment-hijri:
optional: true
moment-jalaali:
optional: true
'@mui/x-internals@8.14.0':
resolution: {integrity: sha512-esYyl61nuuFXiN631TWuPh2tqdoyTdBI/4UXgwH3rytF8jiWvy6prPBPRHEH1nvW3fgw9FoBI48FlOO+yEI8xg==}
engines: {node: '>=14.0.0'}
@@ -2175,6 +2215,26 @@ snapshots:
transitivePeerDependencies:
- '@types/react'
'@mui/x-date-pickers@8.14.0(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@7.3.3(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(dayjs@1.11.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@babel/runtime': 7.28.4
'@mui/material': 7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mui/system': 7.3.3(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)
'@mui/utils': 7.3.3(@types/react@19.2.2)(react@18.3.1)
'@mui/x-internals': 8.14.0(@types/react@19.2.2)(react@18.3.1)
'@types/react-transition-group': 4.4.12(@types/react@19.2.2)
clsx: 2.1.1
prop-types: 15.8.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.2.2)(react@18.3.1)
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)
dayjs: 1.11.18
transitivePeerDependencies:
- '@types/react'
'@mui/x-internals@8.14.0(@types/react@19.2.2)(react@18.3.1)':
dependencies:
'@babel/runtime': 7.28.4

View File

@@ -0,0 +1,74 @@
import React from 'react';
import { Checkbox, FormControlLabel, FormControl, FormHelperText, Box, Typography } from '@mui/material';
import { useFormContext, Controller } from 'react-hook-form';
import { type IFormLayoutType } from './index';
export interface CheckboxFormFieldProps extends IFormLayoutType {
name: string;
label: string;
defaultValue?: boolean;
required?: boolean;
disabled?: boolean;
helperText?: string;
color?: 'primary' | 'secondary' | 'default';
}
export function CheckboxFormField({
name,
label,
defaultValue = false,
required = false,
disabled = false,
layout = 'vertical',
helperText,
color = 'primary',
}: CheckboxFormFieldProps) {
const { control, formState: { errors } } = useFormContext();
const error = errors[name];
const isHorizontal = layout === 'horizontal';
const checkbox = (
<Controller
name={name}
control={control}
defaultValue={defaultValue}
render={({ field }) => (
<FormControl error={!!error} disabled={disabled}>
<FormControlLabel
control={
<Checkbox
{...field}
checked={field.value || false}
onChange={(e) => field.onChange(e.target.checked)}
color={color}
required={required}
/>
}
label={isHorizontal ? undefined : label}
/>
{(error?.message || helperText) && (
<FormHelperText>
{error?.message as string || helperText}
</FormHelperText>
)}
</FormControl>
)}
/>
);
if (isHorizontal) {
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Typography variant="subtitle1" sx={{ minWidth: 120, pt: 1 }}>
{label}
{required && <span style={{ color: 'red' }}>*</span>}
</Typography>
<Box sx={{ flex: 1 }}>
{checkbox}
</Box>
</Box>
);
}
return checkbox;
}

View File

@@ -0,0 +1,140 @@
import React, { useState } from 'react';
import {
Box,
Typography,
Chip,
IconButton,
TextField,
FormHelperText,
} from '@mui/material';
import { Add as AddIcon } from '@mui/icons-material';
import { Controller, useFormContext } from 'react-hook-form';
export interface ChipListFormFieldProps {
name: string;
label: string;
helperText?: string;
defaultValue?: string[];
disabled?: boolean;
required?: boolean;
allowAdd?: boolean;
allowDelete?: boolean;
maxChips?: number;
placeholder?: string;
chipColor?: 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning';
chipVariant?: 'filled' | 'outlined';
}
export const ChipListFormField: React.FC<ChipListFormFieldProps> = ({
name,
label,
helperText,
defaultValue = [],
disabled = false,
required = false,
allowAdd = true,
allowDelete = true,
maxChips,
placeholder = '输入后按回车添加',
chipColor = 'default',
chipVariant = 'outlined',
}) => {
const { control, setValue, getValues } = useFormContext();
const [inputValue, setInputValue] = useState('');
const handleAddChip = (field: any) => {
if (inputValue.trim() && (!maxChips || field.value.length < maxChips)) {
const newChips = [...field.value, inputValue.trim()];
field.onChange(newChips);
setInputValue('');
}
};
const handleDeleteChip = (field: any, chipToDelete: string) => {
if (allowDelete) {
const newChips = field.value.filter((chip: string) => chip !== chipToDelete);
field.onChange(newChips);
}
};
const handleKeyPress = (event: React.KeyboardEvent, field: any) => {
if (event.key === 'Enter') {
event.preventDefault();
handleAddChip(field);
}
};
return (
<Box>
<Typography variant="subtitle1" gutterBottom>
{required && <span style={{ color: 'red' }}>*</span>}
{label}
</Typography>
<Controller
name={name}
control={control}
defaultValue={defaultValue}
rules={{
required: required ? `${label}是必填项` : false,
validate: (value) => {
if (maxChips && value.length > maxChips) {
return `${label}最多只能有${maxChips}个标签`;
}
return true;
},
}}
render={({ field, fieldState: { error } }) => (
<Box>
{/* 标签显示区域 */}
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1, mb: 2, minHeight: '40px' }}>
{field.value.map((chip: string, index: number) => (
<Chip
key={index}
label={chip}
onDelete={allowDelete && !disabled ? () => handleDeleteChip(field, chip) : undefined}
variant={chipVariant}
color={chipColor}
disabled={disabled}
/>
))}
{field.value.length === 0 && (
<Typography variant="body2" color="text.secondary" sx={{ py: 1 }}>
</Typography>
)}
</Box>
{/* 添加标签输入框 */}
{allowAdd && !disabled && (!maxChips || field.value.length < maxChips) && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<TextField
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(e) => handleKeyPress(e, field)}
placeholder={placeholder}
size="small"
fullWidth
disabled={disabled}
/>
<IconButton
onClick={() => handleAddChip(field)}
disabled={!inputValue.trim() || disabled}
size="small"
>
<AddIcon />
</IconButton>
</Box>
)}
{/* 错误信息和帮助文本 */}
{(error || helperText) && (
<FormHelperText error={!!error}>
{error?.message || helperText}
</FormHelperText>
)}
</Box>
)}
/>
</Box>
);
};

View File

@@ -0,0 +1,64 @@
import React from 'react';
import { Box, Typography } from '@mui/material';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { useFormContext, Controller } from 'react-hook-form';
import dayjs, { Dayjs } from 'dayjs';
export interface DatePickerFormFieldProps {
name: string;
label: string;
defaultValue?: string | Date | Dayjs | null;
required?: boolean;
disabled?: boolean;
helperText?: string;
minDate?: string | Date | Dayjs;
maxDate?: string | Date | Dayjs;
format?: string;
}
export function DatePickerFormField({
name,
label,
defaultValue = null,
required = false,
disabled = false,
helperText,
minDate,
maxDate,
format = 'YYYY-MM-DD',
}: DatePickerFormFieldProps) {
const { control, formState: { errors } } = useFormContext();
const error = errors[name];
const datePicker = (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Controller
name={name}
control={control}
defaultValue={defaultValue ? dayjs(defaultValue) : null}
render={({ field }) => (
<DatePicker
{...field}
disabled={disabled}
minDate={minDate ? dayjs(minDate) : undefined}
maxDate={maxDate ? dayjs(maxDate) : undefined}
format={format}
slotProps={{
textField: {
required,
error: !!error,
helperText: error?.message as string || helperText,
fullWidth: true,
variant: 'outlined',
},
}}
/>
)}
/>
</LocalizationProvider>
);
return datePicker;
}

View File

@@ -0,0 +1,80 @@
import React from 'react';
import {
Box,
Typography,
TextField,
} from '@mui/material';
import { Controller, useFormContext } from 'react-hook-form';
export interface MultilineTextFormFieldProps {
name: string;
label: string;
helperText?: string;
defaultValue?: string;
disabled?: boolean;
required?: boolean;
fullWidth?: boolean;
rows?: number;
maxRows?: number;
minRows?: number;
placeholder?: string;
size?: 'small' | 'medium';
maxLength?: number;
}
export const MultilineTextFormField: React.FC<MultilineTextFormFieldProps> = ({
name,
label,
helperText,
defaultValue = '',
disabled = false,
required = false,
fullWidth = true,
rows = 4,
maxRows,
minRows,
placeholder,
size = 'medium',
maxLength,
}) => {
const { control } = useFormContext();
return (
<Box>
<Typography variant="subtitle1" gutterBottom>
{required && <span style={{ color: 'red' }}>*</span>}
{label}
</Typography>
<Controller
name={name}
control={control}
defaultValue={defaultValue}
rules={{
required: required ? `${label}是必填项` : false,
maxLength: maxLength ? {
value: maxLength,
message: `${label}不能超过${maxLength}个字符`
} : undefined,
}}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
multiline
rows={rows}
maxRows={maxRows}
minRows={minRows}
fullWidth={fullWidth}
disabled={disabled}
placeholder={placeholder}
size={size}
error={!!error}
helperText={error?.message || helperText}
inputProps={{
maxLength: maxLength,
}}
/>
)}
/>
</Box>
);
};

View File

@@ -0,0 +1,112 @@
import React from 'react';
import {
Box,
Typography,
TextField,
IconButton,
} from '@mui/material';
import { Add as AddIcon } from '@mui/icons-material';
import { Controller, useFormContext } from 'react-hook-form';
export interface NumberInputFormFieldProps {
name: string;
label: string;
helperText?: string;
defaultValue?: number;
disabled?: boolean;
required?: boolean;
fullWidth?: boolean;
min?: number;
max?: number;
step?: number;
placeholder?: string;
size?: 'small' | 'medium';
showRandomButton?: boolean;
onRandomClick?: () => void;
}
export const NumberInputFormField: React.FC<NumberInputFormFieldProps> = ({
name,
label,
helperText,
defaultValue = 0,
disabled = false,
required = false,
fullWidth = true,
min,
max,
step,
placeholder,
size = 'medium',
showRandomButton = false,
onRandomClick,
}) => {
const { control } = useFormContext();
const handleRandomClick = () => {
if (onRandomClick) {
onRandomClick();
} else if (min !== undefined && max !== undefined) {
const randomValue = Math.floor(Math.random() * (max - min + 1)) + min;
// 这里需要通过setValue来更新表单值但为了保持组件的纯净性
// 建议通过onRandomClick回调来处理
}
};
return (
<Box>
<Typography variant="subtitle1" gutterBottom>
{required && <span style={{ color: 'red' }}>*</span>}
{label}
</Typography>
<Controller
name={name}
control={control}
defaultValue={defaultValue}
rules={{
required: required ? `${label}是必填项` : false,
min: min !== undefined ? {
value: min,
message: `${label}不能小于${min}`
} : undefined,
max: max !== undefined ? {
value: max,
message: `${label}不能大于${max}`
} : undefined,
}}
render={({ field, fieldState: { error } }) => (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<TextField
{...field}
type="number"
fullWidth={fullWidth}
disabled={disabled}
placeholder={placeholder}
size={size}
error={!!error}
helperText={error?.message || helperText}
inputProps={{
min,
max,
step,
}}
onChange={(e) => {
const value = e.target.value === '' ? '' : Number(e.target.value);
field.onChange(value);
}}
/>
{showRandomButton && (
<IconButton
onClick={handleRandomClick}
disabled={disabled}
size={size}
>
<AddIcon />
</IconButton>
)}
</Box>
)}
/>
</Box>
);
};

View File

@@ -0,0 +1,96 @@
import React from 'react';
import {
Box,
Typography,
FormControl,
Select,
MenuItem,
FormHelperText,
InputLabel,
} from '@mui/material';
import { Controller, useFormContext } from 'react-hook-form';
export interface SelectOption {
value: string | number;
label: string;
disabled?: boolean;
}
export interface SelectFormFieldProps {
name: string;
label: string;
options: SelectOption[];
helperText?: string;
defaultValue?: string | number;
disabled?: boolean;
required?: boolean;
fullWidth?: boolean;
size?: 'small' | 'medium';
displayEmpty?: boolean;
emptyLabel?: string;
multiple?: boolean;
}
export const SelectFormField: React.FC<SelectFormFieldProps> = ({
name,
label,
options,
helperText,
defaultValue = '',
disabled = false,
required = false,
fullWidth = true,
size = 'medium',
displayEmpty = true,
emptyLabel = '请选择',
multiple = false,
}) => {
const { control } = useFormContext();
return (
<Box>
<Typography variant="subtitle1" gutterBottom>
{required && <span style={{ color: 'red' }}>*</span>}
{label}
</Typography>
<Controller
name={name}
control={control}
defaultValue={multiple ? [] : defaultValue}
rules={{
required: required ? `${label}是必填项` : false,
}}
render={({ field, fieldState: { error } }) => (
<FormControl fullWidth={fullWidth} error={!!error} size={size}>
<Select
{...field}
disabled={disabled}
displayEmpty={displayEmpty}
multiple={multiple}
>
{displayEmpty && !multiple && (
<MenuItem value="">
{emptyLabel}
</MenuItem>
)}
{options.map((option) => (
<MenuItem
key={option.value}
value={option.value}
disabled={option.disabled}
>
{option.label}
</MenuItem>
))}
</Select>
{(error || helperText) && (
<FormHelperText>
{error?.message || helperText}
</FormHelperText>
)}
</FormControl>
)}
/>
</Box>
);
};

View File

@@ -0,0 +1,86 @@
import React from 'react';
import { Box, Typography, Slider } from '@mui/material';
import { useController, useFormContext } from 'react-hook-form';
export interface SliderFormFieldProps {
name: string;
label: string;
min?: number;
max?: number;
step?: number;
defaultValue?: number;
valueLabelDisplay?: 'on' | 'auto' | 'off';
marks?: boolean | Array<{ value: number; label?: string }>;
disabled?: boolean;
required?: boolean;
sx?: object;
}
export const SliderFormField: React.FC<SliderFormFieldProps> = ({
name,
label,
min = 0,
max = 100,
step = 1,
defaultValue = 0,
valueLabelDisplay = 'on',
marks = false,
disabled = false,
required = false,
sx = {},
}) => {
const { control } = useFormContext();
const {
field,
fieldState: { error },
} = useController({
name,
control,
defaultValue,
});
return (
<Box sx={{ mb: 2, ...sx }}>
<Typography
variant="subtitle1"
gutterBottom
sx={{
color: error ? 'error.main' : 'inherit',
fontWeight: required ? 600 : 400,
}}
>
{label}
{required && <span style={{ color: 'red' }}> *</span>}
</Typography>
<Box sx={{ px: 2 }}>
<Slider
{...field}
min={min}
max={max}
step={step}
valueLabelDisplay={valueLabelDisplay}
marks={marks}
disabled={disabled}
onChange={(_, value) => field.onChange(value)}
sx={{
color: error ? 'error.main' : 'primary.main',
}}
/>
</Box>
{error && (
<Typography
variant="caption"
color="error"
sx={{ mt: 0.5, display: 'block' }}
>
{error.message}
</Typography>
)}
</Box>
);
};
export default SliderFormField;

View File

@@ -0,0 +1,105 @@
import {
FormControl,
FormHelperText,
Box,
Typography,
Slider,
TextField,
Grid,
} from '@mui/material';
import { useFormContext, Controller } from 'react-hook-form';
import { type ReactNode } from 'react';
import type { IFormLayoutType } from '.';
export type SliderInputFormFieldProps = {
max?: number;
min?: number;
step?: number;
name: string;
label: string;
tooltip?: ReactNode;
defaultValue?: number;
className?: string;
} & IFormLayoutType;
export function SliderInputFormField({
max = 100,
min = 0,
step = 1,
label,
name,
tooltip,
defaultValue = 0,
className,
layout = 'horizontal',
}: SliderInputFormFieldProps) {
const { control, formState: { errors } } = useFormContext();
const isHorizontal = layout === 'horizontal';
return (
<Box sx={{ mb: 3 }} className={className}>
<Controller
name={name}
control={control}
defaultValue={defaultValue}
render={({ field }) => (
<Box>
<Typography
variant="h6"
gutterBottom={!isHorizontal}
sx={{
mb: isHorizontal ? 1 : 2,
fontSize: isHorizontal ? '0.875rem' : '1.25rem',
color: isHorizontal ? 'text.secondary' : 'text.primary'
}}
>
{label}
{tooltip && (
<Typography
component="span"
variant="caption"
sx={{ ml: 1, color: 'text.secondary' }}
>
{tooltip}
</Typography>
)}
</Typography>
<Grid container spacing={2} alignItems="center">
<Grid size={{xs: isHorizontal ? 8 : 9}}>
<FormControl fullWidth>
<Slider
{...field}
min={min}
max={max}
step={step}
valueLabelDisplay="auto"
sx={{ mt: 1 }}
/>
</FormControl>
</Grid>
<Grid size={{xs: isHorizontal ? 4 : 3}}>
<FormControl>
<TextField
{...field}
type="number"
size="small"
inputProps={{ min, max, step }}
sx={{ width: '80px' }}
/>
</FormControl>
</Grid>
</Grid>
{errors[name] && (
<FormHelperText error sx={{ mt: 1 }}>
{errors[name]?.message as string}
</FormHelperText>
)}
</Box>
)}
/>
</Box>
);
}

View File

@@ -0,0 +1,72 @@
import React from 'react';
import {
Box,
Typography,
FormControlLabel,
Switch,
FormHelperText,
} from '@mui/material';
import { Controller, useFormContext } from 'react-hook-form';
export interface SwitchFormFieldProps {
name: string;
label: string;
helperText?: string;
defaultValue?: boolean;
disabled?: boolean;
required?: boolean;
size?: 'small' | 'medium';
color?: 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning';
}
export const SwitchFormField: React.FC<SwitchFormFieldProps> = ({
name,
label,
helperText,
defaultValue = false,
disabled = false,
required = false,
size = 'medium',
color = 'primary',
}) => {
const { control } = useFormContext();
return (
<Box>
<Controller
name={name}
control={control}
defaultValue={defaultValue}
rules={{
required: required ? `${label}是必填项` : false,
}}
render={({ field, fieldState: { error } }) => (
<>
<FormControlLabel
control={
<Switch
checked={field.value || false}
onChange={field.onChange}
disabled={disabled}
size={size}
color={color}
/>
}
label={
<Typography variant="body1">
{required && <span style={{ color: 'red' }}>*</span>}
{label}
</Typography>
}
/>
{(error || helperText) && (
<FormHelperText error={!!error}>
{error?.message || helperText}
</FormHelperText>
)}
</>
)}
/>
</Box>
);
};

View File

@@ -0,0 +1,69 @@
import React from 'react';
import { TextField, Box, Typography } from '@mui/material';
import { useFormContext, Controller } from 'react-hook-form';
import { type IFormLayoutType } from './index';
export interface TextFormFieldProps extends IFormLayoutType {
name: string;
label: string;
placeholder?: string;
defaultValue?: string;
required?: boolean;
disabled?: boolean;
helperText?: string;
type?: 'text' | 'email' | 'password' | 'url' | 'tel';
}
export function TextFormField({
name,
label,
placeholder,
defaultValue = '',
required = false,
disabled = false,
layout = 'vertical',
helperText,
type = 'text',
}: TextFormFieldProps) {
const { control, formState: { errors } } = useFormContext();
const error = errors[name];
const isHorizontal = layout === 'horizontal';
const textField = (
<Controller
name={name}
control={control}
defaultValue={defaultValue}
render={({ field }) => (
<TextField
{...field}
type={type}
label={isHorizontal ? undefined : label}
placeholder={placeholder}
required={required}
disabled={disabled}
error={!!error}
helperText={error?.message as string || helperText}
fullWidth
variant="outlined"
/>
)}
/>
);
if (isHorizontal) {
return (
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Typography variant="subtitle1" sx={{ minWidth: 120, pt: 1 }}>
{label}
{required && <span style={{ color: 'red' }}>*</span>}
</Typography>
<Box sx={{ flex: 1 }}>
{textField}
</Box>
</Box>
);
}
return textField;
}

View File

@@ -0,0 +1,35 @@
// 基础组件导出
export { SliderInputFormField } from './SliderInputFormField';
export { SwitchFormField } from './SwitchFormField';
export { SelectFormField } from './SelectFormField';
export { MultilineTextFormField } from './MultilineTextFormField';
export { NumberInputFormField } from './NumberInputFormField';
export { ChipListFormField } from './ChipListFormField';
export { SliderFormField } from './SliderFormField';
export { TextFormField } from './TextFormField';
export { DatePickerFormField } from './DatePickerFormField';
export { CheckboxFormField } from './CheckboxFormField';
// 类型导出
export type { SliderInputFormFieldProps } from './SliderInputFormField';
export type { SwitchFormFieldProps } from './SwitchFormField';
export type { SelectFormFieldProps, SelectOption } from './SelectFormField';
export type { MultilineTextFormFieldProps } from './MultilineTextFormField';
export type { NumberInputFormFieldProps } from './NumberInputFormField';
export type { ChipListFormFieldProps } from './ChipListFormField';
export type { SliderFormFieldProps } from './SliderFormField';
export type { TextFormFieldProps } from './TextFormField';
export type { DatePickerFormFieldProps } from './DatePickerFormField';
export type { CheckboxFormFieldProps } from './CheckboxFormField';
export type IFormLayoutType = {
layout?: FormLayout;
};
export const FORM_LAYOUTS = {
Vertical: 'vertical',
Horizontal: 'horizontal',
} as const;
export type FormLayout = (typeof FORM_LAYOUTS)[keyof typeof FORM_LAYOUTS];

163
src/pages/FormFieldTest.tsx Normal file
View File

@@ -0,0 +1,163 @@
import React from 'react';
import { Box, Typography, Paper, Divider } from '@mui/material';
import { useForm, FormProvider } from 'react-hook-form';
import {
SliderInputFormField,
SwitchFormField,
SelectFormField,
MultilineTextFormField,
NumberInputFormField,
ChipListFormField,
type SelectOption,
} from '@/components/FormField';
const FormFieldTest: React.FC = () => {
const methods = useForm({
defaultValues: {
parser_config: {
auto_keywords: 5,
auto_questions: 3,
delimiter: '\n',
chunk_token_num: 512,
layout_recognize: 'DeepDOC',
html4excel: false,
},
pagerank: 50,
custom_slider: 25,
},
});
const onSubmit = (data: any) => {
console.log('Form Data:', data);
};
return (
<Box sx={{ p: 3, maxWidth: 800, mx: 'auto' }}>
<Typography variant="h4" gutterBottom>
FormField
</Typography>
<Paper sx={{ p: 3, mt: 2 }}>
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<Typography variant="h6" gutterBottom>
</Typography>
<NumberInputFormField
name="parser_config.auto_keywords"
label="自动关键词"
defaultValue={5}
min={0}
placeholder="输入关键词数量"
/>
<NumberInputFormField
name="parser_config.auto_questions"
label="自动问题"
defaultValue={3}
min={0}
placeholder="输入问题数量"
/>
<Divider sx={{ my: 3 }} />
<Typography variant="h6" gutterBottom>
</Typography>
<MultilineTextFormField
name="parser_config.delimiter"
label="分隔符"
defaultValue="\n"
rows={2}
/>
<Divider sx={{ my: 3 }} />
<Typography variant="h6" gutterBottom>
Token数量配置
</Typography>
<SliderInputFormField
name="parser_config.chunk_token_num"
label="最大Token数"
min={64}
max={2048}
step={64}
defaultValue={512}
layout="horizontal"
/>
<Divider sx={{ my: 3 }} />
<Typography variant="h6" gutterBottom>
</Typography>
<NumberInputFormField
name="pagerank"
label="页面排名"
defaultValue={50}
min={0}
placeholder="输入页面排名"
/>
<Divider sx={{ my: 3 }} />
<Typography variant="h6" gutterBottom>
</Typography>
<SelectFormField
name="parser_config.layout_recognize"
label="布局识别方法"
options={[
{ value: 'DeepDOC', label: 'DeepDOC' },
{ value: 'LayoutLM', label: 'LayoutLM' },
{ value: 'OCR', label: 'OCR' }
]}
defaultValue="DeepDOC"
/>
<Divider sx={{ my: 3 }} />
<Typography variant="h6" gutterBottom>
Excel转HTML
</Typography>
<SwitchFormField
name="parser_config.html4excel"
label="Excel转HTML"
defaultValue={false}
/>
<Divider sx={{ my: 3 }} />
<Typography variant="h6" gutterBottom>
</Typography>
<SliderInputFormField
name="custom_slider"
label="自定义滑块"
tooltip="这是一个自定义的滑块组件"
max={100}
min={0}
defaultValue={25}
layout={'vertical'}
/>
<Box sx={{ mt: 4, display: 'flex', gap: 2 }}>
<button type="submit"></button>
<button
type="button"
onClick={() => methods.reset()}
>
</button>
</Box>
</form>
</FormProvider>
</Paper>
<Paper sx={{ p: 3, mt: 3 }}>
<Typography variant="h6" gutterBottom>
</Typography>
<pre style={{ fontSize: '12px', overflow: 'auto' }}>
{JSON.stringify(methods.watch(), null, 2)}
</pre>
</Paper>
</Box>
);
};
export default FormFieldTest;

View File

@@ -1,49 +1,16 @@
import React from 'react';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import { ChunkMethodItem, EmbeddingModelItem, PageRankItem, AutoKeywordsItem, AutoQuestionsItem, TagsItem } from './common-items';
export function AudioConfiguration() {
return (
<ConfigurationFormContainer>
<ChunkMethodItem />
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
Raptor配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
GraphRAG配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<PageRankItem />
<AutoKeywordsItem />
<AutoQuestionsItem />
<TagsItem />
</ConfigurationFormContainer>
);
}

View File

@@ -1,60 +1,60 @@
import React from 'react';
import { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import {
ChunkMethodItem,
EmbeddingModelItem,
LayoutRecognizeItem,
PageRankItem,
AutoKeywordsItem,
AutoQuestionsItem,
UseRaptorItem,
RaptorPromptItem,
RaptorMaxTokenItem,
RaptorThresholdItem,
RaptorMaxClusterItem,
RaptorRandomSeedItem,
UseGraphragItem,
EntityTypesItem,
GraphragMethodItem,
EntityNormalizeItem,
CommunityReportItem,
TagsItem
} from './common-items';
export function BookConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<ChunkMethodItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<LayoutRecognizeItem />
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
<PageRankItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<AutoKeywordsItem />
<AutoQuestionsItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
Raptor配置 -
</Typography>
</Box>
<UseRaptorItem />
<RaptorPromptItem />
<RaptorMaxTokenItem />
<RaptorThresholdItem />
<RaptorMaxClusterItem />
<RaptorRandomSeedItem />
</ConfigurationFormContainer>
<Box sx={{ mb: 2, p: 2 }}>
<Typography variant="body2" color="text.secondary">
GraphRAG配置 -
</Typography>
</Box>
<ConfigurationFormContainer>
<UseGraphragItem />
<EntityTypesItem />
<GraphragMethodItem />
<EntityNormalizeItem />
<CommunityReportItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<TagsItem />
</ConfigurationFormContainer>
</MainContainer>
);

View File

@@ -1,118 +0,0 @@
import {
FormControl,
InputLabel,
Select,
MenuItem,
FormHelperText,
Box,
Typography,
ListSubheader,
} from '@mui/material';
import { useFormContext, Controller } from 'react-hook-form';
import { DOCUMENT_PARSER_TYPES } from '@/constants/knowledge';
import { useSelectChunkMethodList } from '../hooks';
import { useEmbeddingModelOptions } from '@/hooks/llm-hooks';
// 解析器选项配置
const PARSER_OPTIONS = [
{ value: DOCUMENT_PARSER_TYPES.Naive, label: 'General', description: '通用解析器' },
{ value: DOCUMENT_PARSER_TYPES.Qa, label: 'Q&A', description: 'Q&A解析器' },
{ value: DOCUMENT_PARSER_TYPES.Resume, label: 'Resume', description: 'Resume解析器' },
{ value: DOCUMENT_PARSER_TYPES.Manual, label: 'Manual', description: 'Manual解析器' },
{ value: DOCUMENT_PARSER_TYPES.Table, label: 'Table', description: 'Table解析器' },
{ value: DOCUMENT_PARSER_TYPES.Paper, label: 'Paper', description: 'Paper解析器' },
{ value: DOCUMENT_PARSER_TYPES.Book, label: 'Book', description: 'Book解析器' },
{ value: DOCUMENT_PARSER_TYPES.Laws, label: 'Laws', description: 'Laws解析器' },
{ value: DOCUMENT_PARSER_TYPES.Presentation, label: 'Presentation', description: 'Presentation解析器' },
{ value: DOCUMENT_PARSER_TYPES.One, label: 'One', description: 'One解析器' },
{ value: DOCUMENT_PARSER_TYPES.Tag, label: 'Tag', description: 'Tag解析器' },
];
export function ChunkMethodItem() {
const { control, formState: { errors } } = useFormContext();
const parserIds = useSelectChunkMethodList();
const parserOptions = parserIds.map((x) => ({
value: x,
label: PARSER_OPTIONS.find((y) => y.value === x)?.label || x,
description: PARSER_OPTIONS.find((y) => y.value === x)?.description || x,
}));
return (
<Box>
<Typography variant="h6" gutterBottom>
</Typography>
<Controller
name="parser_id"
control={control}
render={({ field }) => (
<FormControl fullWidth error={!!errors.parser_id}>
<InputLabel></InputLabel>
<Select
{...field}
label="选择切片方法"
>
{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>
{errors.parser_id && (
<FormHelperText>{errors.parser_id.message as string}</FormHelperText>
)}
</FormControl>
)}
/>
</Box>
);
}
export function EmbeddingModelItem() {
const { control, formState: { errors } } = useFormContext();
const { options: embdOptions } = useEmbeddingModelOptions();
return (
<Box sx={{ mb: 3 }}>
<Typography variant="h6" gutterBottom>
</Typography>
<Controller
name="embd_id"
control={control}
render={({ field }) => (
<FormControl fullWidth error={!!errors.embd_id}>
<InputLabel></InputLabel>
<Select
{...field}
label="选择嵌入模型"
>
{
embdOptions.map((group) => [
<ListSubheader key={`header-${group.label}`} disableSticky>
{group.label}
</ListSubheader>,
...group.options.map((option) => (
<MenuItem key={option.value} value={option.value} disabled={option.disabled}>
{option.label}
</MenuItem>
))
])
}
</Select>
{errors.embd_id && (
<FormHelperText>{errors.embd_id.message as string}</FormHelperText>
)}
</FormControl>
)}
/>
</Box>
);
}

View File

@@ -0,0 +1,416 @@
import { useMemo } from 'react';
import {
FormControl,
InputLabel,
Select,
MenuItem,
FormHelperText,
Box,
Typography,
ListSubheader,
Button,
} from '@mui/material';
import { Shuffle as ShuffleIcon } from '@mui/icons-material';
import { useFormContext, Controller } from 'react-hook-form';
import { DOCUMENT_PARSER_TYPES, LLM_MODEL_TYPES, type LlmModelType } from '@/constants/knowledge';
import { useSelectChunkMethodList } from '../hooks';
import { useEmbeddingModelOptions, useLlmOptionsByModelType } from '@/hooks/llm-hooks';
import {
SliderInputFormField,
SwitchFormField,
SelectFormField,
MultilineTextFormField,
NumberInputFormField,
ChipListFormField,
TextFormField,
type SelectOption,
} from '@/components/FormField';
// 解析器选项配置
const PARSER_OPTIONS = [
{ value: DOCUMENT_PARSER_TYPES.Naive, label: 'General', description: '通用解析器' },
{ value: DOCUMENT_PARSER_TYPES.Qa, label: 'Q&A', description: 'Q&A解析器' },
{ value: DOCUMENT_PARSER_TYPES.Resume, label: 'Resume', description: 'Resume解析器' },
{ value: DOCUMENT_PARSER_TYPES.Manual, label: 'Manual', description: 'Manual解析器' },
{ value: DOCUMENT_PARSER_TYPES.Table, label: 'Table', description: 'Table解析器' },
{ value: DOCUMENT_PARSER_TYPES.Paper, label: 'Paper', description: 'Paper解析器' },
{ value: DOCUMENT_PARSER_TYPES.Book, label: 'Book', description: 'Book解析器' },
{ value: DOCUMENT_PARSER_TYPES.Laws, label: 'Laws', description: 'Laws解析器' },
{ value: DOCUMENT_PARSER_TYPES.Presentation, label: 'Presentation', description: 'Presentation解析器' },
{ value: DOCUMENT_PARSER_TYPES.One, label: 'One', description: 'One解析器' },
{ value: DOCUMENT_PARSER_TYPES.Tag, label: 'Tag', description: 'Tag解析器' },
];
export function ChunkMethodItem() {
const { control, formState: { errors } } = useFormContext();
const parserIds = useSelectChunkMethodList();
const parserOptions = parserIds.map((x) => ({
value: x,
label: PARSER_OPTIONS.find((y) => y.value === x)?.label || x,
description: PARSER_OPTIONS.find((y) => y.value === x)?.description || x,
}));
return (
<Box>
<Typography variant="h6" gutterBottom>
</Typography>
<Controller
name="parser_id"
control={control}
render={({ field }) => (
<FormControl fullWidth error={!!errors.parser_id}>
<InputLabel></InputLabel>
<Select
{...field}
label="选择切片方法"
>
{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>
{errors.parser_id && (
<FormHelperText>{errors.parser_id.message as string}</FormHelperText>
)}
</FormControl>
)}
/>
</Box>
);
}
// 基于基础FormField组件的业务组合组件
// 分块token数量配置
export function ChunkTokenNumberItem() {
return (
<SliderInputFormField
name="parser_config.chunk_token_num"
label="建议文本块大小"
min={64}
max={2048}
step={64}
defaultValue={512}
layout="horizontal"
/>
);
}
// 页面排名配置
export function PageRankItem() {
return (
<NumberInputFormField
name="parser_config.page_rank"
label="页面排名"
defaultValue={0}
min={0}
placeholder="输入页面排名"
/>
);
}
// 自动关键词数量配置
export function AutoKeywordsItem() {
return (
<NumberInputFormField
name="parser_config.auto_keywords"
label="自动关键词"
defaultValue={0}
min={0}
placeholder="输入关键词数量"
/>
);
}
// 自动问题数量配置
export function AutoQuestionsItem() {
return (
<NumberInputFormField
name="parser_config.auto_questions"
label="自动问题"
defaultValue={0}
min={0}
placeholder="输入问题数量"
/>
);
}
// 表格转HTML开关
export function HtmlForExcelItem() {
return (
<SwitchFormField
name="parser_config.html4excel"
label="表格转HTML"
defaultValue={false}
/>
);
}
// 标签集选择
export function TagsItem() {
const tagsOptions: SelectOption[] = [
{ value: '', label: '请选择' },
// 这里可以根据实际需求添加标签选项
];
return (
<SelectFormField
name="parser_config.tags"
label="标签集"
options={tagsOptions}
defaultValue=""
displayEmpty
/>
);
}
// RAPTOR策略开关
export function UseRaptorItem() {
return (
<SwitchFormField
name="parser_config.raptor.use_raptor"
label="使用召回增强RAPTOR策略"
defaultValue={false}
/>
);
}
// RAPTOR提示词配置
export function RaptorPromptItem() {
return (
<MultilineTextFormField
name="parser_config.raptor.prompt"
label="提示词"
defaultValue="请总结以下段落。小心数字,不要编造。段落如下:\n{cluster_content}\n以上就是你需要总结的内容。"
rows={4}
/>
);
}
// RAPTOR最大token数配置
export function RaptorMaxTokenItem() {
return (
<SliderInputFormField
name="parser_config.raptor.max_token"
label="最大token数"
min={64}
max={512}
step={32}
defaultValue={256}
layout="horizontal"
/>
);
}
// RAPTOR阈值配置
export function RaptorThresholdItem() {
return (
<SliderInputFormField
name="parser_config.raptor.threshold"
label="阈值"
min={0}
max={1}
step={0.1}
defaultValue={0.1}
layout="horizontal"
/>
);
}
// RAPTOR最大聚类数配置
export function RaptorMaxClusterItem() {
return (
<SliderInputFormField
name="parser_config.raptor.max_cluster"
label="最大聚类数"
min={16}
max={128}
step={16}
defaultValue={64}
layout="horizontal"
/>
);
}
// RAPTOR随机种子配置
export function RaptorRandomSeedItem() {
return (
<NumberInputFormField
name="parser_config.raptor.random_seed"
label="随机种子"
defaultValue={0}
showRandomButton
/>
);
}
// 知识图谱开关
export function UseGraphragItem() {
return (
<SwitchFormField
name="parser_config.graphrag.use_graphrag"
label="提取知识图谱"
defaultValue={false}
/>
);
}
// 实体类型配置
export function EntityTypesItem() {
return (
<ChipListFormField
name="parser_config.graphrag.entity_types"
label="*实体类型"
defaultValue={['organization', 'person', 'geo', 'event', 'category']}
required
allowAdd
allowDelete
maxChips={10}
/>
);
}
// GraphRAG方法选择
export function GraphragMethodItem() {
const methodOptions: SelectOption[] = [
{ value: 'Light', label: 'Light' },
{ value: 'General', label: 'General' },
];
return (
<SelectFormField
name="parser_config.graphrag.method"
label="方法"
options={methodOptions}
defaultValue="Light"
displayEmpty={false}
/>
);
}
// 实体归一化开关
export function EntityNormalizeItem() {
return (
<SwitchFormField
name="parser_config.graphrag.entity_normalize"
label="实体归一化"
defaultValue={false}
/>
);
}
// 社区报告生成开关
export function CommunityReportItem() {
return (
<SwitchFormField
name="parser_config.graphrag.community_report"
label="社区报告生成"
defaultValue={false}
/>
);
}
export function EmbeddingModelItem() {
const { control } = useFormContext();
const { options } = useEmbeddingModelOptions();
return (
<Box>
<Typography variant="subtitle1" sx={{ minWidth: 120 }}>
</Typography>
<Box sx={{ flex: 1 }}>
<Controller
name="embd_id"
control={control}
render={({ field }) => (
<FormControl fullWidth variant="outlined">
<Select
{...field}
>
{options.map((group) => [
<ListSubheader key={group.label}>{group.label}</ListSubheader>,
...group.options.map((option) => (
<MenuItem key={option.value} value={option.value} disabled={option.disabled}>
{option.label}
</MenuItem>
))
])}
</Select>
</FormControl>
)}
/>
</Box>
</Box>
);
}
// PDF解析器配置
export function LayoutRecognizeItem() {
const { control, setValue, formState } = useFormContext();
const { getOptionsByModelType } = useLlmOptionsByModelType();
const options = useMemo(() => {
// 基础选项
const basicOptions = [
{ value: 'DeepDOC', label: 'DeepDOC' },
{ value: 'Plain Text', label: '纯文本' }
];
// 获取图像转文本模型选项
const image2TextOptions = getOptionsByModelType(LLM_MODEL_TYPES.Image2text);
// 将图像转文本模型选项转换为SelectOption格式
const image2TextSelectOptions = image2TextOptions.flatMap(group =>
group.options.map(option => ({
value: option.value,
label: `${option.label} (实验性)`
}))
);
return [...basicOptions, ...image2TextSelectOptions];
}, [getOptionsByModelType]);
return (
<Controller
name="parser_config.layout_recognize"
control={control}
render={({ field }) => {
// 设置默认值
if (typeof field.value === 'undefined') {
const defaultValue = formState.defaultValues?.parser_config?.layout_recognize ?? 'DeepDOC';
setValue('parser_config.layout_recognize', defaultValue);
}
return (
<SelectFormField
name="parser_config.layout_recognize"
label="PDF解析器"
options={options}
defaultValue="DeepDOC"
/>
);
}}
/>
);
}
// 文本分段标识符配置
export function DelimiterItem() {
return (
<TextFormField
name="parser_config.delimiter"
label="分隔符"
placeholder="请输入分隔符"
defaultValue="\n!?。;!?"
/>
);
}

View File

@@ -1,49 +1,16 @@
import React from 'react';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import { ChunkMethodItem, EmbeddingModelItem, PageRankItem, AutoKeywordsItem, AutoQuestionsItem, TagsItem } from './common-items';
export function EmailConfiguration() {
return (
<ConfigurationFormContainer>
<ChunkMethodItem />
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
Raptor配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
GraphRAG配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<PageRankItem />
<AutoKeywordsItem />
<AutoQuestionsItem />
<TagsItem />
</ConfigurationFormContainer>
);
}

View File

@@ -2,7 +2,7 @@
export { NaiveConfiguration } from './naive';
export { QAConfiguration } from './qa';
export { PaperConfiguration } from './paper';
export { ChunkMethodItem, EmbeddingModelItem } from './common-item';
export { ChunkMethodItem, EmbeddingModelItem } from './common-items';
export { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
// 所有解析器配置组件

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { ChunkMethodItem, EmbeddingModelItem } from './common-items';
import { Box, Typography } from '@mui/material';
export function KnowledgeGraphConfiguration() {

View File

@@ -1,61 +1,16 @@
import React from 'react';
import { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem, PageRankItem, AutoKeywordsItem, AutoQuestionsItem, TagsItem } from './common-items';
export function LawsConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<ChunkMethodItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
<PageRankItem />
<AutoKeywordsItem />
<AutoQuestionsItem />
<TagsItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
Raptor配置 -
</Typography>
</Box>
</ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
GraphRAG配置 -
</Typography>
</Box>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@@ -1,59 +1,67 @@
import React from 'react';
import { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import {
ChunkMethodItem,
EmbeddingModelItem,
ChunkTokenNumberItem,
DelimiterItem,
LayoutRecognizeItem,
PageRankItem,
AutoKeywordsItem,
AutoQuestionsItem,
HtmlForExcelItem,
UseRaptorItem,
RaptorPromptItem,
RaptorMaxTokenItem,
RaptorThresholdItem,
RaptorMaxClusterItem,
RaptorRandomSeedItem,
UseGraphragItem,
EntityTypesItem,
GraphragMethodItem,
EntityNormalizeItem,
CommunityReportItem,
TagsItem
} from './common-items';
export function ManualConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<ChunkMethodItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<ChunkTokenNumberItem />
<DelimiterItem />
<LayoutRecognizeItem />
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<PageRankItem />
<AutoKeywordsItem />
<AutoQuestionsItem />
<HtmlForExcelItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
Raptor配置 -
</Typography>
</Box>
<UseRaptorItem />
<RaptorPromptItem />
<RaptorMaxTokenItem />
<RaptorThresholdItem />
<RaptorMaxClusterItem />
<RaptorRandomSeedItem />
</ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
GraphRAG配置 -
</Typography>
</Box>
<ConfigurationFormContainer>
<UseGraphragItem />
<EntityTypesItem />
<GraphragMethodItem />
<EntityNormalizeItem />
<CommunityReportItem />
</ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<ConfigurationFormContainer>
<TagsItem />
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@@ -2,27 +2,39 @@ import React from 'react';
import {
Box,
Typography,
FormControl,
InputLabel,
Select,
MenuItem,
TextField,
FormControlLabel,
Switch,
Slider,
Accordion,
AccordionSummary,
AccordionDetails,
Chip,
IconButton,
} from '@mui/material';
import { ExpandMore as ExpandMoreIcon, Add as AddIcon } from '@mui/icons-material';
import { useFormContext, Controller } from 'react-hook-form';
import { ExpandMore as ExpandMoreIcon } from '@mui/icons-material';
import { useFormContext } from 'react-hook-form';
import { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import {
ChunkMethodItem,
EmbeddingModelItem,
ChunkTokenNumberItem,
PageRankItem,
AutoKeywordsItem,
AutoQuestionsItem,
HtmlForExcelItem,
TagsItem,
UseRaptorItem,
RaptorPromptItem,
RaptorMaxTokenItem,
RaptorThresholdItem,
RaptorMaxClusterItem,
RaptorRandomSeedItem,
UseGraphragItem,
EntityTypesItem,
GraphragMethodItem,
EntityNormalizeItem,
CommunityReportItem,
LayoutRecognizeItem,
DelimiterItem
} from './common-items';
export function NaiveConfiguration() {
const { control, watch, formState: { errors } } = useFormContext();
const { formState: { errors } } = useFormContext();
return (
<ConfigurationFormContainer>
@@ -38,72 +50,16 @@ export function NaiveConfiguration() {
<ChunkMethodItem />
{/* PDF解析器 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
PDF解析器
</Typography>
<Controller
name="parser_config.pdf_parser"
control={control}
render={({ field }) => (
<FormControl fullWidth>
<Select
{...field}
displayEmpty
defaultValue="Naive"
>
<MenuItem value="Naive">Naive</MenuItem>
</Select>
</FormControl>
)}
/>
</Box>
<LayoutRecognizeItem />
{/* 嵌入模型 */}
<EmbeddingModelItem />
{/* 建议文本块大小 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.chunk_token_num"
control={control}
render={({ field }) => (
<Box sx={{ px: 2 }}>
<Slider
{...field}
min={128}
max={2048}
step={64}
valueLabelDisplay="on"
defaultValue={512}
onChange={(_, value) => field.onChange(value)}
/>
</Box>
)}
/>
</Box>
<ChunkTokenNumberItem />
{/* 文本分段标识符 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
*
</Typography>
<Controller
name="parser_config.delimiter"
control={control}
render={({ field }) => (
<TextField
{...field}
fullWidth
placeholder="\\n"
defaultValue="\\n"
/>
)}
/>
</Box>
<DelimiterItem />
</Box>
</AccordionDetails>
</Accordion>
@@ -116,250 +72,47 @@ export function NaiveConfiguration() {
<AccordionDetails>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
{/* 页面排名 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.page_rank"
control={control}
render={({ field }) => (
<TextField
{...field}
type="number"
fullWidth
defaultValue={0}
inputProps={{ min: 0 }}
/>
)}
/>
</Box>
<PageRankItem />
{/* 自动关键词提取 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.auto_keywords"
control={control}
render={({ field }) => (
<TextField
{...field}
type="number"
fullWidth
defaultValue={0}
inputProps={{ min: 0 }}
/>
)}
/>
</Box>
<AutoKeywordsItem />
{/* 自动问题提取 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.auto_questions"
control={control}
render={({ field }) => (
<TextField
{...field}
type="number"
fullWidth
defaultValue={0}
inputProps={{ min: 0 }}
/>
)}
/>
</Box>
<AutoQuestionsItem />
{/* 表格转HTML */}
<Box>
<Controller
name="parser_config.html4excel"
control={control}
render={({ field }) => (
<FormControlLabel
control={
<Switch
checked={field.value || false}
onChange={field.onChange}
/>
}
label="表格转HTML"
/>
)}
/>
</Box>
<HtmlForExcelItem />
{/* 标签集 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.tags"
control={control}
render={({ field }) => (
<FormControl fullWidth>
<Select
{...field}
displayEmpty
defaultValue=""
>
<MenuItem value=""></MenuItem>
</Select>
</FormControl>
)}
/>
</Box>
<TagsItem />
</Box>
</AccordionDetails>
</Accordion>
{/* 第三部分RAPTOR策略 */}
<Accordion defaultExpanded>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">RAPTOR策略</Typography>
</AccordionSummary>
<AccordionDetails>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
{/* 使用召回增强RAPTOR策略 */}
<Box>
<Controller
name="parser_config.raptor.use_raptor"
control={control}
render={({ field }) => (
<FormControlLabel
control={
<Switch
checked={field.value || false}
onChange={field.onChange}
/>
}
label="使用召回增强RAPTOR策略"
/>
)}
/>
</Box>
<UseRaptorItem />
{/* 提示词 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.raptor.prompt"
control={control}
render={({ field }) => (
<TextField
{...field}
multiline
rows={4}
fullWidth
defaultValue="请总结以下段落。小心数字,不要编造。段落如下:\n{cluster_content}\n以上就是你需要总结的内容。"
/>
)}
/>
</Box>
<RaptorPromptItem />
{/* 最大token数 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
token数
</Typography>
<Controller
name="parser_config.raptor.max_token"
control={control}
render={({ field }) => (
<Box sx={{ px: 2 }}>
<Slider
{...field}
min={64}
max={512}
step={32}
valueLabelDisplay="on"
defaultValue={256}
onChange={(_, value) => field.onChange(value)}
/>
</Box>
)}
/>
</Box>
<RaptorMaxTokenItem />
{/* 阈值 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.raptor.threshold"
control={control}
render={({ field }) => (
<Box sx={{ px: 2 }}>
<Slider
{...field}
min={0}
max={1}
step={0.1}
valueLabelDisplay="on"
defaultValue={0.1}
onChange={(_, value) => field.onChange(value)}
/>
</Box>
)}
/>
</Box>
<RaptorThresholdItem />
{/* 最大聚类数 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.raptor.max_cluster"
control={control}
render={({ field }) => (
<Box sx={{ px: 2 }}>
<Slider
{...field}
min={16}
max={128}
step={16}
valueLabelDisplay="on"
defaultValue={64}
onChange={(_, value) => field.onChange(value)}
/>
</Box>
)}
/>
</Box>
<RaptorMaxClusterItem />
{/* 随机种子 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.raptor.random_seed"
control={control}
render={({ field }) => (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<TextField
{...field}
type="number"
defaultValue={0}
sx={{ flex: 1 }}
/>
<IconButton>
<AddIcon />
</IconButton>
</Box>
)}
/>
</Box>
<RaptorRandomSeedItem />
</Box>
</AccordionDetails>
</Accordion>
@@ -372,109 +125,19 @@ export function NaiveConfiguration() {
<AccordionDetails>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
{/* 提取知识图谱 */}
<Box>
<Controller
name="parser_config.graphrag.use_graphrag"
control={control}
render={({ field }) => (
<FormControlLabel
control={
<Switch
checked={field.value || false}
onChange={field.onChange}
/>
}
label="提取知识图谱"
/>
)}
/>
</Box>
<UseGraphragItem />
{/* 实体类型 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
*
</Typography>
<Controller
name="parser_config.graphrag.entity_types"
control={control}
render={({ field }) => (
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1, mb: 2 }}>
{['organization', 'person', 'geo', 'event', 'category'].map((type) => (
<Chip
key={type}
label={type}
onDelete={() => {}}
variant="outlined"
/>
))}
<IconButton size="small">
<AddIcon />
</IconButton>
</Box>
)}
/>
</Box>
<EntityTypesItem />
{/* 方法 */}
<Box>
<Typography variant="subtitle1" gutterBottom>
</Typography>
<Controller
name="parser_config.graphrag.method"
control={control}
render={({ field }) => (
<FormControl fullWidth>
<Select
{...field}
defaultValue="Light"
>
<MenuItem value="Light">Light</MenuItem>
<MenuItem value="General">General</MenuItem>
</Select>
</FormControl>
)}
/>
</Box>
<GraphragMethodItem />
{/* 实体归一化 */}
<Box>
<Controller
name="parser_config.graphrag.entity_normalize"
control={control}
render={({ field }) => (
<FormControlLabel
control={
<Switch
checked={field.value || false}
onChange={field.onChange}
/>
}
label="实体归一化"
/>
)}
/>
</Box>
<EntityNormalizeItem />
{/* 社区报告生成 */}
<Box>
<Controller
name="parser_config.graphrag.community_report"
control={control}
render={({ field }) => (
<FormControlLabel
control={
<Switch
checked={field.value || false}
onChange={field.onChange}
/>
}
label="社区报告生成"
/>
)}
/>
</Box>
<CommunityReportItem />
</Box>
</AccordionDetails>
</Accordion>

View File

@@ -1,48 +1,67 @@
import React from 'react';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
import {
ChunkMethodItem,
EmbeddingModelItem,
ChunkTokenNumberItem,
DelimiterItem,
LayoutRecognizeItem,
PageRankItem,
AutoKeywordsItem,
AutoQuestionsItem,
HtmlForExcelItem,
UseRaptorItem,
RaptorPromptItem,
RaptorMaxTokenItem,
RaptorThresholdItem,
RaptorMaxClusterItem,
RaptorRandomSeedItem,
UseGraphragItem,
EntityTypesItem,
GraphragMethodItem,
EntityNormalizeItem,
CommunityReportItem,
TagsItem
} from './common-items';
export function OneConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<ChunkMethodItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<ChunkTokenNumberItem />
<DelimiterItem />
<LayoutRecognizeItem />
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
GraphRAG配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<PageRankItem />
<AutoKeywordsItem />
<AutoQuestionsItem />
<HtmlForExcelItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<UseRaptorItem />
<RaptorPromptItem />
<RaptorMaxTokenItem />
<RaptorThresholdItem />
<RaptorMaxClusterItem />
<RaptorRandomSeedItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<UseGraphragItem />
<EntityTypesItem />
<GraphragMethodItem />
<EntityNormalizeItem />
<CommunityReportItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<TagsItem />
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@@ -1,121 +1,61 @@
import React from 'react';
import {
Box,
Typography,
FormControl,
InputLabel,
Select,
MenuItem,
TextField,
Slider,
} from '@mui/material';
import { useFormContext, Controller } from 'react-hook-form';
import { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
import {
ChunkMethodItem,
EmbeddingModelItem,
LayoutRecognizeItem,
PageRankItem,
AutoKeywordsItem,
AutoQuestionsItem,
UseRaptorItem,
RaptorPromptItem,
RaptorMaxTokenItem,
RaptorThresholdItem,
RaptorMaxClusterItem,
RaptorRandomSeedItem,
UseGraphragItem,
EntityTypesItem,
GraphragMethodItem,
EntityNormalizeItem,
CommunityReportItem,
TagsItem
} from './common-items';
export function PaperConfiguration() {
const { control } = useFormContext();
return (
<ConfigurationFormContainer>
<MainContainer>
{/* 布局识别 */}
<Box>
<Typography variant="h6" gutterBottom>
</Typography>
<Controller
name="parser_config.layout_recognize"
control={control}
render={({ field }) => (
<FormControl fullWidth>
<InputLabel></InputLabel>
<Select
{...field}
label="布局识别方式"
>
<MenuItem value="DeepDOC">DeepDOC</MenuItem>
<MenuItem value="Plain Text">Plain Text</MenuItem>
</Select>
</FormControl>
)}
/>
</Box>
{/* 自动关键词 */}
<Box>
<Typography variant="h6" gutterBottom>
</Typography>
<Controller
name="parser_config.auto_keywords"
control={control}
render={({ field }) => (
<Box sx={{ px: 2 }}>
<Slider
{...field}
min={0}
max={10}
step={1}
marks
valueLabelDisplay="auto"
onChange={(_, value) => field.onChange(value)}
/>
</Box>
)}
/>
</Box>
{/* 自动问题 */}
<Box>
<Typography variant="h6" gutterBottom>
</Typography>
<Controller
name="parser_config.auto_questions"
control={control}
render={({ field }) => (
<Box sx={{ px: 2 }}>
<Slider
{...field}
min={0}
max={10}
step={1}
marks
valueLabelDisplay="auto"
onChange={(_, value) => field.onChange(value)}
/>
</Box>
)}
/>
</Box>
{/* 标签数量 */}
<Box>
<Typography variant="h6" gutterBottom>
Top N
</Typography>
<Controller
name="parser_config.topn_tags"
control={control}
render={({ field }) => (
<TextField
{...field}
type="number"
fullWidth
label="标签数量"
inputProps={{ min: 1, max: 10 }}
onChange={(e) => field.onChange(parseInt(e.target.value))}
/>
)}
/>
</Box>
<Box>
<Typography variant="body2" color="text.secondary">
</Typography>
</Box>
</MainContainer>
<ConfigurationFormContainer>
<ChunkMethodItem />
<LayoutRecognizeItem />
<EmbeddingModelItem />
<PageRankItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<AutoKeywordsItem />
<AutoQuestionsItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<UseRaptorItem />
<RaptorPromptItem />
<RaptorMaxTokenItem />
<RaptorThresholdItem />
<RaptorMaxClusterItem />
<RaptorRandomSeedItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<UseGraphragItem />
<EntityTypesItem />
<GraphragMethodItem />
<EntityNormalizeItem />
<CommunityReportItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<TagsItem />
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@@ -1,37 +1,16 @@
import React from 'react';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import { ChunkMethodItem, EmbeddingModelItem, PageRankItem, AutoKeywordsItem, AutoQuestionsItem, TagsItem } from './common-items';
export function PictureConfiguration() {
return (
<ConfigurationFormContainer>
<ChunkMethodItem />
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<PageRankItem />
<AutoKeywordsItem />
<AutoQuestionsItem />
<TagsItem />
</ConfigurationFormContainer>
);
}

View File

@@ -1,61 +1,16 @@
import React from 'react';
import { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem, PageRankItem, AutoKeywordsItem, AutoQuestionsItem, TagsItem } from './common-items';
export function PresentationConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<ChunkMethodItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
<PageRankItem />
<AutoKeywordsItem />
<AutoQuestionsItem />
<TagsItem />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
Raptor配置 -
</Typography>
</Box>
</ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
GraphRAG配置 -
</Typography>
</Box>
<ConfigurationFormContainer>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@@ -1,45 +1,14 @@
import React from 'react';
import {
Box,
Typography,
TextField,
} from '@mui/material';
import { useFormContext, Controller } from 'react-hook-form';
import { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem, PageRankItem, TagsItem } from './common-items';
export function QAConfiguration() {
const { control } = useFormContext();
return (
<ConfigurationFormContainer>
<MainContainer>
{/* 标签数量 */}
<Box>
<Typography variant="h6" gutterBottom>
Top N
</Typography>
<Controller
name="parser_config.topn_tags"
control={control}
render={({ field }) => (
<TextField
{...field}
type="number"
fullWidth
label="标签数量"
inputProps={{ min: 1, max: 10 }}
onChange={(e) => field.onChange(parseInt(e.target.value))}
/>
)}
/>
</Box>
<Box>
<Typography variant="body2" color="text.secondary">
Q&A解析器专门用于处理问答格式的文档
</Typography>
</Box>
</MainContainer>
<ChunkMethodItem />
<EmbeddingModelItem />
<PageRankItem />
<TagsItem />
</ConfigurationFormContainer>
);
}

View File

@@ -1,25 +1,16 @@
import React from 'react';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import { ChunkMethodItem, EmbeddingModelItem, PageRankItem, AutoKeywordsItem, AutoQuestionsItem, TagsItem } from './common-items';
export function ResumeConfiguration() {
return (
<ConfigurationFormContainer>
<ChunkMethodItem />
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
-
</Typography>
</Box>
<PageRankItem />
<AutoKeywordsItem />
<AutoQuestionsItem />
<TagsItem />
</ConfigurationFormContainer>
);
}

View File

@@ -1,19 +1,16 @@
import React from 'react';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { Box, Typography } from '@mui/material';
import { ChunkMethodItem, EmbeddingModelItem, PageRankItem, AutoKeywordsItem, AutoQuestionsItem, TagsItem } from './common-items';
export function TableConfiguration() {
return (
<ConfigurationFormContainer>
<ChunkMethodItem />
<EmbeddingModelItem />
<Box sx={{ mb: 2 }}>
<Typography variant="body2" color="text.secondary">
PageRank配置 -
</Typography>
</Box>
<PageRankItem />
<AutoKeywordsItem />
<AutoQuestionsItem />
<TagsItem />
</ConfigurationFormContainer>
);
}

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { ConfigurationFormContainer } from './configuration-form-container';
import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
import { ChunkMethodItem, EmbeddingModelItem } from './common-items';
import { Box, Typography } from '@mui/material';
export function TagConfiguration() {

View File

@@ -71,6 +71,7 @@ function KnowledgeBaseSetting() {
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',

View File

@@ -7,6 +7,7 @@ import Dashboard from '../pages/Dashboard';
import ModelsResources from '../pages/ModelsResources';
import { KnowledgeBaseList, KnowledgeBaseCreate, KnowledgeBaseDetail, KnowledgeBaseSetting, KnowledgeBaseTesting } from '../pages/knowledge';
import MCP from '../pages/MCP';
import FormFieldTest from '../pages/FormFieldTest';
const AppRoutes = () => {
return (
@@ -31,6 +32,7 @@ const AppRoutes = () => {
<Route path="dashboard" element={<Dashboard />} />
<Route path="models-resources" element={<ModelsResources />} />
<Route path="mcp" element={<MCP />} />
<Route path="form-field-test" element={<FormFieldTest />} />
</Route>
{/* 处理未匹配的路由 */}