From 1ffa56897446cb36bd1e0a5699b6bc9c89e844a4 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 22 Dec 2023 09:08:53 +0530 Subject: [PATCH 01/41] Addition of Pinecone MMR search --- .../nodes/vectorstores/Pinecone/Pinecone.ts | 63 +++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts index 4e6967bc..3f2e3ef1 100644 --- a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts +++ b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts @@ -23,11 +23,11 @@ class Pinecone_VectorStores implements INode { constructor() { this.label = 'Pinecone' this.name = 'pinecone' - this.version = 1.0 + this.version = 2.0 this.type = 'Pinecone' this.icon = 'pinecone.svg' this.category = 'Vector Stores' - this.description = `Upsert embedded data and perform similarity search upon query using Pinecone, a leading fully managed hosted vector database` + this.description = `Upsert embedded data and perform search upon query using Pinecone, a leading fully managed hosted vector database` this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.badge = 'NEW' this.credential = { @@ -77,6 +77,43 @@ class Pinecone_VectorStores implements INode { type: 'number', additionalParams: true, optional: true + }, + { + label: 'Search Type', + name: 'searchType', + type: 'options', + default: 'similarity', + options: [ + { + label: 'Similarity', + name: 'similarity' + }, + { + label: 'Max Marginal Relevance', + name: 'mmr' + } + ], + additionalParams: true, + optional: true + }, + { + label: 'Fetch K (for MMR Search)', + name: 'fetchK', + description: 'Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR', + placeholder: '20', + type: 'number', + additionalParams: true, + optional: true + }, + { + label: 'Lambda (for MMR Search)', + name: 'lambda', + description: + 'Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR', + placeholder: '0.5', + type: 'number', + additionalParams: true, + optional: true } ] this.outputs = [ @@ -141,6 +178,7 @@ class Pinecone_VectorStores implements INode { const docs = nodeData.inputs?.document as Document[] const embeddings = nodeData.inputs?.embeddings as Embeddings const output = nodeData.outputs?.output as string + const searchType = nodeData.outputs?.searchType as string const topK = nodeData.inputs?.topK as string const k = topK ? parseFloat(topK) : 4 @@ -176,8 +214,25 @@ class Pinecone_VectorStores implements INode { const vectorStore = await PineconeStore.fromExistingIndex(embeddings, obj) if (output === 'retriever') { - const retriever = vectorStore.asRetriever(k) - return retriever + if ('mmr' === searchType) { + const fetchK = nodeData.inputs?.fetchK as string + const lambda = nodeData.inputs?.lambda as string + const f = fetchK ? parseInt(fetchK) : 20 + const l = lambda ? parseFloat(lambda) : 0.5 + const retriever = vectorStore.asRetriever({ + searchType: 'mmr', + k: 5, + searchKwargs: { + fetchK: f, + lambda: l + } + }) + return retriever + } else { + // "searchType" is "similarity" + const retriever = vectorStore.asRetriever(k) + return retriever + } } else if (output === 'vectorStore') { ;(vectorStore as any).k = k return vectorStore From 579f66e57e3da71e0a53db10cf1baeb986d4bb31 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 22 Dec 2023 09:20:55 +0530 Subject: [PATCH 02/41] Updating langchain to 0.0.198 --- 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 9cb0bf1e..018d7a77 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -52,7 +52,7 @@ "html-to-text": "^9.0.5", "husky": "^8.0.3", "ioredis": "^5.3.2", - "langchain": "^0.0.196", + "langchain": "^0.0.198", "langfuse": "^1.2.0", "langfuse-langchain": "^1.0.31", "langsmith": "^0.0.49", From 56b043264a5370ac041f8fde1adf928b5068eace Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 22 Dec 2023 12:08:48 +0530 Subject: [PATCH 03/41] MMR Search for Pinecone, Weaviate, Zep and Supabase --- .../nodes/vectorstores/Pinecone/Pinecone.ts | 73 ++---------------- .../nodes/vectorstores/Supabase/Supabase.ts | 18 ++--- .../nodes/vectorstores/VectorStoreUtils.ts | 76 +++++++++++++++++++ .../nodes/vectorstores/Weaviate/Weaviate.ts | 18 ++--- .../components/nodes/vectorstores/Zep/Zep.ts | 22 ++---- 5 files changed, 98 insertions(+), 109 deletions(-) create mode 100644 packages/components/nodes/vectorstores/VectorStoreUtils.ts diff --git a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts index 3f2e3ef1..4b91a9b5 100644 --- a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts +++ b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts @@ -5,6 +5,7 @@ import { Embeddings } from 'langchain/embeddings/base' import { Document } from 'langchain/document' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils' class Pinecone_VectorStores implements INode { label: string @@ -23,11 +24,11 @@ class Pinecone_VectorStores implements INode { constructor() { this.label = 'Pinecone' this.name = 'pinecone' - this.version = 2.0 + this.version = 3.0 this.type = 'Pinecone' this.icon = 'pinecone.svg' this.category = 'Vector Stores' - this.description = `Upsert embedded data and perform search upon query using Pinecone, a leading fully managed hosted vector database` + this.description = `Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database` this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.badge = 'NEW' this.credential = { @@ -77,45 +78,9 @@ class Pinecone_VectorStores implements INode { type: 'number', additionalParams: true, optional: true - }, - { - label: 'Search Type', - name: 'searchType', - type: 'options', - default: 'similarity', - options: [ - { - label: 'Similarity', - name: 'similarity' - }, - { - label: 'Max Marginal Relevance', - name: 'mmr' - } - ], - additionalParams: true, - optional: true - }, - { - label: 'Fetch K (for MMR Search)', - name: 'fetchK', - description: 'Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR', - placeholder: '20', - type: 'number', - additionalParams: true, - optional: true - }, - { - label: 'Lambda (for MMR Search)', - name: 'lambda', - description: - 'Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR', - placeholder: '0.5', - type: 'number', - additionalParams: true, - optional: true } ] + addMMRInputParams(this.inputs) this.outputs = [ { label: 'Pinecone Retriever', @@ -177,10 +142,6 @@ class Pinecone_VectorStores implements INode { const pineconeMetadataFilter = nodeData.inputs?.pineconeMetadataFilter const docs = nodeData.inputs?.document as Document[] const embeddings = nodeData.inputs?.embeddings as Embeddings - const output = nodeData.outputs?.output as string - const searchType = nodeData.outputs?.searchType as string - const topK = nodeData.inputs?.topK as string - const k = topK ? parseFloat(topK) : 4 const credentialData = await getCredentialData(nodeData.credential ?? '', options) const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData) @@ -213,31 +174,7 @@ class Pinecone_VectorStores implements INode { const vectorStore = await PineconeStore.fromExistingIndex(embeddings, obj) - if (output === 'retriever') { - if ('mmr' === searchType) { - const fetchK = nodeData.inputs?.fetchK as string - const lambda = nodeData.inputs?.lambda as string - const f = fetchK ? parseInt(fetchK) : 20 - const l = lambda ? parseFloat(lambda) : 0.5 - const retriever = vectorStore.asRetriever({ - searchType: 'mmr', - k: 5, - searchKwargs: { - fetchK: f, - lambda: l - } - }) - return retriever - } else { - // "searchType" is "similarity" - const retriever = vectorStore.asRetriever(k) - return retriever - } - } else if (output === 'vectorStore') { - ;(vectorStore as any).k = k - return vectorStore - } - return vectorStore + return resolveVectorStoreOrRetriever(nodeData, vectorStore) } } diff --git a/packages/components/nodes/vectorstores/Supabase/Supabase.ts b/packages/components/nodes/vectorstores/Supabase/Supabase.ts index 13840ab7..a5477914 100644 --- a/packages/components/nodes/vectorstores/Supabase/Supabase.ts +++ b/packages/components/nodes/vectorstores/Supabase/Supabase.ts @@ -5,6 +5,7 @@ import { Embeddings } from 'langchain/embeddings/base' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' import { SupabaseLibArgs, SupabaseVectorStore } from 'langchain/vectorstores/supabase' +import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils' class Supabase_VectorStores implements INode { label: string @@ -23,11 +24,11 @@ class Supabase_VectorStores implements INode { constructor() { this.label = 'Supabase' this.name = 'supabase' - this.version = 1.0 + this.version = 2.0 this.type = 'Supabase' this.icon = 'supabase.svg' this.category = 'Vector Stores' - this.description = 'Upsert embedded data and perform similarity search upon query using Supabase via pgvector extension' + this.description = 'Upsert embedded data and perform similarity or mmr search upon query using Supabase via pgvector extension' this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.badge = 'NEW' this.credential = { @@ -81,6 +82,7 @@ class Supabase_VectorStores implements INode { optional: true } ] + addMMRInputParams(this.inputs) this.outputs = [ { label: 'Supabase Retriever', @@ -135,9 +137,6 @@ class Supabase_VectorStores implements INode { const queryName = nodeData.inputs?.queryName as string const embeddings = nodeData.inputs?.embeddings as Embeddings const supabaseMetadataFilter = nodeData.inputs?.supabaseMetadataFilter - const output = nodeData.outputs?.output as string - const topK = nodeData.inputs?.topK as string - const k = topK ? parseFloat(topK) : 4 const credentialData = await getCredentialData(nodeData.credential ?? '', options) const supabaseApiKey = getCredentialParam('supabaseApiKey', credentialData, nodeData) @@ -157,14 +156,7 @@ class Supabase_VectorStores implements INode { const vectorStore = await SupabaseVectorStore.fromExistingIndex(embeddings, obj) - if (output === 'retriever') { - const retriever = vectorStore.asRetriever(k) - return retriever - } else if (output === 'vectorStore') { - ;(vectorStore as any).k = k - return vectorStore - } - return vectorStore + return resolveVectorStoreOrRetriever(nodeData, vectorStore) } } diff --git a/packages/components/nodes/vectorstores/VectorStoreUtils.ts b/packages/components/nodes/vectorstores/VectorStoreUtils.ts new file mode 100644 index 00000000..b63a4121 --- /dev/null +++ b/packages/components/nodes/vectorstores/VectorStoreUtils.ts @@ -0,0 +1,76 @@ +import { INodeData } from '../../src' + +export const resolveVectorStoreOrRetriever = (nodeData: INodeData, vectorStore: any) => { + const output = nodeData.outputs?.output as string + const searchType = nodeData.outputs?.searchType as string + const topK = nodeData.inputs?.topK as string + const k = topK ? parseFloat(topK) : 4 + + if (output === 'retriever') { + if ('mmr' === searchType) { + const fetchK = nodeData.inputs?.fetchK as string + const lambda = nodeData.inputs?.lambda as string + const f = fetchK ? parseInt(fetchK) : 20 + const l = lambda ? parseFloat(lambda) : 0.5 + const retriever = vectorStore.asRetriever({ + searchType: 'mmr', + k: k, + searchKwargs: { + fetchK: f, + lambda: l + } + }) + return retriever + } else { + // "searchType" is "similarity" + return vectorStore.asRetriever(k) + } + } else if (output === 'vectorStore') { + ;(vectorStore as any).k = k + return vectorStore + } +} + +export const addMMRInputParams = (inputs: any[]) => { + const mmrInputParams = [ + { + label: 'Search Type', + name: 'searchType', + type: 'options', + default: 'similarity', + options: [ + { + label: 'Similarity', + name: 'similarity' + }, + { + label: 'Max Marginal Relevance', + name: 'mmr' + } + ], + additionalParams: true, + optional: true + }, + { + label: 'Fetch K (for MMR Search)', + name: 'fetchK', + description: 'Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR', + placeholder: '20', + type: 'number', + additionalParams: true, + optional: true + }, + { + label: 'Lambda (for MMR Search)', + name: 'lambda', + description: + 'Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR', + placeholder: '0.5', + type: 'number', + additionalParams: true, + optional: true + } + ] + + inputs.push(...mmrInputParams) +} diff --git a/packages/components/nodes/vectorstores/Weaviate/Weaviate.ts b/packages/components/nodes/vectorstores/Weaviate/Weaviate.ts index 5c31c737..0eface58 100644 --- a/packages/components/nodes/vectorstores/Weaviate/Weaviate.ts +++ b/packages/components/nodes/vectorstores/Weaviate/Weaviate.ts @@ -5,6 +5,7 @@ import { Document } from 'langchain/document' import { Embeddings } from 'langchain/embeddings/base' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils' class Weaviate_VectorStores implements INode { label: string @@ -23,12 +24,12 @@ class Weaviate_VectorStores implements INode { constructor() { this.label = 'Weaviate' this.name = 'weaviate' - this.version = 1.0 + this.version = 2.0 this.type = 'Weaviate' this.icon = 'weaviate.png' this.category = 'Vector Stores' this.description = - 'Upsert embedded data and perform similarity search upon query using Weaviate, a scalable open-source vector database' + 'Upsert embedded data and perform similarity or mmr search using Weaviate, a scalable open-source vector database' this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.badge = 'NEW' this.credential = { @@ -107,6 +108,7 @@ class Weaviate_VectorStores implements INode { optional: true } ] + addMMRInputParams(this.inputs) this.outputs = [ { label: 'Weaviate Retriever', @@ -174,9 +176,6 @@ class Weaviate_VectorStores implements INode { const weaviateTextKey = nodeData.inputs?.weaviateTextKey as string const weaviateMetadataKeys = nodeData.inputs?.weaviateMetadataKeys as string const embeddings = nodeData.inputs?.embeddings as Embeddings - const output = nodeData.outputs?.output as string - const topK = nodeData.inputs?.topK as string - const k = topK ? parseFloat(topK) : 4 const credentialData = await getCredentialData(nodeData.credential ?? '', options) const weaviateApiKey = getCredentialParam('weaviateApiKey', credentialData, nodeData) @@ -199,14 +198,7 @@ class Weaviate_VectorStores implements INode { const vectorStore = await WeaviateStore.fromExistingIndex(embeddings, obj) - if (output === 'retriever') { - const retriever = vectorStore.asRetriever(k) - return retriever - } else if (output === 'vectorStore') { - ;(vectorStore as any).k = k - return vectorStore - } - return vectorStore + return resolveVectorStoreOrRetriever(nodeData, vectorStore) } } diff --git a/packages/components/nodes/vectorstores/Zep/Zep.ts b/packages/components/nodes/vectorstores/Zep/Zep.ts index ebb13c64..3d9f1978 100644 --- a/packages/components/nodes/vectorstores/Zep/Zep.ts +++ b/packages/components/nodes/vectorstores/Zep/Zep.ts @@ -5,6 +5,7 @@ import { Embeddings } from 'langchain/embeddings/base' import { Document } from 'langchain/document' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils' class Zep_VectorStores implements INode { label: string @@ -23,12 +24,12 @@ class Zep_VectorStores implements INode { constructor() { this.label = 'Zep' this.name = 'zep' - this.version = 1.0 + this.version = 2.0 this.type = 'Zep' this.icon = 'zep.svg' this.category = 'Vector Stores' this.description = - 'Upsert embedded data and perform similarity search upon query using Zep, a fast and scalable building block for LLM apps' + 'Upsert embedded data and perform similarity or mmr search upon query using Zep, a fast and scalable building block for LLM apps' this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.badge = 'NEW' this.credential = { @@ -88,6 +89,7 @@ class Zep_VectorStores implements INode { optional: true } ] + addMMRInputParams(this.inputs) this.outputs = [ { label: 'Zep Retriever', @@ -144,9 +146,6 @@ class Zep_VectorStores implements INode { const zepMetadataFilter = nodeData.inputs?.zepMetadataFilter const dimension = nodeData.inputs?.dimension as number const embeddings = nodeData.inputs?.embeddings as Embeddings - const output = nodeData.outputs?.output as string - const topK = nodeData.inputs?.topK as string - const k = topK ? parseFloat(topK) : 4 const credentialData = await getCredentialData(nodeData.credential ?? '', options) const apiKey = getCredentialParam('apiKey', credentialData, nodeData) @@ -165,14 +164,7 @@ class Zep_VectorStores implements INode { const vectorStore = await ZepExistingVS.fromExistingIndex(embeddings, zepConfig) - if (output === 'retriever') { - const retriever = vectorStore.asRetriever(k) - return retriever - } else if (output === 'vectorStore') { - ;(vectorStore as any).k = k - return vectorStore - } - return vectorStore + return resolveVectorStoreOrRetriever(nodeData, vectorStore) } } @@ -210,7 +202,7 @@ class ZepExistingVS extends ZepVectorStore { this.args = args } - async initalizeCollection(args: IZepConfig & Partial) { + async initializeCollection(args: IZepConfig & Partial) { this.client = await ZepClient.init(args.apiUrl, args.apiKey) try { this.collection = await this.client.document.getCollection(args.collectionName) @@ -259,7 +251,7 @@ class ZepExistingVS extends ZepVectorStore { const newfilter = { where: { and: ANDFilters } } - await this.initalizeCollection(this.args!).catch((err) => { + await this.initializeCollection(this.args!).catch((err) => { console.error('Error initializing collection:', err) throw err }) From 94236c4b5fe80a3449eed29f36ddb9e620077abe Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 22 Dec 2023 12:12:04 +0530 Subject: [PATCH 04/41] Compression Retriever - Cohere Rerank --- .../CohereRerankRetriever/CohereRerank.ts | 51 ++++++++++++ .../CohereRerankRetriever.ts | 77 +++++++++++++++++++ .../compressionRetriever.svg | 7 ++ 3 files changed, 135 insertions(+) create mode 100644 packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts create mode 100644 packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts create mode 100644 packages/components/nodes/retrievers/CohereRerankRetriever/compressionRetriever.svg diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts new file mode 100644 index 00000000..612581ed --- /dev/null +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts @@ -0,0 +1,51 @@ +import { Callbacks } from 'langchain/callbacks' +import { Document } from 'langchain/document' +import { BaseDocumentCompressor } from 'langchain/retrievers/document_compressors' +import axios from 'axios' +export class CohereRerank extends BaseDocumentCompressor { + private cohereAPIKey: any + private COHERE_API_URL = 'https://api.cohere.ai/v1/rerank' + private model: string + + constructor(cohereAPIKey: string, model: string) { + super() + this.cohereAPIKey = cohereAPIKey + this.model = model + } + async compressDocuments( + documents: Document>[], + query: string, + _?: Callbacks | undefined + ): Promise>[]> { + // avoid empty api call + if (documents.length === 0) { + return [] + } + const config = { + headers: { + Authorization: `Bearer ${this.cohereAPIKey}`, + 'Content-Type': 'application/json', + Accept: 'application/json' + } + } + const data = { + model: this.model, + max_chunks_per_doc: 10, + query: query, + return_documents: false, + documents: documents.map((doc) => doc.pageContent) + } + try { + let returnedDocs = await axios.post(this.COHERE_API_URL, data, config) + const finalResults: Document>[] = [] + returnedDocs.data.results.forEach((result: any) => { + const doc = documents[result.index] + doc.metadata.relevance_score = result.relevance_score + finalResults.push(doc) + }) + return finalResults + } catch (error) { + return documents + } + } +} diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts new file mode 100644 index 00000000..2e7090bc --- /dev/null +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts @@ -0,0 +1,77 @@ +import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { BaseRetriever } from 'langchain/schema/retriever' +import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' +import { getCredentialData, getCredentialParam } from '../../../src' +import { CohereRerank } from './CohereRerank' + +class CohereRerankRetriever_Retrievers implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + credential: INodeParams + badge: string + + constructor() { + this.label = 'Cohere Rerank Retriever' + this.name = 'cohereRerankRetriever' + this.version = 1.0 + this.type = 'Cohere Rerank Retriever' + this.icon = 'compressionRetriever.svg' + this.category = 'Retrievers' + this.badge = 'NEW' + this.description = 'Cohere Rerank indexes the documents from most to least semantically relevant to the query.' + this.baseClasses = [this.type, 'BaseRetriever'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['cohereApi'] + } + this.inputs = [ + { + label: 'Base Retriever', + name: 'baseRetriever', + type: 'VectorStoreRetriever' + }, + { + label: 'Model Name', + name: 'model', + type: 'options', + options: [ + { + label: 'rerank-english-v2.0', + name: 'rerank-english-v2.0' + }, + { + label: 'rerank-multilingual-v2.0', + name: 'rerank-multilingual-v2.0' + } + ], + default: 'rerank-english-v2.0', + optional: true + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const baseRetriever = nodeData.inputs?.baseRetriever as BaseRetriever + const model = nodeData.inputs?.model as string + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const cohereApiKey = getCredentialParam('cohereApiKey', credentialData, nodeData) + + const cohereCompressor = new CohereRerank(cohereApiKey, model) + return new ContextualCompressionRetriever({ + baseCompressor: cohereCompressor, + baseRetriever: baseRetriever + }) + } +} + +module.exports = { nodeClass: CohereRerankRetriever_Retrievers } diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/compressionRetriever.svg b/packages/components/nodes/retrievers/CohereRerankRetriever/compressionRetriever.svg new file mode 100644 index 00000000..23c52d25 --- /dev/null +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/compressionRetriever.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From fb02632f4b682b8b0ee2d1ec1a79330118318eaa Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 22 Dec 2023 12:12:16 +0530 Subject: [PATCH 05/41] Compression Retriever - Embeddings Filter --- .../EmbeddingsFilterRetriever.ts | 97 +++++++++++++++++++ .../compressionRetriever.svg | 7 ++ 2 files changed, 104 insertions(+) create mode 100644 packages/components/nodes/retrievers/EmbeddingsFilterRetriever/EmbeddingsFilterRetriever.ts create mode 100644 packages/components/nodes/retrievers/EmbeddingsFilterRetriever/compressionRetriever.svg diff --git a/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/EmbeddingsFilterRetriever.ts b/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/EmbeddingsFilterRetriever.ts new file mode 100644 index 00000000..d373704c --- /dev/null +++ b/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/EmbeddingsFilterRetriever.ts @@ -0,0 +1,97 @@ +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { BaseRetriever } from 'langchain/schema/retriever' +import { Embeddings } from 'langchain/embeddings/base' +import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' +import { EmbeddingsFilter } from 'langchain/retrievers/document_compressors/embeddings_filter' + +class EmbeddingsFilterRetriever_Retrievers implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + badge: string + + constructor() { + this.label = 'Embeddings Filter Retriever' + this.name = 'embeddingsFilterRetriever' + this.version = 1.0 + this.type = 'EmbeddingsFilterRetriever' + this.icon = 'compressionRetriever.svg' + this.category = 'Retrievers' + this.badge = 'NEW' + this.description = 'A document compressor that uses embeddings to drop documents unrelated to the query' + this.baseClasses = [this.type, 'BaseRetriever'] + this.inputs = [ + { + label: 'Base Retriever', + name: 'baseRetriever', + type: 'VectorStoreRetriever' + }, + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings', + optional: false + }, + { + label: 'Similarity Threshold', + name: 'similarityThreshold', + description: + 'Threshold for determining when two documents are similar enough to be considered redundant. Must be specified if `k` is not set', + type: 'number', + default: 0.8, + step: 0.1, + optional: true + }, + { + label: 'K', + name: 'k', + description: + 'The number of relevant documents to return. Can be explicitly set to undefined, in which case similarity_threshold must be specified. Defaults to 20', + type: 'number', + default: 20, + step: 1, + optional: true, + additionalParams: true + } + ] + } + + async init(nodeData: INodeData): Promise { + const baseRetriever = nodeData.inputs?.baseRetriever as BaseRetriever + const embeddings = nodeData.inputs?.embeddings as Embeddings + const similarityThreshold = nodeData.inputs?.similarityThreshold as string + const k = nodeData.inputs?.k as string + + if (k === undefined && similarityThreshold === undefined) { + throw new Error(`Must specify one of "k" or "similarity_threshold".`) + } + + let similarityThresholdNumber = 0.8 + if (similarityThreshold) { + similarityThresholdNumber = parseFloat(similarityThreshold) + } + let kNumber = 0.8 + if (k) { + kNumber = parseFloat(k) + } + const baseCompressor = new EmbeddingsFilter({ + embeddings: embeddings, + similarityThreshold: similarityThresholdNumber, + k: kNumber + }) + + return new ContextualCompressionRetriever({ + baseCompressor, + baseRetriever: baseRetriever + }) + } +} + +module.exports = { nodeClass: EmbeddingsFilterRetriever_Retrievers } diff --git a/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/compressionRetriever.svg b/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/compressionRetriever.svg new file mode 100644 index 00000000..23c52d25 --- /dev/null +++ b/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/compressionRetriever.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From f2f8ed6a9ce1ab41bd69193ce283757cd28cb16e Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 22 Dec 2023 12:12:25 +0530 Subject: [PATCH 06/41] Compression Retriever - LLM filter --- .../LLMFilterCompressionRetriever.ts | 60 +++++++++++++++++++ .../compressionRetriever.svg | 7 +++ 2 files changed, 67 insertions(+) create mode 100644 packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts create mode 100644 packages/components/nodes/retrievers/LLMFilterRetriever/compressionRetriever.svg diff --git a/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts b/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts new file mode 100644 index 00000000..c421c7ce --- /dev/null +++ b/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts @@ -0,0 +1,60 @@ +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { BaseRetriever } from 'langchain/schema/retriever' +import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' +import { BaseLanguageModel } from 'langchain/base_language' +import { LLMChainExtractor } from 'langchain/retrievers/document_compressors/chain_extract' + +class LLMFilterCompressionRetriever_Retrievers implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + badge: string + + constructor() { + this.label = 'LLM Filter Retriever' + this.name = 'llmFilterRetriever' + this.version = 1.0 + this.type = 'LLMFilterRetriever' + this.icon = 'compressionRetriever.svg' + this.category = 'Retrievers' + this.badge = 'NEW' + this.description = + 'Iterate over the initially returned documents and extract, from each, only the content that is relevant to the query' + this.baseClasses = [this.type, 'BaseRetriever'] + this.inputs = [ + { + label: 'Base Retriever', + name: 'baseRetriever', + type: 'VectorStoreRetriever' + }, + { + label: 'Language Model', + name: 'model', + type: 'BaseLanguageModel', + optional: true + }, + ] + } + + async init(nodeData: INodeData): Promise { + const baseRetriever = nodeData.inputs?.baseRetriever as BaseRetriever + const model = nodeData.inputs?.model as BaseLanguageModel + + if (model) { + return new ContextualCompressionRetriever({ + baseCompressor: LLMChainExtractor.fromLLM(model), + baseRetriever: baseRetriever + }) + } + return {} + } +} + +module.exports = { nodeClass: LLMFilterCompressionRetriever_Retrievers } diff --git a/packages/components/nodes/retrievers/LLMFilterRetriever/compressionRetriever.svg b/packages/components/nodes/retrievers/LLMFilterRetriever/compressionRetriever.svg new file mode 100644 index 00000000..23c52d25 --- /dev/null +++ b/packages/components/nodes/retrievers/LLMFilterRetriever/compressionRetriever.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From be79adb07c22586d4debd5384268463a874b878e Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 22 Dec 2023 12:13:52 +0530 Subject: [PATCH 07/41] lint fixes --- .../LLMFilterRetriever/LLMFilterCompressionRetriever.ts | 2 +- packages/components/nodes/vectorstores/VectorStoreUtils.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts b/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts index c421c7ce..e044468f 100644 --- a/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts +++ b/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts @@ -39,7 +39,7 @@ class LLMFilterCompressionRetriever_Retrievers implements INode { name: 'model', type: 'BaseLanguageModel', optional: true - }, + } ] } diff --git a/packages/components/nodes/vectorstores/VectorStoreUtils.ts b/packages/components/nodes/vectorstores/VectorStoreUtils.ts index b63a4121..a01d43c4 100644 --- a/packages/components/nodes/vectorstores/VectorStoreUtils.ts +++ b/packages/components/nodes/vectorstores/VectorStoreUtils.ts @@ -1,4 +1,4 @@ -import { INodeData } from '../../src' +import { INodeData } from "../../src"; export const resolveVectorStoreOrRetriever = (nodeData: INodeData, vectorStore: any) => { const output = nodeData.outputs?.output as string @@ -12,7 +12,7 @@ export const resolveVectorStoreOrRetriever = (nodeData: INodeData, vectorStore: const lambda = nodeData.inputs?.lambda as string const f = fetchK ? parseInt(fetchK) : 20 const l = lambda ? parseFloat(lambda) : 0.5 - const retriever = vectorStore.asRetriever({ + return vectorStore.asRetriever({ searchType: 'mmr', k: k, searchKwargs: { @@ -20,7 +20,6 @@ export const resolveVectorStoreOrRetriever = (nodeData: INodeData, vectorStore: lambda: l } }) - return retriever } else { // "searchType" is "similarity" return vectorStore.asRetriever(k) From f6ee137ca3e60b350f794181b43453eff520474b Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 22 Dec 2023 12:14:10 +0530 Subject: [PATCH 08/41] lint fixes --- packages/components/nodes/vectorstores/VectorStoreUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/nodes/vectorstores/VectorStoreUtils.ts b/packages/components/nodes/vectorstores/VectorStoreUtils.ts index a01d43c4..0d92587f 100644 --- a/packages/components/nodes/vectorstores/VectorStoreUtils.ts +++ b/packages/components/nodes/vectorstores/VectorStoreUtils.ts @@ -1,4 +1,4 @@ -import { INodeData } from "../../src"; +import { INodeData } from '../../src' export const resolveVectorStoreOrRetriever = (nodeData: INodeData, vectorStore: any) => { const output = nodeData.outputs?.output as string From 4dd2f245ffdfb2fac5a169c97f9c825e7aa04828 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 29 Dec 2023 20:35:42 +0530 Subject: [PATCH 09/41] Compression Retriever: Reciprocal Rank Fusion --- .../retrievers/RRFRetriever/RRFRetriever.ts | 84 ++++++++++++++++ .../RRFRetriever/ReciprocalRankFusion.ts | 95 +++++++++++++++++++ .../RRFRetriever/compressionRetriever.svg | 7 ++ 3 files changed, 186 insertions(+) create mode 100644 packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts create mode 100644 packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts create mode 100644 packages/components/nodes/retrievers/RRFRetriever/compressionRetriever.svg diff --git a/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts b/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts new file mode 100644 index 00000000..8d6d9d6f --- /dev/null +++ b/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts @@ -0,0 +1,84 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { BaseLanguageModel } from 'langchain/base_language' +import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' +import { BaseRetriever } from 'langchain/schema/retriever' +import { ReciprocalRankFusion } from './ReciprocalRankFusion' +import { VectorStoreRetriever } from 'langchain/vectorstores/base' + +class RRFRetriever_Retrievers implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + badge: string + + constructor() { + this.label = 'Reciprocal Rank Fusion Retriever' + this.name = 'RRFRetriever' + this.version = 2.0 + this.type = 'RRFRetriever' + this.badge = 'NEW' + this.icon = 'compressionRetriever.svg' + this.category = 'Retrievers' + this.description = 'Reciprocal Rank Fusion to re-rank search results by multiple query generation.' + this.baseClasses = [this.type, 'BaseRetriever'] + this.inputs = [ + { + label: 'Base Retriever', + name: 'baseRetriever', + type: 'VectorStoreRetriever' + }, + { + label: 'Language Model', + name: 'model', + type: 'BaseLanguageModel' + }, + { + label: 'Query Count', + name: 'queryCount', + description: 'Number of synthetic queries to generate. Default to 4', + placeholder: '4', + type: 'number', + default: 4, + additionalParams: true, + optional: true + }, + { + label: 'Top K', + name: 'topK', + description: 'Number of top results to fetch. Default to the TopK of the Base Retriever', + placeholder: '0', + type: 'number', + default: 0, + additionalParams: true, + optional: true + } + ] + } + + async init(nodeData: INodeData): Promise { + const llm = nodeData.inputs?.model as BaseLanguageModel + const baseRetriever = nodeData.inputs?.baseRetriever as BaseRetriever + const queryCount = nodeData.inputs?.queryCount as string + const q = queryCount ? parseFloat(queryCount) : 4 + const topK = nodeData.inputs?.topK as string + let k = topK ? parseFloat(topK) : 4 + + if (k <= 0) { + k = (baseRetriever as VectorStoreRetriever).k + } + + const ragFusion = new ReciprocalRankFusion(llm, baseRetriever as VectorStoreRetriever, q, k) + return new ContextualCompressionRetriever({ + baseCompressor: ragFusion, + baseRetriever: baseRetriever + }) + } +} + +module.exports = { nodeClass: RRFRetriever_Retrievers } diff --git a/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts b/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts new file mode 100644 index 00000000..134d7c8a --- /dev/null +++ b/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts @@ -0,0 +1,95 @@ +import { BaseDocumentCompressor } from 'langchain/retrievers/document_compressors' +import { Document } from 'langchain/document' +import { Callbacks } from 'langchain/callbacks' +import { BaseLanguageModel } from 'langchain/base_language' +import { ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate } from 'langchain/prompts' +import { LLMChain } from 'langchain/chains' +import { VectorStoreRetriever } from 'langchain/vectorstores/base' + +export class ReciprocalRankFusion extends BaseDocumentCompressor { + private readonly llm: BaseLanguageModel + private readonly queryCount: number + private readonly topK: number + private baseRetriever: VectorStoreRetriever + constructor(llm: BaseLanguageModel, baseRetriever: VectorStoreRetriever, queryCount: number, topK: number) { + super() + this.queryCount = queryCount + this.llm = llm + this.baseRetriever = baseRetriever + this.topK = topK + } + async compressDocuments( + documents: Document>[], + query: string, + _?: Callbacks | undefined + ): Promise>[]> { + // avoid empty api call + if (documents.length === 0) { + return [] + } + const chatPrompt = ChatPromptTemplate.fromMessages([ + SystemMessagePromptTemplate.fromTemplate( + 'You are a helpful assistant that generates multiple search queries based on a single input query.' + ), + HumanMessagePromptTemplate.fromTemplate( + 'Generate multiple search queries related to: {input}. Provide these alternative questions separated by newlines, do not add any numbers.' + ), + HumanMessagePromptTemplate.fromTemplate('OUTPUT (' + this.queryCount + ' queries):') + ]) + const llmChain = new LLMChain({ + llm: this.llm, + prompt: chatPrompt + }) + const multipleQueries = await llmChain.call({ input: query }) + const queries = [] + queries.push(query) + multipleQueries.text.split('\n').map((q: string) => { + queries.push(q) + }) + console.log(JSON.stringify(queries)) + const docList: Document>[][] = [] + for (let i = 0; i < queries.length; i++) { + const resultOne = await this.baseRetriever.vectorStore.similaritySearch(queries[i], 5) + const docs: any[] = [] + resultOne.forEach((doc) => { + docs.push(doc) + }) + docList.push(docs) + } + + return this.reciprocalRankFunction(docList, 60) + } + + reciprocalRankFunction(docList: Document>[][], k: number): Document>[] { + docList.forEach((docs: Document>[]) => { + docs.forEach((doc: any, index: number) => { + let rank = index + 1 + if (doc.metadata.relevancy_score) { + doc.metadata.relevancy_score += 1 / (rank + k) + } else { + doc.metadata.relevancy_score = 1 / (rank + k) + } + }) + }) + const scoreArray: any[] = [] + docList.forEach((docs: Document>[]) => { + docs.forEach((doc: any) => { + scoreArray.push(doc.metadata.relevancy_score) + }) + }) + scoreArray.sort((a, b) => b - a) + const rerankedDocuments: Document>[] = [] + const seenScores: any[] = [] + scoreArray.forEach((score) => { + docList.forEach((docs) => { + docs.forEach((doc: any) => { + if (doc.metadata.relevancy_score === score && seenScores.indexOf(score) === -1) { + rerankedDocuments.push(doc) + seenScores.push(doc.metadata.relevancy_score) + } + }) + }) + }) + return rerankedDocuments.splice(0, this.topK) + } +} diff --git a/packages/components/nodes/retrievers/RRFRetriever/compressionRetriever.svg b/packages/components/nodes/retrievers/RRFRetriever/compressionRetriever.svg new file mode 100644 index 00000000..23c52d25 --- /dev/null +++ b/packages/components/nodes/retrievers/RRFRetriever/compressionRetriever.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From d0ab21e733d03098a1faa3f0fd50b5d5baa9d381 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 29 Dec 2023 20:37:25 +0530 Subject: [PATCH 10/41] Compression Retriever: Addition of topK to Cohere Rerank Retriever --- .../CohereRerankRetriever/CohereRerank.ts | 8 +++++--- .../CohereRerankRetriever.ts | 19 ++++++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts index 612581ed..55f3c4aa 100644 --- a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts @@ -5,12 +5,13 @@ import axios from 'axios' export class CohereRerank extends BaseDocumentCompressor { private cohereAPIKey: any private COHERE_API_URL = 'https://api.cohere.ai/v1/rerank' - private model: string - - constructor(cohereAPIKey: string, model: string) { + private readonly model: string + private readonly k: number + constructor(cohereAPIKey: string, model: string, k: number) { super() this.cohereAPIKey = cohereAPIKey this.model = model + this.k = k } async compressDocuments( documents: Document>[], @@ -30,6 +31,7 @@ export class CohereRerank extends BaseDocumentCompressor { } const data = { model: this.model, + topN: this.k, max_chunks_per_doc: 10, query: query, return_documents: false, diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts index 2e7090bc..3c1872b3 100644 --- a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts @@ -3,6 +3,7 @@ import { BaseRetriever } from 'langchain/schema/retriever' import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' import { getCredentialData, getCredentialParam } from '../../../src' import { CohereRerank } from './CohereRerank' +import { VectorStoreRetriever } from 'langchain/vectorstores/base' class CohereRerankRetriever_Retrievers implements INode { label: string @@ -56,6 +57,16 @@ class CohereRerankRetriever_Retrievers implements INode { ], default: 'rerank-english-v2.0', optional: true + }, + { + label: 'Top K', + name: 'topK', + description: 'Number of top results to fetch. Default to the TopK of the Base Retriever', + placeholder: '0', + type: 'number', + default: 0, + additionalParams: true, + optional: true } ] } @@ -65,8 +76,14 @@ class CohereRerankRetriever_Retrievers implements INode { const model = nodeData.inputs?.model as string const credentialData = await getCredentialData(nodeData.credential ?? '', options) const cohereApiKey = getCredentialParam('cohereApiKey', credentialData, nodeData) + const topK = nodeData.inputs?.topK as string + let k = topK ? parseFloat(topK) : 4 - const cohereCompressor = new CohereRerank(cohereApiKey, model) + if (k <= 0) { + k = (baseRetriever as VectorStoreRetriever).k + } + + const cohereCompressor = new CohereRerank(cohereApiKey, model, k) return new ContextualCompressionRetriever({ baseCompressor: cohereCompressor, baseRetriever: baseRetriever From 1bd3b5d0ee9395ed5bce48eadc5c4e58f5385099 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sat, 30 Dec 2023 08:07:15 +0530 Subject: [PATCH 11/41] Compression Retriever: Addition of constant to RRF Retriever --- .../retrievers/RRFRetriever/RRFRetriever.ts | 16 +++++++++++++++- .../RRFRetriever/ReciprocalRankFusion.ts | 6 ++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts b/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts index 8d6d9d6f..3229b3a8 100644 --- a/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts +++ b/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts @@ -57,6 +57,18 @@ class RRFRetriever_Retrievers implements INode { default: 0, additionalParams: true, optional: true + }, + { + label: 'Constant', + name: 'c', + description: + 'A constant added to the rank, controlling the balance between the importance of high-ranked items and the consideration given to lower-ranked items.\n' + + 'Default is 60', + placeholder: '60', + type: 'number', + default: 60, + additionalParams: true, + optional: true } ] } @@ -68,12 +80,14 @@ class RRFRetriever_Retrievers implements INode { const q = queryCount ? parseFloat(queryCount) : 4 const topK = nodeData.inputs?.topK as string let k = topK ? parseFloat(topK) : 4 + const constantC = nodeData.inputs?.c as string + let c = topK ? parseFloat(constantC) : 60 if (k <= 0) { k = (baseRetriever as VectorStoreRetriever).k } - const ragFusion = new ReciprocalRankFusion(llm, baseRetriever as VectorStoreRetriever, q, k) + const ragFusion = new ReciprocalRankFusion(llm, baseRetriever as VectorStoreRetriever, q, k, c) return new ContextualCompressionRetriever({ baseCompressor: ragFusion, baseRetriever: baseRetriever diff --git a/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts b/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts index 134d7c8a..b14608fe 100644 --- a/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts +++ b/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts @@ -10,13 +10,15 @@ export class ReciprocalRankFusion extends BaseDocumentCompressor { private readonly llm: BaseLanguageModel private readonly queryCount: number private readonly topK: number + private readonly c: number private baseRetriever: VectorStoreRetriever - constructor(llm: BaseLanguageModel, baseRetriever: VectorStoreRetriever, queryCount: number, topK: number) { + constructor(llm: BaseLanguageModel, baseRetriever: VectorStoreRetriever, queryCount: number, topK: number, c: number) { super() this.queryCount = queryCount this.llm = llm this.baseRetriever = baseRetriever this.topK = topK + this.c = c } async compressDocuments( documents: Document>[], @@ -57,7 +59,7 @@ export class ReciprocalRankFusion extends BaseDocumentCompressor { docList.push(docs) } - return this.reciprocalRankFunction(docList, 60) + return this.reciprocalRankFunction(docList, this.c) } reciprocalRankFunction(docList: Document>[][], k: number): Document>[] { From fd55fa62dd6ba7d0679adb494bfb3f14070cdce3 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sat, 30 Dec 2023 08:08:15 +0530 Subject: [PATCH 12/41] fixes for lint failures --- .../nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts b/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts index b14608fe..0789ca17 100644 --- a/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts +++ b/packages/components/nodes/retrievers/RRFRetriever/ReciprocalRankFusion.ts @@ -48,7 +48,6 @@ export class ReciprocalRankFusion extends BaseDocumentCompressor { multipleQueries.text.split('\n').map((q: string) => { queries.push(q) }) - console.log(JSON.stringify(queries)) const docList: Document>[][] = [] for (let i = 0; i < queries.length; i++) { const resultOne = await this.baseRetriever.vectorStore.similaritySearch(queries[i], 5) From 3407fa92f4e39f8d4804257224639063deced46a Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Wed, 17 Jan 2024 18:29:37 +0530 Subject: [PATCH 13/41] Compression Retriever - Cohere Rerank - Add max chunks per document as optional parameter --- .../CohereRerankRetriever/CohereRerank.ts | 6 ++++-- .../CohereRerankRetriever/CohereRerankRetriever.ts | 13 ++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts index 55f3c4aa..f74b8365 100644 --- a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts @@ -7,11 +7,13 @@ export class CohereRerank extends BaseDocumentCompressor { private COHERE_API_URL = 'https://api.cohere.ai/v1/rerank' private readonly model: string private readonly k: number - constructor(cohereAPIKey: string, model: string, k: number) { + private readonly maxChunksPerDoc: number + constructor(cohereAPIKey: string, model: string, k: number, maxChunksPerDoc: number) { super() this.cohereAPIKey = cohereAPIKey this.model = model this.k = k + this.maxChunksPerDoc = maxChunksPerDoc } async compressDocuments( documents: Document>[], @@ -32,7 +34,7 @@ export class CohereRerank extends BaseDocumentCompressor { const data = { model: this.model, topN: this.k, - max_chunks_per_doc: 10, + max_chunks_per_doc: this.maxChunksPerDoc, query: query, return_documents: false, documents: documents.map((doc) => doc.pageContent) diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts index 3c1872b3..ca89ca77 100644 --- a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts @@ -67,6 +67,15 @@ class CohereRerankRetriever_Retrievers implements INode { default: 0, additionalParams: true, optional: true + }, + { + label: 'Max Chunks Per Document', + name: 'maxChunksPerDoc', + placeholder: '10', + type: 'number', + default: 10, + additionalParams: true, + optional: true } ] } @@ -78,12 +87,14 @@ class CohereRerankRetriever_Retrievers implements INode { const cohereApiKey = getCredentialParam('cohereApiKey', credentialData, nodeData) const topK = nodeData.inputs?.topK as string let k = topK ? parseFloat(topK) : 4 + const maxChunks = nodeData.inputs?.maxChunksPerDoc as string + let max = maxChunks ? parseInt(maxChunks) : 10 if (k <= 0) { k = (baseRetriever as VectorStoreRetriever).k } - const cohereCompressor = new CohereRerank(cohereApiKey, model, k) + const cohereCompressor = new CohereRerank(cohereApiKey, model, k, max) return new ContextualCompressionRetriever({ baseCompressor: cohereCompressor, baseRetriever: baseRetriever From 1bf7944776c83ceb3903fe9d33dba82f2acb1fdf Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 17 Jan 2024 15:55:56 +0000 Subject: [PATCH 14/41] update retrievers and add mmr to other vector stores --- .../CohereRerankRetriever/Cohere.svg | 1 + .../CohereRerankRetriever/CohereRerank.ts | 7 +- .../CohereRerankRetriever.ts | 74 ++++++++++++--- .../compressionRetriever.svg | 7 -- .../EmbeddingsFilterRetriever.ts | 62 ++++++++++--- .../retrievers/HydeRetriever/HydeRetriever.ts | 50 ++++++++++- .../LLMFilterCompressionRetriever.ts | 62 ++++++++++--- .../compressionRetriever.svg | 7 -- .../LLMFilterRetriever/llmFilterRetriever.svg | 1 + .../retrievers/RRFRetriever/RRFRetriever.ts | 64 ++++++++++--- .../RRFRetriever/compressionRetriever.svg | 7 -- .../retrievers/RRFRetriever/rrfRetriever.svg | 1 + .../SimilarityThresholdRetriever.ts | 21 +++-- .../nodes/vectorstores/Astra/Astra.ts | 16 +--- .../vectorstores/MongoDBAtlas/MongoDBAtlas.ts | 15 +--- .../nodes/vectorstores/Pinecone/Pinecone.ts | 2 +- .../marketplaces/chatflows/AutoGPT.json | 46 +++++++++- .../marketplaces/chatflows/BabyAGI.json | 46 +++++++++- .../Conversational Retrieval Agent.json | 46 +++++++++- .../Conversational Retrieval QA Chain.json | 46 +++++++++- .../chatflows/Metadata Filter.json | 46 +++++++++- .../chatflows/Multi Retrieval QA Chain.json | 90 ++++++++++++++++++- .../marketplaces/chatflows/WebPage QnA.json | 46 +++++++++- 23 files changed, 642 insertions(+), 121 deletions(-) create mode 100644 packages/components/nodes/retrievers/CohereRerankRetriever/Cohere.svg delete mode 100644 packages/components/nodes/retrievers/CohereRerankRetriever/compressionRetriever.svg delete mode 100644 packages/components/nodes/retrievers/LLMFilterRetriever/compressionRetriever.svg create mode 100644 packages/components/nodes/retrievers/LLMFilterRetriever/llmFilterRetriever.svg delete mode 100644 packages/components/nodes/retrievers/RRFRetriever/compressionRetriever.svg create mode 100644 packages/components/nodes/retrievers/RRFRetriever/rrfRetriever.svg diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/Cohere.svg b/packages/components/nodes/retrievers/CohereRerankRetriever/Cohere.svg new file mode 100644 index 00000000..88bcabe3 --- /dev/null +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/Cohere.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts index 55f3c4aa..e70c044f 100644 --- a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerank.ts @@ -7,11 +7,14 @@ export class CohereRerank extends BaseDocumentCompressor { private COHERE_API_URL = 'https://api.cohere.ai/v1/rerank' private readonly model: string private readonly k: number - constructor(cohereAPIKey: string, model: string, k: number) { + private readonly max_chunks_per_doc: number + + constructor(cohereAPIKey: string, model: string, k: number, max_chunks_per_doc: number) { super() this.cohereAPIKey = cohereAPIKey this.model = model this.k = k + this.max_chunks_per_doc = max_chunks_per_doc } async compressDocuments( documents: Document>[], @@ -32,8 +35,8 @@ export class CohereRerank extends BaseDocumentCompressor { const data = { model: this.model, topN: this.k, - max_chunks_per_doc: 10, query: query, + max_chunks_per_doc: this.max_chunks_per_doc, return_documents: false, documents: documents.map((doc) => doc.pageContent) } diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts index 3c1872b3..442fdc7a 100644 --- a/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts +++ b/packages/components/nodes/retrievers/CohereRerankRetriever/CohereRerankRetriever.ts @@ -1,7 +1,7 @@ import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { BaseRetriever } from 'langchain/schema/retriever' import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' -import { getCredentialData, getCredentialParam } from '../../../src' +import { getCredentialData, getCredentialParam, handleEscapeCharacters } from '../../../src' import { CohereRerank } from './CohereRerank' import { VectorStoreRetriever } from 'langchain/vectorstores/base' @@ -15,16 +15,16 @@ class CohereRerankRetriever_Retrievers implements INode { category: string baseClasses: string[] inputs: INodeParams[] - outputs: INodeOutputsValue[] credential: INodeParams badge: string + outputs: INodeOutputsValue[] constructor() { this.label = 'Cohere Rerank Retriever' this.name = 'cohereRerankRetriever' this.version = 1.0 this.type = 'Cohere Rerank Retriever' - this.icon = 'compressionRetriever.svg' + this.icon = 'Cohere.svg' this.category = 'Retrievers' this.badge = 'NEW' this.description = 'Cohere Rerank indexes the documents from most to least semantically relevant to the query.' @@ -37,7 +37,7 @@ class CohereRerankRetriever_Retrievers implements INode { } this.inputs = [ { - label: 'Base Retriever', + label: 'Vector Store Retriever', name: 'baseRetriever', type: 'VectorStoreRetriever' }, @@ -58,36 +58,84 @@ class CohereRerankRetriever_Retrievers implements INode { default: 'rerank-english-v2.0', optional: true }, + { + label: 'Query', + name: 'query', + type: 'string', + description: 'Query to retrieve documents from retriever. If not specified, user question will be used', + optional: true, + acceptVariable: true + }, { label: 'Top K', name: 'topK', description: 'Number of top results to fetch. Default to the TopK of the Base Retriever', - placeholder: '0', + placeholder: '4', + type: 'number', + additionalParams: true, + optional: true + }, + { + label: 'Max Chunks Per Doc', + name: 'maxChunksPerDoc', + description: 'The maximum number of chunks to produce internally from a document. Default to 10', + placeholder: '10', type: 'number', - default: 0, additionalParams: true, optional: true } ] + this.outputs = [ + { + label: 'Cohere Rerank Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Document', + name: 'document', + baseClasses: ['Document'] + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] } - async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { const baseRetriever = nodeData.inputs?.baseRetriever as BaseRetriever const model = nodeData.inputs?.model as string + const query = nodeData.inputs?.query as string const credentialData = await getCredentialData(nodeData.credential ?? '', options) const cohereApiKey = getCredentialParam('cohereApiKey', credentialData, nodeData) const topK = nodeData.inputs?.topK as string - let k = topK ? parseFloat(topK) : 4 + const k = topK ? parseFloat(topK) : (baseRetriever as VectorStoreRetriever).k ?? 4 + const maxChunksPerDoc = nodeData.inputs?.maxChunksPerDoc as string + const max_chunks_per_doc = maxChunksPerDoc ? parseFloat(maxChunksPerDoc) : 10 + const output = nodeData.outputs?.output as string - if (k <= 0) { - k = (baseRetriever as VectorStoreRetriever).k - } + const cohereCompressor = new CohereRerank(cohereApiKey, model, k, max_chunks_per_doc) - const cohereCompressor = new CohereRerank(cohereApiKey, model, k) - return new ContextualCompressionRetriever({ + const retriever = new ContextualCompressionRetriever({ baseCompressor: cohereCompressor, baseRetriever: baseRetriever }) + + if (output === 'retriever') return retriever + else if (output === 'document') return await retriever.getRelevantDocuments(query ? query : input) + else if (output === 'text') { + let finaltext = '' + + const docs = await retriever.getRelevantDocuments(query ? query : input) + + for (const doc of docs) finaltext += `${doc.pageContent}\n` + + return handleEscapeCharacters(finaltext, false) + } + + return retriever } } diff --git a/packages/components/nodes/retrievers/CohereRerankRetriever/compressionRetriever.svg b/packages/components/nodes/retrievers/CohereRerankRetriever/compressionRetriever.svg deleted file mode 100644 index 23c52d25..00000000 --- a/packages/components/nodes/retrievers/CohereRerankRetriever/compressionRetriever.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/EmbeddingsFilterRetriever.ts b/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/EmbeddingsFilterRetriever.ts index d373704c..d1049fa4 100644 --- a/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/EmbeddingsFilterRetriever.ts +++ b/packages/components/nodes/retrievers/EmbeddingsFilterRetriever/EmbeddingsFilterRetriever.ts @@ -3,6 +3,7 @@ import { BaseRetriever } from 'langchain/schema/retriever' import { Embeddings } from 'langchain/embeddings/base' import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' import { EmbeddingsFilter } from 'langchain/retrievers/document_compressors/embeddings_filter' +import { handleEscapeCharacters } from '../../../src/utils' class EmbeddingsFilterRetriever_Retrievers implements INode { label: string @@ -29,15 +30,22 @@ class EmbeddingsFilterRetriever_Retrievers implements INode { this.baseClasses = [this.type, 'BaseRetriever'] this.inputs = [ { - label: 'Base Retriever', + label: 'Vector Store Retriever', name: 'baseRetriever', type: 'VectorStoreRetriever' }, { label: 'Embeddings', name: 'embeddings', - type: 'Embeddings', - optional: false + type: 'Embeddings' + }, + { + label: 'Query', + name: 'query', + type: 'string', + description: 'Query to retrieve documents from retriever. If not specified, user question will be used', + optional: true, + acceptVariable: true }, { label: 'Similarity Threshold', @@ -61,36 +69,64 @@ class EmbeddingsFilterRetriever_Retrievers implements INode { additionalParams: true } ] + this.outputs = [ + { + label: 'Embeddings Filter Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Document', + name: 'document', + baseClasses: ['Document'] + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] } - async init(nodeData: INodeData): Promise { + async init(nodeData: INodeData, input: string): Promise { const baseRetriever = nodeData.inputs?.baseRetriever as BaseRetriever const embeddings = nodeData.inputs?.embeddings as Embeddings + const query = nodeData.inputs?.query as string const similarityThreshold = nodeData.inputs?.similarityThreshold as string const k = nodeData.inputs?.k as string + const output = nodeData.outputs?.output as string if (k === undefined && similarityThreshold === undefined) { throw new Error(`Must specify one of "k" or "similarity_threshold".`) } - let similarityThresholdNumber = 0.8 - if (similarityThreshold) { - similarityThresholdNumber = parseFloat(similarityThreshold) - } - let kNumber = 0.8 - if (k) { - kNumber = parseFloat(k) - } + const similarityThresholdNumber = similarityThreshold ? parseFloat(similarityThreshold) : 0.8 + const kNumber = k ? parseFloat(k) : undefined + const baseCompressor = new EmbeddingsFilter({ embeddings: embeddings, similarityThreshold: similarityThresholdNumber, k: kNumber }) - return new ContextualCompressionRetriever({ + const retriever = new ContextualCompressionRetriever({ baseCompressor, baseRetriever: baseRetriever }) + + if (output === 'retriever') return retriever + else if (output === 'document') return await retriever.getRelevantDocuments(query ? query : input) + else if (output === 'text') { + let finaltext = '' + + const docs = await retriever.getRelevantDocuments(query ? query : input) + + for (const doc of docs) finaltext += `${doc.pageContent}\n` + + return handleEscapeCharacters(finaltext, false) + } + + return retriever } } diff --git a/packages/components/nodes/retrievers/HydeRetriever/HydeRetriever.ts b/packages/components/nodes/retrievers/HydeRetriever/HydeRetriever.ts index 10d9a6e7..10fff764 100644 --- a/packages/components/nodes/retrievers/HydeRetriever/HydeRetriever.ts +++ b/packages/components/nodes/retrievers/HydeRetriever/HydeRetriever.ts @@ -1,8 +1,9 @@ import { VectorStore } from 'langchain/vectorstores/base' -import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { HydeRetriever, HydeRetrieverOptions, PromptKey } from 'langchain/retrievers/hyde' import { BaseLanguageModel } from 'langchain/base_language' import { PromptTemplate } from 'langchain/prompts' +import { handleEscapeCharacters } from '../../../src/utils' class HydeRetriever_Retrievers implements INode { label: string @@ -14,11 +15,12 @@ class HydeRetriever_Retrievers implements INode { category: string baseClasses: string[] inputs: INodeParams[] + outputs: INodeOutputsValue[] constructor() { - this.label = 'Hyde Retriever' + this.label = 'HyDE Retriever' this.name = 'HydeRetriever' - this.version = 2.0 + this.version = 3.0 this.type = 'HydeRetriever' this.icon = 'hyderetriever.svg' this.category = 'Retrievers' @@ -35,6 +37,14 @@ class HydeRetriever_Retrievers implements INode { name: 'vectorStore', type: 'VectorStore' }, + { + label: 'Query', + name: 'query', + type: 'string', + description: 'Query to retrieve documents from retriever. If not specified, user question will be used', + optional: true, + acceptVariable: true + }, { label: 'Select Defined Prompt', name: 'promptKey', @@ -121,15 +131,34 @@ Passage:` optional: true } ] + this.outputs = [ + { + label: 'HyDE Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Document', + name: 'document', + baseClasses: ['Document'] + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] } - async init(nodeData: INodeData): Promise { + async init(nodeData: INodeData, input: string): Promise { const llm = nodeData.inputs?.model as BaseLanguageModel const vectorStore = nodeData.inputs?.vectorStore as VectorStore const promptKey = nodeData.inputs?.promptKey as PromptKey const customPrompt = nodeData.inputs?.customPrompt as string + const query = nodeData.inputs?.query as string const topK = nodeData.inputs?.topK as string const k = topK ? parseFloat(topK) : 4 + const output = nodeData.outputs?.output as string const obj: HydeRetrieverOptions = { llm, @@ -141,6 +170,19 @@ Passage:` else if (promptKey) obj.promptTemplate = promptKey const retriever = new HydeRetriever(obj) + + if (output === 'retriever') return retriever + else if (output === 'document') return await retriever.getRelevantDocuments(query ? query : input) + else if (output === 'text') { + let finaltext = '' + + const docs = await retriever.getRelevantDocuments(query ? query : input) + + for (const doc of docs) finaltext += `${doc.pageContent}\n` + + return handleEscapeCharacters(finaltext, false) + } + return retriever } } diff --git a/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts b/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts index e044468f..6b710cf3 100644 --- a/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts +++ b/packages/components/nodes/retrievers/LLMFilterRetriever/LLMFilterCompressionRetriever.ts @@ -3,6 +3,7 @@ import { BaseRetriever } from 'langchain/schema/retriever' import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' import { BaseLanguageModel } from 'langchain/base_language' import { LLMChainExtractor } from 'langchain/retrievers/document_compressors/chain_extract' +import { handleEscapeCharacters } from '../../../src/utils' class LLMFilterCompressionRetriever_Retrievers implements INode { label: string @@ -22,7 +23,7 @@ class LLMFilterCompressionRetriever_Retrievers implements INode { this.name = 'llmFilterRetriever' this.version = 1.0 this.type = 'LLMFilterRetriever' - this.icon = 'compressionRetriever.svg' + this.icon = 'llmFilterRetriever.svg' this.category = 'Retrievers' this.badge = 'NEW' this.description = @@ -30,30 +31,69 @@ class LLMFilterCompressionRetriever_Retrievers implements INode { this.baseClasses = [this.type, 'BaseRetriever'] this.inputs = [ { - label: 'Base Retriever', + label: 'Vector Store Retriever', name: 'baseRetriever', type: 'VectorStoreRetriever' }, { label: 'Language Model', name: 'model', - type: 'BaseLanguageModel', - optional: true + type: 'BaseLanguageModel' + }, + { + label: 'Query', + name: 'query', + type: 'string', + description: 'Query to retrieve documents from retriever. If not specified, user question will be used', + optional: true, + acceptVariable: true + } + ] + this.outputs = [ + { + label: 'LLM Filter Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Document', + name: 'document', + baseClasses: ['Document'] + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] } ] } - async init(nodeData: INodeData): Promise { + async init(nodeData: INodeData, input: string): Promise { const baseRetriever = nodeData.inputs?.baseRetriever as BaseRetriever const model = nodeData.inputs?.model as BaseLanguageModel + const query = nodeData.inputs?.query as string + const output = nodeData.outputs?.output as string - if (model) { - return new ContextualCompressionRetriever({ - baseCompressor: LLMChainExtractor.fromLLM(model), - baseRetriever: baseRetriever - }) + if (!model) throw new Error('There must be a LLM model connected to LLM Filter Retriever') + + const retriever = new ContextualCompressionRetriever({ + baseCompressor: LLMChainExtractor.fromLLM(model), + baseRetriever: baseRetriever + }) + + if (output === 'retriever') return retriever + else if (output === 'document') return await retriever.getRelevantDocuments(query ? query : input) + else if (output === 'text') { + let finaltext = '' + + const docs = await retriever.getRelevantDocuments(query ? query : input) + + for (const doc of docs) finaltext += `${doc.pageContent}\n` + + return handleEscapeCharacters(finaltext, false) } - return {} + + return retriever } } diff --git a/packages/components/nodes/retrievers/LLMFilterRetriever/compressionRetriever.svg b/packages/components/nodes/retrievers/LLMFilterRetriever/compressionRetriever.svg deleted file mode 100644 index 23c52d25..00000000 --- a/packages/components/nodes/retrievers/LLMFilterRetriever/compressionRetriever.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/packages/components/nodes/retrievers/LLMFilterRetriever/llmFilterRetriever.svg b/packages/components/nodes/retrievers/LLMFilterRetriever/llmFilterRetriever.svg new file mode 100644 index 00000000..d3f4d15f --- /dev/null +++ b/packages/components/nodes/retrievers/LLMFilterRetriever/llmFilterRetriever.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts b/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts index 3229b3a8..ed15ed24 100644 --- a/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts +++ b/packages/components/nodes/retrievers/RRFRetriever/RRFRetriever.ts @@ -1,9 +1,10 @@ -import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { BaseLanguageModel } from 'langchain/base_language' import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' import { BaseRetriever } from 'langchain/schema/retriever' import { ReciprocalRankFusion } from './ReciprocalRankFusion' import { VectorStoreRetriever } from 'langchain/vectorstores/base' +import { handleEscapeCharacters } from '../../../src/utils' class RRFRetriever_Retrievers implements INode { label: string @@ -16,20 +17,21 @@ class RRFRetriever_Retrievers implements INode { baseClasses: string[] inputs: INodeParams[] badge: string + outputs: INodeOutputsValue[] constructor() { this.label = 'Reciprocal Rank Fusion Retriever' this.name = 'RRFRetriever' - this.version = 2.0 + this.version = 1.0 this.type = 'RRFRetriever' this.badge = 'NEW' - this.icon = 'compressionRetriever.svg' + this.icon = 'rrfRetriever.svg' this.category = 'Retrievers' this.description = 'Reciprocal Rank Fusion to re-rank search results by multiple query generation.' this.baseClasses = [this.type, 'BaseRetriever'] this.inputs = [ { - label: 'Base Retriever', + label: 'Vector Store Retriever', name: 'baseRetriever', type: 'VectorStoreRetriever' }, @@ -38,6 +40,14 @@ class RRFRetriever_Retrievers implements INode { name: 'model', type: 'BaseLanguageModel' }, + { + label: 'Query', + name: 'query', + type: 'string', + description: 'Query to retrieve documents from retriever. If not specified, user question will be used', + optional: true, + acceptVariable: true + }, { label: 'Query Count', name: 'queryCount', @@ -54,7 +64,6 @@ class RRFRetriever_Retrievers implements INode { description: 'Number of top results to fetch. Default to the TopK of the Base Retriever', placeholder: '0', type: 'number', - default: 0, additionalParams: true, optional: true }, @@ -71,27 +80,56 @@ class RRFRetriever_Retrievers implements INode { optional: true } ] + this.outputs = [ + { + label: 'Reciprocal Rank Fusion Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Document', + name: 'document', + baseClasses: ['Document'] + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] } - async init(nodeData: INodeData): Promise { + async init(nodeData: INodeData, input: string): Promise { const llm = nodeData.inputs?.model as BaseLanguageModel const baseRetriever = nodeData.inputs?.baseRetriever as BaseRetriever + const query = nodeData.inputs?.query as string const queryCount = nodeData.inputs?.queryCount as string const q = queryCount ? parseFloat(queryCount) : 4 const topK = nodeData.inputs?.topK as string - let k = topK ? parseFloat(topK) : 4 + const k = topK ? parseFloat(topK) : (baseRetriever as VectorStoreRetriever).k ?? 4 const constantC = nodeData.inputs?.c as string - let c = topK ? parseFloat(constantC) : 60 - - if (k <= 0) { - k = (baseRetriever as VectorStoreRetriever).k - } + const c = topK ? parseFloat(constantC) : 60 + const output = nodeData.outputs?.output as string const ragFusion = new ReciprocalRankFusion(llm, baseRetriever as VectorStoreRetriever, q, k, c) - return new ContextualCompressionRetriever({ + const retriever = new ContextualCompressionRetriever({ baseCompressor: ragFusion, baseRetriever: baseRetriever }) + + if (output === 'retriever') return retriever + else if (output === 'document') return await retriever.getRelevantDocuments(query ? query : input) + else if (output === 'text') { + let finaltext = '' + + const docs = await retriever.getRelevantDocuments(query ? query : input) + + for (const doc of docs) finaltext += `${doc.pageContent}\n` + + return handleEscapeCharacters(finaltext, false) + } + + return retriever } } diff --git a/packages/components/nodes/retrievers/RRFRetriever/compressionRetriever.svg b/packages/components/nodes/retrievers/RRFRetriever/compressionRetriever.svg deleted file mode 100644 index 23c52d25..00000000 --- a/packages/components/nodes/retrievers/RRFRetriever/compressionRetriever.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/packages/components/nodes/retrievers/RRFRetriever/rrfRetriever.svg b/packages/components/nodes/retrievers/RRFRetriever/rrfRetriever.svg new file mode 100644 index 00000000..56fbcc5a --- /dev/null +++ b/packages/components/nodes/retrievers/RRFRetriever/rrfRetriever.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/components/nodes/retrievers/SimilarityThresholdRetriever/SimilarityThresholdRetriever.ts b/packages/components/nodes/retrievers/SimilarityThresholdRetriever/SimilarityThresholdRetriever.ts index a9f4b3d8..5f5a9ed0 100644 --- a/packages/components/nodes/retrievers/SimilarityThresholdRetriever/SimilarityThresholdRetriever.ts +++ b/packages/components/nodes/retrievers/SimilarityThresholdRetriever/SimilarityThresholdRetriever.ts @@ -18,7 +18,7 @@ class SimilarityThresholdRetriever_Retrievers implements INode { constructor() { this.label = 'Similarity Score Threshold Retriever' this.name = 'similarityThresholdRetriever' - this.version = 1.0 + this.version = 2.0 this.type = 'SimilarityThresholdRetriever' this.icon = 'similaritythreshold.svg' this.category = 'Retrievers' @@ -30,6 +30,14 @@ class SimilarityThresholdRetriever_Retrievers implements INode { name: 'vectorStore', type: 'VectorStore' }, + { + label: 'Query', + name: 'query', + type: 'string', + description: 'Query to retrieve documents from retriever. If not specified, user question will be used', + optional: true, + acceptVariable: true + }, { label: 'Minimum Similarity Score (%)', name: 'minSimilarityScore', @@ -44,7 +52,8 @@ class SimilarityThresholdRetriever_Retrievers implements INode { description: `The maximum number of results to fetch`, type: 'number', default: 20, - step: 1 + step: 1, + additionalParams: true }, { label: 'K Increment', @@ -52,7 +61,8 @@ class SimilarityThresholdRetriever_Retrievers implements INode { description: `How much to increase K by each time. It'll fetch N results, then N + kIncrement, then N + kIncrement * 2, etc.`, type: 'number', default: 2, - step: 1 + step: 1, + additionalParams: true } ] this.outputs = [ @@ -77,6 +87,7 @@ class SimilarityThresholdRetriever_Retrievers implements INode { async init(nodeData: INodeData, input: string): Promise { const vectorStore = nodeData.inputs?.vectorStore as VectorStore const minSimilarityScore = nodeData.inputs?.minSimilarityScore as number + const query = nodeData.inputs?.query as string const maxK = nodeData.inputs?.maxK as string const kIncrement = nodeData.inputs?.kIncrement as string @@ -89,11 +100,11 @@ class SimilarityThresholdRetriever_Retrievers implements INode { }) if (output === 'retriever') return retriever - else if (output === 'document') return await retriever.getRelevantDocuments(input) + else if (output === 'document') return await retriever.getRelevantDocuments(query ? query : input) else if (output === 'text') { let finaltext = '' - const docs = await retriever.getRelevantDocuments(input) + const docs = await retriever.getRelevantDocuments(query ? query : input) for (const doc of docs) finaltext += `${doc.pageContent}\n` diff --git a/packages/components/nodes/vectorstores/Astra/Astra.ts b/packages/components/nodes/vectorstores/Astra/Astra.ts index 865f1044..edaadc9c 100644 --- a/packages/components/nodes/vectorstores/Astra/Astra.ts +++ b/packages/components/nodes/vectorstores/Astra/Astra.ts @@ -4,6 +4,7 @@ import { Document } from 'langchain/document' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData } from '../../../src/utils' import { AstraDBVectorStore, AstraLibArgs } from '@langchain/community/vectorstores/astradb' +import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils' class Astra_VectorStores implements INode { label: string @@ -26,7 +27,7 @@ class Astra_VectorStores implements INode { this.type = 'Astra' this.icon = 'astra.svg' this.category = 'Vector Stores' - this.description = `Upsert embedded data and perform similarity search upon query using DataStax Astra DB, a serverless vector database that’s perfect for managing mission-critical AI workloads` + this.description = `Upsert embedded data and perform similarity or mmr search upon query using DataStax Astra DB, a serverless vector database that’s perfect for managing mission-critical AI workloads` this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] this.badge = 'NEW' this.credential = { @@ -74,6 +75,7 @@ class Astra_VectorStores implements INode { optional: true } ] + addMMRInputParams(this.inputs) this.outputs = [ { label: 'Astra Retriever', @@ -139,9 +141,6 @@ class Astra_VectorStores implements INode { const embeddings = nodeData.inputs?.embeddings as Embeddings const vectorDimension = nodeData.inputs?.vectorDimension as number const similarityMetric = nodeData.inputs?.similarityMetric as 'cosine' | 'euclidean' | 'dot_product' | undefined - const output = nodeData.outputs?.output as string - const topK = nodeData.inputs?.topK as string - const k = topK ? parseFloat(topK) : 4 const credentialData = await getCredentialData(nodeData.credential ?? '', options) @@ -176,14 +175,7 @@ class Astra_VectorStores implements INode { const vectorStore = await AstraDBVectorStore.fromExistingIndex(embeddings, astraConfig) - if (output === 'retriever') { - const retriever = vectorStore.asRetriever(k) - return retriever - } else if (output === 'vectorStore') { - ;(vectorStore as any).k = k - return vectorStore - } - return vectorStore + return resolveVectorStoreOrRetriever(nodeData, vectorStore) } } diff --git a/packages/components/nodes/vectorstores/MongoDBAtlas/MongoDBAtlas.ts b/packages/components/nodes/vectorstores/MongoDBAtlas/MongoDBAtlas.ts index 9bc23f10..6ba7199f 100644 --- a/packages/components/nodes/vectorstores/MongoDBAtlas/MongoDBAtlas.ts +++ b/packages/components/nodes/vectorstores/MongoDBAtlas/MongoDBAtlas.ts @@ -5,6 +5,7 @@ import { Embeddings } from 'langchain/embeddings/base' import { Document } from 'langchain/document' import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStoreUtils' class MongoDBAtlas_VectorStores implements INode { label: string @@ -24,7 +25,7 @@ class MongoDBAtlas_VectorStores implements INode { this.label = 'MongoDB Atlas' this.name = 'mongoDBAtlas' this.version = 1.0 - this.description = `Upsert embedded data and perform similarity search upon query using MongoDB Atlas, a managed cloud mongodb database` + this.description = `Upsert embedded data and perform similarity or mmr search upon query using MongoDB Atlas, a managed cloud mongodb database` this.type = 'MongoDB Atlas' this.icon = 'mongodb.svg' this.category = 'Vector Stores' @@ -95,6 +96,7 @@ class MongoDBAtlas_VectorStores implements INode { optional: true } ] + addMMRInputParams(this.inputs) this.outputs = [ { label: 'MongoDB Retriever', @@ -162,9 +164,6 @@ class MongoDBAtlas_VectorStores implements INode { let textKey = nodeData.inputs?.textKey as string let embeddingKey = nodeData.inputs?.embeddingKey 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 let mongoDBConnectUrl = getCredentialParam('mongoDBConnectUrl', credentialData, nodeData) @@ -181,13 +180,7 @@ class MongoDBAtlas_VectorStores implements INode { embeddingKey }) - if (output === 'retriever') { - return vectorStore.asRetriever(k) - } else if (output === 'vectorStore') { - ;(vectorStore as any).k = k - return vectorStore - } - return vectorStore + return resolveVectorStoreOrRetriever(nodeData, vectorStore) } } diff --git a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts index 4b91a9b5..6623b1a2 100644 --- a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts +++ b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts @@ -24,7 +24,7 @@ class Pinecone_VectorStores implements INode { constructor() { this.label = 'Pinecone' this.name = 'pinecone' - this.version = 3.0 + this.version = 2.0 this.type = 'Pinecone' this.icon = 'pinecone.svg' this.category = 'Vector Stores' diff --git a/packages/server/marketplaces/chatflows/AutoGPT.json b/packages/server/marketplaces/chatflows/AutoGPT.json index 150fe17e..0062cd43 100644 --- a/packages/server/marketplaces/chatflows/AutoGPT.json +++ b/packages/server/marketplaces/chatflows/AutoGPT.json @@ -511,7 +511,7 @@ "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", - "description": "Upsert embedded data and perform similarity search upon query using Pinecone, a leading fully managed hosted vector database", + "description": "Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database", "inputParams": [ { "label": "Connect Credential", @@ -552,6 +552,45 @@ "additionalParams": true, "optional": true, "id": "pinecone_0-input-topK-number" + }, + { + "label": "Search Type", + "name": "searchType", + "type": "options", + "default": "similarity", + "options": [ + { + "label": "Similarity", + "name": "similarity" + }, + { + "label": "Max Marginal Relevance", + "name": "mmr" + } + ], + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-searchType-options" + }, + { + "label": "Fetch K (for MMR Search)", + "name": "fetchK", + "description": "Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR", + "placeholder": "20", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-fetchK-number" + }, + { + "label": "Lambda (for MMR Search)", + "name": "lambda", + "description": "Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR", + "placeholder": "0.5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-lambda-number" } ], "inputAnchors": [ @@ -576,7 +615,10 @@ "pineconeIndex": "", "pineconeNamespace": "", "pineconeMetadataFilter": "", - "topK": "" + "topK": "", + "searchType": "similarity", + "fetchK": "", + "lambda": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/BabyAGI.json b/packages/server/marketplaces/chatflows/BabyAGI.json index ab387205..81e3f230 100644 --- a/packages/server/marketplaces/chatflows/BabyAGI.json +++ b/packages/server/marketplaces/chatflows/BabyAGI.json @@ -166,7 +166,7 @@ "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", - "description": "Upsert embedded data and perform similarity search upon query using Pinecone, a leading fully managed hosted vector database", + "description": "Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database", "inputParams": [ { "label": "Connect Credential", @@ -207,6 +207,45 @@ "additionalParams": true, "optional": true, "id": "pinecone_0-input-topK-number" + }, + { + "label": "Search Type", + "name": "searchType", + "type": "options", + "default": "similarity", + "options": [ + { + "label": "Similarity", + "name": "similarity" + }, + { + "label": "Max Marginal Relevance", + "name": "mmr" + } + ], + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-searchType-options" + }, + { + "label": "Fetch K (for MMR Search)", + "name": "fetchK", + "description": "Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR", + "placeholder": "20", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-fetchK-number" + }, + { + "label": "Lambda (for MMR Search)", + "name": "lambda", + "description": "Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR", + "placeholder": "0.5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-lambda-number" } ], "inputAnchors": [ @@ -231,7 +270,10 @@ "pineconeIndex": "", "pineconeNamespace": "", "pineconeMetadataFilter": "", - "topK": "" + "topK": "", + "searchType": "similarity", + "fetchK": "", + "lambda": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json index 0e9e41bd..4378a47d 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval Agent.json @@ -301,7 +301,7 @@ "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", - "description": "Upsert embedded data and perform similarity search upon query using Pinecone, a leading fully managed hosted vector database", + "description": "Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database", "inputParams": [ { "label": "Connect Credential", @@ -342,6 +342,45 @@ "additionalParams": true, "optional": true, "id": "pinecone_0-input-topK-number" + }, + { + "label": "Search Type", + "name": "searchType", + "type": "options", + "default": "similarity", + "options": [ + { + "label": "Similarity", + "name": "similarity" + }, + { + "label": "Max Marginal Relevance", + "name": "mmr" + } + ], + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-searchType-options" + }, + { + "label": "Fetch K (for MMR Search)", + "name": "fetchK", + "description": "Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR", + "placeholder": "20", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-fetchK-number" + }, + { + "label": "Lambda (for MMR Search)", + "name": "lambda", + "description": "Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR", + "placeholder": "0.5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-lambda-number" } ], "inputAnchors": [ @@ -366,7 +405,10 @@ "pineconeIndex": "", "pineconeNamespace": "", "pineconeMetadataFilter": "", - "topK": "" + "topK": "", + "searchType": "similarity", + "fetchK": "", + "lambda": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json index e2fd6421..253a1dfc 100644 --- a/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json @@ -541,7 +541,7 @@ "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", - "description": "Upsert embedded data and perform similarity search upon query using Pinecone, a leading fully managed hosted vector database", + "description": "Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database", "inputParams": [ { "label": "Connect Credential", @@ -582,6 +582,45 @@ "additionalParams": true, "optional": true, "id": "pinecone_0-input-topK-number" + }, + { + "label": "Search Type", + "name": "searchType", + "type": "options", + "default": "similarity", + "options": [ + { + "label": "Similarity", + "name": "similarity" + }, + { + "label": "Max Marginal Relevance", + "name": "mmr" + } + ], + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-searchType-options" + }, + { + "label": "Fetch K (for MMR Search)", + "name": "fetchK", + "description": "Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR", + "placeholder": "20", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-fetchK-number" + }, + { + "label": "Lambda (for MMR Search)", + "name": "lambda", + "description": "Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR", + "placeholder": "0.5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-lambda-number" } ], "inputAnchors": [ @@ -606,7 +645,10 @@ "pineconeIndex": "", "pineconeNamespace": "", "pineconeMetadataFilter": "", - "topK": "" + "topK": "", + "searchType": "similarity", + "fetchK": "", + "lambda": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/Metadata Filter.json b/packages/server/marketplaces/chatflows/Metadata Filter.json index abd85d36..f7b2fbfb 100644 --- a/packages/server/marketplaces/chatflows/Metadata Filter.json +++ b/packages/server/marketplaces/chatflows/Metadata Filter.json @@ -625,7 +625,7 @@ "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", - "description": "Upsert embedded data and perform similarity search upon query using Pinecone, a leading fully managed hosted vector database", + "description": "Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database", "inputParams": [ { "label": "Connect Credential", @@ -666,6 +666,45 @@ "additionalParams": true, "optional": true, "id": "pinecone_0-input-topK-number" + }, + { + "label": "Search Type", + "name": "searchType", + "type": "options", + "default": "similarity", + "options": [ + { + "label": "Similarity", + "name": "similarity" + }, + { + "label": "Max Marginal Relevance", + "name": "mmr" + } + ], + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-searchType-options" + }, + { + "label": "Fetch K (for MMR Search)", + "name": "fetchK", + "description": "Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR", + "placeholder": "20", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-fetchK-number" + }, + { + "label": "Lambda (for MMR Search)", + "name": "lambda", + "description": "Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR", + "placeholder": "0.5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-lambda-number" } ], "inputAnchors": [ @@ -690,7 +729,10 @@ "pineconeIndex": "", "pineconeNamespace": "", "pineconeMetadataFilter": "{\"id\":{\"$in\":[\"doc1\",\"doc2\"]}}", - "topK": "" + "topK": "", + "searchType": "similarity", + "fetchK": "", + "lambda": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json index 5388d965..e86b28c9 100644 --- a/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json +++ b/packages/server/marketplaces/chatflows/Multi Retrieval QA Chain.json @@ -560,7 +560,7 @@ "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", - "description": "Upsert embedded data and perform similarity search upon query using Pinecone, a leading fully managed hosted vector database", + "description": "Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database", "inputParams": [ { "label": "Connect Credential", @@ -601,6 +601,45 @@ "additionalParams": true, "optional": true, "id": "pinecone_0-input-topK-number" + }, + { + "label": "Search Type", + "name": "searchType", + "type": "options", + "default": "similarity", + "options": [ + { + "label": "Similarity", + "name": "similarity" + }, + { + "label": "Max Marginal Relevance", + "name": "mmr" + } + ], + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-searchType-options" + }, + { + "label": "Fetch K (for MMR Search)", + "name": "fetchK", + "description": "Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR", + "placeholder": "20", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-fetchK-number" + }, + { + "label": "Lambda (for MMR Search)", + "name": "lambda", + "description": "Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR", + "placeholder": "0.5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-lambda-number" } ], "inputAnchors": [ @@ -625,7 +664,10 @@ "pineconeIndex": "", "pineconeNamespace": "", "pineconeMetadataFilter": "", - "topK": "" + "topK": "", + "searchType": "similarity", + "fetchK": "", + "lambda": "" }, "outputAnchors": [ { @@ -840,6 +882,45 @@ "additionalParams": true, "optional": true, "id": "supabase_0-input-topK-number" + }, + { + "label": "Search Type", + "name": "searchType", + "type": "options", + "default": "similarity", + "options": [ + { + "label": "Similarity", + "name": "similarity" + }, + { + "label": "Max Marginal Relevance", + "name": "mmr" + } + ], + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-searchType-options" + }, + { + "label": "Fetch K (for MMR Search)", + "name": "fetchK", + "description": "Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR", + "placeholder": "20", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-fetchK-number" + }, + { + "label": "Lambda (for MMR Search)", + "name": "lambda", + "description": "Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR", + "placeholder": "0.5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-lambda-number" } ], "inputAnchors": [ @@ -865,7 +946,10 @@ "tableName": "", "queryName": "", "supabaseMetadataFilter": "", - "topK": "" + "topK": "", + "searchType": "similarity", + "fetchK": "", + "lambda": "" }, "outputAnchors": [ { diff --git a/packages/server/marketplaces/chatflows/WebPage QnA.json b/packages/server/marketplaces/chatflows/WebPage QnA.json index 1b1d8de6..df05feef 100644 --- a/packages/server/marketplaces/chatflows/WebPage QnA.json +++ b/packages/server/marketplaces/chatflows/WebPage QnA.json @@ -643,7 +643,7 @@ "type": "Pinecone", "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", - "description": "Upsert embedded data and perform similarity search upon query using Pinecone, a leading fully managed hosted vector database", + "description": "Upsert embedded data and perform similarity or mmr search using Pinecone, a leading fully managed hosted vector database", "inputParams": [ { "label": "Connect Credential", @@ -684,6 +684,45 @@ "additionalParams": true, "optional": true, "id": "pinecone_0-input-topK-number" + }, + { + "label": "Search Type", + "name": "searchType", + "type": "options", + "default": "similarity", + "options": [ + { + "label": "Similarity", + "name": "similarity" + }, + { + "label": "Max Marginal Relevance", + "name": "mmr" + } + ], + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-searchType-options" + }, + { + "label": "Fetch K (for MMR Search)", + "name": "fetchK", + "description": "Number of initial documents to fetch for MMR reranking. Default to 20. Used only when the search type is MMR", + "placeholder": "20", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-fetchK-number" + }, + { + "label": "Lambda (for MMR Search)", + "name": "lambda", + "description": "Number between 0 and 1 that determines the degree of diversity among the results, where 0 corresponds to maximum diversity and 1 to minimum diversity. Used only when the search type is MMR", + "placeholder": "0.5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pinecone_0-input-lambda-number" } ], "inputAnchors": [ @@ -708,7 +747,10 @@ "pineconeIndex": "", "pineconeNamespace": "", "pineconeMetadataFilter": "", - "topK": "" + "topK": "", + "searchType": "similarity", + "fetchK": "", + "lambda": "" }, "outputAnchors": [ { From f26a99ade246a11d8cead064807cdf6752e83fbc Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 17 Jan 2024 22:08:04 +0000 Subject: [PATCH 15/41] update figma loader --- .../nodes/documentloaders/Figma/Figma.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/components/nodes/documentloaders/Figma/Figma.ts b/packages/components/nodes/documentloaders/Figma/Figma.ts index 3d313044..6d7aa530 100644 --- a/packages/components/nodes/documentloaders/Figma/Figma.ts +++ b/packages/components/nodes/documentloaders/Figma/Figma.ts @@ -1,6 +1,7 @@ import { getCredentialData, getCredentialParam } from '../../../src' import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' import { FigmaFileLoader, FigmaLoaderParams } from 'langchain/document_loaders/web/figma' +import { TextSplitter } from 'langchain/text_splitter' class Figma_DocumentLoaders implements INode { label: string @@ -71,6 +72,8 @@ class Figma_DocumentLoaders implements INode { async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { const nodeIds = (nodeData.inputs?.nodeIds as string)?.trim().split(',') || [] const fileKey = nodeData.inputs?.fileKey as string + const textSplitter = nodeData.inputs?.textSplitter as TextSplitter + const metadata = nodeData.inputs?.metadata const credentialData = await getCredentialData(nodeData.credential ?? '', options) const accessToken = getCredentialParam('accessToken', credentialData, nodeData) @@ -82,7 +85,21 @@ class Figma_DocumentLoaders implements INode { } const loader = new FigmaFileLoader(figmaOptions) - const docs = await loader.load() + + const docs = textSplitter ? await loader.loadAndSplit() : await loader.load() + + if (metadata) { + const parsedMetadata = typeof metadata === 'object' ? metadata : JSON.parse(metadata) + return docs.map((doc) => { + return { + ...doc, + metadata: { + ...doc.metadata, + ...parsedMetadata + } + } + }) + } return docs } From 4256655c7bace928ff4bc8e12ebe81696c9304f1 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 17 Jan 2024 23:47:11 +0000 Subject: [PATCH 16/41] add $vars and $flow to custom function --- .../nodes/tools/CustomTool/CustomTool.ts | 20 +----- .../components/nodes/tools/CustomTool/core.ts | 39 +--------- .../CustomFunction/CustomFunction.ts | 35 +++++---- .../IfElseFunction/IfElseFunction.ts | 35 +++++---- packages/components/src/Interface.ts | 6 ++ packages/components/src/utils.ts | 72 ++++++++++++++++++- packages/server/src/index.ts | 27 +++++-- packages/server/src/utils/index.ts | 3 + 8 files changed, 136 insertions(+), 101 deletions(-) diff --git a/packages/components/nodes/tools/CustomTool/CustomTool.ts b/packages/components/nodes/tools/CustomTool/CustomTool.ts index a983d0d9..6ba5bc26 100644 --- a/packages/components/nodes/tools/CustomTool/CustomTool.ts +++ b/packages/components/nodes/tools/CustomTool/CustomTool.ts @@ -1,5 +1,5 @@ import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../src/Interface' -import { convertSchemaToZod, getBaseClasses } from '../../../src/utils' +import { convertSchemaToZod, getBaseClasses, getVars } from '../../../src/utils' import { DynamicStructuredTool } from './core' import { z } from 'zod' import { DataSource } from 'typeorm' @@ -81,23 +81,7 @@ class CustomTool_Tools implements INode { } if (customToolFunc) obj.code = customToolFunc - const variables = await appDataSource.getRepository(databaseEntities['Variable']).find() - - // override variables defined in overrideConfig - // nodeData.inputs.variables is an Object, check each property and override the variable - if (nodeData?.inputs?.vars) { - for (const propertyName of Object.getOwnPropertyNames(nodeData.inputs.vars)) { - const foundVar = variables.find((v) => v.name === propertyName) - if (foundVar) { - // even if the variable was defined as runtime, we override it with static value - foundVar.type = 'static' - foundVar.value = nodeData.inputs.vars[propertyName] - } else { - // add it the variables, if not found locally in the db - variables.push({ name: propertyName, type: 'static', value: nodeData.inputs.vars[propertyName] }) - } - } - } + const variables = await getVars(appDataSource, databaseEntities, nodeData) const flow = { chatflowId: options.chatflowid } diff --git a/packages/components/nodes/tools/CustomTool/core.ts b/packages/components/nodes/tools/CustomTool/core.ts index b543aefa..19be88f1 100644 --- a/packages/components/nodes/tools/CustomTool/core.ts +++ b/packages/components/nodes/tools/CustomTool/core.ts @@ -1,6 +1,6 @@ import { z } from 'zod' import { NodeVM } from 'vm2' -import { availableDependencies } from '../../../src/utils' +import { availableDependencies, defaultAllowBuiltInDep, prepareSandboxVars } from '../../../src/utils' import { RunnableConfig } from '@langchain/core/runnables' import { StructuredTool, ToolParams } from '@langchain/core/tools' import { CallbackManagerForToolRun, Callbacks, CallbackManager, parseCallbackConfigArg } from '@langchain/core/callbacks/manager' @@ -112,48 +112,13 @@ export class DynamicStructuredTool< } } - // inject variables - let vars = {} - if (this.variables) { - for (const item of this.variables) { - let value = item.value - - // read from .env file - if (item.type === 'runtime') { - value = process.env[item.name] - } - - Object.defineProperty(vars, item.name, { - enumerable: true, - configurable: true, - writable: true, - value: value - }) - } - } - sandbox['$vars'] = vars + sandbox['$vars'] = prepareSandboxVars(this.variables) // inject flow properties if (this.flowObj) { sandbox['$flow'] = { ...this.flowObj, ...flowConfig } } - const defaultAllowBuiltInDep = [ - 'assert', - 'buffer', - 'crypto', - 'events', - 'http', - 'https', - 'net', - 'path', - 'querystring', - 'timers', - 'tls', - 'url', - 'zlib' - ] - const builtinDeps = process.env.TOOL_FUNCTION_BUILTIN_DEP ? defaultAllowBuiltInDep.concat(process.env.TOOL_FUNCTION_BUILTIN_DEP.split(',')) : defaultAllowBuiltInDep diff --git a/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts b/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts index 749c3a86..ff29d589 100644 --- a/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts +++ b/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts @@ -1,6 +1,7 @@ -import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { NodeVM } from 'vm2' -import { availableDependencies, handleEscapeCharacters } from '../../../src/utils' +import { DataSource } from 'typeorm' +import { availableDependencies, defaultAllowBuiltInDep, getVars, handleEscapeCharacters, prepareSandboxVars } from '../../../src/utils' class CustomFunction_Utilities implements INode { label: string @@ -55,9 +56,19 @@ class CustomFunction_Utilities implements INode { ] } - async init(nodeData: INodeData, input: string): Promise { + async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { const javascriptFunction = nodeData.inputs?.javascriptFunction as string const functionInputVariablesRaw = nodeData.inputs?.functionInputVariables + const appDataSource = options.appDataSource as DataSource + const databaseEntities = options.databaseEntities as IDatabaseEntity + + const variables = await getVars(appDataSource, databaseEntities, nodeData) + const flow = { + chatflowId: options.chatflowid, + sessionId: options.sessionId, + chatId: options.chatId, + input + } let inputVars: ICommonObject = {} if (functionInputVariablesRaw) { @@ -70,6 +81,8 @@ class CustomFunction_Utilities implements INode { } let sandbox: any = { $input: input } + sandbox['$vars'] = prepareSandboxVars(variables) + sandbox['$flow'] = flow if (Object.keys(inputVars).length) { for (const item in inputVars) { @@ -81,22 +94,6 @@ class CustomFunction_Utilities implements INode { } } - const defaultAllowBuiltInDep = [ - 'assert', - 'buffer', - 'crypto', - 'events', - 'http', - 'https', - 'net', - 'path', - 'querystring', - 'timers', - 'tls', - 'url', - 'zlib' - ] - const builtinDeps = process.env.TOOL_FUNCTION_BUILTIN_DEP ? defaultAllowBuiltInDep.concat(process.env.TOOL_FUNCTION_BUILTIN_DEP.split(',')) : defaultAllowBuiltInDep diff --git a/packages/components/nodes/utilities/IfElseFunction/IfElseFunction.ts b/packages/components/nodes/utilities/IfElseFunction/IfElseFunction.ts index 862521eb..55339e1a 100644 --- a/packages/components/nodes/utilities/IfElseFunction/IfElseFunction.ts +++ b/packages/components/nodes/utilities/IfElseFunction/IfElseFunction.ts @@ -1,6 +1,7 @@ -import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { NodeVM } from 'vm2' -import { availableDependencies } from '../../../src/utils' +import { DataSource } from 'typeorm' +import { availableDependencies, defaultAllowBuiltInDep, getVars, prepareSandboxVars } from '../../../src/utils' class IfElseFunction_Utilities implements INode { label: string @@ -73,10 +74,20 @@ class IfElseFunction_Utilities implements INode { ] } - async init(nodeData: INodeData, input: string): Promise { + async init(nodeData: INodeData, input: string, options: ICommonObject): Promise { const ifFunction = nodeData.inputs?.ifFunction as string const elseFunction = nodeData.inputs?.elseFunction as string const functionInputVariablesRaw = nodeData.inputs?.functionInputVariables + const appDataSource = options.appDataSource as DataSource + const databaseEntities = options.databaseEntities as IDatabaseEntity + + const variables = await getVars(appDataSource, databaseEntities, nodeData) + const flow = { + chatflowId: options.chatflowid, + sessionId: options.sessionId, + chatId: options.chatId, + input + } let inputVars: ICommonObject = {} if (functionInputVariablesRaw) { @@ -89,6 +100,8 @@ class IfElseFunction_Utilities implements INode { } let sandbox: any = { $input: input } + sandbox['$vars'] = prepareSandboxVars(variables) + sandbox['$flow'] = flow if (Object.keys(inputVars).length) { for (const item in inputVars) { @@ -96,22 +109,6 @@ class IfElseFunction_Utilities implements INode { } } - const defaultAllowBuiltInDep = [ - 'assert', - 'buffer', - 'crypto', - 'events', - 'http', - 'https', - 'net', - 'path', - 'querystring', - 'timers', - 'tls', - 'url', - 'zlib' - ] - const builtinDeps = process.env.TOOL_FUNCTION_BUILTIN_DEP ? defaultAllowBuiltInDep.concat(process.env.TOOL_FUNCTION_BUILTIN_DEP.split(',')) : defaultAllowBuiltInDep diff --git a/packages/components/src/Interface.ts b/packages/components/src/Interface.ts index d74ba1b4..fe08f070 100644 --- a/packages/components/src/Interface.ts +++ b/packages/components/src/Interface.ts @@ -29,6 +29,12 @@ export interface ICommonObject { [key: string]: any | CommonType | ICommonObject | CommonType[] | ICommonObject[] } +export interface IVariable { + name: string + value: string + type: string +} + export type IDatabaseEntity = { [key: string]: any } diff --git a/packages/components/src/utils.ts b/packages/components/src/utils.ts index 2215eb41..7e9a68eb 100644 --- a/packages/components/src/utils.ts +++ b/packages/components/src/utils.ts @@ -5,7 +5,7 @@ import * as path from 'path' import { JSDOM } from 'jsdom' import { z } from 'zod' import { DataSource } from 'typeorm' -import { ICommonObject, IDatabaseEntity, IMessage, INodeData } from './Interface' +import { ICommonObject, IDatabaseEntity, IMessage, INodeData, IVariable } from './Interface' import { AES, enc } from 'crypto-js' import { ChatMessageHistory } from 'langchain/memory' import { AIMessage, HumanMessage, BaseMessage } from 'langchain/schema' @@ -70,6 +70,22 @@ export const availableDependencies = [ 'weaviate-ts-client' ] +export const defaultAllowBuiltInDep = [ + 'assert', + 'buffer', + 'crypto', + 'events', + 'http', + 'https', + 'net', + 'path', + 'querystring', + 'timers', + 'tls', + 'url', + 'zlib' +] + /** * Get base classes of components * @@ -688,3 +704,57 @@ export const convertMultiOptionsToStringArray = (inputString: string): string[] } return ArrayString } + +/** + * Get variables + * @param {DataSource} appDataSource + * @param {IDatabaseEntity} databaseEntities + * @param {INodeData} nodeData + */ +export const getVars = async (appDataSource: DataSource, databaseEntities: IDatabaseEntity, nodeData: INodeData) => { + const variables = ((await appDataSource.getRepository(databaseEntities['Variable']).find()) as IVariable[]) ?? [] + + // override variables defined in overrideConfig + // nodeData.inputs.variables is an Object, check each property and override the variable + if (nodeData?.inputs?.vars) { + for (const propertyName of Object.getOwnPropertyNames(nodeData.inputs.vars)) { + const foundVar = variables.find((v) => v.name === propertyName) + if (foundVar) { + // even if the variable was defined as runtime, we override it with static value + foundVar.type = 'static' + foundVar.value = nodeData.inputs.vars[propertyName] + } else { + // add it the variables, if not found locally in the db + variables.push({ name: propertyName, type: 'static', value: nodeData.inputs.vars[propertyName] }) + } + } + } + + return variables +} + +/** + * Prepare sandbox variables + * @param {IVariable[]} variables + */ +export const prepareSandboxVars = (variables: IVariable[]) => { + let vars = {} + if (variables) { + for (const item of variables) { + let value = item.value + + // read from .env file + if (item.type === 'runtime') { + value = process.env[item.name] ?? '' + } + + Object.defineProperty(vars, item.name, { + enumerable: true, + configurable: true, + writable: true, + value: value + }) + } + } + return vars +} diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 94a3b538..1986d207 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -294,7 +294,13 @@ export class App { const nodeModule = await import(nodeInstanceFilePath) const newNodeInstance = new nodeModule.nodeClass() - const returnData = await newNodeInstance.init(nodeData) + const options: ICommonObject = { + appDataSource: this.AppDataSource, + databaseEntities, + logger + } + + const returnData = await newNodeInstance.init(nodeData, '', options) const result = typeof returnData === 'string' ? handleEscapeCharacters(returnData, true) : returnData return res.json(result) @@ -1448,6 +1454,11 @@ export class App { let chatId = incomingInput.chatId ?? '' let isUpsert = true + // Get session ID + const memoryNode = findMemoryNode(nodes, edges) + let sessionId = undefined + if (memoryNode) sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal) + const vsNodes = nodes.filter( (node) => node.data.category === 'Vector Stores' && @@ -1485,6 +1496,7 @@ export class App { incomingInput.question, chatHistory, chatId, + sessionId ?? '', chatflowid, this.AppDataSource, incomingInput?.overrideConfig, @@ -1562,6 +1574,12 @@ export class App { const nodes = parsedFlowData.nodes const edges = parsedFlowData.edges + // Get session ID + const memoryNode = findMemoryNode(nodes, edges) + const memoryType = memoryNode?.data.label + let sessionId = undefined + if (memoryNode) sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal) + /* Reuse the flow without having to rebuild (to avoid duplicated upsert, recomputation, reinitialization of memory) when all these conditions met: * - Node Data already exists in pool * - Still in sync (i.e the flow has not been modified since) @@ -1671,6 +1689,7 @@ export class App { incomingInput.question, chatHistory, chatId, + sessionId ?? '', chatflowid, this.AppDataSource, incomingInput?.overrideConfig, @@ -1700,12 +1719,6 @@ export class App { logger.debug(`[server]: Running ${nodeToExecuteData.label} (${nodeToExecuteData.id})`) - const memoryNode = findMemoryNode(nodes, edges) - const memoryType = memoryNode?.data.label - - let sessionId = undefined - if (memoryNode) sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal) - const nodeInstanceFilePath = this.nodesPool.componentNodes[nodeToExecuteData.name].filePath as string const nodeModule = await import(nodeInstanceFilePath) const nodeInstance = new nodeModule.nodeClass({ sessionId }) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index dafe612c..2d6acf58 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -273,6 +273,7 @@ export const buildLangchain = async ( question: string, chatHistory: IMessage[], chatId: string, + sessionId: string, chatflowid: string, appDataSource: DataSource, overrideConfig?: ICommonObject, @@ -317,6 +318,7 @@ export const buildLangchain = async ( logger.debug(`[server]: Upserting ${reactFlowNode.data.label} (${reactFlowNode.data.id})`) await newNodeInstance.vectorStoreMethods!['upsert']!.call(newNodeInstance, reactFlowNodeData, { chatId, + sessionId, chatflowid, chatHistory, logger, @@ -331,6 +333,7 @@ export const buildLangchain = async ( logger.debug(`[server]: Initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`) let outputResult = await newNodeInstance.init(reactFlowNodeData, question, { chatId, + sessionId, chatflowid, chatHistory, logger, From d02b5a89885495cbf28997da3e0f4ed3335e7372 Mon Sep 17 00:00:00 2001 From: Octavian Cioaca <132788754+domselardi@users.noreply.github.com> Date: Thu, 18 Jan 2024 01:47:33 +0100 Subject: [PATCH 17/41] Add autoSync github workflows --- .../workflows/autoSyncMergedPullRequest.yml | 24 ++++++++++++++ .github/workflows/autoSyncSingleCommit.yml | 31 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 .github/workflows/autoSyncMergedPullRequest.yml create mode 100644 .github/workflows/autoSyncSingleCommit.yml diff --git a/.github/workflows/autoSyncMergedPullRequest.yml b/.github/workflows/autoSyncMergedPullRequest.yml new file mode 100644 index 00000000..5b1991d7 --- /dev/null +++ b/.github/workflows/autoSyncMergedPullRequest.yml @@ -0,0 +1,24 @@ +name: autoSyncMergedPullRequest +on: + pull_request: + types: + - closed + branches: [ "main" ] +jobs: + build: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Show PR info + env: + GITHUB_CONTEXT: ${{ toJSON(github) }} + run: | + echo The PR #${{ github.event.pull_request.number }} was merged on main branch! + - name: Repository Dispatch + uses: peter-evans/repository-dispatch@v2 + with: + token: ${{ secrets.AUTOSYNC_TOKEN }} + repository: ${{ secrets.AUTOSYNC_CH_URL }} + event-type: ${{ secrets.AUTOSYNC_PR_EVENT_TYPE }} + client-payload: '{"ref": "${{ github.ref }}", "prNumber": "${{ github.event.pull_request.number }}", "sha": "${{ github.sha }}"}' diff --git a/.github/workflows/autoSyncSingleCommit.yml b/.github/workflows/autoSyncSingleCommit.yml new file mode 100644 index 00000000..ce429a60 --- /dev/null +++ b/.github/workflows/autoSyncSingleCommit.yml @@ -0,0 +1,31 @@ +name: autoSyncSingleCommit +on: + push: + branches: + - main +jobs: + doNotAutoSyncSingleCommit: + if: github.event.commits[1] != null + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: IGNORE autoSyncSingleCommit + run: | + echo This single commit has came from a merged commit. We will ignore it. This case is handled in autoSyncMergedPullRequest workflow for merge commits comming from merged pull requests only! Beware, the regular merge commits are not handled by any workflow for the moment. + autoSyncSingleCommit: + if: github.event.commits[1] == null + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: autoSyncSingleCommit + env: + GITHUB_CONTEXT: ${{ toJSON(github) }} + run: | + echo Autosync a single commit with id: ${{ github.sha }} from openSource main branch towards cloud hosted version. + - name: Repository Dispatch + uses: peter-evans/repository-dispatch@v2 + with: + token: ${{ secrets.AUTOSYNC_TOKEN }} + repository: ${{ secrets.AUTOSYNC_CH_URL }} + event-type: ${{ secrets.AUTOSYNC_SC_EVENT_TYPE }} + client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}' From db7915f426c1016f352de11d00bfdfe1ec14a31d Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 18 Jan 2024 15:21:01 +0000 Subject: [PATCH 18/41] Update artillery-load-test.yml --- artillery-load-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artillery-load-test.yml b/artillery-load-test.yml index 6b1c8140..809a2a8e 100644 --- a/artillery-load-test.yml +++ b/artillery-load-test.yml @@ -33,4 +33,4 @@ scenarios: # Seconds # Total Users = 2 + 3 + 3 = 8 # Each making 1 HTTP call -# Over a duration of 3 seconds +# Over a durations of 3 seconds From 0214ed1a7333d5ecc108a442393bf41f70026377 Mon Sep 17 00:00:00 2001 From: niztal Date: Thu, 18 Jan 2024 19:28:38 +0200 Subject: [PATCH 19/41] support pinecone serverless indexes --- packages/components/credentials/PineconeApi.credential.ts | 5 ----- packages/components/nodes/vectorstores/Pinecone/Pinecone.ts | 6 ++---- .../nodes/vectorstores/Pinecone/Pinecone_Existing.ts | 4 +--- .../nodes/vectorstores/Pinecone/Pinecone_Upsert.ts | 4 +--- packages/components/package.json | 2 +- 5 files changed, 5 insertions(+), 16 deletions(-) diff --git a/packages/components/credentials/PineconeApi.credential.ts b/packages/components/credentials/PineconeApi.credential.ts index 4c5f62fe..486c9834 100644 --- a/packages/components/credentials/PineconeApi.credential.ts +++ b/packages/components/credentials/PineconeApi.credential.ts @@ -16,11 +16,6 @@ class PineconeApi implements INodeCredential { label: 'Pinecone Api Key', name: 'pineconeApiKey', type: 'password' - }, - { - label: 'Pinecone Environment', - name: 'pineconeEnv', - type: 'string' } ] } diff --git a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts index 6623b1a2..dd0c76f7 100644 --- a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts +++ b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts @@ -108,8 +108,7 @@ class Pinecone_VectorStores implements INode { const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData) const client = new Pinecone({ - apiKey: pineconeApiKey, - environment: pineconeEnv + apiKey: pineconeApiKey }) const pineconeIndex = client.Index(index) @@ -148,8 +147,7 @@ class Pinecone_VectorStores implements INode { const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData) const client = new Pinecone({ - apiKey: pineconeApiKey, - environment: pineconeEnv + apiKey: pineconeApiKey }) const pineconeIndex = client.Index(index) diff --git a/packages/components/nodes/vectorstores/Pinecone/Pinecone_Existing.ts b/packages/components/nodes/vectorstores/Pinecone/Pinecone_Existing.ts index 9eea70de..f805fc33 100644 --- a/packages/components/nodes/vectorstores/Pinecone/Pinecone_Existing.ts +++ b/packages/components/nodes/vectorstores/Pinecone/Pinecone_Existing.ts @@ -95,11 +95,9 @@ class Pinecone_Existing_VectorStores implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData) - const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData) const client = new Pinecone({ - apiKey: pineconeApiKey, - environment: pineconeEnv + apiKey: pineconeApiKey }) const pineconeIndex = client.Index(index) diff --git a/packages/components/nodes/vectorstores/Pinecone/Pinecone_Upsert.ts b/packages/components/nodes/vectorstores/Pinecone/Pinecone_Upsert.ts index cb54e6e9..14dbf663 100644 --- a/packages/components/nodes/vectorstores/Pinecone/Pinecone_Upsert.ts +++ b/packages/components/nodes/vectorstores/Pinecone/Pinecone_Upsert.ts @@ -96,11 +96,9 @@ class PineconeUpsert_VectorStores implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData) - const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData) const client = new Pinecone({ - apiKey: pineconeApiKey, - environment: pineconeEnv + apiKey: pineconeApiKey }) const pineconeIndex = client.Index(index) diff --git a/packages/components/package.json b/packages/components/package.json index 894014d4..0d4cd274 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -33,7 +33,7 @@ "@langchain/mistralai": "^0.0.6", "@notionhq/client": "^2.2.8", "@opensearch-project/opensearch": "^1.2.0", - "@pinecone-database/pinecone": "^1.1.1", + "@pinecone-database/pinecone": "^2.0.1", "@qdrant/js-client-rest": "^1.2.2", "@supabase/supabase-js": "^2.29.0", "@types/js-yaml": "^4.0.5", From 953e1468bbfb2e51d4e958c4a4e8389fc6174a09 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 19 Jan 2024 00:02:31 +0000 Subject: [PATCH 20/41] add telemetry --- packages/server/package.json | 1 + packages/server/src/index.ts | 44 +++++++++++++++++++- packages/server/src/utils/index.ts | 56 ++++++++++++++++++++++++++ packages/server/src/utils/telemetry.ts | 50 +++++++++++++++++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 packages/server/src/utils/telemetry.ts diff --git a/packages/server/package.json b/packages/server/package.json index 79ff4961..fe27f8d6 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -60,6 +60,7 @@ "multer": "^1.4.5-lts.1", "mysql": "^2.18.1", "pg": "^8.11.1", + "posthog-node": "^3.5.0", "reflect-metadata": "^0.1.13", "sanitize-html": "^2.11.0", "socket.io": "^4.6.1", diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 1986d207..c64333dd 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -45,7 +45,9 @@ import { getSessionChatHistory, getAllConnectedNodes, clearSessionMemory, - findMemoryNode + findMemoryNode, + getTelemetryFlowObj, + getAppVersion } from './utils' import { cloneDeep, omit, uniqWith, isEqual } from 'lodash' import { getDataSource } from './DataSource' @@ -64,6 +66,7 @@ import { sanitizeMiddleware } from './utils/XSS' import axios from 'axios' import { Client } from 'langchainhub' import { parsePrompt } from './utils/hub' +import { Telemetry } from './utils/telemetry' import { Variable } from './database/entities/Variable' export class App { @@ -71,6 +74,7 @@ export class App { nodesPool: NodesPool chatflowPool: ChatflowPool cachePool: CachePool + telemetry: Telemetry AppDataSource = getDataSource() constructor() { @@ -105,6 +109,9 @@ export class App { // Initialize cache pool this.cachePool = new CachePool() + + // Initialize telemetry + this.telemetry = new Telemetry() }) .catch((err) => { logger.error('❌ [server]: Error during Data Source initialization:', err) @@ -388,6 +395,12 @@ export class App { const chatflow = this.AppDataSource.getRepository(ChatFlow).create(newChatFlow) const results = await this.AppDataSource.getRepository(ChatFlow).save(chatflow) + await this.telemetry.sendTelemetry('chatflow_created', { + version: await getAppVersion(), + chatlowId: results.id, + flowGraph: getTelemetryFlowObj(JSON.parse(results.flowData)?.nodes, JSON.parse(results.flowData)?.edges) + }) + return res.json(results) }) @@ -674,6 +687,12 @@ export class App { const tool = this.AppDataSource.getRepository(Tool).create(newTool) const results = await this.AppDataSource.getRepository(Tool).save(tool) + await this.telemetry.sendTelemetry('tool_created', { + version: await getAppVersion(), + toolId: results.id, + toolName: results.name + }) + return res.json(results) }) @@ -880,6 +899,11 @@ export class App { const assistant = this.AppDataSource.getRepository(Assistant).create(newAssistant) const results = await this.AppDataSource.getRepository(Assistant).save(assistant) + await this.telemetry.sendTelemetry('assistant_created', { + version: await getAppVersion(), + assistantId: results.id + }) + return res.json(results) }) @@ -1508,6 +1532,15 @@ export class App { const startingNodes = nodes.filter((nd) => startingNodeIds.includes(nd.data.id)) this.chatflowPool.add(chatflowid, undefined, startingNodes, incomingInput?.overrideConfig) + + await this.telemetry.sendTelemetry('vector_upserted', { + version: await getAppVersion(), + chatlowId: chatflowid, + type: isInternal ? chatType.INTERNAL : chatType.EXTERNAL, + flowGraph: getTelemetryFlowObj(nodes, edges), + stopNodeId + }) + return res.status(201).send('Successfully Upserted') } catch (e: any) { logger.error('[server]: Error:', e) @@ -1784,6 +1817,14 @@ export class App { await this.addChatMessage(apiMessage) logger.debug(`[server]: Finished running ${nodeToExecuteData.label} (${nodeToExecuteData.id})`) + await this.telemetry.sendTelemetry('prediction_sent', { + version: await getAppVersion(), + chatlowId: chatflowid, + chatId, + sessionId, + type: isInternal ? chatType.INTERNAL : chatType.EXTERNAL, + flowGraph: getTelemetryFlowObj(nodes, edges) + }) // Only return ChatId when its Internal OR incoming input has ChatId, to avoid confusion when calling API if (incomingInput.chatId || isInternal) result.chatId = chatId @@ -1798,6 +1839,7 @@ export class App { async stopApp() { try { const removePromises: any[] = [] + removePromises.push(this.telemetry.flush()) await Promise.all(removePromises) } catch (e) { logger.error(`❌[server]: Flowise Server shut down error: ${e}`) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 2d6acf58..a232094e 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -1082,3 +1082,59 @@ export const getAllValuesFromJson = (obj: any): any[] => { extractValues(obj) return values } + +/** + * Get only essential flow data items for telemetry + * @param {IReactFlowNode[]} nodes + * @param {IReactFlowEdge[]} edges + */ +export const getTelemetryFlowObj = (nodes: IReactFlowNode[], edges: IReactFlowEdge[]) => { + const nodeData = nodes.map((node) => node.id) + const edgeData = edges.map((edge) => ({ source: edge.source, target: edge.target })) + return { nodes: nodeData, edges: edgeData } +} + +/** + * Get user settings file + * TODO: move env variables to settings json file, easier configuration + */ +export const getUserSettingsFilePath = () => { + const checkPaths = [path.join(getUserHome(), '.flowise', 'settings.json')] + for (const checkPath of checkPaths) { + if (fs.existsSync(checkPath)) { + return checkPath + } + } + return '' +} + +/** + * Get app current version + */ +export const getAppVersion = async () => { + const getPackageJsonPath = (): string => { + const checkPaths = [ + path.join(__dirname, '..', 'package.json'), + path.join(__dirname, '..', '..', 'package.json'), + path.join(__dirname, '..', '..', '..', 'package.json'), + path.join(__dirname, '..', '..', '..', '..', 'package.json'), + path.join(__dirname, '..', '..', '..', '..', '..', 'package.json') + ] + for (const checkPath of checkPaths) { + if (fs.existsSync(checkPath)) { + return checkPath + } + } + return '' + } + + const packagejsonPath = getPackageJsonPath() + if (!packagejsonPath) return '' + try { + const content = await fs.promises.readFile(packagejsonPath, 'utf8') + const parsedContent = JSON.parse(content) + return parsedContent.version + } catch (error) { + return '' + } +} diff --git a/packages/server/src/utils/telemetry.ts b/packages/server/src/utils/telemetry.ts new file mode 100644 index 00000000..4254ea76 --- /dev/null +++ b/packages/server/src/utils/telemetry.ts @@ -0,0 +1,50 @@ +import { v4 as uuidv4 } from 'uuid' +import { PostHog } from 'posthog-node' +import path from 'path' +import fs from 'fs' +import { getUserHome, getUserSettingsFilePath } from '.' + +export class Telemetry { + postHog?: PostHog + + constructor() { + if (process.env.DISABLE_FLOWISE_TELEMETRY !== 'true') { + this.postHog = new PostHog('phc_jEDuFYnOnuXsws986TLWzuisbRjwFqTl9JL8tDMgqme') + } else { + this.postHog = undefined + } + } + + async id(): Promise { + try { + const settingsContent = await fs.promises.readFile(getUserSettingsFilePath(), 'utf8') + const settings = JSON.parse(settingsContent) + return settings.instanceId + } catch (error) { + const instanceId = uuidv4() + const settings = { + instanceId + } + const defaultLocation = path.join(getUserHome(), '.flowise', 'settings.json') + await fs.promises.writeFile(defaultLocation, JSON.stringify(settings, null, 2)) + return instanceId + } + } + + async sendTelemetry(event: string, properties = {}): Promise { + if (this.postHog) { + const distinctId = await this.id() + this.postHog.capture({ + event, + distinctId, + properties + }) + } + } + + async flush(): Promise { + if (this.postHog) { + await this.postHog.shutdownAsync() + } + } +} From b5de88784bd718989b0a8102ef59c36a020b4c5b Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 19 Jan 2024 00:38:08 +0000 Subject: [PATCH 21/41] add flag --- CONTRIBUTING-ZH.md | 1 + CONTRIBUTING.md | 1 + docker/.env.example | 4 +++- docker/docker-compose.yml | 1 + packages/server/.env.example | 2 ++ packages/server/src/commands/start.ts | 6 +++++- 6 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING-ZH.md b/CONTRIBUTING-ZH.md index 5a752280..7e35d194 100644 --- a/CONTRIBUTING-ZH.md +++ b/CONTRIBUTING-ZH.md @@ -138,6 +138,7 @@ Flowise 支持不同的环境变量来配置您的实例。您可以在 `package | DATABASE_NAME | 数据库名称(当 DATABASE_TYPE 不是 sqlite 时) | 字符串 | | | SECRETKEY_PATH | 保存加密密钥(用于加密/解密凭据)的位置 | 字符串 | `your-path/Flowise/packages/server` | | FLOWISE_SECRETKEY_OVERWRITE | 加密密钥用于替代存储在 SECRETKEY_PATH 中的密钥 | 字符串 | +| DISABLE_FLOWISE_TELEMETRY | 关闭遥测 | 字符串 | 您也可以在使用 `npx` 时指定环境变量。例如: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04cb80b4..88d1aaac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -141,6 +141,7 @@ Flowise support different environment variables to configure your instance. You | DATABASE_SSL | Database connection overssl (When DATABASE_TYPE is postgre) | Boolean | false | | SECRETKEY_PATH | Location where encryption key (used to encrypt/decrypt credentials) is saved | String | `your-path/Flowise/packages/server` | | FLOWISE_SECRETKEY_OVERWRITE | Encryption key to be used instead of the key stored in SECRETKEY_PATH | String | +| DISABLE_FLOWISE_TELEMETRY | Turn off telemetry | Boolean | You can also specify the env variables when using `npx`. For example: diff --git a/docker/.env.example b/docker/.env.example index 7d4f1699..0fe69dd1 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -25,4 +25,6 @@ LOG_PATH=/root/.flowise/logs # LANGCHAIN_TRACING_V2=true # LANGCHAIN_ENDPOINT=https://api.smith.langchain.com # LANGCHAIN_API_KEY=your_api_key -# LANGCHAIN_PROJECT=your_project \ No newline at end of file +# LANGCHAIN_PROJECT=your_project + +# DISABLE_FLOWISE_TELEMETRY=true \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 92688469..c8c88bf3 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -22,6 +22,7 @@ services: - FLOWISE_SECRETKEY_OVERWRITE=${FLOWISE_SECRETKEY_OVERWRITE} - LOG_LEVEL=${LOG_LEVEL} - LOG_PATH=${LOG_PATH} + - DISABLE_FLOWISE_TELEMETRY=${DISABLE_FLOWISE_TELEMETRY} ports: - '${PORT}:${PORT}' volumes: diff --git a/packages/server/.env.example b/packages/server/.env.example index 6e746a4d..ed54ac66 100644 --- a/packages/server/.env.example +++ b/packages/server/.env.example @@ -26,3 +26,5 @@ PORT=3000 # LANGCHAIN_ENDPOINT=https://api.smith.langchain.com # LANGCHAIN_API_KEY=your_api_key # LANGCHAIN_PROJECT=your_project + +# DISABLE_FLOWISE_TELEMETRY=true \ No newline at end of file diff --git a/packages/server/src/commands/start.ts b/packages/server/src/commands/start.ts index d4e8cfdb..08cd8298 100644 --- a/packages/server/src/commands/start.ts +++ b/packages/server/src/commands/start.ts @@ -39,7 +39,8 @@ export default class Start extends Command { LANGCHAIN_TRACING_V2: Flags.string(), LANGCHAIN_ENDPOINT: Flags.string(), LANGCHAIN_API_KEY: Flags.string(), - LANGCHAIN_PROJECT: Flags.string() + LANGCHAIN_PROJECT: Flags.string(), + DISABLE_FLOWISE_TELEMETRY: Flags.string() } async stopProcess() { @@ -113,6 +114,9 @@ export default class Start extends Command { if (flags.LANGCHAIN_API_KEY) process.env.LANGCHAIN_API_KEY = flags.LANGCHAIN_API_KEY if (flags.LANGCHAIN_PROJECT) process.env.LANGCHAIN_PROJECT = flags.LANGCHAIN_PROJECT + // Telemetry + if (flags.DISABLE_FLOWISE_TELEMETRY) process.env.DISABLE_FLOWISE_TELEMETRY = flags.DISABLE_FLOWISE_TELEMETRY + await (async () => { try { logger.info('Starting Flowise...') From 2640f6b1dc1d86a29f7d70a436a87f26ae55b239 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 19 Jan 2024 00:49:52 +0000 Subject: [PATCH 22/41] update prediction_sent metadata --- packages/server/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index c64333dd..3c5766fd 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1821,7 +1821,6 @@ export class App { version: await getAppVersion(), chatlowId: chatflowid, chatId, - sessionId, type: isInternal ? chatType.INTERNAL : chatType.EXTERNAL, flowGraph: getTelemetryFlowObj(nodes, edges) }) From 31a4769079c73601596130cf2244899da79c7eee Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 19 Jan 2024 14:27:40 +0000 Subject: [PATCH 23/41] fix output prediction output parser --- .../nodes/chains/LLMChain/LLMChain.ts | 11 ++++++++-- .../CustomFunction/CustomFunction.ts | 11 ++++++++++ .../IfElseFunction/IfElseFunction.ts | 21 ++++++++++++++++--- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/packages/components/nodes/chains/LLMChain/LLMChain.ts b/packages/components/nodes/chains/LLMChain/LLMChain.ts index b7c055e4..f83fc36a 100644 --- a/packages/components/nodes/chains/LLMChain/LLMChain.ts +++ b/packages/components/nodes/chains/LLMChain/LLMChain.ts @@ -82,7 +82,7 @@ class LLMChain_Chains implements INode { const model = nodeData.inputs?.model as BaseLanguageModel const prompt = nodeData.inputs?.prompt const output = nodeData.outputs?.output as string - const promptValues = prompt.promptValues as ICommonObject + let promptValues: ICommonObject | undefined = nodeData.inputs?.prompt.promptValues as ICommonObject const llmOutputParser = nodeData.inputs?.outputParser as BaseOutputParser this.outputParser = llmOutputParser if (llmOutputParser) { @@ -107,17 +107,24 @@ class LLMChain_Chains implements INode { verbose: process.env.DEBUG === 'true' }) const inputVariables = chain.prompt.inputVariables as string[] // ["product"] + promptValues = injectOutputParser(this.outputParser, chain, promptValues) const res = await runPrediction(inputVariables, chain, input, promptValues, options, nodeData) // eslint-disable-next-line no-console console.log('\x1b[92m\x1b[1m\n*****OUTPUT PREDICTION*****\n\x1b[0m\x1b[0m') // eslint-disable-next-line no-console console.log(res) + + let finalRes = res + if (this.outputParser && typeof res === 'object' && Object.prototype.hasOwnProperty.call(res, 'json')) { + finalRes = (res as ICommonObject).json + } + /** * Apply string transformation to convert special chars: * FROM: hello i am ben\n\n\thow are you? * TO: hello i am benFLOWISE_NEWLINEFLOWISE_NEWLINEFLOWISE_TABhow are you? */ - return handleEscapeCharacters(res, false) + return handleEscapeCharacters(finalRes, false) } } diff --git a/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts b/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts index ff29d589..3dbb7c7d 100644 --- a/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts +++ b/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts @@ -80,6 +80,17 @@ class CustomFunction_Utilities implements INode { } } + // Some values might be a stringified JSON, parse it + for (const key in inputVars) { + if (typeof inputVars[key] === 'string' && inputVars[key].startsWith('{') && inputVars[key].endsWith('}')) { + try { + inputVars[key] = JSON.parse(inputVars[key]) + } catch (e) { + continue + } + } + } + let sandbox: any = { $input: input } sandbox['$vars'] = prepareSandboxVars(variables) sandbox['$flow'] = flow diff --git a/packages/components/nodes/utilities/IfElseFunction/IfElseFunction.ts b/packages/components/nodes/utilities/IfElseFunction/IfElseFunction.ts index 55339e1a..1c5c0b7d 100644 --- a/packages/components/nodes/utilities/IfElseFunction/IfElseFunction.ts +++ b/packages/components/nodes/utilities/IfElseFunction/IfElseFunction.ts @@ -1,7 +1,7 @@ import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { NodeVM } from 'vm2' import { DataSource } from 'typeorm' -import { availableDependencies, defaultAllowBuiltInDep, getVars, prepareSandboxVars } from '../../../src/utils' +import { availableDependencies, defaultAllowBuiltInDep, getVars, handleEscapeCharacters, prepareSandboxVars } from '../../../src/utils' class IfElseFunction_Utilities implements INode { label: string @@ -95,7 +95,18 @@ class IfElseFunction_Utilities implements INode { inputVars = typeof functionInputVariablesRaw === 'object' ? functionInputVariablesRaw : JSON.parse(functionInputVariablesRaw) } catch (exception) { - throw new Error("Invalid JSON in the PromptTemplate's promptValues: " + exception) + throw new Error("Invalid JSON in the IfElse's Input Variables: " + exception) + } + } + + // Some values might be a stringified JSON, parse it + for (const key in inputVars) { + if (typeof inputVars[key] === 'string' && inputVars[key].startsWith('{') && inputVars[key].endsWith('}')) { + try { + inputVars[key] = JSON.parse(inputVars[key]) + } catch (e) { + continue + } } } @@ -105,7 +116,11 @@ class IfElseFunction_Utilities implements INode { if (Object.keys(inputVars).length) { for (const item in inputVars) { - sandbox[`$${item}`] = inputVars[item] + let value = inputVars[item] + if (typeof value === 'string') { + value = handleEscapeCharacters(value, true) + } + sandbox[`$${item}`] = value } } From 2b2a5b90289286464207bf1eed8f14a549ad02a1 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 19 Jan 2024 18:36:49 +0000 Subject: [PATCH 24/41] add console call back to chains --- .../ConversationChain/ConversationChain.ts | 86 ++-- .../ConversationalRetrievalQAChain.ts | 11 +- .../marketplaces/chatflows/Claude LLM.json | 261 +++++++---- .../chatflows/Simple Conversation Chain.json | 418 +++++++++--------- 4 files changed, 446 insertions(+), 330 deletions(-) diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index fcd9921e..764f4f0e 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -1,13 +1,12 @@ import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams } from '../../../src/Interface' import { ConversationChain } from 'langchain/chains' -import { getBaseClasses } from '../../../src/utils' +import { getBaseClasses, handleEscapeCharacters } from '../../../src/utils' import { ChatPromptTemplate, HumanMessagePromptTemplate, MessagesPlaceholder, SystemMessagePromptTemplate } from 'langchain/prompts' import { BaseChatModel } from 'langchain/chat_models/base' import { ConsoleCallbackHandler, CustomChainHandler, additionalCallbacks } from '../../../src/handler' -import { flatten } from 'lodash' -import { Document } from 'langchain/document' import { RunnableSequence } from 'langchain/schema/runnable' import { StringOutputParser } from 'langchain/schema/output_parser' +import { ConsoleCallbackHandler as LCConsoleCallbackHandler } from '@langchain/core/tracers/console' let systemMessage = `The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.` const inputKey = 'input' @@ -27,7 +26,7 @@ class ConversationChain_Chains implements INode { constructor(fields?: { sessionId?: string }) { this.label = 'Conversation Chain' this.name = 'conversationChain' - this.version = 1.0 + this.version = 2.0 this.type = 'ConversationChain' this.icon = 'conv.svg' this.category = 'Chains' @@ -44,6 +43,14 @@ class ConversationChain_Chains implements INode { name: 'memory', type: 'BaseMemory' }, + { + label: 'Chat Prompt Template', + name: 'chatPromptTemplate', + type: 'ChatPromptTemplate', + description: 'Override existing prompt with Chat Prompt Template. Human Message must includes {input} variable', + optional: true + }, + /* Deprecated { label: 'Document', name: 'document', @@ -52,15 +59,17 @@ class ConversationChain_Chains implements INode { 'Include whole document into the context window, if you get maximum context length error, please use model with higher context window like Claude 100k, or gpt4 32k', optional: true, list: true - }, + },*/ { label: 'System Message', name: 'systemMessagePrompt', type: 'string', rows: 4, + description: 'If Chat Prompt Template is provided, this will be ignored', additionalParams: true, optional: true, - placeholder: 'You are a helpful assistant that write codes' + default: systemMessage, + placeholder: systemMessage } ] this.sessionId = fields?.sessionId @@ -76,15 +85,21 @@ class ConversationChain_Chains implements INode { const chain = prepareChain(nodeData, this.sessionId, options.chatHistory) const loggerHandler = new ConsoleCallbackHandler(options.logger) - const callbacks = await additionalCallbacks(nodeData, options) + const additionalCallback = await additionalCallbacks(nodeData, options) let res = '' + let callbacks = [loggerHandler, ...additionalCallback] + + if (process.env.DEBUG === 'true') { + callbacks.push(new LCConsoleCallbackHandler()) + } if (options.socketIO && options.socketIOClientId) { const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId) - res = await chain.invoke({ input }, { callbacks: [loggerHandler, handler, ...callbacks] }) + callbacks.push(handler) + res = await chain.invoke({ input }, { callbacks }) } else { - res = await chain.invoke({ input }, { callbacks: [loggerHandler, ...callbacks] }) + res = await chain.invoke({ input }, { callbacks }) } await memory.addChatMessages( @@ -108,28 +123,27 @@ class ConversationChain_Chains implements INode { const prepareChatPrompt = (nodeData: INodeData) => { const memory = nodeData.inputs?.memory as FlowiseMemory const prompt = nodeData.inputs?.systemMessagePrompt as string - const docs = nodeData.inputs?.document as Document[] + const chatPromptTemplate = nodeData.inputs?.chatPromptTemplate as ChatPromptTemplate - const flattenDocs = docs && docs.length ? flatten(docs) : [] - const finalDocs = [] - for (let i = 0; i < flattenDocs.length; i += 1) { - if (flattenDocs[i] && flattenDocs[i].pageContent) { - finalDocs.push(new Document(flattenDocs[i])) + if (chatPromptTemplate && chatPromptTemplate.promptMessages.length) { + const sysPrompt = chatPromptTemplate.promptMessages[0] + const humanPrompt = chatPromptTemplate.promptMessages[chatPromptTemplate.promptMessages.length - 1] + const chatPrompt = ChatPromptTemplate.fromMessages([ + sysPrompt, + new MessagesPlaceholder(memory.memoryKey ?? 'chat_history'), + humanPrompt + ]) + + if ((chatPromptTemplate as any).promptValues) { + // @ts-ignore + chatPrompt.promptValues = (chatPromptTemplate as any).promptValues } + + return chatPrompt } - let finalText = '' - for (let i = 0; i < finalDocs.length; i += 1) { - finalText += finalDocs[i].pageContent - } - - const replaceChar: string[] = ['{', '}'] - for (const char of replaceChar) finalText = finalText.replaceAll(char, '') - - if (finalText) systemMessage = `${systemMessage}\nThe AI has the following context:\n${finalText}` - const chatPrompt = ChatPromptTemplate.fromMessages([ - SystemMessagePromptTemplate.fromTemplate(prompt ? `${prompt}\n${systemMessage}` : systemMessage), + SystemMessagePromptTemplate.fromTemplate(prompt ? prompt : systemMessage), new MessagesPlaceholder(memory.memoryKey ?? 'chat_history'), HumanMessagePromptTemplate.fromTemplate(`{${inputKey}}`) ]) @@ -142,15 +156,31 @@ const prepareChain = (nodeData: INodeData, sessionId?: string, chatHistory: IMes const memory = nodeData.inputs?.memory as FlowiseMemory const memoryKey = memory.memoryKey ?? 'chat_history' + const chatPrompt = prepareChatPrompt(nodeData) + let promptVariables = {} + const promptValuesRaw = (chatPrompt as any).promptValues + if (promptValuesRaw) { + const promptValues = handleEscapeCharacters(promptValuesRaw, true) + for (const val in promptValues) { + promptVariables = { + ...promptVariables, + [val]: () => { + return promptValues[val] + } + } + } + } + const conversationChain = RunnableSequence.from([ { [inputKey]: (input: { input: string }) => input.input, [memoryKey]: async () => { const history = await memory.getChatMessages(sessionId, true, chatHistory) return history - } + }, + ...promptVariables }, - prepareChatPrompt(nodeData), + chatPrompt, model, new StringOutputParser() ]) diff --git a/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts index 5f98cba1..964543de 100644 --- a/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts +++ b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts @@ -13,6 +13,7 @@ import { applyPatch } from 'fast-json-patch' import { convertBaseMessagetoIMessage, getBaseClasses } from '../../../src/utils' import { ConsoleCallbackHandler, additionalCallbacks } from '../../../src/handler' import { FlowiseMemory, ICommonObject, IMessage, INode, INodeData, INodeParams, MemoryMethods } from '../../../src/Interface' +import { ConsoleCallbackHandler as LCConsoleCallbackHandler } from '@langchain/core/tracers/console' type RetrievalChainInput = { chat_history: string @@ -176,11 +177,17 @@ class ConversationalRetrievalQAChain_Chains implements INode { const history = ((await memory.getChatMessages(this.sessionId, false, options.chatHistory)) as IMessage[]) ?? [] const loggerHandler = new ConsoleCallbackHandler(options.logger) - const callbacks = await additionalCallbacks(nodeData, options) + const additionalCallback = await additionalCallbacks(nodeData, options) + + let callbacks = [loggerHandler, ...additionalCallback] + + if (process.env.DEBUG === 'true') { + callbacks.push(new LCConsoleCallbackHandler()) + } const stream = answerChain.streamLog( { question: input, chat_history: history }, - { callbacks: [loggerHandler, ...callbacks] }, + { callbacks }, { includeNames: [sourceRunnableName] } diff --git a/packages/server/marketplaces/chatflows/Claude LLM.json b/packages/server/marketplaces/chatflows/Claude LLM.json index 39d4d400..5d632ff1 100644 --- a/packages/server/marketplaces/chatflows/Claude LLM.json +++ b/packages/server/marketplaces/chatflows/Claude LLM.json @@ -6,15 +6,15 @@ "height": 376, "id": "bufferMemory_0", "position": { - "x": 451.4449437285705, - "y": 118.30026803362762 + "x": 240.5161028076149, + "y": 165.35849026339048 }, "type": "customNode", "data": { "id": "bufferMemory_0", "label": "Buffer Memory", - "name": "bufferMemory", "version": 1, + "name": "bufferMemory", "type": "BufferMemory", "baseClasses": ["BufferMemory", "BaseChatMemory", "BaseMemory"], "category": "Memory", @@ -53,8 +53,8 @@ }, "selected": false, "positionAbsolute": { - "x": 451.4449437285705, - "y": 118.30026803362762 + "x": 240.5161028076149, + "y": 165.35849026339048 }, "dragging": false }, @@ -63,17 +63,17 @@ "height": 383, "id": "conversationChain_0", "position": { - "x": 1176.1569322079652, - "y": 303.56879146735974 + "x": 958.9887390513221, + "y": 318.8734467468765 }, "type": "customNode", "data": { "id": "conversationChain_0", "label": "Conversation Chain", + "version": 2, "name": "conversationChain", - "version": 1, "type": "ConversationChain", - "baseClasses": ["ConversationChain", "LLMChain", "BaseChain"], + "baseClasses": ["ConversationChain", "LLMChain", "BaseChain", "Runnable"], "category": "Chains", "description": "Chat models specific conversational chain with memory", "inputParams": [ @@ -82,9 +82,11 @@ "name": "systemMessagePrompt", "type": "string", "rows": 4, + "description": "If Chat Prompt Template is provided, this will be ignored", "additionalParams": true, "optional": true, - "placeholder": "You are a helpful assistant that write codes", + "default": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.", + "placeholder": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.", "id": "conversationChain_0-input-systemMessagePrompt-string" } ], @@ -102,27 +104,26 @@ "id": "conversationChain_0-input-memory-BaseMemory" }, { - "label": "Document", - "name": "document", - "type": "Document", - "description": "Include whole document into the context window", + "label": "Chat Prompt Template", + "name": "chatPromptTemplate", + "type": "ChatPromptTemplate", + "description": "Override existing prompt with Chat Prompt Template. Human Message must includes {input} variable", "optional": true, - "list": true, - "id": "conversationChain_0-input-document-Document" + "id": "conversationChain_0-input-chatPromptTemplate-ChatPromptTemplate" } ], "inputs": { "model": "{{chatAnthropic_0.data.instance}}", "memory": "{{bufferMemory_0.data.instance}}", - "document": ["{{pdfFile_0.data.instance}}"], - "systemMessagePrompt": "" + "chatPromptTemplate": "{{chatPromptTemplate_0.data.instance}}", + "systemMessagePrompt": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know." }, "outputAnchors": [ { - "id": "conversationChain_0-output-conversationChain-ConversationChain|LLMChain|BaseChain", + "id": "conversationChain_0-output-conversationChain-ConversationChain|LLMChain|BaseChain|Runnable", "name": "conversationChain", "label": "ConversationChain", - "type": "ConversationChain | LLMChain | BaseChain" + "type": "ConversationChain | LLMChain | BaseChain | Runnable" } ], "outputs": {}, @@ -130,27 +131,27 @@ }, "selected": false, "positionAbsolute": { - "x": 1176.1569322079652, - "y": 303.56879146735974 + "x": 958.9887390513221, + "y": 318.8734467468765 }, "dragging": false }, { "width": 300, - "height": 523, + "height": 574, "id": "chatAnthropic_0", "position": { - "x": 800.5525382783799, - "y": -130.7988221837009 + "x": 585.3308245972187, + "y": -116.32789506560908 }, "type": "customNode", "data": { "id": "chatAnthropic_0", "label": "ChatAnthropic", - "name": "chatAnthropic", "version": 3, + "name": "chatAnthropic", "type": "ChatAnthropic", - "baseClasses": ["ChatAnthropic", "BaseChatModel", "BaseLanguageModel"], + "baseClasses": ["ChatAnthropic", "BaseChatModel", "BaseLanguageModel", "Runnable"], "category": "Chat Models", "description": "Wrapper around ChatAnthropic large language models that use the Chat endpoint", "inputParams": [ @@ -226,7 +227,7 @@ "name": "claude-instant-v1.1-100k" } ], - "default": "claude-v1", + "default": "claude-2", "optional": true, "id": "chatAnthropic_0-input-modelName-options" }, @@ -234,6 +235,7 @@ "label": "Temperature", "name": "temperature", "type": "number", + "step": 0.1, "default": 0.9, "optional": true, "id": "chatAnthropic_0-input-temperature-number" @@ -242,6 +244,7 @@ "label": "Max Tokens", "name": "maxTokensToSample", "type": "number", + "step": 1, "optional": true, "additionalParams": true, "id": "chatAnthropic_0-input-maxTokensToSample-number" @@ -250,6 +253,7 @@ "label": "Top P", "name": "topP", "type": "number", + "step": 0.1, "optional": true, "additionalParams": true, "id": "chatAnthropic_0-input-topP-number" @@ -258,6 +262,7 @@ "label": "Top K", "name": "topK", "type": "number", + "step": 0.1, "optional": true, "additionalParams": true, "id": "chatAnthropic_0-input-topK-number" @@ -273,6 +278,7 @@ } ], "inputs": { + "cache": "", "modelName": "claude-2.1", "temperature": 0.9, "maxTokensToSample": "", @@ -281,10 +287,10 @@ }, "outputAnchors": [ { - "id": "chatAnthropic_0-output-chatAnthropic-ChatAnthropic|BaseChatModel|BaseLanguageModel", + "id": "chatAnthropic_0-output-chatAnthropic-ChatAnthropic|BaseChatModel|BaseLanguageModel|Runnable", "name": "chatAnthropic", "label": "ChatAnthropic", - "type": "ChatAnthropic | BaseChatModel | BaseLanguageModel" + "type": "ChatAnthropic | BaseChatModel | BaseLanguageModel | Runnable" } ], "outputs": {}, @@ -292,61 +298,106 @@ }, "selected": false, "positionAbsolute": { - "x": 800.5525382783799, - "y": -130.7988221837009 + "x": 585.3308245972187, + "y": -116.32789506560908 }, "dragging": false }, { "width": 300, - "height": 507, - "id": "pdfFile_0", + "height": 688, + "id": "chatPromptTemplate_0", "position": { - "x": 94.16886576108482, - "y": 37.12056504707391 + "x": -106.44189698270114, + "y": 20.133956087516538 }, "type": "customNode", "data": { - "id": "pdfFile_0", - "label": "Pdf File", - "name": "pdfFile", + "id": "chatPromptTemplate_0", + "label": "Chat Prompt Template", "version": 1, + "name": "chatPromptTemplate", + "type": "ChatPromptTemplate", + "baseClasses": ["ChatPromptTemplate", "BaseChatPromptTemplate", "BasePromptTemplate", "Runnable"], + "category": "Prompts", + "description": "Schema to represent a chat prompt", + "inputParams": [ + { + "label": "System Message", + "name": "systemMessagePrompt", + "type": "string", + "rows": 4, + "placeholder": "You are a helpful assistant that translates {input_language} to {output_language}.", + "id": "chatPromptTemplate_0-input-systemMessagePrompt-string" + }, + { + "label": "Human Message", + "name": "humanMessagePrompt", + "type": "string", + "rows": 4, + "placeholder": "{text}", + "id": "chatPromptTemplate_0-input-humanMessagePrompt-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "chatPromptTemplate_0-input-promptValues-json" + } + ], + "inputAnchors": [], + "inputs": { + "systemMessagePrompt": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\nThe AI has the following context:\n{context}", + "humanMessagePrompt": "{input}", + "promptValues": "{\"context\":\"{{plainText_0.data.instance}}\",\"input\":\"{{question}}\"}" + }, + "outputAnchors": [ + { + "id": "chatPromptTemplate_0-output-chatPromptTemplate-ChatPromptTemplate|BaseChatPromptTemplate|BasePromptTemplate|Runnable", + "name": "chatPromptTemplate", + "label": "ChatPromptTemplate", + "type": "ChatPromptTemplate | BaseChatPromptTemplate | BasePromptTemplate | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": -106.44189698270114, + "y": 20.133956087516538 + }, + "dragging": false + }, + { + "width": 300, + "height": 485, + "id": "plainText_0", + "position": { + "x": -487.7511991135089, + "y": 77.83838996645807 + }, + "type": "customNode", + "data": { + "id": "plainText_0", + "label": "Plain Text", + "version": 2, + "name": "plainText", "type": "Document", "baseClasses": ["Document"], "category": "Document Loaders", - "description": "Load data from PDF files", + "description": "Load data from plain text", "inputParams": [ { - "label": "Pdf File", - "name": "pdfFile", - "type": "file", - "fileType": ".pdf", - "id": "pdfFile_0-input-pdfFile-file" - }, - { - "label": "Usage", - "name": "usage", - "type": "options", - "options": [ - { - "label": "One document per page", - "name": "perPage" - }, - { - "label": "One document per file", - "name": "perFile" - } - ], - "default": "perPage", - "id": "pdfFile_0-input-usage-options" - }, - { - "label": "Use Legacy Build", - "name": "legacyBuild", - "type": "boolean", - "optional": true, - "additionalParams": true, - "id": "pdfFile_0-input-legacyBuild-boolean" + "label": "Text", + "name": "text", + "type": "string", + "rows": 4, + "placeholder": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua...", + "id": "plainText_0-input-text-string" }, { "label": "Metadata", @@ -354,7 +405,7 @@ "type": "json", "optional": true, "additionalParams": true, - "id": "pdfFile_0-input-metadata-json" + "id": "plainText_0-input-metadata-json" } ], "inputAnchors": [ @@ -363,30 +414,45 @@ "name": "textSplitter", "type": "TextSplitter", "optional": true, - "id": "pdfFile_0-input-textSplitter-TextSplitter" + "id": "plainText_0-input-textSplitter-TextSplitter" } ], "inputs": { + "text": "Welcome to Skyworld Hotel, where your dreams take flight and your stay soars to new heights. Nestled amidst breathtaking cityscape views, our upscale establishment offers an unparalleled blend of luxury and comfort. Our rooms are elegantly appointed, featuring modern amenities and plush furnishings to ensure your relaxation.\n\nIndulge in culinary delights at our rooftop restaurant, offering a gastronomic journey with panoramic vistas. Skyworld Hotel boasts state-of-the-art conference facilities, perfect for business travelers, and an inviting spa for relaxation seekers. Our attentive staff is dedicated to ensuring your every need is met, making your stay memorable.\n\nCentrally located, we offer easy access to local attractions, making us an ideal choice for both leisure and business travelers. Experience the world of hospitality like never before at Skyworld Hotel.", "textSplitter": "", - "usage": "perPage", - "legacyBuild": "", "metadata": "" }, "outputAnchors": [ { - "id": "pdfFile_0-output-pdfFile-Document", - "name": "pdfFile", - "label": "Document", - "type": "Document" + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "plainText_0-output-document-Document", + "name": "document", + "label": "Document", + "type": "Document" + }, + { + "id": "plainText_0-output-text-string|json", + "name": "text", + "label": "Text", + "type": "string | json" + } + ], + "default": "document" } ], - "outputs": {}, + "outputs": { + "output": "text" + }, "selected": false }, "selected": false, "positionAbsolute": { - "x": 94.16886576108482, - "y": 37.12056504707391 + "x": -487.7511991135089, + "y": 77.83838996645807 }, "dragging": false } @@ -398,32 +464,31 @@ "target": "conversationChain_0", "targetHandle": "conversationChain_0-input-memory-BaseMemory", "type": "buttonedge", - "id": "bufferMemory_0-bufferMemory_0-output-bufferMemory-BufferMemory|BaseChatMemory|BaseMemory-conversationChain_0-conversationChain_0-input-memory-BaseMemory", - "data": { - "label": "" - } + "id": "bufferMemory_0-bufferMemory_0-output-bufferMemory-BufferMemory|BaseChatMemory|BaseMemory-conversationChain_0-conversationChain_0-input-memory-BaseMemory" }, { "source": "chatAnthropic_0", - "sourceHandle": "chatAnthropic_0-output-chatAnthropic-ChatAnthropic|BaseChatModel|BaseLanguageModel", + "sourceHandle": "chatAnthropic_0-output-chatAnthropic-ChatAnthropic|BaseChatModel|BaseLanguageModel|Runnable", "target": "conversationChain_0", "targetHandle": "conversationChain_0-input-model-BaseChatModel", "type": "buttonedge", - "id": "chatAnthropic_0-chatAnthropic_0-output-chatAnthropic-ChatAnthropic|BaseChatModel|BaseLanguageModel-conversationChain_0-conversationChain_0-input-model-BaseChatModel", - "data": { - "label": "" - } + "id": "chatAnthropic_0-chatAnthropic_0-output-chatAnthropic-ChatAnthropic|BaseChatModel|BaseLanguageModel|Runnable-conversationChain_0-conversationChain_0-input-model-BaseChatModel" }, { - "source": "pdfFile_0", - "sourceHandle": "pdfFile_0-output-pdfFile-Document", - "target": "conversationChain_0", - "targetHandle": "conversationChain_0-input-document-Document", + "source": "plainText_0", + "sourceHandle": "plainText_0-output-text-string|json", + "target": "chatPromptTemplate_0", + "targetHandle": "chatPromptTemplate_0-input-promptValues-json", "type": "buttonedge", - "id": "pdfFile_0-pdfFile_0-output-pdfFile-Document-conversationChain_0-conversationChain_0-input-document-Document", - "data": { - "label": "" - } + "id": "plainText_0-plainText_0-output-text-string|json-chatPromptTemplate_0-chatPromptTemplate_0-input-promptValues-json" + }, + { + "source": "chatPromptTemplate_0", + "sourceHandle": "chatPromptTemplate_0-output-chatPromptTemplate-ChatPromptTemplate|BaseChatPromptTemplate|BasePromptTemplate|Runnable", + "target": "conversationChain_0", + "targetHandle": "conversationChain_0-input-chatPromptTemplate-ChatPromptTemplate", + "type": "buttonedge", + "id": "chatPromptTemplate_0-chatPromptTemplate_0-output-chatPromptTemplate-ChatPromptTemplate|BaseChatPromptTemplate|BasePromptTemplate|Runnable-conversationChain_0-conversationChain_0-input-chatPromptTemplate-ChatPromptTemplate" } ] } diff --git a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json index 2322136c..9689bf8c 100644 --- a/packages/server/marketplaces/chatflows/Simple Conversation Chain.json +++ b/packages/server/marketplaces/chatflows/Simple Conversation Chain.json @@ -2,20 +2,210 @@ "description": "Basic example of Conversation Chain with built-in memory - works exactly like ChatGPT", "badge": "POPULAR", "nodes": [ + { + "width": 300, + "height": 574, + "id": "chatOpenAI_0", + "position": { + "x": 579.0877964395976, + "y": -138.68792413227874 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "version": 2, + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "chatOpenAI_0-input-credential-credential" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "gpt-4", + "name": "gpt-4" + }, + { + "label": "gpt-4-1106-preview", + "name": "gpt-4-1106-preview" + }, + { + "label": "gpt-4-vision-preview", + "name": "gpt-4-vision-preview" + }, + { + "label": "gpt-4-0613", + "name": "gpt-4-0613" + }, + { + "label": "gpt-4-32k", + "name": "gpt-4-32k" + }, + { + "label": "gpt-4-32k-0613", + "name": "gpt-4-32k-0613" + }, + { + "label": "gpt-3.5-turbo", + "name": "gpt-3.5-turbo" + }, + { + "label": "gpt-3.5-turbo-1106", + "name": "gpt-3.5-turbo-1106" + }, + { + "label": "gpt-3.5-turbo-0613", + "name": "gpt-3.5-turbo-0613" + }, + { + "label": "gpt-3.5-turbo-16k", + "name": "gpt-3.5-turbo-16k" + }, + { + "label": "gpt-3.5-turbo-16k-0613", + "name": "gpt-3.5-turbo-16k-0613" + } + ], + "default": "gpt-3.5-turbo", + "optional": true, + "id": "chatOpenAI_0-input-modelName-options" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_0-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-basepath-string" + }, + { + "label": "BaseOptions", + "name": "baseOptions", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-baseOptions-json" + } + ], + "inputAnchors": [ + { + "label": "Cache", + "name": "cache", + "type": "BaseCache", + "optional": true, + "id": "chatOpenAI_0-input-cache-BaseCache" + } + ], + "inputs": { + "cache": "", + "modelName": "gpt-3.5-turbo-16k", + "temperature": 0.9, + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "", + "baseOptions": "" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 579.0877964395976, + "y": -138.68792413227874 + }, + "dragging": false + }, { "width": 300, "height": 376, "id": "bufferMemory_0", "position": { - "x": 753.4300788823234, - "y": 479.5336426526603 + "x": 220.30240896145915, + "y": 351.61324070296877 }, "type": "customNode", "data": { "id": "bufferMemory_0", "label": "Buffer Memory", - "name": "bufferMemory", "version": 1, + "name": "bufferMemory", "type": "BufferMemory", "baseClasses": ["BufferMemory", "BaseChatMemory", "BaseMemory"], "category": "Memory", @@ -54,179 +244,8 @@ }, "selected": false, "positionAbsolute": { - "x": 753.4300788823234, - "y": 479.5336426526603 - }, - "dragging": false - }, - { - "width": 300, - "height": 523, - "id": "chatOpenAI_0", - "position": { - "x": 754.8942497823595, - "y": -140 - }, - "type": "customNode", - "data": { - "id": "chatOpenAI_0", - "label": "ChatOpenAI", - "name": "chatOpenAI", - "version": 2, - "type": "ChatOpenAI", - "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], - "category": "Chat Models", - "description": "Wrapper around OpenAI large language models that use the Chat endpoint", - "inputParams": [ - { - "label": "Connect Credential", - "name": "credential", - "type": "credential", - "credentialNames": ["openAIApi"], - "id": "chatOpenAI_0-input-credential-credential" - }, - { - "label": "Model Name", - "name": "modelName", - "type": "options", - "options": [ - { - "label": "gpt-4", - "name": "gpt-4" - }, - { - "label": "gpt-4-0613", - "name": "gpt-4-0613" - }, - { - "label": "gpt-4-32k", - "name": "gpt-4-32k" - }, - { - "label": "gpt-4-32k-0613", - "name": "gpt-4-32k-0613" - }, - { - "label": "gpt-3.5-turbo", - "name": "gpt-3.5-turbo" - }, - { - "label": "gpt-3.5-turbo-0613", - "name": "gpt-3.5-turbo-0613" - }, - { - "label": "gpt-3.5-turbo-16k", - "name": "gpt-3.5-turbo-16k" - }, - { - "label": "gpt-3.5-turbo-16k-0613", - "name": "gpt-3.5-turbo-16k-0613" - } - ], - "default": "gpt-3.5-turbo", - "optional": true, - "id": "chatOpenAI_0-input-modelName-options" - }, - { - "label": "Temperature", - "name": "temperature", - "type": "number", - "default": 0.9, - "optional": true, - "id": "chatOpenAI_0-input-temperature-number" - }, - { - "label": "Max Tokens", - "name": "maxTokens", - "type": "number", - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-maxTokens-number" - }, - { - "label": "Top Probability", - "name": "topP", - "type": "number", - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-topP-number" - }, - { - "label": "Frequency Penalty", - "name": "frequencyPenalty", - "type": "number", - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-frequencyPenalty-number" - }, - { - "label": "Presence Penalty", - "name": "presencePenalty", - "type": "number", - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-presencePenalty-number" - }, - { - "label": "Timeout", - "name": "timeout", - "type": "number", - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-timeout-number" - }, - { - "label": "BasePath", - "name": "basepath", - "type": "string", - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-basepath-string" - }, - { - "label": "BaseOptions", - "name": "baseOptions", - "type": "json", - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-baseOptions-json" - } - ], - "inputAnchors": [ - { - "label": "Cache", - "name": "cache", - "type": "BaseCache", - "optional": true, - "id": "chatOpenAI_0-input-cache-BaseCache" - } - ], - "inputs": { - "modelName": "gpt-3.5-turbo", - "temperature": 0.9, - "maxTokens": "", - "topP": "", - "frequencyPenalty": "", - "presencePenalty": "", - "timeout": "", - "basepath": "", - "baseOptions": "" - }, - "outputAnchors": [ - { - "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", - "name": "chatOpenAI", - "label": "ChatOpenAI", - "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel" - } - ], - "outputs": {}, - "selected": false - }, - "selected": false, - "positionAbsolute": { - "x": 754.8942497823595, - "y": -140 + "x": 220.30240896145915, + "y": 351.61324070296877 }, "dragging": false }, @@ -235,17 +254,17 @@ "height": 383, "id": "conversationChain_0", "position": { - "x": 1174.6496397666272, - "y": 311.1052536740497 + "x": 958.9887390513221, + "y": 318.8734467468765 }, "type": "customNode", "data": { "id": "conversationChain_0", "label": "Conversation Chain", + "version": 2, "name": "conversationChain", - "version": 1, "type": "ConversationChain", - "baseClasses": ["ConversationChain", "LLMChain", "BaseChain"], + "baseClasses": ["ConversationChain", "LLMChain", "BaseChain", "Runnable"], "category": "Chains", "description": "Chat models specific conversational chain with memory", "inputParams": [ @@ -254,9 +273,11 @@ "name": "systemMessagePrompt", "type": "string", "rows": 4, + "description": "If Chat Prompt Template is provided, this will be ignored", "additionalParams": true, "optional": true, - "placeholder": "You are a helpful assistant that write codes", + "default": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.", + "placeholder": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.", "id": "conversationChain_0-input-systemMessagePrompt-string" } ], @@ -274,27 +295,26 @@ "id": "conversationChain_0-input-memory-BaseMemory" }, { - "label": "Document", - "name": "document", - "type": "Document", - "description": "Include whole document into the context window", + "label": "Chat Prompt Template", + "name": "chatPromptTemplate", + "type": "ChatPromptTemplate", + "description": "Override existing prompt with Chat Prompt Template. Human Message must includes {input} variable", "optional": true, - "list": true, - "id": "conversationChain_0-input-document-Document" + "id": "conversationChain_0-input-chatPromptTemplate-ChatPromptTemplate" } ], "inputs": { "model": "{{chatOpenAI_0.data.instance}}", "memory": "{{bufferMemory_0.data.instance}}", - "document": "", - "systemMessagePrompt": "" + "chatPromptTemplate": "", + "systemMessagePrompt": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know." }, "outputAnchors": [ { - "id": "conversationChain_0-output-conversationChain-ConversationChain|LLMChain|BaseChain", + "id": "conversationChain_0-output-conversationChain-ConversationChain|LLMChain|BaseChain|Runnable", "name": "conversationChain", "label": "ConversationChain", - "type": "ConversationChain | LLMChain | BaseChain" + "type": "ConversationChain | LLMChain | BaseChain | Runnable" } ], "outputs": {}, @@ -302,8 +322,8 @@ }, "selected": false, "positionAbsolute": { - "x": 1174.6496397666272, - "y": 311.1052536740497 + "x": 958.9887390513221, + "y": 318.8734467468765 }, "dragging": false } @@ -311,14 +331,11 @@ "edges": [ { "source": "chatOpenAI_0", - "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", "target": "conversationChain_0", "targetHandle": "conversationChain_0-input-model-BaseChatModel", "type": "buttonedge", - "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-conversationChain_0-conversationChain_0-input-model-BaseChatModel", - "data": { - "label": "" - } + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-conversationChain_0-conversationChain_0-input-model-BaseChatModel" }, { "source": "bufferMemory_0", @@ -326,10 +343,7 @@ "target": "conversationChain_0", "targetHandle": "conversationChain_0-input-memory-BaseMemory", "type": "buttonedge", - "id": "bufferMemory_0-bufferMemory_0-output-bufferMemory-BufferMemory|BaseChatMemory|BaseMemory-conversationChain_0-conversationChain_0-input-memory-BaseMemory", - "data": { - "label": "" - } + "id": "bufferMemory_0-bufferMemory_0-output-bufferMemory-BufferMemory|BaseChatMemory|BaseMemory-conversationChain_0-conversationChain_0-input-memory-BaseMemory" } ] } From d2e6b094f62b1781749a3635ec3a1a00f52bdf16 Mon Sep 17 00:00:00 2001 From: Octavian FlowiseAI <154992625+ocflowiseai@users.noreply.github.com> Date: Fri, 19 Jan 2024 23:20:50 +0100 Subject: [PATCH 25/41] Update autoSyncMergedPullRequest workflow flags --- .github/workflows/autoSyncMergedPullRequest.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/autoSyncMergedPullRequest.yml b/.github/workflows/autoSyncMergedPullRequest.yml index 5b1991d7..288d0971 100644 --- a/.github/workflows/autoSyncMergedPullRequest.yml +++ b/.github/workflows/autoSyncMergedPullRequest.yml @@ -5,14 +5,16 @@ on: - closed branches: [ "main" ] jobs: - build: + autoSyncMergedPullRequest: if: github.event.pull_request.merged == true runs-on: ubuntu-latest + permissions: + contents: write steps: - uses: actions/checkout@v3 - name: Show PR info env: - GITHUB_CONTEXT: ${{ toJSON(github) }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | echo The PR #${{ github.event.pull_request.number }} was merged on main branch! - name: Repository Dispatch From 5d25c35a1ac4250bb79b21bc22243576a18b2e36 Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 21 Jan 2024 18:24:54 +0000 Subject: [PATCH 26/41] add env path for settings json --- packages/server/src/utils/index.ts | 1 + packages/server/src/utils/telemetry.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index a232094e..aa3e9ef6 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -1099,6 +1099,7 @@ export const getTelemetryFlowObj = (nodes: IReactFlowNode[], edges: IReactFlowEd * TODO: move env variables to settings json file, easier configuration */ export const getUserSettingsFilePath = () => { + if (process.env.SECRETKEY_PATH) return path.join(process.env.SECRETKEY_PATH, 'settings.json') const checkPaths = [path.join(getUserHome(), '.flowise', 'settings.json')] for (const checkPath of checkPaths) { if (fs.existsSync(checkPath)) { diff --git a/packages/server/src/utils/telemetry.ts b/packages/server/src/utils/telemetry.ts index 4254ea76..4b033f20 100644 --- a/packages/server/src/utils/telemetry.ts +++ b/packages/server/src/utils/telemetry.ts @@ -25,7 +25,9 @@ export class Telemetry { const settings = { instanceId } - const defaultLocation = path.join(getUserHome(), '.flowise', 'settings.json') + const defaultLocation = process.env.SECRETKEY_PATH + ? path.join(process.env.SECRETKEY_PATH, 'settings.json') + : path.join(getUserHome(), '.flowise', 'settings.json') await fs.promises.writeFile(defaultLocation, JSON.stringify(settings, null, 2)) return instanceId } From 2dd1c71cf26d2cb627da2a97be32aa5c312df01b Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 21 Jan 2024 22:26:58 +0000 Subject: [PATCH 27/41] return response --- packages/server/src/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 3c5766fd..b11653ee 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1825,8 +1825,10 @@ export class App { flowGraph: getTelemetryFlowObj(nodes, edges) }) - // Only return ChatId when its Internal OR incoming input has ChatId, to avoid confusion when calling API - if (incomingInput.chatId || isInternal) result.chatId = chatId + // Prepare response + result.chatId = chatId + if (sessionId) result.sessionId = sessionId + if (memoryType) result.memoryType = memoryType return res.json(result) } catch (e: any) { From ddab853cfd2266d95f2f379917359a2e9ca210f1 Mon Sep 17 00:00:00 2001 From: Octavian FlowiseAI <154992625+ocflowiseai@users.noreply.github.com> Date: Mon, 22 Jan 2024 09:57:01 +0100 Subject: [PATCH 28/41] Update autoSyncMergedPullRequest.yml - send pr title - send pr description --- .github/workflows/autoSyncMergedPullRequest.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/autoSyncMergedPullRequest.yml b/.github/workflows/autoSyncMergedPullRequest.yml index 288d0971..518db0bc 100644 --- a/.github/workflows/autoSyncMergedPullRequest.yml +++ b/.github/workflows/autoSyncMergedPullRequest.yml @@ -23,4 +23,11 @@ jobs: token: ${{ secrets.AUTOSYNC_TOKEN }} repository: ${{ secrets.AUTOSYNC_CH_URL }} event-type: ${{ secrets.AUTOSYNC_PR_EVENT_TYPE }} - client-payload: '{"ref": "${{ github.ref }}", "prNumber": "${{ github.event.pull_request.number }}", "sha": "${{ github.sha }}"}' + client-payload: >- + { + "ref": "${{ github.ref }}", + "prNumber": "${{ github.event.pull_request.number }}", + "prTitle": "${{ github.event.pull_request.title }}", + "prDescription": "${{ github.event.pull_request.description }}", + "sha": "${{ github.sha }}" + } From fb2e6a0e08cb62284ca11647e294d4dcf30136f7 Mon Sep 17 00:00:00 2001 From: Octavian FlowiseAI <154992625+ocflowiseai@users.noreply.github.com> Date: Mon, 22 Jan 2024 10:08:29 +0100 Subject: [PATCH 29/41] Update autoSyncSingleCommit.yml - send single commit message --- .github/workflows/autoSyncSingleCommit.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/autoSyncSingleCommit.yml b/.github/workflows/autoSyncSingleCommit.yml index ce429a60..738e271a 100644 --- a/.github/workflows/autoSyncSingleCommit.yml +++ b/.github/workflows/autoSyncSingleCommit.yml @@ -28,4 +28,9 @@ jobs: token: ${{ secrets.AUTOSYNC_TOKEN }} repository: ${{ secrets.AUTOSYNC_CH_URL }} event-type: ${{ secrets.AUTOSYNC_SC_EVENT_TYPE }} - client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}' + client-payload: >- + { + "ref": "${{ github.ref }}", + "sha": "${{ github.sha }}", + "commitMessage": "${{ github.event.commits[0].message }}", + } From 764efcccb738e1683b7e0cf623044ce3286d2f39 Mon Sep 17 00:00:00 2001 From: Octavian FlowiseAI <154992625+ocflowiseai@users.noreply.github.com> Date: Mon, 22 Jan 2024 10:09:19 +0100 Subject: [PATCH 30/41] Update autoSyncSingleCommit.yml --- .github/workflows/autoSyncSingleCommit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/autoSyncSingleCommit.yml b/.github/workflows/autoSyncSingleCommit.yml index 738e271a..8700f232 100644 --- a/.github/workflows/autoSyncSingleCommit.yml +++ b/.github/workflows/autoSyncSingleCommit.yml @@ -32,5 +32,5 @@ jobs: { "ref": "${{ github.ref }}", "sha": "${{ github.sha }}", - "commitMessage": "${{ github.event.commits[0].message }}", + "commitMessage": "${{ github.event.commits[0].message }}" } From 61e18666155626a89ede36624a5f5236b870cb4f Mon Sep 17 00:00:00 2001 From: Darien Kindlund Date: Mon, 1 Jan 2024 13:33:09 -0500 Subject: [PATCH 31/41] Added support for gpt-4 and gpt-4-32k models --- .../components/nodes/llms/Azure OpenAI/AzureOpenAI.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts index f50e3d95..a8ac8830 100644 --- a/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts +++ b/packages/components/nodes/llms/Azure OpenAI/AzureOpenAI.ts @@ -18,7 +18,7 @@ class AzureOpenAI_LLMs implements INode { constructor() { this.label = 'Azure OpenAI' this.name = 'azureOpenAI' - this.version = 2.0 + this.version = 2.1 this.type = 'AzureOpenAI' this.icon = 'Azure.svg' this.category = 'LLMs' @@ -89,6 +89,14 @@ class AzureOpenAI_LLMs implements INode { { label: 'gpt-35-turbo', name: 'gpt-35-turbo' + }, + { + label: 'gpt-4', + name: 'gpt-4' + }, + { + label: 'gpt-4-32k', + name: 'gpt-4-32k' } ], default: 'text-davinci-003', From da346d781499f01a2dfad5fcc4187a81c4954dfe Mon Sep 17 00:00:00 2001 From: "nikos.tsiougkos" Date: Wed, 24 Jan 2024 18:05:32 +0200 Subject: [PATCH 32/41] include chat message id in result --- packages/server/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index b11653ee..6d4c1887 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1814,7 +1814,8 @@ export class App { if (result?.sourceDocuments) apiMessage.sourceDocuments = JSON.stringify(result.sourceDocuments) if (result?.usedTools) apiMessage.usedTools = JSON.stringify(result.usedTools) if (result?.fileAnnotations) apiMessage.fileAnnotations = JSON.stringify(result.fileAnnotations) - await this.addChatMessage(apiMessage) + const chatMessage = await this.addChatMessage(apiMessage) + result.chatMessageId = chatMessage.id logger.debug(`[server]: Finished running ${nodeToExecuteData.label} (${nodeToExecuteData.id})`) await this.telemetry.sendTelemetry('prediction_sent', { From 03e2869b8e2a8d777305f3b10366799f39375e03 Mon Sep 17 00:00:00 2001 From: Ofer Mendelevitch Date: Wed, 24 Jan 2024 16:13:19 -0800 Subject: [PATCH 33/41] updated vectara chatflow --- .../chatflows/Vectara LLM Chain Upload.json | 461 ------------------ .../chatflows/Vectara RAG Chain.json | 395 +++++++++++++++ 2 files changed, 395 insertions(+), 461 deletions(-) delete mode 100644 packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json create mode 100644 packages/server/marketplaces/chatflows/Vectara RAG Chain.json diff --git a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json deleted file mode 100644 index 1a440be7..00000000 --- a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json +++ /dev/null @@ -1,461 +0,0 @@ -{ - "description": "A simple LLM chain that uses Vectara to enable conversations with uploaded files", - "nodes": [ - { - "width": 300, - "height": 574, - "id": "chatOpenAI_0", - "position": { - "x": 581.1784360612766, - "y": -229.3906666911439 - }, - "type": "customNode", - "data": { - "id": "chatOpenAI_0", - "label": "ChatOpenAI", - "version": 2, - "name": "chatOpenAI", - "type": "ChatOpenAI", - "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], - "category": "Chat Models", - "description": "Wrapper around OpenAI large language models that use the Chat endpoint", - "inputParams": [ - { - "label": "Connect Credential", - "name": "credential", - "type": "credential", - "credentialNames": ["openAIApi"], - "id": "chatOpenAI_0-input-credential-credential" - }, - { - "label": "Model Name", - "name": "modelName", - "type": "options", - "options": [ - { - "label": "gpt-4", - "name": "gpt-4" - }, - { - "label": "gpt-4-0613", - "name": "gpt-4-0613" - }, - { - "label": "gpt-4-32k", - "name": "gpt-4-32k" - }, - { - "label": "gpt-4-32k-0613", - "name": "gpt-4-32k-0613" - }, - { - "label": "gpt-3.5-turbo", - "name": "gpt-3.5-turbo" - }, - { - "label": "gpt-3.5-turbo-0613", - "name": "gpt-3.5-turbo-0613" - }, - { - "label": "gpt-3.5-turbo-16k", - "name": "gpt-3.5-turbo-16k" - }, - { - "label": "gpt-3.5-turbo-16k-0613", - "name": "gpt-3.5-turbo-16k-0613" - } - ], - "default": "gpt-3.5-turbo", - "optional": true, - "id": "chatOpenAI_0-input-modelName-options" - }, - { - "label": "Temperature", - "name": "temperature", - "type": "number", - "step": 0.1, - "default": 0.9, - "optional": true, - "id": "chatOpenAI_0-input-temperature-number" - }, - { - "label": "Max Tokens", - "name": "maxTokens", - "type": "number", - "step": 1, - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-maxTokens-number" - }, - { - "label": "Top Probability", - "name": "topP", - "type": "number", - "step": 0.1, - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-topP-number" - }, - { - "label": "Frequency Penalty", - "name": "frequencyPenalty", - "type": "number", - "step": 0.1, - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-frequencyPenalty-number" - }, - { - "label": "Presence Penalty", - "name": "presencePenalty", - "type": "number", - "step": 0.1, - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-presencePenalty-number" - }, - { - "label": "Timeout", - "name": "timeout", - "type": "number", - "step": 1, - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-timeout-number" - }, - { - "label": "BasePath", - "name": "basepath", - "type": "string", - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-basepath-string" - }, - { - "label": "BaseOptions", - "name": "baseOptions", - "type": "json", - "optional": true, - "additionalParams": true, - "id": "chatOpenAI_0-input-baseOptions-json" - } - ], - "inputAnchors": [ - { - "label": "Cache", - "name": "cache", - "type": "BaseCache", - "optional": true, - "id": "chatOpenAI_0-input-cache-BaseCache" - } - ], - "inputs": { - "modelName": "gpt-3.5-turbo", - "temperature": "0.6", - "maxTokens": "", - "topP": "", - "frequencyPenalty": "", - "presencePenalty": "", - "timeout": "", - "basepath": "", - "baseOptions": "" - }, - "outputAnchors": [ - { - "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", - "name": "chatOpenAI", - "label": "ChatOpenAI", - "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" - } - ], - "outputs": {}, - "selected": false - }, - "selected": false, - "positionAbsolute": { - "x": 581.1784360612766, - "y": -229.3906666911439 - }, - "dragging": false - }, - { - "width": 300, - "height": 480, - "id": "conversationalRetrievalQAChain_0", - "position": { - "x": 979.9713511176517, - "y": 200.09513217589273 - }, - "type": "customNode", - "data": { - "id": "conversationalRetrievalQAChain_0", - "label": "Conversational Retrieval QA Chain", - "version": 2, - "name": "conversationalRetrievalQAChain", - "type": "ConversationalRetrievalQAChain", - "baseClasses": ["ConversationalRetrievalQAChain", "BaseChain", "Runnable"], - "category": "Chains", - "description": "Document QA - built on RetrievalQAChain to provide a chat history component", - "inputParams": [ - { - "label": "Return Source Documents", - "name": "returnSourceDocuments", - "type": "boolean", - "optional": true, - "id": "conversationalRetrievalQAChain_0-input-returnSourceDocuments-boolean" - }, - { - "label": "Rephrase Prompt", - "name": "rephrasePrompt", - "type": "string", - "description": "Using previous chat history, rephrase question into a standalone question", - "warning": "Prompt must include input variables: {chat_history} and {question}", - "rows": 4, - "additionalParams": true, - "optional": true, - "default": "Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.\n\nChat History:\n{chat_history}\nFollow Up Input: {question}\nStandalone Question:", - "id": "conversationalRetrievalQAChain_0-input-rephrasePrompt-string" - }, - { - "label": "Response Prompt", - "name": "responsePrompt", - "type": "string", - "description": "Taking the rephrased question, search for answer from the provided context", - "warning": "Prompt must include input variable: {context}", - "rows": 4, - "additionalParams": true, - "optional": true, - "default": "You are a helpful assistant. Using the provided context, answer the user's question to the best of your ability using the resources provided.\nIf there is nothing in the context relevant to the question at hand, just say \"Hmm, I'm not sure.\" Don't try to make up an answer.\n------------\n{context}\n------------\nREMEMBER: If there is no relevant information within the context, just say \"Hmm, I'm not sure.\" Don't try to make up an answer.", - "id": "conversationalRetrievalQAChain_0-input-responsePrompt-string" - } - ], - "inputAnchors": [ - { - "label": "Chat Model", - "name": "model", - "type": "BaseChatModel", - "id": "conversationalRetrievalQAChain_0-input-model-BaseChatModel" - }, - { - "label": "Vector Store Retriever", - "name": "vectorStoreRetriever", - "type": "BaseRetriever", - "id": "conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever" - }, - { - "label": "Memory", - "name": "memory", - "type": "BaseMemory", - "optional": true, - "description": "If left empty, a default BufferMemory will be used", - "id": "conversationalRetrievalQAChain_0-input-memory-BaseMemory" - } - ], - "inputs": { - "model": "{{chatOpenAI_0.data.instance}}", - "vectorStoreRetriever": "{{vectara_0.data.instance}}", - "memory": "", - "returnSourceDocuments": true, - "rephrasePrompt": "Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.\n\nChat History:\n{chat_history}\nFollow Up Input: {question}\nStandalone Question:", - "responsePrompt": "You are a helpful assistant. Using the provided context, answer the user's question to the best of your ability using the resources provided.\nIf there is nothing in the context relevant to the question at hand, just say \"Hmm, I'm not sure.\" Don't try to make up an answer.\n------------\n{context}\n------------\nREMEMBER: If there is no relevant information within the context, just say \"Hmm, I'm not sure.\" Don't try to make up an answer." - }, - "outputAnchors": [ - { - "id": "conversationalRetrievalQAChain_0-output-conversationalRetrievalQAChain-ConversationalRetrievalQAChain|BaseChain|Runnable", - "name": "conversationalRetrievalQAChain", - "label": "ConversationalRetrievalQAChain", - "type": "ConversationalRetrievalQAChain | BaseChain | Runnable" - } - ], - "outputs": {}, - "selected": false - }, - "selected": false, - "dragging": false, - "positionAbsolute": { - "x": 979.9713511176517, - "y": 200.09513217589273 - } - }, - { - "width": 300, - "height": 535, - "id": "vectara_0", - "position": { - "x": 199.28476672510158, - "y": 177.63260741741112 - }, - "type": "customNode", - "data": { - "id": "vectara_0", - "label": "Vectara", - "version": 1, - "name": "vectara", - "type": "Vectara", - "baseClasses": ["Vectara", "VectorStoreRetriever", "BaseRetriever"], - "category": "Vector Stores", - "description": "Upsert embedded data and perform similarity search upon query using Vectara, a LLM-powered search-as-a-service", - "inputParams": [ - { - "label": "Connect Credential", - "name": "credential", - "type": "credential", - "credentialNames": ["vectaraApi"], - "id": "vectara_0-input-credential-credential" - }, - { - "label": "File", - "name": "file", - "description": "File to upload to Vectara. Supported file types: https://docs.vectara.com/docs/api-reference/indexing-apis/file-upload/file-upload-filetypes", - "type": "file", - "optional": true, - "id": "vectara_0-input-file-file" - }, - { - "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", - "additionalParams": true, - "optional": true, - "id": "vectara_0-input-filter-string" - }, - { - "label": "Sentences Before", - "name": "sentencesBefore", - "description": "Number of sentences to fetch before the matched sentence. Defaults to 2.", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_0-input-sentencesBefore-number" - }, - { - "label": "Sentences After", - "name": "sentencesAfter", - "description": "Number of sentences to fetch after the matched sentence. Defaults to 2.", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_0-input-sentencesAfter-number" - }, - { - "label": "Lambda", - "name": "lambda", - "description": "Improves retrieval accuracy by adjusting the balance (from 0 to 1) between neural search and keyword-based search factors.", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_0-input-lambda-number" - }, - { - "label": "Top K", - "name": "topK", - "description": "Number of top results to fetch. Defaults to 5", - "placeholder": "5", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_0-input-topK-number" - }, - { - "label": "MMR K", - "name": "mmrK", - "description": "The number of results to rerank if MMR is enabled.", - "placeholder": "50", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_0-input-mmrK-number" - }, - { - "label": "MMR Diversity Bias", - "name": "mmrDiversityBias", - "step": 0.1, - "description": "Diversity Bias parameter for MMR, if enabled. 0.0 means no diversiry bias, 1.0 means maximum diversity bias. Defaults to 0.0 (MMR disabled).", - "placeholder": "0.0", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_0-input-mmrDiversityBias-number" - } - ], - "inputAnchors": [ - { - "label": "Document", - "name": "document", - "type": "Document", - "list": true, - "optional": true, - "id": "vectara_0-input-document-Document" - } - ], - "inputs": { - "document": "", - "filter": "", - "sentencesBefore": "", - "sentencesAfter": "", - "lambda": "", - "topK": "", - "mmrK": "", - "mmrDiversityBias": "" - }, - "outputAnchors": [ - { - "name": "output", - "label": "Output", - "type": "options", - "options": [ - { - "id": "vectara_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", - "name": "retriever", - "label": "Vectara Retriever", - "type": "Vectara | VectorStoreRetriever | BaseRetriever" - }, - { - "id": "vectara_0-output-vectorStore-Vectara|VectorStore", - "name": "vectorStore", - "label": "Vectara Vector Store", - "type": "Vectara | VectorStore" - } - ], - "default": "retriever" - } - ], - "outputs": { - "output": "retriever" - }, - "selected": false - }, - "selected": false, - "positionAbsolute": { - "x": 199.28476672510158, - "y": 177.63260741741112 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "chatOpenAI_0", - "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", - "target": "conversationalRetrievalQAChain_0", - "targetHandle": "conversationalRetrievalQAChain_0-input-model-BaseChatModel", - "type": "buttonedge", - "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-model-BaseChatModel", - "data": { - "label": "" - } - }, - { - "source": "vectara_0", - "sourceHandle": "vectara_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", - "target": "conversationalRetrievalQAChain_0", - "targetHandle": "conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever", - "type": "buttonedge", - "id": "vectara_0-vectara_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever", - "data": { - "label": "" - } - } - ] -} diff --git a/packages/server/marketplaces/chatflows/Vectara RAG Chain.json b/packages/server/marketplaces/chatflows/Vectara RAG Chain.json new file mode 100644 index 00000000..ac239d0f --- /dev/null +++ b/packages/server/marketplaces/chatflows/Vectara RAG Chain.json @@ -0,0 +1,395 @@ +{ + "nodes": [ + { + "width": 300, + "height": 520, + "id": "vectaraQAChain_0", + "position": { + "x": 740.28434119739, + "y": 164.93261446841598 + }, + "type": "customNode", + "data": { + "id": "vectaraQAChain_0", + "label": "Vectara QA Chain", + "version": 1, + "name": "vectaraQAChain", + "type": "VectaraQAChain", + "baseClasses": [ + "VectaraQAChain", + "BaseChain", + "Runnable" + ], + "category": "Chains", + "description": "QA chain for Vectara", + "inputParams": [ + { + "label": "Summarizer Prompt Name", + "name": "summarizerPromptName", + "description": "Summarize the results fetched from Vectara. Read more", + "type": "options", + "options": [ + { + "label": "vectara-summary-ext-v1.2.0 (gpt-3.5-turbo)", + "name": "vectara-summary-ext-v1.2.0" + }, + { + "label": "vectara-experimental-summary-ext-2023-10-23-small (gpt-3.5-turbo)", + "name": "vectara-experimental-summary-ext-2023-10-23-small", + "description": "In beta, available to both Growth and Scale Vectara users" + }, + { + "label": "vectara-summary-ext-v1.3.0 (gpt-4.0)", + "name": "vectara-summary-ext-v1.3.0", + "description": "Only available to paying Scale Vectara users" + }, + { + "label": "vectara-experimental-summary-ext-2023-10-23-med (gpt-4.0)", + "name": "vectara-experimental-summary-ext-2023-10-23-med", + "description": "In beta, only available to paying Scale Vectara users" + } + ], + "default": "vectara-summary-ext-v1.2.0", + "id": "vectaraQAChain_0-input-summarizerPromptName-options" + }, + { + "label": "Response Language", + "name": "responseLang", + "description": "Return the response in specific language. If not selected, Vectara will automatically detects the language. Read more", + "type": "options", + "options": [ + { + "label": "English", + "name": "eng" + }, + { + "label": "German", + "name": "deu" + }, + { + "label": "French", + "name": "fra" + }, + { + "label": "Chinese", + "name": "zho" + }, + { + "label": "Korean", + "name": "kor" + }, + { + "label": "Arabic", + "name": "ara" + }, + { + "label": "Russian", + "name": "rus" + }, + { + "label": "Thai", + "name": "tha" + }, + { + "label": "Dutch", + "name": "nld" + }, + { + "label": "Italian", + "name": "ita" + }, + { + "label": "Portuguese", + "name": "por" + }, + { + "label": "Spanish", + "name": "spa" + }, + { + "label": "Japanese", + "name": "jpn" + }, + { + "label": "Polish", + "name": "pol" + }, + { + "label": "Turkish", + "name": "tur" + }, + { + "label": "Vietnamese", + "name": "vie" + }, + { + "label": "Indonesian", + "name": "ind" + }, + { + "label": "Czech", + "name": "ces" + }, + { + "label": "Ukrainian", + "name": "ukr" + }, + { + "label": "Greek", + "name": "ell" + }, + { + "label": "Hebrew", + "name": "heb" + }, + { + "label": "Farsi/Persian", + "name": "fas" + }, + { + "label": "Hindi", + "name": "hin" + }, + { + "label": "Urdu", + "name": "urd" + }, + { + "label": "Swedish", + "name": "swe" + }, + { + "label": "Bengali", + "name": "ben" + }, + { + "label": "Malay", + "name": "msa" + }, + { + "label": "Romanian", + "name": "ron" + } + ], + "optional": true, + "default": "eng", + "id": "vectaraQAChain_0-input-responseLang-options" + }, + { + "label": "Max Summarized Results", + "name": "maxSummarizedResults", + "description": "Maximum results used to build the summarized response", + "type": "number", + "default": 7, + "id": "vectaraQAChain_0-input-maxSummarizedResults-number" + } + ], + "inputAnchors": [ + { + "label": "Vectara Store", + "name": "vectaraStore", + "type": "VectorStore", + "id": "vectaraQAChain_0-input-vectaraStore-VectorStore" + } + ], + "inputs": { + "vectaraStore": "{{vectara_1.data.instance}}", + "summarizerPromptName": "vectara-experimental-summary-ext-2023-10-23-small", + "responseLang": "eng", + "maxSummarizedResults": 7 + }, + "outputAnchors": [ + { + "id": "vectaraQAChain_0-output-vectaraQAChain-VectaraQAChain|BaseChain|Runnable", + "name": "vectaraQAChain", + "label": "VectaraQAChain", + "type": "VectaraQAChain | BaseChain | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 740.28434119739, + "y": 164.93261446841598 + }, + "dragging": false + }, + { + "width": 300, + "height": 536, + "id": "vectara_1", + "position": { + "x": 139.43135627266395, + "y": 189.3685569634871 + }, + "type": "customNode", + "data": { + "id": "vectara_1", + "label": "Vectara", + "version": 2, + "name": "vectara", + "type": "Vectara", + "baseClasses": [ + "Vectara", + "VectorStoreRetriever", + "BaseRetriever" + ], + "category": "Vector Stores", + "description": "Upsert embedded data and perform similarity search upon query using Vectara, a LLM-powered search-as-a-service", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": [ + "vectaraApi" + ], + "id": "vectara_1-input-credential-credential" + }, + { + "label": "File", + "name": "file", + "description": "File to upload to Vectara. Supported file types: https://docs.vectara.com/docs/api-reference/indexing-apis/file-upload/file-upload-filetypes", + "type": "file", + "optional": true, + "id": "vectara_1-input-file-file" + }, + { + "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", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-filter-string" + }, + { + "label": "Sentences Before", + "name": "sentencesBefore", + "description": "Number of sentences to fetch before the matched sentence. Defaults to 2.", + "type": "number", + "default": 2, + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-sentencesBefore-number" + }, + { + "label": "Sentences After", + "name": "sentencesAfter", + "description": "Number of sentences to fetch after the matched sentence. Defaults to 2.", + "type": "number", + "default": 2, + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-sentencesAfter-number" + }, + { + "label": "Lambda", + "name": "lambda", + "description": "Enable hybrid search to improve retrieval accuracy by adjusting the balance (from 0 to 1) between neural search and keyword-based search factors.A value of 0.0 means that only neural search is used, while a value of 1.0 means that only keyword-based search is used. Defaults to 0.0 (neural only).", + "default": 0, + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-lambda-number" + }, + { + "label": "Top K", + "name": "topK", + "description": "Number of top results to fetch. Defaults to 5", + "placeholder": "5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-topK-number" + }, + { + "label": "MMR K", + "name": "mmrK", + "description": "Number of top results to fetch for MMR. Defaults to 50", + "placeholder": "50", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-mmrK-number" + }, + { + "label": "MMR diversity bias", + "name": "mmrDiversityBias", + "step": 0.1, + "description": "The diversity bias to use for MMR. This is a value between 0.0 and 1.0Values closer to 1.0 optimize for the most diverse results.Defaults to 0 (MMR disabled)", + "placeholder": "0.0", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-mmrDiversityBias-number" + } + ], + "inputAnchors": [ + { + "label": "Document", + "name": "document", + "type": "Document", + "list": true, + "optional": true, + "id": "vectara_1-input-document-Document" + } + ], + "inputs": { + "document": "", + "filter": "", + "sentencesBefore": 2, + "sentencesAfter": 2, + "lambda": "", + "topK": "", + "mmrK": "", + "mmrDiversityBias": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "vectara_1-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", + "name": "retriever", + "label": "Vectara Retriever", + "type": "Vectara | VectorStoreRetriever | BaseRetriever" + }, + { + "id": "vectara_1-output-vectorStore-Vectara|VectorStore", + "name": "vectorStore", + "label": "Vectara Vector Store", + "type": "Vectara | VectorStore" + } + ], + "default": "retriever" + } + ], + "outputs": { + "output": "vectorStore" + }, + "selected": false + }, + "positionAbsolute": { + "x": 139.43135627266395, + "y": 189.3685569634871 + }, + "selected": false, + "dragging": false + } + ], + "edges": [ + { + "source": "vectara_1", + "sourceHandle": "vectara_1-output-vectorStore-Vectara|VectorStore", + "target": "vectaraQAChain_0", + "targetHandle": "vectaraQAChain_0-input-vectaraStore-VectorStore", + "type": "buttonedge", + "id": "vectara_1-vectara_1-output-vectorStore-Vectara|VectorStore-vectaraQAChain_0-vectaraQAChain_0-input-vectaraStore-VectorStore" + } + ] + } \ No newline at end of file From 8a96493e32e3e05a12d93b9fe84e8303fc7a4288 Mon Sep 17 00:00:00 2001 From: Ofer Mendelevitch Date: Wed, 24 Jan 2024 16:45:37 -0800 Subject: [PATCH 34/41] after yarn lint --- .../chatflows/Vectara RAG Chain.json | 758 +++++++++--------- 1 file changed, 374 insertions(+), 384 deletions(-) diff --git a/packages/server/marketplaces/chatflows/Vectara RAG Chain.json b/packages/server/marketplaces/chatflows/Vectara RAG Chain.json index ac239d0f..d3bb5bf8 100644 --- a/packages/server/marketplaces/chatflows/Vectara RAG Chain.json +++ b/packages/server/marketplaces/chatflows/Vectara RAG Chain.json @@ -1,395 +1,385 @@ { "nodes": [ - { - "width": 300, - "height": 520, - "id": "vectaraQAChain_0", - "position": { - "x": 740.28434119739, - "y": 164.93261446841598 + { + "width": 300, + "height": 520, + "id": "vectaraQAChain_0", + "position": { + "x": 740.28434119739, + "y": 164.93261446841598 + }, + "type": "customNode", + "data": { + "id": "vectaraQAChain_0", + "label": "Vectara QA Chain", + "version": 1, + "name": "vectaraQAChain", + "type": "VectaraQAChain", + "baseClasses": ["VectaraQAChain", "BaseChain", "Runnable"], + "category": "Chains", + "description": "QA chain for Vectara", + "inputParams": [ + { + "label": "Summarizer Prompt Name", + "name": "summarizerPromptName", + "description": "Summarize the results fetched from Vectara. Read more", + "type": "options", + "options": [ + { + "label": "vectara-summary-ext-v1.2.0 (gpt-3.5-turbo)", + "name": "vectara-summary-ext-v1.2.0" + }, + { + "label": "vectara-experimental-summary-ext-2023-10-23-small (gpt-3.5-turbo)", + "name": "vectara-experimental-summary-ext-2023-10-23-small", + "description": "In beta, available to both Growth and Scale Vectara users" + }, + { + "label": "vectara-summary-ext-v1.3.0 (gpt-4.0)", + "name": "vectara-summary-ext-v1.3.0", + "description": "Only available to paying Scale Vectara users" + }, + { + "label": "vectara-experimental-summary-ext-2023-10-23-med (gpt-4.0)", + "name": "vectara-experimental-summary-ext-2023-10-23-med", + "description": "In beta, only available to paying Scale Vectara users" + } + ], + "default": "vectara-summary-ext-v1.2.0", + "id": "vectaraQAChain_0-input-summarizerPromptName-options" + }, + { + "label": "Response Language", + "name": "responseLang", + "description": "Return the response in specific language. If not selected, Vectara will automatically detects the language. Read more", + "type": "options", + "options": [ + { + "label": "English", + "name": "eng" + }, + { + "label": "German", + "name": "deu" + }, + { + "label": "French", + "name": "fra" + }, + { + "label": "Chinese", + "name": "zho" + }, + { + "label": "Korean", + "name": "kor" + }, + { + "label": "Arabic", + "name": "ara" + }, + { + "label": "Russian", + "name": "rus" + }, + { + "label": "Thai", + "name": "tha" + }, + { + "label": "Dutch", + "name": "nld" + }, + { + "label": "Italian", + "name": "ita" + }, + { + "label": "Portuguese", + "name": "por" + }, + { + "label": "Spanish", + "name": "spa" + }, + { + "label": "Japanese", + "name": "jpn" + }, + { + "label": "Polish", + "name": "pol" + }, + { + "label": "Turkish", + "name": "tur" + }, + { + "label": "Vietnamese", + "name": "vie" + }, + { + "label": "Indonesian", + "name": "ind" + }, + { + "label": "Czech", + "name": "ces" + }, + { + "label": "Ukrainian", + "name": "ukr" + }, + { + "label": "Greek", + "name": "ell" + }, + { + "label": "Hebrew", + "name": "heb" + }, + { + "label": "Farsi/Persian", + "name": "fas" + }, + { + "label": "Hindi", + "name": "hin" + }, + { + "label": "Urdu", + "name": "urd" + }, + { + "label": "Swedish", + "name": "swe" + }, + { + "label": "Bengali", + "name": "ben" + }, + { + "label": "Malay", + "name": "msa" + }, + { + "label": "Romanian", + "name": "ron" + } + ], + "optional": true, + "default": "eng", + "id": "vectaraQAChain_0-input-responseLang-options" + }, + { + "label": "Max Summarized Results", + "name": "maxSummarizedResults", + "description": "Maximum results used to build the summarized response", + "type": "number", + "default": 7, + "id": "vectaraQAChain_0-input-maxSummarizedResults-number" + } + ], + "inputAnchors": [ + { + "label": "Vectara Store", + "name": "vectaraStore", + "type": "VectorStore", + "id": "vectaraQAChain_0-input-vectaraStore-VectorStore" + } + ], + "inputs": { + "vectaraStore": "{{vectara_1.data.instance}}", + "summarizerPromptName": "vectara-experimental-summary-ext-2023-10-23-small", + "responseLang": "eng", + "maxSummarizedResults": 7 + }, + "outputAnchors": [ + { + "id": "vectaraQAChain_0-output-vectaraQAChain-VectaraQAChain|BaseChain|Runnable", + "name": "vectaraQAChain", + "label": "VectaraQAChain", + "type": "VectaraQAChain | BaseChain | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 740.28434119739, + "y": 164.93261446841598 + }, + "dragging": false }, - "type": "customNode", - "data": { - "id": "vectaraQAChain_0", - "label": "Vectara QA Chain", - "version": 1, - "name": "vectaraQAChain", - "type": "VectaraQAChain", - "baseClasses": [ - "VectaraQAChain", - "BaseChain", - "Runnable" - ], - "category": "Chains", - "description": "QA chain for Vectara", - "inputParams": [ - { - "label": "Summarizer Prompt Name", - "name": "summarizerPromptName", - "description": "Summarize the results fetched from Vectara. Read more", - "type": "options", - "options": [ - { - "label": "vectara-summary-ext-v1.2.0 (gpt-3.5-turbo)", - "name": "vectara-summary-ext-v1.2.0" - }, - { - "label": "vectara-experimental-summary-ext-2023-10-23-small (gpt-3.5-turbo)", - "name": "vectara-experimental-summary-ext-2023-10-23-small", - "description": "In beta, available to both Growth and Scale Vectara users" - }, - { - "label": "vectara-summary-ext-v1.3.0 (gpt-4.0)", - "name": "vectara-summary-ext-v1.3.0", - "description": "Only available to paying Scale Vectara users" - }, - { - "label": "vectara-experimental-summary-ext-2023-10-23-med (gpt-4.0)", - "name": "vectara-experimental-summary-ext-2023-10-23-med", - "description": "In beta, only available to paying Scale Vectara users" - } - ], - "default": "vectara-summary-ext-v1.2.0", - "id": "vectaraQAChain_0-input-summarizerPromptName-options" + { + "width": 300, + "height": 536, + "id": "vectara_1", + "position": { + "x": 139.43135627266395, + "y": 189.3685569634871 }, - { - "label": "Response Language", - "name": "responseLang", - "description": "Return the response in specific language. If not selected, Vectara will automatically detects the language. Read more", - "type": "options", - "options": [ - { - "label": "English", - "name": "eng" + "type": "customNode", + "data": { + "id": "vectara_1", + "label": "Vectara", + "version": 2, + "name": "vectara", + "type": "Vectara", + "baseClasses": ["Vectara", "VectorStoreRetriever", "BaseRetriever"], + "category": "Vector Stores", + "description": "Upsert embedded data and perform similarity search upon query using Vectara, a LLM-powered search-as-a-service", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["vectaraApi"], + "id": "vectara_1-input-credential-credential" + }, + { + "label": "File", + "name": "file", + "description": "File to upload to Vectara. Supported file types: https://docs.vectara.com/docs/api-reference/indexing-apis/file-upload/file-upload-filetypes", + "type": "file", + "optional": true, + "id": "vectara_1-input-file-file" + }, + { + "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", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-filter-string" + }, + { + "label": "Sentences Before", + "name": "sentencesBefore", + "description": "Number of sentences to fetch before the matched sentence. Defaults to 2.", + "type": "number", + "default": 2, + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-sentencesBefore-number" + }, + { + "label": "Sentences After", + "name": "sentencesAfter", + "description": "Number of sentences to fetch after the matched sentence. Defaults to 2.", + "type": "number", + "default": 2, + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-sentencesAfter-number" + }, + { + "label": "Lambda", + "name": "lambda", + "description": "Enable hybrid search to improve retrieval accuracy by adjusting the balance (from 0 to 1) between neural search and keyword-based search factors.A value of 0.0 means that only neural search is used, while a value of 1.0 means that only keyword-based search is used. Defaults to 0.0 (neural only).", + "default": 0, + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-lambda-number" + }, + { + "label": "Top K", + "name": "topK", + "description": "Number of top results to fetch. Defaults to 5", + "placeholder": "5", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-topK-number" + }, + { + "label": "MMR K", + "name": "mmrK", + "description": "Number of top results to fetch for MMR. Defaults to 50", + "placeholder": "50", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-mmrK-number" + }, + { + "label": "MMR diversity bias", + "name": "mmrDiversityBias", + "step": 0.1, + "description": "The diversity bias to use for MMR. This is a value between 0.0 and 1.0Values closer to 1.0 optimize for the most diverse results.Defaults to 0 (MMR disabled)", + "placeholder": "0.0", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectara_1-input-mmrDiversityBias-number" + } + ], + "inputAnchors": [ + { + "label": "Document", + "name": "document", + "type": "Document", + "list": true, + "optional": true, + "id": "vectara_1-input-document-Document" + } + ], + "inputs": { + "document": "", + "filter": "", + "sentencesBefore": 2, + "sentencesAfter": 2, + "lambda": "", + "topK": "", + "mmrK": "", + "mmrDiversityBias": "" }, - { - "label": "German", - "name": "deu" + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "vectara_1-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", + "name": "retriever", + "label": "Vectara Retriever", + "type": "Vectara | VectorStoreRetriever | BaseRetriever" + }, + { + "id": "vectara_1-output-vectorStore-Vectara|VectorStore", + "name": "vectorStore", + "label": "Vectara Vector Store", + "type": "Vectara | VectorStore" + } + ], + "default": "retriever" + } + ], + "outputs": { + "output": "vectorStore" }, - { - "label": "French", - "name": "fra" - }, - { - "label": "Chinese", - "name": "zho" - }, - { - "label": "Korean", - "name": "kor" - }, - { - "label": "Arabic", - "name": "ara" - }, - { - "label": "Russian", - "name": "rus" - }, - { - "label": "Thai", - "name": "tha" - }, - { - "label": "Dutch", - "name": "nld" - }, - { - "label": "Italian", - "name": "ita" - }, - { - "label": "Portuguese", - "name": "por" - }, - { - "label": "Spanish", - "name": "spa" - }, - { - "label": "Japanese", - "name": "jpn" - }, - { - "label": "Polish", - "name": "pol" - }, - { - "label": "Turkish", - "name": "tur" - }, - { - "label": "Vietnamese", - "name": "vie" - }, - { - "label": "Indonesian", - "name": "ind" - }, - { - "label": "Czech", - "name": "ces" - }, - { - "label": "Ukrainian", - "name": "ukr" - }, - { - "label": "Greek", - "name": "ell" - }, - { - "label": "Hebrew", - "name": "heb" - }, - { - "label": "Farsi/Persian", - "name": "fas" - }, - { - "label": "Hindi", - "name": "hin" - }, - { - "label": "Urdu", - "name": "urd" - }, - { - "label": "Swedish", - "name": "swe" - }, - { - "label": "Bengali", - "name": "ben" - }, - { - "label": "Malay", - "name": "msa" - }, - { - "label": "Romanian", - "name": "ron" - } - ], - "optional": true, - "default": "eng", - "id": "vectaraQAChain_0-input-responseLang-options" + "selected": false }, - { - "label": "Max Summarized Results", - "name": "maxSummarizedResults", - "description": "Maximum results used to build the summarized response", - "type": "number", - "default": 7, - "id": "vectaraQAChain_0-input-maxSummarizedResults-number" - } - ], - "inputAnchors": [ - { - "label": "Vectara Store", - "name": "vectaraStore", - "type": "VectorStore", - "id": "vectaraQAChain_0-input-vectaraStore-VectorStore" - } - ], - "inputs": { - "vectaraStore": "{{vectara_1.data.instance}}", - "summarizerPromptName": "vectara-experimental-summary-ext-2023-10-23-small", - "responseLang": "eng", - "maxSummarizedResults": 7 - }, - "outputAnchors": [ - { - "id": "vectaraQAChain_0-output-vectaraQAChain-VectaraQAChain|BaseChain|Runnable", - "name": "vectaraQAChain", - "label": "VectaraQAChain", - "type": "VectaraQAChain | BaseChain | Runnable" - } - ], - "outputs": {}, - "selected": false - }, - "selected": false, - "positionAbsolute": { - "x": 740.28434119739, - "y": 164.93261446841598 - }, - "dragging": false - }, - { - "width": 300, - "height": 536, - "id": "vectara_1", - "position": { - "x": 139.43135627266395, - "y": 189.3685569634871 - }, - "type": "customNode", - "data": { - "id": "vectara_1", - "label": "Vectara", - "version": 2, - "name": "vectara", - "type": "Vectara", - "baseClasses": [ - "Vectara", - "VectorStoreRetriever", - "BaseRetriever" - ], - "category": "Vector Stores", - "description": "Upsert embedded data and perform similarity search upon query using Vectara, a LLM-powered search-as-a-service", - "inputParams": [ - { - "label": "Connect Credential", - "name": "credential", - "type": "credential", - "credentialNames": [ - "vectaraApi" - ], - "id": "vectara_1-input-credential-credential" + "positionAbsolute": { + "x": 139.43135627266395, + "y": 189.3685569634871 }, - { - "label": "File", - "name": "file", - "description": "File to upload to Vectara. Supported file types: https://docs.vectara.com/docs/api-reference/indexing-apis/file-upload/file-upload-filetypes", - "type": "file", - "optional": true, - "id": "vectara_1-input-file-file" - }, - { - "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", - "additionalParams": true, - "optional": true, - "id": "vectara_1-input-filter-string" - }, - { - "label": "Sentences Before", - "name": "sentencesBefore", - "description": "Number of sentences to fetch before the matched sentence. Defaults to 2.", - "type": "number", - "default": 2, - "additionalParams": true, - "optional": true, - "id": "vectara_1-input-sentencesBefore-number" - }, - { - "label": "Sentences After", - "name": "sentencesAfter", - "description": "Number of sentences to fetch after the matched sentence. Defaults to 2.", - "type": "number", - "default": 2, - "additionalParams": true, - "optional": true, - "id": "vectara_1-input-sentencesAfter-number" - }, - { - "label": "Lambda", - "name": "lambda", - "description": "Enable hybrid search to improve retrieval accuracy by adjusting the balance (from 0 to 1) between neural search and keyword-based search factors.A value of 0.0 means that only neural search is used, while a value of 1.0 means that only keyword-based search is used. Defaults to 0.0 (neural only).", - "default": 0, - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_1-input-lambda-number" - }, - { - "label": "Top K", - "name": "topK", - "description": "Number of top results to fetch. Defaults to 5", - "placeholder": "5", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_1-input-topK-number" - }, - { - "label": "MMR K", - "name": "mmrK", - "description": "Number of top results to fetch for MMR. Defaults to 50", - "placeholder": "50", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_1-input-mmrK-number" - }, - { - "label": "MMR diversity bias", - "name": "mmrDiversityBias", - "step": 0.1, - "description": "The diversity bias to use for MMR. This is a value between 0.0 and 1.0Values closer to 1.0 optimize for the most diverse results.Defaults to 0 (MMR disabled)", - "placeholder": "0.0", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectara_1-input-mmrDiversityBias-number" - } - ], - "inputAnchors": [ - { - "label": "Document", - "name": "document", - "type": "Document", - "list": true, - "optional": true, - "id": "vectara_1-input-document-Document" - } - ], - "inputs": { - "document": "", - "filter": "", - "sentencesBefore": 2, - "sentencesAfter": 2, - "lambda": "", - "topK": "", - "mmrK": "", - "mmrDiversityBias": "" - }, - "outputAnchors": [ - { - "name": "output", - "label": "Output", - "type": "options", - "options": [ - { - "id": "vectara_1-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", - "name": "retriever", - "label": "Vectara Retriever", - "type": "Vectara | VectorStoreRetriever | BaseRetriever" - }, - { - "id": "vectara_1-output-vectorStore-Vectara|VectorStore", - "name": "vectorStore", - "label": "Vectara Vector Store", - "type": "Vectara | VectorStore" - } - ], - "default": "retriever" - } - ], - "outputs": { - "output": "vectorStore" - }, - "selected": false - }, - "positionAbsolute": { - "x": 139.43135627266395, - "y": 189.3685569634871 - }, - "selected": false, - "dragging": false - } + "selected": false, + "dragging": false + } ], "edges": [ - { - "source": "vectara_1", - "sourceHandle": "vectara_1-output-vectorStore-Vectara|VectorStore", - "target": "vectaraQAChain_0", - "targetHandle": "vectaraQAChain_0-input-vectaraStore-VectorStore", - "type": "buttonedge", - "id": "vectara_1-vectara_1-output-vectorStore-Vectara|VectorStore-vectaraQAChain_0-vectaraQAChain_0-input-vectaraStore-VectorStore" - } + { + "source": "vectara_1", + "sourceHandle": "vectara_1-output-vectorStore-Vectara|VectorStore", + "target": "vectaraQAChain_0", + "targetHandle": "vectaraQAChain_0-input-vectaraStore-VectorStore", + "type": "buttonedge", + "id": "vectara_1-vectara_1-output-vectorStore-Vectara|VectorStore-vectaraQAChain_0-vectaraQAChain_0-input-vectaraStore-VectorStore" + } ] - } \ No newline at end of file +} From 600f99aa95dd90d662de9b5ee47940bae6bd9ce4 Mon Sep 17 00:00:00 2001 From: Octavian FlowiseAI <154992625+ocflowiseai@users.noreply.github.com> Date: Thu, 25 Jan 2024 03:42:06 +0100 Subject: [PATCH 35/41] Update autoSyncMergedPullRequest.yml Use the pull_request_target event instead of pull_request since pull_request_target has access to the secrets. --- .github/workflows/autoSyncMergedPullRequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/autoSyncMergedPullRequest.yml b/.github/workflows/autoSyncMergedPullRequest.yml index 518db0bc..a0191ba9 100644 --- a/.github/workflows/autoSyncMergedPullRequest.yml +++ b/.github/workflows/autoSyncMergedPullRequest.yml @@ -1,6 +1,6 @@ name: autoSyncMergedPullRequest on: - pull_request: + pull_request_target: types: - closed branches: [ "main" ] From 52f2471ebca147b1ca62892e09f567dada3b886b Mon Sep 17 00:00:00 2001 From: Octavian FlowiseAI <154992625+ocflowiseai@users.noreply.github.com> Date: Thu, 25 Jan 2024 03:55:35 +0100 Subject: [PATCH 36/41] Update autoSyncSingleCommit.yml - enable multi-line commitMessage --- .github/workflows/autoSyncSingleCommit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/autoSyncSingleCommit.yml b/.github/workflows/autoSyncSingleCommit.yml index 8700f232..d6a40c6a 100644 --- a/.github/workflows/autoSyncSingleCommit.yml +++ b/.github/workflows/autoSyncSingleCommit.yml @@ -32,5 +32,5 @@ jobs: { "ref": "${{ github.ref }}", "sha": "${{ github.sha }}", - "commitMessage": "${{ github.event.commits[0].message }}" + "commitMessage": >- "${{ github.event.commits[0].message }}" } From 1104257720e6ab8771a16479ebfc252ceadb86f6 Mon Sep 17 00:00:00 2001 From: Octavian FlowiseAI <154992625+ocflowiseai@users.noreply.github.com> Date: Thu, 25 Jan 2024 04:01:10 +0100 Subject: [PATCH 37/41] yml linter fix --- .github/workflows/autoSyncSingleCommit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/autoSyncSingleCommit.yml b/.github/workflows/autoSyncSingleCommit.yml index d6a40c6a..8700f232 100644 --- a/.github/workflows/autoSyncSingleCommit.yml +++ b/.github/workflows/autoSyncSingleCommit.yml @@ -32,5 +32,5 @@ jobs: { "ref": "${{ github.ref }}", "sha": "${{ github.sha }}", - "commitMessage": >- "${{ github.event.commits[0].message }}" + "commitMessage": "${{ github.event.commits[0].message }}" } From dc19fde063257a718e91ddbc4bf8d359c6a2bfb8 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 25 Jan 2024 16:21:05 +0000 Subject: [PATCH 38/41] =?UTF-8?q?=F0=9F=A5=B3=20flowise-components@1.5.2?= =?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 0d4cd274..a9d57a10 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "flowise-components", - "version": "1.5.1", + "version": "1.5.2", "description": "Flowiseai Components", "main": "dist/src/index", "types": "dist/src/index.d.ts", From 4ce0ee26001c082bc2da1c953791def770535b5e Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 25 Jan 2024 16:21:41 +0000 Subject: [PATCH 39/41] =?UTF-8?q?=F0=9F=A5=B3=20flowise-ui@1.4.8=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 fef08851..32c20aed 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "flowise-ui", - "version": "1.4.7", + "version": "1.4.8", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://flowiseai.com", "author": { From 1c6694b197ca9d1fd05ed735f2437cdef24101d7 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 25 Jan 2024 16:22:42 +0000 Subject: [PATCH 40/41] =?UTF-8?q?=F0=9F=A5=B3=20flowise@1.4.11=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 561694d0..31440848 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.4.10", + "version": "1.4.11", "private": true, "homepage": "https://flowiseai.com", "workspaces": [ diff --git a/packages/server/package.json b/packages/server/package.json index fe27f8d6..0955448d 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.4.10", + "version": "1.4.11", "description": "Flowiseai Server", "main": "dist/index", "types": "dist/index.d.ts", From 049a35968a643d6da683e1dbdf3a671ffe3b5491 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 25 Jan 2024 18:30:27 +0000 Subject: [PATCH 41/41] remove pinecone env linting issue --- packages/components/nodes/vectorstores/Pinecone/Pinecone.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts index dd0c76f7..a1ec0e57 100644 --- a/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts +++ b/packages/components/nodes/vectorstores/Pinecone/Pinecone.ts @@ -105,7 +105,6 @@ class Pinecone_VectorStores implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData) - const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData) const client = new Pinecone({ apiKey: pineconeApiKey @@ -144,7 +143,6 @@ class Pinecone_VectorStores implements INode { const credentialData = await getCredentialData(nodeData.credential ?? '', options) const pineconeApiKey = getCredentialParam('pineconeApiKey', credentialData, nodeData) - const pineconeEnv = getCredentialParam('pineconeEnv', credentialData, nodeData) const client = new Pinecone({ apiKey: pineconeApiKey