UNPKG

dtamind-components

Version:

Apps integration for Dtamind. Contain Nodes and Credentials.

225 lines 9.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const chains_1 = require("langchain/chains"); const prompts_1 = require("@langchain/core/prompts"); const runnables_1 = require("@langchain/core/runnables"); const output_parsers_1 = require("@langchain/core/output_parsers"); const messages_1 = require("@langchain/core/messages"); const console_1 = require("@langchain/core/tracers/console"); const Moderation_1 = require("../../moderation/Moderation"); const OutputParserHelpers_1 = require("../../outputparsers/OutputParserHelpers"); const multiModalUtils_1 = require("../../../src/multiModalUtils"); const DtamindChatOpenAI_1 = require("../../chatmodels/ChatOpenAI/DtamindChatOpenAI"); const handler_1 = require("../../../src/handler"); const utils_1 = require("../../../src/utils"); let systemMessage = `The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.`; const inputKey = 'input'; class ConversationChain_Chains { constructor(fields) { this.label = 'Conversation Chain'; this.name = 'conversationChain'; this.version = 3.0; this.type = 'ConversationChain'; this.icon = 'conv.svg'; this.category = 'Chains'; this.description = 'Chat models specific conversational chain with memory'; this.baseClasses = [this.type, ...(0, utils_1.getBaseClasses)(chains_1.ConversationChain)]; this.inputs = [ { label: 'Chat Model', name: 'model', type: 'BaseChatModel' }, { label: 'Memory', name: 'memory', type: 'BaseMemory' }, { label: 'Chat Prompt Template', name: 'chatPromptTemplate', type: 'ChatPromptTemplate', description: 'Override existing prompt with Chat Prompt Template. Human Message must includes {input} variable', optional: true }, /* Deprecated { label: 'Document', name: 'document', type: 'Document', description: 'Include whole document into the context window, if you get maximum context length error, please use model with higher context window like Claude 100k, or gpt4 32k', optional: true, list: true },*/ { label: 'Input Moderation', description: 'Detect text that could generate harmful output and prevent it from being sent to the language model', name: 'inputModeration', type: 'Moderation', optional: true, list: true }, { label: 'System Message', name: 'systemMessagePrompt', type: 'string', rows: 4, description: 'If Chat Prompt Template is provided, this will be ignored', additionalParams: true, optional: true, default: systemMessage, placeholder: systemMessage } ]; this.sessionId = fields?.sessionId; } async init(nodeData, _, options) { const chain = prepareChain(nodeData, options, this.sessionId); return chain; } async run(nodeData, input, options) { const memory = nodeData.inputs?.memory; const chain = await prepareChain(nodeData, options, this.sessionId); const moderations = nodeData.inputs?.inputModeration; const shouldStreamResponse = options.shouldStreamResponse; const sseStreamer = options.sseStreamer; const chatId = options.chatId; if (moderations && moderations.length > 0) { try { // Use the output of the moderation chain as input for the LLM chain input = await (0, Moderation_1.checkInputs)(moderations, input); } catch (e) { await new Promise((resolve) => setTimeout(resolve, 500)); if (options.shouldStreamResponse) { (0, Moderation_1.streamResponse)(options.sseStreamer, options.chatId, e.message); } return (0, OutputParserHelpers_1.formatResponse)(e.message); } } const loggerHandler = new handler_1.ConsoleCallbackHandler(options.logger, options?.orgId); const additionalCallback = await (0, handler_1.additionalCallbacks)(nodeData, options); let res = ''; let callbacks = [loggerHandler, ...additionalCallback]; if (process.env.DEBUG === 'true') { callbacks.push(new console_1.ConsoleCallbackHandler()); } if (shouldStreamResponse) { const handler = new handler_1.CustomChainHandler(sseStreamer, chatId); callbacks.push(handler); res = await chain.invoke({ input }, { callbacks }); } else { res = await chain.invoke({ input }, { callbacks }); } await memory.addChatMessages([ { text: input, type: 'userMessage' }, { text: res, type: 'apiMessage' } ], this.sessionId); return res; } } const prepareChatPrompt = (nodeData, humanImageMessages) => { const memory = nodeData.inputs?.memory; let prompt = nodeData.inputs?.systemMessagePrompt; prompt = (0, utils_1.transformBracesWithColon)(prompt); const chatPromptTemplate = nodeData.inputs?.chatPromptTemplate; let model = nodeData.inputs?.model; if (chatPromptTemplate && chatPromptTemplate.promptMessages.length) { const sysPrompt = chatPromptTemplate.promptMessages[0]; const humanPrompt = chatPromptTemplate.promptMessages[chatPromptTemplate.promptMessages.length - 1]; const messages = [sysPrompt, new prompts_1.MessagesPlaceholder(memory.memoryKey ?? 'chat_history'), humanPrompt]; // OpenAI works better when separate images into standalone human messages if (model instanceof DtamindChatOpenAI_1.ChatOpenAI && humanImageMessages.length) { messages.push(new messages_1.HumanMessage({ content: [...humanImageMessages] })); } else if (humanImageMessages.length) { const lastMessage = messages.pop(); const template = lastMessage.prompt.template; const msg = prompts_1.HumanMessagePromptTemplate.fromTemplate([ ...humanImageMessages, { text: template } ]); msg.inputVariables = lastMessage.inputVariables; messages.push(msg); } const chatPrompt = prompts_1.ChatPromptTemplate.fromMessages(messages); if (chatPromptTemplate.promptValues) { // @ts-ignore chatPrompt.promptValues = chatPromptTemplate.promptValues; } return chatPrompt; } const messages = [ prompts_1.SystemMessagePromptTemplate.fromTemplate(prompt ? prompt : systemMessage), new prompts_1.MessagesPlaceholder(memory.memoryKey ?? 'chat_history'), prompts_1.HumanMessagePromptTemplate.fromTemplate(`{${inputKey}}`) ]; // OpenAI works better when separate images into standalone human messages if (model instanceof DtamindChatOpenAI_1.ChatOpenAI && humanImageMessages.length) { messages.push(new messages_1.HumanMessage({ content: [...humanImageMessages] })); } else if (humanImageMessages.length) { messages.pop(); messages.push(prompts_1.HumanMessagePromptTemplate.fromTemplate([`{${inputKey}}`, ...humanImageMessages])); } const chatPrompt = prompts_1.ChatPromptTemplate.fromMessages(messages); return chatPrompt; }; const prepareChain = async (nodeData, options, sessionId) => { let model = nodeData.inputs?.model; const memory = nodeData.inputs?.memory; const memoryKey = memory.memoryKey ?? 'chat_history'; const prependMessages = options?.prependMessages; let messageContent = []; if ((0, multiModalUtils_1.llmSupportsVision)(model)) { messageContent = await (0, multiModalUtils_1.addImagesToMessages)(nodeData, options, model.multiModalOption); const visionChatModel = model; if (messageContent?.length) { visionChatModel.setVisionModel(); } else { // revert to previous values if image upload is empty visionChatModel.revertToOriginalModel(); } } const chatPrompt = prepareChatPrompt(nodeData, messageContent); let promptVariables = {}; const promptValuesRaw = chatPrompt.promptValues; if (promptValuesRaw) { const promptValues = (0, utils_1.handleEscapeCharacters)(promptValuesRaw, true); for (const val in promptValues) { promptVariables = { ...promptVariables, [val]: () => { return promptValues[val]; } }; } } const conversationChain = runnables_1.RunnableSequence.from([ { [inputKey]: (input) => input.input, [memoryKey]: async () => { const history = await memory.getChatMessages(sessionId, true, prependMessages); return history; }, ...promptVariables }, prepareChatPrompt(nodeData, messageContent), model, new output_parsers_1.StringOutputParser() ]); return conversationChain; }; module.exports = { nodeClass: ConversationChain_Chains }; //# sourceMappingURL=ConversationChain.js.map