mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
123 lines
3.3 KiB
TypeScript
123 lines
3.3 KiB
TypeScript
import { CHAT_TRIGGER_NODE_TYPE, MANUAL_CHAT_TRIGGER_NODE_TYPE } from '@/constants';
|
|
import { type IExecutionResponse, type INodeUi, type IWorkflowDb } from '@/Interface';
|
|
import { type ChatMessage } from '@n8n/chat/types';
|
|
import { get, isEmpty } from 'lodash-es';
|
|
import { NodeConnectionTypes, type IDataObject, type IRunExecutionData } from 'n8n-workflow';
|
|
import { v4 as uuid } from 'uuid';
|
|
|
|
export function isChatNode(node: INodeUi) {
|
|
return [CHAT_TRIGGER_NODE_TYPE, MANUAL_CHAT_TRIGGER_NODE_TYPE].includes(node.type);
|
|
}
|
|
|
|
export function getInputKey(node: INodeUi): string {
|
|
if (node.type === MANUAL_CHAT_TRIGGER_NODE_TYPE && node.typeVersion < 1.1) {
|
|
return 'input';
|
|
}
|
|
if (node.type === CHAT_TRIGGER_NODE_TYPE) {
|
|
return 'chatInput';
|
|
}
|
|
|
|
return 'chatInput';
|
|
}
|
|
|
|
function extractChatInput(
|
|
workflow: IWorkflowDb,
|
|
resultData: IRunExecutionData['resultData'],
|
|
): ChatMessage | undefined {
|
|
const chatTrigger = workflow.nodes.find(isChatNode);
|
|
|
|
if (chatTrigger === undefined) {
|
|
return undefined;
|
|
}
|
|
|
|
const inputKey = getInputKey(chatTrigger);
|
|
const runData = (resultData.runData[chatTrigger.name] ?? [])[0];
|
|
const message = runData?.data?.[NodeConnectionTypes.Main]?.[0]?.[0]?.json?.[inputKey];
|
|
|
|
if (runData === undefined || typeof message !== 'string') {
|
|
return undefined;
|
|
}
|
|
|
|
return {
|
|
text: message,
|
|
sender: 'user',
|
|
id: uuid(),
|
|
};
|
|
}
|
|
|
|
export function extractBotResponse(
|
|
resultData: IRunExecutionData['resultData'],
|
|
executionId: string,
|
|
emptyText?: string,
|
|
): ChatMessage | undefined {
|
|
const lastNodeExecuted = resultData.lastNodeExecuted;
|
|
|
|
if (!lastNodeExecuted) return undefined;
|
|
|
|
const nodeResponseDataArray = get(resultData.runData, lastNodeExecuted) ?? [];
|
|
|
|
const nodeResponseData = nodeResponseDataArray[nodeResponseDataArray.length - 1];
|
|
|
|
let responseMessage: string;
|
|
|
|
if (get(nodeResponseData, 'error')) {
|
|
responseMessage = '[ERROR: ' + get(nodeResponseData, 'error.message') + ']';
|
|
} else {
|
|
const responseData = get(nodeResponseData, 'data.main[0][0].json');
|
|
const text = extractResponseText(responseData) ?? emptyText;
|
|
|
|
if (!text) {
|
|
return undefined;
|
|
}
|
|
|
|
responseMessage = text;
|
|
}
|
|
|
|
return {
|
|
text: responseMessage,
|
|
sender: 'bot',
|
|
id: executionId ?? uuid(),
|
|
};
|
|
}
|
|
|
|
/** Extracts response message from workflow output */
|
|
function extractResponseText(responseData?: IDataObject): string | undefined {
|
|
if (!responseData || isEmpty(responseData)) {
|
|
return undefined;
|
|
}
|
|
|
|
// Paths where the response message might be located
|
|
const paths = ['output', 'text', 'response.text'];
|
|
const matchedPath = paths.find((path) => get(responseData, path));
|
|
|
|
if (!matchedPath) return JSON.stringify(responseData, null, 2);
|
|
|
|
const matchedOutput = get(responseData, matchedPath);
|
|
if (typeof matchedOutput === 'object') {
|
|
return '```json\n' + JSON.stringify(matchedOutput, null, 2) + '\n```';
|
|
}
|
|
|
|
return matchedOutput?.toString() ?? '';
|
|
}
|
|
|
|
export function restoreChatHistory(
|
|
workflowExecutionData: IExecutionResponse | null,
|
|
emptyText?: string,
|
|
): ChatMessage[] {
|
|
if (!workflowExecutionData?.data) {
|
|
return [];
|
|
}
|
|
|
|
const userMessage = extractChatInput(
|
|
workflowExecutionData.workflowData,
|
|
workflowExecutionData.data.resultData,
|
|
);
|
|
const botMessage = extractBotResponse(
|
|
workflowExecutionData.data.resultData,
|
|
workflowExecutionData.id,
|
|
emptyText,
|
|
);
|
|
|
|
return [...(userMessage ? [userMessage] : []), ...(botMessage ? [botMessage] : [])];
|
|
}
|