diff --git a/web/src/components/knowledge-base-item.tsx b/web/src/components/knowledge-base-item.tsx index e01ff6e80..8d595c88d 100644 --- a/web/src/components/knowledge-base-item.tsx +++ b/web/src/components/knowledge-base-item.tsx @@ -1,9 +1,13 @@ import { DocumentParserType } from '@/constants/knowledge'; import { useTranslate } from '@/hooks/common-hooks'; import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks'; +import { useBuildQueryVariableOptions } from '@/pages/agent/hooks/use-get-begin-query'; import { UserOutlined } from '@ant-design/icons'; import { Avatar as AntAvatar, Form, Select, Space } from 'antd'; +import { toLower } from 'lodash'; +import { useMemo } from 'react'; import { useFormContext } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; import { RAGFlowAvatar } from './ragflow-avatar'; import { FormControl, FormField, FormItem, FormLabel } from './ui/form'; import { MultiSelect } from './ui/multi-select'; @@ -66,9 +70,13 @@ const KnowledgeBaseItem = ({ export default KnowledgeBaseItem; -export function KnowledgeBaseFormField() { +export function KnowledgeBaseFormField({ + showVariable = false, +}: { + showVariable?: boolean; +}) { const form = useFormContext(); - const { t } = useTranslate('chat'); + const { t } = useTranslation(); const { list: knowledgeList } = useFetchKnowledgeList(true); @@ -76,6 +84,8 @@ export function KnowledgeBaseFormField() { (x) => x.parser_id !== DocumentParserType.Tag, ); + const nextOptions = useBuildQueryVariableOptions(); + const knowledgeOptions = filteredKnowledgeList.map((x) => ({ label: x.name, value: x.id, @@ -84,18 +94,48 @@ export function KnowledgeBaseFormField() { ), })); + const options = useMemo(() => { + if (showVariable) { + return [ + { + label: t('knowledgeDetails.dataset'), + options: knowledgeOptions, + }, + ...nextOptions.map((x) => { + return { + ...x, + options: x.options + .filter((y) => toLower(y.type).includes('string')) + .map((x) => ({ + ...x, + icon: () => ( + + ), + })), + }; + }), + ]; + } + + return knowledgeOptions; + }, [knowledgeOptions, nextOptions, showVariable, t]); + return ( ( - {t('knowledgeBases')} + {t('chat.knowledgeBases')} ; +}; + +export type MultiSelectGroupOptionType = { + label: React.ReactNode; + options: MultiSelectOptionType[]; +}; + +function MultiCommandItem({ + option, + isSelected, + toggleOption, +}: { + option: MultiSelectOptionType; + isSelected: boolean; + toggleOption(value: string): void; +}) { + return ( + toggleOption(option.value)} + className="cursor-pointer" + > +
+ +
+ {option.icon && ( + + )} + {option.label} +
+ ); +} + /** * Variants for the multi-select component to handle different styles. * Uses class-variance-authority (cva) to define different styles based on "variant" prop. @@ -63,14 +109,7 @@ interface MultiSelectProps * An array of option objects to be displayed in the multi-select component. * Each option object has a label, value, and an optional icon. */ - options: { - /** The text to display for the option. */ - label: string; - /** The unique value associated with the option. */ - value: string; - /** Optional icon component to display alongside the option. */ - icon?: React.ComponentType<{ className?: string }>; - }[]; + options: (MultiSelectGroupOptionType | MultiSelectOptionType)[]; /** * Callback function triggered when the selected values change. @@ -144,6 +183,11 @@ export const MultiSelect = React.forwardRef< const [isPopoverOpen, setIsPopoverOpen] = React.useState(false); const [isAnimating, setIsAnimating] = React.useState(false); + const flatOptions = React.useMemo(() => { + return options.flatMap((option) => + 'options' in option ? option.options : [option], + ); + }, [options]); const handleInputKeyDown = ( event: React.KeyboardEvent, ) => { @@ -181,10 +225,10 @@ export const MultiSelect = React.forwardRef< }; const toggleAll = () => { - if (selectedValues.length === options.length) { + if (selectedValues.length === flatOptions.length) { handleClear(); } else { - const allValues = options.map((option) => option.value); + const allValues = flatOptions.map((option) => option.value); setSelectedValues(allValues); onValueChange(allValues); } @@ -210,7 +254,7 @@ export const MultiSelect = React.forwardRef<
{selectedValues?.slice(0, maxCount)?.map((value) => { - const option = options.find((o) => o.value === value); + const option = flatOptions.find((o) => o.value === value); const IconComponent = option?.icon; return ( (Select All) - {options.map((option) => { - const isSelected = selectedValues.includes(option.value); - return ( - toggleOption(option.value)} - className="cursor-pointer" - > -
- -
- {option.icon && ( - - )} - {option.label} -
- ); - })} + {!options.some((x) => 'options' in x) && + (options as unknown as MultiSelectOptionType[]).map( + (option) => { + const isSelected = selectedValues.includes(option.value); + return ( + + ); + }, + )} + {options.every((x) => 'options' in x) && + options.map((x, idx) => ( + + {x.options.map((option) => { + const isSelected = selectedValues.includes(option.value); + + return ( + + ); + })} + + ))}
diff --git a/web/src/pages/agent/canvas/node/retrieval-node.tsx b/web/src/pages/agent/canvas/node/retrieval-node.tsx index 22a43537e..bd0885d6f 100644 --- a/web/src/pages/agent/canvas/node/retrieval-node.tsx +++ b/web/src/pages/agent/canvas/node/retrieval-node.tsx @@ -2,11 +2,11 @@ import { RAGFlowAvatar } from '@/components/ragflow-avatar'; import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks'; import { IRetrievalNode } from '@/interfaces/database/flow'; import { NodeProps, Position } from '@xyflow/react'; -import { Flex } from 'antd'; import classNames from 'classnames'; import { get } from 'lodash'; import { memo, useMemo } from 'react'; import { NodeHandleId } from '../../constant'; +import { useGetVariableLabelByValue } from '../../hooks/use-get-begin-query'; import { CommonHandle } from './handle'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import styles from './index.less'; @@ -21,6 +21,7 @@ function InnerRetrievalNode({ selected, }: NodeProps) { const knowledgeBaseIds: string[] = get(data, 'form.kb_ids', []); + console.log('🚀 ~ InnerRetrievalNode ~ knowledgeBaseIds:', knowledgeBaseIds); const { list: knowledgeList } = useFetchKnowledgeList(true); const knowledgeBases = useMemo(() => { return knowledgeBaseIds.map((x) => { @@ -33,6 +34,8 @@ function InnerRetrievalNode({ }); }, [knowledgeList, knowledgeBaseIds]); + const getLabel = useGetVariableLabelByValue(id); + return ( @@ -63,25 +66,27 @@ function InnerRetrievalNode({ [styles.nodeHeader]: knowledgeBaseIds.length > 0, })} > - - {knowledgeBases.map((knowledge) => { +
+ {knowledgeBaseIds.map((id) => { + const item = knowledgeList.find((y) => id === y.id); + const label = getLabel(id); + return ( -
- +
+
- - {knowledge.name} - - + +
{label || item?.name}
+
); })} -
+
); diff --git a/web/src/pages/agent/form/retrieval-form/next.tsx b/web/src/pages/agent/form/retrieval-form/next.tsx index 3f28d3f74..876547df5 100644 --- a/web/src/pages/agent/form/retrieval-form/next.tsx +++ b/web/src/pages/agent/form/retrieval-form/next.tsx @@ -97,7 +97,7 @@ function RetrievalForm({ node }: INextOperatorForm) { - + Advanced Settings
}> diff --git a/web/src/pages/agent/form/tool-form/retrieval-form/index.tsx b/web/src/pages/agent/form/tool-form/retrieval-form/index.tsx index b07490a4c..326e8a136 100644 --- a/web/src/pages/agent/form/tool-form/retrieval-form/index.tsx +++ b/web/src/pages/agent/form/tool-form/retrieval-form/index.tsx @@ -43,7 +43,7 @@ const RetrievalForm = () => { > - + Advanced Settings
}> diff --git a/web/src/pages/next-chats/share/index.tsx b/web/src/pages/next-chats/share/index.tsx index a15491990..29c5a4f09 100644 --- a/web/src/pages/next-chats/share/index.tsx +++ b/web/src/pages/next-chats/share/index.tsx @@ -175,7 +175,7 @@ const ChatContainer = () => { ); })}
-
+