Skip to content

Commit d16d78b

Browse files
committed
fix: interactive
1 parent c46d421 commit d16d78b

File tree

3 files changed

+52
-55
lines changed

3 files changed

+52
-55
lines changed

packages/service/core/chat/saveChat.ts

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { mergeChatResponseData } from '@fastgpt/global/core/chat/utils';
1616
import { pushChatLog } from './pushChatLog';
1717
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
1818
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
19+
import { extractDeepestInteractive } from '@fastgpt/global/core/workflow/runtime/utils';
1920

2021
type Props = {
2122
chatId: string;
@@ -209,34 +210,24 @@ export const updateInteractiveChat = async ({
209210
}
210211
})();
211212

212-
if (interactiveValue.interactive.type === 'userSelect') {
213-
interactiveValue.interactive = {
214-
...interactiveValue.interactive,
215-
params: {
216-
...interactiveValue.interactive.params,
217-
userSelectedVal: userInteractiveVal
218-
}
219-
};
213+
let finalInteractive = extractDeepestInteractive(interactiveValue.interactive);
214+
215+
if (finalInteractive.type === 'userSelect') {
216+
finalInteractive.params.userSelectedVal = userInteractiveVal;
220217
} else if (
221-
interactiveValue.interactive.type === 'userInput' &&
218+
finalInteractive.type === 'userInput' &&
222219
typeof parsedUserInteractiveVal === 'object'
223220
) {
224-
interactiveValue.interactive = {
225-
...interactiveValue.interactive,
226-
params: {
227-
...interactiveValue.interactive.params,
228-
inputForm: interactiveValue.interactive.params.inputForm.map((item) => {
229-
const itemValue = parsedUserInteractiveVal[item.label];
230-
return itemValue !== undefined
231-
? {
232-
...item,
233-
value: itemValue
234-
}
235-
: item;
236-
}),
237-
submitted: true
238-
}
239-
};
221+
finalInteractive.params.inputForm = finalInteractive.params.inputForm.map((item) => {
222+
const itemValue = parsedUserInteractiveVal[item.label];
223+
return itemValue !== undefined
224+
? {
225+
...item,
226+
value: itemValue
227+
}
228+
: item;
229+
});
230+
finalInteractive.params.submitted = true;
240231
}
241232

242233
if (aiResponse.customFeedbacks) {

packages/service/core/workflow/dispatch/index.ts

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
141141
} else {
142142
props.workflowDispatchDeep += 1;
143143
}
144+
const isRootRuntime = props.workflowDispatchDeep === 1;
144145

145146
if (props.workflowDispatchDeep > 20) {
146147
return {
@@ -161,25 +162,28 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
161162
let workflowRunTimes = 0;
162163

163164
// set sse response headers
164-
if (stream && res) {
165-
res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');
166-
res.setHeader('Access-Control-Allow-Origin', '*');
167-
res.setHeader('X-Accel-Buffering', 'no');
168-
res.setHeader('Cache-Control', 'no-cache, no-transform');
169-
170-
// 10s sends a message to prevent the browser from thinking that the connection is disconnected
171-
const sendStreamTimerSign = () => {
172-
setTimeout(() => {
173-
props?.workflowStreamResponse?.({
174-
event: SseResponseEventEnum.answer,
175-
data: textAdaptGptResponse({
176-
text: ''
177-
})
178-
});
179-
sendStreamTimerSign();
180-
}, 10000);
181-
};
182-
sendStreamTimerSign();
165+
if (isRootRuntime) {
166+
res?.setHeader('Connection', 'keep-alive'); // Set keepalive for long connection
167+
if (stream && res) {
168+
res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');
169+
res.setHeader('Access-Control-Allow-Origin', '*');
170+
res.setHeader('X-Accel-Buffering', 'no');
171+
res.setHeader('Cache-Control', 'no-cache, no-transform');
172+
173+
// 10s sends a message to prevent the browser from thinking that the connection is disconnected
174+
const sendStreamTimerSign = () => {
175+
setTimeout(() => {
176+
props?.workflowStreamResponse?.({
177+
event: SseResponseEventEnum.answer,
178+
data: textAdaptGptResponse({
179+
text: ''
180+
})
181+
});
182+
sendStreamTimerSign();
183+
}, 10000);
184+
};
185+
sendStreamTimerSign();
186+
}
183187
}
184188

185189
variables = {
@@ -373,7 +377,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
373377
};
374378

375379
// Tool call, not need interactive response
376-
if (!props.isToolCall && !props.runningAppInfo.isChildApp) {
380+
if (!props.isToolCall && isRootRuntime) {
377381
props.workflowStreamResponse?.({
378382
event: SseResponseEventEnum.interactive,
379383
data: { interactive: interactiveResult }
@@ -427,14 +431,6 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
427431
})();
428432

429433
if (!nodeRunResult) return [];
430-
if (res?.closed) {
431-
addLog.warn('Request is closed', {
432-
appId: props.runningAppInfo.id,
433-
nodeId: node.nodeId,
434-
nodeName: node.name
435-
});
436-
return [];
437-
}
438434

439435
/*
440436
特殊情况:
@@ -491,6 +487,15 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
491487
await Promise.all(nextStepSkipNodes.map((node) => checkNodeCanRun(node, skippedNodeIdList)))
492488
).flat();
493489

490+
if (res?.closed) {
491+
addLog.warn('Request is closed', {
492+
appId: props.runningAppInfo.id,
493+
nodeId: node.nodeId,
494+
nodeName: node.name
495+
});
496+
return [];
497+
}
498+
494499
return [
495500
...nextStepActiveNodes,
496501
...nextStepSkipNodes,
@@ -631,7 +636,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
631636
if (
632637
version === 'v2' &&
633638
!props.isToolCall &&
634-
!props.runningAppInfo.isChildApp &&
639+
isRootRuntime &&
635640
formatResponseData &&
636641
!(!props.responseDetail && filterModuleTypeList.includes(formatResponseData.moduleType))
637642
) {
@@ -720,7 +725,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
720725
entryNodeIds: nodeInteractiveResponse.entryNodeIds,
721726
interactiveResponse: nodeInteractiveResponse.interactiveResponse
722727
});
723-
if (!props.runningAppInfo.isChildApp) {
728+
if (isRootRuntime) {
724729
chatAssistantResponse.push(interactiveAssistant);
725730
}
726731
return interactiveAssistant.interactive;

projects/app/src/pages/api/v2/chat/completions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
291291
runtimeEdges: initWorkflowEdgeStatus(edges, interactive),
292292
variables,
293293
query: removeEmptyUserInput(userQuestion.value),
294+
lastInteractive: interactive,
294295
chatConfig,
295296
histories: newHistories,
296297
stream,

0 commit comments

Comments
 (0)