diff --git a/web/package-lock.json b/web/package-lock.json index ea0b007b22..c809df444e 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -11,6 +11,7 @@ "@ant-design/pro-layout": "^7.17.16", "@antv/g6": "^5.0.10", "@js-preview/excel": "^1.7.8", + "@monaco-editor/react": "^4.6.0", "@tanstack/react-query": "^5.40.0", "@tanstack/react-query-devtools": "^5.51.5", "ahooks": "^3.7.10", @@ -3843,6 +3844,30 @@ "resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/@monaco-editor/loader": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/@monaco-editor/loader/-/loader-1.4.0.tgz", + "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", + "dependencies": { + "state-local": "^1.0.6" + }, + "peerDependencies": { + "monaco-editor": ">= 0.21.0 < 1" + } + }, + "node_modules/@monaco-editor/react": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/@monaco-editor/react/-/react-4.6.0.tgz", + "integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==", + "dependencies": { + "@monaco-editor/loader": "^1.4.0" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmmirror.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -19956,6 +19981,12 @@ "node": "*" } }, + "node_modules/monaco-editor": { + "version": "0.52.0", + "resolved": "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.52.0.tgz", + "integrity": "sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==", + "peer": true + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/mri/-/mri-1.2.0.tgz", @@ -25827,6 +25858,11 @@ "resolved": "https://registry.npmmirror.com/stackframe/-/stackframe-1.3.4.tgz", "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" }, + "node_modules/state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" + }, "node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmmirror.com/static-extend/-/static-extend-0.1.2.tgz", diff --git a/web/package.json b/web/package.json index e4ecbb5018..c0493cd177 100644 --- a/web/package.json +++ b/web/package.json @@ -22,6 +22,7 @@ "@ant-design/pro-layout": "^7.17.16", "@antv/g6": "^5.0.10", "@js-preview/excel": "^1.7.8", + "@monaco-editor/react": "^4.6.0", "@tanstack/react-query": "^5.40.0", "@tanstack/react-query-devtools": "^5.51.5", "ahooks": "^3.7.10", diff --git a/web/src/assets/svg/invoke-ai.svg b/web/src/assets/svg/invoke-ai.svg new file mode 100644 index 0000000000..783fad8132 --- /dev/null +++ b/web/src/assets/svg/invoke-ai.svg @@ -0,0 +1,15 @@ + + + \ No newline at end of file diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 402f9b2c85..6ed87c5b69 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -29,6 +29,7 @@ export default { move: 'Move', warn: 'Warn', action: 'Action', + s: 'S', }, login: { login: 'Sign in', @@ -1016,6 +1017,13 @@ The above is the content you need to summarize.`, note: 'Note', noteDescription: 'Note', notePlaceholder: 'Please enter a note', + invoke: 'Invoke', + invokeDescription: + 'This component can invoke remote end point call. Put the output of other components as parameters or set constant parameters to call remote functions.', + url: 'Url', + method: 'Method', + timeout: 'Timeout', + headers: 'Headers', }, footer: { profile: 'All rights reserved @ React', diff --git a/web/src/locales/zh-traditional.ts b/web/src/locales/zh-traditional.ts index 9335c3619d..2d33907c8a 100644 --- a/web/src/locales/zh-traditional.ts +++ b/web/src/locales/zh-traditional.ts @@ -29,6 +29,7 @@ export default { move: '移動', warn: '提醒', action: '操作', + s: '秒', }, login: { login: '登入', @@ -965,6 +966,13 @@ export default { note: '註解', noteDescription: '註解', notePlaceholder: '請輸入註釋', + invoke: 'Invoke', + invokeDescription: + '此元件可以呼叫遠端端點呼叫。將其他元件的輸出作為參數或設定常數參數來呼叫遠端函數。', + url: '網址', + method: '方法', + timeout: '超時', + headers: '請求頭', }, footer: { profile: '“保留所有權利 @ react”', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index e0a32171cc..30f65f9151 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -29,6 +29,7 @@ export default { move: '移动', warn: '提醒', action: '操作', + s: '秒', }, login: { login: '登录', @@ -985,6 +986,13 @@ export default { note: '注释', noteDescription: '注释', notePlaceholder: '请输入注释', + invoke: 'Invoke', + invokeDescription: + '该组件可以调用远程端点调用。将其他组件的输出作为参数或设置常量参数来调用远程函数。', + url: 'Url', + method: '方法', + timeout: '超时', + headers: '请求头', }, footer: { profile: 'All rights reserved @ React', diff --git a/web/src/pages/flow/constant.tsx b/web/src/pages/flow/constant.tsx index 2874b2135d..2131bfa3c0 100644 --- a/web/src/pages/flow/constant.tsx +++ b/web/src/pages/flow/constant.tsx @@ -12,6 +12,7 @@ import { ReactComponent as ExeSqlIcon } from '@/assets/svg/exesql.svg'; import { ReactComponent as GithubIcon } from '@/assets/svg/github.svg'; import { ReactComponent as GoogleScholarIcon } from '@/assets/svg/google-scholar.svg'; import { ReactComponent as GoogleIcon } from '@/assets/svg/google.svg'; +import { ReactComponent as InvokeIcon } from '@/assets/svg/invoke-ai.svg'; import { ReactComponent as Jin10Icon } from '@/assets/svg/jin10.svg'; import { ReactComponent as KeywordIcon } from '@/assets/svg/keyword.svg'; import { ReactComponent as NoteIcon } from '@/assets/svg/note.svg'; @@ -75,6 +76,7 @@ export enum Operator { TuShare = 'TuShare', Note = 'Note', Crawler = 'Crawler', + Invoke = 'Invoke', } export const CommonOperatorList = Object.values(Operator).filter( @@ -113,6 +115,7 @@ export const operatorIconMap = { [Operator.TuShare]: TuShareIcon, [Operator.Note]: NoteIcon, [Operator.Crawler]: CrawlerIcon, + [Operator.Invoke]: InvokeIcon, }; export const operatorMap: Record< @@ -239,6 +242,9 @@ export const operatorMap: Record< [Operator.Crawler]: { backgroundColor: '#dee0e2', }, + [Operator.Invoke]: { + backgroundColor: '#dee0e2', + }, }; export const componentMenuList = [ @@ -332,6 +338,9 @@ export const componentMenuList = [ { name: Operator.Crawler, }, + { + name: Operator.Invoke, + }, ]; export const initialRetrievalValues = { @@ -509,6 +518,18 @@ export const initialCrawlerValues = { extract_type: 'markdown', }; +export const initialInvokeValues = { + url: 'http://', + method: 'GET', + timeout: 60, + headers: `{ + "Accept": "*/*", + "Cache-Control": "no-cache", + "Connection": "keep-alive" +}`, + proxy: 'http://', +}; + export const CategorizeAnchorPointPositions = [ { top: 1, right: 34 }, { top: 8, right: 18 }, @@ -621,6 +642,7 @@ export const NodeMap = { [Operator.TuShare]: 'ragNode', [Operator.Note]: 'noteNode', [Operator.Crawler]: 'ragNode', + [Operator.Invoke]: 'ragNode', }; export const LanguageOptions = [ diff --git a/web/src/pages/flow/flow-drawer/index.tsx b/web/src/pages/flow/flow-drawer/index.tsx index e85976bc9d..979e6e44a3 100644 --- a/web/src/pages/flow/flow-drawer/index.tsx +++ b/web/src/pages/flow/flow-drawer/index.tsx @@ -20,6 +20,7 @@ import GenerateForm from '../form/generate-form'; import GithubForm from '../form/github-form'; import GoogleForm from '../form/google-form'; import GoogleScholarForm from '../form/google-scholar-form'; +import InvokeForm from '../form/invoke-form'; import Jin10Form from '../form/jin10-form'; import KeywordExtractForm from '../form/keyword-extract-form'; import MessageForm from '../form/message-form'; @@ -74,6 +75,9 @@ const FormMap = { [Operator.Jin10]: Jin10Form, [Operator.TuShare]: TuShareForm, [Operator.Crawler]: CrawlerForm, + [Operator.Invoke]: InvokeForm, + [Operator.Concentrator]: <>>, + [Operator.Note]: <>>, }; const EmptyContent = () =>
; diff --git a/web/src/pages/flow/form/invoke-form/dynamic-variables.tsx b/web/src/pages/flow/form/invoke-form/dynamic-variables.tsx new file mode 100644 index 0000000000..edb6ed9b0a --- /dev/null +++ b/web/src/pages/flow/form/invoke-form/dynamic-variables.tsx @@ -0,0 +1,119 @@ +import { EditableCell, EditableRow } from '@/components/editable-cell'; +import { useTranslate } from '@/hooks/common-hooks'; +import { DeleteOutlined } from '@ant-design/icons'; +import { Button, Flex, Input, Select, Table, TableProps } from 'antd'; +import { useBuildComponentIdSelectOptions } from '../../hooks'; +import { IInvokeVariable } from '../../interface'; +import { useHandleOperateParameters } from './hooks'; + +import { trim } from 'lodash'; +import styles from './index.less'; + +interface IProps { + nodeId?: string; +} + +const components = { + body: { + row: EditableRow, + cell: EditableCell, + }, +}; + +const DynamicVariables = ({ nodeId }: IProps) => { + const { t } = useTranslate('flow'); + + const options = useBuildComponentIdSelectOptions(nodeId); + const { + dataSource, + handleAdd, + handleRemove, + handleSave, + handleComponentIdChange, + handleValueChange, + } = useHandleOperateParameters(nodeId!); + + const columns: TableProps