From f108c62acf009d4b0ef26690cdffe0f18804b6ea Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Thu, 28 Sep 2023 10:31:40 +0530 Subject: [PATCH 01/76] Support for ElasticSearch as a vector store --- .../ElasticsearchAPI.credential.ts | 31 ++++ .../ElectricsearchUserPassword.credential.ts | 31 ++++ .../Elasticsearch/Elasticsearch_Existing.ts | 111 ++++++++++++ .../Elasticsearch/Elasticsearch_Upsert.ts | 165 ++++++++++++++++++ .../Elasticsearch/elasticsearch.png | Bin 0 -> 3719 bytes packages/components/package.json | 1 + 6 files changed, 339 insertions(+) create mode 100644 packages/components/credentials/ElasticsearchAPI.credential.ts create mode 100644 packages/components/credentials/ElectricsearchUserPassword.credential.ts create mode 100644 packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts create mode 100644 packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Upsert.ts create mode 100644 packages/components/nodes/vectorstores/Elasticsearch/elasticsearch.png diff --git a/packages/components/credentials/ElasticsearchAPI.credential.ts b/packages/components/credentials/ElasticsearchAPI.credential.ts new file mode 100644 index 00000000..e377243d --- /dev/null +++ b/packages/components/credentials/ElasticsearchAPI.credential.ts @@ -0,0 +1,31 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class ElectricsearchAPI implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Elasticsearch API' + this.name = 'elasticsearchApi' + this.version = 1.0 + this.description = + 'Refer to official guide on how to get an API Key from ElasticSearch' + this.inputs = [ + { + label: 'Elasticsearch Endpoint', + name: 'endpoint', + type: 'string' + }, + { + label: 'Elasticsearch API ID', + name: 'apiKey', + type: 'password' + } + ] + } +} + +module.exports = { credClass: ElectricsearchAPI } diff --git a/packages/components/credentials/ElectricsearchUserPassword.credential.ts b/packages/components/credentials/ElectricsearchUserPassword.credential.ts new file mode 100644 index 00000000..2dd88937 --- /dev/null +++ b/packages/components/credentials/ElectricsearchUserPassword.credential.ts @@ -0,0 +1,31 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class ElasticSearchUserPassword implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'ElasticSearch User Password' + this.name = 'elasticSearchUserPassword' + this.version = 1.0 + this.description = + 'Refer to official guide on how to get User Password from ElasticSearch' + this.inputs = [ + { + label: 'ElasticSearch User', + name: 'elasticSearchUser', + type: 'string' + }, + { + label: 'ElasticSearch Password', + name: 'elasticSearchPassword', + type: 'password' + } + ] + } +} + +module.exports = { credClass: ElasticSearchUserPassword } diff --git a/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts new file mode 100644 index 00000000..6e785c85 --- /dev/null +++ b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts @@ -0,0 +1,111 @@ +import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { Embeddings } from 'langchain/embeddings/base' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src' + +import { Client, ClientOptions } from '@elastic/elasticsearch' +import { ElasticClientArgs, ElasticVectorSearch } from 'langchain/vectorstores/elasticsearch' + +class ElasicsearchExisting_VectorStores implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Elasticsearch Load Existing Index' + this.name = 'ElasticsearchIndex' + this.version = 1.0 + this.type = 'Elasticsearch' + this.icon = 'elasticsearch.png' + this.category = 'Vector Stores' + this.description = 'Load existing index from Elasticsearch (i.e: Document has been upserted)' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['elasticsearchApi', 'elasticSearchUserPassword'] + } + this.inputs = [ + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Index Name', + name: 'indexName', + placeholder: '', + type: 'string' + }, + { + label: 'Top K', + name: 'topK', + description: 'Number of top results to fetch. Default to 4', + placeholder: '4', + type: 'number', + additionalParams: true, + optional: true + } + ] + this.outputs = [ + { + label: 'Elasticsearch Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Elasticsearch Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(ElasticVectorSearch)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const endPoint = getCredentialParam('endpoint', credentialData, nodeData) + const apiKey = getCredentialParam('apiKey', credentialData, nodeData) + const indexName = nodeData.inputs?.indexName as string + const embeddings = nodeData.inputs?.embeddings as Embeddings + const topK = nodeData.inputs?.topK as string + + const k = topK ? parseFloat(topK) : 4 + const output = nodeData.outputs?.output as string + + // eslint-disable-next-line no-console + console.log('EndPoint:: ' + endPoint + ', APIKey:: ' + apiKey + ', Index:: ' + indexName) + + const elasticSearchClientOptions: ClientOptions = { + node: endPoint, + auth: { + apiKey: apiKey + } + } + + const elasticSearchClientArgs: ElasticClientArgs = { + client: new Client(elasticSearchClientOptions), + indexName: indexName + } + + const vectorStore = await ElasticVectorSearch.fromExistingIndex(embeddings, elasticSearchClientArgs) + // eslint-disable-next-line no-console + console.log('vectorStore ::' + vectorStore._vectorstoreType()) + if (output === 'retriever') { + return vectorStore.asRetriever(k) + } else if (output === 'vectorStore') { + ;(vectorStore as any).k = k + return vectorStore + } + return vectorStore + } +} + +module.exports = { nodeClass: ElasicsearchExisting_VectorStores } diff --git a/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Upsert.ts b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Upsert.ts new file mode 100644 index 00000000..5a0065d5 --- /dev/null +++ b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Upsert.ts @@ -0,0 +1,165 @@ +import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { Embeddings } from 'langchain/embeddings/base' +import { Document } from 'langchain/document' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src' + +import { Client, ClientOptions } from '@elastic/elasticsearch' +import { ElasticClientArgs, ElasticVectorSearch } from 'langchain/vectorstores/elasticsearch' +import { flatten } from 'lodash' + +class ElasicsearchUpsert_VectorStores implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Elasticsearch Upsert Document' + this.name = 'ElasticsearchUpsert' + this.version = 1.0 + this.type = 'Elasticsearch' + this.icon = 'elasticsearch.png' + this.category = 'Vector Stores' + this.description = 'Upsert documents to Elasticsearch' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['elasticsearchApi', 'elasticSearchUserPassword'] + } + this.inputs = [ + { + label: 'Document', + name: 'document', + type: 'Document', + list: true + }, + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Index Name', + name: 'indexName', + placeholder: '', + type: 'string' + }, + { + label: 'Top K', + name: 'topK', + description: 'Number of top results to fetch. Default to 4', + placeholder: '4', + type: 'number', + additionalParams: true, + optional: true + }, + { + label: 'Similarity', + name: 'similarity', + description: 'Similarity measure used in Elasticsearch.', + type: 'options', + default: 'l2_norm', + options: [ + { + label: 'l2_norm', + name: 'l2_norm' + }, + { + label: 'dot_product', + name: 'dot_product' + }, + { + label: 'cosine', + name: 'cosine' + } + ], + additionalParams: true, + optional: true + } + ] + this.outputs = [ + { + label: 'Elasticsearch Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Elasticsearch Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(ElasticVectorSearch)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const endPoint = getCredentialParam('endpoint', credentialData, nodeData) + const apiKey = getCredentialParam('apiKey', credentialData, nodeData) + const docs = nodeData.inputs?.document as Document[] + const indexName = nodeData.inputs?.indexName as string + const embeddings = nodeData.inputs?.embeddings as Embeddings + const topK = nodeData.inputs?.topK as string + const k = topK ? parseFloat(topK) : 4 + const output = nodeData.outputs?.output as string + const similarityMeasure = nodeData.inputs?.similarityMeasure as string + + // eslint-disable-next-line no-console + console.log('EndPoint:: ' + endPoint + ', APIKey:: ' + apiKey + ', Index:: ' + indexName) + + const elasticSearchClientOptions: ClientOptions = { + node: endPoint, + auth: { + apiKey: apiKey + } + } + let vectorSearchOptions = {} + switch (similarityMeasure) { + case 'dot_product': + vectorSearchOptions = { + similarity: 'dot_product' + } + break + case 'cosine': + vectorSearchOptions = { + similarity: 'cosine' + } + break + default: + vectorSearchOptions = { + similarity: 'l2_norm' + } + } + const elasticSearchClientArgs: ElasticClientArgs = { + client: new Client(elasticSearchClientOptions), + indexName: indexName, + vectorSearchOptions: vectorSearchOptions + } + + const flattenDocs = docs && docs.length ? flatten(docs) : [] + const finalDocs = [] + for (let i = 0; i < flattenDocs.length; i += 1) { + finalDocs.push(new Document(flattenDocs[i])) + } + + const vectorStore = await ElasticVectorSearch.fromDocuments(finalDocs, embeddings, elasticSearchClientArgs) + + if (output === 'retriever') { + return vectorStore.asRetriever(k) + } else if (output === 'vectorStore') { + ;(vectorStore as any).k = k + return vectorStore + } + return vectorStore + } +} + +module.exports = { nodeClass: ElasicsearchUpsert_VectorStores } diff --git a/packages/components/nodes/vectorstores/Elasticsearch/elasticsearch.png b/packages/components/nodes/vectorstores/Elasticsearch/elasticsearch.png new file mode 100644 index 0000000000000000000000000000000000000000..fdb6686369bf0186319e24f2dd96ebee1ee6a54b GIT binary patch literal 3719 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 literal 0 HcmV?d00001 diff --git a/packages/components/package.json b/packages/components/package.json index 93609106..3fdd8923 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -19,6 +19,7 @@ "@aws-sdk/client-dynamodb": "^3.360.0", "@dqbd/tiktoken": "^1.0.7", "@getzep/zep-js": "^0.6.3", + "@elastic/elasticsearch": "^8.9.0", "@google-ai/generativelanguage": "^0.2.1", "@huggingface/inference": "^2.6.1", "@notionhq/client": "^2.2.8", From d588ac0480846271e00324caf413cd408eb5d19e Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 29 Sep 2023 07:54:16 +0530 Subject: [PATCH 02/76] Adding support for LLM Caching. --- .../LocalMemoryCache/LocalMemoryCache.ts | 44 ++++++++++++++++++ .../llmcache/LocalMemoryCache/memorycache.png | Bin 0 -> 2717 bytes .../components/nodes/llms/OpenAI/OpenAI.ts | 17 +++++-- packages/components/package.json | 2 +- packages/components/src/Interface.ts | 7 +++ packages/components/src/handler.ts | 22 ++++++++- 6 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts create mode 100644 packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png diff --git a/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts b/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts new file mode 100644 index 00000000..73f4415e --- /dev/null +++ b/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts @@ -0,0 +1,44 @@ +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { InMemoryCache } from 'langchain/cache' +import { getBaseClasses } from '../../../src' + +class LocalMemoryCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + inMemoryCache: any + + constructor() { + this.label = 'Local (Builtin) Cache' + this.name = 'localCache' + this.version = 1.0 + this.type = 'LLMCache' + this.icon = 'memorycache.png' + this.category = 'LLM Cache' + this.baseClasses = [this.type, 'LLMCacheBase'] + this.inputs = [] + this.outputs = [ + { + label: 'LLM Cache', + name: 'cache', + baseClasses: [this.type, ...getBaseClasses(InMemoryCache)] + } + ] + } + + async init(nodeData: INodeData): Promise { + if (!this.inMemoryCache) { + this.inMemoryCache = InMemoryCache.global() + } + return this.inMemoryCache + } +} + +module.exports = { nodeClass: LocalMemoryCache } diff --git a/packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png b/packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png new file mode 100644 index 0000000000000000000000000000000000000000..aaeecd6fb100be3a10b3d1faca046f9fa409f018 GIT binary patch literal 2717 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 XQt;1#;KI))00000NkvXXu0mjfl~Wzs literal 0 HcmV?d00001 diff --git a/packages/components/nodes/llms/OpenAI/OpenAI.ts b/packages/components/nodes/llms/OpenAI/OpenAI.ts index 2960ad2a..9fa61653 100644 --- a/packages/components/nodes/llms/OpenAI/OpenAI.ts +++ b/packages/components/nodes/llms/OpenAI/OpenAI.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { OpenAI, OpenAIInput } from 'langchain/llms/openai' +import { BaseLLMParams } from 'langchain/dist/llms/base' +import { BaseCache } from 'langchain/schema' class OpenAI_LLMs implements INode { label: string @@ -17,7 +19,7 @@ class OpenAI_LLMs implements INode { constructor() { this.label = 'OpenAI' this.name = 'openAI' - this.version = 2.0 + this.version = 3.0 this.type = 'OpenAI' this.icon = 'openai.png' this.category = 'LLMs' @@ -30,6 +32,12 @@ class OpenAI_LLMs implements INode { credentialNames: ['openAIApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -149,7 +157,9 @@ class OpenAI_LLMs implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const obj: Partial & { openAIApiKey?: string } = { + const llmCache = nodeData.inputs?.llmCache as BaseCache + + const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), modelName, openAIApiKey, @@ -164,8 +174,9 @@ class OpenAI_LLMs implements INode { if (batchSize) obj.batchSize = parseInt(batchSize, 10) if (bestOf) obj.bestOf = parseInt(bestOf, 10) - let parsedBaseOptions: any | undefined = undefined + if (llmCache) obj.cache = llmCache + let parsedBaseOptions: any | undefined = undefined if (baseOptions) { try { parsedBaseOptions = typeof baseOptions === 'object' ? baseOptions : JSON.parse(baseOptions) diff --git a/packages/components/package.json b/packages/components/package.json index 93609106..f8498e31 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -42,7 +42,7 @@ "google-auth-library": "^9.0.0", "graphql": "^16.6.0", "html-to-text": "^9.0.5", - "langchain": "^0.0.152", + "langchain": "^0.0.154", "langfuse-langchain": "^1.0.14-alpha.0", "langsmith": "^0.0.32", "linkifyjs": "^4.1.1", diff --git a/packages/components/src/Interface.ts b/packages/components/src/Interface.ts index e883d056..76dc7354 100644 --- a/packages/components/src/Interface.ts +++ b/packages/components/src/Interface.ts @@ -1,6 +1,7 @@ /** * Types */ +import { BaseCache } from 'langchain/schema' export type NodeParamsType = | 'asyncOptions' @@ -176,3 +177,9 @@ export class VectorStoreRetriever { this.vectorStore = fields.vectorStore } } + +export interface LLMCacheBase { + name: string + description: string + baseCache: BaseCache +} diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index 10f9a214..a102b473 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -151,6 +151,7 @@ export class CustomChainHandler extends BaseCallbackHandler { socketIOClientId = '' skipK = 0 // Skip streaming for first K numbers of handleLLMStart returnSourceDocuments = false + cachedResponse = true constructor(socketIO: Server, socketIOClientId: string, skipK?: number, returnSourceDocuments?: boolean) { super() @@ -161,6 +162,7 @@ export class CustomChainHandler extends BaseCallbackHandler { } handleLLMStart() { + this.cachedResponse = false if (this.skipK > 0) this.skipK -= 1 } @@ -175,13 +177,31 @@ export class CustomChainHandler extends BaseCallbackHandler { } handleLLMEnd() { - this.socketIO.to(this.socketIOClientId).emit('end') + /* send the end event from handleChainEnd */ + // this.socketIO.to(this.socketIOClientId).emit('end') } handleChainEnd(outputs: ChainValues): void | Promise { if (this.returnSourceDocuments) { this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments) } + /* + Langchain does not call handleLLMStart, handleLLMEnd, handleLLMNewToken when the chain is cached. + Callback Order is "Chain Start -> LLM Start --> LLM Token --> LLM End -> Chain End" for normal responses. + Callback Order is "Chain Start -> Chain End" for cached responses. + */ + if (this.cachedResponse) { + const cachedValue = outputs.text as string + //split at whitespace, and keep the whitespace. This is to preserve the original formatting. + const result = cachedValue.split(/(\s+)/) + result.forEach((token: string, index: number) => { + if (index === 0) { + this.socketIO.to(this.socketIOClientId).emit('start', token) + } + this.socketIO.to(this.socketIOClientId).emit('token', token) + }) + } + this.socketIO.to(this.socketIOClientId).emit('end') } } From d81869fd59de2894f15b1649a909d4e513393302 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 29 Sep 2023 08:19:44 +0530 Subject: [PATCH 03/76] Extending support for Caching to all LLM's. --- .../nodes/llms/Azure OpenAI/AzureOpenAI.ts | 16 +++++++++++++--- .../components/nodes/llms/Bittensor/Bittensor.ts | 15 +++++++++++++-- packages/components/nodes/llms/Cohere/Cohere.ts | 13 ++++++++++--- .../nodes/llms/GooglePaLM/GooglePaLM.ts | 12 ++++++++++-- .../nodes/llms/GoogleVertexAI/GoogleVertexAI.ts | 11 ++++++++++- .../HuggingFaceInference/HuggingFaceInference.ts | 13 ++++++++++++- packages/components/nodes/llms/OpenAI/OpenAI.ts | 2 +- .../components/nodes/llms/Replicate/Replicate.ts | 16 ++++++++++++++-- 8 files changed, 83 insertions(+), 15 deletions(-) diff --git a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts index f48c4642..e5cca769 100644 --- a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts +++ b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts @@ -1,7 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { AzureOpenAIInput, OpenAI, OpenAIInput } from 'langchain/llms/openai' - +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class AzureOpenAI_LLMs implements INode { label: string name: string @@ -17,7 +18,7 @@ class AzureOpenAI_LLMs implements INode { constructor() { this.label = 'Azure OpenAI' this.name = 'azureOpenAI' - this.version = 1.0 + this.version = 2.0 this.type = 'AzureOpenAI' this.icon = 'Azure.svg' this.category = 'LLMs' @@ -30,6 +31,12 @@ class AzureOpenAI_LLMs implements INode { credentialNames: ['azureOpenAIApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -163,7 +170,9 @@ class AzureOpenAI_LLMs implements INode { const azureOpenAIApiDeploymentName = getCredentialParam('azureOpenAIApiDeploymentName', credentialData, nodeData) const azureOpenAIApiVersion = getCredentialParam('azureOpenAIApiVersion', credentialData, nodeData) - const obj: Partial & Partial = { + const llmCache = nodeData.inputs?.llmCache as BaseCache + + const obj: Partial & BaseLLMParams & Partial = { temperature: parseFloat(temperature), modelName, azureOpenAIApiKey, @@ -179,6 +188,7 @@ class AzureOpenAI_LLMs implements INode { if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) if (bestOf) obj.bestOf = parseInt(bestOf, 10) + if (llmCache) obj.cache = llmCache const model = new OpenAI(obj) return model diff --git a/packages/components/nodes/llms/Bittensor/Bittensor.ts b/packages/components/nodes/llms/Bittensor/Bittensor.ts index a87a7e48..84401e59 100644 --- a/packages/components/nodes/llms/Bittensor/Bittensor.ts +++ b/packages/components/nodes/llms/Bittensor/Bittensor.ts @@ -1,6 +1,8 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' import { NIBittensorLLM, BittensorInput } from 'langchain/experimental/llms/bittensor' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class Bittensor_LLMs implements INode { label: string @@ -16,13 +18,19 @@ class Bittensor_LLMs implements INode { constructor() { this.label = 'NIBittensorLLM' this.name = 'NIBittensorLLM' - this.version = 1.0 + this.version = 2.0 this.type = 'Bittensor' this.icon = 'logo.png' this.category = 'LLMs' this.description = 'Wrapper around Bittensor subnet 1 large language models' this.baseClasses = [this.type, ...getBaseClasses(NIBittensorLLM)] this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'System prompt', name: 'system_prompt', @@ -44,10 +52,13 @@ class Bittensor_LLMs implements INode { async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string const topResponses = Number(nodeData.inputs?.topResponses as number) - const obj: Partial = { + const llmCache = nodeData.inputs?.llmCache as BaseCache + + const obj: Partial & BaseLLMParams = { systemPrompt: system_prompt, topResponses: topResponses } + if (llmCache) obj.cache = llmCache const model = new NIBittensorLLM(obj) return model diff --git a/packages/components/nodes/llms/Cohere/Cohere.ts b/packages/components/nodes/llms/Cohere/Cohere.ts index 4a3a8a80..8b4c0ac2 100644 --- a/packages/components/nodes/llms/Cohere/Cohere.ts +++ b/packages/components/nodes/llms/Cohere/Cohere.ts @@ -1,6 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { Cohere, CohereInput } from './core' +import { BaseCache } from 'langchain/schema' class Cohere_LLMs implements INode { label: string @@ -17,7 +18,7 @@ class Cohere_LLMs implements INode { constructor() { this.label = 'Cohere' this.name = 'cohere' - this.version = 1.0 + this.version = 2.0 this.type = 'Cohere' this.icon = 'cohere.png' this.category = 'LLMs' @@ -30,6 +31,12 @@ class Cohere_LLMs implements INode { credentialNames: ['cohereApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -85,7 +92,7 @@ class Cohere_LLMs implements INode { const temperature = nodeData.inputs?.temperature as string const modelName = nodeData.inputs?.modelName as string const maxTokens = nodeData.inputs?.maxTokens as string - + const llmCache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const cohereApiKey = getCredentialParam('cohereApiKey', credentialData, nodeData) @@ -96,7 +103,7 @@ class Cohere_LLMs implements INode { if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) if (modelName) obj.model = modelName if (temperature) obj.temperature = parseFloat(temperature) - + if (llmCache) obj.cache = llmCache const model = new Cohere(obj) return model } diff --git a/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts b/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts index 24630360..d916c09f 100644 --- a/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts +++ b/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts @@ -1,7 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { GooglePaLM, GooglePaLMTextInput } from 'langchain/llms/googlepalm' - +import { BaseCache } from 'langchain/schema' class GooglePaLM_LLMs implements INode { label: string name: string @@ -17,7 +17,7 @@ class GooglePaLM_LLMs implements INode { constructor() { this.label = 'GooglePaLM' this.name = 'GooglePaLM' - this.version = 1.0 + this.version = 2.0 this.type = 'GooglePaLM' this.icon = 'Google_PaLM_Logo.svg' this.category = 'LLMs' @@ -30,6 +30,12 @@ class GooglePaLM_LLMs implements INode { credentialNames: ['googleMakerSuite'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -126,6 +132,7 @@ class GooglePaLM_LLMs implements INode { const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string const stopSequencesObj = nodeData.inputs?.stopSequencesObj + const llmCache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData) @@ -139,6 +146,7 @@ class GooglePaLM_LLMs implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) if (topK) obj.topK = parseFloat(topK) + if (llmCache) obj.cache = llmCache let parsedStopSequences: any | undefined = undefined if (stopSequencesObj) { diff --git a/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts b/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts index 4d19d04f..41b18475 100644 --- a/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts +++ b/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts @@ -2,6 +2,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { GoogleVertexAI, GoogleVertexAITextInput } from 'langchain/llms/googlevertexai' import { GoogleAuthOptions } from 'google-auth-library' +import { BaseCache } from 'langchain/schema' class GoogleVertexAI_LLMs implements INode { label: string @@ -18,7 +19,7 @@ class GoogleVertexAI_LLMs implements INode { constructor() { this.label = 'GoogleVertexAI' this.name = 'googlevertexai' - this.version = 1.0 + this.version = 2.0 this.type = 'GoogleVertexAI' this.icon = 'vertexai.svg' this.category = 'LLMs' @@ -34,6 +35,12 @@ class GoogleVertexAI_LLMs implements INode { 'Google Vertex AI credential. If you are using a GCP service like Cloud Run, or if you have installed default credentials on your local machine, you do not need to set this credential.' } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -120,6 +127,7 @@ class GoogleVertexAI_LLMs implements INode { const modelName = nodeData.inputs?.modelName as string const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string const topP = nodeData.inputs?.topP as string + const llmCache = nodeData.inputs?.llmCache as BaseCache const obj: Partial = { temperature: parseFloat(temperature), @@ -129,6 +137,7 @@ class GoogleVertexAI_LLMs implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) + if (llmCache) obj.cache = llmCache const model = new GoogleVertexAI(obj) return model diff --git a/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts index c7f6a37e..9d6226e2 100644 --- a/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts +++ b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts @@ -1,6 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { HFInput, HuggingFaceInference } from './core' +import { BaseCache } from 'langchain/schema' class HuggingFaceInference_LLMs implements INode { label: string @@ -17,7 +18,7 @@ class HuggingFaceInference_LLMs implements INode { constructor() { this.label = 'HuggingFace Inference' this.name = 'huggingFaceInference_LLMs' - this.version = 1.0 + this.version = 2.0 this.type = 'HuggingFaceInference' this.icon = 'huggingface.png' this.category = 'LLMs' @@ -30,6 +31,12 @@ class HuggingFaceInference_LLMs implements INode { credentialNames: ['huggingFaceApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model', name: 'model', @@ -106,6 +113,8 @@ class HuggingFaceInference_LLMs implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData) + const llmCache = nodeData.inputs?.llmCache as BaseCache + const obj: Partial = { model, apiKey: huggingFaceApiKey @@ -119,6 +128,8 @@ class HuggingFaceInference_LLMs implements INode { if (endpoint) obj.endpoint = endpoint const huggingFace = new HuggingFaceInference(obj) + if (llmCache) huggingFace.cache = llmCache + return huggingFace } } diff --git a/packages/components/nodes/llms/OpenAI/OpenAI.ts b/packages/components/nodes/llms/OpenAI/OpenAI.ts index 9fa61653..607ebeb4 100644 --- a/packages/components/nodes/llms/OpenAI/OpenAI.ts +++ b/packages/components/nodes/llms/OpenAI/OpenAI.ts @@ -1,7 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { OpenAI, OpenAIInput } from 'langchain/llms/openai' -import { BaseLLMParams } from 'langchain/dist/llms/base' +import { BaseLLMParams } from 'langchain/llms/base' import { BaseCache } from 'langchain/schema' class OpenAI_LLMs implements INode { diff --git a/packages/components/nodes/llms/Replicate/Replicate.ts b/packages/components/nodes/llms/Replicate/Replicate.ts index 22c6e93a..fd1eb6f7 100644 --- a/packages/components/nodes/llms/Replicate/Replicate.ts +++ b/packages/components/nodes/llms/Replicate/Replicate.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { Replicate, ReplicateInput } from 'langchain/llms/replicate' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class Replicate_LLMs implements INode { label: string @@ -17,7 +19,7 @@ class Replicate_LLMs implements INode { constructor() { this.label = 'Replicate' this.name = 'replicate' - this.version = 1.0 + this.version = 2.0 this.type = 'Replicate' this.icon = 'replicate.svg' this.category = 'LLMs' @@ -30,6 +32,12 @@ class Replicate_LLMs implements INode { credentialNames: ['replicateApi'] } this.inputs = [ + { + label: 'Cache', + name: 'llmCache', + type: 'LLMCache', + optional: true + }, { label: 'Model', name: 'model', @@ -103,7 +111,9 @@ class Replicate_LLMs implements INode { const name = modelName.split(':')[0].split('/').pop() const org = modelName.split(':')[0].split('/')[0] - const obj: ReplicateInput = { + const llmCache = nodeData.inputs?.llmCache as BaseCache + + const obj: ReplicateInput & BaseLLMParams = { model: `${org}/${name}:${version}`, apiKey } @@ -120,6 +130,8 @@ class Replicate_LLMs implements INode { } if (Object.keys(inputs).length) obj.input = inputs + if (llmCache) obj.cache = llmCache + const model = new Replicate(obj) return model } From 18702e4c479916ac409fd136d1b13aba85a6ed29 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sat, 30 Sep 2023 12:05:51 +0530 Subject: [PATCH 04/76] Refactoring of LLM In Cache Memory files for better clarity of name --- .../LLMInMemoryCache.ts} | 4 ++-- .../memorycache.png | Bin 2 files changed, 2 insertions(+), 2 deletions(-) rename packages/components/nodes/llmcache/{LocalMemoryCache/LocalMemoryCache.ts => LLMInMemoryCache/LLMInMemoryCache.ts} (92%) rename packages/components/nodes/llmcache/{LocalMemoryCache => LLMInMemoryCache}/memorycache.png (100%) diff --git a/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts b/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts similarity index 92% rename from packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts rename to packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts index 73f4415e..5e77a029 100644 --- a/packages/components/nodes/llmcache/LocalMemoryCache/LocalMemoryCache.ts +++ b/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts @@ -2,7 +2,7 @@ import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/I import { InMemoryCache } from 'langchain/cache' import { getBaseClasses } from '../../../src' -class LocalMemoryCache implements INode { +class LLMInMemoryCache implements INode { label: string name: string version: number @@ -41,4 +41,4 @@ class LocalMemoryCache implements INode { } } -module.exports = { nodeClass: LocalMemoryCache } +module.exports = { nodeClass: LLMInMemoryCache } diff --git a/packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png b/packages/components/nodes/llmcache/LLMInMemoryCache/memorycache.png similarity index 100% rename from packages/components/nodes/llmcache/LocalMemoryCache/memorycache.png rename to packages/components/nodes/llmcache/LLMInMemoryCache/memorycache.png From 4efec94dc8d404755379a8068628341870c5da04 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sat, 30 Sep 2023 12:07:48 +0530 Subject: [PATCH 05/76] LLM Cache - Addition of Momento Cache --- .../credentials/MomentoCacheApi.credential.ts | 36 +++++++++ .../LLMMomentoCache/LLMMomentoCache.ts | 75 ++++++++++++++++++ .../llmcache/LLMMomentoCache/momento.png | Bin 0 -> 5534 bytes packages/components/package.json | 1 + 4 files changed, 112 insertions(+) create mode 100644 packages/components/credentials/MomentoCacheApi.credential.ts create mode 100644 packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts create mode 100644 packages/components/nodes/llmcache/LLMMomentoCache/momento.png diff --git a/packages/components/credentials/MomentoCacheApi.credential.ts b/packages/components/credentials/MomentoCacheApi.credential.ts new file mode 100644 index 00000000..038f826d --- /dev/null +++ b/packages/components/credentials/MomentoCacheApi.credential.ts @@ -0,0 +1,36 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class MomentoCacheApi implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Momento Cache API' + this.name = 'momentoCacheApi' + this.version = 1.0 + this.description = + 'Refer to official guide on how to get API key on Momento' + this.inputs = [ + { + label: 'Cache', + name: 'momentoCache', + type: 'string' + }, + { + label: 'API Key', + name: 'momentoApiKey', + type: 'password' + }, + { + label: 'Endpoint', + name: 'momentoEndpoint', + type: 'string' + } + ] + } +} + +module.exports = { credClass: MomentoCacheApi } diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts b/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts new file mode 100644 index 00000000..82267c24 --- /dev/null +++ b/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts @@ -0,0 +1,75 @@ +import { + getBaseClasses, + getCredentialData, + getCredentialParam, + ICommonObject, + INode, + INodeData, + INodeOutputsValue, + INodeParams +} from '../../../src' +import { MomentoCache } from 'langchain/cache/momento' +import { CacheClient, Configurations, CredentialProvider } from '@gomomento/sdk' + +class LLMMomentoCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + credential: INodeParams + + constructor() { + this.label = 'Momento Cache' + this.name = 'momentoCache' + this.version = 1.0 + this.type = 'LLMCache' + this.icon = 'momento.png' + this.category = 'LLM Cache' + this.baseClasses = [this.type, 'LLMCacheBase'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + credentialNames: ['momentoCacheApi'] + } + this.inputs = [] + this.outputs = [ + { + label: 'LLM Cache', + name: 'cache', + baseClasses: [this.type, ...getBaseClasses(MomentoCache)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const apiKey = getCredentialParam('momentoApiKey', credentialData, nodeData) + const cacheName = getCredentialParam('momentoCache', credentialData, nodeData) + const endPoint = getCredentialParam('momentoEndpoint', credentialData, nodeData) + + // See https://github.com/momentohq/client-sdk-javascript for connection options + const client = new CacheClient({ + configuration: Configurations.Laptop.v1(), + credentialProvider: CredentialProvider.fromString({ + apiKey: apiKey + }), + defaultTtlSeconds: 60 * 60 * 24 + }) + + let momentoCache = await MomentoCache.fromProps({ + client, + cacheName: cacheName + }) + return momentoCache + } +} + +module.exports = { nodeClass: LLMMomentoCache } diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/momento.png b/packages/components/nodes/llmcache/LLMMomentoCache/momento.png new file mode 100644 index 0000000000000000000000000000000000000000..0f2b54b6a0c0e6100d2546d053e0b4548c42e4c6 GIT binary patch literal 5534 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 literal 0 HcmV?d00001 diff --git a/packages/components/package.json b/packages/components/package.json index f8498e31..18bf8e6a 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -19,6 +19,7 @@ "@aws-sdk/client-dynamodb": "^3.360.0", "@dqbd/tiktoken": "^1.0.7", "@getzep/zep-js": "^0.6.3", + "@gomomento/sdk": "^1.40.2", "@google-ai/generativelanguage": "^0.2.1", "@huggingface/inference": "^2.6.1", "@notionhq/client": "^2.2.8", From 29be2d2608de2e7c21b762041409aab8b827cb7d Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sat, 30 Sep 2023 18:51:14 +0530 Subject: [PATCH 06/76] Addition of Redis LLM Cache --- .../credentials/RedisCacheApi.credential.ts | 43 +++++++++++ .../llmcache/LLMRedisCache/LLMRedisCache.ts | 75 +++++++++++++++++++ .../nodes/llmcache/LLMRedisCache/redis.svg | 1 + packages/components/package.json | 1 + 4 files changed, 120 insertions(+) create mode 100644 packages/components/credentials/RedisCacheApi.credential.ts create mode 100644 packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts create mode 100644 packages/components/nodes/llmcache/LLMRedisCache/redis.svg diff --git a/packages/components/credentials/RedisCacheApi.credential.ts b/packages/components/credentials/RedisCacheApi.credential.ts new file mode 100644 index 00000000..e09a94e7 --- /dev/null +++ b/packages/components/credentials/RedisCacheApi.credential.ts @@ -0,0 +1,43 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class RedisCacheApi implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Redis Cache API' + this.name = 'redisCacheApi' + this.version = 1.0 + this.inputs = [ + { + label: 'Redis Host', + name: 'redisCacheHost', + type: 'string', + default: '127.0.0.1' + }, + { + label: 'Port', + name: 'redisCachePort', + type: 'number', + default: '6789' + }, + { + label: 'User', + name: 'redisCacheUser', + type: 'string', + placeholder: '' + }, + { + label: 'Password', + name: 'redisCachePwd', + type: 'password', + placeholder: '' + } + ] + } +} + +module.exports = { credClass: RedisCacheApi } diff --git a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts b/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts new file mode 100644 index 00000000..4a098e82 --- /dev/null +++ b/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts @@ -0,0 +1,75 @@ +import { + getBaseClasses, + getCredentialData, + getCredentialParam, + ICommonObject, + INode, + INodeData, + INodeOutputsValue, + INodeParams +} from '../../../src' +import { RedisCache } from 'langchain/cache/ioredis' +import { Redis } from 'ioredis' + +class LLMRedisCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + credential: INodeParams + + constructor() { + this.label = 'Redis LLM Cache' + this.name = 'redisCache' + this.version = 1.0 + this.type = 'LLMCache' + this.icon = 'redis.svg' + this.category = 'LLM Cache' + this.baseClasses = [this.type, 'LLMCacheBase'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + credentialNames: ['redisCacheApi'] + } + this.inputs = [] + this.outputs = [ + { + label: 'LLM Cache', + name: 'cache', + baseClasses: [this.type, ...getBaseClasses(RedisCache)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const username = getCredentialParam('redisCacheUser', credentialData, nodeData) + const password = getCredentialParam('redisCachePwd', credentialData, nodeData) + const portStr = getCredentialParam('redisCachePort', credentialData, nodeData) + const host = getCredentialParam('redisCacheHost', credentialData, nodeData) + let port = 6379 + try { + port = portStr ? parseInt(portStr) : 6379 + } catch (e) { + port = 6379 + } + + const client = new Redis({ + port: port, // Redis port + host: host, + username: username, + password: password + }) + return new RedisCache(client) + } +} + +module.exports = { nodeClass: LLMRedisCache } diff --git a/packages/components/nodes/llmcache/LLMRedisCache/redis.svg b/packages/components/nodes/llmcache/LLMRedisCache/redis.svg new file mode 100644 index 00000000..90359069 --- /dev/null +++ b/packages/components/nodes/llmcache/LLMRedisCache/redis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/package.json b/packages/components/package.json index 18bf8e6a..5e993f86 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -43,6 +43,7 @@ "google-auth-library": "^9.0.0", "graphql": "^16.6.0", "html-to-text": "^9.0.5", + "ioredis": "^5.3.2", "langchain": "^0.0.154", "langfuse-langchain": "^1.0.14-alpha.0", "langsmith": "^0.0.32", From 786dd8a11c3af6bb6cd122637d44978df600073b Mon Sep 17 00:00:00 2001 From: Ayush Jain Date: Wed, 4 Oct 2023 00:16:12 +0530 Subject: [PATCH 07/76] Added Upstash Redis Memory support --- .../UpstashRedisBackedChatMemory.ts | 131 ++++++++++++++++++ .../UpstashRedisBackedChatMemory/upstash.svg | 12 ++ packages/components/package.json | 3 +- 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts create mode 100644 packages/components/nodes/memory/UpstashRedisBackedChatMemory/upstash.svg diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts new file mode 100644 index 00000000..e0b5e20e --- /dev/null +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -0,0 +1,131 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import { ICommonObject } from '../../../src' +import { BufferMemory, BufferMemoryInput } from 'langchain/memory' +import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from "langchain/stores/message/upstash_redis"; +import { Redis, RedisConfigNodejs } from '@upstash/redis'; + +class UpstashRedisBackedChatMemory_Memory implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Upstash Redis-Backed Chat Memory' + this.name = 'UpstashRedisBackedChatMemory' + this.version = 1.0 + this.type = 'UpstashRedisBackedChatMemory' + this.icon = 'upstash.svg' + this.category = 'Memory' + this.description = 'Summarizes the conversation and stores the memory in upstash Redis server' + this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)] + this.inputs = [ + { + label: 'Base URL', + name: 'baseURL', + type: 'string', + default: 'redis://localhost:6379' + }, + { + label: 'Token', + name: 'token', + type: 'string', + default: '********' + }, + { + label: 'Session Id', + name: 'sessionId', + type: 'string', + description: 'If not specified, the first CHAT_MESSAGE_ID will be used as sessionId', + default: '', + additionalParams: true, + optional: true + }, + { + label: 'Session Timeouts', + name: 'sessionTTL', + type: 'number', + description: 'Omit this parameter to make sessions never expire', + additionalParams: true, + optional: true + }, + { + label: 'Memory Key', + name: 'memoryKey', + type: 'string', + default: 'chat_history', + additionalParams: true + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + return initalizeUpstashRedis(nodeData, options) + } + + async clearSessionMemory(nodeData: INodeData, options: ICommonObject): Promise { + const redis = initalizeUpstashRedis(nodeData, options) + const sessionId = nodeData.inputs?.sessionId as string + const chatId = options?.chatId as string + options.logger.info(`Clearing Upstash Redis memory session ${sessionId ? sessionId : chatId}`) + await redis.clear() + options.logger.info(`Successfully cleared Upstash Redis memory session ${sessionId ? sessionId : chatId}`) + } +} + +const initalizeUpstashRedis = (nodeData: INodeData, options: ICommonObject): BufferMemory => { + const baseURL = nodeData.inputs?.baseURL as string + const sessionId = nodeData.inputs?.sessionId as string + const sessionTTL = nodeData.inputs?.sessionTTL as number + const memoryKey = nodeData.inputs?.memoryKey as string + const chatId = options?.chatId as string + const token = nodeData.inputs?.token as string + + let isSessionIdUsingChatMessageId = false + if (!sessionId && chatId) isSessionIdUsingChatMessageId = true + + const upstashRedisConfig = ({ url: baseURL, token }) as RedisConfigNodejs; + const redisClient = new Redis(upstashRedisConfig) + let obj: UpstashRedisChatMessageHistoryInput = { + sessionId: sessionId ? sessionId : chatId, + client: redisClient + } + + if (sessionTTL) { + obj = { + ...obj, + sessionTTL + } + } + + const redisChatMessageHistory = new UpstashRedisChatMessageHistory(obj) + + const memory = new BufferMemoryExtended({ + memoryKey, + chatHistory: redisChatMessageHistory, + returnMessages: true, + isSessionIdUsingChatMessageId + }) + return memory +} + +interface BufferMemoryExtendedInput { + isSessionIdUsingChatMessageId: boolean +} + +class BufferMemoryExtended extends BufferMemory { + isSessionIdUsingChatMessageId? = false + + constructor(fields: BufferMemoryInput & Partial) { + super(fields) + this.isSessionIdUsingChatMessageId = fields.isSessionIdUsingChatMessageId + } +} + +module.exports = { nodeClass: UpstashRedisBackedChatMemory_Memory } diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/upstash.svg b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/upstash.svg new file mode 100644 index 00000000..a0fb96a7 --- /dev/null +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/upstash.svg @@ -0,0 +1,12 @@ + + + upstash + + + + + + + + + diff --git a/packages/components/package.json b/packages/components/package.json index 93609106..77ada2ad 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -64,7 +64,8 @@ "srt-parser-2": "^1.2.3", "vm2": "^3.9.19", "weaviate-ts-client": "^1.1.0", - "ws": "^8.9.0" + "ws": "^8.9.0", + "@upstash/redis": "^1.22.1" }, "devDependencies": { "@types/gulp": "4.0.9", From 086944dc077752fb30eb8d887450af34ca398098 Mon Sep 17 00:00:00 2001 From: Ayush Jain Date: Thu, 5 Oct 2023 18:29:39 +0530 Subject: [PATCH 08/76] Fixed linting errors --- .../UpstashRedisBackedChatMemory.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index e0b5e20e..64b14e2c 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -2,8 +2,8 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' import { ICommonObject } from '../../../src' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' -import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from "langchain/stores/message/upstash_redis"; -import { Redis, RedisConfigNodejs } from '@upstash/redis'; +import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from "langchain/stores/message/upstash_redis" +import { Redis, RedisConfigNodejs } from '@upstash/redis' class UpstashRedisBackedChatMemory_Memory implements INode { label: string @@ -90,7 +90,7 @@ const initalizeUpstashRedis = (nodeData: INodeData, options: ICommonObject): Buf let isSessionIdUsingChatMessageId = false if (!sessionId && chatId) isSessionIdUsingChatMessageId = true - const upstashRedisConfig = ({ url: baseURL, token }) as RedisConfigNodejs; + const upstashRedisConfig = ({ url: baseURL, token }) as RedisConfigNodejs const redisClient = new Redis(upstashRedisConfig) let obj: UpstashRedisChatMessageHistoryInput = { sessionId: sessionId ? sessionId : chatId, From cddc68c187d6e430e1dce85497c8ff254caeb0a2 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 6 Oct 2023 13:17:56 +0530 Subject: [PATCH 09/76] LLM Cache - Addition of Upstash Redis --- .../credentials/UpstashRedisApi.credential.ts | 28 ++++++++ .../LLMUpstashRedisCache.ts | 66 ++++++++++++++++++ .../llmcache/LLMUpstashRedisCache/upstash.png | Bin 0 -> 2698 bytes packages/components/package.json | 3 +- 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 packages/components/credentials/UpstashRedisApi.credential.ts create mode 100644 packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts create mode 100644 packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png diff --git a/packages/components/credentials/UpstashRedisApi.credential.ts b/packages/components/credentials/UpstashRedisApi.credential.ts new file mode 100644 index 00000000..b6e62ff3 --- /dev/null +++ b/packages/components/credentials/UpstashRedisApi.credential.ts @@ -0,0 +1,28 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class UpstashRedisApi implements INodeCredential { + label: string + name: string + version: number + inputs: INodeParams[] + + constructor() { + this.label = 'Upstash Redis API' + this.name = 'upstashRedisApi' + this.version = 1.0 + this.inputs = [ + { + label: 'Upstash Redis REST URL', + name: 'upstashConnectionUrl', + type: 'string' + }, + { + label: 'Token', + name: 'upstashConnectionToken', + type: 'password' + } + ] + } +} + +module.exports = { credClass: UpstashRedisApi } diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts b/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts new file mode 100644 index 00000000..b16d6e13 --- /dev/null +++ b/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts @@ -0,0 +1,66 @@ +import { + getBaseClasses, + getCredentialData, + getCredentialParam, + ICommonObject, + INode, + INodeData, + INodeOutputsValue, + INodeParams +} from '../../../src' +import { UpstashRedisCache } from 'langchain/cache/upstash_redis' + +class LLMUpstashRedisCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + credential: INodeParams + + constructor() { + this.label = 'Upstash Redis LLM Cache' + this.name = 'upstashRedisCache' + this.version = 1.0 + this.type = 'LLMCache' + this.icon = 'upstash.png' + this.category = 'LLM Cache' + this.baseClasses = [this.type, 'LLMCacheBase'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + credentialNames: ['upstashRedisApi'] + } + this.inputs = [] + this.outputs = [ + { + label: 'LLM Cache', + name: 'cache', + baseClasses: [this.type, ...getBaseClasses(UpstashRedisCache)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const upstashConnectionUrl = getCredentialParam('upstashConnectionUrl', credentialData, nodeData) + const upstashToken = getCredentialParam('upstashConnectionToken', credentialData, nodeData) + + const cache = new UpstashRedisCache({ + config: { + url: upstashConnectionUrl, + token: upstashToken + } + }) + return cache + } +} + +module.exports = { nodeClass: LLMUpstashRedisCache } diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png b/packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png new file mode 100644 index 0000000000000000000000000000000000000000..e27e02f4a3ba635cf04a33dbcfaa1a8e973ee2cc GIT binary patch literal 2698 zcmV;53U&2~P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf3Li;CK~z{rwODCv zRM#0jGhW6X+he@o1>0b-OTb{u1PC;ViGm<$NE4*0qHWrS0!gY?irP|KO4>->)$*rJ zgj#~s$`MLYnkFhK6bK=TB1l>j63k}sg24;M9`E+-i+jHN-psriKgT9Yj`cjA``)|v z+;2JGcWs#@@EM@fH-<}|K@0{xa0a{>341XX^1~YrBCJ1?3=1-oQjyJTPI4NGlkF%- zv7^>LSB=kvPfgYx4B+r+JKmq@MT>6)nbs7fTa%GwvGB6O%4aO{W6?g(&Pr)6NJuz|vhez7c6_}uPY_M696ge}Hrzy-9 zlreueq&y+yA8?dmYwl7MrrNa!h*^_8KGK1P!Di3^$f6a^2#S^D^2wr;L3sEX=65Tf zm1X27#hRo%kj71>^6zB&K)jJiLgsJ=-Kb8_!>)pr$S3I;$#(lE@bjM2aP#HtBpVlw zx0jHU*mQ>js7;%T($p+0;{ugw*_fA_sXrBiI}|{de;ijm!)Wu3qS-r$?tqK2o36Z+ zIDcR=gqz+md@XPBCzCzsY{tJv+f*_nCs;DF^HugjY;?@W{aGdYojZrP|L;Rr@!nWB z6ElE3t`{La5b&VFmW}7ZisO$ z+f8FAEwDMTBrO+}bnV)#dD=^}L>$>hS1*3q^FNd(SWVo%IeQVlnZHyYnTkg0?V+I- z^ia|y`)#}=&XdF^dKAe@l8}BTO^AO}BWQqPd@HX?$>2sZJvHpb`(iLS91 zVP~D6u%Dt7(6VG7K2s&)YEd3&0}Rr zL@TRLt9Jx8gX=@IXpryhE?$jld%iw8Jq|2-2(K=Gk_%B!xydM4$_KdNFI_prFf@!4 zimZptLr@FdD5Q?(vb>t1kCn?qHyTT$SanHyE^65B%@$kot8ldH8+5-%lZpr^n^&nW zPhUT-4`|Rl&+f#Mkg`HUB*+Z%s9Z6sf=OC>YGO#=@W|yuc%k=0eIy>6ax3vt#g}QZ zL4GsLm^KFuH{OMdMu|YNNwylrN`sJ@2>G-x32@L=(sW2NMIf=;>KQ?wxK+pN1I;Ko z`zLm6?f7BaVf?Q91N}}so+(;^n(T#|g^jT1VRQ3q`WKySX-Wpt7=NM)5v0B6QrLloakqm>+dOAja{sCOWDu!eYkwWFYw!<3_5LtGnSC*e5v3g|JbK1YyUZIQGy=a+s5& zMg%gR#YJB1Kaan%i=X1E1RP^y^4OJEIXkUwv?8T&E&GKv?28l8!Q=cpJSC{4jDU$~ zXJJ~aKOfg3M&Mz$w5{VU>aSHbDpu~+&M>)3N&1iTB5bTMPtC2t(*-NoOlPU{zf5y* z@Cwgu7w|C~6tKCDCrWQon#R`drl$HQo}wO#DIBn*xWwBVM1SZg*oiCUaxS7p1%lZ?p`M7kwzEDq95@&1L{XV^EGmt)JB z-)Qd}&vd?V)R*3mz2)oG*J;T{aFA8#NeVoqp-~z-O>!hcre$*kO50jTIZiEmLiMj^ z*vOE1d$?6A9udgqT~16s_yD#@&U>hNibN5NKo@$Z}b$F z`z8;4&$1`|Jn=C%`8ZwQ%|055|FvOxuX8NGd)4f96A&fa(BFh@SJ>gu!zFAwUgWO6 zl6RMS=(B>0WqBj5`2o8yMbemvLc>3bhq5bh!i1>6((iXo)-i#u@mv&jhr}K;F(bu} z?@*%tz--Jg>farrfwBG<_Op#F6kw>RcsD}goT^h_whnt)wx@$-d+U+OzjeOL!dx(Q z5|uEND0W{-T;vIs)^eWn*E{B;iV`HvhY`}>Ho5!p(fBRAKi-LREYVHsoFz)aXA?`Z z%ulyxQf1E7Y{%khDq93947z+{c(nPSxHv-jP&+q~7@0Uio+n$db<;W|Q3GCbPsoS| znC zg%Fg@G1DvPou8K0;i znH(~K9E0*%YRh=sDQ2cu+vcFq=D<3}dDSeA<}(BMKR;-3TtO!==>Px#07*qoM6N<$ Ef=GE79{>OV literal 0 HcmV?d00001 diff --git a/packages/components/package.json b/packages/components/package.json index 5e993f86..e3c4380a 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -29,6 +29,7 @@ "@supabase/supabase-js": "^2.29.0", "@types/js-yaml": "^4.0.5", "@types/jsdom": "^21.1.1", + "@upstash/redis": "^1.22.1", "@zilliz/milvus2-sdk-node": "^2.2.24", "apify-client": "^2.7.1", "axios": "^0.27.2", @@ -44,7 +45,7 @@ "graphql": "^16.6.0", "html-to-text": "^9.0.5", "ioredis": "^5.3.2", - "langchain": "^0.0.154", + "langchain": "^0.0.157", "langfuse-langchain": "^1.0.14-alpha.0", "langsmith": "^0.0.32", "linkifyjs": "^4.1.1", From 9bae1c33f71070fe8406a78ad1b4a343402b3b33 Mon Sep 17 00:00:00 2001 From: Ayush Jain Date: Fri, 6 Oct 2023 23:23:21 +0530 Subject: [PATCH 10/76] Review changes --- .../UpstashRedisMemoryApi.credential.ts | 26 ++++++++++++++++ .../UpstashRedisBackedChatMemory.ts | 30 +++++++++++-------- 2 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 packages/components/credentials/UpstashRedisMemoryApi.credential.ts diff --git a/packages/components/credentials/UpstashRedisMemoryApi.credential.ts b/packages/components/credentials/UpstashRedisMemoryApi.credential.ts new file mode 100644 index 00000000..9c0f99aa --- /dev/null +++ b/packages/components/credentials/UpstashRedisMemoryApi.credential.ts @@ -0,0 +1,26 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class UpstashRedisMemoryApi implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Upstash Redis Memory API' + this.name = 'upstashRedisMemoryApi' + this.version = 1.0 + this.description = + 'Refer to official guide on how to create redis instance and get password on upstash' + this.inputs = [ + { + label: 'Upstash Redis Password', + name: 'upstashRedisPassword', + type: 'password' + } + ] + } +} + +module.exports = { credClass: UpstashRedisMemoryApi } diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index 64b14e2c..98983ecb 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -1,8 +1,8 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' -import { getBaseClasses } from '../../../src/utils' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ICommonObject } from '../../../src' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' -import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from "langchain/stores/message/upstash_redis" +import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from 'langchain/stores/message/upstash_redis' import { Redis, RedisConfigNodejs } from '@upstash/redis' class UpstashRedisBackedChatMemory_Memory implements INode { @@ -14,6 +14,7 @@ class UpstashRedisBackedChatMemory_Memory implements INode { icon: string category: string baseClasses: string[] + credential: INodeParams inputs: INodeParams[] constructor() { @@ -25,18 +26,19 @@ class UpstashRedisBackedChatMemory_Memory implements INode { this.category = 'Memory' this.description = 'Summarizes the conversation and stores the memory in upstash Redis server' this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + description: 'Configure password authentication on your upstash redis instance', + credentialNames: ['upstashRedisMemoryApi'] + } this.inputs = [ { label: 'Base URL', name: 'baseURL', type: 'string', - default: 'redis://localhost:6379' - }, - { - label: 'Token', - name: 'token', - type: 'string', - default: '********' + default: 'https://.upstash.io' }, { label: 'Session Id', @@ -70,7 +72,7 @@ class UpstashRedisBackedChatMemory_Memory implements INode { } async clearSessionMemory(nodeData: INodeData, options: ICommonObject): Promise { - const redis = initalizeUpstashRedis(nodeData, options) + const redis = await initalizeUpstashRedis(nodeData, options) const sessionId = nodeData.inputs?.sessionId as string const chatId = options?.chatId as string options.logger.info(`Clearing Upstash Redis memory session ${sessionId ? sessionId : chatId}`) @@ -79,18 +81,20 @@ class UpstashRedisBackedChatMemory_Memory implements INode { } } -const initalizeUpstashRedis = (nodeData: INodeData, options: ICommonObject): BufferMemory => { +const initalizeUpstashRedis = async (nodeData: INodeData, options: ICommonObject): Promise => { const baseURL = nodeData.inputs?.baseURL as string const sessionId = nodeData.inputs?.sessionId as string const sessionTTL = nodeData.inputs?.sessionTTL as number const memoryKey = nodeData.inputs?.memoryKey as string const chatId = options?.chatId as string - const token = nodeData.inputs?.token as string let isSessionIdUsingChatMessageId = false if (!sessionId && chatId) isSessionIdUsingChatMessageId = true - const upstashRedisConfig = ({ url: baseURL, token }) as RedisConfigNodejs + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const upstashRedisPassword = getCredentialParam('upstashRedisPassword', credentialData, nodeData) + + const upstashRedisConfig = { url: baseURL, token: upstashRedisPassword } as RedisConfigNodejs const redisClient = new Redis(upstashRedisConfig) let obj: UpstashRedisChatMessageHistoryInput = { sessionId: sessionId ? sessionId : chatId, From 0b0cf357c58d8f88aaf22adc68abef41af607e80 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:34:07 +0100 Subject: [PATCH 11/76] Update LLMInMemoryCache.ts code cleanup --- .../llmcache/LLMInMemoryCache/LLMInMemoryCache.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts b/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts index 5e77a029..44133486 100644 --- a/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts +++ b/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts @@ -1,4 +1,4 @@ -import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { INode, INodeParams } from '../../../src/Interface' import { InMemoryCache } from 'langchain/cache' import { getBaseClasses } from '../../../src' @@ -12,7 +12,6 @@ class LLMInMemoryCache implements INode { category: string baseClasses: string[] inputs: INodeParams[] - outputs: INodeOutputsValue[] inMemoryCache: any constructor() { @@ -22,18 +21,11 @@ class LLMInMemoryCache implements INode { this.type = 'LLMCache' this.icon = 'memorycache.png' this.category = 'LLM Cache' - this.baseClasses = [this.type, 'LLMCacheBase'] + this.baseClasses = [this.type, ...getBaseClasses(InMemoryCache)] this.inputs = [] - this.outputs = [ - { - label: 'LLM Cache', - name: 'cache', - baseClasses: [this.type, ...getBaseClasses(InMemoryCache)] - } - ] } - async init(nodeData: INodeData): Promise { + async init(): Promise { if (!this.inMemoryCache) { this.inMemoryCache = InMemoryCache.global() } From 2785e3b685f6e5adcee00af3b52dcfec0f5af058 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:34:36 +0100 Subject: [PATCH 12/76] Update LLMMomentoCache.ts code cleanup --- .../LLMMomentoCache/LLMMomentoCache.ts | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts b/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts index 82267c24..f8fd61fb 100644 --- a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts +++ b/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts @@ -1,13 +1,4 @@ -import { - getBaseClasses, - getCredentialData, - getCredentialParam, - ICommonObject, - INode, - INodeData, - INodeOutputsValue, - INodeParams -} from '../../../src' +import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' import { MomentoCache } from 'langchain/cache/momento' import { CacheClient, Configurations, CredentialProvider } from '@gomomento/sdk' @@ -21,7 +12,6 @@ class LLMMomentoCache implements INode { category: string baseClasses: string[] inputs: INodeParams[] - outputs: INodeOutputsValue[] credential: INodeParams constructor() { @@ -31,7 +21,7 @@ class LLMMomentoCache implements INode { this.type = 'LLMCache' this.icon = 'momento.png' this.category = 'LLM Cache' - this.baseClasses = [this.type, 'LLMCacheBase'] + this.baseClasses = [this.type, ...getBaseClasses(MomentoCache)] this.credential = { label: 'Connect Credential', name: 'credential', @@ -40,13 +30,6 @@ class LLMMomentoCache implements INode { credentialNames: ['momentoCacheApi'] } this.inputs = [] - this.outputs = [ - { - label: 'LLM Cache', - name: 'cache', - baseClasses: [this.type, ...getBaseClasses(MomentoCache)] - } - ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { From 52ccb89949cb75a32730bdd7fcaeb00fe8195cf6 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:34:56 +0100 Subject: [PATCH 13/76] Update LLMRedisCache.ts code cleanup --- .../llmcache/LLMRedisCache/LLMRedisCache.ts | 35 ++++--------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts b/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts index 4a098e82..a7208977 100644 --- a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts +++ b/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts @@ -1,13 +1,4 @@ -import { - getBaseClasses, - getCredentialData, - getCredentialParam, - ICommonObject, - INode, - INodeData, - INodeOutputsValue, - INodeParams -} from '../../../src' +import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' import { RedisCache } from 'langchain/cache/ioredis' import { Redis } from 'ioredis' @@ -21,7 +12,6 @@ class LLMRedisCache implements INode { category: string baseClasses: string[] inputs: INodeParams[] - outputs: INodeOutputsValue[] credential: INodeParams constructor() { @@ -31,7 +21,7 @@ class LLMRedisCache implements INode { this.type = 'LLMCache' this.icon = 'redis.svg' this.category = 'LLM Cache' - this.baseClasses = [this.type, 'LLMCacheBase'] + this.baseClasses = [this.type, ...getBaseClasses(RedisCache)] this.credential = { label: 'Connect Credential', name: 'credential', @@ -40,13 +30,6 @@ class LLMRedisCache implements INode { credentialNames: ['redisCacheApi'] } this.inputs = [] - this.outputs = [ - { - label: 'LLM Cache', - name: 'cache', - baseClasses: [this.type, ...getBaseClasses(RedisCache)] - } - ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { @@ -55,18 +38,12 @@ class LLMRedisCache implements INode { const password = getCredentialParam('redisCachePwd', credentialData, nodeData) const portStr = getCredentialParam('redisCachePort', credentialData, nodeData) const host = getCredentialParam('redisCacheHost', credentialData, nodeData) - let port = 6379 - try { - port = portStr ? parseInt(portStr) : 6379 - } catch (e) { - port = 6379 - } const client = new Redis({ - port: port, // Redis port - host: host, - username: username, - password: password + port: portStr ? parseInt(portStr) : 6379, + host, + username, + password }) return new RedisCache(client) } From 5288ea8155447fb75b843eec05deb540231d249d Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:35:16 +0100 Subject: [PATCH 14/76] Update LLMUpstashRedisCache.ts code cleanup --- .../LLMUpstashRedisCache.ts | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts b/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts index b16d6e13..8914b2a1 100644 --- a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts +++ b/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts @@ -1,13 +1,4 @@ -import { - getBaseClasses, - getCredentialData, - getCredentialParam, - ICommonObject, - INode, - INodeData, - INodeOutputsValue, - INodeParams -} from '../../../src' +import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' import { UpstashRedisCache } from 'langchain/cache/upstash_redis' class LLMUpstashRedisCache implements INode { @@ -20,7 +11,6 @@ class LLMUpstashRedisCache implements INode { category: string baseClasses: string[] inputs: INodeParams[] - outputs: INodeOutputsValue[] credential: INodeParams constructor() { @@ -30,7 +20,7 @@ class LLMUpstashRedisCache implements INode { this.type = 'LLMCache' this.icon = 'upstash.png' this.category = 'LLM Cache' - this.baseClasses = [this.type, 'LLMCacheBase'] + this.baseClasses = [this.type, ...getBaseClasses(UpstashRedisCache)] this.credential = { label: 'Connect Credential', name: 'credential', @@ -39,13 +29,6 @@ class LLMUpstashRedisCache implements INode { credentialNames: ['upstashRedisApi'] } this.inputs = [] - this.outputs = [ - { - label: 'LLM Cache', - name: 'cache', - baseClasses: [this.type, ...getBaseClasses(UpstashRedisCache)] - } - ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { From 8ee4f0fc3c71971d7408c65d91d9b9f3f7735c46 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Fri, 6 Oct 2023 23:36:09 +0100 Subject: [PATCH 15/76] Update Interface.ts code cleanup --- packages/components/src/Interface.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/components/src/Interface.ts b/packages/components/src/Interface.ts index 76dc7354..e883d056 100644 --- a/packages/components/src/Interface.ts +++ b/packages/components/src/Interface.ts @@ -1,7 +1,6 @@ /** * Types */ -import { BaseCache } from 'langchain/schema' export type NodeParamsType = | 'asyncOptions' @@ -177,9 +176,3 @@ export class VectorStoreRetriever { this.vectorStore = fields.vectorStore } } - -export interface LLMCacheBase { - name: string - description: string - baseCache: BaseCache -} From dbd655580d9bf68c7976b0b4502426ad8774ff3c Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sat, 7 Oct 2023 19:17:33 +0100 Subject: [PATCH 16/76] Add fix where flow is not restarted when cache is used --- packages/server/src/utils/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index bb048490..98802cde 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -477,6 +477,7 @@ export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig: */ export const isStartNodeDependOnInput = (startingNodes: IReactFlowNode[], nodes: IReactFlowNode[]): boolean => { for (const node of startingNodes) { + if (node.data.category === 'LLM Cache') return true for (const inputName in node.data.inputs) { const inputVariables = getInputVariables(node.data.inputs[inputName]) if (inputVariables.length > 0) return true From 424e71312873fc88023fb7bc3e91bcb607f4a06b Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 01:52:19 +0100 Subject: [PATCH 17/76] Update UpstashRedisBackedChatMemory.ts code cleanup --- .../UpstashRedisBackedChatMemory.ts | 41 ++++++------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index 98983ecb..00d7697a 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -2,8 +2,7 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ICommonObject } from '../../../src' import { BufferMemory, BufferMemoryInput } from 'langchain/memory' -import { UpstashRedisChatMessageHistory, UpstashRedisChatMessageHistoryInput } from 'langchain/stores/message/upstash_redis' -import { Redis, RedisConfigNodejs } from '@upstash/redis' +import { UpstashRedisChatMessageHistory } from 'langchain/stores/message/upstash_redis' class UpstashRedisBackedChatMemory_Memory implements INode { label: string @@ -35,10 +34,10 @@ class UpstashRedisBackedChatMemory_Memory implements INode { } this.inputs = [ { - label: 'Base URL', + label: 'Upstash Redis REST URL', name: 'baseURL', type: 'string', - default: 'https://.upstash.io' + placeholder: 'https://.upstash.io' }, { label: 'Session Id', @@ -56,13 +55,6 @@ class UpstashRedisBackedChatMemory_Memory implements INode { description: 'Omit this parameter to make sessions never expire', additionalParams: true, optional: true - }, - { - label: 'Memory Key', - name: 'memoryKey', - type: 'string', - default: 'chat_history', - additionalParams: true } ] } @@ -84,38 +76,29 @@ class UpstashRedisBackedChatMemory_Memory implements INode { const initalizeUpstashRedis = async (nodeData: INodeData, options: ICommonObject): Promise => { const baseURL = nodeData.inputs?.baseURL as string const sessionId = nodeData.inputs?.sessionId as string - const sessionTTL = nodeData.inputs?.sessionTTL as number - const memoryKey = nodeData.inputs?.memoryKey as string + const sessionTTL = nodeData.inputs?.sessionTTL as string const chatId = options?.chatId as string let isSessionIdUsingChatMessageId = false if (!sessionId && chatId) isSessionIdUsingChatMessageId = true const credentialData = await getCredentialData(nodeData.credential ?? '', options) - const upstashRedisPassword = getCredentialParam('upstashRedisPassword', credentialData, nodeData) + const upstashRestToken = getCredentialParam('upstashRestToken', credentialData, nodeData) - const upstashRedisConfig = { url: baseURL, token: upstashRedisPassword } as RedisConfigNodejs - const redisClient = new Redis(upstashRedisConfig) - let obj: UpstashRedisChatMessageHistoryInput = { + const redisChatMessageHistory = new UpstashRedisChatMessageHistory({ sessionId: sessionId ? sessionId : chatId, - client: redisClient - } - - if (sessionTTL) { - obj = { - ...obj, - sessionTTL + sessionTTL: sessionTTL ? parseInt(sessionTTL, 10) : undefined, + config: { + url: baseURL, + token: upstashRestToken } - } - - const redisChatMessageHistory = new UpstashRedisChatMessageHistory(obj) + }) const memory = new BufferMemoryExtended({ - memoryKey, chatHistory: redisChatMessageHistory, - returnMessages: true, isSessionIdUsingChatMessageId }) + return memory } From e2355555ed16e87be60d697378f9485e031d22ec Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 01:52:48 +0100 Subject: [PATCH 18/76] Update UpstashRedisMemoryApi.credential.ts rename token label --- .../credentials/UpstashRedisMemoryApi.credential.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/credentials/UpstashRedisMemoryApi.credential.ts b/packages/components/credentials/UpstashRedisMemoryApi.credential.ts index 9c0f99aa..8d3e9528 100644 --- a/packages/components/credentials/UpstashRedisMemoryApi.credential.ts +++ b/packages/components/credentials/UpstashRedisMemoryApi.credential.ts @@ -12,11 +12,11 @@ class UpstashRedisMemoryApi implements INodeCredential { this.name = 'upstashRedisMemoryApi' this.version = 1.0 this.description = - 'Refer to official guide on how to create redis instance and get password on upstash' + 'Refer to official guide on how to create redis instance and get redis REST Token' this.inputs = [ { - label: 'Upstash Redis Password', - name: 'upstashRedisPassword', + label: 'Upstash Redis REST Token', + name: 'upstashRestToken', type: 'password' } ] From 7c020c4b3ea97c8fef4b79e4d3a083d1bca7cf9f Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 01:53:58 +0100 Subject: [PATCH 19/76] Update package.json --- packages/components/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/package.json b/packages/components/package.json index 77ada2ad..cf5a5f17 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -28,6 +28,7 @@ "@supabase/supabase-js": "^2.29.0", "@types/js-yaml": "^4.0.5", "@types/jsdom": "^21.1.1", + "@upstash/redis": "^1.22.1", "@zilliz/milvus2-sdk-node": "^2.2.24", "apify-client": "^2.7.1", "axios": "^0.27.2", @@ -64,8 +65,7 @@ "srt-parser-2": "^1.2.3", "vm2": "^3.9.19", "weaviate-ts-client": "^1.1.0", - "ws": "^8.9.0", - "@upstash/redis": "^1.22.1" + "ws": "^8.9.0" }, "devDependencies": { "@types/gulp": "4.0.9", From 8b555e02f80b7deedb8d54f658a390e8e431feaf Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 01:55:45 +0100 Subject: [PATCH 20/76] Update UpstashRedisBackedChatMemory.ts camelCase node name --- .../UpstashRedisBackedChatMemory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts index 00d7697a..6b5fdf66 100644 --- a/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts +++ b/packages/components/nodes/memory/UpstashRedisBackedChatMemory/UpstashRedisBackedChatMemory.ts @@ -18,12 +18,12 @@ class UpstashRedisBackedChatMemory_Memory implements INode { constructor() { this.label = 'Upstash Redis-Backed Chat Memory' - this.name = 'UpstashRedisBackedChatMemory' + this.name = 'upstashRedisBackedChatMemory' this.version = 1.0 this.type = 'UpstashRedisBackedChatMemory' this.icon = 'upstash.svg' this.category = 'Memory' - this.description = 'Summarizes the conversation and stores the memory in upstash Redis server' + this.description = 'Summarizes the conversation and stores the memory in Upstash Redis server' this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)] this.credential = { label: 'Connect Credential', From 679eac1d0b24c5b7b8ba6a582dcf88ebc4589588 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sun, 8 Oct 2023 11:44:43 +0530 Subject: [PATCH 21/76] Addition of Cache Option for Chat Models --- .../nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts | 14 ++++++++++++-- .../chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts | 14 ++++++++++++-- .../nodes/chatmodels/Bittensor/Bittensor.ts | 13 ++++++++++++- .../chatmodels/ChatAnthropic/ChatAnthropic.ts | 14 ++++++++++++-- .../chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts | 11 ++++++++++- .../ChatGoogleVertexAI/ChatGoogleVertexAI.ts | 11 ++++++++++- .../chatmodels/ChatHuggingFace/ChatHuggingFace.ts | 11 ++++++++++- .../nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts | 14 ++++++++++++-- .../nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts | 15 +++++++++++++-- .../ChatOpenAICustom/ChatOpenAICustom.ts | 14 ++++++++++++-- 10 files changed, 115 insertions(+), 16 deletions(-) diff --git a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts index f5fa8bba..ba4bdd8a 100644 --- a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts +++ b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts @@ -2,6 +2,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatBedrock } from 'langchain/chat_models/bedrock' import { BaseBedrockInput } from 'langchain/dist/util/bedrock' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' /** * I had to run the following to build the component @@ -25,7 +27,7 @@ class AWSChatBedrock_ChatModels implements INode { constructor() { this.label = 'AWS Bedrock' this.name = 'awsChatBedrock' - this.version = 1.1 + this.version = 2.0 this.type = 'AWSChatBedrock' this.icon = 'awsBedrock.png' this.category = 'Chat Models' @@ -39,6 +41,12 @@ class AWSChatBedrock_ChatModels implements INode { optional: true } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Region', name: 'region', @@ -130,8 +138,9 @@ class AWSChatBedrock_ChatModels implements INode { const iModel = nodeData.inputs?.model as string const iTemperature = nodeData.inputs?.temperature as string const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string + const cache = nodeData.inputs?.llmCache as BaseCache - const obj: BaseBedrockInput = { + const obj: BaseBedrockInput & BaseLLMParams = { region: iRegion, model: iModel, maxTokens: parseInt(iMax_tokens_to_sample, 10), @@ -157,6 +166,7 @@ class AWSChatBedrock_ChatModels implements INode { sessionToken: credentialApiSession } } + if (cache) obj.cache = cache const amazonBedrock = new ChatBedrock(obj) return amazonBedrock diff --git a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts index 90f430f0..5acf4dce 100644 --- a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts @@ -2,6 +2,8 @@ import { OpenAIBaseInput } from 'langchain/dist/types/openai-types' import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { AzureOpenAIInput, ChatOpenAI } from 'langchain/chat_models/openai' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class AzureChatOpenAI_ChatModels implements INode { label: string @@ -18,7 +20,7 @@ class AzureChatOpenAI_ChatModels implements INode { constructor() { this.label = 'Azure ChatOpenAI' this.name = 'azureChatOpenAI' - this.version = 1.0 + this.version = 2.0 this.type = 'AzureChatOpenAI' this.icon = 'Azure.svg' this.category = 'Chat Models' @@ -31,6 +33,12 @@ class AzureChatOpenAI_ChatModels implements INode { credentialNames: ['azureOpenAIApi'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -107,6 +115,7 @@ class AzureChatOpenAI_ChatModels implements INode { const presencePenalty = nodeData.inputs?.presencePenalty as string const timeout = nodeData.inputs?.timeout as string const streaming = nodeData.inputs?.streaming as boolean + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const azureOpenAIApiKey = getCredentialParam('azureOpenAIApiKey', credentialData, nodeData) @@ -114,7 +123,7 @@ class AzureChatOpenAI_ChatModels implements INode { const azureOpenAIApiDeploymentName = getCredentialParam('azureOpenAIApiDeploymentName', credentialData, nodeData) const azureOpenAIApiVersion = getCredentialParam('azureOpenAIApiVersion', credentialData, nodeData) - const obj: Partial & Partial = { + const obj: Partial & BaseLLMParams & Partial = { temperature: parseFloat(temperature), modelName, azureOpenAIApiKey, @@ -128,6 +137,7 @@ class AzureChatOpenAI_ChatModels implements INode { if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty) if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) + if (cache) obj.cache = cache const model = new ChatOpenAI(obj) return model diff --git a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts index cfcac863..89c37157 100644 --- a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts +++ b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts @@ -1,6 +1,7 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' import { NIBittensorChatModel, BittensorInput } from 'langchain/experimental/chat_models/bittensor' +import { BaseCache } from 'langchain/schema' class Bittensor_ChatModels implements INode { label: string @@ -16,13 +17,19 @@ class Bittensor_ChatModels implements INode { constructor() { this.label = 'NIBittensorChat' this.name = 'NIBittensorChatModel' - this.version = 1.0 + this.version = 2.0 this.type = 'BittensorChat' this.icon = 'logo.png' this.category = 'Chat Models' this.description = 'Wrapper around Bittensor subnet 1 large language models' this.baseClasses = [this.type, ...getBaseClasses(NIBittensorChatModel)] this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'System prompt', name: 'system_prompt', @@ -35,9 +42,13 @@ class Bittensor_ChatModels implements INode { async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string + const cache = nodeData.inputs?.llmCache as BaseCache + const obj: Partial = { systemPrompt: system_prompt } + if (cache) obj.cache = cache + const model = new NIBittensorChatModel(obj) return model } diff --git a/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts b/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts index 12a33d99..039b437b 100644 --- a/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts +++ b/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { AnthropicInput, ChatAnthropic } from 'langchain/chat_models/anthropic' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class ChatAnthropic_ChatModels implements INode { label: string @@ -17,7 +19,7 @@ class ChatAnthropic_ChatModels implements INode { constructor() { this.label = 'ChatAnthropic' this.name = 'chatAnthropic' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatAnthropic' this.icon = 'chatAnthropic.png' this.category = 'Chat Models' @@ -30,6 +32,12 @@ class ChatAnthropic_ChatModels implements INode { credentialNames: ['anthropicApi'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -135,11 +143,12 @@ class ChatAnthropic_ChatModels implements INode { const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string const streaming = nodeData.inputs?.streaming as boolean + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const anthropicApiKey = getCredentialParam('anthropicApiKey', credentialData, nodeData) - const obj: Partial & { anthropicApiKey?: string } = { + const obj: Partial & BaseLLMParams & { anthropicApiKey?: string } = { temperature: parseFloat(temperature), modelName, anthropicApiKey, @@ -149,6 +158,7 @@ class ChatAnthropic_ChatModels implements INode { if (maxTokensToSample) obj.maxTokensToSample = parseInt(maxTokensToSample, 10) if (topP) obj.topP = parseFloat(topP) if (topK) obj.topK = parseFloat(topK) + if (cache) obj.cache = cache const model = new ChatAnthropic(obj) return model diff --git a/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts b/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts index 642ddb5e..8ee3fbb8 100644 --- a/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts +++ b/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts @@ -1,6 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatGooglePaLM, GooglePaLMChatInput } from 'langchain/chat_models/googlepalm' +import { BaseCache } from 'langchain/schema' class ChatGooglePaLM_ChatModels implements INode { label: string @@ -17,7 +18,7 @@ class ChatGooglePaLM_ChatModels implements INode { constructor() { this.label = 'ChatGooglePaLM' this.name = 'chatGooglePaLM' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatGooglePaLM' this.icon = 'Google_PaLM_Logo.svg' this.category = 'Chat Models' @@ -30,6 +31,12 @@ class ChatGooglePaLM_ChatModels implements INode { credentialNames: ['googleMakerSuite'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -96,6 +103,7 @@ class ChatGooglePaLM_ChatModels implements INode { const temperature = nodeData.inputs?.temperature as string const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData) @@ -108,6 +116,7 @@ class ChatGooglePaLM_ChatModels implements INode { if (topP) obj.topP = parseFloat(topP) if (topK) obj.topK = parseFloat(topK) + if (cache) obj.cache = cache const model = new ChatGooglePaLM(obj) return model diff --git a/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts b/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts index 4cb206f5..4f876239 100644 --- a/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts +++ b/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts @@ -2,6 +2,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatGoogleVertexAI, GoogleVertexAIChatInput } from 'langchain/chat_models/googlevertexai' import { GoogleAuthOptions } from 'google-auth-library' +import { BaseCache } from 'langchain/schema' class GoogleVertexAI_ChatModels implements INode { label: string @@ -18,7 +19,7 @@ class GoogleVertexAI_ChatModels implements INode { constructor() { this.label = 'ChatGoogleVertexAI' this.name = 'chatGoogleVertexAI' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatGoogleVertexAI' this.icon = 'vertexai.svg' this.category = 'Chat Models' @@ -34,6 +35,12 @@ class GoogleVertexAI_ChatModels implements INode { 'Google Vertex AI credential. If you are using a GCP service like Cloud Run, or if you have installed default credentials on your local machine, you do not need to set this credential.' } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -113,6 +120,7 @@ class GoogleVertexAI_ChatModels implements INode { const modelName = nodeData.inputs?.modelName as string const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string const topP = nodeData.inputs?.topP as string + const cache = nodeData.inputs?.llmCache as BaseCache const obj: GoogleVertexAIChatInput = { temperature: parseFloat(temperature), @@ -122,6 +130,7 @@ class GoogleVertexAI_ChatModels implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) + if (cache) obj.cache = cache const model = new ChatGoogleVertexAI(obj) return model diff --git a/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts b/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts index ee55c7bb..d9c0d22f 100644 --- a/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts +++ b/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts @@ -1,6 +1,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { HFInput, HuggingFaceInference } from './core' +import { BaseCache } from 'langchain/schema' class ChatHuggingFace_ChatModels implements INode { label: string @@ -17,7 +18,7 @@ class ChatHuggingFace_ChatModels implements INode { constructor() { this.label = 'ChatHuggingFace' this.name = 'chatHuggingFace' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatHuggingFace' this.icon = 'huggingface.png' this.category = 'Chat Models' @@ -30,6 +31,12 @@ class ChatHuggingFace_ChatModels implements INode { credentialNames: ['huggingFaceApi'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model', name: 'model', @@ -102,6 +109,7 @@ class ChatHuggingFace_ChatModels implements INode { const hfTopK = nodeData.inputs?.hfTopK as string const frequencyPenalty = nodeData.inputs?.frequencyPenalty as string const endpoint = nodeData.inputs?.endpoint as string + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData) @@ -119,6 +127,7 @@ class ChatHuggingFace_ChatModels implements INode { if (endpoint) obj.endpoint = endpoint const huggingFace = new HuggingFaceInference(obj) + if (cache) huggingFace.cache = cache return huggingFace } } diff --git a/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts b/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts index a6ddfae4..78fe31dd 100644 --- a/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts +++ b/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts @@ -2,6 +2,8 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses } from '../../../src/utils' import { OpenAIChat } from 'langchain/llms/openai' import { OpenAIChatInput } from 'langchain/chat_models/openai' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class ChatLocalAI_ChatModels implements INode { label: string @@ -17,13 +19,19 @@ class ChatLocalAI_ChatModels implements INode { constructor() { this.label = 'ChatLocalAI' this.name = 'chatLocalAI' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatLocalAI' this.icon = 'localai.png' this.category = 'Chat Models' this.description = 'Use local LLMs like llama.cpp, gpt4all using LocalAI' this.baseClasses = [this.type, 'BaseChatModel', ...getBaseClasses(OpenAIChat)] this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Base Path', name: 'basePath', @@ -78,8 +86,9 @@ class ChatLocalAI_ChatModels implements INode { const topP = nodeData.inputs?.topP as string const timeout = nodeData.inputs?.timeout as string const basePath = nodeData.inputs?.basePath as string + const cache = nodeData.inputs?.llmCache as BaseCache - const obj: Partial & { openAIApiKey?: string } = { + const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), modelName, openAIApiKey: 'sk-' @@ -88,6 +97,7 @@ class ChatLocalAI_ChatModels implements INode { if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) if (topP) obj.topP = parseFloat(topP) if (timeout) obj.timeout = parseInt(timeout, 10) + if (cache) obj.cache = cache const model = new OpenAIChat(obj, { basePath }) diff --git a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts index ca081ff4..a9eae481 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatOpenAI, OpenAIChatInput } from 'langchain/chat_models/openai' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class ChatOpenAI_ChatModels implements INode { label: string @@ -17,7 +19,7 @@ class ChatOpenAI_ChatModels implements INode { constructor() { this.label = 'ChatOpenAI' this.name = 'chatOpenAI' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatOpenAI' this.icon = 'openai.png' this.category = 'Chat Models' @@ -30,6 +32,12 @@ class ChatOpenAI_ChatModels implements INode { credentialNames: ['openAIApi'] } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -151,7 +159,9 @@ class ChatOpenAI_ChatModels implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const obj: Partial & { openAIApiKey?: string } = { + const cache = nodeData.inputs?.llmCache as BaseCache + + const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), modelName, openAIApiKey, @@ -163,6 +173,7 @@ class ChatOpenAI_ChatModels implements INode { if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty) if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) + if (cache) obj.cache = cache let parsedBaseOptions: any | undefined = undefined diff --git a/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts b/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts index 29c1181a..6f8d1310 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts @@ -1,6 +1,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { ChatOpenAI, OpenAIChatInput } from 'langchain/chat_models/openai' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' class ChatOpenAICustom_ChatModels implements INode { label: string @@ -17,7 +19,7 @@ class ChatOpenAICustom_ChatModels implements INode { constructor() { this.label = 'ChatOpenAI Custom' this.name = 'chatOpenAICustom' - this.version = 1.0 + this.version = 2.0 this.type = 'ChatOpenAI-Custom' this.icon = 'openai.png' this.category = 'Chat Models' @@ -31,6 +33,12 @@ class ChatOpenAICustom_ChatModels implements INode { optional: true } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'LLMCache', + optional: true + }, { label: 'Model Name', name: 'modelName', @@ -113,11 +121,12 @@ class ChatOpenAICustom_ChatModels implements INode { const streaming = nodeData.inputs?.streaming as boolean const basePath = nodeData.inputs?.basepath as string const baseOptions = nodeData.inputs?.baseOptions + const cache = nodeData.inputs?.llmCache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const obj: Partial & { openAIApiKey?: string } = { + const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), modelName, openAIApiKey, @@ -129,6 +138,7 @@ class ChatOpenAICustom_ChatModels implements INode { if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty) if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) + if (cache) obj.cache = cache let parsedBaseOptions: any | undefined = undefined From e01acbc3e8f1bf866e168890066c9183afefaf25 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sun, 8 Oct 2023 15:53:06 +0530 Subject: [PATCH 22/76] Renaming of Category, Class Names and File names from LLMCache to Cache as this functionality is applicable to both LLM and Chat Models. --- .../InMemoryCache/InMemoryCache.ts} | 12 ++++++------ .../InMemoryCache}/memorycache.png | Bin .../MomentoCache/MomentoCache.ts} | 12 ++++++------ .../MomentoCache}/momento.png | Bin .../RedisCache/RedisCache.ts} | 12 ++++++------ .../LLMRedisCache => cache/RedisCache}/redis.svg | 0 .../UpstashRedisCache/UpstashRedisCache.ts} | 12 ++++++------ .../UpstashRedisCache}/upstash.png | Bin 8 files changed, 24 insertions(+), 24 deletions(-) rename packages/components/nodes/{llmcache/LLMInMemoryCache/LLMInMemoryCache.ts => cache/InMemoryCache/InMemoryCache.ts} (71%) rename packages/components/nodes/{llmcache/LLMInMemoryCache => cache/InMemoryCache}/memorycache.png (100%) rename packages/components/nodes/{llmcache/LLMMomentoCache/LLMMomentoCache.ts => cache/MomentoCache/MomentoCache.ts} (86%) rename packages/components/nodes/{llmcache/LLMMomentoCache => cache/MomentoCache}/momento.png (100%) rename packages/components/nodes/{llmcache/LLMRedisCache/LLMRedisCache.ts => cache/RedisCache/RedisCache.ts} (85%) rename packages/components/nodes/{llmcache/LLMRedisCache => cache/RedisCache}/redis.svg (100%) rename packages/components/nodes/{llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts => cache/UpstashRedisCache/UpstashRedisCache.ts} (82%) rename packages/components/nodes/{llmcache/LLMUpstashRedisCache => cache/UpstashRedisCache}/upstash.png (100%) diff --git a/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts similarity index 71% rename from packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts rename to packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts index 44133486..8bed721f 100644 --- a/packages/components/nodes/llmcache/LLMInMemoryCache/LLMInMemoryCache.ts +++ b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts @@ -1,8 +1,8 @@ import { INode, INodeParams } from '../../../src/Interface' -import { InMemoryCache } from 'langchain/cache' +import { InMemoryCache as LangchainInMemoryCache } from 'langchain/cache' import { getBaseClasses } from '../../../src' -class LLMInMemoryCache implements INode { +class InMemoryCache implements INode { label: string name: string version: number @@ -18,19 +18,19 @@ class LLMInMemoryCache implements INode { this.label = 'Local (Builtin) Cache' this.name = 'localCache' this.version = 1.0 - this.type = 'LLMCache' + this.type = 'Cache' this.icon = 'memorycache.png' - this.category = 'LLM Cache' + this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(InMemoryCache)] this.inputs = [] } async init(): Promise { if (!this.inMemoryCache) { - this.inMemoryCache = InMemoryCache.global() + this.inMemoryCache = LangchainInMemoryCache.global() } return this.inMemoryCache } } -module.exports = { nodeClass: LLMInMemoryCache } +module.exports = { nodeClass: InMemoryCache } diff --git a/packages/components/nodes/llmcache/LLMInMemoryCache/memorycache.png b/packages/components/nodes/cache/InMemoryCache/memorycache.png similarity index 100% rename from packages/components/nodes/llmcache/LLMInMemoryCache/memorycache.png rename to packages/components/nodes/cache/InMemoryCache/memorycache.png diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts similarity index 86% rename from packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts rename to packages/components/nodes/cache/MomentoCache/MomentoCache.ts index f8fd61fb..37d90941 100644 --- a/packages/components/nodes/llmcache/LLMMomentoCache/LLMMomentoCache.ts +++ b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts @@ -1,8 +1,8 @@ import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' -import { MomentoCache } from 'langchain/cache/momento' +import { MomentoCache as LangchainMomentoCache } from 'langchain/cache/momento' import { CacheClient, Configurations, CredentialProvider } from '@gomomento/sdk' -class LLMMomentoCache implements INode { +class MomentoCache implements INode { label: string name: string version: number @@ -18,9 +18,9 @@ class LLMMomentoCache implements INode { this.label = 'Momento Cache' this.name = 'momentoCache' this.version = 1.0 - this.type = 'LLMCache' + this.type = 'Cache' this.icon = 'momento.png' - this.category = 'LLM Cache' + this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(MomentoCache)] this.credential = { label: 'Connect Credential', @@ -47,7 +47,7 @@ class LLMMomentoCache implements INode { defaultTtlSeconds: 60 * 60 * 24 }) - let momentoCache = await MomentoCache.fromProps({ + let momentoCache = await LangchainMomentoCache.fromProps({ client, cacheName: cacheName }) @@ -55,4 +55,4 @@ class LLMMomentoCache implements INode { } } -module.exports = { nodeClass: LLMMomentoCache } +module.exports = { nodeClass: MomentoCache } diff --git a/packages/components/nodes/llmcache/LLMMomentoCache/momento.png b/packages/components/nodes/cache/MomentoCache/momento.png similarity index 100% rename from packages/components/nodes/llmcache/LLMMomentoCache/momento.png rename to packages/components/nodes/cache/MomentoCache/momento.png diff --git a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts similarity index 85% rename from packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts rename to packages/components/nodes/cache/RedisCache/RedisCache.ts index a7208977..d0143d76 100644 --- a/packages/components/nodes/llmcache/LLMRedisCache/LLMRedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -1,8 +1,8 @@ import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' -import { RedisCache } from 'langchain/cache/ioredis' +import { RedisCache as LangchainRedisCache } from 'langchain/cache/ioredis' import { Redis } from 'ioredis' -class LLMRedisCache implements INode { +class RedisCache implements INode { label: string name: string version: number @@ -18,9 +18,9 @@ class LLMRedisCache implements INode { this.label = 'Redis LLM Cache' this.name = 'redisCache' this.version = 1.0 - this.type = 'LLMCache' + this.type = 'Cache' this.icon = 'redis.svg' - this.category = 'LLM Cache' + this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(RedisCache)] this.credential = { label: 'Connect Credential', @@ -45,8 +45,8 @@ class LLMRedisCache implements INode { username, password }) - return new RedisCache(client) + return new LangchainRedisCache(client) } } -module.exports = { nodeClass: LLMRedisCache } +module.exports = { nodeClass: RedisCache } diff --git a/packages/components/nodes/llmcache/LLMRedisCache/redis.svg b/packages/components/nodes/cache/RedisCache/redis.svg similarity index 100% rename from packages/components/nodes/llmcache/LLMRedisCache/redis.svg rename to packages/components/nodes/cache/RedisCache/redis.svg diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts similarity index 82% rename from packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts rename to packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts index 8914b2a1..a9322b1e 100644 --- a/packages/components/nodes/llmcache/LLMUpstashRedisCache/LLMUpstashRedisCache.ts +++ b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts @@ -1,7 +1,7 @@ import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' -import { UpstashRedisCache } from 'langchain/cache/upstash_redis' +import { UpstashRedisCache as LangchainUpstashRedisCache } from 'langchain/cache/upstash_redis' -class LLMUpstashRedisCache implements INode { +class UpstashRedisCache implements INode { label: string name: string version: number @@ -17,9 +17,9 @@ class LLMUpstashRedisCache implements INode { this.label = 'Upstash Redis LLM Cache' this.name = 'upstashRedisCache' this.version = 1.0 - this.type = 'LLMCache' + this.type = 'Cache' this.icon = 'upstash.png' - this.category = 'LLM Cache' + this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(UpstashRedisCache)] this.credential = { label: 'Connect Credential', @@ -36,7 +36,7 @@ class LLMUpstashRedisCache implements INode { const upstashConnectionUrl = getCredentialParam('upstashConnectionUrl', credentialData, nodeData) const upstashToken = getCredentialParam('upstashConnectionToken', credentialData, nodeData) - const cache = new UpstashRedisCache({ + const cache = new LangchainUpstashRedisCache({ config: { url: upstashConnectionUrl, token: upstashToken @@ -46,4 +46,4 @@ class LLMUpstashRedisCache implements INode { } } -module.exports = { nodeClass: LLMUpstashRedisCache } +module.exports = { nodeClass: UpstashRedisCache } diff --git a/packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png b/packages/components/nodes/cache/UpstashRedisCache/upstash.png similarity index 100% rename from packages/components/nodes/llmcache/LLMUpstashRedisCache/upstash.png rename to packages/components/nodes/cache/UpstashRedisCache/upstash.png From a7574913422c518da259a35d39a85bb623871ae5 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 11:58:37 +0100 Subject: [PATCH 23/76] Update MomentoCache.ts Base Class --- packages/components/nodes/cache/MomentoCache/MomentoCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts index 37d90941..722f7340 100644 --- a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts +++ b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts @@ -21,7 +21,7 @@ class MomentoCache implements INode { this.type = 'Cache' this.icon = 'momento.png' this.category = 'Cache' - this.baseClasses = [this.type, ...getBaseClasses(MomentoCache)] + this.baseClasses = [this.type, ...getBaseClasses(LangchainMomentoCache)] this.credential = { label: 'Connect Credential', name: 'credential', From 132913f50b26524e43c4d1eb6c48619a34920c5a Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 11:58:57 +0100 Subject: [PATCH 24/76] Update RedisCache.ts Base Class --- packages/components/nodes/cache/RedisCache/RedisCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/cache/RedisCache/RedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts index d0143d76..46980acb 100644 --- a/packages/components/nodes/cache/RedisCache/RedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -21,7 +21,7 @@ class RedisCache implements INode { this.type = 'Cache' this.icon = 'redis.svg' this.category = 'Cache' - this.baseClasses = [this.type, ...getBaseClasses(RedisCache)] + this.baseClasses = [this.type, ...getBaseClasses(LangchainRedisCache)] this.credential = { label: 'Connect Credential', name: 'credential', From 40b06cd43af8baf6aaf9f0b57393810245debb01 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 11:59:14 +0100 Subject: [PATCH 25/76] Update UpstashRedisCache.ts Base Class --- .../nodes/cache/UpstashRedisCache/UpstashRedisCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts index a9322b1e..b4ba71a5 100644 --- a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts +++ b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts @@ -20,7 +20,7 @@ class UpstashRedisCache implements INode { this.type = 'Cache' this.icon = 'upstash.png' this.category = 'Cache' - this.baseClasses = [this.type, ...getBaseClasses(UpstashRedisCache)] + this.baseClasses = [this.type, ...getBaseClasses(LangchainUpstashRedisCache)] this.credential = { label: 'Connect Credential', name: 'credential', From 77899b956ec16f7b1b5a1771384f182673013bb9 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 12:00:44 +0100 Subject: [PATCH 26/76] Update index.ts --- packages/server/src/utils/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 98802cde..664f110b 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -477,7 +477,7 @@ export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig: */ export const isStartNodeDependOnInput = (startingNodes: IReactFlowNode[], nodes: IReactFlowNode[]): boolean => { for (const node of startingNodes) { - if (node.data.category === 'LLM Cache') return true + if (node.data.category === 'Cache') return true for (const inputName in node.data.inputs) { const inputVariables = getInputVariables(node.data.inputs[inputName]) if (inputVariables.length > 0) return true From 643adb59792bb37b4716b3ce5e8922b72ebac8d9 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 12:08:23 +0100 Subject: [PATCH 27/76] Update MomentoCache.ts type --- packages/components/nodes/cache/MomentoCache/MomentoCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts index 722f7340..70ac9da7 100644 --- a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts +++ b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts @@ -18,7 +18,7 @@ class MomentoCache implements INode { this.label = 'Momento Cache' this.name = 'momentoCache' this.version = 1.0 - this.type = 'Cache' + this.type = 'MomentoCache' this.icon = 'momento.png' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(LangchainMomentoCache)] From abce51353b302ef6c3138741aaa6eb73bf9388a0 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 12:08:51 +0100 Subject: [PATCH 28/76] Update RedisCache.ts type --- packages/components/nodes/cache/RedisCache/RedisCache.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/cache/RedisCache/RedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts index 46980acb..c1b08be6 100644 --- a/packages/components/nodes/cache/RedisCache/RedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -15,10 +15,10 @@ class RedisCache implements INode { credential: INodeParams constructor() { - this.label = 'Redis LLM Cache' + this.label = 'Redis Cache' this.name = 'redisCache' this.version = 1.0 - this.type = 'Cache' + this.type = 'RedisCache' this.icon = 'redis.svg' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(LangchainRedisCache)] From 12159f6730711ab0b0690c72787305e30d823c85 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sun, 8 Oct 2023 12:09:16 +0100 Subject: [PATCH 29/76] Update UpstashRedisCache.ts type --- .../nodes/cache/UpstashRedisCache/UpstashRedisCache.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts index b4ba71a5..eb5a9e2f 100644 --- a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts +++ b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts @@ -14,10 +14,10 @@ class UpstashRedisCache implements INode { credential: INodeParams constructor() { - this.label = 'Upstash Redis LLM Cache' + this.label = 'Upstash Redis Cache' this.name = 'upstashRedisCache' this.version = 1.0 - this.type = 'Cache' + this.type = 'UpstashRedisCache' this.icon = 'upstash.png' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(LangchainUpstashRedisCache)] From 7d4337724d6ab323a09fb96451989b115b2638b3 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sun, 8 Oct 2023 22:59:43 +0530 Subject: [PATCH 30/76] Updating of Type LLMCache to BaseCache and renaming vars for clarity --- .../nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts | 4 ++-- .../chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts | 4 ++-- .../nodes/chatmodels/Bittensor/Bittensor.ts | 4 ++-- .../nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts | 4 ++-- .../chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts | 4 ++-- .../ChatGoogleVertexAI/ChatGoogleVertexAI.ts | 4 ++-- .../chatmodels/ChatHuggingFace/ChatHuggingFace.ts | 4 ++-- .../nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts | 4 ++-- .../nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts | 4 ++-- .../chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts | 4 ++-- .../components/nodes/llms/AWSBedrock/AWSBedrock.ts | 13 +++++++++++-- .../nodes/llms/Azure OpenAI/AzureOpenAI.ts | 8 ++++---- .../components/nodes/llms/Bittensor/Bittensor.ts | 8 ++++---- packages/components/nodes/llms/Cohere/Cohere.ts | 8 ++++---- .../components/nodes/llms/GooglePaLM/GooglePaLM.ts | 8 ++++---- .../nodes/llms/GoogleVertexAI/GoogleVertexAI.ts | 8 ++++---- .../HuggingFaceInference/HuggingFaceInference.ts | 8 ++++---- packages/components/nodes/llms/OpenAI/OpenAI.ts | 8 ++++---- .../components/nodes/llms/Replicate/Replicate.ts | 8 ++++---- 19 files changed, 63 insertions(+), 54 deletions(-) diff --git a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts index ba4bdd8a..16fbc8dc 100644 --- a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts +++ b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts @@ -44,7 +44,7 @@ class AWSChatBedrock_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -138,7 +138,7 @@ class AWSChatBedrock_ChatModels implements INode { const iModel = nodeData.inputs?.model as string const iTemperature = nodeData.inputs?.temperature as string const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: BaseBedrockInput & BaseLLMParams = { region: iRegion, diff --git a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts index 5acf4dce..99e151e6 100644 --- a/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/AzureChatOpenAI/AzureChatOpenAI.ts @@ -36,7 +36,7 @@ class AzureChatOpenAI_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -115,7 +115,7 @@ class AzureChatOpenAI_ChatModels implements INode { const presencePenalty = nodeData.inputs?.presencePenalty as string const timeout = nodeData.inputs?.timeout as string const streaming = nodeData.inputs?.streaming as boolean - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const azureOpenAIApiKey = getCredentialParam('azureOpenAIApiKey', credentialData, nodeData) diff --git a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts index 89c37157..36b084e6 100644 --- a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts +++ b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts @@ -27,7 +27,7 @@ class Bittensor_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -42,7 +42,7 @@ class Bittensor_ChatModels implements INode { async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial = { systemPrompt: system_prompt diff --git a/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts b/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts index 039b437b..f16968b6 100644 --- a/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts +++ b/packages/components/nodes/chatmodels/ChatAnthropic/ChatAnthropic.ts @@ -35,7 +35,7 @@ class ChatAnthropic_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -143,7 +143,7 @@ class ChatAnthropic_ChatModels implements INode { const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string const streaming = nodeData.inputs?.streaming as boolean - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const anthropicApiKey = getCredentialParam('anthropicApiKey', credentialData, nodeData) diff --git a/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts b/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts index 8ee3fbb8..121406c7 100644 --- a/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts +++ b/packages/components/nodes/chatmodels/ChatGooglePaLM/ChatGooglePaLM.ts @@ -34,7 +34,7 @@ class ChatGooglePaLM_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -103,7 +103,7 @@ class ChatGooglePaLM_ChatModels implements INode { const temperature = nodeData.inputs?.temperature as string const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData) diff --git a/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts b/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts index 4f876239..6b070bd9 100644 --- a/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts +++ b/packages/components/nodes/chatmodels/ChatGoogleVertexAI/ChatGoogleVertexAI.ts @@ -38,7 +38,7 @@ class GoogleVertexAI_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -120,7 +120,7 @@ class GoogleVertexAI_ChatModels implements INode { const modelName = nodeData.inputs?.modelName as string const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string const topP = nodeData.inputs?.topP as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: GoogleVertexAIChatInput = { temperature: parseFloat(temperature), diff --git a/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts b/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts index d9c0d22f..153c5d10 100644 --- a/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts +++ b/packages/components/nodes/chatmodels/ChatHuggingFace/ChatHuggingFace.ts @@ -34,7 +34,7 @@ class ChatHuggingFace_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -109,7 +109,7 @@ class ChatHuggingFace_ChatModels implements INode { const hfTopK = nodeData.inputs?.hfTopK as string const frequencyPenalty = nodeData.inputs?.frequencyPenalty as string const endpoint = nodeData.inputs?.endpoint as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData) diff --git a/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts b/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts index 78fe31dd..18ed409b 100644 --- a/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts +++ b/packages/components/nodes/chatmodels/ChatLocalAI/ChatLocalAI.ts @@ -29,7 +29,7 @@ class ChatLocalAI_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -86,7 +86,7 @@ class ChatLocalAI_ChatModels implements INode { const topP = nodeData.inputs?.topP as string const timeout = nodeData.inputs?.timeout as string const basePath = nodeData.inputs?.basePath as string - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), diff --git a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts index a9eae481..f74bd642 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts @@ -35,7 +35,7 @@ class ChatOpenAI_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -159,7 +159,7 @@ class ChatOpenAI_ChatModels implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), diff --git a/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts b/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts index 6f8d1310..2a01a2e5 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAICustom/ChatOpenAICustom.ts @@ -36,7 +36,7 @@ class ChatOpenAICustom_ChatModels implements INode { { label: 'Cache', name: 'cache', - type: 'LLMCache', + type: 'BaseCache', optional: true }, { @@ -121,7 +121,7 @@ class ChatOpenAICustom_ChatModels implements INode { const streaming = nodeData.inputs?.streaming as boolean const basePath = nodeData.inputs?.basepath as string const baseOptions = nodeData.inputs?.baseOptions - const cache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) diff --git a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts index 68ee7ed2..8f57daac 100644 --- a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts +++ b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts @@ -2,6 +2,8 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { Bedrock } from 'langchain/llms/bedrock' import { BaseBedrockInput } from 'langchain/dist/util/bedrock' +import { BaseCache } from 'langchain/schema' +import { BaseLLMParams } from 'langchain/llms/base' /** * I had to run the following to build the component @@ -39,6 +41,12 @@ class AWSBedrock_LLMs implements INode { optional: true } this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'BaseCache', + optional: true + }, { label: 'Region', name: 'region', @@ -130,8 +138,8 @@ class AWSBedrock_LLMs implements INode { const iModel = nodeData.inputs?.model as string const iTemperature = nodeData.inputs?.temperature as string const iMax_tokens_to_sample = nodeData.inputs?.max_tokens_to_sample as string - - const obj: Partial = { + const cache = nodeData.inputs?.cache as BaseCache + const obj: Partial & BaseLLMParams = { model: iModel, region: iRegion, temperature: parseFloat(iTemperature), @@ -157,6 +165,7 @@ class AWSBedrock_LLMs implements INode { sessionToken: credentialApiSession } } + if (cache) obj.cache = cache const amazonBedrock = new Bedrock(obj) return amazonBedrock diff --git a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts index e5cca769..f50e3d95 100644 --- a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts +++ b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts @@ -33,8 +33,8 @@ class AzureOpenAI_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -170,7 +170,7 @@ class AzureOpenAI_LLMs implements INode { const azureOpenAIApiDeploymentName = getCredentialParam('azureOpenAIApiDeploymentName', credentialData, nodeData) const azureOpenAIApiVersion = getCredentialParam('azureOpenAIApiVersion', credentialData, nodeData) - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams & Partial = { temperature: parseFloat(temperature), @@ -188,7 +188,7 @@ class AzureOpenAI_LLMs implements INode { if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) if (bestOf) obj.bestOf = parseInt(bestOf, 10) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new OpenAI(obj) return model diff --git a/packages/components/nodes/llms/Bittensor/Bittensor.ts b/packages/components/nodes/llms/Bittensor/Bittensor.ts index 84401e59..e6cc2bb6 100644 --- a/packages/components/nodes/llms/Bittensor/Bittensor.ts +++ b/packages/components/nodes/llms/Bittensor/Bittensor.ts @@ -27,8 +27,8 @@ class Bittensor_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -52,13 +52,13 @@ class Bittensor_LLMs implements INode { async init(nodeData: INodeData, _: string): Promise { const system_prompt = nodeData.inputs?.system_prompt as string const topResponses = Number(nodeData.inputs?.topResponses as number) - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams = { systemPrompt: system_prompt, topResponses: topResponses } - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new NIBittensorLLM(obj) return model diff --git a/packages/components/nodes/llms/Cohere/Cohere.ts b/packages/components/nodes/llms/Cohere/Cohere.ts index 8b4c0ac2..3fde0af0 100644 --- a/packages/components/nodes/llms/Cohere/Cohere.ts +++ b/packages/components/nodes/llms/Cohere/Cohere.ts @@ -33,8 +33,8 @@ class Cohere_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -92,7 +92,7 @@ class Cohere_LLMs implements INode { const temperature = nodeData.inputs?.temperature as string const modelName = nodeData.inputs?.modelName as string const maxTokens = nodeData.inputs?.maxTokens as string - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const cohereApiKey = getCredentialParam('cohereApiKey', credentialData, nodeData) @@ -103,7 +103,7 @@ class Cohere_LLMs implements INode { if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10) if (modelName) obj.model = modelName if (temperature) obj.temperature = parseFloat(temperature) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new Cohere(obj) return model } diff --git a/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts b/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts index d916c09f..d3212a1c 100644 --- a/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts +++ b/packages/components/nodes/llms/GooglePaLM/GooglePaLM.ts @@ -32,8 +32,8 @@ class GooglePaLM_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -132,7 +132,7 @@ class GooglePaLM_LLMs implements INode { const topP = nodeData.inputs?.topP as string const topK = nodeData.inputs?.topK as string const stopSequencesObj = nodeData.inputs?.stopSequencesObj - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const credentialData = await getCredentialData(nodeData.credential ?? '', options) const googleMakerSuiteKey = getCredentialParam('googleMakerSuiteKey', credentialData, nodeData) @@ -146,7 +146,7 @@ class GooglePaLM_LLMs implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) if (topK) obj.topK = parseFloat(topK) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache let parsedStopSequences: any | undefined = undefined if (stopSequencesObj) { diff --git a/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts b/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts index 41b18475..6b6d534b 100644 --- a/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts +++ b/packages/components/nodes/llms/GoogleVertexAI/GoogleVertexAI.ts @@ -37,8 +37,8 @@ class GoogleVertexAI_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -127,7 +127,7 @@ class GoogleVertexAI_LLMs implements INode { const modelName = nodeData.inputs?.modelName as string const maxOutputTokens = nodeData.inputs?.maxOutputTokens as string const topP = nodeData.inputs?.topP as string - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial = { temperature: parseFloat(temperature), @@ -137,7 +137,7 @@ class GoogleVertexAI_LLMs implements INode { if (maxOutputTokens) obj.maxOutputTokens = parseInt(maxOutputTokens, 10) if (topP) obj.topP = parseFloat(topP) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new GoogleVertexAI(obj) return model diff --git a/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts index 9d6226e2..8dcf021b 100644 --- a/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts +++ b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts @@ -33,8 +33,8 @@ class HuggingFaceInference_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -113,7 +113,7 @@ class HuggingFaceInference_LLMs implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData) - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial = { model, @@ -128,7 +128,7 @@ class HuggingFaceInference_LLMs implements INode { if (endpoint) obj.endpoint = endpoint const huggingFace = new HuggingFaceInference(obj) - if (llmCache) huggingFace.cache = llmCache + if (cache) huggingFace.cache = cache return huggingFace } diff --git a/packages/components/nodes/llms/OpenAI/OpenAI.ts b/packages/components/nodes/llms/OpenAI/OpenAI.ts index 607ebeb4..9109dd40 100644 --- a/packages/components/nodes/llms/OpenAI/OpenAI.ts +++ b/packages/components/nodes/llms/OpenAI/OpenAI.ts @@ -34,8 +34,8 @@ class OpenAI_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -157,7 +157,7 @@ class OpenAI_LLMs implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: Partial & BaseLLMParams & { openAIApiKey?: string } = { temperature: parseFloat(temperature), @@ -174,7 +174,7 @@ class OpenAI_LLMs implements INode { if (batchSize) obj.batchSize = parseInt(batchSize, 10) if (bestOf) obj.bestOf = parseInt(bestOf, 10) - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache let parsedBaseOptions: any | undefined = undefined if (baseOptions) { diff --git a/packages/components/nodes/llms/Replicate/Replicate.ts b/packages/components/nodes/llms/Replicate/Replicate.ts index fd1eb6f7..fd5373a1 100644 --- a/packages/components/nodes/llms/Replicate/Replicate.ts +++ b/packages/components/nodes/llms/Replicate/Replicate.ts @@ -34,8 +34,8 @@ class Replicate_LLMs implements INode { this.inputs = [ { label: 'Cache', - name: 'llmCache', - type: 'LLMCache', + name: 'cache', + type: 'BaseCache', optional: true }, { @@ -111,7 +111,7 @@ class Replicate_LLMs implements INode { const name = modelName.split(':')[0].split('/').pop() const org = modelName.split(':')[0].split('/')[0] - const llmCache = nodeData.inputs?.llmCache as BaseCache + const cache = nodeData.inputs?.cache as BaseCache const obj: ReplicateInput & BaseLLMParams = { model: `${org}/${name}:${version}`, @@ -130,7 +130,7 @@ class Replicate_LLMs implements INode { } if (Object.keys(inputs).length) obj.input = inputs - if (llmCache) obj.cache = llmCache + if (cache) obj.cache = cache const model = new Replicate(obj) return model From 644bd09ef2a659687daa6431a52edca8ca693a7b Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sun, 8 Oct 2023 23:03:00 +0530 Subject: [PATCH 31/76] Removing InMemoryCache and code cleanup in MomentoCache --- .../cache/InMemoryCache/InMemoryCache.ts | 36 ------------------ .../nodes/cache/InMemoryCache/memorycache.png | Bin 2717 -> 0 bytes .../nodes/cache/MomentoCache/MomentoCache.ts | 1 - 3 files changed, 37 deletions(-) delete mode 100644 packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts delete mode 100644 packages/components/nodes/cache/InMemoryCache/memorycache.png diff --git a/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts deleted file mode 100644 index 8bed721f..00000000 --- a/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { INode, INodeParams } from '../../../src/Interface' -import { InMemoryCache as LangchainInMemoryCache } from 'langchain/cache' -import { getBaseClasses } from '../../../src' - -class InMemoryCache implements INode { - label: string - name: string - version: number - description: string - type: string - icon: string - category: string - baseClasses: string[] - inputs: INodeParams[] - inMemoryCache: any - - constructor() { - this.label = 'Local (Builtin) Cache' - this.name = 'localCache' - this.version = 1.0 - this.type = 'Cache' - this.icon = 'memorycache.png' - this.category = 'Cache' - this.baseClasses = [this.type, ...getBaseClasses(InMemoryCache)] - this.inputs = [] - } - - async init(): Promise { - if (!this.inMemoryCache) { - this.inMemoryCache = LangchainInMemoryCache.global() - } - return this.inMemoryCache - } -} - -module.exports = { nodeClass: InMemoryCache } diff --git a/packages/components/nodes/cache/InMemoryCache/memorycache.png b/packages/components/nodes/cache/InMemoryCache/memorycache.png deleted file mode 100644 index aaeecd6fb100be3a10b3d1faca046f9fa409f018..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2717 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 XQt;1#;KI))00000NkvXXu0mjfl~Wzs diff --git a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts index 70ac9da7..9aa82e82 100644 --- a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts +++ b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts @@ -36,7 +36,6 @@ class MomentoCache implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const apiKey = getCredentialParam('momentoApiKey', credentialData, nodeData) const cacheName = getCredentialParam('momentoCache', credentialData, nodeData) - const endPoint = getCredentialParam('momentoEndpoint', credentialData, nodeData) // See https://github.com/momentohq/client-sdk-javascript for connection options const client = new CacheClient({ From 303e5653dd403f408dbac04011b49af7ff5fb972 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Mon, 9 Oct 2023 16:44:04 +0100 Subject: [PATCH 32/76] update cacheValue to capture other outputs object --- packages/components/src/handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index a102b473..1ae16050 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -191,7 +191,7 @@ export class CustomChainHandler extends BaseCallbackHandler { Callback Order is "Chain Start -> Chain End" for cached responses. */ if (this.cachedResponse) { - const cachedValue = outputs.text as string + const cachedValue: string = outputs.text ?? outputs.response ?? outputs.output ?? '' //split at whitespace, and keep the whitespace. This is to preserve the original formatting. const result = cachedValue.split(/(\s+)/) result.forEach((token: string, index: number) => { From 719c8c4e55d8f570918c2c0aa2a4c35893591ea1 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Mon, 9 Oct 2023 18:25:36 +0100 Subject: [PATCH 33/76] only emit token when parentId is undefined --- packages/components/src/handler.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index 1ae16050..3b1952d6 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -177,21 +177,17 @@ export class CustomChainHandler extends BaseCallbackHandler { } handleLLMEnd() { - /* send the end event from handleChainEnd */ - // this.socketIO.to(this.socketIOClientId).emit('end') + this.socketIO.to(this.socketIOClientId).emit('end') } - handleChainEnd(outputs: ChainValues): void | Promise { - if (this.returnSourceDocuments) { - this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments) - } + handleChainEnd(outputs: ChainValues, _: string, parentRunId?: string): void | Promise { /* Langchain does not call handleLLMStart, handleLLMEnd, handleLLMNewToken when the chain is cached. Callback Order is "Chain Start -> LLM Start --> LLM Token --> LLM End -> Chain End" for normal responses. Callback Order is "Chain Start -> Chain End" for cached responses. */ - if (this.cachedResponse) { - const cachedValue: string = outputs.text ?? outputs.response ?? outputs.output ?? '' + if (this.cachedResponse && parentRunId === undefined) { + const cachedValue = outputs.text ?? outputs.response ?? outputs.output ?? outputs.output_text //split at whitespace, and keep the whitespace. This is to preserve the original formatting. const result = cachedValue.split(/(\s+)/) result.forEach((token: string, index: number) => { @@ -200,8 +196,15 @@ export class CustomChainHandler extends BaseCallbackHandler { } this.socketIO.to(this.socketIOClientId).emit('token', token) }) + if (this.returnSourceDocuments) { + this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments) + } + this.socketIO.to(this.socketIOClientId).emit('end') + } else { + if (this.returnSourceDocuments) { + this.socketIO.to(this.socketIOClientId).emit('sourceDocuments', outputs?.sourceDocuments) + } } - this.socketIO.to(this.socketIOClientId).emit('end') } } From 41caf2aee75067fae735724dfed84ba8972a6efd Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 9 Oct 2023 19:56:15 +0100 Subject: [PATCH 34/76] add memory fix --- .../agents/ConversationalAgent/ConversationalAgent.ts | 8 ++++++-- .../ConversationalRetrievalAgent.ts | 6 +++++- .../agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts | 8 ++++++-- .../nodes/chains/ConversationChain/ConversationChain.ts | 8 ++++++-- .../ConversationalRetrievalQAChain.ts | 6 +++++- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts index 661ef151..00f825d4 100644 --- a/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts +++ b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts @@ -95,8 +95,12 @@ class ConversationalAgent_Agents implements INode { const callbacks = await additionalCallbacks(nodeData, options) if (options && options.chatHistory) { - memory.chatHistory = mapChatHistory(options) - executor.memory = memory + const chatHistoryClassName = memory.chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + memory.chatHistory = mapChatHistory(options) + executor.memory = memory + } } const result = await executor.call({ input }, [...callbacks]) diff --git a/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts b/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts index 3d70a2d3..4a908d7f 100644 --- a/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts +++ b/packages/components/nodes/agents/ConversationalRetrievalAgent/ConversationalRetrievalAgent.ts @@ -82,7 +82,11 @@ class ConversationalRetrievalAgent_Agents implements INode { if (executor.memory) { ;(executor.memory as any).memoryKey = 'chat_history' ;(executor.memory as any).outputKey = 'output' - ;(executor.memory as any).chatHistory = mapChatHistory(options) + const chatHistoryClassName = (executor.memory as any).chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + ;(executor.memory as any).chatHistory = mapChatHistory(options) + } } const loggerHandler = new ConsoleCallbackHandler(options.logger) diff --git a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts index c1bd32ec..c920c399 100644 --- a/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts +++ b/packages/components/nodes/agents/OpenAIFunctionAgent/OpenAIFunctionAgent.ts @@ -81,8 +81,12 @@ class OpenAIFunctionAgent_Agents implements INode { const memory = nodeData.inputs?.memory as BaseChatMemory if (options && options.chatHistory) { - memory.chatHistory = mapChatHistory(options) - executor.memory = memory + const chatHistoryClassName = memory.chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + memory.chatHistory = mapChatHistory(options) + executor.memory = memory + } } const loggerHandler = new ConsoleCallbackHandler(options.logger) diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index b26603e2..1cd15c9a 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -106,8 +106,12 @@ class ConversationChain_Chains implements INode { const memory = nodeData.inputs?.memory as BufferMemory if (options && options.chatHistory) { - memory.chatHistory = mapChatHistory(options) - chain.memory = memory + const chatHistoryClassName = memory.chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + memory.chatHistory = mapChatHistory(options) + chain.memory = memory + } } const loggerHandler = new ConsoleCallbackHandler(options.logger) diff --git a/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts index 1b4675bd..9a8c1b18 100644 --- a/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts +++ b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts @@ -179,7 +179,11 @@ class ConversationalRetrievalQAChain_Chains implements INode { const obj = { question: input } if (options && options.chatHistory && chain.memory) { - ;(chain.memory as any).chatHistory = mapChatHistory(options) + const chatHistoryClassName = (chain.memory as any).chatHistory.constructor.name + // Only replace when its In-Memory + if (chatHistoryClassName && chatHistoryClassName === 'ChatMessageHistory') { + ;(chain.memory as any).chatHistory = mapChatHistory(options) + } } const loggerHandler = new ConsoleCallbackHandler(options.logger) From 4caa9ba9abf6996b3bc16727df2da08cf56fe5c6 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 10 Oct 2023 00:01:28 +0100 Subject: [PATCH 35/76] update marketplace llm with cache --- .../chatflows/API Agent OpenAI.json | 24 +++++++-- .../marketplaces/chatflows/API Agent.json | 36 ++++++++++--- .../marketplaces/chatflows/Antonym.json | 16 ++++-- .../marketplaces/chatflows/AutoGPT.json | 12 ++++- .../marketplaces/chatflows/BabyAGI.json | 12 ++++- .../marketplaces/chatflows/CSV Agent.json | 12 ++++- .../marketplaces/chatflows/ChatGPTPlugin.json | 12 ++++- .../marketplaces/chatflows/Claude LLM.json | 16 ++++-- .../chatflows/Conversational Agent.json | 12 ++++- .../Conversational Retrieval Agent.json | 12 ++++- .../Conversational Retrieval QA Chain.json | 16 ++++-- .../chatflows/Flowise Docs QnA.json | 12 ++++- .../chatflows/HuggingFace LLM Chain.json | 16 ++++-- .../marketplaces/chatflows/Local QnA.json | 16 ++++-- .../chatflows/Long Term Memory.json | 16 ++++-- .../marketplaces/chatflows/MRKLAgent.json | 12 ++++- .../chatflows/Metadata Filter Load.json | 16 ++++-- .../chatflows/Metadata Filter Upsert.json | 12 ++++- .../chatflows/Multi Prompt Chain.json | 12 ++++- .../chatflows/Multi Retrieval QA Chain.json | 12 ++++- .../chatflows/Multiple VectorDB.json | 52 ++++++++++++++----- .../marketplaces/chatflows/OpenAI Agent.json | 12 ++++- .../Prompt Chaining with VectorStore.json | 32 +++++++++--- .../chatflows/Prompt Chaining.json | 32 +++++++++--- .../marketplaces/chatflows/Replicate LLM.json | 16 ++++-- .../marketplaces/chatflows/SQL DB Chain.json | 12 ++++- .../chatflows/Simple Conversation Chain.json | 16 ++++-- .../chatflows/Simple LLM Chain.json | 16 ++++-- .../marketplaces/chatflows/Translator.json | 16 ++++-- .../chatflows/Vectara LLM Chain Upload.json | 12 ++++- .../marketplaces/chatflows/WebBrowser.json | 32 +++++++++--- .../marketplaces/chatflows/WebPage QnA.json | 12 ++++- .../marketplaces/chatflows/Zapier NLA.json | 12 ++++- 33 files changed, 452 insertions(+), 124 deletions(-) diff --git a/packages/server/marketplaces/chatflows/API Agent OpenAI.json b/packages/server/marketplaces/chatflows/API Agent OpenAI.json index 01e3d8f9..b2ff977b 100644 --- a/packages/server/marketplaces/chatflows/API Agent OpenAI.json +++ b/packages/server/marketplaces/chatflows/API Agent OpenAI.json @@ -89,7 +89,7 @@ "id": "chatOpenAI_1", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -201,7 +201,15 @@ "id": "chatOpenAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -392,7 +400,7 @@ "id": "chatOpenAI_2", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -504,7 +512,15 @@ "id": "chatOpenAI_2-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_2-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/API Agent.json b/packages/server/marketplaces/chatflows/API Agent.json index b9862add..c37aaff2 100644 --- a/packages/server/marketplaces/chatflows/API Agent.json +++ b/packages/server/marketplaces/chatflows/API Agent.json @@ -397,7 +397,7 @@ "id": "chatOpenAI_2", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -509,7 +509,15 @@ "id": "chatOpenAI_2-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_2-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -551,7 +559,7 @@ "id": "chatOpenAI_1", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -663,7 +671,15 @@ "id": "chatOpenAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -705,7 +721,7 @@ "id": "chatOpenAI_3", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -817,7 +833,15 @@ "id": "chatOpenAI_3-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_3-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Antonym.json b/packages/server/marketplaces/chatflows/Antonym.json index 95d3c151..5f8ff7a8 100644 --- a/packages/server/marketplaces/chatflows/Antonym.json +++ b/packages/server/marketplaces/chatflows/Antonym.json @@ -169,14 +169,14 @@ "id": "chatOpenAI_0", "position": { "x": 1226.7977900193628, - "y": 48.01100655894436 + "y": -22.01100655894436 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -288,7 +288,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -313,7 +321,7 @@ "selected": false, "positionAbsolute": { "x": 1226.7977900193628, - "y": 48.01100655894436 + "y": -22.01100655894436 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/AutoGPT.json b/packages/server/marketplaces/chatflows/AutoGPT.json index 53837151..4fb706ab 100644 --- a/packages/server/marketplaces/chatflows/AutoGPT.json +++ b/packages/server/marketplaces/chatflows/AutoGPT.json @@ -252,7 +252,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -364,7 +364,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/BabyAGI.json b/packages/server/marketplaces/chatflows/BabyAGI.json index c2897531..04410b82 100644 --- a/packages/server/marketplaces/chatflows/BabyAGI.json +++ b/packages/server/marketplaces/chatflows/BabyAGI.json @@ -78,7 +78,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -190,7 +190,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/CSV Agent.json b/packages/server/marketplaces/chatflows/CSV Agent.json index 1515fcad..37764a53 100644 --- a/packages/server/marketplaces/chatflows/CSV Agent.json +++ b/packages/server/marketplaces/chatflows/CSV Agent.json @@ -70,7 +70,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -182,7 +182,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/ChatGPTPlugin.json b/packages/server/marketplaces/chatflows/ChatGPTPlugin.json index 471853ba..1f00ff5f 100644 --- a/packages/server/marketplaces/chatflows/ChatGPTPlugin.json +++ b/packages/server/marketplaces/chatflows/ChatGPTPlugin.json @@ -215,7 +215,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -327,7 +327,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Claude LLM.json b/packages/server/marketplaces/chatflows/Claude LLM.json index 243d2600..b7989815 100644 --- a/packages/server/marketplaces/chatflows/Claude LLM.json +++ b/packages/server/marketplaces/chatflows/Claude LLM.json @@ -141,14 +141,14 @@ "id": "chatAnthropic_0", "position": { "x": 800.5525382783799, - "y": -76.7988221837009 + "y": -130.7988221837009 }, "type": "customNode", "data": { "id": "chatAnthropic_0", "label": "ChatAnthropic", "name": "chatAnthropic", - "version": 1, + "version": 2, "type": "ChatAnthropic", "baseClasses": ["ChatAnthropic", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -258,7 +258,15 @@ "id": "chatAnthropic_0-input-topK-number" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatAnthropic_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "claude-2", "temperature": 0.9, @@ -280,7 +288,7 @@ "selected": false, "positionAbsolute": { "x": 800.5525382783799, - "y": -76.7988221837009 + "y": -130.7988221837009 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/Conversational Agent.json b/packages/server/marketplaces/chatflows/Conversational Agent.json index 55475b3e..d18f2ac0 100644 --- a/packages/server/marketplaces/chatflows/Conversational Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Agent.json @@ -157,7 +157,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -269,7 +269,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json index dcf344d1..7c5c38e2 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json @@ -13,7 +13,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -126,7 +126,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-16k", "temperature": "0", diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json index bf27e443..725ca7c9 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json @@ -7,14 +7,14 @@ "id": "chatOpenAI_0", "position": { "x": 1184.1176114500388, - "y": -44.15535835370571 + "y": -74.15535835370571 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -126,7 +126,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", @@ -150,7 +158,7 @@ }, "positionAbsolute": { "x": 1184.1176114500388, - "y": -44.15535835370571 + "y": -74.15535835370571 }, "selected": false, "dragging": false diff --git a/packages/server/marketplaces/chatflows/Flowise Docs QnA.json b/packages/server/marketplaces/chatflows/Flowise Docs QnA.json index f8b274a1..2928d29d 100644 --- a/packages/server/marketplaces/chatflows/Flowise Docs QnA.json +++ b/packages/server/marketplaces/chatflows/Flowise Docs QnA.json @@ -386,7 +386,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -498,7 +498,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json b/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json index 6e159a28..e51e1ee0 100644 --- a/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json +++ b/packages/server/marketplaces/chatflows/HuggingFace LLM Chain.json @@ -148,14 +148,14 @@ "id": "huggingFaceInference_LLMs_0", "position": { "x": 498.8594464193537, - "y": -44.91050256311678 + "y": -94.91050256311678 }, "type": "customNode", "data": { "id": "huggingFaceInference_LLMs_0", "label": "HuggingFace Inference", "name": "huggingFaceInference_LLMs", - "version": 1, + "version": 2, "type": "HuggingFaceInference", "baseClasses": ["HuggingFaceInference", "LLM", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -232,7 +232,15 @@ "id": "huggingFaceInference_LLMs_0-input-frequencyPenalty-number" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "huggingFaceInference_LLMs_0-input-cache-BaseCache" + } + ], "inputs": { "model": "tiiuae/falcon-7b-instruct", "endpoint": "", @@ -256,7 +264,7 @@ "selected": false, "positionAbsolute": { "x": 498.8594464193537, - "y": -44.91050256311678 + "y": -94.91050256311678 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/Local QnA.json b/packages/server/marketplaces/chatflows/Local QnA.json index 9d9f5ec8..21bdf744 100644 --- a/packages/server/marketplaces/chatflows/Local QnA.json +++ b/packages/server/marketplaces/chatflows/Local QnA.json @@ -265,14 +265,14 @@ "id": "chatLocalAI_0", "position": { "x": 1191.9512064167336, - "y": -44.05401001663306 + "y": -94.05401001663306 }, "type": "customNode", "data": { "id": "chatLocalAI_0", "label": "ChatLocalAI", "name": "chatLocalAI", - "version": 1, + "version": 2, "type": "ChatLocalAI", "baseClasses": ["ChatLocalAI", "BaseChatModel", "LLM", "BaseLLM", "BaseLanguageModel", "BaseLangChain"], "category": "Chat Models", @@ -325,7 +325,15 @@ "id": "chatLocalAI_0-input-timeout-number" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatLocalAI_0-input-cache-BaseCache" + } + ], "inputs": { "basePath": "http://localhost:8080/v1", "modelName": "ggml-gpt4all-j.bin", @@ -348,7 +356,7 @@ "selected": false, "positionAbsolute": { "x": 1191.9512064167336, - "y": -44.05401001663306 + "y": -94.05401001663306 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/Long Term Memory.json b/packages/server/marketplaces/chatflows/Long Term Memory.json index 07669f82..6f22c00a 100644 --- a/packages/server/marketplaces/chatflows/Long Term Memory.json +++ b/packages/server/marketplaces/chatflows/Long Term Memory.json @@ -115,14 +115,14 @@ "id": "chatOpenAI_0", "position": { "x": 1554.3875781165111, - "y": -14.792508259787212 + "y": -74.792508259787212 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -234,7 +234,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", @@ -259,7 +267,7 @@ "selected": false, "positionAbsolute": { "x": 1554.3875781165111, - "y": -14.792508259787212 + "y": -74.792508259787212 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/MRKLAgent.json b/packages/server/marketplaces/chatflows/MRKLAgent.json index f851b0ed..697e4919 100644 --- a/packages/server/marketplaces/chatflows/MRKLAgent.json +++ b/packages/server/marketplaces/chatflows/MRKLAgent.json @@ -156,7 +156,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -268,7 +268,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Metadata Filter Load.json b/packages/server/marketplaces/chatflows/Metadata Filter Load.json index b6ca91e3..43438d6b 100644 --- a/packages/server/marketplaces/chatflows/Metadata Filter Load.json +++ b/packages/server/marketplaces/chatflows/Metadata Filter Load.json @@ -113,14 +113,14 @@ "id": "chatOpenAI_0", "position": { "x": 1197.7264239788542, - "y": -16.177600120515933 + "y": -76.177600120515933 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -232,7 +232,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", @@ -257,7 +265,7 @@ "selected": false, "positionAbsolute": { "x": 1197.7264239788542, - "y": -16.177600120515933 + "y": -76.177600120515933 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json b/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json index e70b11f7..525fa1b9 100644 --- a/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json +++ b/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json @@ -436,7 +436,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -548,7 +548,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Multi Prompt Chain.json b/packages/server/marketplaces/chatflows/Multi Prompt Chain.json index cf86df5b..e1063dcf 100644 --- a/packages/server/marketplaces/chatflows/Multi Prompt Chain.json +++ b/packages/server/marketplaces/chatflows/Multi Prompt Chain.json @@ -278,7 +278,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -390,7 +390,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json index f5604bf6..36240e39 100644 --- a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json @@ -679,7 +679,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -791,7 +791,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Multiple VectorDB.json b/packages/server/marketplaces/chatflows/Multiple VectorDB.json index ac4643aa..b4dedfdd 100644 --- a/packages/server/marketplaces/chatflows/Multiple VectorDB.json +++ b/packages/server/marketplaces/chatflows/Multiple VectorDB.json @@ -321,14 +321,14 @@ "id": "openAI_2", "position": { "x": 520.8471510168988, - "y": -1282.1183473852964 + "y": -1362.1183473852964 }, "type": "customNode", "data": { "id": "openAI_2", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -436,7 +436,15 @@ "id": "openAI_2-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_2-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -463,7 +471,7 @@ "selected": false, "positionAbsolute": { "x": 520.8471510168988, - "y": -1282.1183473852964 + "y": -1362.1183473852964 }, "dragging": false }, @@ -557,7 +565,7 @@ "id": "chromaExistingIndex_0", "position": { "x": 509.55198017578016, - "y": -732.42003311752 + "y": -782.42003311752 }, "type": "customNode", "data": { @@ -638,7 +646,7 @@ "selected": false, "positionAbsolute": { "x": 509.55198017578016, - "y": -732.42003311752 + "y": -782.42003311752 }, "dragging": false }, @@ -732,14 +740,14 @@ "id": "openAI_3", "position": { "x": 504.808358369027, - "y": -197.78194663790197 + "y": -257.78194663790197 }, "type": "customNode", "data": { "id": "openAI_3", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -847,7 +855,15 @@ "id": "openAI_3-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_3-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -874,7 +890,7 @@ "selected": false, "positionAbsolute": { "x": 504.808358369027, - "y": -197.78194663790197 + "y": -257.78194663790197 }, "dragging": false }, @@ -993,14 +1009,14 @@ "id": "openAI_4", "position": { "x": 1619.5346765785587, - "y": 292.29615581180684 + "y": 352.29615581180684 }, "type": "customNode", "data": { "id": "openAI_4", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -1108,7 +1124,15 @@ "id": "openAI_4-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_4-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -1135,7 +1159,7 @@ "selected": false, "positionAbsolute": { "x": 1619.5346765785587, - "y": 292.29615581180684 + "y": 352.29615581180684 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/OpenAI Agent.json b/packages/server/marketplaces/chatflows/OpenAI Agent.json index 91d5d38c..9a98d29d 100644 --- a/packages/server/marketplaces/chatflows/OpenAI Agent.json +++ b/packages/server/marketplaces/chatflows/OpenAI Agent.json @@ -281,7 +281,7 @@ "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -393,7 +393,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, diff --git a/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json index 9d6838eb..2af61190 100644 --- a/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json +++ b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json @@ -260,13 +260,13 @@ "id": "chatOpenAI_0", "position": { "x": 335.7621848973805, - "y": -651.7411273245009 + "y": -721.7411273245009 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -385,7 +385,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-16k", "temperature": 0.9, @@ -411,7 +419,7 @@ "dragging": false, "positionAbsolute": { "x": 335.7621848973805, - "y": -651.7411273245009 + "y": -721.7411273245009 } }, { @@ -420,13 +428,13 @@ "id": "chatOpenAI_1", "position": { "x": 1765.2801848172305, - "y": -667.9261054149061 + "y": -737.9261054149061 }, "type": "customNode", "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -545,7 +553,15 @@ "id": "chatOpenAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-16k", "temperature": 0.9, @@ -571,7 +587,7 @@ "dragging": false, "positionAbsolute": { "x": 1765.2801848172305, - "y": -667.9261054149061 + "y": -737.9261054149061 } }, { diff --git a/packages/server/marketplaces/chatflows/Prompt Chaining.json b/packages/server/marketplaces/chatflows/Prompt Chaining.json index 5bce9905..77c238ad 100644 --- a/packages/server/marketplaces/chatflows/Prompt Chaining.json +++ b/packages/server/marketplaces/chatflows/Prompt Chaining.json @@ -289,14 +289,14 @@ "id": "openAI_1", "position": { "x": 791.6102007244282, - "y": -13.71386876566092 + "y": -83.71386876566092 }, "type": "customNode", "data": { "id": "openAI_1", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -404,7 +404,15 @@ "id": "openAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -431,7 +439,7 @@ "selected": false, "positionAbsolute": { "x": 791.6102007244282, - "y": -13.71386876566092 + "y": -83.71386876566092 }, "dragging": false }, @@ -441,14 +449,14 @@ "id": "openAI_2", "position": { "x": 1571.148617508543, - "y": -20.372437481171687 + "y": -90.372437481171687 }, "type": "customNode", "data": { "id": "openAI_2", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -556,7 +564,15 @@ "id": "openAI_2-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_2-input-cache-BaseCache" + } + ], "default": "gpt-3.5-turbo-instruct", "inputs": { "modelName": "gpt-3.5-turbo-instruct", @@ -584,7 +600,7 @@ "selected": false, "positionAbsolute": { "x": 1571.148617508543, - "y": -20.372437481171687 + "y": -90.372437481171687 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/Replicate LLM.json b/packages/server/marketplaces/chatflows/Replicate LLM.json index c5a0ac8f..0049214c 100644 --- a/packages/server/marketplaces/chatflows/Replicate LLM.json +++ b/packages/server/marketplaces/chatflows/Replicate LLM.json @@ -148,13 +148,13 @@ "id": "replicate_0", "position": { "x": 623.313978186024, - "y": -72.92788335022428 + "y": -142.92788335022428 }, "type": "customNode", "data": { "id": "replicate_0", "label": "Replicate", - "version": 1, + "version": 2, "name": "replicate", "type": "Replicate", "baseClasses": ["Replicate", "BaseChatModel", "LLM", "BaseLLM", "BaseLanguageModel", "Runnable"], @@ -226,7 +226,15 @@ "id": "replicate_0-input-additionalInputs-json" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "replicate_0-input-cache-BaseCache" + } + ], "inputs": { "model": "a16z-infra/llama13b-v2-chat:df7690f1994d94e96ad9d568eac121aecf50684a0b0963b25a41cc40061269e5", "temperature": 0.7, @@ -249,7 +257,7 @@ "selected": false, "positionAbsolute": { "x": 623.313978186024, - "y": -72.92788335022428 + "y": -142.92788335022428 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/SQL DB Chain.json b/packages/server/marketplaces/chatflows/SQL DB Chain.json index 646db5d4..3b32efe0 100644 --- a/packages/server/marketplaces/chatflows/SQL DB Chain.json +++ b/packages/server/marketplaces/chatflows/SQL DB Chain.json @@ -13,7 +13,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -126,7 +126,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", diff --git a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json index 2c41a54f..57ff348a 100644 --- a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json +++ b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json @@ -64,14 +64,14 @@ "id": "chatOpenAI_0", "position": { "x": 754.8942497823595, - "y": -70.76607584232393 + "y": -140 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -183,7 +183,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -208,7 +216,7 @@ "selected": false, "positionAbsolute": { "x": 754.8942497823595, - "y": -70.76607584232393 + "y": -140 }, "dragging": false }, diff --git a/packages/server/marketplaces/chatflows/Simple LLM Chain.json b/packages/server/marketplaces/chatflows/Simple LLM Chain.json index 21d5ab68..f3db04ef 100644 --- a/packages/server/marketplaces/chatflows/Simple LLM Chain.json +++ b/packages/server/marketplaces/chatflows/Simple LLM Chain.json @@ -148,14 +148,14 @@ "id": "openAI_0", "position": { "x": 513.3297923232442, - "y": -42.67554802812833 + "y": -112.67554802812833 }, "type": "customNode", "data": { "id": "openAI_0", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -263,7 +263,15 @@ "id": "openAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, @@ -290,7 +298,7 @@ "selected": false, "positionAbsolute": { "x": 513.3297923232442, - "y": -42.67554802812833 + "y": -112.67554802812833 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/Translator.json b/packages/server/marketplaces/chatflows/Translator.json index dc2ee6ba..b552aceb 100644 --- a/packages/server/marketplaces/chatflows/Translator.json +++ b/packages/server/marketplaces/chatflows/Translator.json @@ -157,14 +157,14 @@ "id": "chatOpenAI_0", "position": { "x": 436.97058562345904, - "y": 99.96180150605153 + "y": 29.96180150605153 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -276,7 +276,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0", @@ -301,7 +309,7 @@ "selected": false, "positionAbsolute": { "x": 436.97058562345904, - "y": 99.96180150605153 + "y": 29.96180150605153 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json index 47cfef87..dc1c1e17 100644 --- a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json +++ b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json @@ -124,7 +124,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], @@ -230,7 +230,15 @@ "id": "chatOpenAI_0-input-baseOptions-json" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": "0.5", diff --git a/packages/server/marketplaces/chatflows/WebBrowser.json b/packages/server/marketplaces/chatflows/WebBrowser.json index 95743f9f..b784f9ab 100644 --- a/packages/server/marketplaces/chatflows/WebBrowser.json +++ b/packages/server/marketplaces/chatflows/WebBrowser.json @@ -194,14 +194,14 @@ "id": "chatOpenAI_0", "position": { "x": 734.7477982032904, - "y": -400.9979556765114 + "y": -470.9979556765114 }, "type": "customNode", "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -313,7 +313,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -338,7 +346,7 @@ "selected": false, "positionAbsolute": { "x": 734.7477982032904, - "y": -400.9979556765114 + "y": -470.9979556765114 }, "dragging": false }, @@ -432,14 +440,14 @@ "id": "chatOpenAI_1", "position": { "x": 68.312124033115, - "y": -169.65476709991256 + "y": -239.65476709991256 }, "type": "customNode", "data": { "id": "chatOpenAI_1", "label": "ChatOpenAI", "name": "chatOpenAI", - "version": 1, + "version": 2, "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", @@ -551,7 +559,15 @@ "id": "chatOpenAI_1-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_1-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo", "temperature": 0.9, @@ -576,7 +592,7 @@ "selected": false, "positionAbsolute": { "x": 68.312124033115, - "y": -169.65476709991256 + "y": -239.65476709991256 }, "dragging": false } diff --git a/packages/server/marketplaces/chatflows/WebPage QnA.json b/packages/server/marketplaces/chatflows/WebPage QnA.json index 812f0bd5..66bac37f 100644 --- a/packages/server/marketplaces/chatflows/WebPage QnA.json +++ b/packages/server/marketplaces/chatflows/WebPage QnA.json @@ -13,7 +13,7 @@ "data": { "id": "chatOpenAI_0", "label": "ChatOpenAI", - "version": 1, + "version": 2, "name": "chatOpenAI", "type": "ChatOpenAI", "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], @@ -126,7 +126,15 @@ "id": "chatOpenAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-16k", "temperature": "0.9", diff --git a/packages/server/marketplaces/chatflows/Zapier NLA.json b/packages/server/marketplaces/chatflows/Zapier NLA.json index 182b24ae..49527da2 100644 --- a/packages/server/marketplaces/chatflows/Zapier NLA.json +++ b/packages/server/marketplaces/chatflows/Zapier NLA.json @@ -115,7 +115,7 @@ "id": "openAI_0", "label": "OpenAI", "name": "openAI", - "version": 2, + "version": 3, "type": "OpenAI", "baseClasses": ["OpenAI", "BaseLLM", "BaseLanguageModel"], "category": "LLMs", @@ -223,7 +223,15 @@ "id": "openAI_0-input-basepath-string" } ], - "inputAnchors": [], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "openAI_0-input-cache-BaseCache" + } + ], "inputs": { "modelName": "gpt-3.5-turbo-instruct", "temperature": 0.7, From a9148c23a42df98c2d86ed4bc5ce2a6148ad3448 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar H M Date: Tue, 10 Oct 2023 16:53:47 +0530 Subject: [PATCH 36/76] Update SqlDatabaseChain.ts --- .../SqlDatabaseChain/SqlDatabaseChain.ts | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts index ba9cd7f8..6fc42b45 100644 --- a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts +++ b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts @@ -7,28 +7,10 @@ import { BaseLanguageModel } from 'langchain/base_language' import { PromptTemplate, PromptTemplateInput } from 'langchain/prompts' import { ConsoleCallbackHandler, CustomChainHandler, additionalCallbacks } from '../../../src/handler' import { DataSourceOptions } from 'typeorm/data-source' +import { DEFAULT_SQL_DATABASE_PROMPT } from 'langchain/chains/sql_db' type DatabaseType = 'sqlite' | 'postgres' | 'mssql' | 'mysql' -const defaultPrompt = `Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. Unless the user specifies in his question a specific number of examples he wishes to obtain, always limit your query to at most {top_k} results. You can order the results by a relevant column to return the most interesting examples in the database. - -Never query for all the columns from a specific table, only ask for a the few relevant columns given the question. - -Pay attention to use only the column names that you can see in the schema description. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table. - -Use the following format: - -Question: "Question here" -SQLQuery: "SQL Query to run" -SQLResult: "Result of the SQLQuery" -Answer: "Final answer here" - -Only use the tables listed below. - -{table_info} - -Question: {input}` - class SqlDatabaseChain_Chains implements INode { label: string name: string @@ -131,7 +113,7 @@ class SqlDatabaseChain_Chains implements INode { warning: 'Prompt must include 3 input variables: {input}, {dialect}, {table_info}. You can refer to official guide from description above', rows: 4, - placeholder: defaultPrompt, + placeholder: DEFAULT_SQL_DATABASE_PROMPT.template + DEFAULT_SQL_DATABASE_PROMPT.templateFormat, additionalParams: true, optional: true } From ff3b862c9f247674942f5592f28f09bd8bd87711 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar H M Date: Tue, 10 Oct 2023 19:18:24 +0530 Subject: [PATCH 37/76] Update SqlDatabaseChain.ts --- .../nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts index 6fc42b45..ac33fa0e 100644 --- a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts +++ b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts @@ -1,5 +1,5 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' -import { SqlDatabaseChain, SqlDatabaseChainInput } from 'langchain/chains/sql_db' +import { SqlDatabaseChain, SqlDatabaseChainInput, DEFAULT_SQL_DATABASE_PROMPT } from 'langchain/chains/sql_db' import { getBaseClasses, getInputVariables } from '../../../src/utils' import { DataSource } from 'typeorm' import { SqlDatabase } from 'langchain/sql_db' @@ -7,7 +7,6 @@ import { BaseLanguageModel } from 'langchain/base_language' import { PromptTemplate, PromptTemplateInput } from 'langchain/prompts' import { ConsoleCallbackHandler, CustomChainHandler, additionalCallbacks } from '../../../src/handler' import { DataSourceOptions } from 'typeorm/data-source' -import { DEFAULT_SQL_DATABASE_PROMPT } from 'langchain/chains/sql_db' type DatabaseType = 'sqlite' | 'postgres' | 'mssql' | 'mysql' From 9af7775d0e0efe2c15f88d78bb2bee2c7838ac47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Stan=C4=9Bk?= Date: Tue, 10 Oct 2023 16:30:46 +0200 Subject: [PATCH 38/76] text output for Text File and Plain Text components --- .../documentloaders/PlainText/PlainText.ts | 32 ++++++++++++++--- .../nodes/documentloaders/Text/Text.ts | 34 ++++++++++++++++--- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/packages/components/nodes/documentloaders/PlainText/PlainText.ts b/packages/components/nodes/documentloaders/PlainText/PlainText.ts index 261f2d98..53953698 100644 --- a/packages/components/nodes/documentloaders/PlainText/PlainText.ts +++ b/packages/components/nodes/documentloaders/PlainText/PlainText.ts @@ -1,6 +1,7 @@ -import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { TextSplitter } from 'langchain/text_splitter' import { Document } from 'langchain/document' +import { handleEscapeCharacters } from '../../../src' class PlainText_DocumentLoaders implements INode { label: string @@ -12,6 +13,7 @@ class PlainText_DocumentLoaders implements INode { category: string baseClasses: string[] inputs: INodeParams[] + outputs: INodeOutputsValue[] constructor() { this.label = 'Plain Text' @@ -45,12 +47,25 @@ class PlainText_DocumentLoaders implements INode { additionalParams: true } ] + this.outputs = [ + { + label: 'Document', + name: 'document', + baseClasses: this.baseClasses + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] } async init(nodeData: INodeData): Promise { const textSplitter = nodeData.inputs?.textSplitter as TextSplitter const text = nodeData.inputs?.text as string const metadata = nodeData.inputs?.metadata + const output = nodeData.outputs?.output as string let alldocs: Document>[] = [] @@ -65,9 +80,9 @@ class PlainText_DocumentLoaders implements INode { ) } + let finaldocs: Document>[] = [] if (metadata) { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) - let finaldocs: Document>[] = [] for (const doc of alldocs) { const newdoc = { ...doc, @@ -78,10 +93,19 @@ class PlainText_DocumentLoaders implements INode { } finaldocs.push(newdoc) } - return finaldocs + } else { + finaldocs = alldocs } - return alldocs + if (output === 'document') { + return finaldocs + } else { + let finaltext = '' + for (const doc of finaldocs) { + finaltext += `${doc.pageContent}\n` + } + return handleEscapeCharacters(finaltext, false) + } } } diff --git a/packages/components/nodes/documentloaders/Text/Text.ts b/packages/components/nodes/documentloaders/Text/Text.ts index dacf087c..01b6ae5d 100644 --- a/packages/components/nodes/documentloaders/Text/Text.ts +++ b/packages/components/nodes/documentloaders/Text/Text.ts @@ -1,6 +1,8 @@ -import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { TextSplitter } from 'langchain/text_splitter' import { TextLoader } from 'langchain/document_loaders/fs/text' +import { Document } from 'langchain/document' +import { handleEscapeCharacters } from '../../../src' class Text_DocumentLoaders implements INode { label: string @@ -12,6 +14,7 @@ class Text_DocumentLoaders implements INode { category: string baseClasses: string[] inputs: INodeParams[] + outputs: INodeOutputsValue[] constructor() { this.label = 'Text File' @@ -43,12 +46,25 @@ class Text_DocumentLoaders implements INode { additionalParams: true } ] + this.outputs = [ + { + label: 'Document', + name: 'document', + baseClasses: this.baseClasses + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] } async init(nodeData: INodeData): Promise { const textSplitter = nodeData.inputs?.textSplitter as TextSplitter const txtFileBase64 = nodeData.inputs?.txtFile as string const metadata = nodeData.inputs?.metadata + const output = nodeData.outputs?.output as string let alldocs = [] let files: string[] = [] @@ -75,9 +91,9 @@ class Text_DocumentLoaders implements INode { } } + let finaldocs: Document>[] = [] if (metadata) { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) - let finaldocs = [] for (const doc of alldocs) { const newdoc = { ...doc, @@ -88,9 +104,19 @@ class Text_DocumentLoaders implements INode { } finaldocs.push(newdoc) } - return finaldocs + } else { + finaldocs = alldocs + } + + if (output === 'document') { + return finaldocs + } else { + let finaltext = '' + for (const doc of finaldocs) { + finaltext += `${doc.pageContent}\n` + } + return handleEscapeCharacters(finaltext, false) } - return alldocs } } From 57760dc633a1700316e7c3fc3427d82e89e19eec Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Tue, 10 Oct 2023 20:03:21 +0530 Subject: [PATCH 39/76] Updates to Elasticsearch VectoreStore Functionality. --- .../ElectricsearchUserPassword.credential.ts | 9 +- .../Elasticsearch/ElasticSearchBase.ts | 193 ++++++++++++++++++ .../Elasticsearch/Elasticsearch_Existing.ts | 112 ++-------- .../Elasticsearch/Elasticsearch_Upsert.ts | 168 +++------------ 4 files changed, 245 insertions(+), 237 deletions(-) create mode 100644 packages/components/nodes/vectorstores/Elasticsearch/ElasticSearchBase.ts diff --git a/packages/components/credentials/ElectricsearchUserPassword.credential.ts b/packages/components/credentials/ElectricsearchUserPassword.credential.ts index 2dd88937..6c47f7b1 100644 --- a/packages/components/credentials/ElectricsearchUserPassword.credential.ts +++ b/packages/components/credentials/ElectricsearchUserPassword.credential.ts @@ -14,14 +14,19 @@ class ElasticSearchUserPassword implements INodeCredential { this.description = 'Refer to official guide on how to get User Password from ElasticSearch' this.inputs = [ + { + label: 'Cloud ID', + name: 'cloudId', + type: 'string' + }, { label: 'ElasticSearch User', - name: 'elasticSearchUser', + name: 'username', type: 'string' }, { label: 'ElasticSearch Password', - name: 'elasticSearchPassword', + name: 'password', type: 'password' } ] diff --git a/packages/components/nodes/vectorstores/Elasticsearch/ElasticSearchBase.ts b/packages/components/nodes/vectorstores/Elasticsearch/ElasticSearchBase.ts new file mode 100644 index 00000000..59294b7e --- /dev/null +++ b/packages/components/nodes/vectorstores/Elasticsearch/ElasticSearchBase.ts @@ -0,0 +1,193 @@ +import { + getBaseClasses, + getCredentialData, + getCredentialParam, + ICommonObject, + INodeData, + INodeOutputsValue, + INodeParams +} from '../../../src' +import { Client, ClientOptions } from '@elastic/elasticsearch' +import { ElasticClientArgs, ElasticVectorSearch } from 'langchain/vectorstores/elasticsearch' +import { Embeddings } from 'langchain/embeddings/base' +import { VectorStore } from 'langchain/vectorstores/base' +import { Document } from 'langchain/document' + +export abstract class ElasticSearchBase { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + outputs: INodeOutputsValue[] + + protected constructor() { + this.type = 'Elasticsearch' + this.icon = 'elasticsearch.png' + this.category = 'Vector Stores' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['elasticsearchApi', 'elasticSearchUserPassword'] + } + this.inputs = [ + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Index Name', + name: 'indexName', + placeholder: '', + type: 'string' + }, + { + label: 'Top K', + name: 'topK', + description: 'Number of top results to fetch. Default to 4', + placeholder: '4', + type: 'number', + additionalParams: true, + optional: true + }, + { + label: 'Similarity', + name: 'similarity', + description: 'Similarity measure used in Elasticsearch.', + type: 'options', + default: 'l2_norm', + options: [ + { + label: 'l2_norm', + name: 'l2_norm' + }, + { + label: 'dot_product', + name: 'dot_product' + }, + { + label: 'cosine', + name: 'cosine' + } + ], + additionalParams: true, + optional: true + } + ] + this.outputs = [ + { + label: 'Elasticsearch Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Elasticsearch Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(ElasticVectorSearch)] + } + ] + } + + abstract constructVectorStore( + embeddings: Embeddings, + elasticSearchClientArgs: ElasticClientArgs, + docs: Document>[] | undefined + ): Promise + + async init(nodeData: INodeData, _: string, options: ICommonObject, docs: Document>[] | undefined): Promise { + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const endPoint = getCredentialParam('endpoint', credentialData, nodeData) + const cloudId = getCredentialParam('cloudId', credentialData, nodeData) + const indexName = nodeData.inputs?.indexName as string + const embeddings = nodeData.inputs?.embeddings as Embeddings + const topK = nodeData.inputs?.topK as string + const similarityMeasure = nodeData.inputs?.similarityMeasure as string + const k = topK ? parseFloat(topK) : 4 + const output = nodeData.outputs?.output as string + + const elasticSearchClientArgs = this.prepareClientArgs(endPoint, cloudId, credentialData, nodeData, similarityMeasure, indexName) + + const vectorStore = await this.constructVectorStore(embeddings, elasticSearchClientArgs, docs) + + if (output === 'retriever') { + return vectorStore.asRetriever(k) + } else if (output === 'vectorStore') { + ;(vectorStore as any).k = k + return vectorStore + } + return vectorStore + } + + protected prepareConnectionOptions( + endPoint: string | undefined, + cloudId: string | undefined, + credentialData: ICommonObject, + nodeData: INodeData + ) { + let elasticSearchClientOptions: ClientOptions = {} + if (endPoint) { + let apiKey = getCredentialParam('apiKey', credentialData, nodeData) + elasticSearchClientOptions = { + node: endPoint, + auth: { + apiKey: apiKey + } + } + } else if (cloudId) { + let username = getCredentialParam('username', credentialData, nodeData) + let password = getCredentialParam('password', credentialData, nodeData) + elasticSearchClientOptions = { + cloud: { + id: cloudId + }, + auth: { + username: username, + password: password + } + } + } + return elasticSearchClientOptions + } + + protected prepareClientArgs( + endPoint: string | undefined, + cloudId: string | undefined, + credentialData: ICommonObject, + nodeData: INodeData, + similarityMeasure: string, + indexName: string + ) { + let elasticSearchClientOptions = this.prepareConnectionOptions(endPoint, cloudId, credentialData, nodeData) + let vectorSearchOptions = {} + switch (similarityMeasure) { + case 'dot_product': + vectorSearchOptions = { + similarity: 'dot_product' + } + break + case 'cosine': + vectorSearchOptions = { + similarity: 'cosine' + } + break + default: + vectorSearchOptions = { + similarity: 'l2_norm' + } + } + const elasticSearchClientArgs: ElasticClientArgs = { + client: new Client(elasticSearchClientOptions), + indexName: indexName, + vectorSearchOptions: vectorSearchOptions + } + return elasticSearchClientArgs + } +} diff --git a/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts index 6e785c85..94e45d74 100644 --- a/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts +++ b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts @@ -1,110 +1,30 @@ -import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { ICommonObject, INode, INodeData } from '../../../src/Interface' import { Embeddings } from 'langchain/embeddings/base' -import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src' -import { Client, ClientOptions } from '@elastic/elasticsearch' import { ElasticClientArgs, ElasticVectorSearch } from 'langchain/vectorstores/elasticsearch' +import { ElasticSearchBase } from './ElasticSearchBase' +import { VectorStore } from 'langchain/vectorstores/base' +import { Document } from 'langchain/document' -class ElasicsearchExisting_VectorStores implements INode { - label: string - name: string - version: number - description: string - type: string - icon: string - category: string - baseClasses: string[] - inputs: INodeParams[] - credential: INodeParams - outputs: INodeOutputsValue[] - +class ElasicsearchExisting_VectorStores extends ElasticSearchBase implements INode { constructor() { + super() this.label = 'Elasticsearch Load Existing Index' this.name = 'ElasticsearchIndex' this.version = 1.0 - this.type = 'Elasticsearch' - this.icon = 'elasticsearch.png' - this.category = 'Vector Stores' - this.description = 'Load existing index from Elasticsearch (i.e: Document has been upserted)' - this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] - this.credential = { - label: 'Connect Credential', - name: 'credential', - type: 'credential', - credentialNames: ['elasticsearchApi', 'elasticSearchUserPassword'] - } - this.inputs = [ - { - label: 'Embeddings', - name: 'embeddings', - type: 'Embeddings' - }, - { - label: 'Index Name', - name: 'indexName', - placeholder: '', - type: 'string' - }, - { - label: 'Top K', - name: 'topK', - description: 'Number of top results to fetch. Default to 4', - placeholder: '4', - type: 'number', - additionalParams: true, - optional: true - } - ] - this.outputs = [ - { - label: 'Elasticsearch Retriever', - name: 'retriever', - baseClasses: this.baseClasses - }, - { - label: 'Elasticsearch Vector Store', - name: 'vectorStore', - baseClasses: [this.type, ...getBaseClasses(ElasticVectorSearch)] - } - ] + this.description = 'Load existing index from Elasticsearch (i.e: Document has been upserted)' + } + + async constructVectorStore( + embeddings: Embeddings, + elasticSearchClientArgs: ElasticClientArgs, + docs: Document>[] | undefined + ): Promise { + return await ElasticVectorSearch.fromExistingIndex(embeddings, elasticSearchClientArgs) } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { - const credentialData = await getCredentialData(nodeData.credential ?? '', options) - const endPoint = getCredentialParam('endpoint', credentialData, nodeData) - const apiKey = getCredentialParam('apiKey', credentialData, nodeData) - const indexName = nodeData.inputs?.indexName as string - const embeddings = nodeData.inputs?.embeddings as Embeddings - const topK = nodeData.inputs?.topK as string - - const k = topK ? parseFloat(topK) : 4 - const output = nodeData.outputs?.output as string - - // eslint-disable-next-line no-console - console.log('EndPoint:: ' + endPoint + ', APIKey:: ' + apiKey + ', Index:: ' + indexName) - - const elasticSearchClientOptions: ClientOptions = { - node: endPoint, - auth: { - apiKey: apiKey - } - } - - const elasticSearchClientArgs: ElasticClientArgs = { - client: new Client(elasticSearchClientOptions), - indexName: indexName - } - - const vectorStore = await ElasticVectorSearch.fromExistingIndex(embeddings, elasticSearchClientArgs) - // eslint-disable-next-line no-console - console.log('vectorStore ::' + vectorStore._vectorstoreType()) - if (output === 'retriever') { - return vectorStore.asRetriever(k) - } else if (output === 'vectorStore') { - ;(vectorStore as any).k = k - return vectorStore - } - return vectorStore + return super.init(nodeData, _, options, undefined) } } diff --git a/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Upsert.ts b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Upsert.ts index 5a0065d5..d4b79a5d 100644 --- a/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Upsert.ts +++ b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Upsert.ts @@ -1,148 +1,39 @@ -import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { ICommonObject, INode, INodeData } from '../../../src/Interface' import { Embeddings } from 'langchain/embeddings/base' import { Document } from 'langchain/document' -import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src' -import { Client, ClientOptions } from '@elastic/elasticsearch' import { ElasticClientArgs, ElasticVectorSearch } from 'langchain/vectorstores/elasticsearch' import { flatten } from 'lodash' +import { ElasticSearchBase } from './ElasticSearchBase' +import { VectorStore } from 'langchain/vectorstores/base' -class ElasicsearchUpsert_VectorStores implements INode { - label: string - name: string - version: number - description: string - type: string - icon: string - category: string - baseClasses: string[] - inputs: INodeParams[] - credential: INodeParams - outputs: INodeOutputsValue[] - +class ElasicsearchUpsert_VectorStores extends ElasticSearchBase implements INode { constructor() { + super() this.label = 'Elasticsearch Upsert Document' this.name = 'ElasticsearchUpsert' this.version = 1.0 - this.type = 'Elasticsearch' - this.icon = 'elasticsearch.png' - this.category = 'Vector Stores' this.description = 'Upsert documents to Elasticsearch' - this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] - this.credential = { - label: 'Connect Credential', - name: 'credential', - type: 'credential', - credentialNames: ['elasticsearchApi', 'elasticSearchUserPassword'] - } - this.inputs = [ - { - label: 'Document', - name: 'document', - type: 'Document', - list: true - }, - { - label: 'Embeddings', - name: 'embeddings', - type: 'Embeddings' - }, - { - label: 'Index Name', - name: 'indexName', - placeholder: '', - type: 'string' - }, - { - label: 'Top K', - name: 'topK', - description: 'Number of top results to fetch. Default to 4', - placeholder: '4', - type: 'number', - additionalParams: true, - optional: true - }, - { - label: 'Similarity', - name: 'similarity', - description: 'Similarity measure used in Elasticsearch.', - type: 'options', - default: 'l2_norm', - options: [ - { - label: 'l2_norm', - name: 'l2_norm' - }, - { - label: 'dot_product', - name: 'dot_product' - }, - { - label: 'cosine', - name: 'cosine' - } - ], - additionalParams: true, - optional: true - } - ] - this.outputs = [ - { - label: 'Elasticsearch Retriever', - name: 'retriever', - baseClasses: this.baseClasses - }, - { - label: 'Elasticsearch Vector Store', - name: 'vectorStore', - baseClasses: [this.type, ...getBaseClasses(ElasticVectorSearch)] - } - ] + this.inputs.unshift({ + label: 'Document', + name: 'document', + type: 'Document', + list: true + }) + } + + async constructVectorStore( + embeddings: Embeddings, + elasticSearchClientArgs: ElasticClientArgs, + docs: Document>[] + ): Promise { + const vectorStore = new ElasticVectorSearch(embeddings, elasticSearchClientArgs) + await vectorStore.addDocuments(docs) + return vectorStore } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { - const credentialData = await getCredentialData(nodeData.credential ?? '', options) - const endPoint = getCredentialParam('endpoint', credentialData, nodeData) - const apiKey = getCredentialParam('apiKey', credentialData, nodeData) const docs = nodeData.inputs?.document as Document[] - const indexName = nodeData.inputs?.indexName as string - const embeddings = nodeData.inputs?.embeddings as Embeddings - const topK = nodeData.inputs?.topK as string - const k = topK ? parseFloat(topK) : 4 - const output = nodeData.outputs?.output as string - const similarityMeasure = nodeData.inputs?.similarityMeasure as string - - // eslint-disable-next-line no-console - console.log('EndPoint:: ' + endPoint + ', APIKey:: ' + apiKey + ', Index:: ' + indexName) - - const elasticSearchClientOptions: ClientOptions = { - node: endPoint, - auth: { - apiKey: apiKey - } - } - let vectorSearchOptions = {} - switch (similarityMeasure) { - case 'dot_product': - vectorSearchOptions = { - similarity: 'dot_product' - } - break - case 'cosine': - vectorSearchOptions = { - similarity: 'cosine' - } - break - default: - vectorSearchOptions = { - similarity: 'l2_norm' - } - } - const elasticSearchClientArgs: ElasticClientArgs = { - client: new Client(elasticSearchClientOptions), - indexName: indexName, - vectorSearchOptions: vectorSearchOptions - } const flattenDocs = docs && docs.length ? flatten(docs) : [] const finalDocs = [] @@ -150,15 +41,14 @@ class ElasicsearchUpsert_VectorStores implements INode { finalDocs.push(new Document(flattenDocs[i])) } - const vectorStore = await ElasticVectorSearch.fromDocuments(finalDocs, embeddings, elasticSearchClientArgs) - - if (output === 'retriever') { - return vectorStore.asRetriever(k) - } else if (output === 'vectorStore') { - ;(vectorStore as any).k = k - return vectorStore - } - return vectorStore + // The following code is a workaround for a bug (Langchain Issue #1589) in the underlying library. + // Store does not support object in metadata and fail silently + finalDocs.forEach((d) => { + delete d.metadata.pdf + delete d.metadata.loc + }) + // end of workaround + return super.init(nodeData, _, options, flattenDocs) } } From 9cbdcff8a89f1879a602277257219e9fb02bf15b Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 10 Oct 2023 16:57:29 +0100 Subject: [PATCH 40/76] =?UTF-8?q?=F0=9F=A5=B3=20flowise-components@1.3.8?= =?UTF-8?q?=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/components/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/package.json b/packages/components/package.json index e3c4380a..cf545ec3 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "flowise-components", - "version": "1.3.7", + "version": "1.3.8", "description": "Flowiseai Components", "main": "dist/src/index", "types": "dist/src/index.d.ts", From bf5d9a01be4c2d8c121a8be6963c1de887ba8743 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 10 Oct 2023 16:58:18 +0100 Subject: [PATCH 41/76] =?UTF-8?q?=F0=9F=A5=B3=20flowise-ui@1.3.5=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index f0101d2c..239cc3ce 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "flowise-ui", - "version": "1.3.4", + "version": "1.3.5", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://flowiseai.com", "author": { From 4a0918519554016ac60503157320d37b6b9894ce Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 10 Oct 2023 16:58:44 +0100 Subject: [PATCH 42/76] =?UTF-8?q?=F0=9F=A5=B3=20flowise@1.3.7=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- packages/server/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 210a95c4..e123cc68 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.3.6", + "version": "1.3.7", "private": true, "homepage": "https://flowiseai.com", "workspaces": [ diff --git a/packages/server/package.json b/packages/server/package.json index 6f17ad61..a5fb994c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.3.6", + "version": "1.3.7", "description": "Flowiseai Server", "main": "dist/index", "types": "dist/index.d.ts", From 4d312cb13b21104b4aabd45333199966e750f520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Stan=C4=9Bk?= Date: Wed, 11 Oct 2023 08:16:50 +0200 Subject: [PATCH 43/76] version --- .../components/nodes/documentloaders/PlainText/PlainText.ts | 2 +- packages/components/nodes/documentloaders/Text/Text.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/documentloaders/PlainText/PlainText.ts b/packages/components/nodes/documentloaders/PlainText/PlainText.ts index 53953698..c2adceeb 100644 --- a/packages/components/nodes/documentloaders/PlainText/PlainText.ts +++ b/packages/components/nodes/documentloaders/PlainText/PlainText.ts @@ -18,7 +18,7 @@ class PlainText_DocumentLoaders implements INode { constructor() { this.label = 'Plain Text' this.name = 'plainText' - this.version = 1.0 + this.version = 2.0 this.type = 'Document' this.icon = 'plaintext.svg' this.category = 'Document Loaders' diff --git a/packages/components/nodes/documentloaders/Text/Text.ts b/packages/components/nodes/documentloaders/Text/Text.ts index 01b6ae5d..c3e3b61e 100644 --- a/packages/components/nodes/documentloaders/Text/Text.ts +++ b/packages/components/nodes/documentloaders/Text/Text.ts @@ -19,7 +19,7 @@ class Text_DocumentLoaders implements INode { constructor() { this.label = 'Text File' this.name = 'textFile' - this.version = 1.0 + this.version = 2.0 this.type = 'Document' this.icon = 'textFile.svg' this.category = 'Document Loaders' From cf9e3499a764233b31dc80b9d7b75a652068d4ab Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 11 Oct 2023 12:24:06 +0100 Subject: [PATCH 44/76] add ollama --- .../nodes/chatmodels/ChatOllama/ChatOllama.ts | 241 ++++++++++++++++++ .../nodes/chatmodels/ChatOllama/ollama.png | Bin 0 -> 7487 bytes .../OllamaEmbedding/OllamaEmbedding.ts | 95 +++++++ .../embeddings/OllamaEmbedding/ollama.png | Bin 0 -> 7487 bytes .../components/nodes/llms/Ollama/Ollama.ts | 241 ++++++++++++++++++ .../components/nodes/llms/Ollama/ollama.png | Bin 0 -> 7487 bytes packages/server/src/utils/index.ts | 4 +- 7 files changed, 579 insertions(+), 2 deletions(-) create mode 100644 packages/components/nodes/chatmodels/ChatOllama/ChatOllama.ts create mode 100644 packages/components/nodes/chatmodels/ChatOllama/ollama.png create mode 100644 packages/components/nodes/embeddings/OllamaEmbedding/OllamaEmbedding.ts create mode 100644 packages/components/nodes/embeddings/OllamaEmbedding/ollama.png create mode 100644 packages/components/nodes/llms/Ollama/Ollama.ts create mode 100644 packages/components/nodes/llms/Ollama/ollama.png diff --git a/packages/components/nodes/chatmodels/ChatOllama/ChatOllama.ts b/packages/components/nodes/chatmodels/ChatOllama/ChatOllama.ts new file mode 100644 index 00000000..31267743 --- /dev/null +++ b/packages/components/nodes/chatmodels/ChatOllama/ChatOllama.ts @@ -0,0 +1,241 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import { ChatOllama } from 'langchain/chat_models/ollama' +import { BaseCache } from 'langchain/schema' +import { OllamaInput } from 'langchain/dist/util/ollama' +import { BaseLLMParams } from 'langchain/llms/base' + +class ChatOllama_ChatModels implements INode { + label: string + name: string + version: number + type: string + icon: string + category: string + description: string + baseClasses: string[] + credential: INodeParams + inputs: INodeParams[] + + constructor() { + this.label = 'ChatOllama' + this.name = 'chatOllama' + this.version = 2.0 + this.type = 'ChatOllama' + this.icon = 'ollama.png' + this.category = 'Chat Models' + this.description = 'Chat completion using open-source LLM on Ollama' + this.baseClasses = [this.type, ...getBaseClasses(ChatOllama)] + this.inputs = [ + { + label: 'Cache', + name: 'cache', + type: 'BaseCache', + optional: true + }, + { + label: 'Base URL', + name: 'baseUrl', + type: 'string', + default: 'http://localhost:11434' + }, + { + label: 'Model Name', + name: 'modelName', + type: 'string', + placeholder: 'llama2' + }, + { + label: 'Temperature', + name: 'temperature', + type: 'number', + description: + 'The temperature of the model. Increasing the temperature will make the model answer more creatively. (Default: 0.8). Refer to docs for more details', + step: 0.1, + default: 0.9, + optional: true + }, + { + label: 'Top P', + name: 'topP', + type: 'number', + description: + 'Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text. (Default: 0.9). Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Top K', + name: 'topK', + type: 'number', + description: + 'Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Mirostat', + name: 'mirostat', + type: 'number', + description: + 'Enable Mirostat sampling for controlling perplexity. (default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Mirostat ETA', + name: 'mirostatEta', + type: 'number', + description: + 'Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive. (Default: 0.1) Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Mirostat TAU', + name: 'mirostatTau', + type: 'number', + description: + 'Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text. (Default: 5.0) Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Context Window Size', + name: 'numCtx', + type: 'number', + description: + 'Sets the size of the context window used to generate the next token. (Default: 2048) Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of GQA groups', + name: 'numGqa', + type: 'number', + description: + 'The number of GQA groups in the transformer layer. Required for some models, for example it is 8 for llama2:70b. Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of GPU', + name: 'numGpu', + type: 'number', + description: + 'The number of layers to send to the GPU(s). On macOS it defaults to 1 to enable metal support, 0 to disable. Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of Thread', + name: 'numThread', + type: 'number', + description: + 'Sets the number of threads to use during computation. By default, Ollama will detect this for optimal performance. It is recommended to set this value to the number of physical CPU cores your system has (as opposed to the logical number of cores). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Repeat Last N', + name: 'repeatLastN', + type: 'number', + description: + 'Sets how far back for the model to look back to prevent repetition. (Default: 64, 0 = disabled, -1 = num_ctx). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Repeat Penalty', + name: 'repeatPenalty', + type: 'number', + description: + 'Sets how strongly to penalize repetitions. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. (Default: 1.1). Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Stop Sequence', + name: 'stop', + type: 'string', + rows: 4, + placeholder: 'AI assistant:', + description: + 'Sets the stop sequences to use. Use comma to seperate different sequences. Refer to docs for more details', + optional: true, + additionalParams: true + }, + { + label: 'Tail Free Sampling', + name: 'tfsZ', + type: 'number', + description: + 'Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (Default: 1). Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + } + ] + } + + async init(nodeData: INodeData): Promise { + const temperature = nodeData.inputs?.temperature as string + const baseUrl = nodeData.inputs?.baseUrl as string + const modelName = nodeData.inputs?.modelName as string + const topP = nodeData.inputs?.topP as string + const topK = nodeData.inputs?.topK as string + const mirostat = nodeData.inputs?.mirostat as string + const mirostatEta = nodeData.inputs?.mirostatEta as string + const mirostatTau = nodeData.inputs?.mirostatTau as string + const numCtx = nodeData.inputs?.numCtx as string + const numGqa = nodeData.inputs?.numGqa as string + const numGpu = nodeData.inputs?.numGpu as string + const numThread = nodeData.inputs?.numThread as string + const repeatLastN = nodeData.inputs?.repeatLastN as string + const repeatPenalty = nodeData.inputs?.repeatPenalty as string + const stop = nodeData.inputs?.stop as string + const tfsZ = nodeData.inputs?.tfsZ as string + + const cache = nodeData.inputs?.cache as BaseCache + + const obj: OllamaInput & BaseLLMParams = { + baseUrl, + temperature: parseFloat(temperature), + model: modelName + } + + if (topP) obj.topP = parseFloat(topP) + if (topK) obj.topK = parseFloat(topK) + if (mirostat) obj.mirostat = parseFloat(mirostat) + if (mirostatEta) obj.mirostatEta = parseFloat(mirostatEta) + if (mirostatTau) obj.mirostatTau = parseFloat(mirostatTau) + if (numCtx) obj.numCtx = parseFloat(numCtx) + if (numGqa) obj.numGqa = parseFloat(numGqa) + if (numGpu) obj.numGpu = parseFloat(numGpu) + if (numThread) obj.numThread = parseFloat(numThread) + if (repeatLastN) obj.repeatLastN = parseFloat(repeatLastN) + if (repeatPenalty) obj.repeatPenalty = parseFloat(repeatPenalty) + if (tfsZ) obj.tfsZ = parseFloat(tfsZ) + if (stop) { + const stopSequences = stop.split(',') + obj.stop = stopSequences + } + if (cache) obj.cache = cache + + const model = new ChatOllama(obj) + return model + } +} + +module.exports = { nodeClass: ChatOllama_ChatModels } diff --git a/packages/components/nodes/chatmodels/ChatOllama/ollama.png b/packages/components/nodes/chatmodels/ChatOllama/ollama.png new file mode 100644 index 0000000000000000000000000000000000000000..8cd2cf1ed8043caf62e8b069330889c0cf0f5a3b GIT binary patch literal 7487 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 for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of Thread', + name: 'numThread', + type: 'number', + description: + 'Sets the number of threads to use during computation. By default, Ollama will detect this for optimal performance. It is recommended to set this value to the number of physical CPU cores your system has (as opposed to the logical number of cores). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Use MMap', + name: 'useMMap', + type: 'boolean', + optional: true, + additionalParams: true + } + ] + } + + async init(nodeData: INodeData): Promise { + const modelName = nodeData.inputs?.modelName as string + const baseUrl = nodeData.inputs?.baseUrl as string + const numThread = nodeData.inputs?.numThread as string + const numGpu = nodeData.inputs?.numGpu as string + const useMMap = nodeData.inputs?.useMMap as boolean + + const obj = { + model: modelName, + baseUrl, + requestOptions: {} + } + + const requestOptions: OllamaInput = {} + if (numThread) requestOptions.numThread = parseFloat(numThread) + if (numGpu) requestOptions.numGpu = parseFloat(numGpu) + if (useMMap !== undefined) requestOptions.useMMap = useMMap + + if (Object.keys(requestOptions).length) obj.requestOptions = requestOptions + + const model = new OllamaEmbeddings(obj) + return model + } +} + +module.exports = { nodeClass: OllamaEmbedding_Embeddings } diff --git a/packages/components/nodes/embeddings/OllamaEmbedding/ollama.png b/packages/components/nodes/embeddings/OllamaEmbedding/ollama.png new file mode 100644 index 0000000000000000000000000000000000000000..8cd2cf1ed8043caf62e8b069330889c0cf0f5a3b GIT binary patch literal 7487 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 for more details', + step: 0.1, + default: 0.9, + optional: true + }, + { + label: 'Top P', + name: 'topP', + type: 'number', + description: + 'Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text. (Default: 0.9). Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Top K', + name: 'topK', + type: 'number', + description: + 'Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Mirostat', + name: 'mirostat', + type: 'number', + description: + 'Enable Mirostat sampling for controlling perplexity. (default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Mirostat ETA', + name: 'mirostatEta', + type: 'number', + description: + 'Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive. (Default: 0.1) Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Mirostat TAU', + name: 'mirostatTau', + type: 'number', + description: + 'Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text. (Default: 5.0) Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Context Window Size', + name: 'numCtx', + type: 'number', + description: + 'Sets the size of the context window used to generate the next token. (Default: 2048) Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of GQA groups', + name: 'numGqa', + type: 'number', + description: + 'The number of GQA groups in the transformer layer. Required for some models, for example it is 8 for llama2:70b. Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of GPU', + name: 'numGpu', + type: 'number', + description: + 'The number of layers to send to the GPU(s). On macOS it defaults to 1 to enable metal support, 0 to disable. Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Number of Thread', + name: 'numThread', + type: 'number', + description: + 'Sets the number of threads to use during computation. By default, Ollama will detect this for optimal performance. It is recommended to set this value to the number of physical CPU cores your system has (as opposed to the logical number of cores). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Repeat Last N', + name: 'repeatLastN', + type: 'number', + description: + 'Sets how far back for the model to look back to prevent repetition. (Default: 64, 0 = disabled, -1 = num_ctx). Refer to docs for more details', + step: 1, + optional: true, + additionalParams: true + }, + { + label: 'Repeat Penalty', + name: 'repeatPenalty', + type: 'number', + description: + 'Sets how strongly to penalize repetitions. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. (Default: 1.1). Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + }, + { + label: 'Stop Sequence', + name: 'stop', + type: 'string', + rows: 4, + placeholder: 'AI assistant:', + description: + 'Sets the stop sequences to use. Use comma to seperate different sequences. Refer to docs for more details', + optional: true, + additionalParams: true + }, + { + label: 'Tail Free Sampling', + name: 'tfsZ', + type: 'number', + description: + 'Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (Default: 1). Refer to docs for more details', + step: 0.1, + optional: true, + additionalParams: true + } + ] + } + + async init(nodeData: INodeData): Promise { + const temperature = nodeData.inputs?.temperature as string + const baseUrl = nodeData.inputs?.baseUrl as string + const modelName = nodeData.inputs?.modelName as string + const topP = nodeData.inputs?.topP as string + const topK = nodeData.inputs?.topK as string + const mirostat = nodeData.inputs?.mirostat as string + const mirostatEta = nodeData.inputs?.mirostatEta as string + const mirostatTau = nodeData.inputs?.mirostatTau as string + const numCtx = nodeData.inputs?.numCtx as string + const numGqa = nodeData.inputs?.numGqa as string + const numGpu = nodeData.inputs?.numGpu as string + const numThread = nodeData.inputs?.numThread as string + const repeatLastN = nodeData.inputs?.repeatLastN as string + const repeatPenalty = nodeData.inputs?.repeatPenalty as string + const stop = nodeData.inputs?.stop as string + const tfsZ = nodeData.inputs?.tfsZ as string + + const cache = nodeData.inputs?.cache as BaseCache + + const obj: OllamaInput & BaseLLMParams = { + baseUrl, + temperature: parseFloat(temperature), + model: modelName + } + + if (topP) obj.topP = parseFloat(topP) + if (topK) obj.topK = parseFloat(topK) + if (mirostat) obj.mirostat = parseFloat(mirostat) + if (mirostatEta) obj.mirostatEta = parseFloat(mirostatEta) + if (mirostatTau) obj.mirostatTau = parseFloat(mirostatTau) + if (numCtx) obj.numCtx = parseFloat(numCtx) + if (numGqa) obj.numGqa = parseFloat(numGqa) + if (numGpu) obj.numGpu = parseFloat(numGpu) + if (numThread) obj.numThread = parseFloat(numThread) + if (repeatLastN) obj.repeatLastN = parseFloat(repeatLastN) + if (repeatPenalty) obj.repeatPenalty = parseFloat(repeatPenalty) + if (tfsZ) obj.tfsZ = parseFloat(tfsZ) + if (stop) { + const stopSequences = stop.split(',') + obj.stop = stopSequences + } + if (cache) obj.cache = cache + + const model = new Ollama(obj) + return model + } +} + +module.exports = { nodeClass: Ollama_LLMs } diff --git a/packages/components/nodes/llms/Ollama/ollama.png b/packages/components/nodes/llms/Ollama/ollama.png new file mode 100644 index 0000000000000000000000000000000000000000..8cd2cf1ed8043caf62e8b069330889c0cf0f5a3b GIT binary patch literal 7487 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 { const streamAvailableLLMs = { - 'Chat Models': ['azureChatOpenAI', 'chatOpenAI', 'chatAnthropic'], - LLMs: ['azureOpenAI', 'openAI'] + 'Chat Models': ['azureChatOpenAI', 'chatOpenAI', 'chatAnthropic', 'chatOllama'], + LLMs: ['azureOpenAI', 'openAI', 'ollama'] } let isChatOrLLMsExist = false From 536ed07f9defc0b5028f934e67b9c8fe9dc17fef Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 11 Oct 2023 14:08:04 +0100 Subject: [PATCH 45/76] add bedrock embeddings --- .../chatmodels/AWSBedrock/AWSChatBedrock.ts | 23 +-- .../AWSBedrockEmbedding.ts | 152 ++++++++++++++++++ .../AWSBedrockEmbedding/awsBedrock.png | Bin 0 -> 62897 bytes .../nodes/llms/AWSBedrock/AWSBedrock.ts | 22 +-- packages/components/package.json | 3 +- 5 files changed, 167 insertions(+), 33 deletions(-) create mode 100644 packages/components/nodes/embeddings/AWSBedrockEmbedding/AWSBedrockEmbedding.ts create mode 100644 packages/components/nodes/embeddings/AWSBedrockEmbedding/awsBedrock.png diff --git a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts index 16fbc8dc..ade46ab9 100644 --- a/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts +++ b/packages/components/nodes/chatmodels/AWSBedrock/AWSChatBedrock.ts @@ -31,7 +31,7 @@ class AWSChatBedrock_ChatModels implements INode { this.type = 'AWSChatBedrock' this.icon = 'awsBedrock.png' this.category = 'Chat Models' - this.description = 'Wrapper around AWS Bedrock large language models' + this.description = 'Wrapper around AWS Bedrock large language models that use the Chat endpoint' this.baseClasses = [this.type, ...getBaseClasses(ChatBedrock)] this.credential = { label: 'AWS Credential', @@ -88,27 +88,18 @@ class AWSChatBedrock_ChatModels implements INode { { label: 'us-west-1', name: 'us-west-1' }, { label: 'us-west-2', name: 'us-west-2' } ], - default: 'us-east-1', - optional: false + default: 'us-east-1' }, { label: 'Model Name', name: 'model', type: 'options', options: [ - { label: 'amazon.titan-tg1-large', name: 'amazon.titan-tg1-large' }, - { label: 'amazon.titan-e1t-medium', name: 'amazon.titan-e1t-medium' }, - { label: 'stability.stable-diffusion-xl', name: 'stability.stable-diffusion-xl' }, - { label: 'ai21.j2-grande-instruct', name: 'ai21.j2-grande-instruct' }, - { label: 'ai21.j2-jumbo-instruct', name: 'ai21.j2-jumbo-instruct' }, - { label: 'ai21.j2-mid', name: 'ai21.j2-mid' }, - { label: 'ai21.j2-ultra', name: 'ai21.j2-ultra' }, { label: 'anthropic.claude-instant-v1', name: 'anthropic.claude-instant-v1' }, { label: 'anthropic.claude-v1', name: 'anthropic.claude-v1' }, { label: 'anthropic.claude-v2', name: 'anthropic.claude-v2' } ], - default: 'anthropic.claude-v2', - optional: false + default: 'anthropic.claude-v2' }, { label: 'Temperature', @@ -117,8 +108,7 @@ class AWSChatBedrock_ChatModels implements INode { step: 0.1, description: 'Temperature parameter may not apply to certain model. Please check available model parameters', optional: true, - default: 0.7, - additionalParams: false + default: 0.7 }, { label: 'Max Tokens to Sample', @@ -126,9 +116,8 @@ class AWSChatBedrock_ChatModels implements INode { type: 'number', step: 10, description: 'Max Tokens parameter may not apply to certain model. Please check available model parameters', - optional: false, - default: 200, - additionalParams: false + optional: true, + default: 200 } ] } diff --git a/packages/components/nodes/embeddings/AWSBedrockEmbedding/AWSBedrockEmbedding.ts b/packages/components/nodes/embeddings/AWSBedrockEmbedding/AWSBedrockEmbedding.ts new file mode 100644 index 00000000..0ac26d85 --- /dev/null +++ b/packages/components/nodes/embeddings/AWSBedrockEmbedding/AWSBedrockEmbedding.ts @@ -0,0 +1,152 @@ +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { BedrockEmbeddings, BedrockEmbeddingsParams } from 'langchain/embeddings/bedrock' +import { BedrockRuntimeClient, InvokeModelCommand } from '@aws-sdk/client-bedrock-runtime' + +class AWSBedrockEmbedding_Embeddings implements INode { + label: string + name: string + version: number + type: string + icon: string + category: string + description: string + baseClasses: string[] + credential: INodeParams + inputs: INodeParams[] + + constructor() { + this.label = 'AWS Bedrock Embeddings' + this.name = 'AWSBedrockEmbeddings' + this.version = 1.0 + this.type = 'AWSBedrockEmbeddings' + this.icon = 'awsBedrock.png' + this.category = 'Embeddings' + this.description = 'AWSBedrock embedding models to generate embeddings for a given text' + this.baseClasses = [this.type, ...getBaseClasses(BedrockEmbeddings)] + this.credential = { + label: 'AWS Credential', + name: 'credential', + type: 'credential', + credentialNames: ['awsApi'], + optional: true + } + this.inputs = [ + { + label: 'Region', + name: 'region', + type: 'options', + options: [ + { label: 'af-south-1', name: 'af-south-1' }, + { label: 'ap-east-1', name: 'ap-east-1' }, + { label: 'ap-northeast-1', name: 'ap-northeast-1' }, + { label: 'ap-northeast-2', name: 'ap-northeast-2' }, + { label: 'ap-northeast-3', name: 'ap-northeast-3' }, + { label: 'ap-south-1', name: 'ap-south-1' }, + { label: 'ap-south-2', name: 'ap-south-2' }, + { label: 'ap-southeast-1', name: 'ap-southeast-1' }, + { label: 'ap-southeast-2', name: 'ap-southeast-2' }, + { label: 'ap-southeast-3', name: 'ap-southeast-3' }, + { label: 'ap-southeast-4', name: 'ap-southeast-4' }, + { label: 'ap-southeast-5', name: 'ap-southeast-5' }, + { label: 'ap-southeast-6', name: 'ap-southeast-6' }, + { label: 'ca-central-1', name: 'ca-central-1' }, + { label: 'ca-west-1', name: 'ca-west-1' }, + { label: 'cn-north-1', name: 'cn-north-1' }, + { label: 'cn-northwest-1', name: 'cn-northwest-1' }, + { label: 'eu-central-1', name: 'eu-central-1' }, + { label: 'eu-central-2', name: 'eu-central-2' }, + { label: 'eu-north-1', name: 'eu-north-1' }, + { label: 'eu-south-1', name: 'eu-south-1' }, + { label: 'eu-south-2', name: 'eu-south-2' }, + { label: 'eu-west-1', name: 'eu-west-1' }, + { label: 'eu-west-2', name: 'eu-west-2' }, + { label: 'eu-west-3', name: 'eu-west-3' }, + { label: 'il-central-1', name: 'il-central-1' }, + { label: 'me-central-1', name: 'me-central-1' }, + { label: 'me-south-1', name: 'me-south-1' }, + { label: 'sa-east-1', name: 'sa-east-1' }, + { label: 'us-east-1', name: 'us-east-1' }, + { label: 'us-east-2', name: 'us-east-2' }, + { label: 'us-gov-east-1', name: 'us-gov-east-1' }, + { label: 'us-gov-west-1', name: 'us-gov-west-1' }, + { label: 'us-west-1', name: 'us-west-1' }, + { label: 'us-west-2', name: 'us-west-2' } + ], + default: 'us-east-1' + }, + { + label: 'Model Name', + name: 'model', + type: 'options', + options: [{ label: 'amazon.titan-embed-text-v1', name: 'amazon.titan-embed-text-v1' }], + default: 'amazon.titan-embed-text-v1' + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const iRegion = nodeData.inputs?.region as string + const iModel = nodeData.inputs?.model as string + + const obj: BedrockEmbeddingsParams = { + model: iModel, + region: iRegion + } + + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + if (credentialData && Object.keys(credentialData).length !== 0) { + const credentialApiKey = getCredentialParam('awsKey', credentialData, nodeData) + const credentialApiSecret = getCredentialParam('awsSecret', credentialData, nodeData) + const credentialApiSession = getCredentialParam('awsSession', credentialData, nodeData) + + obj.credentials = { + accessKeyId: credentialApiKey, + secretAccessKey: credentialApiSecret, + sessionToken: credentialApiSession + } + } + + const client = new BedrockRuntimeClient({ + region: obj.region, + credentials: obj.credentials + }) + + const model = new BedrockEmbeddings(obj) + + // Avoid Illegal Invocation + model.embedQuery = async (document: string): Promise => { + return await embedText(document, client, iModel) + } + + model.embedDocuments = async (documents: string[]): Promise => { + return Promise.all(documents.map((document) => embedText(document, client, iModel))) + } + return model + } +} + +const embedText = async (text: string, client: BedrockRuntimeClient, model: string): Promise => { + // replace newlines, which can negatively affect performance. + const cleanedText = text.replace(/\n/g, ' ') + + const res = await client.send( + new InvokeModelCommand({ + modelId: model, + body: JSON.stringify({ + inputText: cleanedText + }), + contentType: 'application/json', + accept: 'application/json' + }) + ) + + try { + const body = new TextDecoder().decode(res.body) + return JSON.parse(body).embedding + } catch (e) { + throw new Error('An invalid response was returned by Bedrock.') + } +} + +module.exports = { nodeClass: AWSBedrockEmbedding_Embeddings } diff --git a/packages/components/nodes/embeddings/AWSBedrockEmbedding/awsBedrock.png b/packages/components/nodes/embeddings/AWSBedrockEmbedding/awsBedrock.png new file mode 100644 index 0000000000000000000000000000000000000000..483bc69a9c7ae460dba316682d08101557629b66 GIT binary patch literal 62897 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 literal 0 HcmV?d00001 diff --git a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts index 8f57daac..b67219f3 100644 --- a/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts +++ b/packages/components/nodes/llms/AWSBedrock/AWSBedrock.ts @@ -88,8 +88,7 @@ class AWSBedrock_LLMs implements INode { { label: 'us-west-1', name: 'us-west-1' }, { label: 'us-west-2', name: 'us-west-2' } ], - default: 'us-east-1', - optional: false + default: 'us-east-1' }, { label: 'Model Name', @@ -98,17 +97,12 @@ class AWSBedrock_LLMs implements INode { options: [ { label: 'amazon.titan-tg1-large', name: 'amazon.titan-tg1-large' }, { label: 'amazon.titan-e1t-medium', name: 'amazon.titan-e1t-medium' }, - { label: 'stability.stable-diffusion-xl', name: 'stability.stable-diffusion-xl' }, + { label: 'cohere.command-text-v14', name: 'cohere.command-text-v14' }, { label: 'ai21.j2-grande-instruct', name: 'ai21.j2-grande-instruct' }, { label: 'ai21.j2-jumbo-instruct', name: 'ai21.j2-jumbo-instruct' }, { label: 'ai21.j2-mid', name: 'ai21.j2-mid' }, - { label: 'ai21.j2-ultra', name: 'ai21.j2-ultra' }, - { label: 'anthropic.claude-instant-v1', name: 'anthropic.claude-instant-v1' }, - { label: 'anthropic.claude-v1', name: 'anthropic.claude-v1' }, - { label: 'anthropic.claude-v2', name: 'anthropic.claude-v2' } - ], - default: 'anthropic.claude-v2', - optional: false + { label: 'ai21.j2-ultra', name: 'ai21.j2-ultra' } + ] }, { label: 'Temperature', @@ -117,8 +111,7 @@ class AWSBedrock_LLMs implements INode { step: 0.1, description: 'Temperature parameter may not apply to certain model. Please check available model parameters', optional: true, - default: 0.7, - additionalParams: false + default: 0.7 }, { label: 'Max Tokens to Sample', @@ -126,9 +119,8 @@ class AWSBedrock_LLMs implements INode { type: 'number', step: 10, description: 'Max Tokens parameter may not apply to certain model. Please check available model parameters', - optional: false, - default: 200, - additionalParams: false + optional: true, + default: 200 } ] } diff --git a/packages/components/package.json b/packages/components/package.json index cf545ec3..b2f30263 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -16,6 +16,7 @@ }, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { + "@aws-sdk/client-bedrock-runtime": "3.422.0", "@aws-sdk/client-dynamodb": "^3.360.0", "@dqbd/tiktoken": "^1.0.7", "@getzep/zep-js": "^0.6.3", @@ -45,7 +46,7 @@ "graphql": "^16.6.0", "html-to-text": "^9.0.5", "ioredis": "^5.3.2", - "langchain": "^0.0.157", + "langchain": "^0.0.165", "langfuse-langchain": "^1.0.14-alpha.0", "langsmith": "^0.0.32", "linkifyjs": "^4.1.1", From f42a2d338765a350c87a41a1fbc21c637de63259 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 11 Oct 2023 19:54:10 +0100 Subject: [PATCH 46/76] add in-mem llm cache --- .../cache/InMemoryCache/InMemoryCache.ts | 64 ++++++++++++++++++ .../cache/InMemoryCache/inmemorycache.png | Bin 0 -> 12175 bytes packages/components/package.json | 2 + packages/server/src/CachePool.ts | 53 +++++++++++++++ packages/server/src/Interface.ts | 4 ++ packages/server/src/index.ts | 9 ++- packages/server/src/utils/index.ts | 11 ++- 7 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts create mode 100644 packages/components/nodes/cache/InMemoryCache/inmemorycache.png create mode 100644 packages/server/src/CachePool.ts diff --git a/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts new file mode 100644 index 00000000..fe7a3f12 --- /dev/null +++ b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts @@ -0,0 +1,64 @@ +import { getBaseClasses, ICommonObject, INode, INodeData, INodeParams } from '../../../src' +import { BaseCache } from 'langchain/schema' +import hash from 'object-hash' + +class InMemoryCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + + constructor() { + this.label = 'InMemory Cache' + this.name = 'inMemoryCache' + this.version = 1.0 + this.type = 'InMemoryCache' + this.icon = 'inmemorycache.png' + this.category = 'Cache' + this.baseClasses = [this.type, ...getBaseClasses(InMemoryCacheExtended)] + this.inputs = [] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const memoryMap = options.cachePool.getLLMCache(options.chatflowid) ?? new Map() + const inMemCache = new InMemoryCacheExtended(memoryMap) + + inMemCache.lookup = async (prompt: string, llmKey: string): Promise => { + const memory = options.cachePool.getLLMCache(options.chatflowid) ?? inMemCache.cache + return Promise.resolve(memory.get(getCacheKey(prompt, llmKey)) ?? null) + } + + inMemCache.update = async (prompt: string, llmKey: string, value: any): Promise => { + inMemCache.cache.set(getCacheKey(prompt, llmKey), value) + options.cachePool.addLLMCache(options.chatflowid, inMemCache.cache) + } + return inMemCache + } +} + +const getCacheKey = (...strings: string[]): string => hash(strings.join('_')) + +class InMemoryCacheExtended extends BaseCache { + cache: Map + + constructor(map: Map) { + super() + this.cache = map + } + + lookup(prompt: string, llmKey: string): Promise { + return Promise.resolve(this.cache.get(getCacheKey(prompt, llmKey)) ?? null) + } + + async update(prompt: string, llmKey: string, value: any): Promise { + this.cache.set(getCacheKey(prompt, llmKey), value) + } +} + +module.exports = { nodeClass: InMemoryCache } diff --git a/packages/components/nodes/cache/InMemoryCache/inmemorycache.png b/packages/components/nodes/cache/InMemoryCache/inmemorycache.png new file mode 100644 index 0000000000000000000000000000000000000000..1e5fe6d14a4eac6876acd05668e165aa9daf9eca GIT binary patch literal 12175 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 value + */ + addLLMCache(chatflowid: string, value: Map) { + this.activeLLMCache[chatflowid] = value + } + + /** + * Add to the embedding cache pool + * @param {string} chatflowid + * @param {Map} value + */ + addEmbeddingCache(chatflowid: string, value: Map) { + this.activeEmbeddingCache[chatflowid] = value + } + + /** + * Get item from llm cache pool + * @param {string} chatflowid + */ + getLLMCache(chatflowid: string): Map | undefined { + return this.activeLLMCache[chatflowid] + } + + /** + * Get item from embedding cache pool + * @param {string} chatflowid + */ + getEmbeddingCache(chatflowid: string): Map | undefined { + return this.activeEmbeddingCache[chatflowid] + } +} + +let cachePoolInstance: CachePool | undefined + +export function getInstance(): CachePool { + if (cachePoolInstance === undefined) { + cachePoolInstance = new CachePool() + } + + return cachePoolInstance +} diff --git a/packages/server/src/Interface.ts b/packages/server/src/Interface.ts index 58740b86..b3c3a392 100644 --- a/packages/server/src/Interface.ts +++ b/packages/server/src/Interface.ts @@ -157,6 +157,10 @@ export interface IActiveChatflows { } } +export interface IActiveCache { + [key: string]: Map +} + export interface IOverrideConfig { node: string nodeId: string diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index db5ecf38..9d3f7052 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -53,6 +53,7 @@ import { ChatMessage } from './database/entities/ChatMessage' import { Credential } from './database/entities/Credential' import { Tool } from './database/entities/Tool' import { ChatflowPool } from './ChatflowPool' +import { CachePool } from './CachePool' import { ICommonObject, INodeOptionsValue } from 'flowise-components' import { createRateLimiter, getRateLimiter, initializeRateLimiter } from './utils/rateLimit' @@ -60,6 +61,7 @@ export class App { app: express.Application nodesPool: NodesPool chatflowPool: ChatflowPool + cachePool: CachePool AppDataSource = getDataSource() constructor() { @@ -91,6 +93,9 @@ export class App { // Initialize Rate Limit const AllChatFlow: IChatFlow[] = await getAllChatFlow() await initializeRateLimiter(AllChatFlow) + + // Initialize cache pool + this.cachePool = new CachePool() }) .catch((err) => { logger.error('❌ [server]: Error during Data Source initialization:', err) @@ -944,8 +949,10 @@ export class App { incomingInput.question, incomingInput.history, chatId, + chatflowid, this.AppDataSource, - incomingInput?.overrideConfig + incomingInput?.overrideConfig, + this.cachePool ) const nodeToExecute = reactFlowNodes.find((node: IReactFlowNode) => node.id === endingNodeId) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 7686e476..317bcc0c 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -35,6 +35,7 @@ import { ChatMessage } from '../database/entities/ChatMessage' import { Credential } from '../database/entities/Credential' import { Tool } from '../database/entities/Tool' import { DataSource } from 'typeorm' +import { CachePool } from '../CachePool' const QUESTION_VAR_PREFIX = 'question' const CHAT_HISTORY_VAR_PREFIX = 'chat_history' @@ -197,8 +198,10 @@ export const getEndingNode = (nodeDependencies: INodeDependencies, graph: INodeD * @param {IComponentNodes} componentNodes * @param {string} question * @param {string} chatId + * @param {string} chatflowid * @param {DataSource} appDataSource * @param {ICommonObject} overrideConfig + * @param {CachePool} cachePool */ export const buildLangchain = async ( startingNodeIds: string[], @@ -209,8 +212,10 @@ export const buildLangchain = async ( question: string, chatHistory: IMessage[], chatId: string, + chatflowid: string, appDataSource: DataSource, - overrideConfig?: ICommonObject + overrideConfig?: ICommonObject, + cachePool?: CachePool ) => { const flowNodes = cloneDeep(reactFlowNodes) @@ -245,9 +250,11 @@ export const buildLangchain = async ( logger.debug(`[server]: Initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`) flowNodes[nodeIndex].data.instance = await newNodeInstance.init(reactFlowNodeData, question, { chatId, + chatflowid, appDataSource, databaseEntities, - logger + logger, + cachePool }) logger.debug(`[server]: Finished initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`) } catch (e: any) { From 41e612408c0ae738dcadfe5ed25cb9574bb02085 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 11 Oct 2023 20:09:13 +0100 Subject: [PATCH 47/76] add description --- packages/components/credentials/UpstashRedisApi.credential.ts | 3 +++ packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts | 1 + packages/components/nodes/cache/MomentoCache/MomentoCache.ts | 1 + packages/components/nodes/cache/RedisCache/RedisCache.ts | 1 + .../nodes/cache/UpstashRedisCache/UpstashRedisCache.ts | 1 + 5 files changed, 7 insertions(+) diff --git a/packages/components/credentials/UpstashRedisApi.credential.ts b/packages/components/credentials/UpstashRedisApi.credential.ts index b6e62ff3..7e2b367f 100644 --- a/packages/components/credentials/UpstashRedisApi.credential.ts +++ b/packages/components/credentials/UpstashRedisApi.credential.ts @@ -4,12 +4,15 @@ class UpstashRedisApi implements INodeCredential { label: string name: string version: number + description: string inputs: INodeParams[] constructor() { this.label = 'Upstash Redis API' this.name = 'upstashRedisApi' this.version = 1.0 + this.description = + 'Refer to official guide on how to create redis instance and get redis REST URL and Token' this.inputs = [ { label: 'Upstash Redis REST URL', diff --git a/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts index fe7a3f12..1ea03566 100644 --- a/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts +++ b/packages/components/nodes/cache/InMemoryCache/InMemoryCache.ts @@ -19,6 +19,7 @@ class InMemoryCache implements INode { this.name = 'inMemoryCache' this.version = 1.0 this.type = 'InMemoryCache' + this.description = 'Cache LLM response in memory, will be cleared once app restarted' this.icon = 'inmemorycache.png' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(InMemoryCacheExtended)] diff --git a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts index 9aa82e82..2bd2625b 100644 --- a/packages/components/nodes/cache/MomentoCache/MomentoCache.ts +++ b/packages/components/nodes/cache/MomentoCache/MomentoCache.ts @@ -19,6 +19,7 @@ class MomentoCache implements INode { this.name = 'momentoCache' this.version = 1.0 this.type = 'MomentoCache' + this.description = 'Cache LLM response using Momento, a distributed, serverless cache' this.icon = 'momento.png' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(LangchainMomentoCache)] diff --git a/packages/components/nodes/cache/RedisCache/RedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts index c1b08be6..da2dfc49 100644 --- a/packages/components/nodes/cache/RedisCache/RedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -19,6 +19,7 @@ class RedisCache implements INode { this.name = 'redisCache' this.version = 1.0 this.type = 'RedisCache' + this.description = 'Cache LLM response in Redis, useful for sharing cache across multiple processes or servers' this.icon = 'redis.svg' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(LangchainRedisCache)] diff --git a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts index eb5a9e2f..f4ed947b 100644 --- a/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts +++ b/packages/components/nodes/cache/UpstashRedisCache/UpstashRedisCache.ts @@ -18,6 +18,7 @@ class UpstashRedisCache implements INode { this.name = 'upstashRedisCache' this.version = 1.0 this.type = 'UpstashRedisCache' + this.description = 'Cache LLM response in Upstash Redis, serverless data for Redis and Kafka' this.icon = 'upstash.png' this.category = 'Cache' this.baseClasses = [this.type, ...getBaseClasses(LangchainUpstashRedisCache)] From 789d8d0001a4da9d37a880c4511f2ee60bec29a4 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 12 Oct 2023 11:56:52 +0100 Subject: [PATCH 48/76] add s3 loader --- .../nodes/documentloaders/S3File/S3File.ts | 241 ++++++++++++++++++ .../nodes/documentloaders/S3File/s3.svg | 1 + packages/components/package.json | 1 + 3 files changed, 243 insertions(+) create mode 100644 packages/components/nodes/documentloaders/S3File/S3File.ts create mode 100644 packages/components/nodes/documentloaders/S3File/s3.svg diff --git a/packages/components/nodes/documentloaders/S3File/S3File.ts b/packages/components/nodes/documentloaders/S3File/S3File.ts new file mode 100644 index 00000000..07295aba --- /dev/null +++ b/packages/components/nodes/documentloaders/S3File/S3File.ts @@ -0,0 +1,241 @@ +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { S3Loader } from 'langchain/document_loaders/web/s3' +import { UnstructuredLoader } from 'langchain/document_loaders/fs/unstructured' +import { getCredentialData, getCredentialParam } from '../../../src/utils' +import { S3Client, GetObjectCommand, S3ClientConfig } from '@aws-sdk/client-s3' +import { Readable } from 'node:stream' +import * as fsDefault from 'node:fs' +import * as path from 'node:path' +import * as os from 'node:os' + +type S3Config = S3ClientConfig & { + /** @deprecated Use the credentials object instead */ + accessKeyId?: string + /** @deprecated Use the credentials object instead */ + secretAccessKey?: string +} + +class S3_DocumentLoaders implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + credential: INodeParams + inputs?: INodeParams[] + + constructor() { + this.label = 'S3' + this.name = 'S3' + this.version = 1.0 + this.type = 'Document' + this.icon = 's3.svg' + this.category = 'Document Loaders' + this.description = 'Load Data from S3 Buckets' + this.baseClasses = [this.type] + this.credential = { + label: 'AWS Credential', + name: 'credential', + type: 'credential', + credentialNames: ['awsApi'] + } + this.inputs = [ + { + label: 'Bucket', + name: 'bucketName', + type: 'string' + }, + { + label: 'Object Key', + name: 'keyName', + type: 'string', + description: 'The object key (or key name) that uniquely identifies object in an Amazon S3 bucket', + placeholder: 'AI-Paper.pdf' + }, + { + label: 'Region', + name: 'region', + type: 'options', + options: [ + { label: 'af-south-1', name: 'af-south-1' }, + { label: 'ap-east-1', name: 'ap-east-1' }, + { label: 'ap-northeast-1', name: 'ap-northeast-1' }, + { label: 'ap-northeast-2', name: 'ap-northeast-2' }, + { label: 'ap-northeast-3', name: 'ap-northeast-3' }, + { label: 'ap-south-1', name: 'ap-south-1' }, + { label: 'ap-south-2', name: 'ap-south-2' }, + { label: 'ap-southeast-1', name: 'ap-southeast-1' }, + { label: 'ap-southeast-2', name: 'ap-southeast-2' }, + { label: 'ap-southeast-3', name: 'ap-southeast-3' }, + { label: 'ap-southeast-4', name: 'ap-southeast-4' }, + { label: 'ap-southeast-5', name: 'ap-southeast-5' }, + { label: 'ap-southeast-6', name: 'ap-southeast-6' }, + { label: 'ca-central-1', name: 'ca-central-1' }, + { label: 'ca-west-1', name: 'ca-west-1' }, + { label: 'cn-north-1', name: 'cn-north-1' }, + { label: 'cn-northwest-1', name: 'cn-northwest-1' }, + { label: 'eu-central-1', name: 'eu-central-1' }, + { label: 'eu-central-2', name: 'eu-central-2' }, + { label: 'eu-north-1', name: 'eu-north-1' }, + { label: 'eu-south-1', name: 'eu-south-1' }, + { label: 'eu-south-2', name: 'eu-south-2' }, + { label: 'eu-west-1', name: 'eu-west-1' }, + { label: 'eu-west-2', name: 'eu-west-2' }, + { label: 'eu-west-3', name: 'eu-west-3' }, + { label: 'il-central-1', name: 'il-central-1' }, + { label: 'me-central-1', name: 'me-central-1' }, + { label: 'me-south-1', name: 'me-south-1' }, + { label: 'sa-east-1', name: 'sa-east-1' }, + { label: 'us-east-1', name: 'us-east-1' }, + { label: 'us-east-2', name: 'us-east-2' }, + { label: 'us-gov-east-1', name: 'us-gov-east-1' }, + { label: 'us-gov-west-1', name: 'us-gov-west-1' }, + { label: 'us-west-1', name: 'us-west-1' }, + { label: 'us-west-2', name: 'us-west-2' } + ], + default: 'us-east-1' + }, + { + label: 'Unstructured API URL', + name: 'unstructuredAPIUrl', + description: + 'Your Unstructured.io URL. Read more on how to get started', + type: 'string', + default: 'http://localhost:8000/general/v0/general' + }, + { + label: 'Unstructured API KEY', + name: 'unstructuredAPIKey', + type: 'password', + optional: true + }, + { + label: 'NarrativeText Only', + name: 'narrativeTextOnly', + description: + 'Only load documents with NarrativeText metadata from Unstructured. See how Unstructured partition data here', + default: true, + type: 'boolean', + optional: true, + additionalParams: true + }, + { + label: 'Metadata', + name: 'metadata', + type: 'json', + optional: true, + additionalParams: true + } + ] + } + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const bucketName = nodeData.inputs?.bucketName as string + const keyName = nodeData.inputs?.keyName as string + const region = nodeData.inputs?.region as string + const unstructuredAPIUrl = nodeData.inputs?.unstructuredAPIUrl as string + const unstructuredAPIKey = nodeData.inputs?.unstructuredAPIKey as string + const metadata = nodeData.inputs?.metadata + const narrativeTextOnly = nodeData.inputs?.narrativeTextOnly as boolean + + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const accessKeyId = getCredentialParam('awsKey', credentialData, nodeData) + const secretAccessKey = getCredentialParam('awsSecret', credentialData, nodeData) + + const loader = new S3Loader({ + bucket: bucketName, + key: keyName, + s3Config: { + region, + credentials: { + accessKeyId, + secretAccessKey + } + }, + unstructuredAPIURL: unstructuredAPIUrl, + unstructuredAPIKey: unstructuredAPIKey + }) + + const s3Config: S3Config & { + accessKeyId?: string + secretAccessKey?: string + } = { + accessKeyId, + secretAccessKey + } + + loader.load = async () => { + const tempDir = fsDefault.mkdtempSync(path.join(os.tmpdir(), 's3fileloader-')) + + const filePath = path.join(tempDir, keyName) + + try { + const s3Client = new S3Client(s3Config) + + const getObjectCommand = new GetObjectCommand({ + Bucket: bucketName, + Key: keyName + }) + + const response = await s3Client.send(getObjectCommand) + + const objectData = await new Promise((resolve, reject) => { + const chunks: Buffer[] = [] + + if (response.Body instanceof Readable) { + response.Body.on('data', (chunk: Buffer) => chunks.push(chunk)) + response.Body.on('end', () => resolve(Buffer.concat(chunks))) + response.Body.on('error', reject) + } else { + reject(new Error('Response body is not a readable stream.')) + } + }) + + fsDefault.mkdirSync(path.dirname(filePath), { recursive: true }) + + fsDefault.writeFileSync(filePath, objectData) + } catch (e: any) { + throw new Error(`Failed to download file ${keyName} from S3 bucket ${bucketName}: ${e.message}`) + } + + try { + const options = { + apiUrl: unstructuredAPIUrl, + apiKey: unstructuredAPIKey + } + + const unstructuredLoader = new UnstructuredLoader(filePath, options) + + const docs = await unstructuredLoader.load() + + fsDefault.rmdirSync(path.dirname(filePath), { recursive: true }) + + return docs + } catch { + fsDefault.rmdirSync(path.dirname(filePath), { recursive: true }) + throw new Error(`Failed to load file ${filePath} using unstructured loader.`) + } + } + + const docs = await loader.load() + + if (metadata) { + const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) + const finaldocs = docs.map((doc) => { + return { + ...doc, + metadata: { + ...doc.metadata, + ...parsedMetadata + } + } + }) + return narrativeTextOnly ? finaldocs.filter((doc) => doc.metadata.category === 'NarrativeText') : finaldocs + } + + return narrativeTextOnly ? docs.filter((doc) => doc.metadata.category === 'NarrativeText') : docs + } +} +module.exports = { nodeClass: S3_DocumentLoaders } diff --git a/packages/components/nodes/documentloaders/S3File/s3.svg b/packages/components/nodes/documentloaders/S3File/s3.svg new file mode 100644 index 00000000..cd203eaa --- /dev/null +++ b/packages/components/nodes/documentloaders/S3File/s3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/package.json b/packages/components/package.json index b2f30263..ef0be265 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -18,6 +18,7 @@ "dependencies": { "@aws-sdk/client-bedrock-runtime": "3.422.0", "@aws-sdk/client-dynamodb": "^3.360.0", + "@aws-sdk/client-s3": "^3.427.0", "@dqbd/tiktoken": "^1.0.7", "@getzep/zep-js": "^0.6.3", "@gomomento/sdk": "^1.40.2", From 8bca7b3c04ad300877822e3d224763f45ba3d6dc Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 12 Oct 2023 12:40:43 +0100 Subject: [PATCH 49/76] Update ElasticsearchAPI.credential.ts --- packages/components/credentials/ElasticsearchAPI.credential.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/credentials/ElasticsearchAPI.credential.ts b/packages/components/credentials/ElasticsearchAPI.credential.ts index e377243d..fbba76f4 100644 --- a/packages/components/credentials/ElasticsearchAPI.credential.ts +++ b/packages/components/credentials/ElasticsearchAPI.credential.ts @@ -20,7 +20,7 @@ class ElectricsearchAPI implements INodeCredential { type: 'string' }, { - label: 'Elasticsearch API ID', + label: 'Elasticsearch API Key', name: 'apiKey', type: 'password' } From 6474895787db2877b11e1e596785011f1200dcc7 Mon Sep 17 00:00:00 2001 From: Kaiwalya Koparkar Date: Thu, 12 Oct 2023 12:24:08 +0000 Subject: [PATCH 50/76] feat: Adding Elestio as deployment option --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 9f685846..25026237 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,10 @@ Flowise support different environment variables to configure your instance. You [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://docs.flowiseai.com/deployment/render) +### [Elestio](https://elest.io/open-source/flowiseai) + +[![Deploy](https://pub-da36157c854648669813f3f76c526c2b.r2.dev/deploy-on-elestio-black.png)](https://elest.io/open-source/flowiseai) + ### [HuggingFace Spaces](https://docs.flowiseai.com/deployment/hugging-face) HuggingFace Spaces From 31379059959151b713fc80d8288e037580a61595 Mon Sep 17 00:00:00 2001 From: Marc Klingen Date: Thu, 12 Oct 2023 15:25:04 +0200 Subject: [PATCH 51/76] Remove unnecessary Langfuse inputs --- packages/components/src/handler.ts | 6 ------ .../ui-component/dialog/AnalyseFlowDialog.js | 21 ------------------- 2 files changed, 27 deletions(-) diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index 3b1952d6..236b423f 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -238,9 +238,6 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO }) callbacks.push(tracer) } else if (provider === 'langFuse') { - const flushAt = analytic[provider].flushAt as string - const flushInterval = analytic[provider].flushInterval as string - const requestTimeout = analytic[provider].requestTimeout as string const release = analytic[provider].release as string const langFuseSecretKey = getCredentialParam('langFuseSecretKey', credentialData, nodeData) @@ -252,9 +249,6 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO publicKey: langFusePublicKey, baseUrl: langFuseEndpoint ?? 'https://cloud.langfuse.com' } - if (flushAt) langFuseOptions.flushAt = parseInt(flushAt, 10) - if (flushInterval) langFuseOptions.flushInterval = parseInt(flushInterval, 10) - if (requestTimeout) langFuseOptions.requestTimeout = parseInt(requestTimeout, 10) if (release) langFuseOptions.release = release const handler = new CallbackHandler(langFuseOptions) diff --git a/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js b/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js index 2d9a7d91..dd6bb8ab 100644 --- a/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js +++ b/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js @@ -81,27 +81,6 @@ const analyticProviders = [ type: 'credential', credentialNames: ['langfuseApi'] }, - { - label: 'Flush At', - name: 'flushAt', - type: 'number', - optional: true, - description: 'Number of queued requests' - }, - { - label: 'Flush Interval', - name: 'flushInterval', - type: 'number', - optional: true, - description: 'Interval in ms to flush requests' - }, - { - label: 'Request Timeout', - name: 'requestTimeout', - type: 'number', - optional: true, - description: 'Timeout in ms for requests' - }, { label: 'Release', name: 'release', From 21b2ef7f1dfff71c1d50765aa26ca3bbe5ed8bfe Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 12 Oct 2023 15:31:19 +0100 Subject: [PATCH 52/76] add unstructured --- .../credentials/UnstructuredApi.credential.ts | 26 +++++ .../Unstructured/UnstructuredFile.ts | 93 ++++++++++++++++++ .../Unstructured/UnstructuredFolder.ts | 93 ++++++++++++++++++ .../Unstructured/unstructured.png | Bin 0 -> 16710 bytes 4 files changed, 212 insertions(+) create mode 100644 packages/components/credentials/UnstructuredApi.credential.ts create mode 100644 packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts create mode 100644 packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts create mode 100644 packages/components/nodes/documentloaders/Unstructured/unstructured.png diff --git a/packages/components/credentials/UnstructuredApi.credential.ts b/packages/components/credentials/UnstructuredApi.credential.ts new file mode 100644 index 00000000..5c77895a --- /dev/null +++ b/packages/components/credentials/UnstructuredApi.credential.ts @@ -0,0 +1,26 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class UnstructuredApi implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Unstructured API' + this.name = 'unstructuredApi' + this.version = 1.0 + this.description = + 'Refer to official guide on how to get api key on Unstructured' + this.inputs = [ + { + label: 'API Key', + name: 'unstructuredAPIKey', + type: 'password' + } + ] + } +} + +module.exports = { credClass: UnstructuredApi } diff --git a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts new file mode 100644 index 00000000..820aaab5 --- /dev/null +++ b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts @@ -0,0 +1,93 @@ +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { UnstructuredLoader, UnstructuredLoaderOptions } from 'langchain/document_loaders/fs/unstructured' +import { getCredentialData, getCredentialParam } from '../../../src/utils' + +class UnstructuredFile_DocumentLoaders implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + credential: INodeParams + inputs: INodeParams[] + + constructor() { + this.label = 'Unstructured File Loader' + this.name = 'unstructuredFileLoader' + this.version = 1.0 + this.type = 'Document' + this.icon = 'unstructured.png' + this.category = 'Document Loaders' + this.description = 'Use Unstructured.io to load data from a file path' + this.baseClasses = [this.type] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['unstructuredApi'], + optional: true + } + this.inputs = [ + { + label: 'File Path', + name: 'filePath', + type: 'string', + placeholder: '' + }, + { + label: 'Unstructured API URL', + name: 'unstructuredAPIUrl', + description: + 'Unstructured API URL. Read more on how to get started', + type: 'string', + default: 'http://localhost:8000/general/v0/general' + }, + { + label: 'Metadata', + name: 'metadata', + type: 'json', + optional: true, + additionalParams: true + } + /*TODO Add Filter Options*/ + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const filePath = nodeData.inputs?.filePath as string + const unstructuredAPIUrl = nodeData.inputs?.unstructuredAPIUrl as string + const metadata = nodeData.inputs?.metadata + + const obj: UnstructuredLoaderOptions = { apiUrl: unstructuredAPIUrl } + + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const unstructuredAPIKey = getCredentialParam('unstructuredAPIKey', credentialData, nodeData) + if (unstructuredAPIKey) obj.apiKey = unstructuredAPIKey + + const loader = new UnstructuredLoader(filePath, obj) + const docs = await loader.load() + + if (metadata) { + const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) + let finaldocs = [] + for (const doc of docs) { + const newdoc = { + ...doc, + metadata: { + ...doc.metadata, + ...parsedMetadata + } + } + finaldocs.push(newdoc) + } + return finaldocs + } + + return docs + } +} + +module.exports = { nodeClass: UnstructuredFile_DocumentLoaders } diff --git a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts new file mode 100644 index 00000000..4a52fb5a --- /dev/null +++ b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts @@ -0,0 +1,93 @@ +import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' +import { UnstructuredDirectoryLoader, UnstructuredLoaderOptions } from 'langchain/document_loaders/fs/unstructured' +import { getCredentialData, getCredentialParam } from '../../../src/utils' + +class UnstructuredFolder_DocumentLoaders implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + credential: INodeParams + inputs: INodeParams[] + + constructor() { + this.label = 'Unstructured Folder Loader' + this.name = 'unstructuredFolderLoader' + this.version = 1.0 + this.type = 'Document' + this.icon = 'unstructured.png' + this.category = 'Document Loaders' + this.description = 'Use Unstructured.io to load data from a folder' + this.baseClasses = [this.type] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['unstructuredApi'], + optional: true + } + this.inputs = [ + { + label: 'Folder Path', + name: 'folderPath', + type: 'string', + placeholder: '' + }, + { + label: 'Unstructured API URL', + name: 'unstructuredAPIUrl', + description: + 'Unstructured API URL. Read more on how to get started', + type: 'string', + default: 'http://localhost:8000/general/v0/general' + }, + { + label: 'Metadata', + name: 'metadata', + type: 'json', + optional: true, + additionalParams: true + } + /*TODO Add Filter Options*/ + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const folderPath = nodeData.inputs?.folderPath as string + const unstructuredAPIUrl = nodeData.inputs?.unstructuredAPIUrl as string + const metadata = nodeData.inputs?.metadata + + const obj: UnstructuredLoaderOptions = { apiUrl: unstructuredAPIUrl } + + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const unstructuredAPIKey = getCredentialParam('unstructuredAPIKey', credentialData, nodeData) + if (unstructuredAPIKey) obj.apiKey = unstructuredAPIKey + + const loader = new UnstructuredDirectoryLoader(folderPath, obj) + const docs = await loader.load() + + if (metadata) { + const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) + let finaldocs = [] + for (const doc of docs) { + const newdoc = { + ...doc, + metadata: { + ...doc.metadata, + ...parsedMetadata + } + } + finaldocs.push(newdoc) + } + return finaldocs + } + + return docs + } +} + +module.exports = { nodeClass: UnstructuredFolder_DocumentLoaders } diff --git a/packages/components/nodes/documentloaders/Unstructured/unstructured.png b/packages/components/nodes/documentloaders/Unstructured/unstructured.png new file mode 100644 index 0000000000000000000000000000000000000000..435219bf7011d7bd4fdbdeb9d08e943a1b349043 GIT binary patch literal 16710 zcmeHuX*gBy`|mPEsgSQELi$GLB2&^PiHsE)%2cL8C{t|N+m#FbDb9fJeAp0(9 zT)2uLw7&4il4%$G^3PtUVEBi|^{V=LB(I%k5-#ZNRCH7jq%fR$>m~zS?{?8JaYc{= zZrC51L0i5D@Z-%p2F7msPIp{%Y}{^I-*mePzaa=-z{>HC%Vp;~PHwIOXKvsH9tfN{ zDJI|re?Ju4xssJu_&;9Do>cgs5&s#FU7J08PrTlUAj(dcE~pqhFrOV@j5E7dy|#!x zZ`E$L_Rfg?SNZT!_pkW#XC4WPsA(cA)q^>`v>sQgP8j~f#=Ylh)`_Q2H6qOEjs`5B zlaANU5R5nPXvO!~@*TJ;m^tgZIyk-Q#m8$sFz%Jl8M%TM_B!`Go&0+MHd1DuyKaa5 z%Tvz+3t*?m!G#X%7W{o$Wq}SsI_dxajsMG$q$R7T;Pq=3{^Ak|49Y^OX#cUL@$sS4 z=$=lNdX^u?wSS4GZa-N@{VghcO=;57MQgqD3pultXgc@Rv*dZc%DzS&p9_4oJoa;R zu~#-e2XV_-r7aQiSyE@=!qcZQllV+$=hRaoBlxy*fBl`19@~TPtPR(mwVGkWZT$T< zwukIQk1P9%Gw(m4-{Y%8T}ufZHP%Wj--Bdc#ed55-NIXST*fn!ZDCY%&vx|v&$06n zG8SbwWM?F#jcCX--6=0t!&rPqg&NFh%h+H|ojqO0OR39xQq&5`rgX_XIU^c=7lPMs zaVyF4*&6kbY6cf}5+BdJUAU5+n_JChpinCZ!ZhH?ON}io%~IOs0&C`(o|G$X&J7

lRr|=5>~u+In>m(vBSFGu0}N9`KLo3Ez#Zl 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 aKv}egM1C~Z(msdHBbU^4FXWxKB>gY8%~GfU literal 0 HcmV?d00001 From 69a499aea744a4d56c0af23dc1d81af89b7f248f Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 12 Oct 2023 16:25:11 +0100 Subject: [PATCH 53/76] =?UTF-8?q?=F0=9F=A5=B3=20flowise-components@1.3.9?= =?UTF-8?q?=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/components/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/package.json b/packages/components/package.json index b52a5d92..d1bb9dea 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "flowise-components", - "version": "1.3.8", + "version": "1.3.9", "description": "Flowiseai Components", "main": "dist/src/index", "types": "dist/src/index.d.ts", From 63b5cfc9598c972234c315edb50b610dd9004594 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 12 Oct 2023 16:25:56 +0100 Subject: [PATCH 54/76] =?UTF-8?q?=F0=9F=A5=B3=20flowise-ui@1.3.6=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index 239cc3ce..41ad515f 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "flowise-ui", - "version": "1.3.5", + "version": "1.3.6", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://flowiseai.com", "author": { From 84a33bb4043154084e65939c394f8fcadc0dd141 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 12 Oct 2023 16:26:27 +0100 Subject: [PATCH 55/76] =?UTF-8?q?=F0=9F=A5=B3=20flowise@1.3.8=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- packages/server/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e123cc68..13db19d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.3.7", + "version": "1.3.8", "private": true, "homepage": "https://flowiseai.com", "workspaces": [ diff --git a/packages/server/package.json b/packages/server/package.json index a5fb994c..eadedea0 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.3.7", + "version": "1.3.8", "description": "Flowiseai Server", "main": "dist/index", "types": "dist/index.d.ts", From 697682ca010ecf2ed144e4b7f7cbd746c1c95c9e Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 12 Oct 2023 17:45:51 +0100 Subject: [PATCH 56/76] upgrade pinecone to v1 --- .../Pinecone_Existing.ts | 5 ++--- .../Pinecone_Upsert.ts | 5 ++--- .../{Pinecone_Existing => Pinecone}/pinecone.png | Bin .../vectorstores/Pinecone_Upsert/pinecone.png | Bin 2423 -> 0 bytes packages/components/package.json | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) rename packages/components/nodes/vectorstores/{Pinecone_Existing => Pinecone}/Pinecone_Existing.ts (97%) rename packages/components/nodes/vectorstores/{Pinecone_Upsert => Pinecone}/Pinecone_Upsert.ts (97%) rename packages/components/nodes/vectorstores/{Pinecone_Existing => Pinecone}/pinecone.png (100%) delete mode 100644 packages/components/nodes/vectorstores/Pinecone_Upsert/pinecone.png diff --git a/packages/components/nodes/vectorstores/Pinecone_Existing/Pinecone_Existing.ts b/packages/components/nodes/vectorstores/Pinecone/Pinecone_Existing.ts similarity index 97% rename from packages/components/nodes/vectorstores/Pinecone_Existing/Pinecone_Existing.ts rename to packages/components/nodes/vectorstores/Pinecone/Pinecone_Existing.ts index 2369165d..e8536d8d 100644 --- a/packages/components/nodes/vectorstores/Pinecone_Existing/Pinecone_Existing.ts +++ b/packages/components/nodes/vectorstores/Pinecone/Pinecone_Existing.ts @@ -1,5 +1,5 @@ import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' -import { PineconeClient } from '@pinecone-database/pinecone' +import { Pinecone } from '@pinecone-database/pinecone' import { PineconeLibArgs, PineconeStore } from 'langchain/vectorstores/pinecone' import { Embeddings } from 'langchain/embeddings/base' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' @@ -95,8 +95,7 @@ class Pinecone_Existing_VectorStores implements INode { const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData) const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData) - const client = new PineconeClient() - await client.init({ + const client = new Pinecone({ apiKey: pineconeApiKey, environment: pineconeEnv }) diff --git a/packages/components/nodes/vectorstores/Pinecone_Upsert/Pinecone_Upsert.ts b/packages/components/nodes/vectorstores/Pinecone/Pinecone_Upsert.ts similarity index 97% rename from packages/components/nodes/vectorstores/Pinecone_Upsert/Pinecone_Upsert.ts rename to packages/components/nodes/vectorstores/Pinecone/Pinecone_Upsert.ts index 3d2a6497..4a12f27b 100644 --- a/packages/components/nodes/vectorstores/Pinecone_Upsert/Pinecone_Upsert.ts +++ b/packages/components/nodes/vectorstores/Pinecone/Pinecone_Upsert.ts @@ -1,5 +1,5 @@ import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' -import { PineconeClient } from '@pinecone-database/pinecone' +import { Pinecone } from '@pinecone-database/pinecone' import { PineconeLibArgs, PineconeStore } from 'langchain/vectorstores/pinecone' import { Embeddings } from 'langchain/embeddings/base' import { Document } from 'langchain/document' @@ -96,8 +96,7 @@ class PineconeUpsert_VectorStores implements INode { const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData) const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData) - const client = new PineconeClient() - await client.init({ + const client = new Pinecone({ apiKey: pineconeApiKey, environment: pineconeEnv }) diff --git a/packages/components/nodes/vectorstores/Pinecone_Existing/pinecone.png b/packages/components/nodes/vectorstores/Pinecone/pinecone.png similarity index 100% rename from packages/components/nodes/vectorstores/Pinecone_Existing/pinecone.png rename to packages/components/nodes/vectorstores/Pinecone/pinecone.png diff --git a/packages/components/nodes/vectorstores/Pinecone_Upsert/pinecone.png b/packages/components/nodes/vectorstores/Pinecone_Upsert/pinecone.png deleted file mode 100644 index 1ae189fdcc3b672a629d34c271a3d963bfaa1d70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2423 zcmeH{XE@vI8^?c9t0{`0#EM!)X~b-5rIJI8P!fs`BUX)2)M#r{J(La(6%9qJdW_57 zdfHO6(ilZ^)E=dR4iYg=`ttwc|Ngu<*L6S7_j>N<`n;>070xJ z+JU2R&N1LW!ntoxo)zQ>w=c>T1pqZ!$M!sUIB%GjrGqU1#Hav3d@=y+a#Hat01&|e zSKR>snFjzTLJC?h7y$rRk-ZHb^NW#{`!D`;;9uy#;o;$#f^7p%kA4n!z&Qed#8thc zzRL$pTb}dXt8kE7(e|K>U~J{Fgps}d%p;QP-*crK%4yz0!m_+UjYuy3nGmf7V-rek z-MbH?ALsPN%+o;DU z6*jx~&<%H>X*TCd^F6rHKYd^izWOWXh(v*vU;OSoP^=ODIsGE*$FN`1v(9_%iCw#o z$kT4oD^8}_N*0b(`PrqdMN!w29Xh%xRpu`l>c5?S{Jf?=5L@t8DqzUSU|w@9CL=P~ zir}Simw4?{93nZ}fwsu06y#}bfu5%L5C0l(zHqE9hHsghPXMOpy}`@->z{NThX+xM zBl9`aKZQl3@RmI}PAqdgL9DanuXYekl^-+I8_xww>ICsj=9-CRd-PobOM&`$5He0j zg}HfiZJ-E{`!iFq3Pk4o%e$`D~4HLroyO^4C84Rh9VKYDj{lap+tKw^KbnOg`93H&0LpS5jhx5^BRsA#A-I!RA*=)i|kJgS&BqA#<>61%ULEfL{ zcd`uo8<52IW^TxKYN!fqbA`++;r2zlUg}`!8U;F^j1JZvc`mhOEk@~oO@nw1Ce0Rq#M9@<~zaLOF|EPbVl`JLo zn$X}k^Qf!QHM?GdAR{@f#E$SOo(a0d*C>{zCJ^-OrDJxafupq98;cEOx%7u`n8e;GC6W7yH>th3gbKY^*A{1H^~29z=HiuctkiD3>6}iFCrX6RXsgu&#M{3tB zyg!YmFl4uOC18^YT6Ql1M(?shb%!6~R#~oCM{j#~Bru;rT+?%Bnpl4l+D*7O=h z^6bO~OE;P;J*9G(=}`aqt=5+ossx28`oqnj)ljQ5RFqyLZQ)ywm)fa*$~W#2O4|e6 zMM?T8U4C&4uu2QC+%V=hOB$du6^x=bMAy_sq*r9L%MA7s(-HO2{2|VTW1#$C>6yl( z0=73)8lu{s?$gKY?bX!xCI+FIECQ4s(ZDY4S^!;?yCAeHm#!o*Lr)5Y)-;Rh22)f& zJJwo}iPiFwLT+B_=jiS=4`-$hrJ*sp`v>SNVDXHu#m7G6HwBT(mJ1tM+ns8GMuOQf z{Xm=p`;$fOTumS0Y5^?MNOVcndASyXe>z6b&=G+c4!Pye0|g7NUXCxU1}o_{X4{h6 z^U1uUI#=Emm3~W_kY8OBFuiUAEtWEla*MyYXXD%zx>{XRHfneKPD*+kmQa3HTm%zW zmpl8dz!ay)YM+P)YQhtf!>*0Yz%;h45Y>5;MXRL}S?jkUNL^F2!+2NbK~mv9NG+v5 z^@iRHdGPlm%(yRW!pbT%qaR8nUH`u)ADxC#y6xtz`+E00=ljM-#5A2{*uNBak`>q@Ioj9FBy;4bS#Y{SOdCBKrG8 V|9=2W4DsLq02YHoSDklH{0AMUaoGR> diff --git a/packages/components/package.json b/packages/components/package.json index d1bb9dea..7e6797f4 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -27,7 +27,7 @@ "@huggingface/inference": "^2.6.1", "@notionhq/client": "^2.2.8", "@opensearch-project/opensearch": "^1.2.0", - "@pinecone-database/pinecone": "^0.0.14", + "@pinecone-database/pinecone": "^1.1.1", "@qdrant/js-client-rest": "^1.2.2", "@supabase/supabase-js": "^2.29.0", "@types/js-yaml": "^4.0.5", From 68862491af8558b3c4e5466b050eb48ec604247a Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 12 Oct 2023 18:03:21 +0100 Subject: [PATCH 57/76] =?UTF-8?q?=F0=9F=A5=B3=20flowise-components@1.3.10?= =?UTF-8?q?=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/components/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/package.json b/packages/components/package.json index 7e6797f4..262a49db 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "flowise-components", - "version": "1.3.9", + "version": "1.3.10", "description": "Flowiseai Components", "main": "dist/src/index", "types": "dist/src/index.d.ts", From db06f85c2a1b28a472132823b77681469b738ad1 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 13 Oct 2023 01:28:48 +0100 Subject: [PATCH 58/76] add multi options --- .../Unstructured/UnstructuredFile.ts | 75 +++++++++++++++++- .../Unstructured/UnstructuredFolder.ts | 75 +++++++++++++++++- .../Elasticsearch/Elasticsearch_Existing.ts | 2 +- packages/components/src/Interface.ts | 1 + .../ui-component/dropdown/MultiDropdown.js | 79 +++++++++++++++++++ packages/ui/src/utils/genericHelper.js | 15 +++- .../ui/src/views/canvas/NodeInputHandler.js | 10 +++ 7 files changed, 249 insertions(+), 8 deletions(-) create mode 100644 packages/ui/src/ui-component/dropdown/MultiDropdown.js diff --git a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts index 820aaab5..3ee7ff73 100644 --- a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts +++ b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFile.ts @@ -45,6 +45,66 @@ class UnstructuredFile_DocumentLoaders implements INode { type: 'string', default: 'http://localhost:8000/general/v0/general' }, + { + label: 'Element Type', + name: 'elementType', + description: + 'Unstructured partition document into different types, select the types to return. If not selected, all types will be returned', + type: 'multiOptions', + options: [ + { + label: 'FigureCaption', + name: 'FigureCaption' + }, + { + label: 'NarrativeText', + name: 'NarrativeText' + }, + { + label: 'ListItem', + name: 'ListItem' + }, + { + label: 'Title', + name: 'Title' + }, + { + label: 'Address', + name: 'Address' + }, + { + label: 'Table', + name: 'Table' + }, + { + label: 'PageBreak', + name: 'PageBreak' + }, + { + label: 'Header', + name: 'Header' + }, + { + label: 'Footer', + name: 'Footer' + }, + { + label: 'UncategorizedText', + name: 'UncategorizedText' + }, + { + label: 'Image', + name: 'Image' + }, + { + label: 'Formula', + name: 'Formula' + } + ], + default: [], + optional: true, + additionalParams: true + }, { label: 'Metadata', name: 'metadata', @@ -52,13 +112,13 @@ class UnstructuredFile_DocumentLoaders implements INode { optional: true, additionalParams: true } - /*TODO Add Filter Options*/ ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { const filePath = nodeData.inputs?.filePath as string const unstructuredAPIUrl = nodeData.inputs?.unstructuredAPIUrl as string + const elementType = nodeData.inputs?.elementType as string const metadata = nodeData.inputs?.metadata const obj: UnstructuredLoaderOptions = { apiUrl: unstructuredAPIUrl } @@ -70,6 +130,15 @@ class UnstructuredFile_DocumentLoaders implements INode { const loader = new UnstructuredLoader(filePath, obj) const docs = await loader.load() + let elementTypes: string[] = [] + if (elementType) { + try { + elementTypes = JSON.parse(elementType) + } catch (e) { + elementTypes = [] + } + } + if (metadata) { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) let finaldocs = [] @@ -83,10 +152,10 @@ class UnstructuredFile_DocumentLoaders implements INode { } finaldocs.push(newdoc) } - return finaldocs + return elementTypes.length ? finaldocs.filter((doc) => elementTypes.includes(doc.metadata.category)) : finaldocs } - return docs + return elementTypes.length ? docs.filter((doc) => elementTypes.includes(doc.metadata.category)) : docs } } diff --git a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts index 4a52fb5a..c56ff023 100644 --- a/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts +++ b/packages/components/nodes/documentloaders/Unstructured/UnstructuredFolder.ts @@ -45,6 +45,66 @@ class UnstructuredFolder_DocumentLoaders implements INode { type: 'string', default: 'http://localhost:8000/general/v0/general' }, + { + label: 'Element Type', + name: 'elementType', + description: + 'Unstructured partition document into different types, select the types to return. If not selected, all types will be returned', + type: 'multiOptions', + options: [ + { + label: 'FigureCaption', + name: 'FigureCaption' + }, + { + label: 'NarrativeText', + name: 'NarrativeText' + }, + { + label: 'ListItem', + name: 'ListItem' + }, + { + label: 'Title', + name: 'Title' + }, + { + label: 'Address', + name: 'Address' + }, + { + label: 'Table', + name: 'Table' + }, + { + label: 'PageBreak', + name: 'PageBreak' + }, + { + label: 'Header', + name: 'Header' + }, + { + label: 'Footer', + name: 'Footer' + }, + { + label: 'UncategorizedText', + name: 'UncategorizedText' + }, + { + label: 'Image', + name: 'Image' + }, + { + label: 'Formula', + name: 'Formula' + } + ], + default: [], + optional: true, + additionalParams: true + }, { label: 'Metadata', name: 'metadata', @@ -52,7 +112,6 @@ class UnstructuredFolder_DocumentLoaders implements INode { optional: true, additionalParams: true } - /*TODO Add Filter Options*/ ] } @@ -60,6 +119,7 @@ class UnstructuredFolder_DocumentLoaders implements INode { const folderPath = nodeData.inputs?.folderPath as string const unstructuredAPIUrl = nodeData.inputs?.unstructuredAPIUrl as string const metadata = nodeData.inputs?.metadata + const elementType = nodeData.inputs?.elementType as string const obj: UnstructuredLoaderOptions = { apiUrl: unstructuredAPIUrl } @@ -70,6 +130,15 @@ class UnstructuredFolder_DocumentLoaders implements INode { const loader = new UnstructuredDirectoryLoader(folderPath, obj) const docs = await loader.load() + let elementTypes: string[] = [] + if (elementType) { + try { + elementTypes = JSON.parse(elementType) + } catch (e) { + elementTypes = [] + } + } + if (metadata) { const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) let finaldocs = [] @@ -83,10 +152,10 @@ class UnstructuredFolder_DocumentLoaders implements INode { } finaldocs.push(newdoc) } - return finaldocs + return elementTypes.length ? finaldocs.filter((doc) => elementTypes.includes(doc.metadata.category)) : finaldocs } - return docs + return elementTypes.length ? docs.filter((doc) => elementTypes.includes(doc.metadata.category)) : docs } } diff --git a/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts index 94e45d74..fcb1b2a5 100644 --- a/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts +++ b/packages/components/nodes/vectorstores/Elasticsearch/Elasticsearch_Existing.ts @@ -18,7 +18,7 @@ class ElasicsearchExisting_VectorStores extends ElasticSearchBase implements INo async constructVectorStore( embeddings: Embeddings, elasticSearchClientArgs: ElasticClientArgs, - docs: Document>[] | undefined + _: Document>[] | undefined ): Promise { return await ElasticVectorSearch.fromExistingIndex(embeddings, elasticSearchClientArgs) } diff --git a/packages/components/src/Interface.ts b/packages/components/src/Interface.ts index e883d056..d0694d6f 100644 --- a/packages/components/src/Interface.ts +++ b/packages/components/src/Interface.ts @@ -5,6 +5,7 @@ export type NodeParamsType = | 'asyncOptions' | 'options' + | 'multiOptions' | 'string' | 'number' | 'boolean' diff --git a/packages/ui/src/ui-component/dropdown/MultiDropdown.js b/packages/ui/src/ui-component/dropdown/MultiDropdown.js new file mode 100644 index 00000000..ff07b89f --- /dev/null +++ b/packages/ui/src/ui-component/dropdown/MultiDropdown.js @@ -0,0 +1,79 @@ +import { useState } from 'react' +import { useSelector } from 'react-redux' + +import { Popper, FormControl, TextField, Box, Typography } from '@mui/material' +import Autocomplete, { autocompleteClasses } from '@mui/material/Autocomplete' +import { styled } from '@mui/material/styles' +import PropTypes from 'prop-types' + +const StyledPopper = styled(Popper)({ + boxShadow: '0px 8px 10px -5px rgb(0 0 0 / 20%), 0px 16px 24px 2px rgb(0 0 0 / 14%), 0px 6px 30px 5px rgb(0 0 0 / 12%)', + borderRadius: '10px', + [`& .${autocompleteClasses.listbox}`]: { + boxSizing: 'border-box', + '& ul': { + padding: 10, + margin: 10 + } + } +}) + +export const MultiDropdown = ({ name, value, options, onSelect, disabled = false, disableClearable = false }) => { + const customization = useSelector((state) => state.customization) + const findMatchingOptions = (options = [], internalValue) => { + let values = [] + if (internalValue && typeof internalValue === 'string') values = JSON.parse(internalValue) + else values = internalValue + return options.filter((option) => values.includes(option.name)) + } + const getDefaultOptionValue = () => [] + let [internalValue, setInternalValue] = useState(value ?? []) + + return ( + + { + let value = '' + if (selections.length) { + const selectionNames = [] + for (let i = 0; i < selections.length; i += 1) { + selectionNames.push(selections[i].name) + } + value = JSON.stringify(selectionNames) + } + setInternalValue(value) + onSelect(value) + }} + PopperComponent={StyledPopper} + renderInput={(params) => } + renderOption={(props, option) => ( + +

+ {option.label} + {option.description && ( + {option.description} + )} +
+ + )} + /> + + ) +} + +MultiDropdown.propTypes = { + name: PropTypes.string, + value: PropTypes.string, + options: PropTypes.array, + onSelect: PropTypes.func, + disabled: PropTypes.bool, + disableClearable: PropTypes.bool +} diff --git a/packages/ui/src/utils/genericHelper.js b/packages/ui/src/utils/genericHelper.js index 324cc112..af7f4353 100644 --- a/packages/ui/src/utils/genericHelper.js +++ b/packages/ui/src/utils/genericHelper.js @@ -39,7 +39,20 @@ export const initNode = (nodeData, newNodeId) => { const incoming = nodeData.inputs ? nodeData.inputs.length : 0 const outgoing = 1 - const whitelistTypes = ['asyncOptions', 'options', 'string', 'number', 'boolean', 'password', 'json', 'code', 'date', 'file', 'folder'] + const whitelistTypes = [ + 'asyncOptions', + 'options', + 'multiOptions', + 'string', + 'number', + 'boolean', + 'password', + 'json', + 'code', + 'date', + 'file', + 'folder' + ] // Inputs for (let i = 0; i < incoming; i += 1) { diff --git a/packages/ui/src/views/canvas/NodeInputHandler.js b/packages/ui/src/views/canvas/NodeInputHandler.js index 176df52f..3a13a3b5 100644 --- a/packages/ui/src/views/canvas/NodeInputHandler.js +++ b/packages/ui/src/views/canvas/NodeInputHandler.js @@ -11,6 +11,7 @@ import { IconArrowsMaximize, IconEdit, IconAlertTriangle } from '@tabler/icons' // project import import { Dropdown } from 'ui-component/dropdown/Dropdown' +import { MultiDropdown } from 'ui-component/dropdown/MultiDropdown' import { AsyncDropdown } from 'ui-component/dropdown/AsyncDropdown' import { Input } from 'ui-component/input/Input' import { File } from 'ui-component/file/File' @@ -308,6 +309,15 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA value={data.inputs[inputParam.name] ?? inputParam.default ?? 'choose an option'} /> )} + {inputParam.type === 'multiOptions' && ( + (data.inputs[inputParam.name] = newValue)} + value={data.inputs[inputParam.name] ?? inputParam.default ?? 'choose an option'} + /> + )} {inputParam.type === 'asyncOptions' && ( <> {data.inputParams.length === 1 &&
} From 6a29ee8c025c44b6910df9721e4aeef479a11eab Mon Sep 17 00:00:00 2001 From: Ofer Mendelevitch Date: Thu, 12 Oct 2023 19:45:44 -0700 Subject: [PATCH 59/76] minor update to labels Upd 'source' in Vectara constructor --- .../nodes/vectorstores/Vectara/Vectara_Existing.ts | 5 +++-- .../components/nodes/vectorstores/Vectara/Vectara_Upload.ts | 3 ++- .../components/nodes/vectorstores/Vectara/Vectara_Upsert.ts | 3 ++- .../marketplaces/chatflows/Vectara LLM Chain Upload.json | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara_Existing.ts b/packages/components/nodes/vectorstores/Vectara/Vectara_Existing.ts index 122fcbd2..961c1796 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara_Existing.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara_Existing.ts @@ -32,7 +32,7 @@ class VectaraExisting_VectorStores implements INode { } this.inputs = [ { - label: 'Vectara Metadata Filter', + label: 'Metadata Filter', name: 'filter', description: 'Filter to apply to Vectara metadata. Refer to the documentation on how to use Vectara filters with Flowise.', @@ -105,7 +105,8 @@ class VectaraExisting_VectorStores implements INode { const vectaraArgs: VectaraLibArgs = { apiKey: apiKey, customerId: customerId, - corpusId: corpusId + corpusId: corpusId, + source: "flowise" } const vectaraFilter: VectaraFilter = {} diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts b/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts index 56cfbcff..10c00cdf 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts @@ -113,7 +113,8 @@ class VectaraUpload_VectorStores implements INode { const vectaraArgs: VectaraLibArgs = { apiKey: apiKey, customerId: customerId, - corpusId: corpusId + corpusId: corpusId, + source: "flowise", } const vectaraFilter: VectaraFilter = {} diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts b/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts index 9918fff2..c0b95b7d 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts @@ -116,7 +116,8 @@ class VectaraUpsert_VectorStores implements INode { const vectaraArgs: VectaraLibArgs = { apiKey: apiKey, customerId: customerId, - corpusId: corpusId + corpusId: corpusId, + source: "flowise" } const vectaraFilter: VectaraFilter = {} diff --git a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json index dc1c1e17..5fc540b0 100644 --- a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json +++ b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json @@ -32,7 +32,7 @@ "id": "vectaraUpload_0-input-file-file" }, { - "label": "Vectara Metadata Filter", + "label": "Metadata Filter", "name": "filter", "description": "Filter to apply to Vectara metadata. Refer to the documentation on how to use Vectara filters with Flowise.", "type": "string", From 7ba38c08762fdf62715f8536b6b9e106e29d3bc0 Mon Sep 17 00:00:00 2001 From: Ofer Mendelevitch Date: Thu, 12 Oct 2023 19:48:20 -0700 Subject: [PATCH 60/76] updated --- .../components/nodes/vectorstores/Vectara/Vectara_Upload.ts | 2 +- .../components/nodes/vectorstores/Vectara/Vectara_Upsert.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts b/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts index 10c00cdf..23903c71 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts @@ -39,7 +39,7 @@ class VectaraUpload_VectorStores implements INode { type: 'file' }, { - label: 'Vectara Metadata Filter', + label: 'Metadata Filter', name: 'filter', description: 'Filter to apply to Vectara metadata. Refer to the documentation on how to use Vectara filters with Flowise.', diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts b/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts index c0b95b7d..83700326 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts @@ -41,7 +41,7 @@ class VectaraUpsert_VectorStores implements INode { list: true }, { - label: 'Vectara Metadata Filter', + label: 'Metadata Filter', name: 'filter', description: 'Filter to apply to Vectara metadata. Refer to the documentation on how to use Vectara filters with Flowise.', From e3d4c73b2ab5bfeb135a6795f8225f1a77b93212 Mon Sep 17 00:00:00 2001 From: Ofer Mendelevitch Date: Thu, 12 Oct 2023 20:11:01 -0700 Subject: [PATCH 61/76] updated to single quotes --- .../components/nodes/vectorstores/Vectara/Vectara_Existing.ts | 2 +- .../components/nodes/vectorstores/Vectara/Vectara_Upload.ts | 2 +- .../components/nodes/vectorstores/Vectara/Vectara_Upsert.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara_Existing.ts b/packages/components/nodes/vectorstores/Vectara/Vectara_Existing.ts index 961c1796..4448aa5c 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara_Existing.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara_Existing.ts @@ -106,7 +106,7 @@ class VectaraExisting_VectorStores implements INode { apiKey: apiKey, customerId: customerId, corpusId: corpusId, - source: "flowise" + source: 'flowise' } const vectaraFilter: VectaraFilter = {} diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts b/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts index 23903c71..f4f3ab82 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts @@ -114,7 +114,7 @@ class VectaraUpload_VectorStores implements INode { apiKey: apiKey, customerId: customerId, corpusId: corpusId, - source: "flowise", + source: 'flowise', } const vectaraFilter: VectaraFilter = {} diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts b/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts index 83700326..3e035a51 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts @@ -117,7 +117,7 @@ class VectaraUpsert_VectorStores implements INode { apiKey: apiKey, customerId: customerId, corpusId: corpusId, - source: "flowise" + source: 'flowise' } const vectaraFilter: VectaraFilter = {} From db475039c24cc8b3634bd22bd4f4f41f4de6ecf6 Mon Sep 17 00:00:00 2001 From: Ofer Mendelevitch Date: Thu, 12 Oct 2023 20:23:17 -0700 Subject: [PATCH 62/76] removed extra comma --- .../components/nodes/vectorstores/Vectara/Vectara_Upload.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts b/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts index f4f3ab82..39104b9d 100644 --- a/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts +++ b/packages/components/nodes/vectorstores/Vectara/Vectara_Upload.ts @@ -114,7 +114,7 @@ class VectaraUpload_VectorStores implements INode { apiKey: apiKey, customerId: customerId, corpusId: corpusId, - source: 'flowise', + source: 'flowise' } const vectaraFilter: VectaraFilter = {} From 98fa249721951a56238f73e3831bcb8ad21b189e Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 13 Oct 2023 15:42:21 +0100 Subject: [PATCH 63/76] fix Illegal Invocation --- .../nodes/cache/RedisCache/RedisCache.ts | 69 ++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/cache/RedisCache/RedisCache.ts b/packages/components/nodes/cache/RedisCache/RedisCache.ts index da2dfc49..38998a46 100644 --- a/packages/components/nodes/cache/RedisCache/RedisCache.ts +++ b/packages/components/nodes/cache/RedisCache/RedisCache.ts @@ -1,6 +1,8 @@ import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' import { RedisCache as LangchainRedisCache } from 'langchain/cache/ioredis' import { Redis } from 'ioredis' +import { Generation, ChatGeneration, StoredGeneration, mapStoredMessageToChatMessage } from 'langchain/schema' +import hash from 'object-hash' class RedisCache implements INode { label: string @@ -30,10 +32,21 @@ class RedisCache implements INode { optional: true, credentialNames: ['redisCacheApi'] } - this.inputs = [] + this.inputs = [ + { + label: 'Time to Live (ms)', + name: 'ttl', + type: 'number', + step: 1, + optional: true, + additionalParams: true + } + ] } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const ttl = nodeData.inputs?.ttl as string + const credentialData = await getCredentialData(nodeData.credential ?? '', options) const username = getCredentialParam('redisCacheUser', credentialData, nodeData) const password = getCredentialParam('redisCachePwd', credentialData, nodeData) @@ -46,8 +59,60 @@ class RedisCache implements INode { username, password }) - return new LangchainRedisCache(client) + + const redisClient = new LangchainRedisCache(client) + + redisClient.lookup = async (prompt: string, llmKey: string) => { + let idx = 0 + let key = getCacheKey(prompt, llmKey, String(idx)) + let value = await client.get(key) + const generations: Generation[] = [] + + while (value) { + const storedGeneration = JSON.parse(value) + generations.push(deserializeStoredGeneration(storedGeneration)) + idx += 1 + key = getCacheKey(prompt, llmKey, String(idx)) + value = await client.get(key) + } + + return generations.length > 0 ? generations : null + } + + redisClient.update = async (prompt: string, llmKey: string, value: Generation[]) => { + for (let i = 0; i < value.length; i += 1) { + const key = getCacheKey(prompt, llmKey, String(i)) + if (ttl !== undefined) { + await client.set(key, JSON.stringify(serializeGeneration(value[i])), 'EX', parseInt(ttl, 10)) + } else { + await client.set(key, JSON.stringify(serializeGeneration(value[i]))) + } + } + } + + return redisClient } } +const getCacheKey = (...strings: string[]): string => hash(strings.join('_')) +const deserializeStoredGeneration = (storedGeneration: StoredGeneration) => { + if (storedGeneration.message !== undefined) { + return { + text: storedGeneration.text, + message: mapStoredMessageToChatMessage(storedGeneration.message) + } + } else { + return { text: storedGeneration.text } + } +} +const serializeGeneration = (generation: Generation) => { + const serializedValue: StoredGeneration = { + text: generation.text + } + if ((generation as ChatGeneration).message !== undefined) { + serializedValue.message = (generation as ChatGeneration).message.toDict() + } + return serializedValue +} + module.exports = { nodeClass: RedisCache } From f822745e38862cd6b8e1dbcba8d304e90ddd86e3 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 13 Oct 2023 15:58:10 +0100 Subject: [PATCH 64/76] update marketplaces --- .../Conversational Retrieval QA Chain.json | 28 +++++++++++++++---- .../marketplaces/chatflows/Local QnA.json | 26 +++++++++++++---- .../chatflows/Metadata Filter Upsert.json | 26 +++++++++++++---- .../marketplaces/chatflows/WebPage QnA.json | 11 +++++++- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json index 725ca7c9..8bbb904e 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json @@ -426,7 +426,7 @@ "id": "textFile_0", "label": "Text File", "name": "textFile", - "version": 1, + "version": 2, "type": "Document", "baseClasses": ["Document"], "category": "Document Loaders", @@ -463,13 +463,29 @@ }, "outputAnchors": [ { - "id": "textFile_0-output-textFile-Document", - "name": "textFile", - "label": "Document", - "type": "Document" + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "textFile_0-output-document-Document", + "name": "document", + "label": "Document", + "type": "Document" + }, + { + "id": "textFile_0-output-text-string|json", + "name": "text", + "label": "Text", + "type": "string | json" + } + ], + "default": "document" } ], - "outputs": {}, + "outputs": { + "output": "document" + }, "selected": false }, "selected": false, diff --git a/packages/server/marketplaces/chatflows/Local QnA.json b/packages/server/marketplaces/chatflows/Local QnA.json index 21bdf744..fb13ba21 100644 --- a/packages/server/marketplaces/chatflows/Local QnA.json +++ b/packages/server/marketplaces/chatflows/Local QnA.json @@ -410,13 +410,29 @@ }, "outputAnchors": [ { - "id": "textFile_0-output-textFile-Document", - "name": "textFile", - "label": "Document", - "type": "Document" + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "textFile_0-output-document-Document", + "name": "document", + "label": "Document", + "type": "Document" + }, + { + "id": "textFile_0-output-text-string|json", + "name": "text", + "label": "Text", + "type": "string | json" + } + ], + "default": "document" } ], - "outputs": {}, + "outputs": { + "output": "document" + }, "selected": false }, "selected": false, diff --git a/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json b/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json index 525fa1b9..6e79301e 100644 --- a/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json +++ b/packages/server/marketplaces/chatflows/Metadata Filter Upsert.json @@ -109,13 +109,29 @@ }, "outputAnchors": [ { - "id": "textFile_0-output-textFile-Document", - "name": "textFile", - "label": "Document", - "type": "Document" + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "textFile_0-output-document-Document", + "name": "document", + "label": "Document", + "type": "Document" + }, + { + "id": "textFile_0-output-text-string|json", + "name": "text", + "label": "Text", + "type": "string | json" + } + ], + "default": "document" } ], - "outputs": {}, + "outputs": { + "output": "document" + }, "selected": false }, "selected": false, diff --git a/packages/server/marketplaces/chatflows/WebPage QnA.json b/packages/server/marketplaces/chatflows/WebPage QnA.json index 66bac37f..da21cb2d 100644 --- a/packages/server/marketplaces/chatflows/WebPage QnA.json +++ b/packages/server/marketplaces/chatflows/WebPage QnA.json @@ -433,7 +433,7 @@ "data": { "id": "cheerioWebScraper_0", "label": "Cheerio Web Scraper", - "version": 1, + "version": 1.1, "name": "cheerioWebScraper", "type": "Document", "baseClasses": ["Document"], @@ -477,6 +477,15 @@ "warning": "Retrieving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)", "id": "cheerioWebScraper_0-input-limit-number" }, + { + "label": "Selector (CSS)", + "name": "selector", + "type": "string", + "description": "Specify a CSS selector to select the content to be extracted", + "optional": true, + "additionalParams": true, + "id": "cheerioWebScraper_0-input-selector-string" + }, { "label": "Metadata", "name": "metadata", From baa3d2afac6bc8d447fba6a9768cb194a4a57101 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 13 Oct 2023 16:23:50 +0100 Subject: [PATCH 65/76] minor convert chat history to text empty array fix --- packages/components/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/utils.ts b/packages/components/src/utils.ts index 3ff57b06..8f33683c 100644 --- a/packages/components/src/utils.ts +++ b/packages/components/src/utils.ts @@ -533,7 +533,7 @@ export const mapChatHistory = (options: ICommonObject): ChatMessageHistory => { * @param {IMessage[]} chatHistory * @returns {string} */ -export const convertChatHistoryToText = (chatHistory: IMessage[]): string => { +export const convertChatHistoryToText = (chatHistory: IMessage[] = []): string => { return chatHistory .map((chatMessage) => { if (chatMessage.type === 'apiMessage') { From e0a1188857d044e2c2d3d5e34fb441134b86fe24 Mon Sep 17 00:00:00 2001 From: automaton82 Date: Fri, 13 Oct 2023 14:30:08 -0400 Subject: [PATCH 66/76] Fix for #911, CRLF line endings on linux scripts. --- packages/server/bin/dev | 0 packages/server/bin/run | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 packages/server/bin/dev mode change 100755 => 100644 packages/server/bin/run diff --git a/packages/server/bin/dev b/packages/server/bin/dev old mode 100755 new mode 100644 diff --git a/packages/server/bin/run b/packages/server/bin/run old mode 100755 new mode 100644 From 76f689cb93272e1715f8e74d5a565e70fb5e9dab Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 13 Oct 2023 21:33:32 +0100 Subject: [PATCH 67/76] add fix for illegal invocation --- .../OpenSearch_Upsert.ts | 40 +++++++++++++- .../OpenSearch_existing.ts | 52 +++++++++++++++++- .../nodes/vectorstores/OpenSearch/core.ts | 8 +++ .../opensearch.png | Bin .../OpenSearch_Upsert/opensearch.png | Bin 5216 -> 0 bytes 5 files changed, 97 insertions(+), 3 deletions(-) rename packages/components/nodes/vectorstores/{OpenSearch_Upsert => OpenSearch}/OpenSearch_Upsert.ts (73%) rename packages/components/nodes/vectorstores/{OpenSearch_Existing => OpenSearch}/OpenSearch_existing.ts (62%) create mode 100644 packages/components/nodes/vectorstores/OpenSearch/core.ts rename packages/components/nodes/vectorstores/{OpenSearch_Existing => OpenSearch}/opensearch.png (100%) delete mode 100644 packages/components/nodes/vectorstores/OpenSearch_Upsert/opensearch.png diff --git a/packages/components/nodes/vectorstores/OpenSearch_Upsert/OpenSearch_Upsert.ts b/packages/components/nodes/vectorstores/OpenSearch/OpenSearch_Upsert.ts similarity index 73% rename from packages/components/nodes/vectorstores/OpenSearch_Upsert/OpenSearch_Upsert.ts rename to packages/components/nodes/vectorstores/OpenSearch/OpenSearch_Upsert.ts index c11d8b11..6cb77414 100644 --- a/packages/components/nodes/vectorstores/OpenSearch_Upsert/OpenSearch_Upsert.ts +++ b/packages/components/nodes/vectorstores/OpenSearch/OpenSearch_Upsert.ts @@ -2,9 +2,10 @@ import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/I import { OpenSearchVectorStore } from 'langchain/vectorstores/opensearch' import { Embeddings } from 'langchain/embeddings/base' import { Document } from 'langchain/document' -import { Client } from '@opensearch-project/opensearch' +import { Client, RequestParams } from '@opensearch-project/opensearch' import { flatten } from 'lodash' import { getBaseClasses } from '../../../src/utils' +import { buildMetadataTerms } from './core' class OpenSearchUpsert_VectorStores implements INode { label: string @@ -95,9 +96,44 @@ class OpenSearchUpsert_VectorStores implements INode { const vectorStore = await OpenSearchVectorStore.fromDocuments(finalDocs, embeddings, { client, - indexName: indexName + indexName }) + vectorStore.similaritySearchVectorWithScore = async ( + query: number[], + k: number, + filter?: object | undefined + ): Promise<[Document, number][]> => { + const search: RequestParams.Search = { + index: indexName, + body: { + query: { + bool: { + filter: { bool: { must: buildMetadataTerms(filter) } }, + must: [ + { + knn: { + embedding: { vector: query, k } + } + } + ] + } + }, + size: k + } + } + + const { body } = await client.search(search) + + return body.hits.hits.map((hit: any) => [ + new Document({ + pageContent: hit._source.text, + metadata: hit._source.metadata + }), + hit._score + ]) + } + if (output === 'retriever') { const retriever = vectorStore.asRetriever(k) return retriever diff --git a/packages/components/nodes/vectorstores/OpenSearch_Existing/OpenSearch_existing.ts b/packages/components/nodes/vectorstores/OpenSearch/OpenSearch_existing.ts similarity index 62% rename from packages/components/nodes/vectorstores/OpenSearch_Existing/OpenSearch_existing.ts rename to packages/components/nodes/vectorstores/OpenSearch/OpenSearch_existing.ts index c8d09470..aeab0e3f 100644 --- a/packages/components/nodes/vectorstores/OpenSearch_Existing/OpenSearch_existing.ts +++ b/packages/components/nodes/vectorstores/OpenSearch/OpenSearch_existing.ts @@ -1,8 +1,10 @@ import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { OpenSearchVectorStore } from 'langchain/vectorstores/opensearch' import { Embeddings } from 'langchain/embeddings/base' -import { Client } from '@opensearch-project/opensearch' +import { Document } from 'langchain/document' +import { Client, RequestParams } from '@opensearch-project/opensearch' import { getBaseClasses } from '../../../src/utils' +import { buildMetadataTerms } from './core' class OpenSearch_Existing_VectorStores implements INode { label: string @@ -42,6 +44,13 @@ class OpenSearch_Existing_VectorStores implements INode { name: 'indexName', type: 'string' }, + { + label: 'OpenSearch Metadata Filter', + name: 'openSearchMetadataFilter', + type: 'json', + optional: true, + additionalParams: true + }, { label: 'Top K', name: 'topK', @@ -73,6 +82,7 @@ class OpenSearch_Existing_VectorStores implements INode { const output = nodeData.outputs?.output as string const topK = nodeData.inputs?.topK as string const k = topK ? parseFloat(topK) : 4 + const openSearchMetadataFilter = nodeData.inputs?.openSearchMetadataFilter const client = new Client({ nodes: [opensearchURL] @@ -83,6 +93,46 @@ class OpenSearch_Existing_VectorStores implements INode { indexName }) + vectorStore.similaritySearchVectorWithScore = async ( + query: number[], + k: number, + filter?: object | undefined + ): Promise<[Document, number][]> => { + if (openSearchMetadataFilter) { + const metadatafilter = + typeof openSearchMetadataFilter === 'object' ? openSearchMetadataFilter : JSON.parse(openSearchMetadataFilter) + filter = metadatafilter + } + const search: RequestParams.Search = { + index: indexName, + body: { + query: { + bool: { + filter: { bool: { must: buildMetadataTerms(filter) } }, + must: [ + { + knn: { + embedding: { vector: query, k } + } + } + ] + } + }, + size: k + } + } + + const { body } = await client.search(search) + + return body.hits.hits.map((hit: any) => [ + new Document({ + pageContent: hit._source.text, + metadata: hit._source.metadata + }), + hit._score + ]) + } + if (output === 'retriever') { const retriever = vectorStore.asRetriever(k) return retriever diff --git a/packages/components/nodes/vectorstores/OpenSearch/core.ts b/packages/components/nodes/vectorstores/OpenSearch/core.ts new file mode 100644 index 00000000..49a1d6e3 --- /dev/null +++ b/packages/components/nodes/vectorstores/OpenSearch/core.ts @@ -0,0 +1,8 @@ +export const buildMetadataTerms = (filter?: object): { term: Record }[] => { + if (filter == null) return [] + const result = [] + for (const [key, value] of Object.entries(filter)) { + result.push({ term: { [`metadata.${key}`]: value } }) + } + return result +} diff --git a/packages/components/nodes/vectorstores/OpenSearch_Existing/opensearch.png b/packages/components/nodes/vectorstores/OpenSearch/opensearch.png similarity index 100% rename from packages/components/nodes/vectorstores/OpenSearch_Existing/opensearch.png rename to packages/components/nodes/vectorstores/OpenSearch/opensearch.png diff --git a/packages/components/nodes/vectorstores/OpenSearch_Upsert/opensearch.png b/packages/components/nodes/vectorstores/OpenSearch_Upsert/opensearch.png deleted file mode 100644 index 3fdcfd3f09ed02c1478f690884ecafe844cb32ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5216 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 Date: Sat, 14 Oct 2023 01:04:00 +0100 Subject: [PATCH 68/76] update langfuse initialization types --- packages/components/src/handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index 236b423f..37075342 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -244,7 +244,7 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO const langFusePublicKey = getCredentialParam('langFusePublicKey', credentialData, nodeData) const langFuseEndpoint = getCredentialParam('langFuseEndpoint', credentialData, nodeData) - const langFuseOptions: ICommonObject = { + const langFuseOptions: any = { secretKey: langFuseSecretKey, publicKey: langFusePublicKey, baseUrl: langFuseEndpoint ?? 'https://cloud.langfuse.com' From 49d5a86fcc7a70ac58f54d7afba3104ca4613974 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Sat, 14 Oct 2023 23:17:08 +0100 Subject: [PATCH 69/76] Revert "Fix for #911, CRLF line endings on Linux scripts." --- packages/server/bin/dev | 0 packages/server/bin/run | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 packages/server/bin/dev mode change 100644 => 100755 packages/server/bin/run diff --git a/packages/server/bin/dev b/packages/server/bin/dev old mode 100644 new mode 100755 diff --git a/packages/server/bin/run b/packages/server/bin/run old mode 100644 new mode 100755 From b34856b71b43dcfa43fd6db40d97f910cea9d756 Mon Sep 17 00:00:00 2001 From: Yavisht Katgara Date: Mon, 16 Oct 2023 18:32:25 +1100 Subject: [PATCH 70/76] fix: ChatPromptTemplate function name --- .../nodes/chains/ConversationChain/ConversationChain.ts | 2 +- .../nodes/prompts/ChatPromptTemplate/ChatPromptTemplate.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index 1cd15c9a..f12cd30b 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -90,7 +90,7 @@ class ConversationChain_Chains implements INode { verbose: process.env.DEBUG === 'true' ? true : false } - const chatPrompt = ChatPromptTemplate.fromPromptMessages([ + const chatPrompt = ChatPromptTemplate.fromMessages([ SystemMessagePromptTemplate.fromTemplate(prompt ? `${prompt}\n${systemMessage}` : systemMessage), new MessagesPlaceholder(memory.memoryKey ?? 'chat_history'), HumanMessagePromptTemplate.fromTemplate('{input}') diff --git a/packages/components/nodes/prompts/ChatPromptTemplate/ChatPromptTemplate.ts b/packages/components/nodes/prompts/ChatPromptTemplate/ChatPromptTemplate.ts index c9ec751d..83e1a857 100644 --- a/packages/components/nodes/prompts/ChatPromptTemplate/ChatPromptTemplate.ts +++ b/packages/components/nodes/prompts/ChatPromptTemplate/ChatPromptTemplate.ts @@ -53,7 +53,7 @@ class ChatPromptTemplate_Prompts implements INode { const humanMessagePrompt = nodeData.inputs?.humanMessagePrompt as string const promptValuesStr = nodeData.inputs?.promptValues as string - const prompt = ChatPromptTemplate.fromPromptMessages([ + const prompt = ChatPromptTemplate.fromMessages([ SystemMessagePromptTemplate.fromTemplate(systemMessagePrompt), HumanMessagePromptTemplate.fromTemplate(humanMessagePrompt) ]) From ff26d658d2f86a9784a83b7093e99b4201c5d478 Mon Sep 17 00:00:00 2001 From: Kenneth Petersen <112469337+KeLeKaPe@users.noreply.github.com> Date: Mon, 16 Oct 2023 14:06:04 +0200 Subject: [PATCH 71/76] Add missing env variables for database to work in container --- docker/docker-compose.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 137b1183..8e0e1af5 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -10,6 +10,12 @@ services: - FLOWISE_PASSWORD=${FLOWISE_PASSWORD} - DEBUG=${DEBUG} - DATABASE_PATH=${DATABASE_PATH} + - DATABASE_TYPE=${DATABASE_TYPE} + - DATABASE_PORT=${DATABASE_PORT} + - DATABASE_HOST=${DATABASE_HOST} + - DATABASE_NAME=${DATABASE_NAME} + - DATABASE_USER=${DATABASE_USER} + - DATABASE_PASSWORD=${DATABASE_PASSWORD} - APIKEY_PATH=${APIKEY_PATH} - SECRETKEY_PATH=${SECRETKEY_PATH} - FLOWISE_SECRETKEY_OVERWRITE=${FLOWISE_SECRETKEY_OVERWRITE} From 1595676c61fc70d4418d6391d111d830563006e5 Mon Sep 17 00:00:00 2001 From: automaton82 Date: Mon, 16 Oct 2023 16:30:25 -0400 Subject: [PATCH 72/76] Fix for #911, CRLF line endings, new fix. --- packages/server/bin/.gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 packages/server/bin/.gitattributes diff --git a/packages/server/bin/.gitattributes b/packages/server/bin/.gitattributes new file mode 100644 index 00000000..473187f2 --- /dev/null +++ b/packages/server/bin/.gitattributes @@ -0,0 +1,2 @@ +dev eol=lf +run eol=lf \ No newline at end of file From 2f021b48373b66df3622edffe3df05cf865d2459 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 17 Oct 2023 23:43:22 +0100 Subject: [PATCH 73/76] add custom separators --- .../CharacterTextSplitter.ts | 14 ++++++++------ .../RecursiveCharacterTextSplitter.ts | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/packages/components/nodes/textsplitters/CharacterTextSplitter/CharacterTextSplitter.ts b/packages/components/nodes/textsplitters/CharacterTextSplitter/CharacterTextSplitter.ts index f9427d10..ed972ad6 100644 --- a/packages/components/nodes/textsplitters/CharacterTextSplitter/CharacterTextSplitter.ts +++ b/packages/components/nodes/textsplitters/CharacterTextSplitter/CharacterTextSplitter.ts @@ -23,12 +23,6 @@ class CharacterTextSplitter_TextSplitters implements INode { this.description = `splits only on one type of character (defaults to "\\n\\n").` this.baseClasses = [this.type, ...getBaseClasses(CharacterTextSplitter)] this.inputs = [ - { - label: 'Separator', - name: 'separator', - type: 'string', - optional: true - }, { label: 'Chunk Size', name: 'chunkSize', @@ -41,6 +35,14 @@ class CharacterTextSplitter_TextSplitters implements INode { name: 'chunkOverlap', type: 'number', optional: true + }, + { + label: 'Custom Separator', + name: 'separator', + type: 'string', + placeholder: `" "`, + description: 'Seperator to determine when to split the text, will override the default separator', + optional: true } ] } diff --git a/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/RecursiveCharacterTextSplitter.ts b/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/RecursiveCharacterTextSplitter.ts index dcca70ba..ec9095b6 100644 --- a/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/RecursiveCharacterTextSplitter.ts +++ b/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/RecursiveCharacterTextSplitter.ts @@ -16,7 +16,7 @@ class RecursiveCharacterTextSplitter_TextSplitters implements INode { constructor() { this.label = 'Recursive Character Text Splitter' this.name = 'recursiveCharacterTextSplitter' - this.version = 1.0 + this.version = 2.0 this.type = 'RecursiveCharacterTextSplitter' this.icon = 'textsplitter.svg' this.category = 'Text Splitters' @@ -35,6 +35,15 @@ class RecursiveCharacterTextSplitter_TextSplitters implements INode { name: 'chunkOverlap', type: 'number', optional: true + }, + { + label: 'Custom Separators', + name: 'separators', + type: 'string', + rows: 4, + description: 'Array of custom seperators to determine when to split the text, will override the default separators', + placeholder: `["|", "##", ">", "-"]`, + optional: true } ] } @@ -42,11 +51,19 @@ class RecursiveCharacterTextSplitter_TextSplitters implements INode { async init(nodeData: INodeData): Promise { const chunkSize = nodeData.inputs?.chunkSize as string const chunkOverlap = nodeData.inputs?.chunkOverlap as string + const separators = nodeData.inputs?.separators as string const obj = {} as RecursiveCharacterTextSplitterParams if (chunkSize) obj.chunkSize = parseInt(chunkSize, 10) if (chunkOverlap) obj.chunkOverlap = parseInt(chunkOverlap, 10) + if (separators) { + try { + obj.separators = JSON.parse(separators) + } catch (e) { + throw new Error(e) + } + } const splitter = new RecursiveCharacterTextSplitter(obj) From 21f6209a1be18a66574b8ffb6db466d8fb556cff Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Wed, 18 Oct 2023 10:58:36 +0530 Subject: [PATCH 74/76] Embeddings Cache Feature - RedisEmbeddingsCache --- .../cache/RedisCache/RedisEmbeddingsCache.ts | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 packages/components/nodes/cache/RedisCache/RedisEmbeddingsCache.ts diff --git a/packages/components/nodes/cache/RedisCache/RedisEmbeddingsCache.ts b/packages/components/nodes/cache/RedisCache/RedisEmbeddingsCache.ts new file mode 100644 index 00000000..4eecb1f5 --- /dev/null +++ b/packages/components/nodes/cache/RedisCache/RedisEmbeddingsCache.ts @@ -0,0 +1,90 @@ +import { getBaseClasses, getCredentialData, getCredentialParam, ICommonObject, INode, INodeData, INodeParams } from '../../../src' +import { Redis } from 'ioredis' +import { CacheBackedEmbeddings } from 'langchain/embeddings/cache_backed' +import { RedisByteStore } from 'langchain/storage/ioredis' +import { Embeddings } from 'langchain/embeddings/base' + +class RedisEmbeddingsCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + + constructor() { + this.label = 'Redis Embeddings Cache' + this.name = 'redisEmbeddingsCache' + this.version = 1.0 + this.type = 'RedisEmbeddingsCache' + this.description = 'Cache generated Embeddings in Redis to avoid needing to recompute them.' + this.icon = 'redis.svg' + this.category = 'Cache' + this.baseClasses = [this.type, ...getBaseClasses(CacheBackedEmbeddings)] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + credentialNames: ['redisCacheApi'] + } + this.inputs = [ + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Time to Live (ms)', + name: 'ttl', + type: 'number', + step: 10, + default: 60 * 60, + optional: true, + additionalParams: true + }, + { + label: 'Namespace', + name: 'namespace', + type: 'string', + optional: true, + additionalParams: true + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + let ttl = nodeData.inputs?.ttl as string + const namespace = nodeData.inputs?.namespace as string + const underlyingEmbeddings = nodeData.inputs?.embeddings as Embeddings + + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const username = getCredentialParam('redisCacheUser', credentialData, nodeData) + const password = getCredentialParam('redisCachePwd', credentialData, nodeData) + const portStr = getCredentialParam('redisCachePort', credentialData, nodeData) + const host = getCredentialParam('redisCacheHost', credentialData, nodeData) + + const client = new Redis({ + port: portStr ? parseInt(portStr) : 6379, + host, + username, + password + }) + ttl ??= '3600' + let ttlNumber = parseInt(ttl, 10) + const redisStore = new RedisByteStore({ + client: client, + ttl: ttlNumber + }) + + return CacheBackedEmbeddings.fromBytesStore(underlyingEmbeddings, redisStore, { + namespace: namespace + }) + } +} + +module.exports = { nodeClass: RedisEmbeddingsCache } From 88d7cb47e2c1b5a1082b9d9db3aafbf463b939ec Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Wed, 18 Oct 2023 13:39:23 +0100 Subject: [PATCH 75/76] Revert "Bugfix/OpenSearch illegal invocation" --- .../nodes/vectorstores/OpenSearch/core.ts | 8 --- .../OpenSearch_existing.ts | 52 +----------------- .../opensearch.png | Bin .../OpenSearch_Upsert.ts | 40 +------------- .../OpenSearch_Upsert/opensearch.png | Bin 0 -> 5216 bytes 5 files changed, 3 insertions(+), 97 deletions(-) delete mode 100644 packages/components/nodes/vectorstores/OpenSearch/core.ts rename packages/components/nodes/vectorstores/{OpenSearch => OpenSearch_Existing}/OpenSearch_existing.ts (62%) rename packages/components/nodes/vectorstores/{OpenSearch => OpenSearch_Existing}/opensearch.png (100%) rename packages/components/nodes/vectorstores/{OpenSearch => OpenSearch_Upsert}/OpenSearch_Upsert.ts (73%) create mode 100644 packages/components/nodes/vectorstores/OpenSearch_Upsert/opensearch.png diff --git a/packages/components/nodes/vectorstores/OpenSearch/core.ts b/packages/components/nodes/vectorstores/OpenSearch/core.ts deleted file mode 100644 index 49a1d6e3..00000000 --- a/packages/components/nodes/vectorstores/OpenSearch/core.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const buildMetadataTerms = (filter?: object): { term: Record }[] => { - if (filter == null) return [] - const result = [] - for (const [key, value] of Object.entries(filter)) { - result.push({ term: { [`metadata.${key}`]: value } }) - } - return result -} diff --git a/packages/components/nodes/vectorstores/OpenSearch/OpenSearch_existing.ts b/packages/components/nodes/vectorstores/OpenSearch_Existing/OpenSearch_existing.ts similarity index 62% rename from packages/components/nodes/vectorstores/OpenSearch/OpenSearch_existing.ts rename to packages/components/nodes/vectorstores/OpenSearch_Existing/OpenSearch_existing.ts index aeab0e3f..c8d09470 100644 --- a/packages/components/nodes/vectorstores/OpenSearch/OpenSearch_existing.ts +++ b/packages/components/nodes/vectorstores/OpenSearch_Existing/OpenSearch_existing.ts @@ -1,10 +1,8 @@ import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { OpenSearchVectorStore } from 'langchain/vectorstores/opensearch' import { Embeddings } from 'langchain/embeddings/base' -import { Document } from 'langchain/document' -import { Client, RequestParams } from '@opensearch-project/opensearch' +import { Client } from '@opensearch-project/opensearch' import { getBaseClasses } from '../../../src/utils' -import { buildMetadataTerms } from './core' class OpenSearch_Existing_VectorStores implements INode { label: string @@ -44,13 +42,6 @@ class OpenSearch_Existing_VectorStores implements INode { name: 'indexName', type: 'string' }, - { - label: 'OpenSearch Metadata Filter', - name: 'openSearchMetadataFilter', - type: 'json', - optional: true, - additionalParams: true - }, { label: 'Top K', name: 'topK', @@ -82,7 +73,6 @@ class OpenSearch_Existing_VectorStores implements INode { const output = nodeData.outputs?.output as string const topK = nodeData.inputs?.topK as string const k = topK ? parseFloat(topK) : 4 - const openSearchMetadataFilter = nodeData.inputs?.openSearchMetadataFilter const client = new Client({ nodes: [opensearchURL] @@ -93,46 +83,6 @@ class OpenSearch_Existing_VectorStores implements INode { indexName }) - vectorStore.similaritySearchVectorWithScore = async ( - query: number[], - k: number, - filter?: object | undefined - ): Promise<[Document, number][]> => { - if (openSearchMetadataFilter) { - const metadatafilter = - typeof openSearchMetadataFilter === 'object' ? openSearchMetadataFilter : JSON.parse(openSearchMetadataFilter) - filter = metadatafilter - } - const search: RequestParams.Search = { - index: indexName, - body: { - query: { - bool: { - filter: { bool: { must: buildMetadataTerms(filter) } }, - must: [ - { - knn: { - embedding: { vector: query, k } - } - } - ] - } - }, - size: k - } - } - - const { body } = await client.search(search) - - return body.hits.hits.map((hit: any) => [ - new Document({ - pageContent: hit._source.text, - metadata: hit._source.metadata - }), - hit._score - ]) - } - if (output === 'retriever') { const retriever = vectorStore.asRetriever(k) return retriever diff --git a/packages/components/nodes/vectorstores/OpenSearch/opensearch.png b/packages/components/nodes/vectorstores/OpenSearch_Existing/opensearch.png similarity index 100% rename from packages/components/nodes/vectorstores/OpenSearch/opensearch.png rename to packages/components/nodes/vectorstores/OpenSearch_Existing/opensearch.png diff --git a/packages/components/nodes/vectorstores/OpenSearch/OpenSearch_Upsert.ts b/packages/components/nodes/vectorstores/OpenSearch_Upsert/OpenSearch_Upsert.ts similarity index 73% rename from packages/components/nodes/vectorstores/OpenSearch/OpenSearch_Upsert.ts rename to packages/components/nodes/vectorstores/OpenSearch_Upsert/OpenSearch_Upsert.ts index 6cb77414..c11d8b11 100644 --- a/packages/components/nodes/vectorstores/OpenSearch/OpenSearch_Upsert.ts +++ b/packages/components/nodes/vectorstores/OpenSearch_Upsert/OpenSearch_Upsert.ts @@ -2,10 +2,9 @@ import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/I import { OpenSearchVectorStore } from 'langchain/vectorstores/opensearch' import { Embeddings } from 'langchain/embeddings/base' import { Document } from 'langchain/document' -import { Client, RequestParams } from '@opensearch-project/opensearch' +import { Client } from '@opensearch-project/opensearch' import { flatten } from 'lodash' import { getBaseClasses } from '../../../src/utils' -import { buildMetadataTerms } from './core' class OpenSearchUpsert_VectorStores implements INode { label: string @@ -96,44 +95,9 @@ class OpenSearchUpsert_VectorStores implements INode { const vectorStore = await OpenSearchVectorStore.fromDocuments(finalDocs, embeddings, { client, - indexName + indexName: indexName }) - vectorStore.similaritySearchVectorWithScore = async ( - query: number[], - k: number, - filter?: object | undefined - ): Promise<[Document, number][]> => { - const search: RequestParams.Search = { - index: indexName, - body: { - query: { - bool: { - filter: { bool: { must: buildMetadataTerms(filter) } }, - must: [ - { - knn: { - embedding: { vector: query, k } - } - } - ] - } - }, - size: k - } - } - - const { body } = await client.search(search) - - return body.hits.hits.map((hit: any) => [ - new Document({ - pageContent: hit._source.text, - metadata: hit._source.metadata - }), - hit._score - ]) - } - if (output === 'retriever') { const retriever = vectorStore.asRetriever(k) return retriever diff --git a/packages/components/nodes/vectorstores/OpenSearch_Upsert/opensearch.png b/packages/components/nodes/vectorstores/OpenSearch_Upsert/opensearch.png new file mode 100644 index 0000000000000000000000000000000000000000..3fdcfd3f09ed02c1478f690884ecafe844cb32ae GIT binary patch literal 5216 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 Date: Thu, 19 Oct 2023 12:39:53 +0100 Subject: [PATCH 76/76] add im-mem cache embeddings --- .../InMemoryCache/InMemoryEmbeddingCache.ts | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 packages/components/nodes/cache/InMemoryCache/InMemoryEmbeddingCache.ts diff --git a/packages/components/nodes/cache/InMemoryCache/InMemoryEmbeddingCache.ts b/packages/components/nodes/cache/InMemoryCache/InMemoryEmbeddingCache.ts new file mode 100644 index 00000000..fad72482 --- /dev/null +++ b/packages/components/nodes/cache/InMemoryCache/InMemoryEmbeddingCache.ts @@ -0,0 +1,131 @@ +import { getBaseClasses, ICommonObject, INode, INodeData, INodeParams } from '../../../src' +import { CacheBackedEmbeddings } from 'langchain/embeddings/cache_backed' +import { Embeddings } from 'langchain/embeddings/base' +import { BaseStore } from 'langchain/schema/storage' + +class InMemoryEmbeddingCache implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + + constructor() { + this.label = 'InMemory Embedding Cache' + this.name = 'inMemoryEmbeddingCache' + this.version = 1.0 + this.type = 'InMemoryEmbeddingCache' + this.description = 'Cache generated Embeddings in memory to avoid needing to recompute them.' + this.icon = 'inmemorycache.png' + this.category = 'Cache' + this.baseClasses = [this.type, ...getBaseClasses(CacheBackedEmbeddings)] + this.inputs = [ + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Namespace', + name: 'namespace', + type: 'string', + optional: true, + additionalParams: true + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const namespace = nodeData.inputs?.namespace as string + const underlyingEmbeddings = nodeData.inputs?.embeddings as Embeddings + const memoryMap = options.cachePool.getEmbeddingCache(options.chatflowid) ?? {} + const inMemCache = new InMemoryEmbeddingCacheExtended(memoryMap) + + inMemCache.mget = async (keys: string[]) => { + const memory = options.cachePool.getEmbeddingCache(options.chatflowid) ?? inMemCache.store + return keys.map((key) => memory[key]) + } + + inMemCache.mset = async (keyValuePairs: [string, any][]): Promise => { + for (const [key, value] of keyValuePairs) { + inMemCache.store[key] = value + } + options.cachePool.addEmbeddingCache(options.chatflowid, inMemCache.store) + } + + inMemCache.mdelete = async (keys: string[]): Promise => { + for (const key of keys) { + delete inMemCache.store[key] + } + options.cachePool.addEmbeddingCache(options.chatflowid, inMemCache.store) + } + + return CacheBackedEmbeddings.fromBytesStore(underlyingEmbeddings, inMemCache, { + namespace: namespace + }) + } +} + +class InMemoryEmbeddingCacheExtended extends BaseStore { + lc_namespace = ['langchain', 'storage', 'in_memory'] + + store: Record = {} + + constructor(map: Record) { + super() + this.store = map + } + + /** + * Retrieves the values associated with the given keys from the store. + * @param keys Keys to retrieve values for. + * @returns Array of values associated with the given keys. + */ + async mget(keys: string[]) { + return keys.map((key) => this.store[key]) + } + + /** + * Sets the values for the given keys in the store. + * @param keyValuePairs Array of key-value pairs to set in the store. + * @returns Promise that resolves when all key-value pairs have been set. + */ + async mset(keyValuePairs: [string, T][]): Promise { + for (const [key, value] of keyValuePairs) { + this.store[key] = value + } + } + + /** + * Deletes the given keys and their associated values from the store. + * @param keys Keys to delete from the store. + * @returns Promise that resolves when all keys have been deleted. + */ + async mdelete(keys: string[]): Promise { + for (const key of keys) { + delete this.store[key] + } + } + + /** + * Asynchronous generator that yields keys from the store. If a prefix is + * provided, it only yields keys that start with the prefix. + * @param prefix Optional prefix to filter keys. + * @returns AsyncGenerator that yields keys from the store. + */ + async *yieldKeys(prefix?: string | undefined): AsyncGenerator { + const keys = Object.keys(this.store) + for (const key of keys) { + if (prefix === undefined || key.startsWith(prefix)) { + yield key + } + } + } +} + +module.exports = { nodeClass: InMemoryEmbeddingCache }