feat: Add InvokeNode #1908 (#3081)

### What problem does this PR solve?

feat: Add InvokeNode #1908

### Type of change

- [ ] Bug Fix (non-breaking change which fixes an issue)
- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu 2024-10-29 16:39:56 +08:00 committed by GitHub
parent 2d1fbefdb5
commit 3ed096fd3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 72 additions and 8 deletions

View File

@ -78,7 +78,7 @@ export const EditableCell: React.FC<EditableCellProps> = ({
if (editable) { if (editable) {
childNode = editing ? ( childNode = editing ? (
<Form.Item <Form.Item
style={{ margin: 0, width: 100 }} style={{ margin: 0, width: 70 }}
name={dataIndex} name={dataIndex}
rules={[ rules={[
{ {
@ -95,7 +95,7 @@ export const EditableCell: React.FC<EditableCellProps> = ({
// style={{ paddingRight: 24 }} // style={{ paddingRight: 24 }}
onClick={toggleEdit} onClick={toggleEdit}
> >
<Text ellipsis={{ tooltip: children }} style={{ width: 100 }}> <Text ellipsis={{ tooltip: children }} style={{ width: 70 }}>
{children} {children}
</Text> </Text>
</div> </div>

View File

@ -1023,6 +1023,7 @@ The above is the content you need to summarize.`,
method: 'Method', method: 'Method',
timeout: 'Timeout', timeout: 'Timeout',
headers: 'Headers', headers: 'Headers',
cleanHtml: 'Clean html',
}, },
footer: { footer: {
profile: 'All rights reserved @ React', profile: 'All rights reserved @ React',

View File

@ -972,6 +972,7 @@ export default {
method: '方法', method: '方法',
timeout: '超時', timeout: '超時',
headers: '請求頭', headers: '請求頭',
cleanHtml: '清除 html',
}, },
footer: { footer: {
profile: '“保留所有權利 @ react”', profile: '“保留所有權利 @ react”',

View File

@ -992,6 +992,7 @@ export default {
method: '方法', method: '方法',
timeout: '超时', timeout: '超时',
headers: '请求头', headers: '请求头',
cleanHtml: '清除 html',
}, },
footer: { footer: {
profile: 'All rights reserved @ React', profile: 'All rights reserved @ React',

View File

@ -23,6 +23,7 @@ import { RagNode } from './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 { GenerateNode } from './node/generate-node'; import { GenerateNode } from './node/generate-node';
import { InvokeNode } from './node/invoke-node';
import { KeywordNode } from './node/keyword-node'; import { KeywordNode } from './node/keyword-node';
import { LogicNode } from './node/logic-node'; import { LogicNode } from './node/logic-node';
import { MessageNode } from './node/message-node'; import { MessageNode } from './node/message-node';
@ -45,6 +46,7 @@ const nodeTypes = {
messageNode: MessageNode, messageNode: MessageNode,
rewriteNode: RewriteNode, rewriteNode: RewriteNode,
keywordNode: KeywordNode, keywordNode: KeywordNode,
invokeNode: InvokeNode,
}; };
const edgeTypes = { const edgeTypes = {

View File

@ -0,0 +1,56 @@
import { Flex } from 'antd';
import classNames from 'classnames';
import { get } from 'lodash';
import { useTranslation } from 'react-i18next';
import { Handle, NodeProps, Position } from 'reactflow';
import { NodeData } from '../../interface';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less';
import NodeHeader from './node-header';
import NodePopover from './popover';
export function InvokeNode({
id,
data,
isConnectable = true,
selected,
}: NodeProps<NodeData>) {
const { t } = useTranslation();
const url = get(data, 'form.url');
return (
<NodePopover nodeId={id}>
<section
className={classNames(styles.ragNode, {
[styles.selectedNode]: selected,
})}
>
<Handle
id="c"
type="source"
position={Position.Left}
isConnectable={isConnectable}
className={styles.handle}
style={LeftHandleStyle}
></Handle>
<Handle
type="source"
position={Position.Right}
isConnectable={isConnectable}
className={styles.handle}
id="b"
style={RightHandleStyle}
></Handle>
<NodeHeader
id={id}
name={data.name}
label={data.label}
className={styles.nodeHeader}
></NodeHeader>
<Flex vertical>
<div>{t('flow.url')}</div>
<div className={styles.nodeText}>{url}</div>
</Flex>
</section>
</NodePopover>
);
}

View File

@ -528,6 +528,7 @@ export const initialInvokeValues = {
"Connection": "keep-alive" "Connection": "keep-alive"
}`, }`,
proxy: 'http://', proxy: 'http://',
clean_html: false,
}; };
export const CategorizeAnchorPointPositions = [ export const CategorizeAnchorPointPositions = [
@ -643,7 +644,7 @@ export const NodeMap = {
[Operator.TuShare]: 'ragNode', [Operator.TuShare]: 'ragNode',
[Operator.Note]: 'noteNode', [Operator.Note]: 'noteNode',
[Operator.Crawler]: 'ragNode', [Operator.Crawler]: 'ragNode',
[Operator.Invoke]: 'ragNode', [Operator.Invoke]: 'invokeNode',
}; };
export const LanguageOptions = [ export const LanguageOptions = [

View File

@ -76,8 +76,8 @@ const FormMap = {
[Operator.TuShare]: TuShareForm, [Operator.TuShare]: TuShareForm,
[Operator.Crawler]: CrawlerForm, [Operator.Crawler]: CrawlerForm,
[Operator.Invoke]: InvokeForm, [Operator.Invoke]: InvokeForm,
[Operator.Concentrator]: <></>, [Operator.Concentrator]: () => <></>,
[Operator.Note]: <></>, [Operator.Note]: () => <></>,
}; };
const EmptyContent = () => <div></div>; const EmptyContent = () => <div></div>;
@ -135,7 +135,7 @@ const FlowDrawer = ({
open={visible} open={visible}
getContainer={false} getContainer={false}
mask={false} mask={false}
width={470} width={500}
closeIcon={null} closeIcon={null}
> >
<section className={styles.formWrapper}> <section className={styles.formWrapper}>

View File

@ -38,7 +38,6 @@ const DynamicVariables = ({ nodeId }: IProps) => {
title: t('key'), title: t('key'),
dataIndex: 'key', dataIndex: 'key',
key: 'key', key: 'key',
// width: 40,
onCell: (record: IInvokeVariable) => ({ onCell: (record: IInvokeVariable) => ({
record, record,
editable: true, editable: true,

View File

@ -1,5 +1,5 @@
import Editor from '@monaco-editor/react'; import Editor from '@monaco-editor/react';
import { Form, Input, InputNumber, Select, Space } from 'antd'; import { Form, Input, InputNumber, Select, Space, Switch } from 'antd';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSetLlmSetting } from '../../hooks'; import { useSetLlmSetting } from '../../hooks';
import { IOperatorForm } from '../../interface'; import { IOperatorForm } from '../../interface';
@ -63,6 +63,9 @@ const InvokeForm = ({ onValuesChange, form, node }: IOperatorForm) => {
<Form.Item name={'proxy'} label={t('flow.proxy')}> <Form.Item name={'proxy'} label={t('flow.proxy')}>
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item name={'clean_html'} label={t('flow.cleanHtml')}>
<Switch />
</Form.Item>
<DynamicVariables nodeId={node?.id}></DynamicVariables> <DynamicVariables nodeId={node?.id}></DynamicVariables>
</Form> </Form>
</> </>