From 5e7c97b7b882a764c0513e7b1f9cfc9ac265b958 Mon Sep 17 00:00:00 2001
From: Archer <545436317@qq.com>
Date: Fri, 20 Sep 2024 11:28:58 +0800
Subject: [PATCH] 4.8.11 test fix (#2746)
* fix: refresh tool param
* perf: load image message
* fix: cannot remoce externalReadUrl
* perf: variables update dom
* perf: empty response tip
* fix: conflict
---
.../content/zh-cn/docs/course/fileInput.md | 2 +-
.../zh-cn/docs/development/openapi/share.md | 2 +-
.../docs/workflow/examples/google_search.md | 2 +-
packages/global/core/ai/prompt/AIChat.ts | 10 +-
packages/service/core/chat/utils.ts | 92 +++--
packages/web/i18n/en/chat.json | 3 +-
packages/web/i18n/zh/chat.json | 3 +-
.../ChatContainer/ChatBox/Input/ChatInput.tsx | 6 +-
.../ChatBox/components/ChatItem.tsx | 2 +-
.../app/src/pages/api/core/dataset/update.ts | 2 +-
.../app/src/pages/api/v1/chat/completions.ts | 2 +-
.../app/detail/components/Plugin/Header.tsx | 6 +-
.../detail/components/SimpleApp/Header.tsx | 6 +-
.../app/detail/components/Workflow/Header.tsx | 7 +-
.../Flow/nodes/NodeVariableUpdate.tsx | 345 +++++++++---------
.../components/WorkflowComponents/context.tsx | 29 +-
.../src/pages/app/list/components/context.tsx | 8 +-
projects/app/src/pages/app/list/index.tsx | 2 +-
.../src/web/common/system/useSystemStore.ts | 10 +
19 files changed, 292 insertions(+), 247 deletions(-)
diff --git a/docSite/content/zh-cn/docs/course/fileInput.md b/docSite/content/zh-cn/docs/course/fileInput.md
index 609fb65b1..d9e9c91bf 100644
--- a/docSite/content/zh-cn/docs/course/fileInput.md
+++ b/docSite/content/zh-cn/docs/course/fileInput.md
@@ -114,7 +114,7 @@ ${content}
它接收一个`string`类型的输入,除了可以引用文档解析结果外,还可以实现自定义内容引用,最终会进行提示词拼接,放置在 role=system 的消息中。提示词模板如下:
```
-将
中的内容作为本次对话的参考内容:
+将
中的内容作为本次对话的参考:
{{quote}}
diff --git a/docSite/content/zh-cn/docs/development/openapi/share.md b/docSite/content/zh-cn/docs/development/openapi/share.md
index 31ad99685..8bd784e59 100644
--- a/docSite/content/zh-cn/docs/development/openapi/share.md
+++ b/docSite/content/zh-cn/docs/development/openapi/share.md
@@ -227,7 +227,7 @@ curl --location --request POST '{{host}}/shareAuth/finish' \
"historyPreview": [
{
"obj": "Human",
- "value": "使用 标记中的内容作为本次对话的参考内容:\n\n\n导演是谁?\n电影《铃芽之旅》的导演是新海诚。\n------\n电影《铃芽之旅》的编剧是谁?22\n新海诚是本片的编剧。\n------\n电影《铃芽之旅》的女主角是谁?\n电影的女主角是铃芽。\n------\n电影《铃芽之旅》的制作团队中有哪位著名人士?2\n川村元气是本片的制作团队成员之一。\n------\n你是谁?\n我是电影《铃芽之旅》助手\n------\n电影《铃芽之旅》男主角是谁?\n电影《铃芽之旅》男主角是宗像草太,由松村北斗配音。\n------\n电影《铃芽之旅》的作者新海诚写了一本小说,叫什么名字?\n小说名字叫《铃芽之旅》。\n------\n电影《铃芽之旅》的女主角是谁?\n电影《铃芽之旅》的女主角是岩户铃芽,由原菜乃华配音。\n------\n电影《铃芽之旅》的故事背景是什么?\n日本\n------\n谁担任电影《铃芽之旅》中岩户环的配音?\n深津绘里担任电影《铃芽之旅》中岩户环的配音。\n\n\n回答要求:\n- 如果你不清楚答案,你需要澄清。\n- 避免提及你是从 获取的知识。\n- 保持答案与 中描述的一致。\n- 使用 Markdown 语法优化回答格式。\n- 使用与问题相同的语言回答。\n\n问题:\"\"\"导演是谁\"\"\""
+ "value": "使用 标记中的内容作为本次对话的参考:\n\n\n导演是谁?\n电影《铃芽之旅》的导演是新海诚。\n------\n电影《铃芽之旅》的编剧是谁?22\n新海诚是本片的编剧。\n------\n电影《铃芽之旅》的女主角是谁?\n电影的女主角是铃芽。\n------\n电影《铃芽之旅》的制作团队中有哪位著名人士?2\n川村元气是本片的制作团队成员之一。\n------\n你是谁?\n我是电影《铃芽之旅》助手\n------\n电影《铃芽之旅》男主角是谁?\n电影《铃芽之旅》男主角是宗像草太,由松村北斗配音。\n------\n电影《铃芽之旅》的作者新海诚写了一本小说,叫什么名字?\n小说名字叫《铃芽之旅》。\n------\n电影《铃芽之旅》的女主角是谁?\n电影《铃芽之旅》的女主角是岩户铃芽,由原菜乃华配音。\n------\n电影《铃芽之旅》的故事背景是什么?\n日本\n------\n谁担任电影《铃芽之旅》中岩户环的配音?\n深津绘里担任电影《铃芽之旅》中岩户环的配音。\n\n\n回答要求:\n- 如果你不清楚答案,你需要澄清。\n- 避免提及你是从 获取的知识。\n- 保持答案与 中描述的一致。\n- 使用 Markdown 语法优化回答格式。\n- 使用与问题相同的语言回答。\n\n问题:\"\"\"导演是谁\"\"\""
},
{
"obj": "AI",
diff --git a/docSite/content/zh-cn/docs/workflow/examples/google_search.md b/docSite/content/zh-cn/docs/workflow/examples/google_search.md
index d74c8f84f..9f01f4fd4 100644
--- a/docSite/content/zh-cn/docs/workflow/examples/google_search.md
+++ b/docSite/content/zh-cn/docs/workflow/examples/google_search.md
@@ -965,7 +965,7 @@ export default async function (ctx: FunctionContext) {
"required": true,
"description": "",
"canEdit": false,
- "value": "请使用下面 中的数据作为本次对话的参考内容。请直接输出答案,不要提及你是从 中获取的知识。\n\n当前时间:{{cTime}}\n\n\n{{response}}\n\n\n我的问题:\"{{q}}\"",
+ "value": "请使用下面 中的数据作为本次对话的参考。请直接输出答案,不要提及你是从 中获取的知识。\n\n当前时间:{{cTime}}\n\n\n{{response}}\n\n\n我的问题:\"{{q}}\"",
"editField": {
"key": true
},
diff --git a/packages/global/core/ai/prompt/AIChat.ts b/packages/global/core/ai/prompt/AIChat.ts
index 6a9d7b075..b0c47cfe9 100644
--- a/packages/global/core/ai/prompt/AIChat.ts
+++ b/packages/global/core/ai/prompt/AIChat.ts
@@ -48,7 +48,7 @@ export const Prompt_userQuotePromptList: PromptTemplateItem[] = [
{
title: i18nT('app:template.standard_template'),
desc: '',
- value: `使用 标记中的内容作为本次对话的参考内容:
+ value: `使用 标记中的内容作为本次对话的参考:
{{quote}}
@@ -83,7 +83,7 @@ export const Prompt_userQuotePromptList: PromptTemplateItem[] = [
{
title: i18nT('app:template.standard_strict'),
desc: '',
- value: `忘记你已有的知识,仅使用 标记中的内容作为本次对话的参考内容:
+ value: `忘记你已有的知识,仅使用 标记中的内容作为本次对话的参考:
{{quote}}
@@ -133,7 +133,7 @@ export const Prompt_systemQuotePromptList: PromptTemplateItem[] = [
{
title: i18nT('app:template.standard_template'),
desc: '',
- value: `使用 标记中的内容作为本次对话的参考内容:
+ value: `使用 标记中的内容作为本次对话的参考:
{{quote}}
@@ -164,7 +164,7 @@ export const Prompt_systemQuotePromptList: PromptTemplateItem[] = [
{
title: i18nT('app:template.standard_strict'),
desc: '',
- value: `忘记你已有的知识,仅使用 标记中的内容作为本次对话的参考内容:
+ value: `忘记你已有的知识,仅使用 标记中的内容作为本次对话的参考:
{{quote}}
@@ -207,7 +207,7 @@ export const Prompt_systemQuotePromptList: PromptTemplateItem[] = [
];
// Document quote prompt
-export const Prompt_DocumentQuote = `将 中的内容作为本次对话的参考内容:
+export const Prompt_DocumentQuote = `将 中的内容作为本次对话的参考:
{{quote}}
diff --git a/packages/service/core/chat/utils.ts b/packages/service/core/chat/utils.ts
index 1212f3ec7..e6492bcb0 100644
--- a/packages/service/core/chat/utils.ts
+++ b/packages/service/core/chat/utils.ts
@@ -8,6 +8,8 @@ import axios from 'axios';
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
import { getFileContentTypeFromHeader, guessBase64ImageType } from '../../common/file/utils';
import { serverRequestBaseUrl } from '../../common/api/serverRequest';
+import { i18nT } from '../../../web/i18n/utils';
+import { addLog } from '../../common/system/log';
/* slice chat context by tokens */
const filterEmptyMessages = (messages: ChatCompletionMessageParam[]) => {
@@ -111,20 +113,62 @@ export const loadRequestMessages = async ({
useVision?: boolean;
origin?: string;
}) => {
+ // Load image to base64
+ const loadImageToBase64 = async (messages: ChatCompletionContentPart[]) => {
+ return Promise.all(
+ messages.map(async (item) => {
+ if (item.type === 'image_url') {
+ // Remove url origin
+ const imgUrl = (() => {
+ if (origin && item.image_url.url.startsWith(origin)) {
+ return item.image_url.url.replace(origin, '');
+ }
+ return item.image_url.url;
+ })();
+
+ // If imgUrl is a local path, load image from local, and set url to base64
+ if (imgUrl.startsWith('/') || process.env.VISION_FOCUS_BASE64 === 'true') {
+ addLog.debug('Load image from local server', {
+ baseUrl: serverRequestBaseUrl,
+ requestUrl: imgUrl
+ });
+ const response = await axios.get(imgUrl, {
+ baseURL: serverRequestBaseUrl,
+ responseType: 'arraybuffer',
+ proxy: false
+ });
+ const base64 = Buffer.from(response.data, 'binary').toString('base64');
+ const imageType =
+ getFileContentTypeFromHeader(response.headers['content-type']) ||
+ guessBase64ImageType(base64);
+
+ return {
+ ...item,
+ image_url: {
+ ...item.image_url,
+ url: `data:${imageType};base64,${base64}`
+ }
+ };
+ }
+ }
+ return item;
+ })
+ );
+ };
// Split question text and image
- function parseStringWithImages(input: string): ChatCompletionContentPart[] {
+ const parseStringWithImages = (input: string): ChatCompletionContentPart[] => {
if (!useVision) {
return [{ type: 'text', text: input || '' }];
}
// 正则表达式匹配图片URL
const imageRegex =
- /(https?:\/\/[^\s/$.?#].[^\s]*\.(?:png|jpe?g|gif|webp|bmp|tiff?|svg|ico|heic|avif))/i;
+ /(https?:\/\/[^\s/$.?#].[^\s]*\.(?:png|jpe?g|gif|webp|bmp|tiff?|svg|ico|heic|avif))/gi;
const result: ChatCompletionContentPart[] = [];
// 提取所有HTTPS图片URL并添加到result开头
- const httpsImages = input.match(imageRegex) || [];
+ const httpsImages = [...new Set(Array.from(input.matchAll(imageRegex), (m) => m[0]))];
httpsImages.forEach((url) => {
result.push({
type: 'image_url',
@@ -137,54 +181,27 @@ export const loadRequestMessages = async ({
// 添加原始input作为文本
result.push({ type: 'text', text: input });
return result;
- }
- // Load image
+ };
+ // Parse user content(text and img)
const parseUserContent = async (content: string | ChatCompletionContentPart[]) => {
if (typeof content === 'string') {
- return parseStringWithImages(content);
+ return loadImageToBase64(parseStringWithImages(content));
}
const result = await Promise.all(
content.map(async (item) => {
if (item.type === 'text') return parseStringWithImages(item.text);
- if (item.type === 'file_url') return;
+ if (item.type === 'file_url') return; // LLM not support file_url
if (!item.image_url.url) return item;
- // Remove url origin
- const imgUrl = (() => {
- if (origin && item.image_url.url.startsWith(origin)) {
- return item.image_url.url.replace(origin, '');
- }
- return item.image_url.url;
- })();
-
- /* Load local image */
- if (imgUrl.startsWith('/')) {
- const response = await axios.get(imgUrl, {
- baseURL: serverRequestBaseUrl,
- responseType: 'arraybuffer'
- });
- const base64 = Buffer.from(response.data, 'binary').toString('base64');
- const imageType =
- getFileContentTypeFromHeader(response.headers['content-type']) ||
- guessBase64ImageType(base64);
-
- return {
- ...item,
- image_url: {
- ...item.image_url,
- url: `data:${imageType};base64,${base64}`
- }
- };
- }
-
return item;
})
);
- return result.flat().filter(Boolean);
+ return loadImageToBase64(result.flat().filter(Boolean) as ChatCompletionContentPart[]);
};
+
// format GPT messages, concat text messages
const clearInvalidMessages = (messages: ChatCompletionMessageParam[]) => {
return messages
@@ -247,7 +264,7 @@ export const loadRequestMessages = async ({
};
if (messages.length === 0) {
- return Promise.reject('core.chat.error.Messages empty');
+ return Promise.reject(i18nT('common:core.chat.error.Messages empty'));
}
// filter messages file
@@ -275,6 +292,7 @@ export const loadRequestMessages = async ({
content: await parseUserContent(item.content)
};
} else if (item.role === ChatCompletionRequestMessageRoleEnum.Assistant) {
+ // remove invalid field
return {
role: item.role,
content: item.content,
diff --git a/packages/web/i18n/en/chat.json b/packages/web/i18n/en/chat.json
index 9e902ff5b..1c3ddf848 100644
--- a/packages/web/i18n/en/chat.json
+++ b/packages/web/i18n/en/chat.json
@@ -19,6 +19,7 @@
"input_guide": "Input Guide",
"input_guide_lexicon": "Lexicon",
"input_guide_tip": "You can set up some preset questions. When the user inputs a question, related questions from these presets will be suggested.",
+ "input_placeholder_phone": "Please enter your question",
"insert_input_guide,_some_data_already_exists": "Duplicate data detected, automatically filtered, {{len}} items inserted",
"is_chatting": "Chatting in progress... please wait until it finishes",
"items": "Items",
@@ -36,4 +37,4 @@
"stream_output": "Stream Output",
"view_citations": "View References",
"web_site_sync": "Web Site Sync"
-}
\ No newline at end of file
+}
diff --git a/packages/web/i18n/zh/chat.json b/packages/web/i18n/zh/chat.json
index 84a7a96f6..add428052 100644
--- a/packages/web/i18n/zh/chat.json
+++ b/packages/web/i18n/zh/chat.json
@@ -19,6 +19,7 @@
"input_guide": "输入引导",
"input_guide_lexicon": "词库",
"input_guide_tip": "可以配置一些预设的问题。在用户输入问题时,会从这些预设问题中获取相关问题进行提示。",
+ "input_placeholder_phone": "输入问题",
"insert_input_guide,_some_data_already_exists": "有重复数据,已自动过滤,共插入 {{len}} 条数据",
"is_chatting": "正在聊天中...请等待结束",
"items": "条",
@@ -36,4 +37,4 @@
"stream_output": "流输出",
"view_citations": "查看引用",
"web_site_sync": "Web站点同步"
-}
\ No newline at end of file
+}
diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx
index 00a859b59..be7053cfc 100644
--- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx
+++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx
@@ -449,7 +449,11 @@ const ChatInput = ({
border: 'none'
}}
placeholder={
- isSpeaking ? t('common:core.chat.Speaking') : t('common:core.chat.Type a message')
+ isSpeaking
+ ? t('common:core.chat.Speaking')
+ : isPc
+ ? t('common:core.chat.Type a message')
+ : t('chat:input_placeholder_phone')
}
resize={'none'}
rows={1}
diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatItem.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatItem.tsx
index e245a6eec..be1af1b85 100644
--- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatItem.tsx
+++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatItem.tsx
@@ -174,7 +174,7 @@ const ChatItem = (props: Props) => {
// Check last group is interactive, Auto add a empty text node(animation)
const lastGroup = groupedValues[groupedValues.length - 1];
- if (isChatting) {
+ if (isChatting || groupedValues.length === 0) {
if (
(lastGroup &&
lastGroup[lastGroup.length - 1] &&
diff --git a/projects/app/src/pages/api/core/dataset/update.ts b/projects/app/src/pages/api/core/dataset/update.ts
index c548c8b47..bcc197d0b 100644
--- a/projects/app/src/pages/api/core/dataset/update.ts
+++ b/projects/app/src/pages/api/core/dataset/update.ts
@@ -72,7 +72,7 @@ async function handler(
...(websiteConfig && { websiteConfig }),
...(status && { status }),
...(intro !== undefined && { intro }),
- ...(externalReadUrl && { externalReadUrl }),
+ ...(externalReadUrl !== undefined && { externalReadUrl }),
// move
...(updatedDefaultPermission !== undefined && {
defaultPermission: updatedDefaultPermission
diff --git a/projects/app/src/pages/api/v1/chat/completions.ts b/projects/app/src/pages/api/v1/chat/completions.ts
index 1a0550d59..6688781fa 100644
--- a/projects/app/src/pages/api/v1/chat/completions.ts
+++ b/projects/app/src/pages/api/v1/chat/completions.ts
@@ -266,7 +266,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
workflowStreamResponse: workflowResponseWrite
});
}
- return Promise.reject('请升级工作流');
+ return Promise.reject('您的工作流版本过低,请重新发布一次');
})();
// save chat
diff --git a/projects/app/src/pages/app/detail/components/Plugin/Header.tsx b/projects/app/src/pages/app/detail/components/Plugin/Header.tsx
index 816b4df04..2247d42a3 100644
--- a/projects/app/src/pages/app/detail/components/Plugin/Header.tsx
+++ b/projects/app/src/pages/app/detail/components/Plugin/Header.tsx
@@ -67,7 +67,7 @@ const Header = () => {
future,
setPast
} = useContextSelector(WorkflowContext, (v) => v);
- const { appType } = useSystemStore();
+ const { lastAppListRouteType } = useSystemStore();
const [isPublished, setIsPublished] = useState(false);
useDebounceEffect(
@@ -138,11 +138,11 @@ const Header = () => {
pathname: '/app/list',
query: {
parentId: appDetail.parentId,
- type: appType
+ type: lastAppListRouteType
}
});
} catch (error) {}
- }, [appDetail._id, appDetail.parentId, router]);
+ }, [appDetail._id, appDetail.parentId, lastAppListRouteType, router]);
const Render = useMemo(() => {
return (
diff --git a/projects/app/src/pages/app/detail/components/SimpleApp/Header.tsx b/projects/app/src/pages/app/detail/components/SimpleApp/Header.tsx
index 17f893262..312322ca5 100644
--- a/projects/app/src/pages/app/detail/components/SimpleApp/Header.tsx
+++ b/projects/app/src/pages/app/detail/components/SimpleApp/Header.tsx
@@ -37,7 +37,7 @@ const Header = ({
const router = useRouter();
const { toast } = useToast();
const { appId, appDetail, onSaveApp, currentTab } = useContextSelector(AppContext, (v) => v);
- const { appType } = useSystemStore();
+ const { lastAppListRouteType } = useSystemStore();
const { data: paths = [] } = useRequest2(() => getAppFolderPath(appId), {
manual: false,
@@ -49,11 +49,11 @@ const Header = ({
pathname: '/app/list',
query: {
parentId,
- type: appType
+ type: lastAppListRouteType
}
});
},
- [router, appType]
+ [router, lastAppListRouteType]
);
const isPublished = useMemo(() => {
diff --git a/projects/app/src/pages/app/detail/components/Workflow/Header.tsx b/projects/app/src/pages/app/detail/components/Workflow/Header.tsx
index fc6d2cf2b..9019f70b3 100644
--- a/projects/app/src/pages/app/detail/components/Workflow/Header.tsx
+++ b/projects/app/src/pages/app/detail/components/Workflow/Header.tsx
@@ -67,7 +67,8 @@ const Header = () => {
future,
setPast
} = useContextSelector(WorkflowContext, (v) => v);
- const { appType } = useSystemStore();
+
+ const { lastAppListRouteType } = useSystemStore();
// Check if the workflow is published
const [isPublished, setIsPublished] = useState(false);
@@ -139,11 +140,11 @@ const Header = () => {
pathname: '/app/list',
query: {
parentId: appDetail.parentId,
- type: appType
+ type: lastAppListRouteType
}
});
} catch (error) {}
- }, [appDetail._id, appDetail.parentId, router]);
+ }, [appDetail._id, appDetail.parentId, lastAppListRouteType, router]);
const Render = useMemo(() => {
return (
diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeVariableUpdate.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeVariableUpdate.tsx
index f99f08d78..af889da30 100644
--- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeVariableUpdate.tsx
+++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeVariableUpdate.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import NodeCard from './render/NodeCard';
import { NodeProps } from 'reactflow';
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
@@ -12,7 +12,8 @@ import {
NumberInput,
NumberInputField,
NumberInputStepper,
- Switch
+ Switch,
+ Textarea
} from '@chakra-ui/react';
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
@@ -33,7 +34,7 @@ import { getRefData } from '@/web/core/workflow/utils';
import { isReferenceValue } from '@fastgpt/global/core/workflow/utils';
import { AppContext } from '@/pages/app/detail/components/context';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
-import { useCreation } from 'ahooks';
+import { useCreation, useMemoizedFn } from 'ahooks';
import { getEditorVariables } from '../../utils';
const NodeVariableUpdate = ({ data, selected }: NodeProps) => {
@@ -45,6 +46,19 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps) =>
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
+ const menuList = useRef([
+ {
+ renderType: FlowNodeInputTypeEnum.input,
+ icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
+ label: t('common:core.workflow.inputType.Manual input')
+ },
+ {
+ renderType: FlowNodeInputTypeEnum.reference,
+ icon: FlowNodeInputMap[FlowNodeInputTypeEnum.reference].icon,
+ label: t('common:core.workflow.inputType.Reference')
+ }
+ ]);
+
const variables = useCreation(() => {
return getEditorVariables({
nodeId,
@@ -80,195 +94,182 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps) =>
[inputs, nodeId, onChangeNode]
);
- const Render = useMemo(() => {
- const menuList = [
- {
- renderType: FlowNodeInputTypeEnum.input,
- icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
- label: t('common:core.workflow.inputType.Manual input')
- },
- {
- renderType: FlowNodeInputTypeEnum.reference,
- icon: FlowNodeInputMap[FlowNodeInputTypeEnum.reference].icon,
- label: t('common:core.workflow.inputType.Reference')
- }
- ];
+ const ValueRender = useMemoizedFn(
+ ({ updateItem, index }: { updateItem: TUpdateListItem; index: number }) => {
+ const { valueType } = getRefData({
+ variable: updateItem.variable,
+ nodeList,
+ chatConfig: appDetail.chatConfig
+ });
+ const renderTypeData = menuList.current.find(
+ (item) => item.renderType === updateItem.renderType
+ );
- return (
- <>
- {updateList.map((updateItem, index) => {
- const { valueType } = getRefData({
- variable: updateItem.variable,
- nodeList,
- chatConfig: appDetail.chatConfig
- });
- const renderTypeData = menuList.find((item) => item.renderType === updateItem.renderType);
- const handleUpdate = (newValue: ReferenceValueProps | string) => {
- if (isReferenceValue(newValue)) {
- onUpdateList(
- updateList.map((update, i) =>
- i === index ? { ...update, value: newValue as ReferenceValueProps } : update
- )
- );
- } else {
- onUpdateList(
- updateList.map((update, i) =>
- i === index ? { ...update, value: ['', newValue as string] } : update
- )
- );
- }
- };
+ const handleUpdate = (newValue: ReferenceValueProps | string) => {
+ if (isReferenceValue(newValue)) {
+ onUpdateList(
+ updateList.map((update, i) =>
+ i === index ? { ...update, value: newValue as ReferenceValueProps } : update
+ )
+ );
+ } else {
+ onUpdateList(
+ updateList.map((update, i) =>
+ i === index ? { ...update, value: ['', newValue as string] } : update
+ )
+ );
+ }
+ };
- return (
-
-
- {t('common:core.workflow.variable')}
- {
+ return (
+
+
+ {t('common:core.workflow.variable')}
+ {
+ onUpdateList(
+ updateList.map((update, i) => {
+ if (i === index) {
+ return {
+ ...update,
+ value: ['', ''],
+ valueType,
+ variable: value
+ };
+ }
+ return update;
+ })
+ );
+ }}
+ />
+
+ {updateList.length > 1 && (
+ {
+ onUpdateList(updateList.filter((_, i) => i !== index));
+ }}
+ />
+ )}
+
+
+
+ {t('common:core.workflow.value')}
+ item.renderType === updateItem.renderType)?.label
+ }
+ >
+
+
+
+
+ {/* Render input components */}
+ {(() => {
+ if (updateItem.renderType === FlowNodeInputTypeEnum.reference) {
+ return (
+
- )}
-
-
-
- {t('common:core.workflow.value')}
- item.renderType === updateItem.renderType)?.label
- }
- >
-
-
-
-
- {/* Render input components */}
- {(() => {
- if (updateItem.renderType === FlowNodeInputTypeEnum.reference) {
- return (
-
- );
- }
- if (valueType === WorkflowIOValueTypeEnum.string) {
- return (
-
-
-
- );
- }
- if (valueType === WorkflowIOValueTypeEnum.number) {
- return (
-
- handleUpdate(e.target.value)}
- />
-
-
-
-
-
- );
- }
- if (valueType === WorkflowIOValueTypeEnum.boolean) {
- return (
- handleUpdate(String(e.target.checked))}
- />
- );
- }
-
- return (
- {
- handleUpdate(e);
- }}
+ );
+ }
+ if (valueType === WorkflowIOValueTypeEnum.string) {
+ return (
+
+
- );
- })()}
-
-
- );
- })}
- >
- );
- }, [appDetail.chatConfig, nodeId, nodeList, onUpdateList, t, updateList, variables]);
+
+ );
+ }
+ if (valueType === WorkflowIOValueTypeEnum.number) {
+ return (
+
+ handleUpdate(e.target.value)} />
+
+
+
+
+
+ );
+ }
+ if (valueType === WorkflowIOValueTypeEnum.boolean) {
+ return (
+ handleUpdate(String(e.target.checked))}
+ />
+ );
+ }
+
+ return (
+
+
+
+ );
+ })()}
+
+
+ );
+ }
+ );
return (
- {Render}
+ <>
+ {updateList.map((updateItem, index) => (
+
+ ))}
+ >