diff --git a/client/public/imgs/module/http.png b/client/public/imgs/module/http.png new file mode 100644 index 000000000..dca870cc0 Binary files /dev/null and b/client/public/imgs/module/http.png differ diff --git a/client/public/locales/en/common.json b/client/public/locales/en/common.json index e296efe6f..b5b8a774f 100644 --- a/client/public/locales/en/common.json +++ b/client/public/locales/en/common.json @@ -9,7 +9,9 @@ "Confirm Save App Tip": "After saving, the advanced orchestration configuration will be overwritten. Make sure that the application does not use advanced orchestration.", "Connection is invalid": "Connecting is invalid", "Connection type is different": "Connection type is different", - "My Apps": "My Apps" + "Input Field Settings": "Input Field Settings", + "My Apps": "My Apps", + "Output Field Settings": "Output Field Settings" }, "chat": { "Confirm to clear history": "Confirm to clear history?", @@ -39,28 +41,28 @@ "Tools": "Tools" }, "user": { + "Account": "Account", + "Application Name": "Application Name", + "Avatar": "Avatar", + "Balance": "Balance", "Bill Detail": "Bill Detail", + "Change": "Change", + "Notice": "Notice", "Old password is error": "Old password is error", "OpenAI Account Setting": "OpenAI Account Setting", + "Password": "Password", "Pay": "Pay", + "Personal Information": "Personal", + "Recharge Record": "Recharge", + "Replace": "Replace", "Set OpenAI Account Failed": "Set OpenAI account failed", + "Sign Out": "Sign Out", + "Source": "Source", + "Time": "Time", + "Total Amount": "Total Amount", "Update Password": "Update Password", "Update password failed": "Update password failed", "Update password succseful": "Update password succseful", - "Personal Information": "Personal", - "Usage Record": "Usage", - "Recharge Record": "Recharge", - "Notice": "Notice", - "Sign Out": "Sign Out", - "Avatar": "Avatar", - "Account": "Account", - "Balance": "Balance", - "Time": "Time", - "Source": "Source", - "Application Name": "Application Name", - "Total Amount": "Total Amount", - "Change": "Change", - "Password": "Password", - "Replace": "Replace" + "Usage Record": "Usage" } -} \ No newline at end of file +} diff --git a/client/public/locales/zh/common.json b/client/public/locales/zh/common.json index d776bc4db..0850d3cb1 100644 --- a/client/public/locales/zh/common.json +++ b/client/public/locales/zh/common.json @@ -9,7 +9,9 @@ "Confirm Save App Tip": "保存后将会覆盖高级编排配置,请确保该应用未使用高级编排功能。", "Connection is invalid": "连接无效", "Connection type is different": "连接的类型不一致", - "My Apps": "我的应用" + "Input Field Settings": "输入字段编辑", + "My Apps": "我的应用", + "Output Field Settings": "输出字段编辑" }, "chat": { "Confirm to clear history": "确认清空该应用的聊天记录?", @@ -39,28 +41,28 @@ "Tools": "工具" }, "user": { + "Account": "账号", + "Application Name": "应用名", + "Avatar": "头像", + "Balance": "余额", "Bill Detail": "账单详情", + "Change": "变更", + "Notice": "通知", "Old password is error": "旧密码错误", "OpenAI Account Setting": "OpenAI 账号配置", + "Password": "密码", "Pay": "充值", + "Personal Information": "个人信息", + "Recharge Record": "充值记录", + "Replace": "更换", "Set OpenAI Account Failed": "设置 OpenAI 账号异常", + "Sign Out": "登出", + "Source": "来源", + "Time": "时间", + "Total Amount": "总金额", "Update Password": "修改密码", "Update password failed": "修改密码异常", "Update password succseful": "修改密码成功", - "Personal Information": "个人信息", - "Usage Record": "使用记录", - "Recharge Record": "充值记录", - "Notice": "通知", - "Sign Out": "登出", - "Avatar": "头像", - "Account": "账号", - "Balance": "余额", - "Time": "时间", - "Source": "来源", - "Application Name": "应用名", - "Total Amount": "总金额", - "Change": "变更", - "Password": "密码", - "Replace": "更换" + "Usage Record": "使用记录" } -} \ No newline at end of file +} diff --git a/client/src/components/Icon/icons/circle/add.svg b/client/src/components/Icon/icons/circle/add.svg new file mode 100644 index 000000000..7c4fd5cd1 --- /dev/null +++ b/client/src/components/Icon/icons/circle/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/components/Icon/icons/withdraw.svg b/client/src/components/Icon/icons/withdraw.svg deleted file mode 100644 index c7cc52da5..000000000 --- a/client/src/components/Icon/icons/withdraw.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/components/Icon/index.tsx b/client/src/components/Icon/index.tsx index ed6a745e0..1c12299dd 100644 --- a/client/src/components/Icon/index.tsx +++ b/client/src/components/Icon/index.tsx @@ -8,7 +8,6 @@ const map = { copy: require('./icons/copy.svg').default, chatSend: require('./icons/chatSend.svg').default, delete: require('./icons/delete.svg').default, - withdraw: require('./icons/withdraw.svg').default, stop: require('./icons/stop.svg').default, collectionLight: require('./icons/collectionLight.svg').default, collectionSolid: require('./icons/collectionSolid.svg').default, @@ -72,7 +71,8 @@ const map = { language_en: require('./icons/language/en.svg').default, language_zh: require('./icons/language/zh.svg').default, outlink_share: require('./icons/outlink/share.svg').default, - outlink_iframe: require('./icons/outlink/iframe.svg').default + outlink_iframe: require('./icons/outlink/iframe.svg').default, + addCircle: require('./icons/circle/add.svg').default }; export type IconName = keyof typeof map; diff --git a/client/src/constants/flow/ModuleTemplate.ts b/client/src/constants/flow/ModuleTemplate.ts index f2a3c868d..3bbe94a4b 100644 --- a/client/src/constants/flow/ModuleTemplate.ts +++ b/client/src/constants/flow/ModuleTemplate.ts @@ -15,7 +15,7 @@ import { Input_Template_TFSwitch, Input_Template_UserChatInput } from './inputTemplate'; -import { ContextExtractEnum } from './flowField'; +import { ContextExtractEnum, HttpPropsEnum } from './flowField'; export const ChatModelSystemTip = '模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}'; @@ -448,6 +448,34 @@ export const ContextExtractModule: FlowModuleTemplateType = { } ] }; +export const HttpModule: FlowModuleTemplateType = { + logo: '/imgs/module/http.png', + name: 'HTTP模块', + intro: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)', + description: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)', + flowType: FlowModuleTypeEnum.httpRequest, + inputs: [ + { + key: HttpPropsEnum.url, + value: '', + type: FlowInputItemTypeEnum.input, + label: '请求地址', + description: '请求目标地址', + placeholder: 'https://api.fastgpt.run/getInventory', + required: true + }, + Input_Template_TFSwitch + ], + outputs: [ + { + key: HttpPropsEnum.finish, + label: '请求结束', + valueType: FlowValueTypeEnum.boolean, + type: FlowOutputItemTypeEnum.source, + targets: [] + } + ] +}; export const EmptyModule: FlowModuleTemplateType = { logo: '/imgs/module/cq.png', name: '该模块已被移除', @@ -477,7 +505,7 @@ export const ModuleTemplates = [ }, { label: 'Agent', - list: [ClassifyQuestionModule, ContextExtractModule] + list: [ClassifyQuestionModule, ContextExtractModule, HttpModule] } ]; export const ModuleTemplatesFlat = ModuleTemplates.map((templates) => templates.list)?.flat(); diff --git a/client/src/constants/flow/flowField.ts b/client/src/constants/flow/flowField.ts index 0f7be6037..1cd0885d5 100644 --- a/client/src/constants/flow/flowField.ts +++ b/client/src/constants/flow/flowField.ts @@ -6,3 +6,10 @@ export enum ContextExtractEnum { failed = 'failed', fields = 'fields' } + +export enum HttpPropsEnum { + url = 'url', + finish = 'finish', + body = 'body', + response = 'response' +} diff --git a/client/src/constants/flow/index.ts b/client/src/constants/flow/index.ts index dc7196b19..e9945ee90 100644 --- a/client/src/constants/flow/index.ts +++ b/client/src/constants/flow/index.ts @@ -31,7 +31,8 @@ export enum FlowModuleTypeEnum { tfSwitchNode = 'tfSwitchNode', answerNode = 'answerNode', classifyQuestion = 'classifyQuestion', - contentExtract = 'contentExtract' + contentExtract = 'contentExtract', + httpRequest = 'httpRequest' } export enum SpecialInputKeyEnum { diff --git a/client/src/pages/api/admin/initv4.ts b/client/src/pages/api/admin/initv4.ts index 213a00d6c..e180ae581 100644 --- a/client/src/pages/api/admin/initv4.ts +++ b/client/src/pages/api/admin/initv4.ts @@ -3,9 +3,9 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; import { authUser } from '@/service/utils/auth'; import { connectToDatabase, App } from '@/service/mongo'; -import { AppModuleInputItemType } from '@/types/app'; import { FlowModuleTypeEnum, SpecialInputKeyEnum } from '@/constants/flow'; import { TaskResponseKeyEnum } from '@/constants/chat'; +import { FlowInputItemType } from '@/types/flow'; const chatModelInput = ({ model, @@ -21,7 +21,7 @@ const chatModelInput = ({ systemPrompt: string; limitPrompt: string; kbList: { kbId: string }[]; -}): AppModuleInputItemType[] => [ +}): FlowInputItemType[] => [ { key: 'model', value: model, diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeCQNode.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeCQNode.tsx index 1720f95e2..425aabd17 100644 --- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeCQNode.tsx +++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeCQNode.tsx @@ -27,7 +27,8 @@ const NodeCQNode = ({ CustomComponent={{ [SpecialInputKeyEnum.agents]: ({ key: agentKey, - value: agents = [] + value: agents = [], + ...props }: { key: string; value?: ClassifyQuestionAgentItemType[]; @@ -50,7 +51,11 @@ const NodeCQNode = ({ moduleId, type: 'inputs', key: agentKey, - value: newInputValue + value: { + ...props, + key: agentKey, + value: newInputValue + } }); onChangeNode({ moduleId, @@ -77,8 +82,13 @@ const NodeCQNode = ({ ); onChangeNode({ moduleId, + type: 'inputs', key: agentKey, - value: newVal + value: { + ...props, + key: agentKey, + value: newVal + } }); }} /> @@ -97,11 +107,16 @@ const NodeCQNode = ({ type: FlowOutputItemTypeEnum.hidden, targets: [] }); + onChangeNode({ moduleId, type: 'inputs', key: agentKey, - value: newInputValue + value: { + ...props, + key: agentKey, + value: newInputValue + } }); onChangeNode({ moduleId, diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeChat.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeChat.tsx index 5c7c1c32f..e8e6386bd 100644 --- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeChat.tsx +++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeChat.tsx @@ -48,33 +48,32 @@ const NodeChat = ({ onchange={(e) => { onChangeNode({ moduleId, + type: 'inputs', key: inputItem.key, - value: e + value: { + ...inputItem, + value: e + } }); + // update max tokens - const model = chatModelList.find((item) => item.model === e); + const model = + chatModelList.find((item) => item.model === e) || chatModelList[0]; if (!model) return; onChangeNode({ moduleId, + type: 'inputs', key: 'maxToken', - valueKey: 'markList', - value: [ - { label: '100', value: 100 }, - { label: `${model.contextMaxToken}`, value: model.contextMaxToken } - ] - }); - onChangeNode({ - moduleId, - key: 'maxToken', - valueKey: 'max', - value: model.contextMaxToken - }); - onChangeNode({ - moduleId, - key: 'maxToken', - valueKey: 'value', - value: model.contextMaxToken / 2 + value: { + ...inputs.find((input) => input.key === 'maxToken'), + markList: [ + { label: '100', value: 100 }, + { label: `${model.contextMaxToken}`, value: model.contextMaxToken } + ], + max: model.contextMaxToken, + value: model.contextMaxToken / 2 + } }); }} /> @@ -100,8 +99,12 @@ const NodeChat = ({ onChange={(e) => { onChangeNode({ moduleId, + type: 'inputs', key: inputItem.key, - value: e + value: { + ...inputItem, + value: e + } }); }} /> @@ -115,7 +118,11 @@ const NodeChat = ({ <> - + )} diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx index 4eaf07273..b06cc512b 100644 --- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx +++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx @@ -31,10 +31,9 @@ const NodeExtract = ({ flowInputList={inputs} CustomComponent={{ [ContextExtractEnum.extractKeys]: ({ - key, - value: extractKeys = [] + value: extractKeys = [], + ...props }: { - key: string; value?: ContextExtractAgentItemType[]; }) => ( @@ -97,7 +96,10 @@ const NodeExtract = ({ moduleId, type: 'inputs', key: ContextExtractEnum.extractKeys, - value: newInputValue + value: { + ...props, + value: newInputValue + } }); onChangeNode({ moduleId, @@ -121,7 +123,7 @@ const NodeExtract = ({ - + {!!editExtractFiled && ( @@ -160,7 +162,10 @@ const NodeExtract = ({ moduleId, type: 'inputs', key: ContextExtractEnum.extractKeys, - value: newInputs + value: { + ...inputs.find((input) => input.key === ContextExtractEnum.extractKeys), + value: newInputs + } }); onChangeNode({ moduleId, diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHistory.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHistory.tsx index 0836a55c3..cf50c0825 100644 --- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHistory.tsx +++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHistory.tsx @@ -18,7 +18,11 @@ const NodeHistory = ({ - + ); diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHttp.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHttp.tsx new file mode 100644 index 000000000..656f4144a --- /dev/null +++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHttp.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { NodeProps } from 'reactflow'; +import NodeCard from '../modules/NodeCard'; +import { FlowModuleItemType } from '@/types/flow'; +import Divider from '../modules/Divider'; +import Container from '../modules/Container'; +import RenderInput from '../render/RenderInput'; +import { Box, Button } from '@chakra-ui/react'; +import { SmallAddIcon } from '@chakra-ui/icons'; +import RenderOutput from '../render/RenderOutput'; + +import { FlowInputItemTypeEnum, FlowOutputItemTypeEnum, FlowValueTypeEnum } from '@/constants/flow'; +import { customAlphabet } from 'nanoid'; +const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6); + +const NodeHttp = ({ + data: { moduleId, inputs, outputs, onChangeNode, ...props } +}: NodeProps) => { + return ( + + + + + + + + + + + + + + ); +}; +export default React.memo(NodeHttp); diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeKbSearch.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeKbSearch.tsx index bb621d55a..80eed4df5 100644 --- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeKbSearch.tsx +++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeKbSearch.tsx @@ -81,14 +81,19 @@ const NodeKbSearch = ({ onChangeNode={onChangeNode} flowInputList={inputs} CustomComponent={{ - kbList: ({ key, value }) => ( + kbList: ({ key, value, ...props }) => ( { onChangeNode({ moduleId, key, - value: e + type: 'inputs', + value: { + ...props, + key, + value: e + } }); }} /> @@ -98,7 +103,7 @@ const NodeKbSearch = ({ - + ); diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeQuestionInput.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeQuestionInput.tsx index bed59d523..f428e382a 100644 --- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeQuestionInput.tsx +++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeQuestionInput.tsx @@ -9,7 +9,7 @@ import { FlowValueTypeEnum } from '@/constants/flow'; import SourceHandle from '../render/SourceHandle'; const QuestionInputNode = ({ - data: { inputs, outputs, onChangeNode, ...props } + data: { inputs, outputs, ...props } }: NodeProps) => { return ( diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeUserGuide.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeUserGuide.tsx index 81d408d61..2b0313805 100644 --- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeUserGuide.tsx +++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeUserGuide.tsx @@ -14,7 +14,7 @@ const NodeUserGuide = ({ data: { inputs, outputs, onChangeNode, ...props } }: NodeProps) => { const welcomeText = useMemo( - () => inputs.find((item) => item.key === SystemInputEnum.welcomeText)?.value, + () => inputs.find((item) => item.key === SystemInputEnum.welcomeText), [inputs] ); @@ -30,22 +30,27 @@ const NodeUserGuide = ({ -