From e294d227bce670055f012922da4458e730737bdf Mon Sep 17 00:00:00 2001 From: Vijay Sai Date: Fri, 26 May 2023 13:40:06 +0530 Subject: [PATCH 1/4] feature: changes to support ApiChain --- .../nodes/chains/ApiChain/ApiChain.ts | 79 +++++++++++++++++++ .../nodes/chains/ApiChain/apichain.svg | 3 + 2 files changed, 82 insertions(+) create mode 100644 packages/components/nodes/chains/ApiChain/ApiChain.ts create mode 100644 packages/components/nodes/chains/ApiChain/apichain.svg diff --git a/packages/components/nodes/chains/ApiChain/ApiChain.ts b/packages/components/nodes/chains/ApiChain/ApiChain.ts new file mode 100644 index 00000000..96342c55 --- /dev/null +++ b/packages/components/nodes/chains/ApiChain/ApiChain.ts @@ -0,0 +1,79 @@ +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { APIChain } from 'langchain/chains' +import { CustomChainHandler, getBaseClasses } from '../../../src/utils' +import { BaseLanguageModel } from 'langchain/base_language' +import { Document } from 'langchain/document' +import { PromptTemplate } from 'langchain/prompts' +import { OpenAI } from 'langchain' + +class ApiChain_Chains implements INode { + label: string + name: string + type: string + icon: string + category: string + baseClasses: string[] + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'API Chain' + this.name = 'apiChain' + this.type = 'ApiChain' + this.icon = 'apichain.svg' + this.category = 'Chains' + this.description = 'Chain to run queries against API' + this.baseClasses = [this.type, ...getBaseClasses(APIChain), ...getBaseClasses(OpenAI)] + this.inputs = [ + { + label: 'Language Model', + name: 'model', + type: 'BaseLanguageModel' + }, + { + label: 'Document', + name: 'document', + type: 'Document', + } + ] + } + + async init(nodeData: INodeData): Promise { + const model = nodeData.inputs?.model as BaseLanguageModel + const docs = nodeData.inputs?.document as Document[] + + const chain = await getOpenAPIChain(docs, model) + return chain + } + + async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { + const model = nodeData.inputs?.model as BaseLanguageModel + const docs = nodeData.inputs?.document as Document[] + + const chain = await getOpenAPIChain(docs, model) + if (options.socketIO && options.socketIOClientId) { + const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId) + const res = await chain.run(input, [handler]) + return res + } else { + const res = await chain.run(input) + return res + } + } +} + +const getOpenAPIChain = async (documents: Document[], llm: BaseLanguageModel, options: any = {}) => { + const texts = documents.map(({ pageContent }) => pageContent); + const apiResponsePrompt = new PromptTemplate({ + inputVariables: ["api_docs", "question", "api_url", "api_response"], + template: "Given this {api_response} response for {api_url}. use the given response to answer this {question}", + }); + + const chain = APIChain.fromLLMAndAPIDocs(llm, texts.toString(), { + apiResponsePrompt, + verbose: process.env.DEBUG === 'true' ? true : false, + }) + return chain +} + +module.exports = { nodeClass: ApiChain_Chains } diff --git a/packages/components/nodes/chains/ApiChain/apichain.svg b/packages/components/nodes/chains/ApiChain/apichain.svg new file mode 100644 index 00000000..ef62e168 --- /dev/null +++ b/packages/components/nodes/chains/ApiChain/apichain.svg @@ -0,0 +1,3 @@ + \ No newline at end of file From 06f933132b5878c5582ce493090e1f6d0e7f2d21 Mon Sep 17 00:00:00 2001 From: VJSai Date: Fri, 26 May 2023 13:46:33 +0530 Subject: [PATCH 2/4] Update ApiChain.ts to remove OpenAI import --- packages/components/nodes/chains/ApiChain/ApiChain.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/components/nodes/chains/ApiChain/ApiChain.ts b/packages/components/nodes/chains/ApiChain/ApiChain.ts index 96342c55..90d13661 100644 --- a/packages/components/nodes/chains/ApiChain/ApiChain.ts +++ b/packages/components/nodes/chains/ApiChain/ApiChain.ts @@ -4,7 +4,6 @@ import { CustomChainHandler, getBaseClasses } from '../../../src/utils' import { BaseLanguageModel } from 'langchain/base_language' import { Document } from 'langchain/document' import { PromptTemplate } from 'langchain/prompts' -import { OpenAI } from 'langchain' class ApiChain_Chains implements INode { label: string @@ -23,7 +22,7 @@ class ApiChain_Chains implements INode { this.icon = 'apichain.svg' this.category = 'Chains' this.description = 'Chain to run queries against API' - this.baseClasses = [this.type, ...getBaseClasses(APIChain), ...getBaseClasses(OpenAI)] + this.baseClasses = [this.type, ...getBaseClasses(APIChain)] this.inputs = [ { label: 'Language Model', From 4a4c940dbd9f709dd99119772cacf9fa9989716f Mon Sep 17 00:00:00 2001 From: Vijay Sai Date: Fri, 26 May 2023 16:07:50 +0530 Subject: [PATCH 3/4] fixed all the linting issues --- .../nodes/chains/ApiChain/ApiChain.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/components/nodes/chains/ApiChain/ApiChain.ts b/packages/components/nodes/chains/ApiChain/ApiChain.ts index 90d13661..6fb65560 100644 --- a/packages/components/nodes/chains/ApiChain/ApiChain.ts +++ b/packages/components/nodes/chains/ApiChain/ApiChain.ts @@ -32,7 +32,7 @@ class ApiChain_Chains implements INode { { label: 'Document', name: 'document', - type: 'Document', + type: 'Document' } ] } @@ -45,7 +45,7 @@ class ApiChain_Chains implements INode { return chain } - async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { + async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { const model = nodeData.inputs?.model as BaseLanguageModel const docs = nodeData.inputs?.document as Document[] @@ -61,16 +61,16 @@ class ApiChain_Chains implements INode { } } -const getOpenAPIChain = async (documents: Document[], llm: BaseLanguageModel, options: any = {}) => { - const texts = documents.map(({ pageContent }) => pageContent); +const getOpenAPIChain = async (documents: Document[], llm: BaseLanguageModel) => { + const texts = documents.map(({ pageContent }) => pageContent) const apiResponsePrompt = new PromptTemplate({ - inputVariables: ["api_docs", "question", "api_url", "api_response"], - template: "Given this {api_response} response for {api_url}. use the given response to answer this {question}", - }); + inputVariables: ['api_docs', 'question', 'api_url', 'api_response'], + template: 'Given this {api_response} response for {api_url}. use the given response to answer this {question}' + }) - const chain = APIChain.fromLLMAndAPIDocs(llm, texts.toString(), { - apiResponsePrompt, - verbose: process.env.DEBUG === 'true' ? true : false, + const chain = APIChain.fromLLMAndAPIDocs(llm, texts.toString(), { + apiResponsePrompt, + verbose: process.env.DEBUG === 'true' ? true : false }) return chain } From 55ed6819a2a03dc109afeb9c2743d7928d969325 Mon Sep 17 00:00:00 2001 From: Vijay Sai Date: Fri, 26 May 2023 19:13:52 +0530 Subject: [PATCH 4/4] integrated headers functionality --- .../nodes/chains/ApiChain/ApiChain.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/components/nodes/chains/ApiChain/ApiChain.ts b/packages/components/nodes/chains/ApiChain/ApiChain.ts index 6fb65560..bf810340 100644 --- a/packages/components/nodes/chains/ApiChain/ApiChain.ts +++ b/packages/components/nodes/chains/ApiChain/ApiChain.ts @@ -33,6 +33,13 @@ class ApiChain_Chains implements INode { label: 'Document', name: 'document', type: 'Document' + }, + { + label: 'Headers', + name: 'headers', + type: 'json', + additionalParams: true, + optional: true } ] } @@ -40,16 +47,18 @@ class ApiChain_Chains implements INode { async init(nodeData: INodeData): Promise { const model = nodeData.inputs?.model as BaseLanguageModel const docs = nodeData.inputs?.document as Document[] + const headers = nodeData.inputs?.headers as string - const chain = await getOpenAPIChain(docs, model) + const chain = await getAPIChain(docs, model, headers) return chain } async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { const model = nodeData.inputs?.model as BaseLanguageModel const docs = nodeData.inputs?.document as Document[] + const headers = nodeData.inputs?.headers as string - const chain = await getOpenAPIChain(docs, model) + const chain = await getAPIChain(docs, model, headers) if (options.socketIO && options.socketIOClientId) { const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId) const res = await chain.run(input, [handler]) @@ -61,7 +70,7 @@ class ApiChain_Chains implements INode { } } -const getOpenAPIChain = async (documents: Document[], llm: BaseLanguageModel) => { +const getAPIChain = async (documents: Document[], llm: BaseLanguageModel, headers: any) => { const texts = documents.map(({ pageContent }) => pageContent) const apiResponsePrompt = new PromptTemplate({ inputVariables: ['api_docs', 'question', 'api_url', 'api_response'], @@ -70,7 +79,8 @@ const getOpenAPIChain = async (documents: Document[], llm: BaseLanguageModel) => const chain = APIChain.fromLLMAndAPIDocs(llm, texts.toString(), { apiResponsePrompt, - verbose: process.env.DEBUG === 'true' ? true : false + verbose: process.env.DEBUG === 'true' ? true : false, + headers: typeof headers === 'object' ? headers : headers ? JSON.parse(headers) : {} }) return chain }