Fix: Added table of contents extraction functionality and optimized form item layout #9869 (#10492)

### What problem does this PR solve?

Fix: Added table of contents extraction functionality and optimized form
item layout #9869

- Added `EnableTocToggle` component to toggle table of contents
extraction on and off
- Added multiple parser configuration components (such as naive, book,
laws, etc.), displaying different parser components based on built-in
slicing methods

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
chanx
2025-10-11 18:45:55 +08:00
committed by GitHub
parent 6a0f448419
commit c21cea2038
35 changed files with 694 additions and 173 deletions

View File

@ -20,6 +20,7 @@ import { IParserConfig } from '@/interfaces/database/document';
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
import {
ChunkMethodItem,
EnableTocToggle,
ParseTypeItem,
} from '@/pages/dataset/dataset-setting/configuration/common-item';
import { zodResolver } from '@hookform/resolvers/zod';
@ -113,6 +114,7 @@ export function ChunkMethodDialog({
auto_keywords: z.coerce.number().optional(),
auto_questions: z.coerce.number().optional(),
html4excel: z.boolean().optional(),
toc_extraction: z.boolean().optional(),
// raptor: z
// .object({
// use_raptor: z.boolean().optional(),
@ -247,7 +249,7 @@ export function ChunkMethodDialog({
}, [parseType, form]);
return (
<Dialog open onOpenChange={hideModal}>
<DialogContent className="max-w-[50vw]">
<DialogContent className="max-w-[50vw] text-text-primary">
<DialogHeader>
<DialogTitle>{t('knowledgeDetails.chunkMethod')}</DialogTitle>
</DialogHeader>
@ -338,6 +340,7 @@ export function ChunkMethodDialog({
show={showAutoKeywords(selectedTag) || showExcelToHtml}
className="space-y-3"
>
<EnableTocToggle />
{showAutoKeywords(selectedTag) && (
<>
<AutoKeywordsFormField></AutoKeywordsFormField>

View File

@ -15,6 +15,7 @@ export function useDefaultParserValues() {
auto_keywords: 0,
auto_questions: 0,
html4excel: false,
toc_extraction: false,
// raptor: {
// use_raptor: false,
// prompt: t('knowledgeConfiguration.promptText'),

View File

@ -1,5 +1,7 @@
import { AgentCategory } from '@/constants/agent';
import { FormLayout } from '@/constants/form';
import { useTranslate } from '@/hooks/common-hooks';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useFetchAgentList } from '@/hooks/use-agent-request';
import { buildSelectOptions } from '@/utils/component-util';
import { ArrowUpRight } from 'lucide-react';
@ -21,18 +23,27 @@ export interface IDataPipelineSelectNode {
}
interface IProps {
toDataPipeline?: () => void;
showToDataPipeline?: boolean;
formFieldName: string;
isMult?: boolean;
setDataList?: (data: IDataPipelineSelectNode[]) => void;
layout?: FormLayout;
}
export function DataFlowSelect(props: IProps) {
const { toDataPipeline, formFieldName, isMult = false, setDataList } = props;
const {
showToDataPipeline,
formFieldName,
isMult = false,
setDataList,
layout = FormLayout.Vertical,
} = props;
const { t } = useTranslate('knowledgeConfiguration');
const form = useFormContext();
const { navigateToAgents } = useNavigatePage();
const toDataPipLine = () => {
toDataPipeline?.();
navigateToAgents();
};
const { data: dataPipelineOptions } = useFetchAgentList({
canvas_category: AgentCategory.DataflowCanvas,
@ -69,15 +80,16 @@ export function DataFlowSelect(props: IProps) {
name={formFieldName}
render={({ field }) => (
<FormItem className=" items-center space-y-0 ">
{layout === FormLayout.Vertical && (
<div className="flex flex-col gap-1">
<div className="flex gap-2 justify-between ">
<FormLabel
tooltip={t('dataFlowTip')}
// tooltip={t('dataFlowTip')}
className="text-sm text-text-primary whitespace-wrap "
>
{t('dataPipeline')}
{t('manualSetup')}
</FormLabel>
{toDataPipeline && (
{showToDataPipeline && (
<div
className="text-sm flex text-text-primary cursor-pointer"
onClick={toDataPipLine}
@ -110,6 +122,50 @@ export function DataFlowSelect(props: IProps) {
</FormControl>
</div>
</div>
)}
{layout === FormLayout.Horizontal && (
<div className="flex gap-1 items-center">
<div className="flex gap-2 justify-between w-1/4">
<FormLabel
// tooltip={t('dataFlowTip')}
className="text-sm text-text-secondary whitespace-wrap "
>
{t('manualSetup')}
</FormLabel>
</div>
<div className="text-muted-foreground w-3/4 flex flex-col items-end">
{showToDataPipeline && (
<div
className="text-sm flex text-text-primary cursor-pointer"
onClick={toDataPipLine}
>
{t('buildItFromScratch')}
<ArrowUpRight size={14} />
</div>
)}
<FormControl>
<>
{!isMult && (
<SelectWithSearch
{...field}
placeholder={t('dataFlowPlaceholder')}
options={options}
/>
)}
{isMult && (
<MultiSelect
{...field}
onValueChange={field.onChange}
placeholder={t('dataFlowPlaceholder')}
options={options}
/>
)}
</>
</FormControl>
</div>
</div>
)}
<div className="flex pt-1">
<FormMessage />
</div>

View File

@ -61,7 +61,7 @@ export function DelimiterFormField() {
<FormLabel
required
tooltip={t('knowledgeDetails.delimiterTip')}
className="text-sm text-muted-foreground whitespace-break-spaces w-1/4"
className="text-sm text-text-secondary whitespace-break-spaces w-1/4"
>
{t('knowledgeDetails.delimiter')}
</FormLabel>

View File

@ -28,7 +28,7 @@ export function ExcelToHtmlFormField() {
<div className="flex items-center gap-1">
<FormLabel
tooltip={t('html4excelTip')}
className="text-sm text-muted-foreground whitespace-break-spaces w-1/4"
className="text-sm text-text-secondary whitespace-break-spaces w-1/4"
>
{t('html4excel')}
</FormLabel>

View File

@ -79,7 +79,7 @@ export function LayoutRecognizeFormField({
>
<FormLabel
tooltip={t('layoutRecognizeTip')}
className={cn('text-sm text-muted-foreground whitespace-wrap', {
className={cn('text-sm text-text-secondary whitespace-wrap', {
['w-1/4']: horizontal,
})}
>

View File

@ -17,7 +17,7 @@ export function MaxTokenNumberFormField({ max = 2048, initialValue }: IProps) {
tooltip={t('chunkTokenNumberTip')}
max={max}
defaultValue={initialValue ?? 0}
layout={FormLayout.Vertical}
layout={FormLayout.Horizontal}
></SliderInputFormField>
);
}

View File

@ -36,7 +36,7 @@ export function SliderInputFormField({
tooltip,
defaultValue,
className,
layout = FormLayout.Vertical,
layout = FormLayout.Horizontal,
}: SliderInputFormFieldProps) {
const form = useFormContext();

View File

@ -1,5 +1,4 @@
import { cn } from '@/lib/utils';
import { Radio as LucideRadio } from 'lucide-react';
import React, { useContext, useState } from 'react';
const RadioGroupContext = React.createContext<{
@ -57,7 +56,7 @@ function Radio({ value, checked, disabled, onChange, children }: RadioProps) {
onClick={handleClick}
>
{isChecked && (
<LucideRadio className="h-3 w-3 fill-primary text-primary" />
<div className="h-3 w-3 fill-primary text-primary bg-text-primary rounded-full" />
)}
</span>
{children && <span className="text-foreground">{children}</span>}

View File

@ -19,7 +19,8 @@ export const useNavigatePage = () => {
const navigateToDataset = useCallback(
(id: string) => () => {
navigate(`${Routes.DatasetBase}${Routes.DataSetOverview}/${id}`);
// navigate(`${Routes.DatasetBase}${Routes.DataSetOverview}/${id}`);
navigate(`${Routes.Dataset}/${id}`);
},
[navigate],
);

View File

@ -126,8 +126,8 @@ export default {
startDate: 'Start Date',
source: 'Source',
fileName: 'File Name',
datasetLogs: 'Dataset Logs',
fileLogs: 'File Logs',
datasetLogs: 'Dataset',
fileLogs: 'File',
overview: 'Overview',
success: 'Success',
failed: 'Failed',
@ -270,6 +270,9 @@ export default {
reRankModelWaring: 'Re-rank model is very time consuming.',
},
knowledgeConfiguration: {
tocExtraction: 'toc toggle',
tocExtractionTip:
" For existing chunks, generate a hierarchical table of contents (one directory per file). During queries, when Directory Enhancement is activated, the system will use a large model to determine which directory items are relevant to the user's question, thereby identifying the relevant chunks.",
deleteGenerateModalContent: `
<p>Deleting the generated <strong class='text-text-primary'>{{type}}</strong> results
will remove all derived entities and relationships from this dataset.

View File

@ -114,8 +114,8 @@ export default {
startDate: '开始时间',
source: '来源',
fileName: '文件名',
datasetLogs: '数据集日志',
fileLogs: '文件日志',
datasetLogs: '数据集',
fileLogs: '文件',
overview: '概览',
success: '成功',
failed: '失败',
@ -255,6 +255,9 @@ export default {
theDocumentBeingParsedCannotBeDeleted: '正在解析的文档不能被删除',
},
knowledgeConfiguration: {
tocExtraction: '目录提取',
tocExtractionTip:
'对于已有的chunk生成层级结构的目录信息每个文件一个目录。在查询时激活`目录增强`后系统会用大模型去判断用户问题和哪些目录项相关从而找到相关的chunk。',
deleteGenerateModalContent: `
<p>删除生成的 <strong class='text-text-primary'>{{type}}</strong> 结果
将从此数据集中移除所有派生实体和关系。

View File

@ -0,0 +1,64 @@
import { useFormContext, useWatch } from 'react-hook-form';
import { DocumentParserType } from '@/constants/knowledge';
import { useMemo } from 'react';
import { AudioConfiguration } from './configuration/audio';
import { BookConfiguration } from './configuration/book';
import { EmailConfiguration } from './configuration/email';
import { KnowledgeGraphConfiguration } from './configuration/knowledge-graph';
import { LawsConfiguration } from './configuration/laws';
import { ManualConfiguration } from './configuration/manual';
import { NaiveConfiguration } from './configuration/naive';
import { OneConfiguration } from './configuration/one';
import { PaperConfiguration } from './configuration/paper';
import { PictureConfiguration } from './configuration/picture';
import { PresentationConfiguration } from './configuration/presentation';
import { QAConfiguration } from './configuration/qa';
import { ResumeConfiguration } from './configuration/resume';
import { TableConfiguration } from './configuration/table';
import { TagConfiguration } from './configuration/tag';
const ConfigurationComponentMap = {
[DocumentParserType.Naive]: NaiveConfiguration,
[DocumentParserType.Qa]: QAConfiguration,
[DocumentParserType.Resume]: ResumeConfiguration,
[DocumentParserType.Manual]: ManualConfiguration,
[DocumentParserType.Table]: TableConfiguration,
[DocumentParserType.Paper]: PaperConfiguration,
[DocumentParserType.Book]: BookConfiguration,
[DocumentParserType.Laws]: LawsConfiguration,
[DocumentParserType.Presentation]: PresentationConfiguration,
[DocumentParserType.Picture]: PictureConfiguration,
[DocumentParserType.One]: OneConfiguration,
[DocumentParserType.Audio]: AudioConfiguration,
[DocumentParserType.Email]: EmailConfiguration,
[DocumentParserType.Tag]: TagConfiguration,
[DocumentParserType.KnowledgeGraph]: KnowledgeGraphConfiguration,
};
function EmptyComponent() {
return <div></div>;
}
export function ChunkMethodForm() {
const form = useFormContext();
const finalParserId: DocumentParserType = useWatch({
control: form.control,
name: 'parser_id',
});
const ConfigurationComponent = useMemo(() => {
return finalParserId
? ConfigurationComponentMap[finalParserId]
: EmptyComponent;
}, [finalParserId]);
return (
<section className="h-full flex flex-col">
<div className="overflow-auto flex-1 min-h-0">
<ConfigurationComponent></ConfigurationComponent>
</div>
</section>
);
}

View File

@ -8,8 +8,9 @@ import {
FormMessage,
} from '@/components/ui/form';
import { MultiSelect } from '@/components/ui/multi-select';
import { FormLayout } from '@/constants/form';
import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks';
import { Flex, Form, InputNumber, Select, Slider, Space } from 'antd';
import { Form, Select, Space } from 'antd';
import DOMPurify from 'dompurify';
import { useFormContext, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@ -44,7 +45,7 @@ export const TagSetItem = () => {
<FormItem className=" items-center space-y-0 ">
<div className="flex items-center">
<FormLabel
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
className="text-sm text-text-secondary whitespace-nowrap w-1/4"
tooltip={
<div
dangerouslySetInnerHTML={{
@ -116,27 +117,9 @@ export const TopNTagsItem = () => {
max={10}
min={1}
defaultValue={3}
layout={FormLayout.Horizontal}
></SliderInputFormField>
);
return (
<Form.Item label={t('knowledgeConfiguration.topnTags')}>
<Flex gap={20} align="center">
<Flex flex={1}>
<Form.Item
name={['parser_config', 'topn_tags']}
noStyle
initialValue={3}
>
<Slider max={10} min={1} style={{ width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item name={['parser_config', 'topn_tags']} noStyle>
<InputNumber max={10} min={1} />
</Form.Item>
</Flex>
</Form.Item>
);
};
export function TagItems() {

View File

@ -0,0 +1,20 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { ConfigurationFormContainer } from '../configuration-form-container';
import { TagItems } from '../components/tag-item';
export function AudioConfiguration() {
return (
<ConfigurationFormContainer>
<>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
</>
<TagItems></TagItems>
</ConfigurationFormContainer>
);
}

View File

@ -0,0 +1,28 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
import { TagItems } from '../components/tag-item';
import {
ConfigurationFormContainer,
MainContainer,
} from '../configuration-form-container';
export function BookConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<LayoutRecognizeFormField></LayoutRecognizeFormField>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<TagItems></TagItems>
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@ -42,7 +42,7 @@ export function ChunkMethodItem(props: IProps) {
'w-1/4 whitespace-pre-wrap': line === 1,
})}
>
{t('dataPipeline')}
{t('builtIn')}
</FormLabel>
<div className={line === 1 ? 'w-3/4 ' : 'w-full'}>
<FormControl>
@ -115,7 +115,7 @@ export function EmbeddingModelItem({ line = 1, isEdit = true }: IProps) {
);
}
export function ParseTypeItem() {
export function ParseTypeItem({ line = 2 }: { line?: number }) {
const { t } = useTranslate('knowledgeConfiguration');
const form = useFormContext();
@ -125,17 +125,26 @@ export function ParseTypeItem() {
name={'parseType'}
render={({ field }) => (
<FormItem className=" items-center space-y-0 ">
<div className="">
<div
className={cn('flex', {
' items-center': line === 1,
'flex-col gap-1': line === 2,
})}
>
<FormLabel
tooltip={t('parseTypeTip')}
className="text-sm whitespace-wrap "
// tooltip={t('parseTypeTip')}
className={cn('text-sm whitespace-wrap ', {
'w-1/4': line === 1,
})}
>
{t('parseType')}
</FormLabel>
<div className="text-muted-foreground">
<div
className={cn('text-muted-foreground', { 'w-3/4': line === 1 })}
>
<FormControl>
<Radio.Group {...field}>
<div className="w-3/4 flex gap-2 justify-between text-muted-foreground">
<div className="w-1/2 flex gap-2 justify-between text-muted-foreground">
<Radio value={1}>{t('builtIn')}</Radio>
<Radio value={2}>{t('manualSetup')}</Radio>
</div>
@ -144,7 +153,7 @@ export function ParseTypeItem() {
</div>
</div>
<div className="flex pt-1">
<div className="w-1/4"></div>
<div className={line === 1 ? 'w-1/4' : ''}></div>
<FormMessage />
</div>
</FormItem>
@ -188,3 +197,39 @@ export function EnableAutoGenerateItem() {
/>
);
}
export function EnableTocToggle() {
const { t } = useTranslate('knowledgeConfiguration');
const form = useFormContext();
return (
<FormField
control={form.control}
name={'parser_config.toc_extraction'}
render={({ field }) => (
<FormItem className=" items-center space-y-0 ">
<div className="flex items-center">
<FormLabel
tooltip={t('tocExtractionTip')}
className="text-sm whitespace-wrap w-1/4"
>
{t('tocExtraction')}
</FormLabel>
<div className="text-muted-foreground w-3/4">
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</div>
</div>
<div className="flex pt-1">
<div className="w-1/4"></div>
<FormMessage />
</div>
</FormItem>
)}
/>
);
}

View File

@ -0,0 +1,18 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { TagItems } from '../components/tag-item';
import { ConfigurationFormContainer } from '../configuration-form-container';
export function EmailConfiguration() {
return (
<ConfigurationFormContainer>
<>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
</>
<TagItems></TagItems>
</ConfigurationFormContainer>
);
}

View File

@ -0,0 +1,15 @@
import { DelimiterFormField } from '@/components/delimiter-form-field';
import { EntityTypesFormField } from '@/components/entity-types-form-field';
import { MaxTokenNumberFormField } from '@/components/max-token-number-from-field';
export function KnowledgeGraphConfiguration() {
return (
<>
<>
<EntityTypesFormField></EntityTypesFormField>
<MaxTokenNumberFormField max={8192 * 2}></MaxTokenNumberFormField>
<DelimiterFormField></DelimiterFormField>
</>
</>
);
}

View File

@ -0,0 +1,29 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
import { TagItems } from '../components/tag-item';
import {
ConfigurationFormContainer,
MainContainer,
} from '../configuration-form-container';
export function LawsConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<LayoutRecognizeFormField></LayoutRecognizeFormField>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<TagItems></TagItems>
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@ -0,0 +1,27 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
import { TagItems } from '../components/tag-item';
import {
ConfigurationFormContainer,
MainContainer,
} from '../configuration-form-container';
export function ManualConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<LayoutRecognizeFormField></LayoutRecognizeFormField>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
</ConfigurationFormContainer>
<TagItems></TagItems>
</MainContainer>
);
}

View File

@ -0,0 +1,33 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { DelimiterFormField } from '@/components/delimiter-form-field';
import { ExcelToHtmlFormField } from '@/components/excel-to-html-form-field';
import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
import { MaxTokenNumberFormField } from '@/components/max-token-number-from-field';
import { TagItems } from '../components/tag-item';
import {
ConfigurationFormContainer,
MainContainer,
} from '../configuration-form-container';
import { EnableTocToggle } from './common-item';
export function NaiveConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<LayoutRecognizeFormField></LayoutRecognizeFormField>
<MaxTokenNumberFormField initialValue={512}></MaxTokenNumberFormField>
<DelimiterFormField></DelimiterFormField>
<EnableTocToggle />
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
<ExcelToHtmlFormField></ExcelToHtmlFormField>
<TagItems></TagItems>
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@ -0,0 +1,21 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
import { TagItems } from '../components/tag-item';
import { ConfigurationFormContainer } from '../configuration-form-container';
export function OneConfiguration() {
return (
<ConfigurationFormContainer>
<LayoutRecognizeFormField></LayoutRecognizeFormField>
<>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
</>
<TagItems></TagItems>
</ConfigurationFormContainer>
);
}

View File

@ -0,0 +1,28 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
import { TagItems } from '../components/tag-item';
import {
ConfigurationFormContainer,
MainContainer,
} from '../configuration-form-container';
export function PaperConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<LayoutRecognizeFormField></LayoutRecognizeFormField>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<TagItems></TagItems>
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@ -0,0 +1,18 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { TagItems } from '../components/tag-item';
import { ConfigurationFormContainer } from '../configuration-form-container';
export function PictureConfiguration() {
return (
<ConfigurationFormContainer>
<>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
</>
<TagItems></TagItems>
</ConfigurationFormContainer>
);
}

View File

@ -0,0 +1,29 @@
import {
AutoKeywordsFormField,
AutoQuestionsFormField,
} from '@/components/auto-keywords-form-field';
import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
import { TagItems } from '../components/tag-item';
import {
ConfigurationFormContainer,
MainContainer,
} from '../configuration-form-container';
export function PresentationConfiguration() {
return (
<MainContainer>
<ConfigurationFormContainer>
<LayoutRecognizeFormField></LayoutRecognizeFormField>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<AutoKeywordsFormField></AutoKeywordsFormField>
<AutoQuestionsFormField></AutoQuestionsFormField>
</ConfigurationFormContainer>
<ConfigurationFormContainer>
<TagItems></TagItems>
</ConfigurationFormContainer>
</MainContainer>
);
}

View File

@ -0,0 +1,10 @@
import { TagItems } from '../components/tag-item';
import { ConfigurationFormContainer } from '../configuration-form-container';
export function QAConfiguration() {
return (
<ConfigurationFormContainer>
<TagItems></TagItems>
</ConfigurationFormContainer>
);
}

View File

@ -0,0 +1,10 @@
import { TagItems } from '../components/tag-item';
import { ConfigurationFormContainer } from '../configuration-form-container';
export function ResumeConfiguration() {
return (
<ConfigurationFormContainer>
<TagItems></TagItems>
</ConfigurationFormContainer>
);
}

View File

@ -0,0 +1,12 @@
import { ConfigurationFormContainer } from '../configuration-form-container';
export function TableConfiguration() {
return (
<ConfigurationFormContainer>
{/* <ChunkMethodItem></ChunkMethodItem>
<EmbeddingModelItem></EmbeddingModelItem>
<PageRankFormField></PageRankFormField> */}
</ConfigurationFormContainer>
);
}

View File

@ -0,0 +1,5 @@
import { ConfigurationFormContainer } from '../configuration-form-container';
export function TagConfiguration() {
return <ConfigurationFormContainer></ConfigurationFormContainer>;
}

View File

@ -1,6 +1,9 @@
import { t } from 'i18next';
import { z } from 'zod';
export const formSchema = z.object({
export const formSchema = z
.object({
parseType: z.number(),
name: z.string().min(1, {
message: 'Username must be at least 2 characters.',
}),
@ -25,6 +28,7 @@ export const formSchema = z.object({
html4excel: z.boolean(),
tag_kb_ids: z.array(z.string()).nullish(),
topn_tags: z.number().optional(),
toc_extraction: z.boolean().optional(),
raptor: z
.object({
use_raptor: z.boolean().optional(),
@ -73,7 +77,16 @@ export const formSchema = z.object({
.optional(),
pagerank: z.number(),
// icon: z.array(z.instanceof(File)),
});
})
.superRefine((data, ctx) => {
if (data.parseType === 2 && !data.pipeline_id) {
ctx.addIssue({
path: ['pipeline_id'],
message: t('common.pleaseSelect'),
code: 'custom',
});
}
});
export const pipelineFormSchema = z.object({
pipeline_id: z.string().optional(),

View File

@ -1,14 +1,18 @@
import { IDataPipelineSelectNode } from '@/components/data-pipeline-select';
import {
DataFlowSelect,
IDataPipelineSelectNode,
} from '@/components/data-pipeline-select';
import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
import { Button } from '@/components/ui/button';
import Divider from '@/components/ui/divider';
import { Form } from '@/components/ui/form';
import { FormLayout } from '@/constants/form';
import { DocumentParserType } from '@/constants/knowledge';
import { PermissionRole } from '@/constants/permission';
import { zodResolver } from '@hookform/resolvers/zod';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useForm, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import { TopTitle } from '../dataset-title';
@ -16,10 +20,10 @@ import {
GenerateType,
IGenerateLogButtonProps,
} from '../dataset/generate-button/generate';
import LinkDataPipeline, {
IDataPipelineNodeProps,
} from './components/link-data-pipeline';
import { ChunkMethodForm } from './chunk-method-form';
import { IDataPipelineNodeProps } from './components/link-data-pipeline';
import { MainContainer } from './configuration-form-container';
import { ChunkMethodItem, ParseTypeItem } from './configuration/common-item';
import { formSchema } from './form-schema';
import { GeneralForm } from './general-form';
import { useFetchKnowledgeConfigurationOnMount } from './hooks';
@ -44,6 +48,7 @@ const enum MethodValue {
export default function DatasetSettings() {
const { t } = useTranslation();
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
@ -58,6 +63,7 @@ export default function DatasetSettings() {
auto_questions: 0,
html4excel: false,
topn_tags: 3,
toc_extraction: false,
raptor: {
use_raptor: true,
max_token: 256,
@ -73,17 +79,17 @@ export default function DatasetSettings() {
},
},
pipeline_id: '',
parseType: 1,
pagerank: 0,
},
});
const knowledgeDetails = useFetchKnowledgeConfigurationOnMount(form);
const [pipelineData, setPipelineData] = useState<IDataPipelineNodeProps>();
const [graphRagGenerateData, setGraphRagGenerateData] =
useState<IGenerateLogButtonProps>();
const [raptorGenerateData, setRaptorGenerateData] =
useState<IGenerateLogButtonProps>();
useEffect(() => {
console.log('🚀 ~ DatasetSettings ~ knowledgeDetails:', knowledgeDetails);
if (knowledgeDetails) {
@ -102,8 +108,10 @@ export default function DatasetSettings() {
finish_at: knowledgeDetails.raptor_task_finish_at,
task_id: knowledgeDetails.raptor_task_id,
} as IGenerateLogButtonProps);
form.setValue('parseType', knowledgeDetails.pipeline_id ? 2 : 1);
form.setValue('pipeline_id', knowledgeDetails.pipeline_id || '');
}
}, [knowledgeDetails]);
}, [knowledgeDetails, form]);
async function onSubmit(data: z.infer<typeof formSchema>) {
try {
@ -137,6 +145,22 @@ export default function DatasetSettings() {
} as IGenerateLogButtonProps);
}
};
const parseType = useWatch({
control: form.control,
name: 'parseType',
defaultValue: knowledgeDetails.pipeline_id ? 2 : 1,
});
const selectedTag = useWatch({
name: 'parser_id',
control: form.control,
});
useEffect(() => {
if (parseType === 1) {
form.setValue('pipeline_id', '');
}
console.log('parseType', parseType);
}, [parseType, form]);
return (
<section className="p-5 h-full flex flex-col">
<TopTitle
@ -167,10 +191,30 @@ export default function DatasetSettings() {
onDelete={() => handleDeletePipelineTask(GenerateType.Raptor)}
></RaptorFormFields>
<Divider />
<LinkDataPipeline
<ParseTypeItem line={1} />
{parseType === 1 && (
<ChunkMethodItem line={1}></ChunkMethodItem>
)}
{parseType === 2 && (
<DataFlowSelect
isMult={false}
showToDataPipeline={true}
formFieldName="pipeline_id"
layout={FormLayout.Horizontal}
/>
)}
<Divider />
{parseType === 1 && (
<ChunkMethodForm
selectedTag={selectedTag as DocumentParserType}
/>
)}
{/* <LinkDataPipeline
data={pipelineData}
handleLinkOrEditSubmit={handleLinkOrEditSubmit}
/>
/> */}
</MainContainer>
</div>
<div className="text-right items-center flex justify-end gap-3 w-[768px]">

View File

@ -62,6 +62,7 @@ export function SavingButton() {
if (beValid) {
form.handleSubmit(async (values) => {
console.log('saveKnowledgeConfiguration: ', values);
delete values['parseType'];
// delete values['avatar'];
await saveKnowledgeConfiguration({
kb_id,

View File

@ -29,11 +29,6 @@ export function SideBar({ refreshCount }: PropType) {
const items = useMemo(() => {
const list = [
{
icon: <DatabaseZap className="size-4" />,
label: t(`knowledgeDetails.overview`),
key: Routes.DataSetOverview,
},
{
icon: <FolderOpen className="size-4" />,
label: t(`knowledgeDetails.subbarFiles`),
@ -44,6 +39,11 @@ export function SideBar({ refreshCount }: PropType) {
label: t(`knowledgeDetails.testing`),
key: Routes.DatasetTesting,
},
{
icon: <DatabaseZap className="size-4" />,
label: t(`knowledgeDetails.overview`),
key: Routes.DataSetOverview,
},
{
icon: <Banknote className="size-4" />,
label: t(`knowledgeDetails.configuration`),

View File

@ -16,6 +16,7 @@ import {
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { FormLayout } from '@/constants/form';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { IModalProps } from '@/interfaces/common';
import { zodResolver } from '@hookform/resolvers/zod';
@ -137,8 +138,9 @@ export function InputForm({ onOk }: IModalProps<any>) {
{parseType === 2 && (
<DataFlowSelect
isMult={false}
toDataPipeline={navigateToAgents}
showToDataPipeline={true}
formFieldName="pipeline_id"
layout={FormLayout.Vertical}
/>
)}
</form>