UNPKG

dtamind-components

Version:

DTAmindai Components

205 lines (201 loc) 8.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const agents_1 = require("langchain/agents"); const chains_1 = require("langchain/chains"); const handler_1 = require("../../../src/handler"); const Interface_1 = require("../../../src/Interface"); const utils_1 = require("../../../src/utils"); const core_1 = require("./core"); const Moderation_1 = require("../../moderation/Moderation"); const OutputParserHelpers_1 = require("../../outputparsers/OutputParserHelpers"); const src_1 = require("../../../src"); class CSV_Agents { constructor() { this.label = 'CSV Agent'; this.name = 'csvAgent'; this.version = 3.0; this.type = 'AgentExecutor'; this.category = 'Agents'; this.icon = 'CSVagent.svg'; this.description = 'Agent used to answer queries on CSV data'; this.baseClasses = [this.type, ...(0, utils_1.getBaseClasses)(agents_1.AgentExecutor)]; this.inputs = [ { label: 'Csv File', name: 'csvFile', type: 'file', fileType: '.csv' }, { label: 'Language Model', name: 'model', type: 'BaseLanguageModel' }, { label: 'System Message', name: 'systemMessagePrompt', type: 'string', rows: 4, additionalParams: true, optional: true, placeholder: 'I want you to act as a document that I am having a conversation with. Your name is "AI Assistant". You will provide me with answers from the given info. If the answer is not included, say exactly "Hmm, I am not sure." and stop after that. Refuse to answer any question not about the info. Never break character.' }, { 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: 'Custom Pandas Read_CSV Code', description: 'Custom Pandas <a target="_blank" href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html">read_csv</a> function. Takes in an input: "csv_data"', name: 'customReadCSV', default: 'read_csv(csv_data)', type: 'code', optional: true, additionalParams: true } ]; } async init() { // Not used return undefined; } async run(nodeData, input, options) { const csvFileBase64 = nodeData.inputs?.csvFile; const model = nodeData.inputs?.model; const systemMessagePrompt = nodeData.inputs?.systemMessagePrompt; const moderations = nodeData.inputs?.inputModeration; const _customReadCSV = nodeData.inputs?.customReadCSV; if (moderations && moderations.length > 0) { try { // Use the output of the moderation chain as input for the CSV agent input = await (0, Moderation_1.checkInputs)(moderations, input); } catch (e) { await new Promise((resolve) => setTimeout(resolve, 500)); // if (options.shouldStreamResponse) { // 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 shouldStreamResponse = options.shouldStreamResponse; const sseStreamer = options.sseStreamer; const chatId = options.chatId; const callbacks = await (0, handler_1.additionalCallbacks)(nodeData, options); let files = []; let base64String = ''; if (csvFileBase64.startsWith('FILE-STORAGE::')) { const fileName = csvFileBase64.replace('FILE-STORAGE::', ''); if (fileName.startsWith('[') && fileName.endsWith(']')) { files = JSON.parse(fileName); } else { files = [fileName]; } const orgId = options.orgId; const chatflowid = options.chatflowid; for (const file of files) { if (!file) continue; const fileData = await (0, src_1.getFileFromStorage)(file, orgId, chatflowid); base64String += fileData.toString('base64'); } } else { if (csvFileBase64.startsWith('[') && csvFileBase64.endsWith(']')) { files = JSON.parse(csvFileBase64); } else { files = [csvFileBase64]; } for (const file of files) { if (!file) continue; const splitDataURI = file.split(','); splitDataURI.pop(); base64String += splitDataURI.pop() ?? ''; } } const pyodide = await (0, core_1.LoadPyodide)(); // First load the csv file and get the dataframe dictionary of column types // For example using titanic.csv: {'PassengerId': 'int64', 'Survived': 'int64', 'Pclass': 'int64', 'Name': 'object', 'Sex': 'object', 'Age': 'float64', 'SibSp': 'int64', 'Parch': 'int64', 'Ticket': 'object', 'Fare': 'float64', 'Cabin': 'object', 'Embarked': 'object'} let dataframeColDict = ''; let customReadCSVFunc = _customReadCSV ? _customReadCSV : 'read_csv(csv_data)'; try { const code = `import pandas as pd import base64 from io import StringIO import json base64_string = "${base64String}" decoded_data = base64.b64decode(base64_string) csv_data = StringIO(decoded_data.decode('utf-8')) df = pd.${customReadCSVFunc} my_dict = df.dtypes.astype(str).to_dict() print(my_dict) json.dumps(my_dict)`; dataframeColDict = await pyodide.runPythonAsync(code); } catch (error) { throw new Error(error); } // Then tell GPT to come out with ONLY python code // For example: len(df), df[df['SibSp'] > 3]['PassengerId'].count() let pythonCode = ''; if (dataframeColDict) { const chain = new chains_1.LLMChain({ llm: model, prompt: Interface_1.PromptTemplate.fromTemplate(core_1.systemPrompt), verbose: process.env.DEBUG === 'true' ? true : false }); const inputs = { dict: dataframeColDict, question: input }; const res = await chain.call(inputs, [loggerHandler, ...callbacks]); pythonCode = res?.text; // Regex to get rid of markdown code blocks syntax pythonCode = pythonCode.replace(/^```[a-z]+\n|\n```$/gm, ''); } // Then run the code using Pyodide let finalResult = ''; if (pythonCode) { try { const code = `import pandas as pd\n${pythonCode}`; // TODO: get print console output finalResult = await pyodide.runPythonAsync(code); } catch (error) { throw new Error(`Sorry, I'm unable to find answer for question: "${input}" using following code: "${pythonCode}"`); } } // Finally, return a complete answer if (finalResult) { const chain = new chains_1.LLMChain({ llm: model, prompt: Interface_1.PromptTemplate.fromTemplate(systemMessagePrompt ? `${systemMessagePrompt}\n${core_1.finalSystemPrompt}` : core_1.finalSystemPrompt), verbose: process.env.DEBUG === 'true' ? true : false }); const inputs = { question: input, answer: finalResult }; if (options.shouldStreamResponse) { const handler = new handler_1.CustomChainHandler(shouldStreamResponse ? sseStreamer : undefined, chatId); const result = await chain.call(inputs, [loggerHandler, handler, ...callbacks]); return result?.text; } else { const result = await chain.call(inputs, [loggerHandler, ...callbacks]); return result?.text; } } return pythonCode; } } module.exports = { nodeClass: CSV_Agents }; //# sourceMappingURL=CSVAgent.js.map