Sfoglia il codice sorgente

Feat: Add Email and DuckDuckGo and Wikipedia Operator #3221 (#9090)

### What problem does this PR solve?

Feat: Add Email and DuckDuckGo and Wikipedia Operator #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
tags/v0.20.0
balibabu 3 mesi fa
parent
commit
b9d3846bb4
Nessun account collegato all'indirizzo email del committer

+ 1
- 2
web/src/pages/agent/canvas/index.tsx Vedi File

import { AgentNode } from './node/agent-node'; import { AgentNode } from './node/agent-node';
import { BeginNode } from './node/begin-node'; import { BeginNode } from './node/begin-node';
import { CategorizeNode } from './node/categorize-node'; import { CategorizeNode } from './node/categorize-node';
import { EmailNode } from './node/email-node';
import { GenerateNode } from './node/generate-node'; import { GenerateNode } from './node/generate-node';
import { InvokeNode } from './node/invoke-node'; import { InvokeNode } from './node/invoke-node';
import { IterationNode, IterationStartNode } from './node/iteration-node'; import { IterationNode, IterationStartNode } from './node/iteration-node';
keywordNode: KeywordNode, keywordNode: KeywordNode,
invokeNode: InvokeNode, invokeNode: InvokeNode,
templateNode: TemplateNode, templateNode: TemplateNode,
emailNode: EmailNode,
// emailNode: EmailNode,
group: IterationNode, group: IterationNode,
iterationStartNode: IterationStartNode, iterationStartNode: IterationStartNode,
agentNode: AgentNode, agentNode: AgentNode,

+ 3
- 0
web/src/pages/agent/canvas/node/dropdown/next-step-dropdown.tsx Vedi File

Operator.ExeSQL, Operator.ExeSQL,
Operator.Google, Operator.Google,
Operator.YahooFinance, Operator.YahooFinance,
Operator.Email,
Operator.DuckDuckGo,
Operator.Wikipedia,
]} ]}
></OperatorItemList> ></OperatorItemList>
</AccordionContent> </AccordionContent>

+ 26
- 4
web/src/pages/agent/constant.tsx Vedi File

export const initialDuckValues = { export const initialDuckValues = {
top_n: 10, top_n: 10,
channel: Channel.Text, channel: Channel.Text,
...initialQueryBaseValues,
query: AgentGlobals.SysQuery,
outputs: {
formalized_content: {
value: '',
type: 'string',
},
json: {
value: [],
type: 'Array<Object>',
},
},
}; };


export const initialBaiduValues = { export const initialBaiduValues = {
export const initialWikipediaValues = { export const initialWikipediaValues = {
top_n: 10, top_n: 10,
language: 'en', language: 'en',
...initialQueryBaseValues,
query: AgentGlobals.SysQuery,
outputs: {
formalized_content: {
value: '',
type: 'string',
},
},
}; };


export const initialPubMedValues = { export const initialPubMedValues = {


export const initialEmailValues = { export const initialEmailValues = {
smtp_server: '', smtp_server: '',
smtp_port: 587,
smtp_port: 465,
email: '', email: '',
password: '', password: '',
sender_name: '', sender_name: '',
cc_email: '', cc_email: '',
subject: '', subject: '',
content: '', content: '',
outputs: {
success: {
value: true,
type: 'boolean',
},
},
}; };


export const initialIterationValues = { export const initialIterationValues = {
[Operator.Crawler]: 'ragNode', [Operator.Crawler]: 'ragNode',
[Operator.Invoke]: 'invokeNode', [Operator.Invoke]: 'invokeNode',
[Operator.Template]: 'templateNode', [Operator.Template]: 'templateNode',
[Operator.Email]: 'emailNode',
[Operator.Email]: 'ragNode',
[Operator.Iteration]: 'group', [Operator.Iteration]: 'group',
[Operator.IterationStart]: 'iterationStartNode', [Operator.IterationStart]: 'iterationStartNode',
[Operator.Code]: 'ragNode', [Operator.Code]: 'ragNode',

+ 64
- 28
web/src/pages/agent/form/duckduckgo-form/index.tsx Vedi File

import { FormContainer } from '@/components/form-container';
import { TopNFormField } from '@/components/top-n-item'; import { TopNFormField } from '@/components/top-n-item';
import { import {
Form, Form,
} from '@/components/ui/form'; } from '@/components/ui/form';
import { RAGFlowSelect } from '@/components/ui/select'; import { RAGFlowSelect } from '@/components/ui/select';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import { useMemo } from 'react';
import { Channel } from '../../constant';
import { zodResolver } from '@hookform/resolvers/zod';
import { memo, useMemo } from 'react';
import { useForm, useFormContext } from 'react-hook-form';
import { z } from 'zod';
import { Channel, initialDuckValues } from '../../constant';
import { useFormValues } from '../../hooks/use-form-values';
import { INextOperatorForm } from '../../interface'; import { INextOperatorForm } from '../../interface';
import { DynamicInputVariable } from '../components/next-dynamic-input-variable';
import { buildOutputList } from '../../utils/build-output-list';
import { FormWrapper } from '../components/form-wrapper';
import { Output } from '../components/output';
import { QueryVariable } from '../components/query-variable';


const DuckDuckGoForm = ({ form, node }: INextOperatorForm) => {
export const DuckDuckGoFormPartialSchema = {
top_n: z.string(),
channel: z.string(),
};

const FormSchema = z.object({
query: z.string(),
...DuckDuckGoFormPartialSchema,
});

export function DuckDuckGoWidgets() {
const { t } = useTranslate('flow'); const { t } = useTranslate('flow');
const form = useFormContext();


const options = useMemo(() => { const options = useMemo(() => {
return Object.values(Channel).map((x) => ({ value: x, label: t(x) })); return Object.values(Channel).map((x) => ({ value: x, label: t(x) }));
}, [t]); }, [t]);


return (
<>
<TopNFormField></TopNFormField>
<FormField
control={form.control}
name={'channel'}
render={({ field }) => (
<FormItem>
<FormLabel tooltip={t('channelTip')}>{t('channel')}</FormLabel>
<FormControl>
<RAGFlowSelect {...field} options={options} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</>
);
}

const outputList = buildOutputList(initialDuckValues.outputs);

function DuckDuckGoForm({ node }: INextOperatorForm) {
const defaultValues = useFormValues(initialDuckValues, node);

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues,
resolver: zodResolver(FormSchema),
});

return ( return (
<Form {...form}> <Form {...form}>
<form
className="space-y-6"
onSubmit={(e) => {
e.preventDefault();
}}
>
<DynamicInputVariable node={node}></DynamicInputVariable>
<TopNFormField></TopNFormField>
<FormField
control={form.control}
name="channel"
render={({ field }) => (
<FormItem>
<FormLabel tooltip={t('channelTip')}>{t('channel')}</FormLabel>
<FormControl>
<RAGFlowSelect {...field} options={options} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</form>
<FormWrapper>
<FormContainer>
<QueryVariable></QueryVariable>
<DuckDuckGoWidgets></DuckDuckGoWidgets>
</FormContainer>
</FormWrapper>
<div className="p-5">
<Output list={outputList}></Output>
</div>
</Form> </Form>
); );
};
}


export default DuckDuckGoForm;
export default memo(DuckDuckGoForm);

+ 111
- 42
web/src/pages/agent/form/email-form/index.tsx Vedi File

import { FormContainer } from '@/components/form-container';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import { Form, Input } from 'antd';
import { IOperatorForm } from '../../interface';
import DynamicInputVariable from '../components/dynamic-input-variable';
import { zodResolver } from '@hookform/resolvers/zod';
import { ReactNode } from 'react';
import { useForm, useFormContext } from 'react-hook-form';
import { z } from 'zod';
import { initialEmailValues } from '../../constant';
import { useFormValues } from '../../hooks/use-form-values';
import { INextOperatorForm } from '../../interface';
import { buildOutputList } from '../../utils/build-output-list';
import { FormWrapper } from '../components/form-wrapper';
import { Output } from '../components/output';


const EmailForm = ({ onValuesChange, form, node }: IOperatorForm) => {
interface InputFormFieldProps {
name: string;
label: ReactNode;
type?: string;
}

function InputFormField({ name, label, type }: InputFormFieldProps) {
const form = useFormContext();

return (
<FormField
control={form.control}
name={name}
render={({ field }) => (
<FormItem>
<FormLabel>{label}</FormLabel>
<FormControl>
<Input {...field} type={type}></Input>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
);
}

export function EmailFormWidgets() {
const { t } = useTranslate('flow'); const { t } = useTranslate('flow');


return ( return (
<Form
name="basic"
autoComplete="off"
form={form}
onValuesChange={onValuesChange}
layout={'vertical'}
>
<DynamicInputVariable node={node}></DynamicInputVariable>

{/* SMTP服务器配置 */}
<Form.Item label={t('smtpServer')} name={'smtp_server'}>
<Input placeholder="smtp.example.com" />
</Form.Item>
<Form.Item label={t('smtpPort')} name={'smtp_port'}>
<Input type="number" placeholder="587" />
</Form.Item>
<Form.Item label={t('senderEmail')} name={'email'}>
<Input placeholder="sender@example.com" />
</Form.Item>
<Form.Item label={t('authCode')} name={'password'}>
<Input.Password placeholder="your_password" />
</Form.Item>
<Form.Item label={t('senderName')} name={'sender_name'}>
<Input placeholder="Sender Name" />
</Form.Item>

{/* 动态参数说明 */}
<div style={{ marginBottom: 24 }}>
<h4>{t('dynamicParameters')}</h4>
<div>{t('jsonFormatTip')}</div>
<pre style={{ background: '#f5f5f5', padding: 12, borderRadius: 4 }}>
{`{
"to_email": "recipient@example.com",
"cc_email": "cc@example.com",
"subject": "Email Subject",
"content": "Email Content"
}`}
</pre>
<>
<InputFormField
name="smtp_server"
label={t('smtpServer')}
></InputFormField>
<InputFormField
name="smtp_port"
label={t('smtpPort')}
type="number"
></InputFormField>
<InputFormField name="email" label={t('senderEmail')}></InputFormField>
<InputFormField
name="password"
label={t('authCode')}
type="password"
></InputFormField>
<InputFormField
name="sender_name"
label={t('senderName')}
></InputFormField>
</>
);
}

export const EmailFormPartialSchema = {
smtp_server: z.string(),
smtp_port: z.number(),
email: z.string(),
password: z.string(),
sender_name: z.string(),
};

const FormSchema = z.object({
to_email: z.string(),
cc_email: z.string(),
content: z.string(),
subject: z.string(),
...EmailFormPartialSchema,
});

const outputList = buildOutputList(initialEmailValues.outputs);

const EmailForm = ({ node }: INextOperatorForm) => {
const { t } = useTranslate('flow');
const defaultValues = useFormValues(initialEmailValues, node);

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues,
resolver: zodResolver(FormSchema),
});

return (
<Form {...form}>
<FormWrapper>
<FormContainer>
<InputFormField name="to_email" label={t('toEmail')}></InputFormField>
<InputFormField name="cc_email" label={t('ccEmail')}></InputFormField>
<InputFormField name="content" label={t('content')}></InputFormField>
<InputFormField name="subject" label={t('subject')}></InputFormField>
<EmailFormWidgets></EmailFormWidgets>
</FormContainer>
</FormWrapper>
<div className="p-5">
<Output list={outputList}></Output>
</div> </div>
</Form> </Form>
); );

+ 3
- 3
web/src/pages/agent/form/tool-form/constant.tsx Vedi File

import AkShareForm from '../akshare-form'; import AkShareForm from '../akshare-form';
import ArXivForm from '../arxiv-form'; import ArXivForm from '../arxiv-form';
import DeepLForm from '../deepl-form'; import DeepLForm from '../deepl-form';
import DuckDuckGoForm from '../duckduckgo-form';
import EmailForm from '../email-form';
import GithubForm from '../github-form'; import GithubForm from '../github-form';
import GoogleScholarForm from '../google-scholar-form'; import GoogleScholarForm from '../google-scholar-form';
import PubMedForm from '../pubmed-form'; import PubMedForm from '../pubmed-form';
import WikipediaForm from '../wikipedia-form';
import BingForm from './bing-form'; import BingForm from './bing-form';
import CrawlerForm from './crawler-form'; import CrawlerForm from './crawler-form';
import DuckDuckGoForm from './duckduckgo-form';
import EmailForm from './email-form';
import ExeSQLForm from './exesql-form'; import ExeSQLForm from './exesql-form';
import RetrievalForm from './retrieval-form'; import RetrievalForm from './retrieval-form';
import TavilyForm from './tavily-form'; import TavilyForm from './tavily-form';
import WikipediaForm from './wikipedia-form';
import YahooFinanceForm from './yahoo-finance-form'; import YahooFinanceForm from './yahoo-finance-form';


export const ToolFormConfigMap = { export const ToolFormConfigMap = {

+ 38
- 0
web/src/pages/agent/form/tool-form/duckduckgo-form/index.tsx Vedi File

import { FormContainer } from '@/components/form-container';
import { Form } from '@/components/ui/form';
import { zodResolver } from '@hookform/resolvers/zod';
import { memo } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { FormWrapper } from '../../components/form-wrapper';
import {
DuckDuckGoFormPartialSchema,
DuckDuckGoWidgets,
} from '../../duckduckgo-form';
import { useValues } from '../use-values';
import { useWatchFormChange } from '../use-watch-change';

function DuckDuckGoForm() {
const values = useValues();

const FormSchema = z.object(DuckDuckGoFormPartialSchema);

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues: values,
resolver: zodResolver(FormSchema),
});

useWatchFormChange(form);

return (
<Form {...form}>
<FormWrapper>
<FormContainer>
<DuckDuckGoWidgets></DuckDuckGoWidgets>
</FormContainer>
</FormWrapper>
</Form>
);
}

export default memo(DuckDuckGoForm);

+ 35
- 0
web/src/pages/agent/form/tool-form/email-form/index.tsx Vedi File

import { FormContainer } from '@/components/form-container';
import { Form } from '@/components/ui/form';
import { zodResolver } from '@hookform/resolvers/zod';
import { memo } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { FormWrapper } from '../../components/form-wrapper';
import { EmailFormPartialSchema, EmailFormWidgets } from '../../email-form';
import { useValues } from '../use-values';
import { useWatchFormChange } from '../use-watch-change';

function EmailForm() {
const values = useValues();

const FormSchema = z.object(EmailFormPartialSchema);

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues: values,
resolver: zodResolver(FormSchema),
});

useWatchFormChange(form);

return (
<Form {...form}>
<FormWrapper>
<FormContainer>
<EmailFormWidgets></EmailFormWidgets>
</FormContainer>
</FormWrapper>
</Form>
);
}

export default memo(EmailForm);

+ 4
- 3
web/src/pages/agent/form/tool-form/tavily-form/index.tsx Vedi File

import { FormContainer } from '@/components/form-container'; import { FormContainer } from '@/components/form-container';
import { Form } from '@/components/ui/form'; import { Form } from '@/components/ui/form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { memo } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';
import { ApiKeyField } from '../../components/api-key-field'; import { ApiKeyField } from '../../components/api-key-field';
import { useValues } from '../use-values'; import { useValues } from '../use-values';
import { useWatchFormChange } from '../use-watch-change'; import { useWatchFormChange } from '../use-watch-change';


const TavilyForm = () => {
function TavilyForm() {
const values = useValues(); const values = useValues();


const FormSchema = z.object(TavilyFormSchema); const FormSchema = z.object(TavilyFormSchema);
</FormWrapper> </FormWrapper>
</Form> </Form>
); );
};
}


export default TavilyForm;
export default memo(TavilyForm);

+ 38
- 0
web/src/pages/agent/form/tool-form/wikipedia-form/index.tsx Vedi File

import { FormContainer } from '@/components/form-container';
import { Form } from '@/components/ui/form';
import { zodResolver } from '@hookform/resolvers/zod';
import { memo } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { FormWrapper } from '../../components/form-wrapper';
import {
WikipediaFormPartialSchema,
WikipediaFormWidgets,
} from '../../wikipedia-form';
import { useValues } from '../use-values';
import { useWatchFormChange } from '../use-watch-change';

function WikipediaForm() {
const values = useValues();

const FormSchema = z.object(WikipediaFormPartialSchema);

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues: values,
resolver: zodResolver(FormSchema),
});

useWatchFormChange(form);

return (
<Form {...form}>
<FormWrapper>
<FormContainer>
<WikipediaFormWidgets></WikipediaFormWidgets>
</FormContainer>
</FormWrapper>
</Form>
);
}

export default memo(WikipediaForm);

+ 65
- 28
web/src/pages/agent/form/wikipedia-form/index.tsx Vedi File

import { FormContainer } from '@/components/form-container';
import { SelectWithSearch } from '@/components/originui/select-with-search';
import { TopNFormField } from '@/components/top-n-item'; import { TopNFormField } from '@/components/top-n-item';
import { import {
Form, Form,
FormLabel, FormLabel,
FormMessage, FormMessage,
} from '@/components/ui/form'; } from '@/components/ui/form';
import { RAGFlowSelect } from '@/components/ui/select';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import { zodResolver } from '@hookform/resolvers/zod';
import { memo } from 'react';
import { useForm, useFormContext } from 'react-hook-form';
import { z } from 'zod';
import { initialWikipediaValues } from '../../constant';
import { useFormValues } from '../../hooks/use-form-values';
import { INextOperatorForm } from '../../interface'; import { INextOperatorForm } from '../../interface';
import { LanguageOptions } from '../../options'; import { LanguageOptions } from '../../options';
import { DynamicInputVariable } from '../components/next-dynamic-input-variable';
import { buildOutputList } from '../../utils/build-output-list';
import { FormWrapper } from '../components/form-wrapper';
import { Output } from '../components/output';
import { QueryVariable } from '../components/query-variable';


const WikipediaForm = ({ form, node }: INextOperatorForm) => {
export const WikipediaFormPartialSchema = {
top_n: z.string(),
language: z.string(),
};

const FormSchema = z.object({
query: z.string(),
...WikipediaFormPartialSchema,
});

export function WikipediaFormWidgets() {
const { t } = useTranslate('common'); const { t } = useTranslate('common');
const form = useFormContext();

return (
<>
<TopNFormField></TopNFormField>
<FormField
control={form.control}
name="language"
render={({ field }) => (
<FormItem>
<FormLabel>{t('language')}</FormLabel>
<FormControl>
<SelectWithSearch {...field} options={LanguageOptions} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</>
);
}

const outputList = buildOutputList(initialWikipediaValues.outputs);

function WikipediaForm({ node }: INextOperatorForm) {
const defaultValues = useFormValues(initialWikipediaValues, node);

const form = useForm<z.infer<typeof FormSchema>>({
defaultValues,
resolver: zodResolver(FormSchema),
});


return ( return (
<Form {...form}> <Form {...form}>
<form
className="space-y-6"
onSubmit={(e) => {
e.preventDefault();
}}
>
<DynamicInputVariable node={node}></DynamicInputVariable>
<TopNFormField></TopNFormField>

<FormField
control={form.control}
name="language"
render={({ field }) => (
<FormItem>
<FormLabel>{t('language')}</FormLabel>
<FormControl>
<RAGFlowSelect {...field} options={LanguageOptions} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</form>
<FormWrapper>
<FormContainer>
<QueryVariable></QueryVariable>
<WikipediaFormWidgets></WikipediaFormWidgets>
</FormContainer>
</FormWrapper>
<div className="p-5">
<Output list={outputList}></Output>
</div>
</Form> </Form>
); );
};
}


export default WikipediaForm;
export default memo(WikipediaForm);

+ 17
- 1
web/src/pages/agent/hooks/use-agent-tool-initial-values.ts Vedi File

import { omit } from 'lodash';
import { omit, pick } from 'lodash';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { Operator } from '../constant'; import { Operator } from '../constant';
import { useInitializeOperatorParams } from './use-add-node'; import { useInitializeOperatorParams } from './use-add-node';
case Operator.YahooFinance: case Operator.YahooFinance:
return omit(initialValues, 'stock_code'); return omit(initialValues, 'stock_code');


case Operator.Email:
return pick(
initialValues,
'smtp_server',
'smtp_port',
'email',
'password',
'sender_name',
);

case Operator.DuckDuckGo:
return pick(initialValues, 'top_n', 'channel');

case Operator.Wikipedia:
return pick(initialValues, 'top_n', 'language');

default: default:
return initialValues; return initialValues;
} }

Loading…
Annulla
Salva