From 3a3e23d8d94b277c3cdaef1abdccc6c4e7e63155 Mon Sep 17 00:00:00 2001 From: balibabu Date: Thu, 21 Nov 2024 18:05:31 +0800 Subject: [PATCH] Feat: Add Template operator #3556 (#3559) ### What problem does this PR solve? Feat: Add Template operator #3560 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/src/assets/svg/template.svg | 6 ++ web/src/components/editable-cell.tsx | 2 +- web/src/locales/en.ts | 7 +- web/src/locales/zh-traditional.ts | 2 + web/src/locales/zh.ts | 2 + web/src/pages/chat/chat-id-modal/index.tsx | 2 +- web/src/pages/flow/canvas/index.tsx | 2 + .../pages/flow/canvas/node/template-node.tsx | 68 +++++++++++++++++++ web/src/pages/flow/constant.tsx | 16 +++++ web/src/pages/flow/flow-drawer/index.tsx | 2 + web/src/pages/flow/flow-id-modal/index.tsx | 2 +- .../form/generate-form/dynamic-parameters.tsx | 2 + .../pages/flow/form/template-form/index.tsx | 26 +++++++ web/src/pages/flow/hooks.tsx | 2 + 14 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 web/src/assets/svg/template.svg create mode 100644 web/src/pages/flow/canvas/node/template-node.tsx create mode 100644 web/src/pages/flow/form/template-form/index.tsx diff --git a/web/src/assets/svg/template.svg b/web/src/assets/svg/template.svg new file mode 100644 index 0000000000..d3871d27a8 --- /dev/null +++ b/web/src/assets/svg/template.svg @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/web/src/components/editable-cell.tsx b/web/src/components/editable-cell.tsx index f8e367ff7b..4a960d4711 100644 --- a/web/src/components/editable-cell.tsx +++ b/web/src/components/editable-cell.tsx @@ -78,7 +78,7 @@ export const EditableCell: React.FC = ({ if (editable) { childNode = editing ? ( {t('howUseId')} diff --git a/web/src/pages/flow/canvas/index.tsx b/web/src/pages/flow/canvas/index.tsx index 0f20b894b3..afa4c1e069 100644 --- a/web/src/pages/flow/canvas/index.tsx +++ b/web/src/pages/flow/canvas/index.tsx @@ -35,6 +35,7 @@ import { RelevantNode } from './node/relevant-node'; import { RetrievalNode } from './node/retrieval-node'; import { RewriteNode } from './node/rewrite-node'; import { SwitchNode } from './node/switch-node'; +import { TemplateNode } from './node/template-node'; const nodeTypes = { ragNode: RagNode, @@ -50,6 +51,7 @@ const nodeTypes = { rewriteNode: RewriteNode, keywordNode: KeywordNode, invokeNode: InvokeNode, + templateNode: TemplateNode, }; const edgeTypes = { diff --git a/web/src/pages/flow/canvas/node/template-node.tsx b/web/src/pages/flow/canvas/node/template-node.tsx new file mode 100644 index 0000000000..65fcbe471d --- /dev/null +++ b/web/src/pages/flow/canvas/node/template-node.tsx @@ -0,0 +1,68 @@ +import { Flex } from 'antd'; +import classNames from 'classnames'; +import { get } from 'lodash'; +import { Handle, NodeProps, Position } from 'reactflow'; +import { useGetComponentLabelByValue } from '../../hooks'; +import { IGenerateParameter, NodeData } from '../../interface'; +import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; +import NodeHeader from './node-header'; + +import styles from './index.less'; + +export function TemplateNode({ + id, + data, + isConnectable = true, + selected, +}: NodeProps) { + const parameters: IGenerateParameter[] = get(data, 'form.parameters', []); + const getLabel = useGetComponentLabelByValue(id); + + return ( +
+ + + + + + + {parameters.map((x) => ( + + + + {getLabel(x.component_id)} + + + ))} + +
+ ); +} diff --git a/web/src/pages/flow/constant.tsx b/web/src/pages/flow/constant.tsx index 132fbd1101..e06398f63e 100644 --- a/web/src/pages/flow/constant.tsx +++ b/web/src/pages/flow/constant.tsx @@ -19,6 +19,7 @@ import { ReactComponent as NoteIcon } from '@/assets/svg/note.svg'; import { ReactComponent as PubMedIcon } from '@/assets/svg/pubmed.svg'; import { ReactComponent as QWeatherIcon } from '@/assets/svg/qweather.svg'; import { ReactComponent as SwitchIcon } from '@/assets/svg/switch.svg'; +import { ReactComponent as TemplateIcon } from '@/assets/svg/template.svg'; import { ReactComponent as TuShareIcon } from '@/assets/svg/tushare.svg'; import { ReactComponent as WenCaiIcon } from '@/assets/svg/wencai.svg'; import { ReactComponent as WikipediaIcon } from '@/assets/svg/wikipedia.svg'; @@ -85,6 +86,7 @@ export enum Operator { Note = 'Note', Crawler = 'Crawler', Invoke = 'Invoke', + Template = 'Template', } export const CommonOperatorList = Object.values(Operator).filter( @@ -124,6 +126,7 @@ export const operatorIconMap = { [Operator.Note]: NoteIcon, [Operator.Crawler]: CrawlerIcon, [Operator.Invoke]: InvokeIcon, + [Operator.Template]: TemplateIcon, }; export const operatorMap: Record< @@ -253,6 +256,9 @@ export const operatorMap: Record< [Operator.Invoke]: { backgroundColor: '#dee0e2', }, + [Operator.Template]: { + backgroundColor: '#dee0e2', + }, }; export const componentMenuList = [ @@ -286,6 +292,9 @@ export const componentMenuList = [ { name: Operator.Concentrator, }, + { + name: Operator.Template, + }, { name: Operator.Note, }, @@ -566,6 +575,11 @@ export const initialInvokeValues = { clean_html: false, }; +export const initialTemplateValues = { + content: '', + parameters: [], +}; + export const CategorizeAnchorPointPositions = [ { top: 1, right: 34 }, { top: 8, right: 18 }, @@ -645,6 +659,7 @@ export const RestrictedUpstreamMap = { [Operator.Crawler]: [Operator.Begin], [Operator.Note]: [], [Operator.Invoke]: [Operator.Begin], + [Operator.Template]: [Operator.Begin, Operator.Relevant], }; export const NodeMap = { @@ -680,6 +695,7 @@ export const NodeMap = { [Operator.Note]: 'noteNode', [Operator.Crawler]: 'ragNode', [Operator.Invoke]: 'invokeNode', + [Operator.Template]: 'templateNode', }; export const LanguageOptions = [ diff --git a/web/src/pages/flow/flow-drawer/index.tsx b/web/src/pages/flow/flow-drawer/index.tsx index 945ca18fd8..5a2c7e40e0 100644 --- a/web/src/pages/flow/flow-drawer/index.tsx +++ b/web/src/pages/flow/flow-drawer/index.tsx @@ -39,6 +39,7 @@ import OperatorIcon from '../operator-icon'; import { CloseOutlined } from '@ant-design/icons'; import { lowerFirst } from 'lodash'; +import TemplateForm from '../form/template-form'; import { getDrawerWidth } from '../utils'; import styles from './index.less'; @@ -79,6 +80,7 @@ const FormMap = { [Operator.Invoke]: InvokeForm, [Operator.Concentrator]: () => <>, [Operator.Note]: () => <>, + [Operator.Template]: TemplateForm, }; const EmptyContent = () =>
; diff --git a/web/src/pages/flow/flow-id-modal/index.tsx b/web/src/pages/flow/flow-id-modal/index.tsx index fd9dbea473..7c54a3c448 100644 --- a/web/src/pages/flow/flow-id-modal/index.tsx +++ b/web/src/pages/flow/flow-id-modal/index.tsx @@ -24,7 +24,7 @@ const FlowIdModal = ({ hideModal }: IModalProps) => { {id} {t('howUseId')} diff --git a/web/src/pages/flow/form/generate-form/dynamic-parameters.tsx b/web/src/pages/flow/form/generate-form/dynamic-parameters.tsx index 427ce04ab0..c5220ebf6a 100644 --- a/web/src/pages/flow/form/generate-form/dynamic-parameters.tsx +++ b/web/src/pages/flow/form/generate-form/dynamic-parameters.tsx @@ -36,6 +36,7 @@ const DynamicParameters = ({ nodeId }: IProps) => { title: t('key'), dataIndex: 'key', key: 'key', + width: '40%', onCell: (record: IGenerateParameter) => ({ record, editable: true, @@ -49,6 +50,7 @@ const DynamicParameters = ({ nodeId }: IProps) => { dataIndex: 'component_id', key: 'component_id', align: 'center', + width: '40%', render(text, record) { return (