mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Improve the tavily form #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
type OutputType = {
|
export type OutputType = {
|
||||||
title: string;
|
title: string;
|
||||||
type: string;
|
type: string;
|
||||||
};
|
};
|
||||||
|
|||||||
57
web/src/pages/agent/form/tavily-form/dynamic-domain.tsx
Normal file
57
web/src/pages/agent/form/tavily-form/dynamic-domain.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { BlockButton, Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from '@/components/ui/form';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { X } from 'lucide-react';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { useFieldArray, useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
|
type DynamicDomainProps = { name: string; label: ReactNode };
|
||||||
|
|
||||||
|
export const DynamicDomain = ({ name, label }: DynamicDomainProps) => {
|
||||||
|
const form = useFormContext();
|
||||||
|
|
||||||
|
const { fields, append, remove } = useFieldArray({
|
||||||
|
name: name,
|
||||||
|
control: form.control,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>{label}</FormLabel>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<div key={field.id} className="flex">
|
||||||
|
<div className="space-y-2 flex-1">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`${name}.${index}.value`}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="flex-1">
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field}></Input>
|
||||||
|
</FormControl>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant={'ghost'}
|
||||||
|
onClick={() => remove(index)}
|
||||||
|
>
|
||||||
|
<X />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<FormMessage />
|
||||||
|
<BlockButton onClick={() => append({ value: '' })}>Add</BlockButton>
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -9,18 +9,23 @@ import {
|
|||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { RAGFlowSelect } from '@/components/ui/select';
|
import { RAGFlowSelect } from '@/components/ui/select';
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { buildOptions } from '@/utils/form';
|
import { buildOptions } from '@/utils/form';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { useMemo } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { Output, OutputType } from '../components/output';
|
||||||
import { QueryVariable } from '../components/query-variable';
|
import { QueryVariable } from '../components/query-variable';
|
||||||
import { SearchDepth, Topic, useValues } from './use-values';
|
import { DynamicDomain } from './dynamic-domain';
|
||||||
|
import { SearchDepth, Topic, defaultValues, useValues } from './use-values';
|
||||||
import { useWatchFormChange } from './use-watch-change';
|
import { useWatchFormChange } from './use-watch-change';
|
||||||
|
|
||||||
const TavilyForm = () => {
|
const TavilyForm = () => {
|
||||||
const values = useValues();
|
const values = useValues();
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
|
api_key: z.string(),
|
||||||
query: z.string(),
|
query: z.string(),
|
||||||
search_depth: z.enum([SearchDepth.Advanced, SearchDepth.Basic]),
|
search_depth: z.enum([SearchDepth.Advanced, SearchDepth.Basic]),
|
||||||
topic: z.enum([Topic.News, Topic.General]),
|
topic: z.enum([Topic.News, Topic.General]),
|
||||||
@ -30,15 +35,25 @@ const TavilyForm = () => {
|
|||||||
include_raw_content: z.boolean(),
|
include_raw_content: z.boolean(),
|
||||||
include_images: z.boolean(),
|
include_images: z.boolean(),
|
||||||
include_image_descriptions: z.boolean(),
|
include_image_descriptions: z.boolean(),
|
||||||
include_domains: z.array(z.string()),
|
include_domains: z.array(z.object({ value: z.any() })), // TODO: z.string should be used, but an error will be reported
|
||||||
exclude_domains: z.array(z.string()),
|
exclude_domains: z.array(z.object({ value: z.any() })),
|
||||||
});
|
});
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
defaultValues: values,
|
defaultValues: values,
|
||||||
resolver: zodResolver(FormSchema),
|
resolver: zodResolver(FormSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const outputList = useMemo(() => {
|
||||||
|
return Object.entries(defaultValues.outputs).reduce<OutputType[]>(
|
||||||
|
(pre, [key, val]) => {
|
||||||
|
pre.push({ title: key, type: val.type });
|
||||||
|
return pre;
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useWatchFormChange(form);
|
useWatchFormChange(form);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -50,9 +65,23 @@ const TavilyForm = () => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<FormContainer>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="api_key"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Api Key</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input type="password" {...field}></Input>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormContainer>
|
||||||
<FormContainer>
|
<FormContainer>
|
||||||
<QueryVariable></QueryVariable>
|
<QueryVariable></QueryVariable>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="search_depth"
|
name="search_depth"
|
||||||
@ -100,8 +129,96 @@ const TavilyForm = () => {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="days"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Days</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input type={'number'} {...field}></Input>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="include_answer"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Include Answer</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
></Switch>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="include_raw_content"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Include Raw Content</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
></Switch>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="include_images"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Include Images</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
></Switch>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="include_image_descriptions"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Include Image Descriptions</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
></Switch>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<DynamicDomain
|
||||||
|
name="include_domains"
|
||||||
|
label={'Include Domains'}
|
||||||
|
></DynamicDomain>
|
||||||
|
<DynamicDomain
|
||||||
|
name="exclude_domains"
|
||||||
|
label={'Exclude Domains'}
|
||||||
|
></DynamicDomain>
|
||||||
</FormContainer>
|
</FormContainer>
|
||||||
</form>
|
</form>
|
||||||
|
<div className="p-5">
|
||||||
|
<Output list={outputList}></Output>
|
||||||
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
|
import { AgentGlobals } from '@/constants/agent';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import useGraphStore from '../../store';
|
import useGraphStore from '../../store';
|
||||||
import { getAgentNodeTools } from '../../utils';
|
import { convertToObjectArray, getAgentNodeTools } from '../../utils';
|
||||||
|
|
||||||
export enum SearchDepth {
|
export enum SearchDepth {
|
||||||
Basic = 'basic',
|
Basic = 'basic',
|
||||||
@ -13,8 +14,9 @@ export enum Topic {
|
|||||||
General = 'general',
|
General = 'general',
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultValues = {
|
export const defaultValues = {
|
||||||
query: '',
|
api_key: '',
|
||||||
|
query: AgentGlobals.SysQuery,
|
||||||
search_depth: SearchDepth.Basic,
|
search_depth: SearchDepth.Basic,
|
||||||
topic: Topic.General,
|
topic: Topic.General,
|
||||||
max_results: 5,
|
max_results: 5,
|
||||||
@ -25,6 +27,16 @@ const defaultValues = {
|
|||||||
include_image_descriptions: false,
|
include_image_descriptions: false,
|
||||||
include_domains: [],
|
include_domains: [],
|
||||||
exclude_domains: [],
|
exclude_domains: [],
|
||||||
|
outputs: {
|
||||||
|
formalized_content: {
|
||||||
|
value: '',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
json: {
|
||||||
|
value: {},
|
||||||
|
type: 'Object',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useValues() {
|
export function useValues() {
|
||||||
@ -46,6 +58,8 @@ export function useValues() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...formData,
|
...formData,
|
||||||
|
include_domains: convertToObjectArray(formData.include_domains),
|
||||||
|
exclude_domains: convertToObjectArray(formData.exclude_domains),
|
||||||
};
|
};
|
||||||
}, [clickedNodeId, clickedToolId, findUpstreamNodeById]);
|
}, [clickedNodeId, clickedToolId, findUpstreamNodeById]);
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { UseFormReturn, useWatch } from 'react-hook-form';
|
import { UseFormReturn, useWatch } from 'react-hook-form';
|
||||||
import useGraphStore from '../../store';
|
import useGraphStore from '../../store';
|
||||||
import { getAgentNodeTools } from '../../utils';
|
import { convertToStringArray, getAgentNodeTools } from '../../utils';
|
||||||
|
|
||||||
export function useWatchFormChange(form?: UseFormReturn<any>) {
|
export function useWatchFormChange(form?: UseFormReturn<any>) {
|
||||||
let values = useWatch({ control: form?.control });
|
let values = useWatch({ control: form?.control });
|
||||||
@ -18,7 +18,14 @@ export function useWatchFormChange(form?: UseFormReturn<any>) {
|
|||||||
values = form?.getValues();
|
values = form?.getValues();
|
||||||
const nextTools = tools.map((x) => {
|
const nextTools = tools.map((x) => {
|
||||||
if (x.component_name === clickedToolId) {
|
if (x.component_name === clickedToolId) {
|
||||||
return { ...x, params: { ...values } };
|
return {
|
||||||
|
...x,
|
||||||
|
params: {
|
||||||
|
...values,
|
||||||
|
include_domains: convertToStringArray(values.include_domains),
|
||||||
|
exclude_domains: convertToStringArray(values.exclude_domains),
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user