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