Fix: The Context Generator(Transformer) node can only be followed by a Tokenizer(Indexer) and a Context Generator(Transformer). #9869 (#10515)

### What problem does this PR solve?

Fix: The Context Generator node can only be followed by a Tokenizer and
a Context Generator. #9869
### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-10-13 14:37:30 +08:00
committed by GitHub
parent 24481f0332
commit 9c53b3336a
7 changed files with 34 additions and 13 deletions

View File

@ -98,7 +98,7 @@ export function FileUploadDialog({
return (
<Dialog open onOpenChange={hideModal}>
<DialogContent className="sm:max-w-[425px]">
<DialogContent>
<DialogHeader>
<DialogTitle>{t('fileManager.uploadFile')}</DialogTitle>
</DialogHeader>

View File

@ -1703,8 +1703,8 @@ This delimiter is used to split the input text into several text pieces echo of
parser: 'Parser',
parserDescription:
'Extracts raw text and structure from files for downstream processing.',
tokenizer: 'Tokenizer',
tokenizerRequired: 'Please add the Tokenizer node first',
tokenizer: 'Indexer',
tokenizerRequired: 'Please add the Indexer node first',
tokenizerDescription:
'Transforms text into the required data structure (e.g., vector embeddings for Embedding Search) depending on the chosen search method.',
splitter: 'Token Splitter',
@ -1713,7 +1713,7 @@ This delimiter is used to split the input text into several text pieces echo of
hierarchicalMergerDescription:
'Split documents into sections by title hierarchy with regex rules for finer control.',
hierarchicalMerger: 'Title Splitter',
extractor: 'Context Generator',
extractor: 'Transformer',
extractorDescription:
'Use an LLM to extract structured insights from document chunks—such as summaries, classifications, etc.',
outputFormat: 'Output format',

View File

@ -292,6 +292,7 @@ function DataFlowCanvas({ drawerVisible, hideDrawer, showLogSheet }: IProps) {
clearActiveDropdown();
}}
position={dropdownPosition}
nodeId={connectionStartRef.current?.nodeId || ''}
>
<span></span>
</NextStepDropdown>

View File

@ -131,16 +131,24 @@ function useRestrictSingleOperatorOnCanvas() {
function AccordionOperators({
isCustomDropdown = false,
mousePosition,
nodeId,
}: {
isCustomDropdown?: boolean;
mousePosition?: { x: number; y: number };
nodeId?: string;
}) {
const singleOperators = useRestrictSingleOperatorOnCanvas();
const { getOperatorTypeFromId } = useGraphStore((state) => state);
const operators = useMemo(() => {
const list = [...singleOperators];
let list = [...singleOperators];
if (getOperatorTypeFromId(nodeId) === Operator.Extractor) {
const Splitters = [Operator.HierarchicalMerger, Operator.Splitter];
list = list.filter((x) => !Splitters.includes(x)); // The Context Generator node can only be followed by a Tokenizer and a Context Generator.
}
list.push(Operator.Extractor);
return list;
}, [singleOperators]);
}, [getOperatorTypeFromId, nodeId, singleOperators]);
return (
<OperatorItemList
@ -151,16 +159,19 @@ function AccordionOperators({
);
}
type NextStepDropdownProps = PropsWithChildren &
IModalProps<any> & {
position?: { x: number; y: number };
onNodeCreated?: (newNodeId: string) => void;
nodeId?: string;
};
export function InnerNextStepDropdown({
children,
hideModal,
position,
onNodeCreated,
}: PropsWithChildren &
IModalProps<any> & {
position?: { x: number; y: number };
onNodeCreated?: (newNodeId: string) => void;
}) {
nodeId,
}: NextStepDropdownProps) {
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
@ -200,6 +211,7 @@ export function InnerNextStepDropdown({
<AccordionOperators
isCustomDropdown={true}
mousePosition={position}
nodeId={nodeId}
></AccordionOperators>
</OnNodeCreatedContext.Provider>
</HideModalContext.Provider>
@ -224,7 +236,7 @@ export function InnerNextStepDropdown({
>
<DropdownMenuLabel>{t('flow.nextStep')}</DropdownMenuLabel>
<HideModalContext.Provider value={hideModal}>
<AccordionOperators></AccordionOperators>
<AccordionOperators nodeId={nodeId}></AccordionOperators>
</HideModalContext.Provider>
</DropdownMenuContent>
</DropdownMenu>

View File

@ -61,6 +61,7 @@ export function CommonHandle({
hideModal();
clearActiveDropdown();
}}
nodeId={nodeId}
>
<span></span>
</NextStepDropdown>

View File

@ -299,7 +299,9 @@ export const initialHierarchicalMergerValues = {
export const initialExtractorValues = {
...initialLlmBaseValues,
field_name: ContextGeneratorFieldName.Summary,
outputs: {},
outputs: {
chunks: { type: 'Array<Object>', value: [] },
},
};
export const CategorizeAnchorPointPositions = [

View File

@ -19,7 +19,9 @@ import { useBuildNodeOutputOptions } from '../../hooks/use-build-options';
import { useFormValues } from '../../hooks/use-form-values';
import { useWatchFormChange } from '../../hooks/use-watch-form-change';
import { INextOperatorForm } from '../../interface';
import { buildOutputList } from '../../utils/build-output-list';
import { FormWrapper } from '../components/form-wrapper';
import { Output } from '../components/output';
import { useSwitchPrompt } from './use-switch-prompt';
export const FormSchema = z.object({
@ -31,6 +33,8 @@ export const FormSchema = z.object({
export type ExtractorFormSchemaType = z.infer<typeof FormSchema>;
const outputList = buildOutputList(initialExtractorValues.outputs);
const ExtractorForm = ({ node }: INextOperatorForm) => {
const defaultValues = useFormValues(initialExtractorValues, node);
const { t } = useTranslation();
@ -85,6 +89,7 @@ const ExtractorForm = ({ node }: INextOperatorForm) => {
baseOptions={promptOptions}
></PromptEditor>
</RAGFlowFormItem>
<Output list={outputList}></Output>
</FormWrapper>
{visible && (
<ConfirmDeleteDialog