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
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user