浏览代码

Feat: New Agent startup parameters add knowledge base parameter #9194 (#9210)

### What problem does this PR solve?

Feat: New Agent startup parameters add knowledge base parameter #9194

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
tags/v0.20.1
balibabu 2 个月前
父节点
当前提交
26b85a10d1
没有帐户链接到提交者的电子邮件

+ 45
- 5
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: () => (
<RAGFlowAvatar
className="size-4 mr-2"
avatar={x.label}
name={x.label}
/>
),
})),
};
}),
];
}

return knowledgeOptions;
}, [knowledgeOptions, nextOptions, showVariable, t]);

return (
<FormField
control={form.control}
name="kb_ids"
render={({ field }) => (
<FormItem>
<FormLabel>{t('knowledgeBases')}</FormLabel>
<FormLabel>{t('chat.knowledgeBases')}</FormLabel>
<FormControl>
<MultiSelect
options={knowledgeOptions}
options={options}
onValueChange={field.onChange}
placeholder={t('knowledgeBasesMessage')}
placeholder={t('chat.knowledgeBasesMessage')}
variant="inverted"
maxCount={100}
defaultValue={field.value}

+ 87
- 37
web/src/components/ui/multi-select.tsx 查看文件

@@ -1,3 +1,4 @@
// https://github.com/sersavan/shadcn-multi-select-component
// src/components/multi-select.tsx

import { cva, type VariantProps } from 'class-variance-authority';
@@ -29,6 +30,51 @@ import {
import { Separator } from '@/components/ui/separator';
import { cn } from '@/lib/utils';

export type MultiSelectOptionType = {
label: React.ReactNode;
value: string;
disabled?: boolean;
icon?: React.ComponentType<{ className?: string }>;
};

export type MultiSelectGroupOptionType = {
label: React.ReactNode;
options: MultiSelectOptionType[];
};

function MultiCommandItem({
option,
isSelected,
toggleOption,
}: {
option: MultiSelectOptionType;
isSelected: boolean;
toggleOption(value: string): void;
}) {
return (
<CommandItem
key={option.value}
onSelect={() => toggleOption(option.value)}
className="cursor-pointer"
>
<div
className={cn(
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary',
isSelected
? 'bg-primary text-primary-foreground'
: 'opacity-50 [&_svg]:invisible',
)}
>
<CheckIcon className="h-4 w-4" />
</div>
{option.icon && (
<option.icon className="mr-2 h-4 w-4 text-muted-foreground" />
)}
<span>{option.label}</span>
</CommandItem>
);
}

/**
* 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<HTMLInputElement>,
) => {
@@ -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<
<div className="flex justify-between items-center w-full">
<div className="flex flex-wrap items-center">
{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 (
<Badge
@@ -304,7 +348,7 @@ export const MultiSelect = React.forwardRef<
<div
className={cn(
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary',
selectedValues.length === options.length
selectedValues.length === flatOptions.length
? 'bg-primary text-primary-foreground'
: 'opacity-50 [&_svg]:invisible',
)}
@@ -313,32 +357,38 @@ export const MultiSelect = React.forwardRef<
</div>
<span>(Select All)</span>
</CommandItem>
{options.map((option) => {
const isSelected = selectedValues.includes(option.value);
return (
<CommandItem
key={option.value}
onSelect={() => toggleOption(option.value)}
className="cursor-pointer"
>
<div
className={cn(
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary',
isSelected
? 'bg-primary text-primary-foreground'
: 'opacity-50 [&_svg]:invisible',
)}
>
<CheckIcon className="h-4 w-4" />
</div>
{option.icon && (
<option.icon className="mr-2 h-4 w-4 text-muted-foreground" />
)}
<span>{option.label}</span>
</CommandItem>
);
})}
{!options.some((x) => 'options' in x) &&
(options as unknown as MultiSelectOptionType[]).map(
(option) => {
const isSelected = selectedValues.includes(option.value);
return (
<MultiCommandItem
option={option}
key={option.value}
isSelected={isSelected}
toggleOption={toggleOption}
></MultiCommandItem>
);
},
)}
</CommandGroup>
{options.every((x) => 'options' in x) &&
options.map((x, idx) => (
<CommandGroup heading={x.label} key={idx}>
{x.options.map((option) => {
const isSelected = selectedValues.includes(option.value);

return (
<MultiCommandItem
option={option}
key={option.value}
isSelected={isSelected}
toggleOption={toggleOption}
></MultiCommandItem>
);
})}
</CommandGroup>
))}
<CommandSeparator />
<CommandGroup>
<div className="flex items-center justify-between">

+ 17
- 12
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<IRetrievalNode>) {
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 (
<ToolBar selected={selected} id={id} label={data.label}>
<NodeWrapper selected={selected}>
@@ -63,25 +66,27 @@ function InnerRetrievalNode({
[styles.nodeHeader]: knowledgeBaseIds.length > 0,
})}
></NodeHeader>
<Flex vertical gap={8}>
{knowledgeBases.map((knowledge) => {
<section className="flex flex-col gap-2">
{knowledgeBaseIds.map((id) => {
const item = knowledgeList.find((y) => id === y.id);
const label = getLabel(id);

return (
<div className={styles.nodeText} key={knowledge.id}>
<Flex align={'center'} gap={6}>
<div className={styles.nodeText} key={id}>
<div className="flex items-center gap-1.5">
<RAGFlowAvatar
className="size-6 rounded-lg"
avatar={knowledge.avatar}
name={knowledge.name || 'CN'}
avatar={id}
name={item?.name || (label as string) || 'CN'}
isPerson={true}
/>
<Flex className={styles.knowledgeNodeName} flex={1}>
{knowledge.name}
</Flex>
</Flex>

<div className={'truncate flex-1'}>{label || item?.name}</div>
</div>
</div>
);
})}
</Flex>
</section>
</NodeWrapper>
</ToolBar>
);

+ 1
- 1
web/src/pages/agent/form/retrieval-form/next.tsx 查看文件

@@ -97,7 +97,7 @@ function RetrievalForm({ node }: INextOperatorForm) {
<FormWrapper>
<FormContainer>
<QueryVariable></QueryVariable>
<KnowledgeBaseFormField></KnowledgeBaseFormField>
<KnowledgeBaseFormField showVariable></KnowledgeBaseFormField>
</FormContainer>
<Collapse title={<div>Advanced Settings</div>}>
<FormContainer>

+ 1
- 1
web/src/pages/agent/form/tool-form/retrieval-form/index.tsx 查看文件

@@ -43,7 +43,7 @@ const RetrievalForm = () => {
>
<FormContainer>
<DescriptionField></DescriptionField>
<KnowledgeBaseFormField></KnowledgeBaseFormField>
<KnowledgeBaseFormField showVariable></KnowledgeBaseFormField>
</FormContainer>
<Collapse title={<div>Advanced Settings</div>}>
<FormContainer>

+ 1
- 1
web/src/pages/next-chats/share/index.tsx 查看文件

@@ -175,7 +175,7 @@ const ChatContainer = () => {
);
})}
</div>
<div ref={ref} />
<div ref={ref.scrollRef} />
</div>
<div className="flex w-full justify-center mb-8">
<div className="w-5/6">

正在加载...
取消
保存