feat(knowledge): add pipeline support and build mode selection
refactor(configuration): reorganize naive config form with pipeline selector feat(form): add RadioFormField component for build mode selection docs: add ahooks usage guide for common patterns style: update app title and favicon chore: clean up unused agent interfaces
This commit is contained in:
@@ -5,6 +5,7 @@ import AppRoutes from './routes';
|
||||
import SnackbarProvider from './components/Provider/SnackbarProvider';
|
||||
import DialogProvider from './components/Provider/DialogProvider';
|
||||
import AuthGuard from './components/AuthGuard';
|
||||
import { useTitle } from 'ahooks';
|
||||
|
||||
import './locales';
|
||||
import './utils/request'
|
||||
@@ -40,6 +41,8 @@ function MaterialUIApp() {
|
||||
}
|
||||
|
||||
function App() {
|
||||
useTitle('RAG Empowerment System');
|
||||
|
||||
return (
|
||||
<MaterialUIApp />
|
||||
);
|
||||
|
||||
97
src/components/FormField/RadioFormField.tsx
Normal file
97
src/components/FormField/RadioFormField.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
RadioGroup,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
FormHelperText,
|
||||
} from '@mui/material';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export interface RadioOption {
|
||||
value: string | number;
|
||||
label: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export interface RadioFormFieldProps {
|
||||
name: string;
|
||||
label?: string;
|
||||
options: RadioOption[];
|
||||
helperText?: string;
|
||||
defaultValue?: string | number;
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
row?: boolean;
|
||||
size?: 'small' | 'medium';
|
||||
onChangeValue?: (value: string | number) => void;
|
||||
}
|
||||
|
||||
export const RadioFormField: React.FC<RadioFormFieldProps> = ({
|
||||
name,
|
||||
label,
|
||||
options,
|
||||
helperText,
|
||||
defaultValue = '',
|
||||
disabled = false,
|
||||
required = false,
|
||||
row = true,
|
||||
size = 'medium',
|
||||
onChangeValue,
|
||||
}) => {
|
||||
const { control } = useFormContext();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
{required && <span style={{ color: 'red' }}>*</span>}
|
||||
{label}
|
||||
</Typography>
|
||||
<Controller
|
||||
name={name}
|
||||
control={control}
|
||||
defaultValue={defaultValue}
|
||||
rules={{
|
||||
required: required ? 'This field is required' : false,
|
||||
}}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl component="fieldset" error={!!error}>
|
||||
{label && <FormLabel component="legend" sx={{ display: 'none' }}>
|
||||
{label}
|
||||
</FormLabel>}
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name={name}
|
||||
row={row}
|
||||
onChange={(_, value) => {
|
||||
field.onChange(value);
|
||||
onChangeValue?.(value);
|
||||
}}
|
||||
>
|
||||
{options.map((item) => (
|
||||
<FormControlLabel
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
control={<Radio size={size} disabled={disabled || item.disabled} />}
|
||||
label={item.label}
|
||||
/>
|
||||
))}
|
||||
</RadioGroup>
|
||||
{(error || helperText) && (
|
||||
<FormHelperText>
|
||||
{error?.message || helperText}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default RadioFormField;
|
||||
@@ -9,6 +9,7 @@ export { SliderFormField } from './SliderFormField';
|
||||
export { TextFormField } from './TextFormField';
|
||||
export { DatePickerFormField } from './DatePickerFormField';
|
||||
export { CheckboxFormField } from './CheckboxFormField';
|
||||
export { RadioFormField } from './RadioFormField';
|
||||
|
||||
// 类型导出
|
||||
export type { SliderInputFormFieldProps } from './SliderInputFormField';
|
||||
|
||||
@@ -44,7 +44,13 @@ export const useAgentList = (initialParams?: IAgentPaginationParams) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const response = await agentService.listCanvas(params);
|
||||
const envMode = import.meta.env.MODE;
|
||||
let response: any = null;
|
||||
if (envMode === 'flask') {
|
||||
response = await agentService.teamlistCanvas(params);
|
||||
} else {
|
||||
response = await agentService.listCanvas(params);
|
||||
}
|
||||
const res = response.data || {};
|
||||
logger.info('useAgentList fetchAgentList', res);
|
||||
const data = res.data
|
||||
|
||||
@@ -268,25 +268,6 @@ export interface IAgentLogMessage {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface IPipeLineListRequest {
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
keywords?: string;
|
||||
orderby?: string;
|
||||
desc?: boolean;
|
||||
// canvas_category?: AgentCategory;
|
||||
}
|
||||
|
||||
// {
|
||||
// "create_date": "Thu, 06 Nov 2025 15:52:42 GMT",
|
||||
// "create_time": 1762415562692,
|
||||
// "id": "931d1cfabae511f097ca36b0b158b556",
|
||||
// "title": "blank_2025_11_06_15_52_42",
|
||||
// "update_date": "Thu, 06 Nov 2025 15:52:42 GMT",
|
||||
// "update_time": 1762415562692,
|
||||
// "user_canvas_id": "1edc3ddabadb11f08d0636b0b158b556"
|
||||
// }
|
||||
|
||||
export interface IAgentVersionItem {
|
||||
id: string;
|
||||
title: string;
|
||||
|
||||
@@ -102,11 +102,11 @@ export interface IKnowledge {
|
||||
/** 解析器ID */
|
||||
parser_id: string;
|
||||
/** 管道ID */
|
||||
pipeline_id: string;
|
||||
pipeline_id?: string;
|
||||
/** 管道名称 */
|
||||
pipeline_name: string;
|
||||
pipeline_name?: string;
|
||||
/** 管道头像 */
|
||||
pipeline_avatar: string;
|
||||
pipeline_avatar?: string;
|
||||
/** 权限设置 */
|
||||
permission: string;
|
||||
/** 相似度阈值 */
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { AgentCategory } from "../../constants/agent";
|
||||
import { DSL } from "../database/agent";
|
||||
|
||||
/**
|
||||
@@ -7,6 +8,9 @@ export interface IAgentPaginationParams {
|
||||
keywords?: string;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
orderby?: string;
|
||||
desc?: boolean;
|
||||
canvas_category?: AgentCategory;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -644,6 +644,7 @@ export default {
|
||||
eidtLinkDataPipeline: 'Edit Data Pipeline',
|
||||
linkPipelineSetTip: 'Manage data pipeline linkage with this dataset',
|
||||
default: 'Default',
|
||||
buildMode: 'Build Mode',
|
||||
dataPipeline: 'Data Pipeline',
|
||||
linkDataPipeline: 'Link Data Pipeline',
|
||||
enableAutoGenerate: 'Enable Auto Generate',
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface AgentTopbarProps {
|
||||
onOpenSettings?: () => void;
|
||||
}
|
||||
|
||||
export default function AgentTopbar({ title, id, onRefresh, subtitle, actionsRight, onOpenVersions, onOpenSettings }: AgentTopbarProps) {
|
||||
export default function AgentTopbar({ title, onRefresh, subtitle, actionsRight, onOpenVersions, onOpenSettings }: AgentTopbarProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box sx={{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useMemo, useEffect, useState } from 'react';
|
||||
import {
|
||||
FormControl,
|
||||
InputLabel,
|
||||
@@ -15,6 +15,7 @@ import { useFormContext, Controller } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { t as translate } from 'i18next';
|
||||
import { DOCUMENT_PARSER_TYPES, LLM_MODEL_TYPES, type LlmModelType } from '@/constants/knowledge';
|
||||
import { AgentCategory } from '@/constants/agent';
|
||||
import { useSelectChunkMethodList } from '../hooks';
|
||||
import { useEmbeddingModelOptions, useLlmOptionsByModelType } from '@/hooks/llm-hooks';
|
||||
import {
|
||||
@@ -27,6 +28,7 @@ import {
|
||||
TextFormField,
|
||||
type SelectOption,
|
||||
} from '@/components/FormField';
|
||||
import agentService from '@/services/agent_service';
|
||||
import { LlmSvgIcon } from '@/components/AppSvgIcon';
|
||||
import {type LLMFactory } from '@/constants/llm';
|
||||
import { getFactoryIconName } from '@/utils/common';
|
||||
@@ -153,7 +155,6 @@ export function ChunkMethodItem() {
|
||||
export function TagsItem() {
|
||||
const { t } = useTranslation();
|
||||
const tagsOptions: SelectOption[] = [
|
||||
{ value: '', label: t('common.pleaseSelect') },
|
||||
// 这里可以根据实际需求添加标签选项
|
||||
];
|
||||
|
||||
@@ -162,8 +163,7 @@ export function TagsItem() {
|
||||
name="parser_config.tags"
|
||||
label={t('knowledge.config.tags')}
|
||||
options={tagsOptions}
|
||||
defaultValue=""
|
||||
displayEmpty
|
||||
displayEmpty={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -341,6 +341,42 @@ export function TOCEnhanceItem() {
|
||||
);
|
||||
}
|
||||
|
||||
// Pipeline 选择器
|
||||
export function PipelineSelectorItem() {
|
||||
const { t } = useTranslation();
|
||||
const [options, setOptions] = useState<SelectOption[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchPipelines = async () => {
|
||||
try {
|
||||
const envMode = import.meta.env.MODE;
|
||||
const service = envMode === 'flask' ? agentService.teamlistCanvas : agentService.listCanvas;
|
||||
const res = await service({ canvas_category: AgentCategory.DataflowCanvas, page_size: 100 });
|
||||
const data = res?.data?.data || {};
|
||||
const list = data.canvas || [];
|
||||
const mapped: SelectOption[] = list.map((item: any) => ({
|
||||
value: item.id,
|
||||
label: item.title || item.name || item.id,
|
||||
disabled: false,
|
||||
}));
|
||||
setOptions(mapped);
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch pipelines:', err);
|
||||
}
|
||||
};
|
||||
fetchPipelines();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SelectFormField
|
||||
name="pipeline_id"
|
||||
label={t('knowledgeConfiguration.dataFlow')}
|
||||
options={options}
|
||||
displayEmpty={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* 第二部分:RAPTOR策略 (RAPTOR Strategy)
|
||||
* ============================================================================ */
|
||||
@@ -510,7 +546,33 @@ export function CommunityReportItem() {
|
||||
* 组合配置组件 (Composite Configuration Components)
|
||||
* ============================================================================ */
|
||||
|
||||
// RAPTOR策略配置项组合
|
||||
/*
|
||||
* 基础配置项 (Basic Configuration Items)
|
||||
*/
|
||||
export function BasicConfigItems() {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
||||
{/* PDF解析器 */}
|
||||
<LayoutRecognizeItem />
|
||||
{/* 建议文本块大小 */}
|
||||
<ChunkTokenNumberItem />
|
||||
{/* 文本分段标识符 */}
|
||||
<DelimiterItem />
|
||||
{/* 目录增强 */}
|
||||
<TOCEnhanceItem />
|
||||
{/* 自动关键词提取 */}
|
||||
<AutoKeywordsItem />
|
||||
{/* 自动问题提取 */}
|
||||
<AutoQuestionsItem />
|
||||
{/* 表格转HTML */}
|
||||
<HtmlForExcelItem />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* RAPTOR策略配置项组合
|
||||
*/
|
||||
export function RaptorConfigItems() {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
||||
@@ -530,7 +592,9 @@ export function RaptorConfigItems() {
|
||||
);
|
||||
}
|
||||
|
||||
// 知识图谱配置项组合
|
||||
/**
|
||||
* 知识图谱配置项组合
|
||||
*/
|
||||
export function KnowledgeGraphConfigItems() {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
@@ -13,20 +13,23 @@ import { useTranslation } from 'react-i18next';
|
||||
import { ConfigurationFormContainer, MainContainer } from './configuration-form-container';
|
||||
import {
|
||||
ChunkMethodItem,
|
||||
ChunkTokenNumberItem,
|
||||
AutoKeywordsItem,
|
||||
AutoQuestionsItem,
|
||||
HtmlForExcelItem,
|
||||
LayoutRecognizeItem,
|
||||
DelimiterItem,
|
||||
TOCEnhanceItem,
|
||||
RaptorConfigItems,
|
||||
KnowledgeGraphConfigItems
|
||||
KnowledgeGraphConfigItems,
|
||||
PipelineSelectorItem,
|
||||
BasicConfigItems,
|
||||
} from './common-items';
|
||||
import { RadioFormField } from '@/components/FormField';
|
||||
|
||||
export function NaiveConfiguration() {
|
||||
const { formState: { errors } } = useFormContext();
|
||||
const { formState: { errors }, watch } = useFormContext();
|
||||
const { t } = useTranslation();
|
||||
const [buildMode, setBuildMode] = useState<'buildIn' | 'pipeline'>('buildIn');
|
||||
|
||||
// 根据表单的 pipeline_id 自动切换 buildMode
|
||||
const pipelineId = watch('pipeline_id');
|
||||
useEffect(() => {
|
||||
setBuildMode(pipelineId ? 'pipeline' : 'buildIn');
|
||||
}, [pipelineId]);
|
||||
|
||||
return (
|
||||
<ConfigurationFormContainer>
|
||||
@@ -38,26 +41,27 @@ export function NaiveConfiguration() {
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
{/* 切片方法 */}
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<ChunkMethodItem />
|
||||
<Box sx={{ mb: 3, display: 'flex', flexDirection: 'column', gap: 3 }}>
|
||||
<RadioFormField
|
||||
name="build_mode"
|
||||
defaultValue="buildIn"
|
||||
options={[
|
||||
{ value: 'buildIn', label: 'Built-in' },
|
||||
{ value: 'pipeline', label: 'Pipeline' },
|
||||
]}
|
||||
onChangeValue={(v) => setBuildMode(String(v) as 'buildIn' | 'pipeline')}
|
||||
/>
|
||||
{buildMode === 'buildIn' ? (
|
||||
<ChunkMethodItem />
|
||||
) : (
|
||||
<PipelineSelectorItem />
|
||||
)}
|
||||
</Box>
|
||||
<Divider />
|
||||
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3, mt: 3 }}>
|
||||
{/* PDF解析器 */}
|
||||
<LayoutRecognizeItem />
|
||||
{/* 建议文本块大小 */}
|
||||
<ChunkTokenNumberItem />
|
||||
{/* 文本分段标识符 */}
|
||||
<DelimiterItem />
|
||||
{/* 目录增强 */}
|
||||
<TOCEnhanceItem />
|
||||
{/* 自动关键词提取 */}
|
||||
<AutoKeywordsItem />
|
||||
{/* 自动问题提取 */}
|
||||
<AutoQuestionsItem />
|
||||
{/* 表格转HTML */}
|
||||
<HtmlForExcelItem />
|
||||
<Box sx={{ mt: 3 }}>
|
||||
{buildMode === 'buildIn' && (
|
||||
<BasicConfigItems />
|
||||
)}
|
||||
</Box>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
@@ -136,6 +136,7 @@ function KnowledgeBaseSetting() {
|
||||
parser_id: data.parser_id,
|
||||
embd_id: data.embd_id,
|
||||
parser_config: data.parser_config,
|
||||
pipeline_id: data.pipeline_id,
|
||||
};
|
||||
|
||||
await updateKnowledgeModelConfig(configData);
|
||||
|
||||
@@ -13,6 +13,12 @@ const agentService = {
|
||||
* 获取团队下的Canvas列表
|
||||
*/
|
||||
listCanvas: (params?: IAgentPaginationParams) => {
|
||||
return request.get(api.listCanvas, { params });
|
||||
},
|
||||
/**
|
||||
* 获取团队下的Canvas列表
|
||||
*/
|
||||
teamlistCanvas: (params?: IAgentPaginationParams) => {
|
||||
return request.get(api.listTeamCanvas, { params });
|
||||
},
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user