mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 05:12:39 +00:00
4.8 test (#1382)
* 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:
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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 & {
|
||||||
|
@@ -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 [];
|
||||||
});
|
});
|
||||||
|
@@ -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
|
||||||
? {
|
? {
|
||||||
|
@@ -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
|
||||||
? {
|
? {
|
||||||
|
@@ -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
|
||||||
? {
|
? {
|
||||||
|
@@ -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
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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
2
pnpm-lock.yaml
generated
@@ -1,4 +1,4 @@
|
|||||||
lockfileVersion: '6.0'
|
lockfileVersion: '6.1'
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
autoInstallPeers: true
|
autoInstallPeers: true
|
||||||
|
@@ -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',
|
||||||
|
@@ -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({
|
||||||
|
@@ -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;
|
||||||
|
@@ -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) => {
|
||||||
|
@@ -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'}
|
||||||
>
|
>
|
||||||
|
@@ -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 })));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -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,
|
||||||
|
@@ -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}
|
||||||
|
@@ -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({
|
||||||
|
@@ -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 = ({
|
||||||
|
Reference in New Issue
Block a user