mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-15 07:31:19 +00:00
Fix workflow (#5592)
* fix: fileselector default * fix: workflow run process
This commit is contained in:
@@ -17,7 +17,6 @@ import { useTranslation } from 'next-i18next';
|
||||
import type { AppFileSelectConfigType } from '@fastgpt/global/core/app/type.d';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import MySlider from '@/components/Slider';
|
||||
import { defaultAppSelectFileConfig } from '@fastgpt/global/core/app/constants';
|
||||
import ChatFunctionTip from './Tip';
|
||||
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
||||
import { useMount } from 'ahooks';
|
||||
@@ -25,6 +24,7 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
import MyTag from '@fastgpt/web/components/common/Tag/index';
|
||||
import MyDivider from '@fastgpt/web/components/common/MyDivider';
|
||||
import { defaultAppSelectFileConfig } from '@fastgpt/global/core/app/constants';
|
||||
|
||||
const FileSelect = ({
|
||||
forbidVision = false,
|
||||
|
@@ -5,21 +5,18 @@ import type { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workf
|
||||
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import type { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||
import type { WorkflowDebugResponse } from '@fastgpt/service/core/workflow/dispatch/type';
|
||||
|
||||
export type PostWorkflowDebugProps = {
|
||||
nodes: RuntimeNodeItemType[];
|
||||
edges: RuntimeEdgeItemType[];
|
||||
skipNodeQueue?: WorkflowDebugResponse['skipNodeQueue'];
|
||||
variables: Record<string, any>;
|
||||
appId: string;
|
||||
query?: UserChatItemValueItemType[];
|
||||
history?: ChatItemType[];
|
||||
};
|
||||
|
||||
export type PostWorkflowDebugResponse = {
|
||||
finishedNodes: RuntimeNodeItemType[];
|
||||
finishedEdges: RuntimeEdgeItemType[];
|
||||
nextStepRunNodes: RuntimeNodeItemType[];
|
||||
flowResponses: ChatHistoryItemResType[];
|
||||
workflowInteractiveResponse?: WorkflowInteractiveResponseType;
|
||||
export type PostWorkflowDebugResponse = WorkflowDebugResponse & {
|
||||
newVariables: Record<string, any>;
|
||||
};
|
||||
|
@@ -31,7 +31,6 @@ import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
||||
import VariableTip from '@/components/common/Textarea/MyTextarea/VariableTip';
|
||||
import { getWebLLMModel } from '@/web/common/system/utils';
|
||||
import ToolSelect from './components/ToolSelect';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import OptimizerPopover from '@/components/common/PromptEditor/OptimizerPopover';
|
||||
|
||||
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
|
||||
@@ -148,7 +147,7 @@ const EditForm = ({
|
||||
},
|
||||
[appForm.aiSettings.systemPrompt, setAppForm]
|
||||
);
|
||||
|
||||
console.log(appForm.chatConfig.fileSelectConfig);
|
||||
return (
|
||||
<>
|
||||
<Box>
|
||||
|
@@ -11,6 +11,7 @@ import { type SimpleAppSnapshotType, useSimpleAppSnapshots } from './useSnapshot
|
||||
import { useDebounceEffect, useMount } from 'ahooks';
|
||||
import { v1Workflow2V2 } from '@/web/core/workflow/adapt';
|
||||
import { getAppConfigByDiff } from '@/web/core/app/diff';
|
||||
import { defaultAppSelectFileConfig } from '@fastgpt/global/core/app/constants';
|
||||
|
||||
const Edit = dynamic(() => import('./Edit'));
|
||||
const Logs = dynamic(() => import('../Logs/index'));
|
||||
@@ -79,7 +80,13 @@ const SimpleEdit = () => {
|
||||
if (past.length === 0) {
|
||||
const appForm = appWorkflow2Form({
|
||||
nodes: appDetail.modules,
|
||||
chatConfig: appDetail.chatConfig
|
||||
chatConfig: {
|
||||
...appDetail.chatConfig,
|
||||
fileSelectConfig: appDetail.chatConfig.fileSelectConfig || {
|
||||
...defaultAppSelectFileConfig,
|
||||
canSelectFile: true
|
||||
}
|
||||
}
|
||||
});
|
||||
saveSnapshot({
|
||||
appForm,
|
||||
|
@@ -127,11 +127,9 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
|
||||
}
|
||||
];
|
||||
|
||||
const lastInteractive = getLastInteractiveValue(mockHistory);
|
||||
onNextNodeDebug({
|
||||
...workflowDebugData,
|
||||
// Rewrite runtimeEdges
|
||||
runtimeEdges: storeEdges2RuntimeEdges(workflowDebugData.runtimeEdges, lastInteractive),
|
||||
runtimeEdges: workflowDebugData.runtimeEdges,
|
||||
query: updatedQuery,
|
||||
history: mockHistory
|
||||
});
|
||||
@@ -189,7 +187,7 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
|
||||
<Box fontWeight={'bold'} flex={'1'}>
|
||||
{t('common:core.workflow.debug.Run result')}
|
||||
</Box>
|
||||
{workflowDebugData?.nextRunNodes.length !== 0 && (
|
||||
{workflowDebugData?.entryNodeIds.length !== 0 && (
|
||||
<PopoverConfirm
|
||||
Trigger={
|
||||
<Button
|
||||
@@ -209,8 +207,8 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
|
||||
<>
|
||||
{(debugResult.status === 'success' || debugResult.status === 'skipped') &&
|
||||
!debugResult.isExpired &&
|
||||
workflowDebugData?.nextRunNodes &&
|
||||
workflowDebugData.nextRunNodes.length > 0 && (
|
||||
workflowDebugData?.entryNodeIds &&
|
||||
workflowDebugData.entryNodeIds.length > 0 && (
|
||||
<Button
|
||||
ml={2}
|
||||
size={'sm'}
|
||||
@@ -221,8 +219,8 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
|
||||
{t('common:next_step')}
|
||||
</Button>
|
||||
)}
|
||||
{workflowDebugData?.nextRunNodes &&
|
||||
workflowDebugData?.nextRunNodes.length === 0 && (
|
||||
{workflowDebugData?.entryNodeIds &&
|
||||
workflowDebugData?.entryNodeIds.length === 0 && (
|
||||
<Button ml={2} size={'sm'} variant={'primary'} onClick={onStopNodeDebug}>
|
||||
{t('common:core.workflow.debug.Done')}
|
||||
</Button>
|
||||
|
@@ -54,12 +54,12 @@ import { cloneDeep } from 'lodash';
|
||||
import { type AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
||||
import WorkflowInitContextProvider, { WorkflowNodeEdgeContext } from './workflowInitContext';
|
||||
import WorkflowEventContextProvider from './workflowEventContext';
|
||||
import { getAppConfigByDiff } from '@/web/core/app/diff';
|
||||
import WorkflowStatusContextProvider from './workflowStatusContext';
|
||||
import { type ChatItemType, type UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { type WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { useChatStore } from '@/web/core/chat/context/useChatStore';
|
||||
import type { WorkflowDebugResponse } from '@fastgpt/service/core/workflow/dispatch/type';
|
||||
|
||||
/*
|
||||
Context
|
||||
@@ -266,7 +266,9 @@ type WorkflowContextType = {
|
||||
export type DebugDataType = {
|
||||
runtimeNodes: RuntimeNodeItemType[];
|
||||
runtimeEdges: RuntimeEdgeItemType[];
|
||||
nextRunNodes: RuntimeNodeItemType[];
|
||||
entryNodeIds: string[];
|
||||
skipNodeQueue?: WorkflowDebugResponse['skipNodeQueue'];
|
||||
|
||||
variables: Record<string, any>;
|
||||
history?: ChatItemType[];
|
||||
query?: UserChatItemValueItemType[];
|
||||
@@ -686,112 +688,67 @@ const WorkflowContextProvider = ({
|
||||
}))
|
||||
);
|
||||
|
||||
// 2. Set isEntry field and get entryNodes
|
||||
// 2. Set isEntry field and get entryNodes, and set running status
|
||||
const runtimeNodes = debugData.runtimeNodes.map((item) => ({
|
||||
...item,
|
||||
isEntry: debugData.nextRunNodes.some((node) => node.nodeId === item.nodeId)
|
||||
isEntry: debugData.entryNodeIds.some((id) => id === item.nodeId)
|
||||
}));
|
||||
const entryNodes = runtimeNodes.filter((item) => item.isEntry);
|
||||
|
||||
const runtimeNodeStatus: Record<string, string> = entryNodes
|
||||
.map((node) => {
|
||||
const status = checkNodeRunStatus({
|
||||
node,
|
||||
nodesMap: new Map(runtimeNodes.map((item) => [item.nodeId, item])),
|
||||
runtimeEdges: debugData?.runtimeEdges || []
|
||||
});
|
||||
|
||||
return {
|
||||
nodeId: node.nodeId,
|
||||
status
|
||||
};
|
||||
})
|
||||
.reduce(
|
||||
(acc, cur) => ({
|
||||
...acc,
|
||||
[cur.nodeId]: cur.status
|
||||
}),
|
||||
{}
|
||||
);
|
||||
|
||||
// 3. Set entry node status to running
|
||||
entryNodes.forEach((node) => {
|
||||
if (runtimeNodeStatus[node.nodeId] !== 'wait') {
|
||||
const entryNodes = runtimeNodes.filter((item) => {
|
||||
if (item.isEntry) {
|
||||
onChangeNode({
|
||||
nodeId: node.nodeId,
|
||||
nodeId: item.nodeId,
|
||||
type: 'attr',
|
||||
key: 'debugResult',
|
||||
value: defaultRunningStatus
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
// 4. Run one step
|
||||
const {
|
||||
finishedEdges,
|
||||
finishedNodes,
|
||||
nextStepRunNodes,
|
||||
flowResponses,
|
||||
newVariables,
|
||||
workflowInteractiveResponse
|
||||
} = await postWorkflowDebug({
|
||||
nodes: runtimeNodes,
|
||||
edges: debugData.runtimeEdges,
|
||||
variables: {
|
||||
appId,
|
||||
cTime: formatTime2YMDHMW(),
|
||||
...debugData.variables
|
||||
},
|
||||
query: debugData.query, // 添加 query 参数
|
||||
history: debugData.history,
|
||||
appId
|
||||
});
|
||||
// 3. Run one step
|
||||
const { memoryEdges, entryNodeIds, skipNodeQueue, nodeResponses, newVariables } =
|
||||
await postWorkflowDebug({
|
||||
nodes: runtimeNodes,
|
||||
edges: debugData.runtimeEdges,
|
||||
skipNodeQueue: debugData.skipNodeQueue,
|
||||
variables: {
|
||||
appId,
|
||||
cTime: formatTime2YMDHMW(),
|
||||
...debugData.variables
|
||||
},
|
||||
query: debugData.query, // 添加 query 参数
|
||||
history: debugData.history,
|
||||
appId
|
||||
});
|
||||
|
||||
// 5. Store debug result
|
||||
// 4. Store debug result
|
||||
setWorkflowDebugData({
|
||||
runtimeNodes: finishedNodes,
|
||||
// edges need to save status
|
||||
runtimeEdges: finishedEdges,
|
||||
nextRunNodes: nextStepRunNodes,
|
||||
variables: newVariables,
|
||||
workflowInteractiveResponse: workflowInteractiveResponse
|
||||
runtimeNodes: debugData.runtimeNodes,
|
||||
runtimeEdges: memoryEdges,
|
||||
entryNodeIds,
|
||||
skipNodeQueue,
|
||||
variables: newVariables
|
||||
});
|
||||
|
||||
// 6. selected entry node and Update entry node debug result
|
||||
// 5. selected entry node and Update entry node debug result
|
||||
setNodes((state) =>
|
||||
state.map((node) => {
|
||||
const isEntryNode = entryNodes.some((item) => item.nodeId === node.data.nodeId);
|
||||
|
||||
if (!isEntryNode || runtimeNodeStatus[node.data.nodeId] === 'wait') return node;
|
||||
|
||||
const result = flowResponses.find((item) => item.nodeId === node.data.nodeId);
|
||||
|
||||
if (runtimeNodeStatus[node.data.nodeId] === 'skip') {
|
||||
return {
|
||||
...node,
|
||||
selected: isEntryNode,
|
||||
data: {
|
||||
...node.data,
|
||||
debugResult: {
|
||||
status: 'skipped',
|
||||
showResult: true,
|
||||
isExpired: false
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
const result = nodeResponses[node.data.nodeId];
|
||||
if (!result) return node;
|
||||
return {
|
||||
...node,
|
||||
selected: isEntryNode,
|
||||
selected: result.type === 'run' && isEntryNode,
|
||||
data: {
|
||||
...node.data,
|
||||
debugResult: {
|
||||
status: 'success',
|
||||
response: result,
|
||||
status: result.type === 'run' ? 'success' : 'skipped',
|
||||
response: result.response,
|
||||
showResult: true,
|
||||
isExpired: false,
|
||||
workflowInteractiveResponse: workflowInteractiveResponse
|
||||
workflowInteractiveResponse: result.interactiveResponse
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -799,13 +756,9 @@ const WorkflowContextProvider = ({
|
||||
);
|
||||
|
||||
// Check for an empty response(Skip node)
|
||||
if (
|
||||
!workflowInteractiveResponse &&
|
||||
flowResponses.length === 0 &&
|
||||
nextStepRunNodes.length > 0
|
||||
) {
|
||||
onNextNodeDebug(debugData);
|
||||
}
|
||||
// if (!workflowInteractiveResponse && flowResponses.length === 0 && entryNodeIds.length > 0) {
|
||||
// onNextNodeDebug(debugData);
|
||||
// }
|
||||
} catch (error) {
|
||||
entryNodes.forEach((node) => {
|
||||
onChangeNode({
|
||||
@@ -856,7 +809,10 @@ const WorkflowContextProvider = ({
|
||||
const data: DebugDataType = {
|
||||
runtimeNodes,
|
||||
runtimeEdges,
|
||||
nextRunNodes: runtimeNodes.filter((node) => node.nodeId === entryNodeId),
|
||||
entryNodeIds: runtimeNodes
|
||||
.filter((node) => node.nodeId === entryNodeId)
|
||||
.map((node) => node.nodeId),
|
||||
skipNodeQueue: [],
|
||||
variables,
|
||||
query,
|
||||
history
|
||||
|
@@ -21,6 +21,7 @@ async function handler(
|
||||
const {
|
||||
nodes = [],
|
||||
edges = [],
|
||||
skipNodeQueue,
|
||||
variables = {},
|
||||
appId,
|
||||
query = [],
|
||||
@@ -47,34 +48,34 @@ async function handler(
|
||||
|
||||
// auth balance
|
||||
const { timezone, externalProvider } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
||||
const lastInteractive = getLastInteractiveValue(history);
|
||||
const interactive = getLastInteractiveValue(history);
|
||||
|
||||
/* start process */
|
||||
const { flowUsages, flowResponses, debugResponse, newVariables, workflowInteractiveResponse } =
|
||||
await dispatchWorkFlow({
|
||||
res,
|
||||
lang: getLocale(req),
|
||||
requestOrigin: req.headers.origin,
|
||||
mode: 'debug',
|
||||
timezone,
|
||||
externalProvider,
|
||||
uid: tmbId,
|
||||
runningAppInfo: {
|
||||
id: app._id,
|
||||
teamId: app.teamId,
|
||||
tmbId: app.tmbId
|
||||
},
|
||||
runningUserInfo: await getRunningUserInfoByTmbId(tmbId),
|
||||
runtimeNodes: nodes,
|
||||
runtimeEdges: edges,
|
||||
lastInteractive,
|
||||
variables,
|
||||
query: query,
|
||||
chatConfig: defaultApp.chatConfig,
|
||||
histories: history,
|
||||
stream: false,
|
||||
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
|
||||
});
|
||||
const { flowUsages, debugResponse, newVariables } = await dispatchWorkFlow({
|
||||
res,
|
||||
lang: getLocale(req),
|
||||
requestOrigin: req.headers.origin,
|
||||
mode: 'debug',
|
||||
timezone,
|
||||
externalProvider,
|
||||
uid: tmbId,
|
||||
runningAppInfo: {
|
||||
id: app._id,
|
||||
teamId: app.teamId,
|
||||
tmbId: app.tmbId
|
||||
},
|
||||
runningUserInfo: await getRunningUserInfoByTmbId(tmbId),
|
||||
runtimeNodes: nodes,
|
||||
runtimeEdges: edges,
|
||||
defaultSkipNodeQueue: skipNodeQueue,
|
||||
lastInteractive: interactive,
|
||||
variables,
|
||||
query: query,
|
||||
chatConfig: defaultApp.chatConfig,
|
||||
histories: history,
|
||||
stream: false,
|
||||
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
|
||||
});
|
||||
|
||||
createChatUsage({
|
||||
appName: `${app.name}-Debug`,
|
||||
@@ -86,10 +87,8 @@ async function handler(
|
||||
});
|
||||
|
||||
return {
|
||||
...debugResponse,
|
||||
newVariables,
|
||||
flowResponses,
|
||||
workflowInteractiveResponse
|
||||
...debugResponse!,
|
||||
newVariables
|
||||
};
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user