4.8 test fix (#1385)

* fix: tool name cannot startwith number

* fix: chatbox update

* fix: chatbox

* perf: drag ui

* perf: drag component

* drag component
This commit is contained in:
Archer
2024-05-07 18:41:34 +08:00
committed by GitHub
parent 2a99e46353
commit fef1a1702b
16 changed files with 203 additions and 118 deletions

View File

@@ -1,5 +1,5 @@
--- ---
title: 'V4.8(进行中)' title: 'V4.8(开发中)'
description: 'FastGPT V4.8 更新说明' description: 'FastGPT V4.8 更新说明'
icon: 'upgrade' icon: 'upgrade'
draft: false draft: false
@@ -18,10 +18,14 @@ FastGPT workflow V2上线支持更加简洁的工作流模式。
## V4.8 更新说明 ## V4.8 更新说明
1. 重构 - 工作流 1. 重构 - 工作流
2. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流 2. 新增 - 判断器。支持 if elseIf else 判断
3. 新增 - 定时执行应用。可轻松实现定时任务 3. 新增 - 变量更新节点。支持更新运行中工作流输出变量,或更新全局变量
4. 新增 - 插件自定义输入优化,可以渲染输入组件 4. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流
6. 优化 - 工作流连线,可以四向连接,方便构建循环工作流 5. 新增 - 定时执行应用。可轻松实现定时任务
7. 优化 - 工作流上下文传递,性能🚀 6. 新增 - 插件自定义输入优化,可以渲染输入组件
8. 优化 - 简易模式,更新配置后自动更新调试框内容,无需保存 7. 优化 - 工作流连线,可以四向连接,方便构建循环工作流
9. 优化 - worker进程管理并将计算 Token 任务分配给 worker 进程 8. 优化 - 工作流上下文传递,性能🚀
9. 优化 - 简易模式,更新配置后自动更新调试框内容,无需保存。
10. 优化 - worker进程管理并将计算 Token 任务分配给 worker 进程。
11. 修复 - 工具调用时候name不能是数字开头随机数有概率数字开头
12. 修复 - 分享链接, query 全局变量会被缓存。

View File

@@ -50,8 +50,18 @@ export const replaceSensitiveText = (text: string) => {
return text; return text;
}; };
/* Make sure the first letter is definitely lowercase */
export const getNanoid = (size = 12) => { export const getNanoid = (size = 12) => {
return customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', size)(); const firstChar = customAlphabet('abcdefghijklmnopqrstuvwxyz', 1)();
if (size === 1) return firstChar;
const randomsStr = customAlphabet(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
size - 1
)();
return `${firstChar}${randomsStr}`;
}; };
export const replaceRegChars = (text: string) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); export const replaceRegChars = (text: string) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

View File

@@ -9,9 +9,10 @@ export const Input_Template_History: FlowNodeInputItemType = {
renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference], renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.chatHistory, valueType: WorkflowIOValueTypeEnum.chatHistory,
label: 'core.module.input.label.chat history', label: 'core.module.input.label.chat history',
description: '最多携带多少轮对话记录',
required: true, required: true,
min: 0, min: 0,
max: 30, max: 50,
value: 6 value: 6
}; };

View File

@@ -0,0 +1,14 @@
import { DragHandleIcon } from '@chakra-ui/icons';
import { Box } from '@chakra-ui/react';
import React from 'react';
import { DraggableProvided } from 'react-beautiful-dnd';
const DragIcon = ({ provided }: { provided: DraggableProvided }) => {
return (
<Box {...provided.dragHandleProps}>
<DragHandleIcon color={'myGray.500'} _hover={{ color: 'primary.600' }} />
</Box>
);
};
export default DragIcon;

View File

@@ -0,0 +1,61 @@
import { Box } from '@chakra-ui/react';
import React, { useState } from 'react';
import {
DragDropContext,
DroppableProps,
Droppable,
DraggableChildrenFn,
DragStart,
DropResult
} from 'react-beautiful-dnd';
type Props<T = any> = {
onDragEndCb: (result: T[]) => void;
renderClone?: DraggableChildrenFn;
children: DroppableProps['children'];
dataList: T[];
};
function DndDrag<T>({ children, renderClone, onDragEndCb, dataList }: Props<T>) {
const [draggingItemHeight, setDraggingItemHeight] = useState(0);
const onDragStart = (start: DragStart) => {
const draggingNode = document.querySelector(`[data-rbd-draggable-id="${start.draggableId}"]`);
setDraggingItemHeight(draggingNode?.getBoundingClientRect().height || 0);
};
const onDragEnd = (result: DropResult) => {
if (!result.destination) {
return;
}
setDraggingItemHeight(0);
const startIndex = result.source.index;
const endIndex = result.destination.index;
const list = Array.from(dataList);
const [removed] = list.splice(startIndex, 1);
list.splice(endIndex, 0, removed);
onDragEndCb(list);
};
return (
<DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
<Droppable droppableId="droppable" renderClone={renderClone}>
{(provided, snapshot) => {
return (
<Box {...provided.droppableProps} ref={provided.innerRef}>
{children(provided, snapshot)}
{snapshot.isDraggingOver && <Box height={draggingItemHeight} />}
</Box>
);
}}
</Droppable>
</DragDropContext>
);
}
export default DndDrag;
export * from 'react-beautiful-dnd';

View File

@@ -31,12 +31,14 @@
"react": "18.2.0", "react": "18.2.0",
"react-day-picker": "^8.7.1", "react-day-picker": "^8.7.1",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-i18next": "13.5.0" "react-i18next": "13.5.0",
"react-beautiful-dnd": "^13.1.1"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash": "^4.14.191", "@types/lodash": "^4.14.191",
"@types/papaparse": "^5.3.7", "@types/papaparse": "^5.3.7",
"@types/react": "18.2.0", "@types/react": "18.2.0",
"@types/react-dom": "18.2.0" "@types/react-dom": "18.2.0",
"@types/react-beautiful-dnd": "^13.1.8"
} }
} }

12
pnpm-lock.yaml generated
View File

@@ -292,6 +292,9 @@ importers:
react: react:
specifier: 18.2.0 specifier: 18.2.0
version: 18.2.0 version: 18.2.0
react-beautiful-dnd:
specifier: ^13.1.1
version: 13.1.1(react-dom@18.2.0)(react@18.2.0)
react-day-picker: react-day-picker:
specifier: ^8.7.1 specifier: ^8.7.1
version: 8.7.1(date-fns@2.30.0)(react@18.2.0) version: 8.7.1(date-fns@2.30.0)(react@18.2.0)
@@ -311,6 +314,9 @@ importers:
'@types/react': '@types/react':
specifier: 18.2.0 specifier: 18.2.0
version: 18.2.0 version: 18.2.0
'@types/react-beautiful-dnd':
specifier: ^13.1.8
version: 13.1.8
'@types/react-dom': '@types/react-dom':
specifier: 18.2.0 specifier: 18.2.0
version: 18.2.0 version: 18.2.0
@@ -431,9 +437,6 @@ importers:
react: react:
specifier: 18.2.0 specifier: 18.2.0
version: 18.2.0 version: 18.2.0
react-beautiful-dnd:
specifier: ^13.1.1
version: 13.1.1(react-dom@18.2.0)(react@18.2.0)
react-day-picker: react-day-picker:
specifier: ^8.7.1 specifier: ^8.7.1
version: 8.7.1(date-fns@2.30.0)(react@18.2.0) version: 8.7.1(date-fns@2.30.0)(react@18.2.0)
@@ -504,9 +507,6 @@ importers:
'@types/react': '@types/react':
specifier: 18.2.0 specifier: 18.2.0
version: 18.2.0 version: 18.2.0
'@types/react-beautiful-dnd':
specifier: ^13.1.8
version: 13.1.8
'@types/react-dom': '@types/react-dom':
specifier: 18.2.0 specifier: 18.2.0
version: 18.2.0 version: 18.2.0

View File

@@ -644,8 +644,7 @@
"success": "开始同步" "success": "开始同步"
} }
}, },
"training": { "training": {}
}
}, },
"data": { "data": {
"Auxiliary Data": "辅助数据", "Auxiliary Data": "辅助数据",
@@ -920,7 +919,7 @@
"AppId": "应用的ID", "AppId": "应用的ID",
"ChatId": "当前对话ID", "ChatId": "当前对话ID",
"Current time": "当前时间", "Current time": "当前时间",
"Histories": "历史记录,最多取10条", "Histories": "最近10条聊天记录",
"Key already exists": "Key 已经存在", "Key already exists": "Key 已经存在",
"Key cannot be empty": "参数名不能为空", "Key cannot be empty": "参数名不能为空",
"Props name": "参数名", "Props name": "参数名",

View File

@@ -47,7 +47,6 @@
"nextjs-node-loader": "^1.1.5", "nextjs-node-loader": "^1.1.5",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"react": "18.2.0", "react": "18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-day-picker": "^8.7.1", "react-day-picker": "^8.7.1",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-hook-form": "7.43.1", "react-hook-form": "7.43.1",
@@ -73,7 +72,6 @@
"@types/lodash": "^4.14.191", "@types/lodash": "^4.14.191",
"@types/node": "^20.8.5", "@types/node": "^20.8.5",
"@types/react": "18.2.0", "@types/react": "18.2.0",
"@types/react-beautiful-dnd": "^13.1.8",
"@types/react-dom": "18.2.0", "@types/react-dom": "18.2.0",
"@types/react-syntax-highlighter": "^15.5.6", "@types/react-syntax-highlighter": "^15.5.6",
"@types/request-ip": "^0.0.37", "@types/request-ip": "^0.0.37",

View File

@@ -1,5 +1,5 @@
import { VariableItemType } from '@fastgpt/global/core/app/type.d'; import { VariableItemType } from '@fastgpt/global/core/app/type.d';
import React, { useState } from 'react'; import React, { useEffect, useState } from 'react';
import { UseFormReturn } from 'react-hook-form'; import { UseFormReturn } from 'react-hook-form';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { Box, Button, Card, Input, Textarea } from '@chakra-ui/react'; import { Box, Button, Card, Input, Textarea } from '@chakra-ui/react';
@@ -24,10 +24,23 @@ const VariableInput = ({
chatForm: UseFormReturn<ChatBoxInputFormType>; chatForm: UseFormReturn<ChatBoxInputFormType>;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [refresh, setRefresh] = useState(false); const { register, unregister, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
const { register, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
const variables = watch('variables'); const variables = watch('variables');
useEffect(() => {
// 重新注册所有字段
variableModules.forEach((item) => {
register(`variables.${item.key}`, { required: item.required });
});
return () => {
// 组件卸载时注销所有字段
variableModules.forEach((item) => {
unregister(`variables.${item.key}`);
});
};
}, [register, unregister, variableModules]);
return ( return (
<Box py={3}> <Box py={3}>
{/* avatar */} {/* avatar */}
@@ -92,7 +105,6 @@ const VariableInput = ({
value={variables[item.key]} value={variables[item.key]}
onchange={(e) => { onchange={(e) => {
setValue(`variables.${item.key}`, e); setValue(`variables.${item.key}`, e);
setRefresh((state) => !state);
}} }}
/> />
)} )}
@@ -116,4 +128,4 @@ const VariableInput = ({
); );
}; };
export default React.memo(VariableInput); export default VariableInput;

View File

@@ -158,12 +158,6 @@ const ChatBox = (
isChatting isChatting
} = useChatProviderStore(); } = useChatProviderStore();
/* variable */
const filterVariableModules = useMemo(
() => variableModules.filter((item) => item.type !== VariableInputEnum.custom),
[variableModules]
);
// compute variable input is finish. // compute variable input is finish.
const chatForm = useForm<ChatBoxInputFormType>({ const chatForm = useForm<ChatBoxInputFormType>({
defaultValues: { defaultValues: {
@@ -174,9 +168,15 @@ const ChatBox = (
} }
}); });
const { setValue, watch, handleSubmit } = chatForm; const { setValue, watch, handleSubmit } = chatForm;
const variables = watch('variables');
const chatStarted = watch('chatStarted'); const chatStarted = watch('chatStarted');
const variableIsFinish = useMemo(() => {
/* variable */
const variables = watch('variables');
const filterVariableModules = useMemo(
() => variableModules.filter((item) => item.type !== VariableInputEnum.custom),
[variableModules]
);
const variableIsFinish = (() => {
if (!filterVariableModules || filterVariableModules.length === 0 || chatHistories.length > 0) if (!filterVariableModules || filterVariableModules.length === 0 || chatHistories.length > 0)
return true; return true;
@@ -188,7 +188,7 @@ const ChatBox = (
} }
return chatStarted; return chatStarted;
}, [filterVariableModules, chatHistories.length, chatStarted, variables]); })();
// 滚动到底部 // 滚动到底部
const scrollToBottom = (behavior: 'smooth' | 'auto' = 'smooth') => { const scrollToBottom = (behavior: 'smooth' | 'auto' = 'smooth') => {
@@ -360,6 +360,12 @@ const ChatBox = (
[questionGuide, shareId, outLinkUid, teamId, teamToken] [questionGuide, shareId, outLinkUid, teamId, teamToken]
); );
/* Abort chat completions, questionGuide */
const abortRequest = useCallback(() => {
chatController.current?.abort('stop');
questionGuideController.current?.abort('stop');
}, []);
/** /**
* user confirm send prompt * user confirm send prompt
*/ */
@@ -383,6 +389,8 @@ const ChatBox = (
return; return;
} }
abortRequest();
text = text.trim(); text = text.trim();
if (!text && files.length === 0) { if (!text && files.length === 0) {
@@ -472,7 +480,8 @@ const ChatBox = (
generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }), generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }),
variables variables
}); });
setValue('variables', newVariables || []);
newVariables && setValue('variables', newVariables);
isNewChatReplace.current = isNewChat; isNewChatReplace.current = isNewChat;
@@ -540,6 +549,7 @@ const ChatBox = (
})(); })();
}, },
[ [
abortRequest,
chatHistories, chatHistories,
createQuestionGuide, createQuestionGuide,
finishSegmentedAudio, finishSegmentedAudio,
@@ -710,7 +720,7 @@ const ChatBox = (
}); });
}; };
}, },
[appId, chatId, feedbackType, teamId, teamToken] [appId, chatId, feedbackType, setChatHistories, teamId, teamToken]
); );
const onADdUserDislike = useCallback( const onADdUserDislike = useCallback(
(chat: ChatSiteItemType) => { (chat: ChatSiteItemType) => {
@@ -747,7 +757,7 @@ const ChatBox = (
return () => setFeedbackId(chat.dataId); return () => setFeedbackId(chat.dataId);
} }
}, },
[appId, chatId, feedbackType, outLinkUid, shareId, teamId, teamToken] [appId, chatId, feedbackType, outLinkUid, setChatHistories, shareId, teamId, teamToken]
); );
const onReadUserDislike = useCallback( const onReadUserDislike = useCallback(
(chat: ChatSiteItemType) => { (chat: ChatSiteItemType) => {
@@ -868,6 +878,7 @@ const ChatBox = (
setValue('variables', e || defaultVal); setValue('variables', e || defaultVal);
}, },
resetHistory(e) { resetHistory(e) {
abortRequest();
setValue('chatStarted', e.length > 0); setValue('chatStarted', e.length > 0);
setChatHistories(e); setChatHistories(e);
}, },

View File

@@ -1,5 +1,8 @@
import { Box, Button, Flex } from '@chakra-ui/react'; import { Box, Button, Flex } from '@chakra-ui/react';
import { DraggableProvided, DraggableStateSnapshot } from 'react-beautiful-dnd'; import {
DraggableProvided,
DraggableStateSnapshot
} from '@fastgpt/web/components/common/DndDrag/index';
import Container from '../../components/Container'; import Container from '../../components/Container';
import { DragHandleIcon, MinusIcon, SmallAddIcon } from '@chakra-ui/icons'; import { DragHandleIcon, MinusIcon, SmallAddIcon } from '@chakra-ui/icons';
import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type'; import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type';
@@ -25,6 +28,7 @@ import { getElseIFLabel, getHandleId } from '@fastgpt/global/core/workflow/utils
import { SourceHandle } from '../render/Handle'; import { SourceHandle } from '../render/Handle';
import { Position, useReactFlow } from 'reactflow'; import { Position, useReactFlow } from 'reactflow';
import { getReferenceDataValueType } from '@/web/core/workflow/utils'; import { getReferenceDataValueType } from '@/web/core/workflow/utils';
import DragIcon from '@fastgpt/web/components/common/DndDrag/DragIcon';
const ListItem = ({ const ListItem = ({
provided, provided,
@@ -63,11 +67,7 @@ const ListItem = ({
> >
<Container w={snapshot.isDragging ? '' : 'full'} className="nodrag"> <Container w={snapshot.isDragging ? '' : 'full'} className="nodrag">
<Flex mb={4} alignItems={'center'}> <Flex mb={4} alignItems={'center'}>
{ifElseList.length > 1 && ( {ifElseList.length > 1 && <DragIcon provided={provided} />}
<Box {...provided.dragHandleProps}>
<DragHandleIcon color={'blackAlpha.600'} />
</Box>
)}
<Box color={'black'} fontSize={'lg'} ml={2}> <Box color={'black'} fontSize={'lg'} ml={2}>
{getElseIFLabel(conditionIndex)} {getElseIFLabel(conditionIndex)}
</Box> </Box>

View File

@@ -9,7 +9,7 @@ import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/syste
import { useContextSelector } from 'use-context-selector'; import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../../context'; import { WorkflowContext } from '../../../context';
import Container from '../../components/Container'; import Container from '../../components/Container';
import { DragDropContext, DragStart, Draggable, DropResult, Droppable } from 'react-beautiful-dnd'; import DndDrag, { Draggable, DropResult } from '@fastgpt/web/components/common/DndDrag/index';
import { SourceHandle } from '../render/Handle'; import { SourceHandle } from '../render/Handle';
import { getHandleId } from '@fastgpt/global/core/workflow/utils'; import { getHandleId } from '@fastgpt/global/core/workflow/utils';
import ListItem from './ListItem'; import ListItem from './ListItem';
@@ -20,8 +20,6 @@ const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { nodeId, inputs = [] } = data; const { nodeId, inputs = [] } = data;
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode); const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const [draggingItemHeight, setDraggingItemHeight] = useState(0);
const ifElseList = useMemo( const ifElseList = useMemo(
() => () =>
(inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList) (inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList)
@@ -47,73 +45,49 @@ const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
[inputs, nodeId, onChangeNode] [inputs, nodeId, onChangeNode]
); );
const reorder = (list: IfElseListItemType[], startIndex: number, endIndex: number) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
const onDragStart = (start: DragStart) => {
const draggingNode = document.querySelector(`[data-rbd-draggable-id="${start.draggableId}"]`);
setDraggingItemHeight(draggingNode?.getBoundingClientRect().height || 0);
};
const onDragEnd = (result: DropResult) => {
if (!result.destination) {
return;
}
const newList = reorder(ifElseList, result.source.index, result.destination.index);
onUpdateIfElseList(newList);
setDraggingItemHeight(0);
};
return ( return (
<NodeCard selected={selected} maxW={'1000px'} {...data}> <NodeCard selected={selected} maxW={'1000px'} {...data}>
<Box px={4}> <Box px={4} cursor={'default'}>
<DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}> <DndDrag<IfElseListItemType>
<Droppable onDragEndCb={(list) => onUpdateIfElseList(list)}
droppableId="droppable" dataList={ifElseList}
renderClone={(provided, snapshot, rubric) => ( renderClone={(provided, snapshot, rubric) => (
<ListItem <ListItem
provided={provided} provided={provided}
snapshot={snapshot} snapshot={snapshot}
conditionItem={ifElseList[rubric.source.index]} conditionItem={ifElseList[rubric.source.index]}
conditionIndex={rubric.source.index} conditionIndex={rubric.source.index}
ifElseList={ifElseList} ifElseList={ifElseList}
onUpdateIfElseList={onUpdateIfElseList} onUpdateIfElseList={onUpdateIfElseList}
nodeId={nodeId} nodeId={nodeId}
/> />
)} )}
> >
{(provided, snapshot) => ( {(provided) => (
<Box {...provided.droppableProps} ref={provided.innerRef}> <Box {...provided.droppableProps} ref={provided.innerRef}>
{ifElseList.map((conditionItem, conditionIndex) => ( {ifElseList.map((conditionItem, conditionIndex) => (
<Draggable <Draggable
key={conditionIndex} key={conditionIndex}
draggableId={conditionIndex.toString()} draggableId={conditionIndex.toString()}
index={conditionIndex} index={conditionIndex}
> >
{(provided, snapshot) => ( {(provided, snapshot) => (
<ListItem <ListItem
provided={provided} provided={provided}
snapshot={snapshot} snapshot={snapshot}
conditionItem={conditionItem} conditionItem={conditionItem}
conditionIndex={conditionIndex} conditionIndex={conditionIndex}
ifElseList={ifElseList} ifElseList={ifElseList}
onUpdateIfElseList={onUpdateIfElseList} onUpdateIfElseList={onUpdateIfElseList}
nodeId={nodeId} nodeId={nodeId}
/> />
)} )}
</Draggable> </Draggable>
))} ))}
{snapshot.isDraggingOver && <Box height={draggingItemHeight} />} </Box>
</Box> )}
)} </DndDrag>
</Droppable>
</DragDropContext>
<Container position={'relative'}> <Container position={'relative'}>
<Flex alignItems={'center'}> <Flex alignItems={'center'}>
<Box color={'black'} fontSize={'lg'} ml={2}> <Box color={'black'} fontSize={'lg'} ml={2}>

View File

@@ -45,7 +45,6 @@ import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runti
import { dispatchWorkFlowV1 } from '@fastgpt/service/core/workflow/dispatchV1'; import { dispatchWorkFlowV1 } from '@fastgpt/service/core/workflow/dispatchV1';
import { setEntryEntries } from '@fastgpt/service/core/workflow/dispatchV1/utils'; import { setEntryEntries } from '@fastgpt/service/core/workflow/dispatchV1/utils';
import { NextAPI } from '@/service/middle/entry'; import { NextAPI } from '@/service/middle/entry';
import { MongoAppVersion } from '@fastgpt/service/core/app/versionSchema';
import { getAppLatestVersion } from '@fastgpt/service/core/app/controller'; import { getAppLatestVersion } from '@fastgpt/service/core/app/controller';
type FastGptWebChatProps = { type FastGptWebChatProps = {

View File

@@ -28,7 +28,7 @@ const Render = ({ app, onClose }: Props) => {
useEffect(() => { useEffect(() => {
if (!isV2Workflow) return; if (!isV2Workflow) return;
initData(JSON.parse(workflowStringData)); initData(JSON.parse(workflowStringData));
}, [isV2Workflow, initData, workflowStringData]); }, [isV2Workflow, initData, app._id]);
useEffect(() => { useEffect(() => {
if (!isV2Workflow) { if (!isV2Workflow) {

View File

@@ -99,8 +99,8 @@ const OutLink = ({
data: { data: {
messages: prompts, messages: prompts,
variables: { variables: {
...customVariables, ...variables,
...variables ...customVariables
}, },
shareId, shareId,
chatId: completionChatId, chatId: completionChatId,