dtamind-components
Version:
DTAmindai Components
269 lines • 12.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const messages_1 = require("@langchain/core/messages");
const prompts_1 = require("@langchain/core/prompts");
const output_parsers_1 = require("langchain/output_parsers");
const chains_1 = require("langchain/chains");
const handler_1 = require("../../../src/handler");
const utils_1 = require("../../../src/utils");
const Moderation_1 = require("../../moderation/Moderation");
const OutputParserHelpers_1 = require("../../outputparsers/OutputParserHelpers");
const multiModalUtils_1 = require("../../../src/multiModalUtils");
class LLMChain_Chains {
constructor() {
this.label = 'LLM Chain';
this.name = 'llmChain';
this.version = 3.0;
this.type = 'LLMChain';
this.icon = 'LLM_Chain.svg';
this.category = 'Chains';
this.description = 'Chain to run queries against LLMs';
this.baseClasses = [this.type, ...(0, utils_1.getBaseClasses)(chains_1.LLMChain)];
this.inputs = [
{
label: 'Language Model',
name: 'model',
type: 'BaseLanguageModel'
},
{
label: 'Prompt',
name: 'prompt',
type: 'BasePromptTemplate'
},
{
label: 'Output Parser',
name: 'outputParser',
type: 'BaseLLMOutputParser',
optional: 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: 'Chain Name',
name: 'chainName',
type: 'string',
placeholder: 'Name Your Chain',
optional: true
}
];
this.outputs = [
{
label: 'LLM Chain',
name: 'llmChain',
baseClasses: [this.type, ...(0, utils_1.getBaseClasses)(chains_1.LLMChain)]
},
{
label: 'Output Prediction',
name: 'outputPrediction',
baseClasses: ['string', 'json']
}
];
}
async init(nodeData, input, options) {
const model = nodeData.inputs?.model;
const prompt = nodeData.inputs?.prompt;
const output = nodeData.outputs?.output;
let promptValues = nodeData.inputs?.prompt.promptValues;
const llmOutputParser = nodeData.inputs?.outputParser;
this.outputParser = llmOutputParser;
if (llmOutputParser) {
let autoFix = llmOutputParser.autoFix;
if (autoFix === true) {
this.outputParser = output_parsers_1.OutputFixingParser.fromLLM(model, llmOutputParser);
}
}
if (output === this.name) {
const chain = new chains_1.LLMChain({
llm: model,
outputParser: this.outputParser,
prompt,
verbose: process.env.DEBUG === 'true'
});
return chain;
}
else if (output === 'outputPrediction') {
const chain = new chains_1.LLMChain({
llm: model,
outputParser: this.outputParser,
prompt,
verbose: process.env.DEBUG === 'true'
});
const inputVariables = chain.prompt.inputVariables; // ["product"]
promptValues = (0, OutputParserHelpers_1.injectOutputParser)(this.outputParser, chain, promptValues);
// Disable streaming because its not final chain
const disableStreaming = true;
const res = await runPrediction(inputVariables, chain, input, promptValues, options, nodeData, disableStreaming);
// eslint-disable-next-line no-console
console.log('\x1b[92m\x1b[1m\n*****OUTPUT PREDICTION*****\n\x1b[0m\x1b[0m');
// eslint-disable-next-line no-console
console.log(res);
let finalRes = res;
if (this.outputParser && typeof res === 'object' && Object.prototype.hasOwnProperty.call(res, 'json')) {
finalRes = res.json;
}
/**
* Apply string transformation to convert special chars:
* FROM: hello i am ben\n\n\thow are you?
* TO: hello i am benFLOWISE_NEWLINEFLOWISE_NEWLINEFLOWISE_TABhow are you?
*/
return (0, utils_1.handleEscapeCharacters)(finalRes, false);
}
}
async run(nodeData, input, options) {
const inputVariables = nodeData.instance.prompt.inputVariables; // ["product"]
const chain = nodeData.instance;
let promptValues = nodeData.inputs?.prompt.promptValues;
const outputParser = nodeData.inputs?.outputParser;
if (!this.outputParser && outputParser) {
this.outputParser = outputParser;
}
promptValues = (0, OutputParserHelpers_1.injectOutputParser)(this.outputParser, chain, promptValues);
const res = await runPrediction(inputVariables, chain, input, promptValues, options, nodeData);
// eslint-disable-next-line no-console
console.log('\x1b[93m\x1b[1m\n*****FINAL RESULT*****\n\x1b[0m\x1b[0m');
// eslint-disable-next-line no-console
console.log(res);
return res;
}
}
const runPrediction = async (inputVariables, chain, input, promptValuesRaw, options, nodeData, disableStreaming) => {
const loggerHandler = new handler_1.ConsoleCallbackHandler(options.logger, options?.orgId);
const callbacks = await (0, handler_1.additionalCallbacks)(nodeData, options);
const moderations = nodeData.inputs?.inputModeration;
// this is true if the prediction is external and the client has requested streaming='true'
const shouldStreamResponse = !disableStreaming && 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 (shouldStreamResponse) {
(0, Moderation_1.streamResponse)(sseStreamer, chatId, e.message);
}
return (0, OutputParserHelpers_1.formatResponse)(e.message);
}
}
/**
* Apply string transformation to reverse converted special chars:
* FROM: { "value": "hello i am benFLOWISE_NEWLINEFLOWISE_NEWLINEFLOWISE_TABhow are you?" }
* TO: { "value": "hello i am ben\n\n\thow are you?" }
*/
const promptValues = (0, utils_1.handleEscapeCharacters)(promptValuesRaw, true);
if ((0, multiModalUtils_1.llmSupportsVision)(chain.llm)) {
const visionChatModel = chain.llm;
const messageContent = await (0, multiModalUtils_1.addImagesToMessages)(nodeData, options, visionChatModel.multiModalOption);
if (messageContent?.length) {
// Change model to gpt-4-vision && max token to higher when using gpt-4-vision
visionChatModel.setVisionModel();
// Add image to the message
if (chain.prompt instanceof prompts_1.PromptTemplate) {
const existingPromptTemplate = chain.prompt.template;
const msg = prompts_1.HumanMessagePromptTemplate.fromTemplate([
...messageContent,
{
text: existingPromptTemplate
}
]);
msg.inputVariables = chain.prompt.inputVariables;
chain.prompt = prompts_1.ChatPromptTemplate.fromMessages([msg]);
}
else if (chain.prompt instanceof prompts_1.ChatPromptTemplate) {
if (chain.prompt.promptMessages.at(-1) instanceof prompts_1.HumanMessagePromptTemplate) {
const lastMessage = chain.prompt.promptMessages.pop();
const template = lastMessage.prompt.template;
const msg = prompts_1.HumanMessagePromptTemplate.fromTemplate([
...messageContent,
{
text: template
}
]);
msg.inputVariables = lastMessage.inputVariables;
chain.prompt.promptMessages.push(msg);
}
else {
chain.prompt.promptMessages.push(new messages_1.HumanMessage({ content: messageContent }));
}
}
else if (chain.prompt instanceof prompts_1.FewShotPromptTemplate) {
let existingFewShotPromptTemplate = chain.prompt.examplePrompt.template;
let newFewShotPromptTemplate = prompts_1.ChatPromptTemplate.fromMessages([
prompts_1.HumanMessagePromptTemplate.fromTemplate(existingFewShotPromptTemplate)
]);
newFewShotPromptTemplate.promptMessages.push(new messages_1.HumanMessage({ content: messageContent }));
// @ts-ignore
chain.prompt.examplePrompt = newFewShotPromptTemplate;
}
}
else {
// revert to previous values if image upload is empty
visionChatModel.revertToOriginalModel();
}
}
if (promptValues && inputVariables.length > 0) {
let seen = [];
for (const variable of inputVariables) {
seen.push(variable);
if (promptValues[variable] != null) {
seen.pop();
}
}
if (seen.length === 0) {
// All inputVariables have fixed values specified
const options = { ...promptValues };
if (shouldStreamResponse) {
const handler = new handler_1.CustomChainHandler(sseStreamer, chatId);
const res = await chain.call(options, [loggerHandler, handler, ...callbacks]);
return (0, OutputParserHelpers_1.formatResponse)(res?.text);
}
else {
const res = await chain.call(options, [loggerHandler, ...callbacks]);
return (0, OutputParserHelpers_1.formatResponse)(res?.text);
}
}
else if (seen.length === 1) {
// If one inputVariable is not specify, use input (user's question) as value
const lastValue = seen.pop();
if (!lastValue)
throw new Error('Please provide Prompt Values');
const options = {
...promptValues,
[lastValue]: input
};
if (shouldStreamResponse) {
const handler = new handler_1.CustomChainHandler(sseStreamer, chatId);
const res = await chain.call(options, [loggerHandler, handler, ...callbacks]);
return (0, OutputParserHelpers_1.formatResponse)(res?.text);
}
else {
const res = await chain.call(options, [loggerHandler, ...callbacks]);
return (0, OutputParserHelpers_1.formatResponse)(res?.text);
}
}
else {
throw new Error(`Please provide Prompt Values for: ${seen.join(', ')}`);
}
}
else {
if (shouldStreamResponse) {
const handler = new handler_1.CustomChainHandler(sseStreamer, chatId);
const res = await chain.run(input, [loggerHandler, handler, ...callbacks]);
return (0, OutputParserHelpers_1.formatResponse)(res);
}
else {
const res = await chain.run(input, [loggerHandler, ...callbacks]);
return (0, OutputParserHelpers_1.formatResponse)(res);
}
}
};
module.exports = { nodeClass: LLMChain_Chains };
//# sourceMappingURL=LLMChain.js.map