mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-02 05:47:31 +08:00
Feat: optimize title chunk (#14325)
### What problem does this PR solve? Feat: optimize title chunk 1. Add a new button to enable "Use root chunk as H0 heading", so that the first chunk is carried on to all remaining chunks. 2. Update resume agent template ### Type of change - [x] New Feature (non-breaking change which adds functionality) <img width="700" alt="img_v3_02111_63b04951-b3d7-4001-a08b-539db6d5298g" src="https://github.com/user-attachments/assets/4179ac4d-90e7-4353-9b93-d649a455e634" /> <img width="700" alt="image" src="https://github.com/user-attachments/assets/c0ba0f3c-05aa-4f2c-b418-e808ca1a2641" />
This commit is contained in:
@@ -1513,6 +1513,9 @@ Example: Virtual Hosted Style`,
|
||||
includeHeadingContent: 'Include heading content',
|
||||
includeHeadingContentTip:
|
||||
'When enabled, content directly under a heading is kept as its own chunk. Child chunks keep only the heading path.',
|
||||
rootAsHeading: 'Use root as H0 heading',
|
||||
rootAsHeadingTip:
|
||||
'Treat the root node as a H0 heading when building the hierarchy',
|
||||
hierarchyTip: `Build a heading tree and produce self-contained chunks, each carrying its full ancestor heading path (e.g. Part 1 › Chapter 3 › Section 2 + body text).\n
|
||||
Best for: Documents with independent, structurally significant sections — such as legal statutes, regulations, contracts, and technical specifications — where each chunk must be identifiable by its structural position even without surrounding context.`,
|
||||
groupTip: `Split the document flat at a chosen heading level and automatically merge adjacent small sections to preserve content continuity. No parent-heading path is injected.\n
|
||||
|
||||
@@ -333,6 +333,7 @@ export const initialTitleChunkerValues = {
|
||||
method: 'hierarchy',
|
||||
hierarchy: Hierarchy.H3,
|
||||
include_heading_content: false,
|
||||
root_chunk_as_heading: false,
|
||||
rules: rules,
|
||||
};
|
||||
|
||||
@@ -340,6 +341,7 @@ export const initialGroupValues = {
|
||||
method: 'group',
|
||||
hierarchy: '0',
|
||||
include_heading_content: false,
|
||||
root_chunk_as_heading: false,
|
||||
rules: rules,
|
||||
};
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ function transformApiResponseToForm(
|
||||
method,
|
||||
hierarchy,
|
||||
include_heading_content: Boolean(apiData.include_heading_content),
|
||||
root_chunk_as_heading: Boolean(apiData.root_chunk_as_heading),
|
||||
rules,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import { transformApiResponseToForm, useDynamicHierarchyOptions } from './hook';
|
||||
type FormModeValues = {
|
||||
hierarchy?: string;
|
||||
include_heading_content?: boolean;
|
||||
root_chunk_as_heading?: boolean;
|
||||
rules: Array<{ levels: Array<{ expression: string }> }>;
|
||||
};
|
||||
|
||||
@@ -60,6 +61,7 @@ export const FormSchema = z.object({
|
||||
method: z.enum(['hierarchy', 'group']),
|
||||
hierarchy: z.string().optional(),
|
||||
include_heading_content: z.boolean().optional(),
|
||||
root_chunk_as_heading: z.boolean().optional(),
|
||||
rules: rulesSchema,
|
||||
});
|
||||
|
||||
@@ -221,12 +223,14 @@ const TitleChunkerForm = ({ node }: INextOperatorForm) => {
|
||||
hierarchyModeValues.current = {
|
||||
hierarchy: hierarchyValue,
|
||||
include_heading_content: form.getValues('include_heading_content'),
|
||||
root_chunk_as_heading: form.getValues('root_chunk_as_heading'),
|
||||
rules: rulesValue,
|
||||
};
|
||||
} else if (currentMode === 'group') {
|
||||
groupValues.current = {
|
||||
hierarchy: hierarchyValue,
|
||||
include_heading_content: form.getValues('include_heading_content'),
|
||||
root_chunk_as_heading: form.getValues('root_chunk_as_heading'),
|
||||
rules: rulesValue,
|
||||
};
|
||||
}
|
||||
@@ -239,6 +243,7 @@ const TitleChunkerForm = ({ node }: INextOperatorForm) => {
|
||||
method: 'group',
|
||||
hierarchy: modeValues?.hierarchy ?? '0',
|
||||
include_heading_content: false,
|
||||
root_chunk_as_heading: false,
|
||||
rules: modeValues?.rules || initialGroupValues.rules,
|
||||
});
|
||||
} else {
|
||||
@@ -251,12 +256,14 @@ const TitleChunkerForm = ({ node }: INextOperatorForm) => {
|
||||
hierarchy: modeValues.hierarchy || defaultHierarchy,
|
||||
include_heading_content:
|
||||
modeValues.include_heading_content || false,
|
||||
root_chunk_as_heading: modeValues.root_chunk_as_heading || false,
|
||||
rules: modeValues.rules,
|
||||
});
|
||||
} else {
|
||||
const newModeValues: FormModeValues = {
|
||||
hierarchy: defaultHierarchy,
|
||||
include_heading_content: false,
|
||||
root_chunk_as_heading: false,
|
||||
rules: JSON.parse(JSON.stringify(initialTitleChunkerValues.rules)),
|
||||
};
|
||||
|
||||
@@ -264,6 +271,7 @@ const TitleChunkerForm = ({ node }: INextOperatorForm) => {
|
||||
method: method,
|
||||
hierarchy: defaultHierarchy,
|
||||
include_heading_content: newModeValues.include_heading_content,
|
||||
root_chunk_as_heading: newModeValues.root_chunk_as_heading,
|
||||
rules: newModeValues.rules,
|
||||
});
|
||||
}
|
||||
@@ -323,23 +331,46 @@ const TitleChunkerForm = ({ node }: INextOperatorForm) => {
|
||||
<SelectWithSearch options={hierarchyOptions}></SelectWithSearch>
|
||||
</RAGFlowFormItem>
|
||||
{method === 'hierarchy' && (
|
||||
<RAGFlowFormItem
|
||||
name="include_heading_content"
|
||||
label={t('flow.includeHeadingContent', 'Include heading content')}
|
||||
tooltip={t('flow.includeHeadingContentTip')}
|
||||
horizontal={true}
|
||||
labelClassName="w-full"
|
||||
valueClassName="w-8"
|
||||
>
|
||||
{(field) => (
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={(checked) => {
|
||||
field.onChange?.(checked);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</RAGFlowFormItem>
|
||||
<>
|
||||
<RAGFlowFormItem
|
||||
name="include_heading_content"
|
||||
label={t('flow.includeHeadingContent', 'Include heading content')}
|
||||
tooltip={t('flow.includeHeadingContentTip')}
|
||||
horizontal={true}
|
||||
labelClassName="w-full"
|
||||
valueClassName="w-8"
|
||||
>
|
||||
{(field) => (
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={(checked) => {
|
||||
field.onChange?.(checked);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</RAGFlowFormItem>
|
||||
|
||||
<RAGFlowFormItem
|
||||
name="root_chunk_as_heading"
|
||||
label={t('flow.rootAsHeading', 'Use root as heading')}
|
||||
tooltip={t(
|
||||
'flow.rootAsHeadingTip',
|
||||
'Treat the root node as a H0 heading when building the hierarchy',
|
||||
)}
|
||||
horizontal={true}
|
||||
labelClassName="w-full"
|
||||
valueClassName="w-8"
|
||||
>
|
||||
{(field) => (
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={(checked) => {
|
||||
field.onChange?.(checked);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</RAGFlowFormItem>
|
||||
</>
|
||||
)}
|
||||
{/* {method === 'group' ? (
|
||||
<Card>
|
||||
|
||||
@@ -338,6 +338,7 @@ function transformTitleChunkerParams(params: TitleChunkerFormSchemaType) {
|
||||
method: params.method,
|
||||
hierarchy: Number(params.hierarchy || 0),
|
||||
include_heading_content: Boolean(params.include_heading_content),
|
||||
root_chunk_as_heading: Boolean(params.root_chunk_as_heading),
|
||||
levels,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user