mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 19:00:59 +03:00
Merge branch 'main' into feature/Milvus
# Conflicts: # packages/components/package.json
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { APIChain } from 'langchain/chains'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { PromptTemplate } from 'langchain/prompts'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
|
||||
export const API_URL_RAW_PROMPT_TEMPLATE = `You are given the below API Documentation:
|
||||
{api_docs}
|
||||
Using this documentation, generate the full API url to call for answering the user question.
|
||||
You should build the API url in order to get a response that is as short as possible, while still getting the necessary information to answer the question. Pay attention to deliberately exclude any unnecessary pieces of data in the API call.
|
||||
|
||||
Question:{question}
|
||||
API url:`
|
||||
|
||||
export const API_RESPONSE_RAW_PROMPT_TEMPLATE =
|
||||
'Given this {api_response} response for {api_url}. use the given response to answer this {question}'
|
||||
|
||||
class GETApiChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
baseClasses: string[]
|
||||
description: string
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'GET API Chain'
|
||||
this.name = 'getApiChain'
|
||||
this.version = 1.0
|
||||
this.type = 'GETApiChain'
|
||||
this.icon = 'apichain.svg'
|
||||
this.category = 'Chains'
|
||||
this.description = 'Chain to run queries against GET API'
|
||||
this.baseClasses = [this.type, ...getBaseClasses(APIChain)]
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'Language Model',
|
||||
name: 'model',
|
||||
type: 'BaseLanguageModel'
|
||||
},
|
||||
{
|
||||
label: 'API Documentation',
|
||||
name: 'apiDocs',
|
||||
type: 'string',
|
||||
description:
|
||||
'Description of how API works. Please refer to more <a target="_blank" href="https://github.com/hwchase17/langchain/blob/master/langchain/chains/api/open_meteo_docs.py">examples</a>',
|
||||
rows: 4
|
||||
},
|
||||
{
|
||||
label: 'Headers',
|
||||
name: 'headers',
|
||||
type: 'json',
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'URL Prompt',
|
||||
name: 'urlPrompt',
|
||||
type: 'string',
|
||||
description: 'Prompt used to tell LLMs how to construct the URL. Must contains {api_docs} and {question}',
|
||||
default: API_URL_RAW_PROMPT_TEMPLATE,
|
||||
rows: 4,
|
||||
additionalParams: true
|
||||
},
|
||||
{
|
||||
label: 'Answer Prompt',
|
||||
name: 'ansPrompt',
|
||||
type: 'string',
|
||||
description:
|
||||
'Prompt used to tell LLMs how to return the API response. Must contains {api_response}, {api_url}, and {question}',
|
||||
default: API_RESPONSE_RAW_PROMPT_TEMPLATE,
|
||||
rows: 4,
|
||||
additionalParams: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData): Promise<any> {
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const apiDocs = nodeData.inputs?.apiDocs as string
|
||||
const headers = nodeData.inputs?.headers as string
|
||||
const urlPrompt = nodeData.inputs?.urlPrompt as string
|
||||
const ansPrompt = nodeData.inputs?.ansPrompt as string
|
||||
|
||||
const chain = await getAPIChain(apiDocs, model, headers, urlPrompt, ansPrompt)
|
||||
return chain
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string> {
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const apiDocs = nodeData.inputs?.apiDocs as string
|
||||
const headers = nodeData.inputs?.headers as string
|
||||
const urlPrompt = nodeData.inputs?.urlPrompt as string
|
||||
const ansPrompt = nodeData.inputs?.ansPrompt as string
|
||||
|
||||
const chain = await getAPIChain(apiDocs, model, headers, urlPrompt, ansPrompt)
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId, 2)
|
||||
const res = await chain.run(input, [loggerHandler, handler])
|
||||
return res
|
||||
} else {
|
||||
const res = await chain.run(input, [loggerHandler])
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getAPIChain = async (documents: string, llm: BaseLanguageModel, headers: string, urlPrompt: string, ansPrompt: string) => {
|
||||
const apiUrlPrompt = new PromptTemplate({
|
||||
inputVariables: ['api_docs', 'question'],
|
||||
template: urlPrompt ? urlPrompt : API_URL_RAW_PROMPT_TEMPLATE
|
||||
})
|
||||
|
||||
const apiResponsePrompt = new PromptTemplate({
|
||||
inputVariables: ['api_docs', 'question', 'api_url', 'api_response'],
|
||||
template: ansPrompt ? ansPrompt : API_RESPONSE_RAW_PROMPT_TEMPLATE
|
||||
})
|
||||
|
||||
const chain = APIChain.fromLLMAndAPIDocs(llm, documents, {
|
||||
apiUrlPrompt,
|
||||
apiResponsePrompt,
|
||||
verbose: process.env.DEBUG === 'true' ? true : false,
|
||||
headers: typeof headers === 'object' ? headers : headers ? JSON.parse(headers) : {}
|
||||
})
|
||||
return chain
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: GETApiChain_Chains }
|
||||
@@ -0,0 +1,100 @@
|
||||
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { APIChain, createOpenAPIChain } from 'langchain/chains'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { ChatOpenAI } from 'langchain/chat_models/openai'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
|
||||
class OpenApiChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
baseClasses: string[]
|
||||
description: string
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'OpenAPI Chain'
|
||||
this.name = 'openApiChain'
|
||||
this.version = 1.0
|
||||
this.type = 'OpenAPIChain'
|
||||
this.icon = 'openapi.png'
|
||||
this.category = 'Chains'
|
||||
this.description = 'Chain that automatically select and call APIs based only on an OpenAPI spec'
|
||||
this.baseClasses = [this.type, ...getBaseClasses(APIChain)]
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'ChatOpenAI Model',
|
||||
name: 'model',
|
||||
type: 'ChatOpenAI'
|
||||
},
|
||||
{
|
||||
label: 'YAML Link',
|
||||
name: 'yamlLink',
|
||||
type: 'string',
|
||||
placeholder: 'https://api.speak.com/openapi.yaml',
|
||||
description: 'If YAML link is provided, uploaded YAML File will be ignored and YAML link will be used instead'
|
||||
},
|
||||
{
|
||||
label: 'YAML File',
|
||||
name: 'yamlFile',
|
||||
type: 'file',
|
||||
fileType: '.yaml',
|
||||
description: 'If YAML link is provided, uploaded YAML File will be ignored and YAML link will be used instead'
|
||||
},
|
||||
{
|
||||
label: 'Headers',
|
||||
name: 'headers',
|
||||
type: 'json',
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData): Promise<any> {
|
||||
return await initChain(nodeData)
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string> {
|
||||
const chain = await initChain(nodeData)
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId)
|
||||
const res = await chain.run(input, [loggerHandler, handler])
|
||||
return res
|
||||
} else {
|
||||
const res = await chain.run(input, [loggerHandler])
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const initChain = async (nodeData: INodeData) => {
|
||||
const model = nodeData.inputs?.model as ChatOpenAI
|
||||
const headers = nodeData.inputs?.headers as string
|
||||
const yamlLink = nodeData.inputs?.yamlLink as string
|
||||
const yamlFileBase64 = nodeData.inputs?.yamlFile as string
|
||||
|
||||
let yamlString = ''
|
||||
|
||||
if (yamlLink) {
|
||||
yamlString = yamlLink
|
||||
} else {
|
||||
const splitDataURI = yamlFileBase64.split(',')
|
||||
splitDataURI.pop()
|
||||
const bf = Buffer.from(splitDataURI.pop() || '', 'base64')
|
||||
yamlString = bf.toString('utf-8')
|
||||
}
|
||||
|
||||
return await createOpenAPIChain(yamlString, {
|
||||
llm: model,
|
||||
headers: typeof headers === 'object' ? headers : headers ? JSON.parse(headers) : {},
|
||||
verbose: process.env.DEBUG === 'true' ? true : false
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: OpenApiChain_Chains }
|
||||
@@ -0,0 +1,123 @@
|
||||
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { PromptTemplate } from 'langchain/prompts'
|
||||
import { API_RESPONSE_RAW_PROMPT_TEMPLATE, API_URL_RAW_PROMPT_TEMPLATE, APIChain } from './postCore'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
|
||||
class POSTApiChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
baseClasses: string[]
|
||||
description: string
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'POST API Chain'
|
||||
this.name = 'postApiChain'
|
||||
this.version = 1.0
|
||||
this.type = 'POSTApiChain'
|
||||
this.icon = 'apichain.svg'
|
||||
this.category = 'Chains'
|
||||
this.description = 'Chain to run queries against POST API'
|
||||
this.baseClasses = [this.type, ...getBaseClasses(APIChain)]
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'Language Model',
|
||||
name: 'model',
|
||||
type: 'BaseLanguageModel'
|
||||
},
|
||||
{
|
||||
label: 'API Documentation',
|
||||
name: 'apiDocs',
|
||||
type: 'string',
|
||||
description:
|
||||
'Description of how API works. Please refer to more <a target="_blank" href="https://github.com/hwchase17/langchain/blob/master/langchain/chains/api/open_meteo_docs.py">examples</a>',
|
||||
rows: 4
|
||||
},
|
||||
{
|
||||
label: 'Headers',
|
||||
name: 'headers',
|
||||
type: 'json',
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'URL Prompt',
|
||||
name: 'urlPrompt',
|
||||
type: 'string',
|
||||
description: 'Prompt used to tell LLMs how to construct the URL. Must contains {api_docs} and {question}',
|
||||
default: API_URL_RAW_PROMPT_TEMPLATE,
|
||||
rows: 4,
|
||||
additionalParams: true
|
||||
},
|
||||
{
|
||||
label: 'Answer Prompt',
|
||||
name: 'ansPrompt',
|
||||
type: 'string',
|
||||
description:
|
||||
'Prompt used to tell LLMs how to return the API response. Must contains {api_response}, {api_url}, and {question}',
|
||||
default: API_RESPONSE_RAW_PROMPT_TEMPLATE,
|
||||
rows: 4,
|
||||
additionalParams: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData): Promise<any> {
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const apiDocs = nodeData.inputs?.apiDocs as string
|
||||
const headers = nodeData.inputs?.headers as string
|
||||
const urlPrompt = nodeData.inputs?.urlPrompt as string
|
||||
const ansPrompt = nodeData.inputs?.ansPrompt as string
|
||||
|
||||
const chain = await getAPIChain(apiDocs, model, headers, urlPrompt, ansPrompt)
|
||||
return chain
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string> {
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const apiDocs = nodeData.inputs?.apiDocs as string
|
||||
const headers = nodeData.inputs?.headers as string
|
||||
const urlPrompt = nodeData.inputs?.urlPrompt as string
|
||||
const ansPrompt = nodeData.inputs?.ansPrompt as string
|
||||
|
||||
const chain = await getAPIChain(apiDocs, model, headers, urlPrompt, ansPrompt)
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId, 2)
|
||||
const res = await chain.run(input, [loggerHandler, handler])
|
||||
return res
|
||||
} else {
|
||||
const res = await chain.run(input, [loggerHandler])
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getAPIChain = async (documents: string, llm: BaseLanguageModel, headers: string, urlPrompt: string, ansPrompt: string) => {
|
||||
const apiUrlPrompt = new PromptTemplate({
|
||||
inputVariables: ['api_docs', 'question'],
|
||||
template: urlPrompt ? urlPrompt : API_URL_RAW_PROMPT_TEMPLATE
|
||||
})
|
||||
|
||||
const apiResponsePrompt = new PromptTemplate({
|
||||
inputVariables: ['api_docs', 'question', 'api_url_body', 'api_response'],
|
||||
template: ansPrompt ? ansPrompt : API_RESPONSE_RAW_PROMPT_TEMPLATE
|
||||
})
|
||||
|
||||
const chain = APIChain.fromLLMAndAPIDocs(llm, documents, {
|
||||
apiUrlPrompt,
|
||||
apiResponsePrompt,
|
||||
verbose: process.env.DEBUG === 'true' ? true : false,
|
||||
headers: typeof headers === 'object' ? headers : headers ? JSON.parse(headers) : {}
|
||||
})
|
||||
return chain
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: POSTApiChain_Chains }
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.88 92.96" style="enable-background:new 0 0 122.88 92.96" xml:space="preserve"><style type="text/css"><![CDATA[
|
||||
.st0{fill-rule:evenodd;clip-rule:evenodd;}
|
||||
]]></style><g><path class="st0" d="M100.09,6.87l2.5,3.3c0.66,0.87,0.49,2.12-0.38,2.77l-2.66,2.02c0.48,1.29,0.79,2.65,0.92,4.06l3.03,0.41 c1.08,0.15,1.84,1.15,1.69,2.23l-0.56,4.1c-0.15,1.08-1.15,1.84-2.23,1.69l-3.3-0.45c-0.59,1.28-1.34,2.46-2.22,3.52l1.85,2.43 c0.66,0.87,0.49,2.12-0.38,2.78l-3.3,2.5c-0.87,0.66-2.12,0.49-2.78-0.38l-2.02-2.66c-1.29,0.48-2.66,0.79-4.06,0.92l-0.41,3.03 c-0.15,1.08-1.15,1.84-2.23,1.69l-4.1-0.56c-1.08-0.15-1.84-1.15-1.69-2.23l0.45-3.3c-1.28-0.59-2.46-1.34-3.52-2.23l-2.43,1.85 c-0.87,0.66-2.12,0.49-2.78-0.38l-2.5-3.3c-0.66-0.87-0.49-2.12,0.38-2.77l2.66-2.02c-0.48-1.29-0.79-2.65-0.92-4.06l-3.03-0.41 c-1.08-0.15-1.84-1.15-1.69-2.23l0.56-4.1c0.15-1.08,1.15-1.84,2.23-1.69l3.3,0.45c0.59-1.28,1.34-2.46,2.23-3.52L70.84,7.9 c-0.66-0.87-0.49-2.12,0.38-2.78l3.3-2.5c0.87-0.66,2.12-0.49,2.78,0.38l2.02,2.66c1.29-0.48,2.66-0.79,4.06-0.92l0.41-3.02 c0.15-1.08,1.15-1.84,2.23-1.69l4.1,0.56c1.08,0.15,1.84,1.15,1.69,2.23l-0.45,3.3c1.28,0.59,2.46,1.34,3.52,2.23l2.43-1.85 C98.19,5.83,99.44,6,100.09,6.87L100.09,6.87L100.09,6.87z M55.71,13.75c-0.23,0.02-0.46,0.04-0.69,0.06 c-5.63,0.54-11.1,2.59-15.62,6.1c-5.23,4.05-9.2,10.11-10.73,18.14l-0.48,2.51L25.69,41c-2.45,0.43-4.64,1.02-6.56,1.77 c-1.86,0.72-3.52,1.61-4.97,2.66c-1.16,0.84-2.16,1.78-3.01,2.8c-2.63,3.15-3.85,7.1-3.82,11.1c0.03,4.06,1.35,8.16,3.79,11.53 c0.91,1.25,1.96,2.4,3.16,3.4l0.03,0.02l-2.68,7.13c-0.71-0.47-1.4-0.98-2.04-1.52c-1.68-1.4-3.15-2.99-4.4-4.72 C1.84,70.57,0.04,64.95,0,59.35c-0.04-5.66,1.72-11.29,5.52-15.85c1.23-1.48,2.68-2.84,4.34-4.04c1.93-1.4,4.14-2.58,6.64-3.55 c1.72-0.67,3.56-1.23,5.5-1.68c2.2-8.74,6.89-15.47,12.92-20.14c5.64-4.37,12.43-6.92,19.42-7.59c2.13-0.21,4.29-0.24,6.43-0.09 c-0.47,0.25-0.91,0.53-1.33,0.85l-0.03,0.02c-1.93,1.47-3.32,3.7-3.68,6.3L55.71,13.75L55.71,13.75z M43.85,87.38H31.99l-1.7,5.58 H19.6l12.75-33.87h11.46l12.7,33.87H45.55L43.85,87.38L43.85,87.38z M41.63,80.04l-3.7-12.17l-3.71,12.17H41.63L41.63,80.04z M59.78,59.09h17.41c3.79,0,6.64,0.9,8.52,2.7c1.88,1.8,2.83,4.38,2.83,7.71c0,3.42-1.04,6.1-3.09,8.03 c-2.06,1.93-5.21,2.89-9.43,2.89h-5.74v12.54h-10.5V59.09L59.78,59.09z M70.28,73.56h2.58c2.03,0,3.46-0.35,4.28-1.06 c0.82-0.7,1.23-1.6,1.23-2.7c0-1.06-0.36-1.96-1.07-2.7c-0.71-0.74-2.05-1.11-4.02-1.11h-3V73.56L70.28,73.56z M92.77,59.09h10.5 v33.87h-10.5V59.09L92.77,59.09z M112.01,31.74c1.07,0.83,2.09,1.77,3.07,2.82c1.07,1.15,2.08,2.45,3.03,3.9 c3.2,4.92,4.84,11.49,4.77,17.92c-0.07,6.31-1.77,12.59-5.25,17.21c-0.84,1.11-1.77,2.15-2.78,3.12V62.15 c0.43-1.87,0.65-3.84,0.67-5.83c0.06-5.07-1.18-10.16-3.59-13.86c-0.69-1.07-1.45-2.03-2.25-2.89c-0.65-0.7-1.34-1.34-2.05-1.9 c0.07-0.3,0.13-0.6,0.17-0.9c0.08-0.62,0.11-1.25,0.07-1.88c0.82-0.32,1.58-0.75,2.26-1.27l0.03-0.02 C110.86,33.06,111.48,32.44,112.01,31.74L112.01,31.74z M85.89,12.37c4.45,0.61,7.57,4.71,6.96,9.17 c-0.61,4.45-4.71,7.57-9.17,6.96c-4.45-0.61-7.57-4.71-6.96-9.17S81.44,11.76,85.89,12.37L85.89,12.37L85.89,12.37z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,162 @@
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { CallbackManagerForChainRun } from 'langchain/callbacks'
|
||||
import { BaseChain, ChainInputs, LLMChain, SerializedAPIChain } from 'langchain/chains'
|
||||
import { BasePromptTemplate, PromptTemplate } from 'langchain/prompts'
|
||||
import { ChainValues } from 'langchain/schema'
|
||||
import fetch from 'node-fetch'
|
||||
|
||||
export const API_URL_RAW_PROMPT_TEMPLATE = `You are given the below API Documentation:
|
||||
{api_docs}
|
||||
Using this documentation, generate a json string with two keys: "url" and "data".
|
||||
The value of "url" should be a string, which is the API url to call for answering the user question.
|
||||
The value of "data" should be a dictionary of key-value pairs you want to POST to the url as a JSON body.
|
||||
Be careful to always use double quotes for strings in the json string.
|
||||
You should build the json string in order to get a response that is as short as possible, while still getting the necessary information to answer the question. Pay attention to deliberately exclude any unnecessary pieces of data in the API call.
|
||||
|
||||
Question:{question}
|
||||
json string:`
|
||||
|
||||
export const API_RESPONSE_RAW_PROMPT_TEMPLATE = `${API_URL_RAW_PROMPT_TEMPLATE} {api_url_body}
|
||||
|
||||
Here is the response from the API:
|
||||
|
||||
{api_response}
|
||||
|
||||
Summarize this response to answer the original question.
|
||||
|
||||
Summary:`
|
||||
|
||||
const defaultApiUrlPrompt = new PromptTemplate({
|
||||
inputVariables: ['api_docs', 'question'],
|
||||
template: API_URL_RAW_PROMPT_TEMPLATE
|
||||
})
|
||||
|
||||
const defaultApiResponsePrompt = new PromptTemplate({
|
||||
inputVariables: ['api_docs', 'question', 'api_url_body', 'api_response'],
|
||||
template: API_RESPONSE_RAW_PROMPT_TEMPLATE
|
||||
})
|
||||
|
||||
export interface APIChainInput extends Omit<ChainInputs, 'memory'> {
|
||||
apiAnswerChain: LLMChain
|
||||
apiRequestChain: LLMChain
|
||||
apiDocs: string
|
||||
inputKey?: string
|
||||
headers?: Record<string, string>
|
||||
/** Key to use for output, defaults to `output` */
|
||||
outputKey?: string
|
||||
}
|
||||
|
||||
export type APIChainOptions = {
|
||||
headers?: Record<string, string>
|
||||
apiUrlPrompt?: BasePromptTemplate
|
||||
apiResponsePrompt?: BasePromptTemplate
|
||||
}
|
||||
|
||||
export class APIChain extends BaseChain implements APIChainInput {
|
||||
apiAnswerChain: LLMChain
|
||||
|
||||
apiRequestChain: LLMChain
|
||||
|
||||
apiDocs: string
|
||||
|
||||
headers = {}
|
||||
|
||||
inputKey = 'question'
|
||||
|
||||
outputKey = 'output'
|
||||
|
||||
get inputKeys() {
|
||||
return [this.inputKey]
|
||||
}
|
||||
|
||||
get outputKeys() {
|
||||
return [this.outputKey]
|
||||
}
|
||||
|
||||
constructor(fields: APIChainInput) {
|
||||
super(fields)
|
||||
this.apiRequestChain = fields.apiRequestChain
|
||||
this.apiAnswerChain = fields.apiAnswerChain
|
||||
this.apiDocs = fields.apiDocs
|
||||
this.inputKey = fields.inputKey ?? this.inputKey
|
||||
this.outputKey = fields.outputKey ?? this.outputKey
|
||||
this.headers = fields.headers ?? this.headers
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
async _call(values: ChainValues, runManager?: CallbackManagerForChainRun): Promise<ChainValues> {
|
||||
try {
|
||||
const question: string = values[this.inputKey]
|
||||
|
||||
const api_url_body = await this.apiRequestChain.predict({ question, api_docs: this.apiDocs }, runManager?.getChild())
|
||||
|
||||
const { url, data } = JSON.parse(api_url_body)
|
||||
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: this.headers,
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
|
||||
const api_response = await res.text()
|
||||
|
||||
const answer = await this.apiAnswerChain.predict(
|
||||
{ question, api_docs: this.apiDocs, api_url_body, api_response },
|
||||
runManager?.getChild()
|
||||
)
|
||||
|
||||
return { [this.outputKey]: answer }
|
||||
} catch (error) {
|
||||
return { [this.outputKey]: error }
|
||||
}
|
||||
}
|
||||
|
||||
_chainType() {
|
||||
return 'api_chain' as const
|
||||
}
|
||||
|
||||
static async deserialize(data: SerializedAPIChain) {
|
||||
const { api_request_chain, api_answer_chain, api_docs } = data
|
||||
|
||||
if (!api_request_chain) {
|
||||
throw new Error('LLMChain must have api_request_chain')
|
||||
}
|
||||
if (!api_answer_chain) {
|
||||
throw new Error('LLMChain must have api_answer_chain')
|
||||
}
|
||||
if (!api_docs) {
|
||||
throw new Error('LLMChain must have api_docs')
|
||||
}
|
||||
|
||||
return new APIChain({
|
||||
apiAnswerChain: await LLMChain.deserialize(api_answer_chain),
|
||||
apiRequestChain: await LLMChain.deserialize(api_request_chain),
|
||||
apiDocs: api_docs
|
||||
})
|
||||
}
|
||||
|
||||
serialize(): SerializedAPIChain {
|
||||
return {
|
||||
_type: this._chainType(),
|
||||
api_answer_chain: this.apiAnswerChain.serialize(),
|
||||
api_request_chain: this.apiRequestChain.serialize(),
|
||||
api_docs: this.apiDocs
|
||||
}
|
||||
}
|
||||
|
||||
static fromLLMAndAPIDocs(
|
||||
llm: BaseLanguageModel,
|
||||
apiDocs: string,
|
||||
options: APIChainOptions & Omit<APIChainInput, 'apiAnswerChain' | 'apiRequestChain' | 'apiDocs'> = {}
|
||||
): APIChain {
|
||||
const { apiUrlPrompt = defaultApiUrlPrompt, apiResponsePrompt = defaultApiResponsePrompt } = options
|
||||
const apiRequestChain = new LLMChain({ prompt: apiUrlPrompt, llm })
|
||||
const apiAnswerChain = new LLMChain({ prompt: apiResponsePrompt, llm })
|
||||
return new this({
|
||||
apiAnswerChain,
|
||||
apiRequestChain,
|
||||
apiDocs,
|
||||
...options
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,19 @@
|
||||
import { ICommonObject, IMessage, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { ConversationChain } from 'langchain/chains'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { getBaseClasses, mapChatHistory } from '../../../src/utils'
|
||||
import { ChatPromptTemplate, HumanMessagePromptTemplate, MessagesPlaceholder, SystemMessagePromptTemplate } from 'langchain/prompts'
|
||||
import { BufferMemory, ChatMessageHistory } from 'langchain/memory'
|
||||
import { BufferMemory } from 'langchain/memory'
|
||||
import { BaseChatModel } from 'langchain/chat_models/base'
|
||||
import { AIChatMessage, HumanChatMessage } from 'langchain/schema'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
import { flatten } from 'lodash'
|
||||
import { Document } from 'langchain/document'
|
||||
|
||||
const 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.`
|
||||
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.`
|
||||
|
||||
class ConversationChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
@@ -21,6 +24,7 @@ class ConversationChain_Chains implements INode {
|
||||
constructor() {
|
||||
this.label = 'Conversation Chain'
|
||||
this.name = 'conversationChain'
|
||||
this.version = 1.0
|
||||
this.type = 'ConversationChain'
|
||||
this.icon = 'chain.svg'
|
||||
this.category = 'Chains'
|
||||
@@ -37,6 +41,15 @@ class ConversationChain_Chains implements INode {
|
||||
name: 'memory',
|
||||
type: 'BaseMemory'
|
||||
},
|
||||
{
|
||||
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: 'System Message',
|
||||
name: 'systemMessagePrompt',
|
||||
@@ -53,10 +66,28 @@ class ConversationChain_Chains implements INode {
|
||||
const model = nodeData.inputs?.model as BaseChatModel
|
||||
const memory = nodeData.inputs?.memory as BufferMemory
|
||||
const prompt = nodeData.inputs?.systemMessagePrompt as string
|
||||
const docs = nodeData.inputs?.document as Document[]
|
||||
|
||||
const flattenDocs = docs && docs.length ? flatten(docs) : []
|
||||
const finalDocs = []
|
||||
for (let i = 0; i < flattenDocs.length; i += 1) {
|
||||
finalDocs.push(new Document(flattenDocs[i]))
|
||||
}
|
||||
|
||||
let finalText = ''
|
||||
for (let i = 0; i < finalDocs.length; i += 1) {
|
||||
finalText += finalDocs[i].pageContent
|
||||
}
|
||||
|
||||
const replaceChar: string[] = ['{', '}']
|
||||
for (const char of replaceChar) finalText = finalText.replaceAll(char, '')
|
||||
|
||||
if (finalText) systemMessage = `${systemMessage}\nThe AI has the following context:\n${finalText}`
|
||||
|
||||
const obj: any = {
|
||||
llm: model,
|
||||
memory
|
||||
memory,
|
||||
verbose: process.env.DEBUG === 'true' ? true : false
|
||||
}
|
||||
|
||||
const chatPrompt = ChatPromptTemplate.fromPromptMessages([
|
||||
@@ -75,22 +106,20 @@ class ConversationChain_Chains implements INode {
|
||||
const memory = nodeData.inputs?.memory as BufferMemory
|
||||
|
||||
if (options && options.chatHistory) {
|
||||
const chatHistory = []
|
||||
const histories: IMessage[] = options.chatHistory
|
||||
|
||||
for (const message of histories) {
|
||||
if (message.type === 'apiMessage') {
|
||||
chatHistory.push(new AIChatMessage(message.message))
|
||||
} else if (message.type === 'userMessage') {
|
||||
chatHistory.push(new HumanChatMessage(message.message))
|
||||
}
|
||||
}
|
||||
memory.chatHistory = new ChatMessageHistory(chatHistory)
|
||||
memory.chatHistory = mapChatHistory(options)
|
||||
chain.memory = memory
|
||||
}
|
||||
|
||||
const res = await chain.call({ input })
|
||||
return res?.response
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId)
|
||||
const res = await chain.call({ input }, [loggerHandler, handler])
|
||||
return res?.response
|
||||
} else {
|
||||
const res = await chain.call({ input }, [loggerHandler])
|
||||
return res?.response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+152
-37
@@ -1,26 +1,25 @@
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { ICommonObject, IMessage, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { ConversationalRetrievalQAChain } from 'langchain/chains'
|
||||
import { BaseRetriever } from 'langchain/schema'
|
||||
|
||||
const default_qa_template = `Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.
|
||||
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Helpful Answer:`
|
||||
|
||||
const qa_template = `Use the following pieces of context to answer the question at the end.
|
||||
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Helpful Answer:`
|
||||
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { getBaseClasses, mapChatHistory } from '../../../src/utils'
|
||||
import { ConversationalRetrievalQAChain, QAChainParams } from 'langchain/chains'
|
||||
import { BaseRetriever } from 'langchain/schema/retriever'
|
||||
import { BufferMemory, BufferMemoryInput } from 'langchain/memory'
|
||||
import { PromptTemplate } from 'langchain/prompts'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
import {
|
||||
default_map_reduce_template,
|
||||
default_qa_template,
|
||||
qa_template,
|
||||
map_reduce_template,
|
||||
CUSTOM_QUESTION_GENERATOR_CHAIN_PROMPT,
|
||||
refine_question_template,
|
||||
refine_template
|
||||
} from './prompts'
|
||||
|
||||
class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
@@ -31,6 +30,7 @@ class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
constructor() {
|
||||
this.label = 'Conversational Retrieval QA Chain'
|
||||
this.name = 'conversationalRetrievalQAChain'
|
||||
this.version = 1.0
|
||||
this.type = 'ConversationalRetrievalQAChain'
|
||||
this.icon = 'chain.svg'
|
||||
this.category = 'Chains'
|
||||
@@ -47,6 +47,19 @@ class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
name: 'vectorStoreRetriever',
|
||||
type: 'BaseRetriever'
|
||||
},
|
||||
{
|
||||
label: 'Memory',
|
||||
name: 'memory',
|
||||
type: 'BaseMemory',
|
||||
optional: true,
|
||||
description: 'If left empty, a default BufferMemory will be used'
|
||||
},
|
||||
{
|
||||
label: 'Return Source Documents',
|
||||
name: 'returnSourceDocuments',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'System Message',
|
||||
name: 'systemMessagePrompt',
|
||||
@@ -56,6 +69,31 @@ class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
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: 'Chain Option',
|
||||
name: 'chainOption',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
label: 'MapReduceDocumentsChain',
|
||||
name: 'map_reduce',
|
||||
description:
|
||||
'Suitable for QA tasks over larger documents and can run the preprocessing step in parallel, reducing the running time'
|
||||
},
|
||||
{
|
||||
label: 'RefineDocumentsChain',
|
||||
name: 'refine',
|
||||
description: 'Suitable for QA tasks over a large number of documents.'
|
||||
},
|
||||
{
|
||||
label: 'StuffDocumentsChain',
|
||||
name: 'stuff',
|
||||
description: 'Suitable for QA tasks over a small number of documents.'
|
||||
}
|
||||
],
|
||||
additionalParams: true,
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -64,35 +102,112 @@ class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const vectorStoreRetriever = nodeData.inputs?.vectorStoreRetriever as BaseRetriever
|
||||
const systemMessagePrompt = nodeData.inputs?.systemMessagePrompt as string
|
||||
const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean
|
||||
const chainOption = nodeData.inputs?.chainOption as string
|
||||
const externalMemory = nodeData.inputs?.memory
|
||||
|
||||
const chain = ConversationalRetrievalQAChain.fromLLM(model, vectorStoreRetriever, {
|
||||
const obj: any = {
|
||||
verbose: process.env.DEBUG === 'true' ? true : false,
|
||||
qaTemplate: systemMessagePrompt ? `${systemMessagePrompt}\n${qa_template}` : default_qa_template
|
||||
})
|
||||
questionGeneratorChainOptions: {
|
||||
template: CUSTOM_QUESTION_GENERATOR_CHAIN_PROMPT
|
||||
}
|
||||
}
|
||||
|
||||
if (returnSourceDocuments) obj.returnSourceDocuments = returnSourceDocuments
|
||||
|
||||
if (chainOption === 'map_reduce') {
|
||||
obj.qaChainOptions = {
|
||||
type: 'map_reduce',
|
||||
combinePrompt: PromptTemplate.fromTemplate(
|
||||
systemMessagePrompt ? `${systemMessagePrompt}\n${map_reduce_template}` : default_map_reduce_template
|
||||
)
|
||||
} as QAChainParams
|
||||
} else if (chainOption === 'refine') {
|
||||
const qprompt = new PromptTemplate({
|
||||
inputVariables: ['context', 'question'],
|
||||
template: refine_question_template(systemMessagePrompt)
|
||||
})
|
||||
const rprompt = new PromptTemplate({
|
||||
inputVariables: ['context', 'question', 'existing_answer'],
|
||||
template: refine_template
|
||||
})
|
||||
obj.qaChainOptions = {
|
||||
type: 'refine',
|
||||
questionPrompt: qprompt,
|
||||
refinePrompt: rprompt
|
||||
} as QAChainParams
|
||||
} else {
|
||||
obj.qaChainOptions = {
|
||||
type: 'stuff',
|
||||
prompt: PromptTemplate.fromTemplate(systemMessagePrompt ? `${systemMessagePrompt}\n${qa_template}` : default_qa_template)
|
||||
} as QAChainParams
|
||||
}
|
||||
|
||||
if (externalMemory) {
|
||||
externalMemory.memoryKey = 'chat_history'
|
||||
externalMemory.inputKey = 'question'
|
||||
externalMemory.outputKey = 'text'
|
||||
externalMemory.returnMessages = true
|
||||
if (chainOption === 'refine') externalMemory.outputKey = 'output_text'
|
||||
obj.memory = externalMemory
|
||||
} else {
|
||||
const fields: BufferMemoryInput = {
|
||||
memoryKey: 'chat_history',
|
||||
inputKey: 'question',
|
||||
outputKey: 'text',
|
||||
returnMessages: true
|
||||
}
|
||||
if (chainOption === 'refine') fields.outputKey = 'output_text'
|
||||
obj.memory = new BufferMemory(fields)
|
||||
}
|
||||
|
||||
const chain = ConversationalRetrievalQAChain.fromLLM(model, vectorStoreRetriever, obj)
|
||||
return chain
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string> {
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | ICommonObject> {
|
||||
const chain = nodeData.instance as ConversationalRetrievalQAChain
|
||||
let chatHistory = ''
|
||||
const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean
|
||||
const chainOption = nodeData.inputs?.chainOption as string
|
||||
|
||||
if (options && options.chatHistory) {
|
||||
const histories: IMessage[] = options.chatHistory
|
||||
chatHistory = histories
|
||||
.map((item) => {
|
||||
return item.message
|
||||
})
|
||||
.join('')
|
||||
let model = nodeData.inputs?.model
|
||||
|
||||
// Temporary fix: https://github.com/hwchase17/langchainjs/issues/754
|
||||
model.streaming = false
|
||||
chain.questionGeneratorChain.llm = model
|
||||
|
||||
const obj = { question: input }
|
||||
|
||||
if (options && options.chatHistory && chain.memory) {
|
||||
;(chain.memory as any).chatHistory = mapChatHistory(options)
|
||||
}
|
||||
|
||||
const obj = {
|
||||
question: input,
|
||||
chat_history: chatHistory ? chatHistory : []
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(
|
||||
options.socketIO,
|
||||
options.socketIOClientId,
|
||||
chainOption === 'refine' ? 4 : undefined,
|
||||
returnSourceDocuments
|
||||
)
|
||||
const res = await chain.call(obj, [loggerHandler, handler])
|
||||
if (chainOption === 'refine') {
|
||||
if (res.output_text && res.sourceDocuments) {
|
||||
return {
|
||||
text: res.output_text,
|
||||
sourceDocuments: res.sourceDocuments
|
||||
}
|
||||
}
|
||||
return res?.output_text
|
||||
}
|
||||
if (res.text && res.sourceDocuments) return res
|
||||
return res?.text
|
||||
} else {
|
||||
const res = await chain.call(obj, [loggerHandler])
|
||||
if (res.text && res.sourceDocuments) return res
|
||||
return res?.text
|
||||
}
|
||||
|
||||
const res = await chain.call(obj)
|
||||
|
||||
return res?.text
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
export const default_qa_template = `Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.
|
||||
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Helpful Answer:`
|
||||
|
||||
export const qa_template = `Use the following pieces of context to answer the question at the end.
|
||||
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
Helpful Answer:`
|
||||
|
||||
export const default_map_reduce_template = `Given the following extracted parts of a long document and a question, create a final answer.
|
||||
If you don't know the answer, just say that you don't know. Don't try to make up an answer.
|
||||
|
||||
{summaries}
|
||||
|
||||
Question: {question}
|
||||
Helpful Answer:`
|
||||
|
||||
export const map_reduce_template = `Given the following extracted parts of a long document and a question, create a final answer.
|
||||
|
||||
{summaries}
|
||||
|
||||
Question: {question}
|
||||
Helpful Answer:`
|
||||
|
||||
export const refine_question_template = (sysPrompt?: string) => {
|
||||
let returnPrompt = ''
|
||||
if (sysPrompt)
|
||||
returnPrompt = `Context information is below.
|
||||
---------------------
|
||||
{context}
|
||||
---------------------
|
||||
Given the context information and not prior knowledge, ${sysPrompt}
|
||||
Answer the question: {question}.
|
||||
Answer:`
|
||||
if (!sysPrompt)
|
||||
returnPrompt = `Context information is below.
|
||||
---------------------
|
||||
{context}
|
||||
---------------------
|
||||
Given the context information and not prior knowledge, answer the question: {question}.
|
||||
Answer:`
|
||||
return returnPrompt
|
||||
}
|
||||
|
||||
export const refine_template = `The original question is as follows: {question}
|
||||
We have provided an existing answer: {existing_answer}
|
||||
We have the opportunity to refine the existing answer (only if needed) with some more context below.
|
||||
------------
|
||||
{context}
|
||||
------------
|
||||
Given the new context, refine the original answer to better answer the question.
|
||||
If you can't find answer from the context, return the original answer.`
|
||||
|
||||
export const CUSTOM_QUESTION_GENERATOR_CHAIN_PROMPT = `Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, answer in the same language as the follow up question. include it in the standalone question.
|
||||
|
||||
Chat History:
|
||||
{chat_history}
|
||||
Follow Up Input: {question}
|
||||
Standalone question:`
|
||||
@@ -1,11 +1,13 @@
|
||||
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { getBaseClasses, handleEscapeCharacters } from '../../../src/utils'
|
||||
import { LLMChain } from 'langchain/chains'
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
|
||||
class LLMChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
@@ -17,6 +19,7 @@ class LLMChain_Chains implements INode {
|
||||
constructor() {
|
||||
this.label = 'LLM Chain'
|
||||
this.name = 'llmChain'
|
||||
this.version = 1.0
|
||||
this.type = 'LLMChain'
|
||||
this.icon = 'chain.svg'
|
||||
this.category = 'Chains'
|
||||
@@ -50,12 +53,12 @@ class LLMChain_Chains implements INode {
|
||||
{
|
||||
label: 'Output Prediction',
|
||||
name: 'outputPrediction',
|
||||
baseClasses: ['string']
|
||||
baseClasses: ['string', 'json']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData, input: string): Promise<any> {
|
||||
async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> {
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const prompt = nodeData.inputs?.prompt
|
||||
const output = nodeData.outputs?.output as string
|
||||
@@ -67,21 +70,25 @@ class LLMChain_Chains implements INode {
|
||||
} else if (output === 'outputPrediction') {
|
||||
const chain = new LLMChain({ llm: model, prompt, verbose: process.env.DEBUG === 'true' ? true : false })
|
||||
const inputVariables = chain.prompt.inputVariables as string[] // ["product"]
|
||||
const res = await runPrediction(inputVariables, chain, input, promptValues)
|
||||
const res = await runPrediction(inputVariables, chain, input, promptValues, options)
|
||||
// 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)
|
||||
return res
|
||||
/**
|
||||
* 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 handleEscapeCharacters(res, false)
|
||||
}
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string): Promise<string> {
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string> {
|
||||
const inputVariables = nodeData.instance.prompt.inputVariables as string[] // ["product"]
|
||||
const chain = nodeData.instance as LLMChain
|
||||
const promptValues = nodeData.inputs?.prompt.promptValues as ICommonObject
|
||||
|
||||
const res = await runPrediction(inputVariables, chain, input, promptValues)
|
||||
const res = await runPrediction(inputVariables, chain, input, promptValues, options)
|
||||
// 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
|
||||
@@ -90,11 +97,26 @@ class LLMChain_Chains implements INode {
|
||||
}
|
||||
}
|
||||
|
||||
const runPrediction = async (inputVariables: string[], chain: LLMChain, input: string, promptValues: ICommonObject) => {
|
||||
if (inputVariables.length === 1) {
|
||||
const res = await chain.run(input)
|
||||
return res
|
||||
} else if (inputVariables.length > 1) {
|
||||
const runPrediction = async (
|
||||
inputVariables: string[],
|
||||
chain: LLMChain,
|
||||
input: string,
|
||||
promptValuesRaw: ICommonObject,
|
||||
options: ICommonObject
|
||||
) => {
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
const isStreaming = options.socketIO && options.socketIOClientId
|
||||
const socketIO = isStreaming ? options.socketIO : undefined
|
||||
const socketIOClientId = isStreaming ? options.socketIOClientId : ''
|
||||
|
||||
/**
|
||||
* 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 = handleEscapeCharacters(promptValuesRaw, true)
|
||||
|
||||
if (promptValues && inputVariables.length > 0) {
|
||||
let seen: string[] = []
|
||||
|
||||
for (const variable of inputVariables) {
|
||||
@@ -106,11 +128,15 @@ const runPrediction = async (inputVariables: string[], chain: LLMChain, input: s
|
||||
|
||||
if (seen.length === 0) {
|
||||
// All inputVariables have fixed values specified
|
||||
const options = {
|
||||
...promptValues
|
||||
const options = { ...promptValues }
|
||||
if (isStreaming) {
|
||||
const handler = new CustomChainHandler(socketIO, socketIOClientId)
|
||||
const res = await chain.call(options, [loggerHandler, handler])
|
||||
return res?.text
|
||||
} else {
|
||||
const res = await chain.call(options, [loggerHandler])
|
||||
return res?.text
|
||||
}
|
||||
const res = await chain.call(options)
|
||||
return res?.text
|
||||
} else if (seen.length === 1) {
|
||||
// If one inputVariable is not specify, use input (user's question) as value
|
||||
const lastValue = seen.pop()
|
||||
@@ -119,14 +145,26 @@ const runPrediction = async (inputVariables: string[], chain: LLMChain, input: s
|
||||
...promptValues,
|
||||
[lastValue]: input
|
||||
}
|
||||
const res = await chain.call(options)
|
||||
return res?.text
|
||||
if (isStreaming) {
|
||||
const handler = new CustomChainHandler(socketIO, socketIOClientId)
|
||||
const res = await chain.call(options, [loggerHandler, handler])
|
||||
return res?.text
|
||||
} else {
|
||||
const res = await chain.call(options, [loggerHandler])
|
||||
return res?.text
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Please provide Prompt Values for: ${seen.join(', ')}`)
|
||||
}
|
||||
} else {
|
||||
const res = await chain.run(input)
|
||||
return res
|
||||
if (isStreaming) {
|
||||
const handler = new CustomChainHandler(socketIO, socketIOClientId)
|
||||
const res = await chain.run(input, [loggerHandler, handler])
|
||||
return res
|
||||
} else {
|
||||
const res = await chain.run(input, [loggerHandler])
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { ICommonObject, INode, INodeData, INodeParams, PromptRetriever } from '../../../src/Interface'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { MultiPromptChain } from 'langchain/chains'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
|
||||
class MultiPromptChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
baseClasses: string[]
|
||||
description: string
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'Multi Prompt Chain'
|
||||
this.name = 'multiPromptChain'
|
||||
this.version = 1.0
|
||||
this.type = 'MultiPromptChain'
|
||||
this.icon = 'chain.svg'
|
||||
this.category = 'Chains'
|
||||
this.description = 'Chain automatically picks an appropriate prompt from multiple prompt templates'
|
||||
this.baseClasses = [this.type, ...getBaseClasses(MultiPromptChain)]
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'Language Model',
|
||||
name: 'model',
|
||||
type: 'BaseLanguageModel'
|
||||
},
|
||||
{
|
||||
label: 'Prompt Retriever',
|
||||
name: 'promptRetriever',
|
||||
type: 'PromptRetriever',
|
||||
list: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData): Promise<any> {
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const promptRetriever = nodeData.inputs?.promptRetriever as PromptRetriever[]
|
||||
const promptNames = []
|
||||
const promptDescriptions = []
|
||||
const promptTemplates = []
|
||||
|
||||
for (const prompt of promptRetriever) {
|
||||
promptNames.push(prompt.name)
|
||||
promptDescriptions.push(prompt.description)
|
||||
promptTemplates.push(prompt.systemMessage)
|
||||
}
|
||||
|
||||
const chain = MultiPromptChain.fromLLMAndPrompts(model, {
|
||||
promptNames,
|
||||
promptDescriptions,
|
||||
promptTemplates,
|
||||
llmChainOpts: { verbose: process.env.DEBUG === 'true' ? true : false }
|
||||
})
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string> {
|
||||
const chain = nodeData.instance as MultiPromptChain
|
||||
const obj = { input }
|
||||
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId, 2)
|
||||
const res = await chain.call(obj, [loggerHandler, handler])
|
||||
return res?.text
|
||||
} else {
|
||||
const res = await chain.call(obj, [loggerHandler])
|
||||
return res?.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: MultiPromptChain_Chains }
|
||||
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-dna" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M14.828 14.828a4 4 0 1 0 -5.656 -5.656a4 4 0 0 0 5.656 5.656z"></path>
|
||||
<path d="M9.172 20.485a4 4 0 1 0 -5.657 -5.657"></path>
|
||||
<path d="M14.828 3.515a4 4 0 0 0 5.657 5.657"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 489 B |
@@ -0,0 +1,92 @@
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { ICommonObject, INode, INodeData, INodeParams, VectorStoreRetriever } from '../../../src/Interface'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { MultiRetrievalQAChain } from 'langchain/chains'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
|
||||
class MultiRetrievalQAChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
baseClasses: string[]
|
||||
description: string
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'Multi Retrieval QA Chain'
|
||||
this.name = 'multiRetrievalQAChain'
|
||||
this.version = 1.0
|
||||
this.type = 'MultiRetrievalQAChain'
|
||||
this.icon = 'chain.svg'
|
||||
this.category = 'Chains'
|
||||
this.description = 'QA Chain that automatically picks an appropriate vector store from multiple retrievers'
|
||||
this.baseClasses = [this.type, ...getBaseClasses(MultiRetrievalQAChain)]
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'Language Model',
|
||||
name: 'model',
|
||||
type: 'BaseLanguageModel'
|
||||
},
|
||||
{
|
||||
label: 'Vector Store Retriever',
|
||||
name: 'vectorStoreRetriever',
|
||||
type: 'VectorStoreRetriever',
|
||||
list: true
|
||||
},
|
||||
{
|
||||
label: 'Return Source Documents',
|
||||
name: 'returnSourceDocuments',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData): Promise<any> {
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const vectorStoreRetriever = nodeData.inputs?.vectorStoreRetriever as VectorStoreRetriever[]
|
||||
const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean
|
||||
|
||||
const retrieverNames = []
|
||||
const retrieverDescriptions = []
|
||||
const retrievers = []
|
||||
|
||||
for (const vs of vectorStoreRetriever) {
|
||||
retrieverNames.push(vs.name)
|
||||
retrieverDescriptions.push(vs.description)
|
||||
retrievers.push(vs.vectorStore.asRetriever((vs.vectorStore as any).k ?? 4))
|
||||
}
|
||||
|
||||
const chain = MultiRetrievalQAChain.fromLLMAndRetrievers(model, {
|
||||
retrieverNames,
|
||||
retrieverDescriptions,
|
||||
retrievers,
|
||||
retrievalQAChainOpts: { verbose: process.env.DEBUG === 'true' ? true : false, returnSourceDocuments }
|
||||
})
|
||||
return chain
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string | ICommonObject> {
|
||||
const chain = nodeData.instance as MultiRetrievalQAChain
|
||||
const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean
|
||||
|
||||
const obj = { input }
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId, 2, returnSourceDocuments)
|
||||
const res = await chain.call(obj, [loggerHandler, handler])
|
||||
if (res.text && res.sourceDocuments) return res
|
||||
return res?.text
|
||||
} else {
|
||||
const res = await chain.call(obj, [loggerHandler])
|
||||
if (res.text && res.sourceDocuments) return res
|
||||
return res?.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: MultiRetrievalQAChain_Chains }
|
||||
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-dna" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M14.828 14.828a4 4 0 1 0 -5.656 -5.656a4 4 0 0 0 5.656 5.656z"></path>
|
||||
<path d="M9.172 20.485a4 4 0 1 0 -5.657 -5.657"></path>
|
||||
<path d="M14.828 3.515a4 4 0 0 0 5.657 5.657"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 489 B |
@@ -1,12 +1,14 @@
|
||||
import { INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { RetrievalQAChain } from 'langchain/chains'
|
||||
import { BaseRetriever } from 'langchain/schema'
|
||||
import { BaseRetriever } from 'langchain/schema/retriever'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
|
||||
class RetrievalQAChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
@@ -17,6 +19,7 @@ class RetrievalQAChain_Chains implements INode {
|
||||
constructor() {
|
||||
this.label = 'Retrieval QA Chain'
|
||||
this.name = 'retrievalQAChain'
|
||||
this.version = 1.0
|
||||
this.type = 'RetrievalQAChain'
|
||||
this.icon = 'chain.svg'
|
||||
this.category = 'Chains'
|
||||
@@ -44,13 +47,21 @@ class RetrievalQAChain_Chains implements INode {
|
||||
return chain
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string): Promise<string> {
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string> {
|
||||
const chain = nodeData.instance as RetrievalQAChain
|
||||
const obj = {
|
||||
query: input
|
||||
}
|
||||
const res = await chain.call(obj)
|
||||
return res?.text
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId)
|
||||
const res = await chain.call(obj, [loggerHandler, handler])
|
||||
return res?.text
|
||||
} else {
|
||||
const res = await chain.call(obj, [loggerHandler])
|
||||
return res?.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import { INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { SqlDatabaseChain, SqlDatabaseChainInput } from 'langchain/chains'
|
||||
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { SqlDatabaseChain, SqlDatabaseChainInput } from 'langchain/chains/sql_db'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { DataSource } from 'typeorm'
|
||||
import { SqlDatabase } from 'langchain/sql_db'
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
import { DataSourceOptions } from 'typeorm/data-source'
|
||||
|
||||
type DatabaseType = 'sqlite' | 'postgres' | 'mssql' | 'mysql'
|
||||
|
||||
class SqlDatabaseChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
@@ -18,6 +23,7 @@ class SqlDatabaseChain_Chains implements INode {
|
||||
constructor() {
|
||||
this.label = 'Sql Database Chain'
|
||||
this.name = 'sqlDatabaseChain'
|
||||
this.version = 1.0
|
||||
this.type = 'SqlDatabaseChain'
|
||||
this.icon = 'sqlchain.svg'
|
||||
this.category = 'Chains'
|
||||
@@ -35,46 +41,73 @@ class SqlDatabaseChain_Chains implements INode {
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
label: 'SQlite',
|
||||
label: 'SQLite',
|
||||
name: 'sqlite'
|
||||
},
|
||||
{
|
||||
label: 'PostgreSQL',
|
||||
name: 'postgres'
|
||||
},
|
||||
{
|
||||
label: 'MSSQL',
|
||||
name: 'mssql'
|
||||
},
|
||||
{
|
||||
label: 'MySQL',
|
||||
name: 'mysql'
|
||||
}
|
||||
],
|
||||
default: 'sqlite'
|
||||
},
|
||||
{
|
||||
label: 'Database File Path',
|
||||
name: 'dbFilePath',
|
||||
label: 'Connection string or file path (sqlite only)',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
placeholder: 'C:/Users/chinook.db'
|
||||
placeholder: '1270.0.0.1:5432/chinook'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData): Promise<any> {
|
||||
const databaseType = nodeData.inputs?.database as 'sqlite'
|
||||
const databaseType = nodeData.inputs?.database as DatabaseType
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const dbFilePath = nodeData.inputs?.dbFilePath
|
||||
const url = nodeData.inputs?.url
|
||||
|
||||
const chain = await getSQLDBChain(databaseType, dbFilePath, model)
|
||||
const chain = await getSQLDBChain(databaseType, url, model)
|
||||
return chain
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string): Promise<string> {
|
||||
const databaseType = nodeData.inputs?.database as 'sqlite'
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string> {
|
||||
const databaseType = nodeData.inputs?.database as DatabaseType
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const dbFilePath = nodeData.inputs?.dbFilePath
|
||||
const url = nodeData.inputs?.url
|
||||
|
||||
const chain = await getSQLDBChain(databaseType, dbFilePath, model)
|
||||
const res = await chain.run(input)
|
||||
return res
|
||||
const chain = await getSQLDBChain(databaseType, url, model)
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId, 2)
|
||||
const res = await chain.run(input, [loggerHandler, handler])
|
||||
return res
|
||||
} else {
|
||||
const res = await chain.run(input, [loggerHandler])
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getSQLDBChain = async (databaseType: 'sqlite', dbFilePath: string, llm: BaseLanguageModel) => {
|
||||
const datasource = new DataSource({
|
||||
type: databaseType,
|
||||
database: dbFilePath
|
||||
})
|
||||
const getSQLDBChain = async (databaseType: DatabaseType, url: string, llm: BaseLanguageModel) => {
|
||||
const datasource = new DataSource(
|
||||
databaseType === 'sqlite'
|
||||
? {
|
||||
type: databaseType,
|
||||
database: url
|
||||
}
|
||||
: ({
|
||||
type: databaseType,
|
||||
url: url
|
||||
} as DataSourceOptions)
|
||||
)
|
||||
|
||||
const db = await SqlDatabase.fromDataSourceParams({
|
||||
appDataSource: datasource
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { VectorDBQAChain } from 'langchain/chains'
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { VectorStore } from 'langchain/vectorstores'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
|
||||
class VectorDBQAChain_Chains implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
@@ -17,6 +19,7 @@ class VectorDBQAChain_Chains implements INode {
|
||||
constructor() {
|
||||
this.label = 'VectorDB QA Chain'
|
||||
this.name = 'vectorDBQAChain'
|
||||
this.version = 1.0
|
||||
this.type = 'VectorDBQAChain'
|
||||
this.icon = 'chain.svg'
|
||||
this.category = 'Chains'
|
||||
@@ -40,17 +43,29 @@ class VectorDBQAChain_Chains implements INode {
|
||||
const model = nodeData.inputs?.model as BaseLanguageModel
|
||||
const vectorStore = nodeData.inputs?.vectorStore as VectorStore
|
||||
|
||||
const chain = VectorDBQAChain.fromLLM(model, vectorStore, { verbose: process.env.DEBUG === 'true' ? true : false })
|
||||
const chain = VectorDBQAChain.fromLLM(model, vectorStore, {
|
||||
k: (vectorStore as any)?.k ?? 4,
|
||||
verbose: process.env.DEBUG === 'true' ? true : false
|
||||
})
|
||||
return chain
|
||||
}
|
||||
|
||||
async run(nodeData: INodeData, input: string): Promise<string> {
|
||||
async run(nodeData: INodeData, input: string, options: ICommonObject): Promise<string> {
|
||||
const chain = nodeData.instance as VectorDBQAChain
|
||||
const obj = {
|
||||
query: input
|
||||
}
|
||||
const res = await chain.call(obj)
|
||||
return res?.text
|
||||
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId)
|
||||
const res = await chain.call(obj, [loggerHandler, handler])
|
||||
return res?.text
|
||||
} else {
|
||||
const res = await chain.call(obj, [loggerHandler])
|
||||
return res?.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user