mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
fix: global variable during debug & variable update textarea rerender (#2553)
* fix: global variable during debug & variable update textarea rerender * update var node use prompt editor * fix
This commit is contained in:
@@ -8,6 +8,7 @@ import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime
|
|||||||
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
|
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
|
||||||
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { removeSystemVariable, valueTypeFormat } from '../utils';
|
import { removeSystemVariable, valueTypeFormat } from '../utils';
|
||||||
|
import { replaceVariableLabel } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
|
||||||
type Props = ModuleDispatchProps<{
|
type Props = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.updateList]: TUpdateListItem[];
|
[NodeInputKeyEnum.updateList]: TUpdateListItem[];
|
||||||
@@ -15,7 +16,7 @@ type Props = ModuleDispatchProps<{
|
|||||||
type Response = DispatchNodeResultType<{}>;
|
type Response = DispatchNodeResultType<{}>;
|
||||||
|
|
||||||
export const dispatchUpdateVariable = async (props: Props): Promise<Response> => {
|
export const dispatchUpdateVariable = async (props: Props): Promise<Response> => {
|
||||||
const { params, variables, runtimeNodes, workflowStreamResponse } = props;
|
const { params, variables, runtimeNodes, workflowStreamResponse, node } = props;
|
||||||
|
|
||||||
const { updateList } = params;
|
const { updateList } = params;
|
||||||
updateList.forEach((item) => {
|
updateList.forEach((item) => {
|
||||||
@@ -28,7 +29,16 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
|
|||||||
|
|
||||||
const value = (() => {
|
const value = (() => {
|
||||||
if (!item.value?.[0]) {
|
if (!item.value?.[0]) {
|
||||||
return valueTypeFormat(item.value?.[1], item.valueType);
|
const formatValue = valueTypeFormat(item.value?.[1], item.valueType);
|
||||||
|
|
||||||
|
return typeof formatValue === 'string'
|
||||||
|
? replaceVariableLabel({
|
||||||
|
text: formatValue,
|
||||||
|
nodes: runtimeNodes,
|
||||||
|
variables,
|
||||||
|
runningNode: node
|
||||||
|
})
|
||||||
|
: formatValue;
|
||||||
} else {
|
} else {
|
||||||
return getReferenceVariableValue({
|
return getReferenceVariableValue({
|
||||||
value: item.value,
|
value: item.value,
|
||||||
|
@@ -40,14 +40,20 @@ const PromptEditor = ({
|
|||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const onChangeInput = useCallback((editorState: EditorState, editor: LexicalEditor) => {
|
const onChangeInput = useCallback(
|
||||||
const text = editorStateToText(editor).replaceAll('}}{{', '}} {{');
|
(editorState: EditorState, editor: LexicalEditor) => {
|
||||||
onChange?.(text);
|
const text = editorStateToText(editor).replaceAll('}}{{', '}} {{');
|
||||||
}, []);
|
onChange?.(text);
|
||||||
const onBlurInput = useCallback((editor: LexicalEditor) => {
|
},
|
||||||
const text = editorStateToText(editor).replaceAll('}}{{', '}} {{');
|
[onChange]
|
||||||
onBlur?.(text);
|
);
|
||||||
}, []);
|
const onBlurInput = useCallback(
|
||||||
|
(editor: LexicalEditor) => {
|
||||||
|
const text = editorStateToText(editor).replaceAll('}}{{', '}} {{');
|
||||||
|
onBlur?.(text);
|
||||||
|
},
|
||||||
|
[onBlur]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@@ -16,4 +16,5 @@ export type PostWorkflowDebugResponse = {
|
|||||||
finishedEdges: RuntimeEdgeItemType[];
|
finishedEdges: RuntimeEdgeItemType[];
|
||||||
nextStepRunNodes: RuntimeNodeItemType[];
|
nextStepRunNodes: RuntimeNodeItemType[];
|
||||||
flowResponses: ChatHistoryItemResType[];
|
flowResponses: ChatHistoryItemResType[];
|
||||||
|
newVariables: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
@@ -39,7 +39,7 @@ async function handler(
|
|||||||
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
||||||
|
|
||||||
/* start process */
|
/* start process */
|
||||||
const { flowUsages, flowResponses, debugResponse } = await dispatchWorkFlow({
|
const { flowUsages, flowResponses, debugResponse, newVariables } = await dispatchWorkFlow({
|
||||||
res,
|
res,
|
||||||
requestOrigin: req.headers.origin,
|
requestOrigin: req.headers.origin,
|
||||||
mode: 'debug',
|
mode: 'debug',
|
||||||
@@ -68,6 +68,7 @@ async function handler(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...debugResponse,
|
...debugResponse,
|
||||||
|
newVariables,
|
||||||
flowResponses
|
flowResponses
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import NodeCard from './render/NodeCard';
|
import NodeCard from './render/NodeCard';
|
||||||
import { NodeProps } from 'reactflow';
|
import { NodeProps } from 'reactflow';
|
||||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||||
@@ -12,8 +12,7 @@ import {
|
|||||||
NumberInput,
|
NumberInput,
|
||||||
NumberInputField,
|
NumberInputField,
|
||||||
NumberInputStepper,
|
NumberInputStepper,
|
||||||
Switch,
|
Switch
|
||||||
Textarea
|
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
|
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
|
||||||
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
@@ -33,6 +32,9 @@ import { ReferSelector, useReference } from './render/RenderInput/templates/Refe
|
|||||||
import { getRefData } from '@/web/core/workflow/utils';
|
import { getRefData } from '@/web/core/workflow/utils';
|
||||||
import { isReferenceValue } from '@fastgpt/global/core/workflow/utils';
|
import { isReferenceValue } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { AppContext } from '@/pages/app/detail/components/context';
|
import { AppContext } from '@/pages/app/detail/components/context';
|
||||||
|
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||||
|
import { useCreation } from 'ahooks';
|
||||||
|
import { getEditorVariables } from '../../utils';
|
||||||
|
|
||||||
const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { inputs = [], nodeId } = data;
|
const { inputs = [], nodeId } = data;
|
||||||
@@ -41,6 +43,17 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
|
|||||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
||||||
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
|
|
||||||
|
const variables = useCreation(() => {
|
||||||
|
return getEditorVariables({
|
||||||
|
nodeId,
|
||||||
|
nodeList,
|
||||||
|
edges,
|
||||||
|
appDetail,
|
||||||
|
t
|
||||||
|
});
|
||||||
|
}, [nodeList, edges, inputs, t]);
|
||||||
|
|
||||||
const updateList = useMemo(
|
const updateList = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -90,7 +103,6 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
|
|||||||
chatConfig: appDetail.chatConfig,
|
chatConfig: appDetail.chatConfig,
|
||||||
t
|
t
|
||||||
});
|
});
|
||||||
|
|
||||||
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) => {
|
||||||
if (isReferenceValue(newValue)) {
|
if (isReferenceValue(newValue)) {
|
||||||
@@ -199,12 +211,15 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
|
|||||||
}
|
}
|
||||||
if (valueType === WorkflowIOValueTypeEnum.string) {
|
if (valueType === WorkflowIOValueTypeEnum.string) {
|
||||||
return (
|
return (
|
||||||
<Textarea
|
<Box w={'300px'}>
|
||||||
bg="white"
|
<PromptEditor
|
||||||
value={updateItem.value?.[1] || ''}
|
value={updateItem.value?.[1] || ''}
|
||||||
w="300px"
|
onChange={handleUpdate}
|
||||||
onChange={(e) => handleUpdate(e.target.value)}
|
showOpenModal={false}
|
||||||
/>
|
variableLabels={variables}
|
||||||
|
h={100}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (valueType === WorkflowIOValueTypeEnum.number) {
|
if (valueType === WorkflowIOValueTypeEnum.number) {
|
||||||
@@ -248,7 +263,7 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
|
|||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}, [nodeId, nodeList, onUpdateList, t, updateList]);
|
}, [appDetail.chatConfig, nodeId, nodeList, onUpdateList, t, updateList, variables]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeCard selected={selected} maxW={'1000px'} {...data}>
|
<NodeCard selected={selected} maxW={'1000px'} {...data}>
|
||||||
|
@@ -4,61 +4,27 @@ import { useTranslation } from 'next-i18next';
|
|||||||
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponents/context';
|
import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponents/context';
|
||||||
import { computedNodeInputReference } from '@/web/core/workflow/utils';
|
|
||||||
import { useCreation } from 'ahooks';
|
import { useCreation } from 'ahooks';
|
||||||
import { AppContext } from '@/pages/app/detail/components/context';
|
import { AppContext } from '@/pages/app/detail/components/context';
|
||||||
|
import { getEditorVariables } from '../../../../../utils';
|
||||||
|
|
||||||
const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
const getNodeDynamicInputs = useContextSelector(WorkflowContext, (v) => v.getNodeDynamicInputs);
|
|
||||||
|
|
||||||
const { appDetail } = useContextSelector(AppContext, (v) => v);
|
const { appDetail } = useContextSelector(AppContext, (v) => v);
|
||||||
|
|
||||||
// get variable
|
// get variable
|
||||||
const variables = useCreation(() => {
|
const variables = useCreation(() => {
|
||||||
const currentNode = nodeList.find((node) => node.nodeId === nodeId)!;
|
return getEditorVariables({
|
||||||
const nodeVariables = getNodeDynamicInputs(nodeId).map((item) => ({
|
|
||||||
key: item.key,
|
|
||||||
label: item.label,
|
|
||||||
parent: {
|
|
||||||
id: currentNode.nodeId,
|
|
||||||
label: currentNode.name,
|
|
||||||
avatar: currentNode.avatar
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
const sourceNodes = computedNodeInputReference({
|
|
||||||
nodeId,
|
nodeId,
|
||||||
nodes: nodeList,
|
nodeList,
|
||||||
edges: edges,
|
edges,
|
||||||
chatConfig: appDetail.chatConfig,
|
appDetail,
|
||||||
t
|
t
|
||||||
});
|
});
|
||||||
|
|
||||||
const sourceNodeVariables = !sourceNodes
|
|
||||||
? []
|
|
||||||
: sourceNodes
|
|
||||||
.map((node) => {
|
|
||||||
return node.outputs
|
|
||||||
.filter((output) => !!output.label)
|
|
||||||
.map((output) => {
|
|
||||||
return {
|
|
||||||
label: t((output.label as any) || ''),
|
|
||||||
key: output.id,
|
|
||||||
parent: {
|
|
||||||
id: node.nodeId,
|
|
||||||
label: node.name,
|
|
||||||
avatar: node.avatar
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.flat();
|
|
||||||
|
|
||||||
return [...nodeVariables, ...sourceNodeVariables];
|
|
||||||
}, [nodeList, edges, inputs, t]);
|
}, [nodeList, edges, inputs, t]);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
|
@@ -188,6 +188,7 @@ type DebugDataType = {
|
|||||||
runtimeNodes: RuntimeNodeItemType[];
|
runtimeNodes: RuntimeNodeItemType[];
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
nextRunNodes: RuntimeNodeItemType[];
|
nextRunNodes: RuntimeNodeItemType[];
|
||||||
|
variables: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WorkflowContext = createContext<WorkflowContextType>({
|
export const WorkflowContext = createContext<WorkflowContextType>({
|
||||||
@@ -676,13 +677,14 @@ const WorkflowContextProvider = ({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 4. Run one step
|
// 4. Run one step
|
||||||
const { finishedEdges, finishedNodes, nextStepRunNodes, flowResponses } =
|
const { finishedEdges, finishedNodes, nextStepRunNodes, flowResponses, newVariables } =
|
||||||
await postWorkflowDebug({
|
await postWorkflowDebug({
|
||||||
nodes: runtimeNodes,
|
nodes: runtimeNodes,
|
||||||
edges: debugData.runtimeEdges,
|
edges: debugData.runtimeEdges,
|
||||||
variables: {
|
variables: {
|
||||||
appId,
|
appId,
|
||||||
cTime: formatTime2YMDHMW()
|
cTime: formatTime2YMDHMW(),
|
||||||
|
...debugData.variables
|
||||||
},
|
},
|
||||||
appId
|
appId
|
||||||
});
|
});
|
||||||
@@ -703,7 +705,8 @@ const WorkflowContextProvider = ({
|
|||||||
status
|
status
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
nextRunNodes: nextStepRunNodes
|
nextRunNodes: nextStepRunNodes,
|
||||||
|
variables: newVariables
|
||||||
};
|
};
|
||||||
setWorkflowDebugData(newStoreDebugData);
|
setWorkflowDebugData(newStoreDebugData);
|
||||||
|
|
||||||
@@ -794,7 +797,8 @@ const WorkflowContextProvider = ({
|
|||||||
const data = {
|
const data = {
|
||||||
runtimeNodes,
|
runtimeNodes,
|
||||||
runtimeEdges,
|
runtimeEdges,
|
||||||
nextRunNodes: runtimeNodes.filter((node) => node.nodeId === entryNodeId)
|
nextRunNodes: runtimeNodes.filter((node) => node.nodeId === entryNodeId),
|
||||||
|
variables: {}
|
||||||
};
|
};
|
||||||
onStopNodeDebug();
|
onStopNodeDebug();
|
||||||
setWorkflowDebugData(data);
|
setWorkflowDebugData(data);
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
|
import { computedNodeInputReference } from '@/web/core/workflow/utils';
|
||||||
|
import { AppDetailType } from '@fastgpt/global/core/app/type';
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||||
import { FlowNodeItemType, StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node.d';
|
import { FlowNodeItemType, StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node.d';
|
||||||
|
import { TFunction } from 'i18next';
|
||||||
import { type Node, type Edge } from 'reactflow';
|
import { type Node, type Edge } from 'reactflow';
|
||||||
|
|
||||||
export const uiWorkflow2StoreWorkflow = ({
|
export const uiWorkflow2StoreWorkflow = ({
|
||||||
@@ -70,3 +73,60 @@ export const filterExportModules = (modules: StoreNodeItemType[]) => {
|
|||||||
export default function Dom() {
|
export default function Dom() {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getEditorVariables = ({
|
||||||
|
nodeId,
|
||||||
|
nodeList,
|
||||||
|
edges,
|
||||||
|
appDetail,
|
||||||
|
t
|
||||||
|
}: {
|
||||||
|
nodeId: string;
|
||||||
|
nodeList: FlowNodeItemType[];
|
||||||
|
edges: Edge<any>[];
|
||||||
|
appDetail: AppDetailType;
|
||||||
|
t: TFunction;
|
||||||
|
}) => {
|
||||||
|
const currentNode = nodeList.find((node) => node.nodeId === nodeId)!;
|
||||||
|
const nodeVariables = currentNode.inputs
|
||||||
|
.filter((input) => input.canEdit)
|
||||||
|
.map((item) => ({
|
||||||
|
key: item.key,
|
||||||
|
label: item.label,
|
||||||
|
parent: {
|
||||||
|
id: currentNode.nodeId,
|
||||||
|
label: currentNode.name,
|
||||||
|
avatar: currentNode.avatar
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const sourceNodes = computedNodeInputReference({
|
||||||
|
nodeId,
|
||||||
|
nodes: nodeList,
|
||||||
|
edges: edges,
|
||||||
|
chatConfig: appDetail.chatConfig,
|
||||||
|
t
|
||||||
|
});
|
||||||
|
|
||||||
|
const sourceNodeVariables = !sourceNodes
|
||||||
|
? []
|
||||||
|
: sourceNodes
|
||||||
|
.map((node) => {
|
||||||
|
return node.outputs
|
||||||
|
.filter((output) => !!output.label)
|
||||||
|
.map((output) => {
|
||||||
|
return {
|
||||||
|
label: t((output.label as any) || ''),
|
||||||
|
key: output.id,
|
||||||
|
parent: {
|
||||||
|
id: node.nodeId,
|
||||||
|
label: node.name,
|
||||||
|
avatar: node.avatar
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
return [...nodeVariables, ...sourceNodeVariables];
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user