* perf: some log, chatTest histories slice; http request failed tip

* fix: ssr render

* perf: if else node ui and fix value type select
This commit is contained in:
Archer
2024-05-07 15:27:05 +08:00
committed by GitHub
parent 2053bbdb1b
commit 8f9203c053
21 changed files with 164 additions and 137 deletions

View File

@@ -46,7 +46,7 @@ export const IfElseNode: FlowNodeTemplateType = {
{ {
id: NodeOutputKeyEnum.ifElseResult, id: NodeOutputKeyEnum.ifElseResult,
key: NodeOutputKeyEnum.ifElseResult, key: NodeOutputKeyEnum.ifElseResult,
label: 'IF ELSE', label: '判断结果',
valueType: WorkflowIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static type: FlowNodeOutputTypeEnum.static
} }

View File

@@ -40,7 +40,7 @@ export type FlowNodeCommonType = {
}; };
export type FlowNodeTemplateType = FlowNodeCommonType & { export type FlowNodeTemplateType = FlowNodeCommonType & {
id: string; // module id, unique id: string; // node id, unique
templateType: `${FlowNodeTemplateTypeEnum}`; templateType: `${FlowNodeTemplateTypeEnum}`;
// show handle // show handle
@@ -132,11 +132,12 @@ export type ChatDispatchProps = {
chatId?: string; chatId?: string;
responseChatItemId?: string; responseChatItemId?: string;
histories: ChatItemType[]; histories: ChatItemType[];
variables: Record<string, any>; variables: Record<string, any>; // global variable
query: UserChatItemValueItemType[]; query: UserChatItemValueItemType[]; // trigger query
stream: boolean; stream: boolean;
detail: boolean; // response detail detail: boolean; // response detail
maxRunTimes: number; maxRunTimes: number;
isToolCall?: boolean;
}; };
export type ModuleDispatchProps<T> = ChatDispatchProps & { export type ModuleDispatchProps<T> = ChatDispatchProps & {

View File

@@ -1,3 +1,4 @@
import { addLog } from '../../../common/system/log';
import { POST } from '../../../common/api/serverRequest'; import { POST } from '../../../common/api/serverRequest';
type PostReRankResponse = { type PostReRankResponse = {
@@ -38,7 +39,7 @@ export function reRankRecall({
} }
) )
.then((data) => { .then((data) => {
console.log('rerank time:', Date.now() - start); addLog.info('ReRank finish:', { time: Date.now() - start });
return data?.results?.map((item) => ({ return data?.results?.map((item) => ({
id: documents[item.index].id, id: documents[item.index].id,
@@ -46,7 +47,7 @@ export function reRankRecall({
})); }));
}) })
.catch((err) => { .catch((err) => {
console.log('rerank error:', err); addLog.error('rerank error', err);
return []; return [];
}); });

View File

@@ -161,6 +161,7 @@ export const runToolWithFunctionCall = async (
const toolRunResponse = await dispatchWorkFlow({ const toolRunResponse = await dispatchWorkFlow({
...props, ...props,
isToolCall: true,
runtimeNodes: runtimeNodes.map((item) => runtimeNodes: runtimeNodes.map((item) =>
item.nodeId === toolNode.nodeId item.nodeId === toolNode.nodeId
? { ? {

View File

@@ -185,6 +185,7 @@ export const runToolWithPromptCall = async (
const moduleRunResponse = await dispatchWorkFlow({ const moduleRunResponse = await dispatchWorkFlow({
...props, ...props,
isToolCall: true,
runtimeNodes: runtimeNodes.map((item) => runtimeNodes: runtimeNodes.map((item) =>
item.nodeId === toolNode.nodeId item.nodeId === toolNode.nodeId
? { ? {

View File

@@ -182,6 +182,7 @@ export const runToolWithToolChoice = async (
const toolRunResponse = await dispatchWorkFlow({ const toolRunResponse = await dispatchWorkFlow({
...props, ...props,
isToolCall: true,
runtimeNodes: runtimeNodes.map((item) => runtimeNodes: runtimeNodes.map((item) =>
item.nodeId === toolNode.nodeId item.nodeId === toolNode.nodeId
? { ? {

View File

@@ -8,12 +8,15 @@ export type UserChatInputProps = ModuleDispatchProps<{
}>; }>;
export const dispatchWorkflowStart = (props: Record<string, any>) => { export const dispatchWorkflowStart = (props: Record<string, any>) => {
const { query } = props as UserChatInputProps; const {
query,
params: { userChatInput }
} = props as UserChatInputProps;
const { text, files } = chatValue2RuntimePrompt(query); const { text, files } = chatValue2RuntimePrompt(query);
return { return {
[NodeInputKeyEnum.userChatInput]: text, [NodeInputKeyEnum.userChatInput]: text || userChatInput,
[NodeInputKeyEnum.inputFiles]: files [NodeInputKeyEnum.inputFiles]: files
}; };
}; };

View File

@@ -49,6 +49,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
variables, variables,
node: { outputs }, node: { outputs },
histories, histories,
isToolCall,
params: { params: {
system_httpMethod: httpMethod = 'POST', system_httpMethod: httpMethod = 'POST',
system_httpReqUrl: httpReqUrl, system_httpReqUrl: httpReqUrl,
@@ -156,17 +157,21 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
}; };
} catch (error) { } catch (error) {
addLog.error('Http request error', error); addLog.error('Http request error', error);
return {
[NodeOutputKeyEnum.failed]: true, if (isToolCall) {
[DispatchNodeResponseKeyEnum.nodeResponse]: { return {
totalPoints: 0, [NodeOutputKeyEnum.failed]: true,
params: Object.keys(params).length > 0 ? params : undefined, [DispatchNodeResponseKeyEnum.nodeResponse]: {
body: Object.keys(requestBody).length > 0 ? requestBody : undefined, totalPoints: 0,
headers: Object.keys(headers).length > 0 ? headers : undefined, params: Object.keys(params).length > 0 ? params : undefined,
httpResult: { error: formatHttpError(error) } body: Object.keys(requestBody).length > 0 ? requestBody : undefined,
}, headers: Object.keys(headers).length > 0 ? headers : undefined,
[NodeOutputKeyEnum.httpRawResponse]: getErrText(error) httpResult: { error: formatHttpError(error) }
}; },
[NodeOutputKeyEnum.httpRawResponse]: getErrText(error)
};
}
return Promise.reject(error);
} }
}; };

View File

@@ -1,4 +1,4 @@
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants'; import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants'; import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type'; import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
import { VariableConditionEnum } from '@fastgpt/global/core/workflow/template/system/ifElse/constant'; import { VariableConditionEnum } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
@@ -15,6 +15,9 @@ type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.condition]: IfElseConditionType; [NodeInputKeyEnum.condition]: IfElseConditionType;
[NodeInputKeyEnum.ifElseList]: IfElseListItemType[]; [NodeInputKeyEnum.ifElseList]: IfElseListItemType[];
}>; }>;
type Response = DispatchNodeResultType<{
[NodeOutputKeyEnum.ifElseResult]: string;
}>;
function checkCondition(condition: VariableConditionEnum, variableValue: any, value: string) { function checkCondition(condition: VariableConditionEnum, variableValue: any, value: string) {
const operations = { const operations = {
@@ -63,7 +66,7 @@ function getResult(
return condition === 'AND' ? listResult.every(Boolean) : listResult.some(Boolean); return condition === 'AND' ? listResult.every(Boolean) : listResult.some(Boolean);
} }
export const dispatchIfElse = async (props: Props): Promise<DispatchNodeResultType<{}>> => { export const dispatchIfElse = async (props: Props): Promise<Response> => {
const { const {
params, params,
runtimeNodes, runtimeNodes,
@@ -88,6 +91,7 @@ export const dispatchIfElse = async (props: Props): Promise<DispatchNodeResultTy
}); });
return { return {
[NodeOutputKeyEnum.ifElseResult]: res,
[DispatchNodeResponseKeyEnum.nodeResponse]: { [DispatchNodeResponseKeyEnum.nodeResponse]: {
totalPoints: 0, totalPoints: 0,
ifElseResult: res ifElseResult: res

View File

@@ -14,7 +14,9 @@ export const useBeforeunload = (props?: { callback?: () => any; tip?: string })
e.returnValue = tip; e.returnValue = tip;
callback?.(); callback?.();
} }
: () => {}; : () => {
callback?.();
};
window.addEventListener('beforeunload', listen); window.addEventListener('beforeunload', listen);
return () => { return () => {

2
pnpm-lock.yaml generated
View File

@@ -1,4 +1,4 @@
lockfileVersion: '6.0' lockfileVersion: '6.1'
settings: settings:
autoInstallPeers: true autoInstallPeers: true

View File

@@ -17,13 +17,13 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import { getFileAndOpen } from '@/web/core/dataset/utils'; import { getFileAndOpen } from '@/web/core/dataset/utils';
import { MARKDOWN_QUOTE_SIGN } from '@fastgpt/global/core/chat/constants'; import { MARKDOWN_QUOTE_SIGN } from '@fastgpt/global/core/chat/constants';
const CodeLight = dynamic(() => import('./CodeLight')); const CodeLight = dynamic(() => import('./CodeLight'), { ssr: false });
const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock')); const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock'), { ssr: false });
const MdImage = dynamic(() => import('./img/Image')); const MdImage = dynamic(() => import('./img/Image'), { ssr: false });
const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock')); const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock'), { ssr: false });
const ChatGuide = dynamic(() => import('./chat/Guide')); const ChatGuide = dynamic(() => import('./chat/Guide'), { ssr: false });
const QuestionGuide = dynamic(() => import('./chat/QuestionGuide')); const QuestionGuide = dynamic(() => import('./chat/QuestionGuide'), { ssr: false });
export enum CodeClassName { export enum CodeClassName {
guide = 'guide', guide = 'guide',

View File

@@ -65,7 +65,7 @@ const ChatTest = (
} }
}); });
}); });
const history = chatList.slice(-historyMaxLen - 2, -2); const history = chatList.slice(-(historyMaxLen * 2) - 2, -2);
// 流请求,获取数据 // 流请求,获取数据
const { responseText, responseData, newVariables } = await streamFetch({ const { responseText, responseData, newVariables } = await streamFetch({

View File

@@ -24,6 +24,7 @@ import MyInput from '@/components/MyInput';
import { getHandleId } from '@fastgpt/global/core/workflow/utils'; import { 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';
const ListItem = ({ const ListItem = ({
provided, provided,
@@ -305,19 +306,17 @@ const ConditionSelect = ({
variable?: ReferenceValueProps; variable?: ReferenceValueProps;
onSelect: (e: VariableConditionEnum) => void; onSelect: (e: VariableConditionEnum) => void;
}) => { }) => {
const { t } = useTranslation();
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList); const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
// get condition type // get condition type
const valueType = useMemo(() => { const valueType = useMemo(() => {
if (!variable) return; return getReferenceDataValueType({
const node = nodeList.find((node) => node.nodeId === variable[0]); variable,
nodeList,
if (!node) return WorkflowIOValueTypeEnum.any; t
const output = node.outputs.find((item) => item.id === variable[1]); });
}, [nodeList, t, variable]);
if (!output) return WorkflowIOValueTypeEnum.any;
return output.valueType;
}, [nodeList, variable]);
const conditionList = useMemo(() => { const conditionList = useMemo(() => {
if (valueType === WorkflowIOValueTypeEnum.string) return stringConditionList; if (valueType === WorkflowIOValueTypeEnum.string) return stringConditionList;

View File

@@ -30,7 +30,7 @@ import { SmallAddIcon } from '@chakra-ui/icons';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io'; import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
import { ReferSelector, useReference } from './render/RenderInput/templates/Reference'; import { ReferSelector, useReference } from './render/RenderInput/templates/Reference';
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils'; import { getReferenceDataValueType } from '@/web/core/workflow/utils';
import { isReferenceValue } from '@fastgpt/global/core/workflow/utils'; import { isReferenceValue } from '@fastgpt/global/core/workflow/utils';
const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) => { const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
@@ -82,19 +82,11 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
return ( return (
<> <>
{updateList.map((updateItem, index) => { {updateList.map((updateItem, index) => {
const valueType = (() => { const valueType = getReferenceDataValueType({
const variable = updateItem.variable; variable: updateItem.variable,
const variableNodeId = variable?.[0]; nodeList,
const variableNode = nodeList.find((node) => node.nodeId === variableNodeId); t
const systemVariables = getWorkflowGlobalVariables(nodeList, t); });
const variableInput = !variableNode
? systemVariables.find((item) => item.key === variable?.[1])
: variableNode.outputs.find((output) => output.id === variable?.[1]);
if (!variableInput) return WorkflowIOValueTypeEnum.any;
return variableInput.valueType;
})();
const renderTypeData = menuList.find((item) => item.renderType === updateItem.renderType); const renderTypeData = menuList.find((item) => item.renderType === updateItem.renderType);
const handleUpdate = (newValue: ReferenceValueProps | string) => { const handleUpdate = (newValue: ReferenceValueProps | string) => {

View File

@@ -79,7 +79,6 @@ const NodeCard = (props: Props) => {
return ( return (
<Box position={'relative'}> <Box position={'relative'}>
{/* debug */} {/* debug */}
<NodeDebugResponse nodeId={nodeId} debugResult={debugResult} />
<Box className="custom-drag-handle" px={4} py={3}> <Box className="custom-drag-handle" px={4} py={3}>
{/* tool target handle */} {/* tool target handle */}
{showToolHandle && <ToolTargetHandle nodeId={nodeId} />} {showToolHandle && <ToolTargetHandle nodeId={nodeId} />}
@@ -134,7 +133,6 @@ const NodeCard = (props: Props) => {
); );
}, [ }, [
nodeId, nodeId,
debugResult,
showToolHandle, showToolHandle,
avatar, avatar,
t, t,
@@ -179,6 +177,7 @@ const NodeCard = (props: Props) => {
borderColor: selected ? 'primary.600' : 'borderColor.base' borderColor: selected ? 'primary.600' : 'borderColor.base'
})} })}
> >
<NodeDebugResponse nodeId={nodeId} debugResult={debugResult} />
{Header} {Header}
{children} {children}
<ConnectionSourceHandle nodeId={nodeId} /> <ConnectionSourceHandle nodeId={nodeId} />
@@ -259,6 +258,22 @@ const MenuRender = React.memo(function MenuRender({
}, },
[setEdges, setNodes] [setEdges, setNodes]
); );
const onclickSyncVersion = useCallback(async () => {
if (!pluginId) return;
try {
setLoading(true);
onResetNode({
id: nodeId,
node: await getPreviewPluginModule(pluginId)
});
} catch (e) {
return toast({
status: 'error',
title: getErrText(e, t('plugin.Get Plugin Module Detail Failed'))
});
}
setLoading(false);
}, [nodeId, onResetNode, pluginId, setLoading, t, toast]);
const Render = useMemo(() => { const Render = useMemo(() => {
const menuList = [ const menuList = [
@@ -288,25 +303,7 @@ const MenuRender = React.memo(function MenuRender({
icon: 'common/refreshLight', icon: 'common/refreshLight',
label: t('plugin.Synchronous version'), label: t('plugin.Synchronous version'),
variant: 'whiteBase', variant: 'whiteBase',
onClick: () => { onClick: onOpenConfirmSync(onclickSyncVersion)
if (!pluginId) return;
onOpenConfirmSync(async () => {
try {
setLoading(true);
const pluginModule = await getPreviewPluginModule(pluginId);
onResetNode({
id: nodeId,
module: pluginModule
});
} catch (e) {
return toast({
status: 'error',
title: getErrText(e, t('plugin.Get Plugin Module Detail Failed'))
});
}
setLoading(false);
})();
}
} }
] ]
: []), : []),
@@ -370,12 +367,9 @@ const MenuRender = React.memo(function MenuRender({
onDelNode, onDelNode,
onOpenConfirmDeleteNode, onOpenConfirmDeleteNode,
onOpenConfirmSync, onOpenConfirmSync,
onResetNode, onclickSyncVersion,
openDebugNode, openDebugNode,
pluginId, t
setLoading,
t,
toast
]); ]);
return Render; return Render;
@@ -530,7 +524,8 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
top={0} top={0}
zIndex={10} zIndex={10}
w={'420px'} w={'420px'}
maxH={'540px'} maxH={'100%'}
minH={'300px'}
overflowY={'auto'} overflowY={'auto'}
border={'base'} border={'base'}
> >

View File

@@ -55,7 +55,7 @@ type WorkflowContextType = {
hoverNodeId?: string; hoverNodeId?: string;
setHoverNodeId: React.Dispatch<React.SetStateAction<string | undefined>>; setHoverNodeId: React.Dispatch<React.SetStateAction<string | undefined>>;
onUpdateNodeError: (node: string, isError: Boolean) => void; onUpdateNodeError: (node: string, isError: Boolean) => void;
onResetNode: (e: { id: string; module: FlowNodeTemplateType }) => void; onResetNode: (e: { id: string; node: FlowNodeTemplateType }) => void;
onChangeNode: (e: FlowNodeChangeProps) => void; onChangeNode: (e: FlowNodeChangeProps) => void;
// edges // edges
@@ -159,7 +159,7 @@ export const WorkflowContext = createContext<WorkflowContextType>({
onEdgesChange: function (changes: EdgeChange[]): void { onEdgesChange: function (changes: EdgeChange[]): void {
throw new Error('Function not implemented.'); throw new Error('Function not implemented.');
}, },
onResetNode: function (e: { id: string; module: FlowNodeTemplateType }): void { onResetNode: function (e: { id: string; node: FlowNodeTemplateType }): void {
throw new Error('Function not implemented.'); throw new Error('Function not implemented.');
}, },
onDelEdge: function (e: { onDelEdge: function (e: {
@@ -279,31 +279,30 @@ const WorkflowContextProvider = ({
}); });
// reset a node data. delete edge and replace it // reset a node data. delete edge and replace it
const onResetNode = useMemoizedFn( const onResetNode = useMemoizedFn(({ id, node }: { id: string; node: FlowNodeTemplateType }) => {
({ id, module }: { id: string; module: FlowNodeTemplateType }) => { setNodes((state) =>
setNodes((state) => state.map((item) => {
state.map((node) => { if (item.id === id) {
if (node.id === id) { return {
// delete edge ...item,
node.data.inputs.forEach((item) => { data: {
onDelEdge({ nodeId: id, targetHandle: item.key }); ...item.data,
});
node.data.outputs.forEach((item) => {
onDelEdge({ nodeId: id, sourceHandle: item.key });
});
return {
...node, ...node,
data: { inputs: node.inputs.map((input) => {
...node.data, const value =
...module item.data.inputs.find((i) => i.key === input.key)?.value ?? input.value;
} return {
}; ...input,
} value
return node; };
}) })
); }
} };
); }
return item;
})
);
});
const onChangeNode = useMemoizedFn((props: FlowNodeChangeProps) => { const onChangeNode = useMemoizedFn((props: FlowNodeChangeProps) => {
const { nodeId, type } = props; const { nodeId, type } = props;
@@ -431,7 +430,6 @@ const WorkflowContextProvider = ({
const initData = useMemoizedFn( const initData = useMemoizedFn(
async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => { async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item }))); setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })));
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item }))); setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })));
} }
); );

View File

@@ -53,10 +53,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
appId, appId,
runtimeNodes: nodes, runtimeNodes: nodes,
runtimeEdges: edges, runtimeEdges: edges,
variables: { variables,
...variables,
userChatInput: ''
},
query: [], query: [],
histories: [], histories: [],
stream: false, stream: false,

View File

@@ -75,6 +75,7 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
WorkflowContext, WorkflowContext,
(v) => v.setIsShowVersionHistories (v) => v.setIsShowVersionHistories
); );
const workflowDebugData = useContextSelector(WorkflowContext, (v) => v.workflowDebugData);
const flowData2StoreDataAndCheck = useCallback(async () => { const flowData2StoreDataAndCheck = useCallback(async () => {
const { nodes } = await getWorkflowStore(); const { nodes } = await getWorkflowStore();
@@ -93,35 +94,40 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
} }
}, [edges, onUpdateNodeError, t, toast]); }, [edges, onUpdateNodeError, t, toast]);
const onclickSave = useCallback(async () => { const onclickSave = useCallback(
if (isShowVersionHistories) return; async (forbid?: boolean) => {
const { nodes } = await getWorkflowStore(); // version preview / debug mode, not save
if (isShowVersionHistories || forbid) return;
if (nodes.length === 0) return null; const { nodes } = await getWorkflowStore();
setIsSaving(true);
const storeWorkflow = flowNode2StoreNodes({ nodes, edges }); if (nodes.length === 0) return null;
setIsSaving(true);
try { const storeWorkflow = flowNode2StoreNodes({ nodes, edges });
await updateAppDetail(app._id, {
...storeWorkflow,
type: AppTypeEnum.advanced,
//@ts-ignore
version: 'v2'
});
setSaveLabel( try {
t('core.app.Auto Save time', { await updateAppDetail(app._id, {
time: formatTime2HM() ...storeWorkflow,
}) type: AppTypeEnum.advanced,
); //@ts-ignore
// ChatTestRef.current?.resetChatTest(); version: 'v2'
} catch (error) {} });
setIsSaving(false); setSaveLabel(
t('core.app.Auto Save time', {
time: formatTime2HM()
})
);
// ChatTestRef.current?.resetChatTest();
} catch (error) {}
return null; setIsSaving(false);
}, [isShowVersionHistories, edges, updateAppDetail, app._id, t]);
return null;
},
[isShowVersionHistories, edges, updateAppDetail, app._id, t]
);
const onclickPublish = useCallback(async () => { const onclickPublish = useCallback(async () => {
setIsSaving(true); setIsSaving(true);
@@ -182,7 +188,7 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
useInterval(() => { useInterval(() => {
if (!app._id) return; if (!app._id) return;
onclickSave(); onclickSave(!!workflowDebugData);
}, 20000); }, 20000);
const Render = useMemo(() => { const Render = useMemo(() => {
@@ -221,7 +227,7 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
display={'inline-block'} display={'inline-block'}
borderRadius={'xs'} borderRadius={'xs'}
cursor={'pointer'} cursor={'pointer'}
onClick={onclickSave} onClick={() => onclickSave()}
color={'myGray.500'} color={'myGray.500'}
> >
{saveLabel} {saveLabel}

View File

@@ -62,7 +62,7 @@ const ChatTest = ({
} }
}); });
}); });
const history = chatList.slice(-historyMaxLen - 2, -2); const history = chatList.slice(-(historyMaxLen * 2) - 2, -2);
// 流请求,获取数据 // 流请求,获取数据
const { responseText, responseData } = await streamFetch({ const { responseText, responseData } = await streamFetch({

View File

@@ -24,6 +24,7 @@ import {
} from '@fastgpt/global/core/workflow/utils'; } from '@fastgpt/global/core/workflow/utils';
import { getSystemVariables } from '../app/utils'; import { getSystemVariables } from '../app/utils';
import { TFunction } from 'next-i18next'; import { TFunction } from 'next-i18next';
import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
export const nodeTemplate2FlowNode = ({ export const nodeTemplate2FlowNode = ({
template, template,
@@ -140,6 +141,26 @@ export const computedNodeInputReference = ({
return sourceNodes; return sourceNodes;
}; };
export const getReferenceDataValueType = ({
variable,
nodeList,
t
}: {
variable?: ReferenceValueProps;
nodeList: FlowNodeItemType[];
t: TFunction;
}) => {
if (!variable) return WorkflowIOValueTypeEnum.any;
const node = nodeList.find((node) => node.nodeId === variable[0]);
const systemVariables = getWorkflowGlobalVariables(nodeList, t);
if (!node) return systemVariables.find((item) => item.key === variable?.[1])?.valueType;
const output = node.outputs.find((item) => item.id === variable[1]);
if (!output) return WorkflowIOValueTypeEnum.any;
return output.valueType;
};
/* Connection rules */ /* Connection rules */
export const checkWorkflowNodeAndConnection = ({ export const checkWorkflowNodeAndConnection = ({