From 75360df34db612d82d66b81c7289887961ff28e7 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 24 May 2023 18:31:30 +0100 Subject: [PATCH 01/24] add milvus --- .../Milvus_Existing/Milvus_Existing.ts | 132 ++++++++++++++++ .../vectorstores/Milvus_Existing/milvus.jpg | Bin 0 -> 9320 bytes .../Milvus_Upsert/Milvus_Upsert.ts | 148 ++++++++++++++++++ .../vectorstores/Milvus_Upsert/milvus.jpg | Bin 0 -> 9320 bytes packages/components/package.json | 1 + 5 files changed, 281 insertions(+) create mode 100644 packages/components/nodes/vectorstores/Milvus_Existing/Milvus_Existing.ts create mode 100644 packages/components/nodes/vectorstores/Milvus_Existing/milvus.jpg create mode 100644 packages/components/nodes/vectorstores/Milvus_Upsert/Milvus_Upsert.ts create mode 100644 packages/components/nodes/vectorstores/Milvus_Upsert/milvus.jpg diff --git a/packages/components/nodes/vectorstores/Milvus_Existing/Milvus_Existing.ts b/packages/components/nodes/vectorstores/Milvus_Existing/Milvus_Existing.ts new file mode 100644 index 00000000..ebfd566c --- /dev/null +++ b/packages/components/nodes/vectorstores/Milvus_Existing/Milvus_Existing.ts @@ -0,0 +1,132 @@ +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { Milvus, MilvusLibArgs } from 'langchain/vectorstores/milvus' +import { Embeddings } from 'langchain/embeddings/base' +import { getBaseClasses } from '../../../src/utils' + +class Milvus_Existing_VectorStores implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Milvus Load Existing Index' + this.name = 'milvusExistingIndex' + this.type = 'Milvus' + this.icon = 'milvus.jpg' + this.category = 'Vector Stores' + this.description = 'Load existing index from Milvus (i.e: Document has been upserted)' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.inputs = [ + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Collection Name', + name: 'milvusCollectionName', + type: 'string', + placeholder: 'my-milvus-collection' + }, + { + label: 'Milvus URL', + name: 'milvusURL', + type: 'string', + placeholder: 'http://localhost:19530' + }, + { + label: 'Primary Field', + name: 'milvusPrimaryField', + type: 'string', + optional: true, + additionalParams: true + }, + { + label: 'Vector Field', + name: 'milvusVectorField', + type: 'string', + optional: true, + additionalParams: true + }, + { + label: 'Vector Text Field', + name: 'milvusTextField', + type: 'string', + optional: true, + additionalParams: true + }, + { + label: 'SSL', + name: 'milvusSSL', + type: 'boolean', + optional: true, + additionalParams: true + }, + { + label: 'Username', + name: 'milvusUsername', + type: 'string', + optional: true, + additionalParams: true + }, + { + label: 'Password', + name: 'milvusPassword', + type: 'password', + optional: true, + additionalParams: true + } + ] + this.outputs = [ + { + label: 'Milvus Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Milvus Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(Milvus)] + } + ] + } + + async init(nodeData: INodeData): Promise { + const collectionName = nodeData.inputs?.milvusCollectionName as string + const embeddings = nodeData.inputs?.embeddings as Embeddings + const milvusURL = nodeData.inputs?.milvusURL as string + const milvusPrimaryField = nodeData.inputs?.milvusPrimaryField as string + const milvusVectorField = nodeData.inputs?.milvusVectorField as string + const milvusTextField = nodeData.inputs?.milvusTextField as string + const milvusSSL = nodeData.inputs?.milvusSSL as boolean + const milvusUsername = nodeData.inputs?.milvusUsername as string + const milvusPassword = nodeData.inputs?.milvusPassword as string + const output = nodeData.outputs?.output as string + + const obj: MilvusLibArgs = { collectionName, url: milvusURL } + if (milvusPrimaryField) obj.primaryField = milvusPrimaryField + if (milvusVectorField) obj.vectorField = milvusVectorField + if (milvusTextField) obj.textField = milvusTextField + if (milvusSSL) obj.ssl = milvusSSL + if (milvusUsername) obj.username = milvusUsername + if (milvusPassword) obj.password = milvusPassword + + const vectorStore = await Milvus.fromExistingCollection(embeddings, obj) + + if (output === 'retriever') { + const retriever = vectorStore.asRetriever() + return retriever + } else if (output === 'vectorStore') { + return vectorStore + } + return vectorStore + } +} + +module.exports = { nodeClass: Milvus_Existing_VectorStores } diff --git a/packages/components/nodes/vectorstores/Milvus_Existing/milvus.jpg b/packages/components/nodes/vectorstores/Milvus_Existing/milvus.jpg new file mode 100644 index 0000000000000000000000000000000000000000..20b6c3499cbcf1e451afa25cfc60887e38ab49a8 GIT binary patch literal 9320 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 MV<_L`Jz!`ChE9Cxxxqn>pp7! zzD3u&z~sL9x+2qs5{=I7n}m)W)c_3A0e8G5<%RHn!j|kIQCq>MB=0UI9!y{MxpC;Z z%2|wfu6g5#h+@Ega4nWd2B{J`@+X}Q@y`$q;2lQ;EKFWfM8hb1P=YROJ$-YETR4Np z;I>@Ru$0qopabsa!OvbSKcg=m(Ew9GOD+bd7oK*^932-BW4}5&#OnI>#j50r-cSce zH6%$oNSXk&&PE!OR(m)}j+8agz+wbKMFT`F6dfr>mLy~u@hqx_)_N=5Ia&p%@1XYb zCrBc*Ss!B)TYE$?%7>2m$YA2zio|WSg#!%pUSN0KA=e7k$Wy*Pe`Blaf}tK1KhsBg z7)Iane)*Kz(GG#B%p#pp@o0Q$Zd9qXN`S6w+v z9Ywzu=j_+1;9ue3_wxK#DhPgMy6aT1lN(tzx-YH$uS^j9%+V%>#>r1DBLZx+^3azK zEGLCJ95tT4<#(v3=vVB1-XV#o9H%?qQ6R2VRC-0+zLaF5s~;>f;iNd0b240@hP{7r z@I615ect^0No6AJ!%$6J+3m=gB4!n5yzDP0Q>BJ#u16z^1A6b zGSiN7=slkjos-x`RA&lb0d8Fh+5p{HO+WZ#HFRBOU*H#K6}1SzMDJX0{zjnB z7Zu@$Sj2$><@EwxTOoT|T@ecVMOBR1ql$2D9m{A8Ci@zzS~pTdv{)Mc@Odb~xGRlU z)S&1?&s?H2&)x`EAEC;>wRuPW()Nf71=1kKD_jwhVPa8S)T4*?T)+8wSmvHxcYzSi z6zLv%x9rV&1%?Qp*bB4?(H@GlEC=hv2C4OxZD4hZru&eM^;vn@%P&3Db0o-BWFhluE0_7qe z-16_aJY|Zs-NKf^B8E5q7)c+Q^9r8}YdJVr@Nsy22aaiiRnlr%#s)7Pso@VdKD=2) zT?f9Aqj5)#uz6>RrRRb|gt-hT)NX5`k(%2N&OaJn;v!(FcLVU>fj(4S5%8GIA8X`r zgp3RWT0MJj75;8{KD51Xo?F_!N=y%+V{oXfWW}?VGx?fo>@k%hGy9}p75BwTqK=M^ z3VMUmGh%rwZbYX}O(o(|gWNR6@Wh;_WP$@`gZx39q+n<;>`oLbV=DR8hzbhKtCWyA zWbB^BbZIx`e2Xq1uH2sQp}HopLB`1LOnJ)lqP|^ zB;^d{fsW5HHzmS0e^L#rWQ7=~j;~#~u(Ef)EOPRmNmR)|Mz-igyse$U>8BrC;D`h) zcEx$i%O8=}LOS12_pOX*6Obu!bqwJuAP%+3u8plAl8zIO544VZ>mg39H1dobYJqU* z$`y8Il7^ZLRP0R1-6*Tg9UiX>!p)UWucBHaOiTIh__lOp@pKtm8y&jjOPeSoEpJ8D zfX017QnG?H_awY&X5B}bVBsjjUuTaS3sd07IL#a zdBR2NCv8lC%1`)4*;oXth`Ur#d?hT@T`aagCx?MM#_X}VZ_g{OQtH>N@f_@}0v(@d z2VS$Ll&mGB{g`;i-6gjtEsbhNsm`WQfomzwrd1kNy50bI60e;+ynp$jGKZ&k?T>*N z3{UME(*@{rHHw6%c2`Zb3D|Ujbw%uicg8D68sPzXPsdH+$zdX*ZnjPrVl+U(#nBMH&7*si;Tuh}2+k@yOl7h{=2 zf$7xKn>TcWnN%~>7Es#Kyz&#GB6ecy=%h^u*Uph5A0maI;IAY$bRmyj+4WZYvhYU( z(t+s4ulL&c&)!_#7T6&Zc5XOKD2da6EtRENo1iGr@mCbjH#HT}N; Dh=sww literal 0 HcmV?d00001 diff --git a/packages/components/nodes/vectorstores/Milvus_Upsert/Milvus_Upsert.ts b/packages/components/nodes/vectorstores/Milvus_Upsert/Milvus_Upsert.ts new file mode 100644 index 00000000..373327b5 --- /dev/null +++ b/packages/components/nodes/vectorstores/Milvus_Upsert/Milvus_Upsert.ts @@ -0,0 +1,148 @@ +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { Milvus, MilvusLibArgs } from 'langchain/vectorstores/milvus' +import { Embeddings } from 'langchain/embeddings/base' +import { getBaseClasses } from '../../../src/utils' +import { Document } from 'langchain/document' + +class Milvus_Upsert_VectorStores implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Milvus Upsert Document' + this.name = 'milvusUpsert' + this.type = 'Milvus' + this.icon = 'milvus.jpg' + this.category = 'Vector Stores' + this.description = 'Upsert documents to Milvus' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.inputs = [ + { + label: 'Document', + name: 'document', + type: 'Document', + list: true + }, + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Collection Name', + name: 'milvusCollectionName', + type: 'string', + placeholder: 'my_milvus_collection' + }, + { + label: 'Milvus URL', + name: 'milvusURL', + type: 'string', + placeholder: 'http://localhost:19530' + }, + { + label: 'Primary Field', + name: 'milvusPrimaryField', + type: 'string', + optional: true, + additionalParams: true + }, + { + label: 'Vector Field', + name: 'milvusVectorField', + type: 'string', + optional: true, + additionalParams: true + }, + { + label: 'Vector Text Field', + name: 'milvusTextField', + type: 'string', + optional: true, + additionalParams: true + }, + { + label: 'SSL', + name: 'milvusSSL', + type: 'boolean', + optional: true, + additionalParams: true + }, + { + label: 'Username', + name: 'milvusUsername', + type: 'string', + placeholder: 'db_admin', + optional: true, + additionalParams: true + }, + { + label: 'Password', + name: 'milvusPassword', + type: 'password', + optional: true, + additionalParams: true + } + ] + this.outputs = [ + { + label: 'Milvus Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Milvus Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(Milvus)] + } + ] + } + + async init(nodeData: INodeData): Promise { + const collectionName = nodeData.inputs?.milvusCollectionName as string + const embeddings = nodeData.inputs?.embeddings as Embeddings + const milvusURL = nodeData.inputs?.milvusURL as string + const milvusPrimaryField = nodeData.inputs?.milvusPrimaryField as string + const milvusVectorField = nodeData.inputs?.milvusVectorField as string + const milvusTextField = nodeData.inputs?.milvusTextField as string + const milvusSSL = nodeData.inputs?.milvusSSL as boolean + const milvusUsername = nodeData.inputs?.milvusUsername as string + const milvusPassword = nodeData.inputs?.milvusPassword as string + const output = nodeData.outputs?.output as string + const docs = nodeData.inputs?.document as Document[] + + const flattenDocs = docs && docs.length ? docs.flat() : [] + const finalDocs = [] + for (let i = 0; i < flattenDocs.length; i += 1) { + finalDocs.push(new Document(flattenDocs[i])) + } + + const obj: MilvusLibArgs = { collectionName, url: milvusURL } + if (milvusPrimaryField) obj.primaryField = milvusPrimaryField + if (milvusVectorField) obj.vectorField = milvusVectorField + if (milvusTextField) obj.textField = milvusTextField + if (milvusSSL) obj.ssl = milvusSSL + if (milvusUsername) obj.username = milvusUsername + if (milvusPassword) obj.password = milvusPassword + + const vectorStore = await Milvus.fromDocuments(finalDocs, embeddings, obj) + console.log('vectorStore = ', vectorStore) + + if (output === 'retriever') { + const retriever = vectorStore.asRetriever() + return retriever + } else if (output === 'vectorStore') { + return vectorStore + } + return vectorStore + } +} + +module.exports = { nodeClass: Milvus_Upsert_VectorStores } diff --git a/packages/components/nodes/vectorstores/Milvus_Upsert/milvus.jpg b/packages/components/nodes/vectorstores/Milvus_Upsert/milvus.jpg new file mode 100644 index 0000000000000000000000000000000000000000..20b6c3499cbcf1e451afa25cfc60887e38ab49a8 GIT binary patch literal 9320 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 MV<_L`Jz!`ChE9Cxxxqn>pp7! zzD3u&z~sL9x+2qs5{=I7n}m)W)c_3A0e8G5<%RHn!j|kIQCq>MB=0UI9!y{MxpC;Z z%2|wfu6g5#h+@Ega4nWd2B{J`@+X}Q@y`$q;2lQ;EKFWfM8hb1P=YROJ$-YETR4Np z;I>@Ru$0qopabsa!OvbSKcg=m(Ew9GOD+bd7oK*^932-BW4}5&#OnI>#j50r-cSce zH6%$oNSXk&&PE!OR(m)}j+8agz+wbKMFT`F6dfr>mLy~u@hqx_)_N=5Ia&p%@1XYb zCrBc*Ss!B)TYE$?%7>2m$YA2zio|WSg#!%pUSN0KA=e7k$Wy*Pe`Blaf}tK1KhsBg z7)Iane)*Kz(GG#B%p#pp@o0Q$Zd9qXN`S6w+v z9Ywzu=j_+1;9ue3_wxK#DhPgMy6aT1lN(tzx-YH$uS^j9%+V%>#>r1DBLZx+^3azK zEGLCJ95tT4<#(v3=vVB1-XV#o9H%?qQ6R2VRC-0+zLaF5s~;>f;iNd0b240@hP{7r z@I615ect^0No6AJ!%$6J+3m=gB4!n5yzDP0Q>BJ#u16z^1A6b zGSiN7=slkjos-x`RA&lb0d8Fh+5p{HO+WZ#HFRBOU*H#K6}1SzMDJX0{zjnB z7Zu@$Sj2$><@EwxTOoT|T@ecVMOBR1ql$2D9m{A8Ci@zzS~pTdv{)Mc@Odb~xGRlU z)S&1?&s?H2&)x`EAEC;>wRuPW()Nf71=1kKD_jwhVPa8S)T4*?T)+8wSmvHxcYzSi z6zLv%x9rV&1%?Qp*bB4?(H@GlEC=hv2C4OxZD4hZru&eM^;vn@%P&3Db0o-BWFhluE0_7qe z-16_aJY|Zs-NKf^B8E5q7)c+Q^9r8}YdJVr@Nsy22aaiiRnlr%#s)7Pso@VdKD=2) zT?f9Aqj5)#uz6>RrRRb|gt-hT)NX5`k(%2N&OaJn;v!(FcLVU>fj(4S5%8GIA8X`r zgp3RWT0MJj75;8{KD51Xo?F_!N=y%+V{oXfWW}?VGx?fo>@k%hGy9}p75BwTqK=M^ z3VMUmGh%rwZbYX}O(o(|gWNR6@Wh;_WP$@`gZx39q+n<;>`oLbV=DR8hzbhKtCWyA zWbB^BbZIx`e2Xq1uH2sQp}HopLB`1LOnJ)lqP|^ zB;^d{fsW5HHzmS0e^L#rWQ7=~j;~#~u(Ef)EOPRmNmR)|Mz-igyse$U>8BrC;D`h) zcEx$i%O8=}LOS12_pOX*6Obu!bqwJuAP%+3u8plAl8zIO544VZ>mg39H1dobYJqU* z$`y8Il7^ZLRP0R1-6*Tg9UiX>!p)UWucBHaOiTIh__lOp@pKtm8y&jjOPeSoEpJ8D zfX017QnG?H_awY&X5B}bVBsjjUuTaS3sd07IL#a zdBR2NCv8lC%1`)4*;oXth`Ur#d?hT@T`aagCx?MM#_X}VZ_g{OQtH>N@f_@}0v(@d z2VS$Ll&mGB{g`;i-6gjtEsbhNsm`WQfomzwrd1kNy50bI60e;+ynp$jGKZ&k?T>*N z3{UME(*@{rHHw6%c2`Zb3D|Ujbw%uicg8D68sPzXPsdH+$zdX*ZnjPrVl+U(#nBMH&7*si;Tuh}2+k@yOl7h{=2 zf$7xKn>TcWnN%~>7Es#Kyz&#GB6ecy=%h^u*Uph5A0maI;IAY$bRmyj+4WZYvhYU( z(t+s4ulL&c&)!_#7T6&Zc5XOKD2da6EtRENo1iGr@mCbjH#HT}N; Dh=sww literal 0 HcmV?d00001 diff --git a/packages/components/package.json b/packages/components/package.json index 9c77db8e..bbce5cb9 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -20,6 +20,7 @@ "@huggingface/inference": "1", "@pinecone-database/pinecone": "^0.0.12", "@supabase/supabase-js": "^2.21.0", + "@zilliz/milvus2-sdk-node": "^2.2.10", "axios": "^0.27.2", "cheerio": "^1.0.0-rc.12", "chromadb": "^1.3.1", From f80547af60f9d5a54b2e916b83888abf4e016004 Mon Sep 17 00:00:00 2001 From: Seif Date: Tue, 15 Aug 2023 11:45:31 -0700 Subject: [PATCH 02/24] Add sentence config to Flowise --- .../Vectara_Existing/Vectara_Existing.ts | 23 ++++++++++++++++++- .../Vectara_Upsert/Vectara_Upsert.ts | 23 ++++++++++++++++++- packages/components/package.json | 2 +- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/components/nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts b/packages/components/nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts index f344338a..80fd0639 100644 --- a/packages/components/nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts +++ b/packages/components/nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts @@ -1,6 +1,6 @@ import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' -import { VectaraStore, VectaraLibArgs, VectaraFilter } from 'langchain/vectorstores/vectara' +import { VectaraStore, VectaraLibArgs, VectaraFilter, VectaraContextConfig } from 'langchain/vectorstores/vectara' class VectaraExisting_VectorStores implements INode { label: string @@ -40,6 +40,20 @@ class VectaraExisting_VectorStores implements INode { additionalParams: true, optional: true }, + { + label: 'Sentences Before', + name: 'sentencesBefore', + type: 'number', + additionalParams: true, + optional: true + }, + { + label: 'Sentences After', + name: 'sentencesAfter', + type: 'number', + additionalParams: true, + optional: true + }, { label: 'Lambda', name: 'lambda', @@ -77,6 +91,8 @@ class VectaraExisting_VectorStores implements INode { const corpusId = getCredentialParam('corpusID', credentialData, nodeData) const vectaraMetadataFilter = nodeData.inputs?.filter as string + const sentencesBefore = nodeData.inputs?.sentencesBefore as number + const sentencesAfter = nodeData.inputs?.sentencesAfter as number const lambda = nodeData.inputs?.lambda as number const output = nodeData.outputs?.output as string const topK = nodeData.inputs?.topK as string @@ -92,6 +108,11 @@ class VectaraExisting_VectorStores implements INode { if (vectaraMetadataFilter) vectaraFilter.filter = vectaraMetadataFilter if (lambda) vectaraFilter.lambda = lambda + const vectaraContextConfig: VectaraContextConfig = {} + if (sentencesBefore) vectaraContextConfig.sentencesBefore = sentencesBefore + if (sentencesAfter) vectaraContextConfig.sentencesAfter = sentencesAfter + vectaraFilter.contextConfig = vectaraContextConfig + const vectorStore = new VectaraStore(vectaraArgs) if (output === 'retriever') { diff --git a/packages/components/nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts b/packages/components/nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts index b2ee79e7..cda03240 100644 --- a/packages/components/nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts +++ b/packages/components/nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts @@ -1,7 +1,7 @@ import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { Embeddings } from 'langchain/embeddings/base' import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' -import { VectaraStore, VectaraLibArgs, VectaraFilter } from 'langchain/vectorstores/vectara' +import { VectaraStore, VectaraLibArgs, VectaraFilter, VectaraContextConfig } from 'langchain/vectorstores/vectara' import { Document } from 'langchain/document' import { flatten } from 'lodash' @@ -49,6 +49,20 @@ class VectaraUpsert_VectorStores implements INode { additionalParams: true, optional: true }, + { + label: 'Sentences Before', + name: 'sentencesBefore', + type: 'number', + additionalParams: true, + optional: true + }, + { + label: 'Sentences After', + name: 'sentencesAfter', + type: 'number', + additionalParams: true, + optional: true + }, { label: 'Lambda', name: 'lambda', @@ -88,6 +102,8 @@ class VectaraUpsert_VectorStores implements INode { const docs = nodeData.inputs?.document as Document[] const embeddings = {} as Embeddings const vectaraMetadataFilter = nodeData.inputs?.filter as string + const sentencesBefore = nodeData.inputs?.sentencesBefore as number + const sentencesAfter = nodeData.inputs?.sentencesAfter as number const lambda = nodeData.inputs?.lambda as number const output = nodeData.outputs?.output as string const topK = nodeData.inputs?.topK as string @@ -103,6 +119,11 @@ class VectaraUpsert_VectorStores implements INode { if (vectaraMetadataFilter) vectaraFilter.filter = vectaraMetadataFilter if (lambda) vectaraFilter.lambda = lambda + const vectaraContextConfig: VectaraContextConfig = {} + if (sentencesBefore) vectaraContextConfig.sentencesBefore = sentencesBefore + if (sentencesAfter) vectaraContextConfig.sentencesAfter = sentencesAfter + vectaraFilter.contextConfig = vectaraContextConfig + const flattenDocs = docs && docs.length ? flatten(docs) : [] const finalDocs = [] for (let i = 0; i < flattenDocs.length; i += 1) { diff --git a/packages/components/package.json b/packages/components/package.json index bad9fb74..da4d0971 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -40,7 +40,7 @@ "google-auth-library": "^9.0.0", "graphql": "^16.6.0", "html-to-text": "^9.0.5", - "langchain": "^0.0.122", + "langchain": "^0.0.126", "linkifyjs": "^4.1.1", "mammoth": "^1.5.1", "moment": "^2.29.3", From 2e8bbaeab1fb1e8bedab6afe77272eac126a1d94 Mon Sep 17 00:00:00 2001 From: Seif Date: Tue, 15 Aug 2023 11:50:37 -0700 Subject: [PATCH 03/24] Add descriptions --- .../nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts | 4 ++++ .../nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/components/nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts b/packages/components/nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts index 80fd0639..3ef04f07 100644 --- a/packages/components/nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts +++ b/packages/components/nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts @@ -43,6 +43,7 @@ class VectaraExisting_VectorStores implements INode { { label: 'Sentences Before', name: 'sentencesBefore', + description: 'Number of sentences to fetch before the matched sentence. Defaults to 2.', type: 'number', additionalParams: true, optional: true @@ -50,6 +51,7 @@ class VectaraExisting_VectorStores implements INode { { label: 'Sentences After', name: 'sentencesAfter', + description: 'Number of sentences to fetch after the matched sentence. Defaults to 2.', type: 'number', additionalParams: true, optional: true @@ -57,6 +59,8 @@ class VectaraExisting_VectorStores implements INode { { 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 diff --git a/packages/components/nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts b/packages/components/nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts index cda03240..51fb67ed 100644 --- a/packages/components/nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts +++ b/packages/components/nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts @@ -52,6 +52,7 @@ class VectaraUpsert_VectorStores implements INode { { label: 'Sentences Before', name: 'sentencesBefore', + description: 'Number of sentences to fetch before the matched sentence. Defaults to 2.', type: 'number', additionalParams: true, optional: true @@ -59,6 +60,7 @@ class VectaraUpsert_VectorStores implements INode { { label: 'Sentences After', name: 'sentencesAfter', + description: 'Number of sentences to fetch after the matched sentence. Defaults to 2.', type: 'number', additionalParams: true, optional: true @@ -66,6 +68,8 @@ class VectaraUpsert_VectorStores implements INode { { 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 From 94461025dc82ceae746f4f91aaad1608f84907d1 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 16 Aug 2023 01:43:11 +0100 Subject: [PATCH 04/24] add vector to prompt --- .../ConversationChain/ConversationChain.ts | 3 +- .../VectorStoreToDocument.ts | 87 ++ .../VectorStoreToDocument/vectorretriever.svg | 7 + packages/components/src/utils.ts | 19 + .../Prompt Chaining with VectorStore.json | 966 ++++++++++++++++++ .../chatflows/Vectara LLM Chain Upload.json | 34 +- packages/server/src/index.ts | 24 +- packages/server/src/utils/index.ts | 42 +- packages/ui/src/assets/images/chathistory.png | Bin 0 -> 12068 bytes .../src/ui-component/dialog/NodeInfoDialog.js | 2 +- .../src/ui-component/json/SelectVariable.js | 50 +- 11 files changed, 1194 insertions(+), 40 deletions(-) create mode 100644 packages/components/nodes/documentloaders/VectorStoreToDocument/VectorStoreToDocument.ts create mode 100644 packages/components/nodes/documentloaders/VectorStoreToDocument/vectorretriever.svg create mode 100644 packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json create mode 100644 packages/ui/src/assets/images/chathistory.png diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index cd42a670..08663395 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -45,7 +45,8 @@ class ConversationChain_Chains implements INode { label: 'Document', name: 'document', type: 'Document', - description: 'Include whole document into the context window', + description: + 'Include whole document into the context window, if you get maximum context length error, please use model with higher context window like Claude 100k, or gpt4 32k', optional: true, list: true }, diff --git a/packages/components/nodes/documentloaders/VectorStoreToDocument/VectorStoreToDocument.ts b/packages/components/nodes/documentloaders/VectorStoreToDocument/VectorStoreToDocument.ts new file mode 100644 index 00000000..b3f320ce --- /dev/null +++ b/packages/components/nodes/documentloaders/VectorStoreToDocument/VectorStoreToDocument.ts @@ -0,0 +1,87 @@ +import { VectorStore } from 'langchain/vectorstores/base' +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { handleEscapeCharacters } from '../../../src/utils' + +class VectorStoreToDocument_DocumentLoaders implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'VectorStore To Document' + this.name = 'vectorStoreToDocument' + this.version = 1.0 + this.type = 'Document' + this.icon = 'vectorretriever.svg' + this.category = 'Document Loaders' + this.description = 'Search documents with scores from vector store' + this.baseClasses = [this.type] + this.inputs = [ + { + label: 'Vector Store', + name: 'vectorStore', + type: 'VectorStore' + }, + { + label: 'Minimum Score (%)', + name: 'minScore', + type: 'number', + optional: true, + placeholder: '75', + step: 1, + description: 'Minumum score for embeddings documents to be included' + } + ] + this.outputs = [ + { + label: 'Document', + name: 'document', + baseClasses: this.baseClasses + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] + } + + async init(nodeData: INodeData, input: string): Promise { + const vectorStore = nodeData.inputs?.vectorStore as VectorStore + const minScore = nodeData.inputs?.minScore as number + const output = nodeData.outputs?.output as string + + const topK = (vectorStore as any)?.k ?? 4 + + const docs = await vectorStore.similaritySearchWithScore(input, topK) + // eslint-disable-next-line no-console + console.log('\x1b[94m\x1b[1m\n*****VectorStore Documents*****\n\x1b[0m\x1b[0m') + // eslint-disable-next-line no-console + console.log(docs) + + if (output === 'document') { + let finaldocs = [] + for (const doc of docs) { + if (minScore && doc[1] < minScore / 100) continue + finaldocs.push(doc[0]) + } + return finaldocs + } else { + let finaltext = '' + for (const doc of docs) { + if (minScore && doc[1] < minScore / 100) continue + finaltext += `${doc[0].pageContent}\n` + } + return handleEscapeCharacters(finaltext, false) + } + } +} + +module.exports = { nodeClass: VectorStoreToDocument_DocumentLoaders } diff --git a/packages/components/nodes/documentloaders/VectorStoreToDocument/vectorretriever.svg b/packages/components/nodes/documentloaders/VectorStoreToDocument/vectorretriever.svg new file mode 100644 index 00000000..208a59f1 --- /dev/null +++ b/packages/components/nodes/documentloaders/VectorStoreToDocument/vectorretriever.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/components/src/utils.ts b/packages/components/src/utils.ts index bcca834a..8d06a650 100644 --- a/packages/components/src/utils.ts +++ b/packages/components/src/utils.ts @@ -520,3 +520,22 @@ export const mapChatHistory = (options: ICommonObject): ChatMessageHistory => { } return new ChatMessageHistory(chatHistory) } + +/** + * Convert incoming chat history to string + * @param {IMessage[]} chatHistory + * @returns {string} + */ +export const convertChatHistoryToText = (chatHistory: IMessage[]): string => { + return chatHistory + .map((chatMessage) => { + if (chatMessage.type === 'apiMessage') { + return `Assistant: ${chatMessage.message}` + } else if (chatMessage.type === 'userMessage') { + return `Human: ${chatMessage.message}` + } else { + return `${chatMessage.message}` + } + }) + .join('\n') +} diff --git a/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json new file mode 100644 index 00000000..9d6838eb --- /dev/null +++ b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json @@ -0,0 +1,966 @@ +{ + "description": "Use chat history to rephrase user question, and answer the rephrased question using retrieved docs from vector store", + "nodes": [ + { + "width": 300, + "height": 503, + "id": "pineconeExistingIndex_0", + "position": { + "x": 1062.7418678410986, + "y": -109.27680365777141 + }, + "type": "customNode", + "data": { + "id": "pineconeExistingIndex_0", + "label": "Pinecone Load Existing Index", + "version": 1, + "name": "pineconeExistingIndex", + "type": "Pinecone", + "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], + "category": "Vector Stores", + "description": "Load existing index from Pinecone (i.e: Document has been upserted)", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["pineconeApi"], + "id": "pineconeExistingIndex_0-input-credential-credential" + }, + { + "label": "Pinecone Index", + "name": "pineconeIndex", + "type": "string", + "id": "pineconeExistingIndex_0-input-pineconeIndex-string" + }, + { + "label": "Pinecone Namespace", + "name": "pineconeNamespace", + "type": "string", + "placeholder": "my-first-namespace", + "additionalParams": true, + "optional": true, + "id": "pineconeExistingIndex_0-input-pineconeNamespace-string" + }, + { + "label": "Pinecone Metadata Filter", + "name": "pineconeMetadataFilter", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "pineconeExistingIndex_0-input-pineconeMetadataFilter-json" + }, + { + "label": "Top K", + "name": "topK", + "description": "Number of top results to fetch. Default to 4", + "placeholder": "4", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pineconeExistingIndex_0-input-topK-number" + } + ], + "inputAnchors": [ + { + "label": "Embeddings", + "name": "embeddings", + "type": "Embeddings", + "id": "pineconeExistingIndex_0-input-embeddings-Embeddings" + } + ], + "inputs": { + "embeddings": "{{openAIEmbeddings_0.data.instance}}", + "pineconeIndex": "newindex", + "pineconeNamespace": "", + "pineconeMetadataFilter": "{}", + "topK": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "pineconeExistingIndex_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever", + "name": "retriever", + "label": "Pinecone Retriever", + "type": "Pinecone | VectorStoreRetriever | BaseRetriever" + }, + { + "id": "pineconeExistingIndex_0-output-vectorStore-Pinecone|VectorStore", + "name": "vectorStore", + "label": "Pinecone Vector Store", + "type": "Pinecone | VectorStore" + } + ], + "default": "retriever" + } + ], + "outputs": { + "output": "vectorStore" + }, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 1062.7418678410986, + "y": -109.27680365777141 + }, + "dragging": false + }, + { + "width": 300, + "height": 327, + "id": "openAIEmbeddings_0", + "position": { + "x": 711.3971966563331, + "y": 7.7184225021727 + }, + "type": "customNode", + "data": { + "id": "openAIEmbeddings_0", + "label": "OpenAI Embeddings", + "version": 1, + "name": "openAIEmbeddings", + "type": "OpenAIEmbeddings", + "baseClasses": ["OpenAIEmbeddings", "Embeddings"], + "category": "Embeddings", + "description": "OpenAI API to generate embeddings for a given text", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "openAIEmbeddings_0-input-credential-credential" + }, + { + "label": "Strip New Lines", + "name": "stripNewLines", + "type": "boolean", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-stripNewLines-boolean" + }, + { + "label": "Batch Size", + "name": "batchSize", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-batchSize-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-basepath-string" + } + ], + "inputAnchors": [], + "inputs": { + "stripNewLines": "", + "batchSize": "", + "timeout": "", + "basepath": "" + }, + "outputAnchors": [ + { + "id": "openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings", + "name": "openAIEmbeddings", + "label": "OpenAIEmbeddings", + "type": "OpenAIEmbeddings | Embeddings" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 711.3971966563331, + "y": 7.7184225021727 + }, + "dragging": false + }, + { + "width": 300, + "height": 473, + "id": "promptTemplate_0", + "position": { + "x": 348.2881107399286, + "y": -97.74510214137423 + }, + "type": "customNode", + "data": { + "id": "promptTemplate_0", + "label": "Prompt Template", + "version": 1, + "name": "promptTemplate", + "type": "PromptTemplate", + "baseClasses": ["PromptTemplate", "BaseStringPromptTemplate", "BasePromptTemplate", "Runnable"], + "category": "Prompts", + "description": "Schema to represent a basic prompt for an LLM", + "inputParams": [ + { + "label": "Template", + "name": "template", + "type": "string", + "rows": 4, + "placeholder": "What is a good name for a company that makes {product}?", + "id": "promptTemplate_0-input-template-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "promptTemplate_0-input-promptValues-json" + } + ], + "inputAnchors": [], + "inputs": { + "template": "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:", + "promptValues": "{\"question\":\"{{question}}\",\"chat_history\":\"{{chat_history}}\"}" + }, + "outputAnchors": [ + { + "id": "promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "name": "promptTemplate", + "label": "PromptTemplate", + "type": "PromptTemplate | BaseStringPromptTemplate | BasePromptTemplate | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 348.2881107399286, + "y": -97.74510214137423 + }, + "dragging": false + }, + { + "width": 300, + "height": 522, + "id": "chatOpenAI_0", + "position": { + "x": 335.7621848973805, + "y": -651.7411273245009 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "version": 1, + "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" + } + ], + "inputAnchors": [], + "inputs": { + "modelName": "gpt-3.5-turbo-16k", + "temperature": 0.9, + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "dragging": false, + "positionAbsolute": { + "x": 335.7621848973805, + "y": -651.7411273245009 + } + }, + { + "width": 300, + "height": 522, + "id": "chatOpenAI_1", + "position": { + "x": 1765.2801848172305, + "y": -667.9261054149061 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_1", + "label": "ChatOpenAI", + "version": 1, + "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_1-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_1-input-modelName-options" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_1-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-basepath-string" + } + ], + "inputAnchors": [], + "inputs": { + "modelName": "gpt-3.5-turbo-16k", + "temperature": 0.9, + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "dragging": false, + "positionAbsolute": { + "x": 1765.2801848172305, + "y": -667.9261054149061 + } + }, + { + "width": 300, + "height": 473, + "id": "promptTemplate_1", + "position": { + "x": 1773.720934090435, + "y": -116.71323227575395 + }, + "type": "customNode", + "data": { + "id": "promptTemplate_1", + "label": "Prompt Template", + "version": 1, + "name": "promptTemplate", + "type": "PromptTemplate", + "baseClasses": ["PromptTemplate", "BaseStringPromptTemplate", "BasePromptTemplate", "Runnable"], + "category": "Prompts", + "description": "Schema to represent a basic prompt for an LLM", + "inputParams": [ + { + "label": "Template", + "name": "template", + "type": "string", + "rows": 4, + "placeholder": "What is a good name for a company that makes {product}?", + "id": "promptTemplate_1-input-template-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "promptTemplate_1-input-promptValues-json" + } + ], + "inputAnchors": [], + "inputs": { + "template": "Use the following pieces of context to answer the question at the end.\n\n{context}\n\nQuestion: {question}\nHelpful Answer:", + "promptValues": "{\"context\":\"{{vectorStoreToDocument_0.data.instance}}\",\"question\":\"{{llmChain_0.data.instance}}\"}" + }, + "outputAnchors": [ + { + "id": "promptTemplate_1-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "name": "promptTemplate", + "label": "PromptTemplate", + "type": "PromptTemplate | BaseStringPromptTemplate | BasePromptTemplate | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 1773.720934090435, + "y": -116.71323227575395 + }, + "dragging": false + }, + { + "width": 300, + "height": 404, + "id": "llmChain_0", + "position": { + "x": 756.1670091985342, + "y": -592.5151355056942 + }, + "type": "customNode", + "data": { + "id": "llmChain_0", + "label": "LLM Chain", + "version": 1, + "name": "llmChain", + "type": "LLMChain", + "baseClasses": ["LLMChain", "BaseChain", "Runnable"], + "category": "Chains", + "description": "Chain to run queries against LLMs", + "inputParams": [ + { + "label": "Chain Name", + "name": "chainName", + "type": "string", + "placeholder": "Name Your Chain", + "optional": true, + "id": "llmChain_0-input-chainName-string" + } + ], + "inputAnchors": [ + { + "label": "Language Model", + "name": "model", + "type": "BaseLanguageModel", + "id": "llmChain_0-input-model-BaseLanguageModel" + }, + { + "label": "Prompt", + "name": "prompt", + "type": "BasePromptTemplate", + "id": "llmChain_0-input-prompt-BasePromptTemplate" + } + ], + "inputs": { + "model": "{{chatOpenAI_0.data.instance}}", + "prompt": "{{promptTemplate_0.data.instance}}", + "chainName": "QuestionChain" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "llmChain_0-output-llmChain-LLMChain|BaseChain|Runnable", + "name": "llmChain", + "label": "LLM Chain", + "type": "LLMChain | BaseChain | Runnable" + }, + { + "id": "llmChain_0-output-outputPrediction-string|json", + "name": "outputPrediction", + "label": "Output Prediction", + "type": "string | json" + } + ], + "default": "llmChain" + } + ], + "outputs": { + "output": "outputPrediction" + }, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 756.1670091985342, + "y": -592.5151355056942 + }, + "dragging": false + }, + { + "width": 300, + "height": 404, + "id": "llmChain_1", + "position": { + "x": 2200.1274896215496, + "y": -144.29167974642334 + }, + "type": "customNode", + "data": { + "id": "llmChain_1", + "label": "LLM Chain", + "version": 1, + "name": "llmChain", + "type": "LLMChain", + "baseClasses": ["LLMChain", "BaseChain", "Runnable"], + "category": "Chains", + "description": "Chain to run queries against LLMs", + "inputParams": [ + { + "label": "Chain Name", + "name": "chainName", + "type": "string", + "placeholder": "Name Your Chain", + "optional": true, + "id": "llmChain_1-input-chainName-string" + } + ], + "inputAnchors": [ + { + "label": "Language Model", + "name": "model", + "type": "BaseLanguageModel", + "id": "llmChain_1-input-model-BaseLanguageModel" + }, + { + "label": "Prompt", + "name": "prompt", + "type": "BasePromptTemplate", + "id": "llmChain_1-input-prompt-BasePromptTemplate" + } + ], + "inputs": { + "model": "{{chatOpenAI_1.data.instance}}", + "prompt": "{{promptTemplate_1.data.instance}}", + "chainName": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "llmChain_1-output-llmChain-LLMChain|BaseChain|Runnable", + "name": "llmChain", + "label": "LLM Chain", + "type": "LLMChain | BaseChain | Runnable" + }, + { + "id": "llmChain_1-output-outputPrediction-string|json", + "name": "outputPrediction", + "label": "Output Prediction", + "type": "string | json" + } + ], + "default": "llmChain" + } + ], + "outputs": { + "output": "llmChain" + }, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 2200.1274896215496, + "y": -144.29167974642334 + }, + "dragging": false + }, + { + "width": 300, + "height": 353, + "id": "vectorStoreToDocument_0", + "position": { + "x": 1407.7038120189868, + "y": -26.16468811205081 + }, + "type": "customNode", + "data": { + "id": "vectorStoreToDocument_0", + "label": "VectorStore To Document", + "version": 1, + "name": "vectorStoreToDocument", + "type": "Document", + "baseClasses": ["Document"], + "category": "Document Loaders", + "description": "Search documents with scores from vector store", + "inputParams": [ + { + "label": "Minimum Score (%)", + "name": "minScore", + "type": "number", + "optional": true, + "placeholder": "75", + "step": 1, + "description": "Minumum score for embeddings documents to be included", + "id": "vectorStoreToDocument_0-input-minScore-number" + } + ], + "inputAnchors": [ + { + "label": "Vector Store", + "name": "vectorStore", + "type": "VectorStore", + "id": "vectorStoreToDocument_0-input-vectorStore-VectorStore" + } + ], + "inputs": { + "vectorStore": "{{pineconeExistingIndex_0.data.instance}}", + "minScore": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "vectorStoreToDocument_0-output-document-Document", + "name": "document", + "label": "Document", + "type": "Document" + }, + { + "id": "vectorStoreToDocument_0-output-text-string|json", + "name": "text", + "label": "Text", + "type": "string | json" + } + ], + "default": "document" + } + ], + "outputs": { + "output": "text" + }, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 1407.7038120189868, + "y": -26.16468811205081 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "openAIEmbeddings_0", + "sourceHandle": "openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings", + "target": "pineconeExistingIndex_0", + "targetHandle": "pineconeExistingIndex_0-input-embeddings-Embeddings", + "type": "buttonedge", + "id": "openAIEmbeddings_0-openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings-pineconeExistingIndex_0-pineconeExistingIndex_0-input-embeddings-Embeddings", + "data": { + "label": "" + } + }, + { + "source": "pineconeExistingIndex_0", + "sourceHandle": "pineconeExistingIndex_0-output-vectorStore-Pinecone|VectorStore", + "target": "vectorStoreToDocument_0", + "targetHandle": "vectorStoreToDocument_0-input-vectorStore-VectorStore", + "type": "buttonedge", + "id": "pineconeExistingIndex_0-pineconeExistingIndex_0-output-vectorStore-Pinecone|VectorStore-vectorStoreToDocument_0-vectorStoreToDocument_0-input-vectorStore-VectorStore", + "data": { + "label": "" + } + }, + { + "source": "vectorStoreToDocument_0", + "sourceHandle": "vectorStoreToDocument_0-output-text-string|json", + "target": "promptTemplate_1", + "targetHandle": "promptTemplate_1-input-promptValues-json", + "type": "buttonedge", + "id": "vectorStoreToDocument_0-vectorStoreToDocument_0-output-text-string|json-promptTemplate_1-promptTemplate_1-input-promptValues-json", + "data": { + "label": "" + } + }, + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "llmChain_0", + "targetHandle": "llmChain_0-input-model-BaseLanguageModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-llmChain_0-llmChain_0-input-model-BaseLanguageModel", + "data": { + "label": "" + } + }, + { + "source": "promptTemplate_0", + "sourceHandle": "promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "target": "llmChain_0", + "targetHandle": "llmChain_0-input-prompt-BasePromptTemplate", + "type": "buttonedge", + "id": "promptTemplate_0-promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable-llmChain_0-llmChain_0-input-prompt-BasePromptTemplate", + "data": { + "label": "" + } + }, + { + "source": "llmChain_0", + "sourceHandle": "llmChain_0-output-outputPrediction-string|json", + "target": "promptTemplate_1", + "targetHandle": "promptTemplate_1-input-promptValues-json", + "type": "buttonedge", + "id": "llmChain_0-llmChain_0-output-outputPrediction-string|json-promptTemplate_1-promptTemplate_1-input-promptValues-json", + "data": { + "label": "" + } + }, + { + "source": "chatOpenAI_1", + "sourceHandle": "chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "llmChain_1", + "targetHandle": "llmChain_1-input-model-BaseLanguageModel", + "type": "buttonedge", + "id": "chatOpenAI_1-chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-llmChain_1-llmChain_1-input-model-BaseLanguageModel", + "data": { + "label": "" + } + }, + { + "source": "promptTemplate_1", + "sourceHandle": "promptTemplate_1-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "target": "llmChain_1", + "targetHandle": "llmChain_1-input-prompt-BasePromptTemplate", + "type": "buttonedge", + "id": "promptTemplate_1-promptTemplate_1-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable-llmChain_1-llmChain_1-input-prompt-BasePromptTemplate", + "data": { + "label": "" + } + } + ] +} diff --git a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json index 2146aa12..0758ec9a 100644 --- a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json +++ b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json @@ -4,14 +4,14 @@ { "width": 300, "height": 408, - "id": "vectaraExisting_0", + "id": "vectaraUpsert_0", "position": { "x": 438, "y": 214 }, "type": "customNode", "data": { - "id": "vectaraExisting_0", + "id": "vectaraUpsert_0", "label": "Vectara Upsert Document", "version": 1, - "name": "vectaraExisting", + "name": "vectaraUpsert", "type": "Vectara", "baseClasses": ["Vectara", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", @@ -22,7 +22,7 @@ "name": "credential", "type": "credential", "credentialNames": ["vectaraApi"], - "id": "vectaraExisting_0-input-credential-credential" + "id": "vectaraUpsert_0-input-credential-credential" }, { "label": "Filter", @@ -30,7 +30,7 @@ "type": "json", "additionalParams": true, "optional": true, - "id": "vectaraExisting_0-input-filter-json" + "id": "vectaraUpsert_0-input-filter-json" }, { "label": "Lambda", @@ -38,7 +38,7 @@ "type": "number", "additionalParams": true, "optional": true, - "id": "vectaraExisting_0-input-lambda-number" + "id": "vectaraUpsert_0-input-lambda-number" }, { "label": "Top K", @@ -48,7 +48,7 @@ "type": "number", "additionalParams": true, "optional": true, - "id": "vectaraExisting_0-input-topK-number" + "id": "vectaraUpsert_0-input-topK-number" } ], "inputAnchors": [ @@ -57,7 +57,7 @@ "name": "document", "type": "Document", "list": true, - "id": "vectaraExisting_0-input-document-Document" + "id": "vectaraUpsert_0-input-document-Document" } ], "inputs": { @@ -73,13 +73,13 @@ "type": "options", "options": [ { - "id": "vectaraExisting_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", + "id": "vectaraUpsert_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", "name": "retriever", "label": "Vectara Retriever", "type": "Vectara | VectorStoreRetriever | BaseRetriever" }, { - "id": "vectaraExisting_0-output-vectorStore-Vectara|VectorStore", + "id": "vectaraUpsert_0-output-vectorStore-Vectara|VectorStore", "name": "vectorStore", "label": "Vectara Vector Store", "type": "Vectara | VectorStore" @@ -392,7 +392,7 @@ ], "inputs": { "model": "{{chatOpenAI_0.data.instance}}", - "vectorStoreRetriever": "{{vectaraExisting_0.data.instance}}", + "vectorStoreRetriever": "{{vectaraUpsert_0.data.instance}}", "memory": "", "returnSourceDocuments": "", "systemMessagePrompt": "", @@ -418,19 +418,19 @@ { "source": "pdfFile_0", "sourceHandle": "pdfFile_0-output-pdfFile-Document", - "target": "vectaraExisting_0", - "targetHandle": "vectaraExisting_0-input-document-Document", + "target": "vectaraUpsert_0", + "targetHandle": "vectaraUpsert_0-input-document-Document", "type": "buttonedge", - "id": "pdfFile_0-pdfFile_0-output-pdfFile-Document-vectaraExisting_0-vectaraExisting_0-input-document-Document", + "id": "pdfFile_0-pdfFile_0-output-pdfFile-Document-vectaraUpsert_0-vectaraUpsert_0-input-document-Document", "data": { "label": "" } }, { - "source": "vectaraExisting_0", - "sourceHandle": "vectaraExisting_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", + "source": "vectaraUpsert_0", + "sourceHandle": "vectaraUpsert_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", "target": "conversationalRetrievalQAChain_0", "targetHandle": "conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever", "type": "buttonedge", - "id": "vectaraExisting_0-vectaraExisting_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever", + "id": "vectaraUpsert_0-vectaraUpsert_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever", "data": { "label": "" } }, { diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index b7289149..fbb61b00 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -811,11 +811,17 @@ export class App { } } + /*** Get chatflows and prepare data ***/ + const flowData = chatflow.flowData + const parsedFlowData: IReactFlowObject = JSON.parse(flowData) + const nodes = parsedFlowData.nodes + const edges = parsedFlowData.edges + /* Reuse the flow without having to rebuild (to avoid duplicated upsert, recomputation) when all these conditions met: * - Node Data already exists in pool * - Still in sync (i.e the flow has not been modified since) * - Existing overrideConfig and new overrideConfig are the same - * - Flow doesn't start with nodes that depend on incomingInput.question + * - Flow doesn't start with/contain nodes that depend on incomingInput.question ***/ const isFlowReusable = () => { return ( @@ -826,16 +832,10 @@ export class App { this.chatflowPool.activeChatflows[chatflowid].overrideConfig, incomingInput.overrideConfig ) && - !isStartNodeDependOnInput(this.chatflowPool.activeChatflows[chatflowid].startingNodes) + !isStartNodeDependOnInput(this.chatflowPool.activeChatflows[chatflowid].startingNodes, nodes) ) } - /*** Get chatflows and prepare data ***/ - const flowData = chatflow.flowData - const parsedFlowData: IReactFlowObject = JSON.parse(flowData) - const nodes = parsedFlowData.nodes - const edges = parsedFlowData.edges - if (isFlowReusable()) { nodeToExecuteData = this.chatflowPool.activeChatflows[chatflowid].endingNodeData isStreamValid = isFlowValidForStream(nodes, nodeToExecuteData) @@ -884,6 +884,7 @@ export class App { depthQueue, this.nodesPool.componentNodes, incomingInput.question, + incomingInput.history, chatId, this.AppDataSource, incomingInput?.overrideConfig @@ -894,7 +895,12 @@ export class App { if (incomingInput.overrideConfig) nodeToExecute.data = replaceInputsWithConfig(nodeToExecute.data, incomingInput.overrideConfig) - const reactFlowNodeData: INodeData = resolveVariables(nodeToExecute.data, reactFlowNodes, incomingInput.question) + const reactFlowNodeData: INodeData = resolveVariables( + nodeToExecute.data, + reactFlowNodes, + incomingInput.question, + incomingInput.history + ) nodeToExecuteData = reactFlowNodeData const startingNodes = nodes.filter((nd) => startingNodeIds.includes(nd.id)) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index cf4a9c3f..788b7c0e 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -19,7 +19,14 @@ import { ICredentialReqBody } from '../Interface' import { cloneDeep, get, omit, merge, isEqual } from 'lodash' -import { ICommonObject, getInputVariables, IDatabaseEntity, handleEscapeCharacters } from 'flowise-components' +import { + ICommonObject, + getInputVariables, + IDatabaseEntity, + handleEscapeCharacters, + IMessage, + convertChatHistoryToText +} from 'flowise-components' import { scryptSync, randomBytes, timingSafeEqual } from 'crypto' import { lib, PBKDF2, AES, enc } from 'crypto-js' @@ -30,6 +37,7 @@ import { Tool } from '../entity/Tool' import { DataSource } from 'typeorm' const QUESTION_VAR_PREFIX = 'question' +const CHAT_HISTORY_VAR_PREFIX = 'chat_history' const REDACTED_CREDENTIAL_VALUE = '_FLOWISE_BLANK_07167752-1a71-43b1-bf8f-4f32252165db' export const databaseEntities: IDatabaseEntity = { ChatFlow: ChatFlow, ChatMessage: ChatMessage, Tool: Tool, Credential: Credential } @@ -199,6 +207,7 @@ export const buildLangchain = async ( depthQueue: IDepthQueue, componentNodes: IComponentNodes, question: string, + chatHistory: IMessage[], chatId: string, appDataSource: DataSource, overrideConfig?: ICommonObject @@ -231,7 +240,7 @@ export const buildLangchain = async ( let flowNodeData = cloneDeep(reactFlowNode.data) if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig) - const reactFlowNodeData: INodeData = resolveVariables(flowNodeData, flowNodes, question) + const reactFlowNodeData: INodeData = resolveVariables(flowNodeData, flowNodes, question, chatHistory) logger.debug(`[server]: Initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`) flowNodes[nodeIndex].data.instance = await newNodeInstance.init(reactFlowNodeData, question, { @@ -315,7 +324,13 @@ export const clearSessionMemory = async ( * @param {boolean} isAcceptVariable * @returns {string} */ -export const getVariableValue = (paramValue: string, reactFlowNodes: IReactFlowNode[], question: string, isAcceptVariable = false) => { +export const getVariableValue = ( + paramValue: string, + reactFlowNodes: IReactFlowNode[], + question: string, + chatHistory: IMessage[], + isAcceptVariable = false +) => { let returnVal = paramValue const variableStack = [] const variableDict = {} as IVariableDict @@ -345,6 +360,10 @@ export const getVariableValue = (paramValue: string, reactFlowNodes: IReactFlowN variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(question, false) } + if (isAcceptVariable && variableFullPath === CHAT_HISTORY_VAR_PREFIX) { + variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(convertChatHistoryToText(chatHistory), false) + } + // Split by first occurrence of '.' to get just nodeId const [variableNodeId, _] = variableFullPath.split('.') const executedNode = reactFlowNodes.find((nd) => nd.id === variableNodeId) @@ -400,7 +419,12 @@ export const isVectorStoreFaiss = (flowNodeData: INodeData) => { * @param {string} question * @returns {INodeData} */ -export const resolveVariables = (reactFlowNodeData: INodeData, reactFlowNodes: IReactFlowNode[], question: string): INodeData => { +export const resolveVariables = ( + reactFlowNodeData: INodeData, + reactFlowNodes: IReactFlowNode[], + question: string, + chatHistory: IMessage[] +): INodeData => { let flowNodeData = cloneDeep(reactFlowNodeData) if (reactFlowNodeData.instance && isVectorStoreFaiss(reactFlowNodeData)) { // omit and merge because cloneDeep of instance gives "Illegal invocation" Exception @@ -415,13 +439,13 @@ export const resolveVariables = (reactFlowNodeData: INodeData, reactFlowNodes: I if (Array.isArray(paramValue)) { const resolvedInstances = [] for (const param of paramValue) { - const resolvedInstance = getVariableValue(param, reactFlowNodes, question) + const resolvedInstance = getVariableValue(param, reactFlowNodes, question, chatHistory) resolvedInstances.push(resolvedInstance) } paramsObj[key] = resolvedInstances } else { const isAcceptVariable = reactFlowNodeData.inputParams.find((param) => param.name === key)?.acceptVariable ?? false - const resolvedInstance = getVariableValue(paramValue, reactFlowNodes, question, isAcceptVariable) + const resolvedInstance = getVariableValue(paramValue, reactFlowNodes, question, chatHistory, isAcceptVariable) paramsObj[key] = resolvedInstance } } @@ -474,13 +498,17 @@ export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig: * @param {IReactFlowNode[]} startingNodes * @returns {boolean} */ -export const isStartNodeDependOnInput = (startingNodes: IReactFlowNode[]): boolean => { +export const isStartNodeDependOnInput = (startingNodes: IReactFlowNode[], nodes: IReactFlowNode[]): boolean => { for (const node of startingNodes) { for (const inputName in node.data.inputs) { const inputVariables = getInputVariables(node.data.inputs[inputName]) if (inputVariables.length > 0) return true } } + const whitelistNodeNames = ['vectorStoreToDocument'] + for (const node of nodes) { + if (whitelistNodeNames.includes(node.data.name)) return true + } return false } diff --git a/packages/ui/src/assets/images/chathistory.png b/packages/ui/src/assets/images/chathistory.png new file mode 100644 index 0000000000000000000000000000000000000000..52f496a89bafe01b39986a9ff63d19fd006972fe GIT binary patch literal 12068 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 { )} {getNodeConfigApi.data && getNodeConfigApi.data.length > 0 && ( - + )} diff --git a/packages/ui/src/ui-component/json/SelectVariable.js b/packages/ui/src/ui-component/json/SelectVariable.js index 1b891ed1..7a482bae 100644 --- a/packages/ui/src/ui-component/json/SelectVariable.js +++ b/packages/ui/src/ui-component/json/SelectVariable.js @@ -2,14 +2,15 @@ import { useSelector } from 'react-redux' import PropTypes from 'prop-types' import { Box, List, ListItemButton, ListItem, ListItemAvatar, ListItemText, Typography, Stack } from '@mui/material' import PerfectScrollbar from 'react-perfect-scrollbar' - +import robotPNG from 'assets/images/robot.png' +import chatPNG from 'assets/images/chathistory.png' import { baseURL } from 'store/constant' const SelectVariable = ({ availableNodesForVariable, disabled = false, onSelectAndReturnVal }) => { const customization = useSelector((state) => state.customization) - const onSelectOutputResponseClick = (node, isUserQuestion = false) => { - let variablePath = isUserQuestion ? `question` : `${node.id}.data.instance` + const onSelectOutputResponseClick = (node, prefix) => { + let variablePath = node ? `${node.id}.data.instance` : prefix const newInput = `{{${variablePath}}}` onSelectAndReturnVal(newInput) } @@ -32,7 +33,7 @@ const SelectVariable = ({ availableNodesForVariable, disabled = false, onSelectA mb: 1 }} disabled={disabled} - onClick={() => onSelectOutputResponseClick(null, true)} + onClick={() => onSelectOutputResponseClick(null, 'question')} > @@ -52,13 +53,52 @@ const SelectVariable = ({ availableNodesForVariable, disabled = false, onSelectA objectFit: 'contain' }} alt='AI' - src='https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png' + src={robotPNG} /> + onSelectOutputResponseClick(null, 'chat_history')} + > + + +
+ chatHistory +
+
+ +
+
{availableNodesForVariable && availableNodesForVariable.length > 0 && availableNodesForVariable.map((node, index) => { From f0f5585cac26ff7a8252b4761a5da6dc923de2d1 Mon Sep 17 00:00:00 2001 From: Seif Date: Wed, 16 Aug 2023 09:56:14 -0700 Subject: [PATCH 05/24] Update template --- .../chatflows/Vectara LLM Chain Upload.json | 388 +++++++++--------- 1 file changed, 195 insertions(+), 193 deletions(-) diff --git a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json index 0758ec9a..784ad240 100644 --- a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json +++ b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json @@ -1,186 +1,11 @@ { "description": "A simple LLM chain that uses Vectara to enable conversations with uploaded documents", "nodes": [ - { - "width": 300, - "height": 408, - "id": "vectaraUpsert_0", - "position": { "x": 438, "y": 214 }, - "type": "customNode", - "data": { - "id": "vectaraUpsert_0", - "label": "Vectara Upsert Document", - "version": 1, - "name": "vectaraUpsert", - "type": "Vectara", - "baseClasses": ["Vectara", "VectorStoreRetriever", "BaseRetriever"], - "category": "Vector Stores", - "description": "Upsert documents to Vectara", - "inputParams": [ - { - "label": "Connect Credential", - "name": "credential", - "type": "credential", - "credentialNames": ["vectaraApi"], - "id": "vectaraUpsert_0-input-credential-credential" - }, - { - "label": "Filter", - "name": "filter", - "type": "json", - "additionalParams": true, - "optional": true, - "id": "vectaraUpsert_0-input-filter-json" - }, - { - "label": "Lambda", - "name": "lambda", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectaraUpsert_0-input-lambda-number" - }, - { - "label": "Top K", - "name": "topK", - "description": "Number of top results to fetch. Defaults to 4", - "placeholder": "4", - "type": "number", - "additionalParams": true, - "optional": true, - "id": "vectaraUpsert_0-input-topK-number" - } - ], - "inputAnchors": [ - { - "label": "Document", - "name": "document", - "type": "Document", - "list": true, - "id": "vectaraUpsert_0-input-document-Document" - } - ], - "inputs": { - "document": ["{{pdfFile_0.data.instance}}"], - "filter": "", - "lambda": "", - "topK": "" - }, - "outputAnchors": [ - { - "name": "output", - "label": "Output", - "type": "options", - "options": [ - { - "id": "vectaraUpsert_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", - "name": "retriever", - "label": "Vectara Retriever", - "type": "Vectara | VectorStoreRetriever | BaseRetriever" - }, - { - "id": "vectaraUpsert_0-output-vectorStore-Vectara|VectorStore", - "name": "vectorStore", - "label": "Vectara Vector Store", - "type": "Vectara | VectorStore" - } - ], - "default": "retriever" - } - ], - "outputs": { "output": "retriever" }, - "selected": false - }, - "selected": false, - "dragging": false, - "positionAbsolute": { "x": 438, "y": 214 } - }, - { - "width": 300, - "height": 509, - "id": "pdfFile_0", - "position": { "x": 68.3013317598369, "y": 199.60454731299677 }, - "type": "customNode", - "data": { - "id": "pdfFile_0", - "label": "Pdf File", - "version": 1, - "name": "pdfFile", - "type": "Document", - "baseClasses": ["Document"], - "category": "Document Loaders", - "description": "Load data from PDF files", - "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": "Metadata", - "name": "metadata", - "type": "json", - "optional": true, - "additionalParams": true, - "id": "pdfFile_0-input-metadata-json" - } - ], - "inputAnchors": [ - { - "label": "Text Splitter", - "name": "textSplitter", - "type": "TextSplitter", - "optional": true, - "id": "pdfFile_0-input-textSplitter-TextSplitter" - } - ], - "inputs": { - "textSplitter": "", - "usage": "perPage", - "legacyBuild": "", - "metadata": "" - }, - "outputAnchors": [ - { - "id": "pdfFile_0-output-pdfFile-Document", - "name": "pdfFile", - "label": "Document", - "type": "Document" - } - ], - "outputs": {}, - "selected": false - }, - "selected": false, - "positionAbsolute": { "x": 68.3013317598369, "y": 199.60454731299677 }, - "dragging": false - }, { "width": 300, "height": 525, "id": "chatOpenAI_0", - "position": { "x": 804.3889791707068, "y": 195.11620799951592 }, + "position": { "x": 514.1088940275924, "y": 199.574479681537 }, "type": "customNode", "data": { "id": "chatOpenAI_0", @@ -211,10 +36,7 @@ { "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" - } + { "label": "gpt-3.5-turbo-16k-0613", "name": "gpt-3.5-turbo-16k-0613" } ], "default": "gpt-3.5-turbo", "optional": true, @@ -286,7 +108,7 @@ "inputAnchors": [], "inputs": { "modelName": "gpt-3.5-turbo", - "temperature": "0.2", + "temperature": "0.5", "maxTokens": "", "topP": "", "frequencyPenalty": "", @@ -306,14 +128,14 @@ "selected": false }, "selected": false, - "positionAbsolute": { "x": 804.3889791707068, "y": 195.11620799951592 }, + "positionAbsolute": { "x": 514.1088940275924, "y": 199.574479681537 }, "dragging": false }, { "width": 300, "height": 481, "id": "conversationalRetrievalQAChain_0", - "position": { "x": 1160.4877473512795, "y": 259.2799138505109 }, + "position": { "x": 900.4793407261002, "y": 205.9476004518217 }, "type": "customNode", "data": { "id": "conversationalRetrievalQAChain_0", @@ -410,11 +232,200 @@ "selected": false }, "selected": false, - "positionAbsolute": { "x": 1160.4877473512795, "y": 259.2799138505109 }, + "positionAbsolute": { "x": 900.4793407261002, "y": 205.9476004518217 }, "dragging": false + }, + { + "width": 300, + "height": 509, + "id": "pdfFile_0", + "position": { "x": -210.44158723479913, "y": 236.6627524951051 }, + "type": "customNode", + "data": { + "id": "pdfFile_0", + "label": "Pdf File", + "version": 1, + "name": "pdfFile", + "type": "Document", + "baseClasses": ["Document"], + "category": "Document Loaders", + "description": "Load data from PDF files", + "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": "Metadata", + "name": "metadata", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "pdfFile_0-input-metadata-json" + } + ], + "inputAnchors": [ + { + "label": "Text Splitter", + "name": "textSplitter", + "type": "TextSplitter", + "optional": true, + "id": "pdfFile_0-input-textSplitter-TextSplitter" + } + ], + "inputs": { "textSplitter": "", "usage": "perPage", "legacyBuild": "", "metadata": "" }, + "outputAnchors": [ + { "id": "pdfFile_0-output-pdfFile-Document", "name": "pdfFile", "label": "Document", "type": "Document" } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { "x": -210.44158723479913, "y": 236.6627524951051 }, + "dragging": false + }, + { + "width": 300, + "height": 408, + "id": "vectaraUpsert_0", + "position": { "x": 172.06946164914868, "y": 373.11406233089934 }, + "type": "customNode", + "data": { + "id": "vectaraUpsert_0", + "label": "Vectara Upsert Document", + "version": 1, + "name": "vectaraUpsert", + "type": "Vectara", + "baseClasses": ["Vectara", "VectorStoreRetriever", "BaseRetriever"], + "category": "Vector Stores", + "description": "Upsert documents to Vectara", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["vectaraApi"], + "id": "vectaraUpsert_0-input-credential-credential" + }, + { + "label": "Vectara 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": "vectaraUpsert_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": "vectaraUpsert_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": "vectaraUpsert_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": "vectaraUpsert_0-input-lambda-number" + }, + { + "label": "Top K", + "name": "topK", + "description": "Number of top results to fetch. Defaults to 4", + "placeholder": "4", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "vectaraUpsert_0-input-topK-number" + } + ], + "inputAnchors": [ + { + "label": "Document", + "name": "document", + "type": "Document", + "list": true, + "id": "vectaraUpsert_0-input-document-Document" + } + ], + "inputs": { + "document": ["{{pdfFile_0.data.instance}}"], + "filter": "", + "sentencesBefore": "", + "sentencesAfter": "", + "lambda": "", + "topK": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "vectaraUpsert_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", + "name": "retriever", + "label": "Vectara Retriever", + "type": "Vectara | VectorStoreRetriever | BaseRetriever" + }, + { + "id": "vectaraUpsert_0-output-vectorStore-Vectara|VectorStore", + "name": "vectorStore", + "label": "Vectara Vector Store", + "type": "Vectara | VectorStore" + } + ], + "default": "retriever" + } + ], + "outputs": { "output": "retriever" }, + "selected": false + }, + "positionAbsolute": { "x": 172.06946164914868, "y": 373.11406233089934 }, + "selected": false } ], "edges": [ + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", + "target": "conversationalRetrievalQAChain_0", + "targetHandle": "conversationalRetrievalQAChain_0-input-model-BaseLanguageModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-model-BaseLanguageModel", + "data": { "label": "" } + }, { "source": "pdfFile_0", "sourceHandle": "pdfFile_0-output-pdfFile-Document", @@ -432,15 +443,6 @@ "type": "buttonedge", "id": "vectaraUpsert_0-vectaraUpsert_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever", "data": { "label": "" } - }, - { - "source": "chatOpenAI_0", - "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel", - "target": "conversationalRetrievalQAChain_0", - "targetHandle": "conversationalRetrievalQAChain_0-input-model-BaseLanguageModel", - "type": "buttonedge", - "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-model-BaseLanguageModel", - "data": { "label": "" } } ] } From c83d0ab3205739dc5fa9e289ed609c2241041a36 Mon Sep 17 00:00:00 2001 From: Atish Amte Date: Thu, 17 Aug 2023 00:33:01 +0530 Subject: [PATCH 06/24] added puppeteer options --- .../documentloaders/Puppeteer/Puppeteer.ts | 64 +++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts b/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts index ea6280db..036e4053 100644 --- a/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts +++ b/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts @@ -1,8 +1,9 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { TextSplitter } from 'langchain/text_splitter' -import { PuppeteerWebBaseLoader } from 'langchain/document_loaders/web/puppeteer' +import { Browser, Page, PuppeteerWebBaseLoader, PuppeteerWebBaseLoaderOptions } from 'langchain/document_loaders/web/puppeteer' import { test } from 'linkifyjs' import { webCrawl, xmlScrape } from '../../../src' +import { PuppeteerLifeCycleEvent } from 'puppeteer' class Puppeteer_DocumentLoaders implements INode { label: string @@ -62,10 +63,47 @@ class Puppeteer_DocumentLoaders implements INode { type: 'number', optional: true, additionalParams: true, - description: - 'Only used when "Get Relative Links Method" is selected. Set 0 to retrieve all relative links, default limit is 10.', + description: 'Only used when "Get Relative Links Method" is selected. Set 0 to retrieve all relative links, default limit is 10.', warning: `Retreiving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)` }, + { + label: 'Wait Until', + name: 'waitUntilGoToOption', + type: 'options', + description: 'Select a go to wait until option', + options: [ + { + label: 'Load', + name: 'load', + description: `When the initial HTML document\'s DOM has been loaded and parsed` + }, + { + label: 'DOM Content Loaded', + name: 'domcontentloaded', + description: `When the complete HTML document\'s DOM has been loaded and parsed` + }, + { + label: 'Network Idle 0', + name: 'networkidle0', + description: 'Navigation is finished when there are no more than 0 network connections for at least 500 ms' + }, + { + label: 'Network Idle 2', + name: 'networkidle2', + description: 'Navigation is finished when there are no more than 2 network connections for at least 500 ms' + } + ], + optional: true, + additionalParams: true + }, + { + label: 'Wait for selector to load', + name: 'waitForSelector', + type: 'string', + optional: true, + additionalParams: true, + description: 'CSS selectors like .div or #div', + }, { label: 'Metadata', name: 'metadata', @@ -81,6 +119,8 @@ class Puppeteer_DocumentLoaders implements INode { const metadata = nodeData.inputs?.metadata const relativeLinksMethod = nodeData.inputs?.relativeLinksMethod as string let limit = nodeData.inputs?.limit as string + let waitUntilGoToOption = nodeData.inputs?.waitUntilGoToOption as PuppeteerLifeCycleEvent + let waitForSelector = nodeData.inputs?.waitForSelector as string let url = nodeData.inputs?.url as string url = url.trim() @@ -91,12 +131,26 @@ class Puppeteer_DocumentLoaders implements INode { async function puppeteerLoader(url: string): Promise { try { let docs = [] - const loader = new PuppeteerWebBaseLoader(url, { + const config: PuppeteerWebBaseLoaderOptions = { launchOptions: { args: ['--no-sandbox'], headless: 'new' } - }) + }; + if (waitUntilGoToOption) { + config['gotoOptions'] = { + waitUntil: waitUntilGoToOption + } + } + if (waitForSelector) { + config['evaluate'] = async (page: Page, browser: Browser): Promise => { + await page.waitForSelector(waitForSelector) + + const result = await page.evaluate(() => document.body.innerHTML) + return result + } + } + const loader = new PuppeteerWebBaseLoader(url, config) if (textSplitter) { docs = await loader.loadAndSplit(textSplitter) } else { From 8414f347def05fe405744562c28615e5bc9952d8 Mon Sep 17 00:00:00 2001 From: Atish Amte Date: Thu, 17 Aug 2023 00:36:03 +0530 Subject: [PATCH 07/24] spelling correction --- .../nodes/documentloaders/Cheerio/Cheerio.ts | 2 +- .../documentloaders/Playwright/Playwright.ts | 2 +- .../documentloaders/Puppeteer/Puppeteer.ts | 2 +- .../marketplaces/chatflows/WebPage QnA.json | 56 ++++++++++++++----- 4 files changed, 46 insertions(+), 16 deletions(-) diff --git a/packages/components/nodes/documentloaders/Cheerio/Cheerio.ts b/packages/components/nodes/documentloaders/Cheerio/Cheerio.ts index 310aa9e6..1c21c1ea 100644 --- a/packages/components/nodes/documentloaders/Cheerio/Cheerio.ts +++ b/packages/components/nodes/documentloaders/Cheerio/Cheerio.ts @@ -64,7 +64,7 @@ class Cheerio_DocumentLoaders implements INode { additionalParams: true, description: 'Only used when "Get Relative Links Method" is selected. Set 0 to retrieve all relative links, default limit is 10.', - warning: `Retreiving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)` + warning: `Retrieving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)` }, { label: 'Metadata', diff --git a/packages/components/nodes/documentloaders/Playwright/Playwright.ts b/packages/components/nodes/documentloaders/Playwright/Playwright.ts index 3399574d..2ddd6a8d 100644 --- a/packages/components/nodes/documentloaders/Playwright/Playwright.ts +++ b/packages/components/nodes/documentloaders/Playwright/Playwright.ts @@ -64,7 +64,7 @@ class Playwright_DocumentLoaders implements INode { additionalParams: true, description: 'Only used when "Get Relative Links Method" is selected. Set 0 to retrieve all relative links, default limit is 10.', - warning: `Retreiving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)` + warning: `Retrieving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)` }, { label: 'Metadata', diff --git a/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts b/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts index 036e4053..c3b61a2b 100644 --- a/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts +++ b/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts @@ -64,7 +64,7 @@ class Puppeteer_DocumentLoaders implements INode { optional: true, additionalParams: true, description: 'Only used when "Get Relative Links Method" is selected. Set 0 to retrieve all relative links, default limit is 10.', - warning: `Retreiving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)` + warning: `Retrieving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)` }, { label: 'Wait Until', diff --git a/packages/server/marketplaces/chatflows/WebPage QnA.json b/packages/server/marketplaces/chatflows/WebPage QnA.json index 8197c20a..09246150 100644 --- a/packages/server/marketplaces/chatflows/WebPage QnA.json +++ b/packages/server/marketplaces/chatflows/WebPage QnA.json @@ -16,7 +16,11 @@ "version": 1, "name": "chatOpenAI", "type": "ChatOpenAI", - "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], + "baseClasses": [ + "ChatOpenAI", + "BaseChatModel", + "BaseLanguageModel" + ], "category": "Chat Models", "description": "Wrapper around OpenAI large language models that use the Chat endpoint", "inputParams": [ @@ -24,7 +28,9 @@ "label": "Connect Credential", "name": "credential", "type": "credential", - "credentialNames": ["openAIApi"], + "credentialNames": [ + "openAIApi" + ], "id": "chatOpenAI_0-input-credential-credential" }, { @@ -170,7 +176,10 @@ "version": 1, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", - "baseClasses": ["OpenAIEmbeddings", "Embeddings"], + "baseClasses": [ + "OpenAIEmbeddings", + "Embeddings" + ], "category": "Embeddings", "description": "OpenAI API to generate embeddings for a given text", "inputParams": [ @@ -178,7 +187,9 @@ "label": "Connect Credential", "name": "credential", "type": "credential", - "credentialNames": ["openAIApi"], + "credentialNames": [ + "openAIApi" + ], "id": "openAIEmbeddings_0-input-credential-credential" }, { @@ -318,7 +329,10 @@ "version": 1, "name": "conversationalRetrievalQAChain", "type": "ConversationalRetrievalQAChain", - "baseClasses": ["ConversationalRetrievalQAChain", "BaseChain"], + "baseClasses": [ + "ConversationalRetrievalQAChain", + "BaseChain" + ], "category": "Chains", "description": "Document QA - built on RetrievalQAChain to provide a chat history component", "inputParams": [ @@ -428,7 +442,9 @@ "version": 1, "name": "cheerioWebScraper", "type": "Document", - "baseClasses": ["Document"], + "baseClasses": [ + "Document" + ], "category": "Document Loaders", "description": "Load data from webpages", "inputParams": [ @@ -466,7 +482,7 @@ "optional": true, "additionalParams": true, "description": "Only used when \"Get Relative Links Method\" is selected. Set 0 to retrieve all relative links, default limit is 10.", - "warning": "Retreiving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)", + "warning": "Retrieving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)", "id": "cheerioWebScraper_0-input-limit-number" }, { @@ -527,7 +543,11 @@ "version": 1, "name": "pineconeUpsert", "type": "Pinecone", - "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], + "baseClasses": [ + "Pinecone", + "VectorStoreRetriever", + "BaseRetriever" + ], "category": "Vector Stores", "description": "Upsert documents to Pinecone", "inputParams": [ @@ -535,7 +555,9 @@ "label": "Connect Credential", "name": "credential", "type": "credential", - "credentialNames": ["pineconeApi"], + "credentialNames": [ + "pineconeApi" + ], "id": "pineconeUpsert_0-input-credential-credential" }, { @@ -580,7 +602,9 @@ } ], "inputs": { - "document": ["{{cheerioWebScraper_0.data.instance}}"], + "document": [ + "{{cheerioWebScraper_0.data.instance}}" + ], "embeddings": "{{openAIEmbeddings_0.data.instance}}", "pineconeIndex": "", "pineconeNamespace": "", @@ -635,7 +659,11 @@ "version": 1, "name": "motorheadMemory", "type": "MotorheadMemory", - "baseClasses": ["MotorheadMemory", "BaseChatMemory", "BaseMemory"], + "baseClasses": [ + "MotorheadMemory", + "BaseChatMemory", + "BaseMemory" + ], "category": "Memory", "description": "Use Motorhead Memory to store chat conversations", "inputParams": [ @@ -645,7 +673,9 @@ "type": "credential", "optional": true, "description": "Only needed when using hosted solution - https://getmetal.io", - "credentialNames": ["motorheadMemoryApi"], + "credentialNames": [ + "motorheadMemoryApi" + ], "id": "motorheadMemory_0-input-credential-credential" }, { @@ -768,4 +798,4 @@ } } ] -} +} \ No newline at end of file From 338082f0aa6e7bfc7d61077d03b0ff10253c3d9b Mon Sep 17 00:00:00 2001 From: Atish Amte Date: Thu, 17 Aug 2023 00:52:35 +0530 Subject: [PATCH 08/24] playwright config --- .../documentloaders/Playwright/Playwright.ts | 63 ++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/packages/components/nodes/documentloaders/Playwright/Playwright.ts b/packages/components/nodes/documentloaders/Playwright/Playwright.ts index 2ddd6a8d..b376c05b 100644 --- a/packages/components/nodes/documentloaders/Playwright/Playwright.ts +++ b/packages/components/nodes/documentloaders/Playwright/Playwright.ts @@ -1,6 +1,6 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' import { TextSplitter } from 'langchain/text_splitter' -import { PlaywrightWebBaseLoader } from 'langchain/document_loaders/web/playwright' +import { Browser, Page, PlaywrightWebBaseLoader, PlaywrightWebBaseLoaderOptions } from 'langchain/document_loaders/web/playwright' import { test } from 'linkifyjs' import { webCrawl, xmlScrape } from '../../../src' @@ -66,6 +66,44 @@ class Playwright_DocumentLoaders implements INode { 'Only used when "Get Relative Links Method" is selected. Set 0 to retrieve all relative links, default limit is 10.', warning: `Retrieving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)` }, + { + label: 'Wait Until', + name: 'waitUntilGoToOption', + type: 'options', + description: 'Select a go to wait until option', + options: [ + { + label: 'Load', + name: 'load', + description: 'Consider operation to be finished when the load event is fired.' + }, + { + label: 'DOM Content Loaded', + name: 'domcontentloaded', + description: 'Consider operation to be finished when the DOMContentLoaded event is fired.' + }, + { + label: 'Network Idle', + name: 'networkidle', + description: 'Navigation is finished when there are no more connections for at least 500 ms.' + }, + { + label: 'Commit', + name: 'commit', + description: 'Consider operation to be finished when network response is received and the document started loading.' + } + ], + optional: true, + additionalParams: true + }, + { + label: 'Wait for selector to load', + name: 'waitForSelector', + type: 'string', + optional: true, + additionalParams: true, + description: 'CSS selectors like .div or #div', + }, { label: 'Metadata', name: 'metadata', @@ -81,6 +119,8 @@ class Playwright_DocumentLoaders implements INode { const metadata = nodeData.inputs?.metadata const relativeLinksMethod = nodeData.inputs?.relativeLinksMethod as string let limit = nodeData.inputs?.limit as string + let waitUntilGoToOption = nodeData.inputs?.waitUntilGoToOption as "load" | "domcontentloaded" | "networkidle" | "commit" | undefined + let waitForSelector = nodeData.inputs?.waitForSelector as string let url = nodeData.inputs?.url as string url = url.trim() @@ -91,7 +131,26 @@ class Playwright_DocumentLoaders implements INode { async function playwrightLoader(url: string): Promise { try { let docs = [] - const loader = new PlaywrightWebBaseLoader(url) + const config: PlaywrightWebBaseLoaderOptions = { + launchOptions: { + args: ['--no-sandbox'], + headless: true + } + }; + if (waitUntilGoToOption) { + config['gotoOptions'] = { + waitUntil: waitUntilGoToOption + } + } + if (waitForSelector) { + config['evaluate'] = async (page: Page, browser: Browser): Promise => { + await page.waitForSelector(waitForSelector) + + const result = await page.evaluate(() => document.body.innerHTML) + return result + } + } + const loader = new PlaywrightWebBaseLoader(url, config) if (textSplitter) { docs = await loader.loadAndSplit(textSplitter) } else { From 888fa356b93d2d0d2ff3b11addd11c839c5b225f Mon Sep 17 00:00:00 2001 From: Atish Amte Date: Thu, 17 Aug 2023 01:11:31 +0530 Subject: [PATCH 09/24] lint fixes --- .../documentloaders/Playwright/Playwright.ts | 8 +-- .../documentloaders/Puppeteer/Puppeteer.ts | 13 ++--- .../marketplaces/chatflows/WebPage QnA.json | 54 +++++-------------- 3 files changed, 23 insertions(+), 52 deletions(-) diff --git a/packages/components/nodes/documentloaders/Playwright/Playwright.ts b/packages/components/nodes/documentloaders/Playwright/Playwright.ts index b376c05b..eb246045 100644 --- a/packages/components/nodes/documentloaders/Playwright/Playwright.ts +++ b/packages/components/nodes/documentloaders/Playwright/Playwright.ts @@ -102,7 +102,7 @@ class Playwright_DocumentLoaders implements INode { type: 'string', optional: true, additionalParams: true, - description: 'CSS selectors like .div or #div', + description: 'CSS selectors like .div or #div' }, { label: 'Metadata', @@ -119,7 +119,7 @@ class Playwright_DocumentLoaders implements INode { const metadata = nodeData.inputs?.metadata const relativeLinksMethod = nodeData.inputs?.relativeLinksMethod as string let limit = nodeData.inputs?.limit as string - let waitUntilGoToOption = nodeData.inputs?.waitUntilGoToOption as "load" | "domcontentloaded" | "networkidle" | "commit" | undefined + let waitUntilGoToOption = nodeData.inputs?.waitUntilGoToOption as 'load' | 'domcontentloaded' | 'networkidle' | 'commit' | undefined let waitForSelector = nodeData.inputs?.waitForSelector as string let url = nodeData.inputs?.url as string @@ -136,14 +136,14 @@ class Playwright_DocumentLoaders implements INode { args: ['--no-sandbox'], headless: true } - }; + } if (waitUntilGoToOption) { config['gotoOptions'] = { waitUntil: waitUntilGoToOption } } if (waitForSelector) { - config['evaluate'] = async (page: Page, browser: Browser): Promise => { + config['evaluate'] = async (page: Page, _: Browser): Promise => { await page.waitForSelector(waitForSelector) const result = await page.evaluate(() => document.body.innerHTML) diff --git a/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts b/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts index c3b61a2b..4691eb94 100644 --- a/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts +++ b/packages/components/nodes/documentloaders/Puppeteer/Puppeteer.ts @@ -63,7 +63,8 @@ class Puppeteer_DocumentLoaders implements INode { type: 'number', optional: true, additionalParams: true, - description: 'Only used when "Get Relative Links Method" is selected. Set 0 to retrieve all relative links, default limit is 10.', + description: + 'Only used when "Get Relative Links Method" is selected. Set 0 to retrieve all relative links, default limit is 10.', warning: `Retrieving all links might take long time, and all links will be upserted again if the flow's state changed (eg: different URL, chunk size, etc)` }, { @@ -75,12 +76,12 @@ class Puppeteer_DocumentLoaders implements INode { { label: 'Load', name: 'load', - description: `When the initial HTML document\'s DOM has been loaded and parsed` + description: `When the initial HTML document's DOM has been loaded and parsed` }, { label: 'DOM Content Loaded', name: 'domcontentloaded', - description: `When the complete HTML document\'s DOM has been loaded and parsed` + description: `When the complete HTML document's DOM has been loaded and parsed` }, { label: 'Network Idle 0', @@ -102,7 +103,7 @@ class Puppeteer_DocumentLoaders implements INode { type: 'string', optional: true, additionalParams: true, - description: 'CSS selectors like .div or #div', + description: 'CSS selectors like .div or #div' }, { label: 'Metadata', @@ -136,14 +137,14 @@ class Puppeteer_DocumentLoaders implements INode { args: ['--no-sandbox'], headless: 'new' } - }; + } if (waitUntilGoToOption) { config['gotoOptions'] = { waitUntil: waitUntilGoToOption } } if (waitForSelector) { - config['evaluate'] = async (page: Page, browser: Browser): Promise => { + config['evaluate'] = async (page: Page, _: Browser): Promise => { await page.waitForSelector(waitForSelector) const result = await page.evaluate(() => document.body.innerHTML) diff --git a/packages/server/marketplaces/chatflows/WebPage QnA.json b/packages/server/marketplaces/chatflows/WebPage QnA.json index 09246150..812f0bd5 100644 --- a/packages/server/marketplaces/chatflows/WebPage QnA.json +++ b/packages/server/marketplaces/chatflows/WebPage QnA.json @@ -16,11 +16,7 @@ "version": 1, "name": "chatOpenAI", "type": "ChatOpenAI", - "baseClasses": [ - "ChatOpenAI", - "BaseChatModel", - "BaseLanguageModel" - ], + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel"], "category": "Chat Models", "description": "Wrapper around OpenAI large language models that use the Chat endpoint", "inputParams": [ @@ -28,9 +24,7 @@ "label": "Connect Credential", "name": "credential", "type": "credential", - "credentialNames": [ - "openAIApi" - ], + "credentialNames": ["openAIApi"], "id": "chatOpenAI_0-input-credential-credential" }, { @@ -176,10 +170,7 @@ "version": 1, "name": "openAIEmbeddings", "type": "OpenAIEmbeddings", - "baseClasses": [ - "OpenAIEmbeddings", - "Embeddings" - ], + "baseClasses": ["OpenAIEmbeddings", "Embeddings"], "category": "Embeddings", "description": "OpenAI API to generate embeddings for a given text", "inputParams": [ @@ -187,9 +178,7 @@ "label": "Connect Credential", "name": "credential", "type": "credential", - "credentialNames": [ - "openAIApi" - ], + "credentialNames": ["openAIApi"], "id": "openAIEmbeddings_0-input-credential-credential" }, { @@ -329,10 +318,7 @@ "version": 1, "name": "conversationalRetrievalQAChain", "type": "ConversationalRetrievalQAChain", - "baseClasses": [ - "ConversationalRetrievalQAChain", - "BaseChain" - ], + "baseClasses": ["ConversationalRetrievalQAChain", "BaseChain"], "category": "Chains", "description": "Document QA - built on RetrievalQAChain to provide a chat history component", "inputParams": [ @@ -442,9 +428,7 @@ "version": 1, "name": "cheerioWebScraper", "type": "Document", - "baseClasses": [ - "Document" - ], + "baseClasses": ["Document"], "category": "Document Loaders", "description": "Load data from webpages", "inputParams": [ @@ -543,11 +527,7 @@ "version": 1, "name": "pineconeUpsert", "type": "Pinecone", - "baseClasses": [ - "Pinecone", - "VectorStoreRetriever", - "BaseRetriever" - ], + "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", "description": "Upsert documents to Pinecone", "inputParams": [ @@ -555,9 +535,7 @@ "label": "Connect Credential", "name": "credential", "type": "credential", - "credentialNames": [ - "pineconeApi" - ], + "credentialNames": ["pineconeApi"], "id": "pineconeUpsert_0-input-credential-credential" }, { @@ -602,9 +580,7 @@ } ], "inputs": { - "document": [ - "{{cheerioWebScraper_0.data.instance}}" - ], + "document": ["{{cheerioWebScraper_0.data.instance}}"], "embeddings": "{{openAIEmbeddings_0.data.instance}}", "pineconeIndex": "", "pineconeNamespace": "", @@ -659,11 +635,7 @@ "version": 1, "name": "motorheadMemory", "type": "MotorheadMemory", - "baseClasses": [ - "MotorheadMemory", - "BaseChatMemory", - "BaseMemory" - ], + "baseClasses": ["MotorheadMemory", "BaseChatMemory", "BaseMemory"], "category": "Memory", "description": "Use Motorhead Memory to store chat conversations", "inputParams": [ @@ -673,9 +645,7 @@ "type": "credential", "optional": true, "description": "Only needed when using hosted solution - https://getmetal.io", - "credentialNames": [ - "motorheadMemoryApi" - ], + "credentialNames": ["motorheadMemoryApi"], "id": "motorheadMemory_0-input-credential-credential" }, { @@ -798,4 +768,4 @@ } } ] -} \ No newline at end of file +} From 913b3439562e8ad7bbeae6ffcfe530736c593de6 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 16 Aug 2023 23:26:18 +0100 Subject: [PATCH 10/24] add Zep VS and update Zep Memory --- .../nodes/memory/ZepMemory/ZepMemory.ts | 20 +- .../components/nodes/memory/ZepMemory/zep.png | Bin 17169 -> 25127 bytes .../nodes/vectorstores/Zep/Zep_Existing.ts | 235 ++++++++++++++++++ .../nodes/vectorstores/Zep/Zep_Upsert.ts | 133 ++++++++++ .../components/nodes/vectorstores/Zep/zep.png | Bin 0 -> 25127 bytes packages/components/package.json | 4 +- 6 files changed, 372 insertions(+), 20 deletions(-) create mode 100644 packages/components/nodes/vectorstores/Zep/Zep_Existing.ts create mode 100644 packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts create mode 100644 packages/components/nodes/vectorstores/Zep/zep.png diff --git a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts index f2a47852..0c05563a 100644 --- a/packages/components/nodes/memory/ZepMemory/ZepMemory.ts +++ b/packages/components/nodes/memory/ZepMemory/ZepMemory.ts @@ -120,7 +120,8 @@ class ZepMemory_Memory implements INode { zep.loadMemoryVariables = async (values) => { let data = await tmpFunc.bind(zep, values)() if (autoSummary && zep.returnMessages && data[zep.memoryKey] && data[zep.memoryKey].length) { - const memory = await zep.zepClient.getMemory(zep.sessionId, parseInt(k, 10) ?? 10) + const zepClient = await zep.zepClientPromise + const memory = await zepClient.memory.getMemory(zep.sessionId, parseInt(k, 10) ?? 10) if (memory?.summary) { let summary = autoSummaryTemplate.replace(/{summary}/g, memory.summary.content) // eslint-disable-next-line no-console @@ -190,23 +191,6 @@ class ZepMemoryExtended extends ZepMemory { super(fields) this.isSessionIdUsingChatMessageId = fields.isSessionIdUsingChatMessageId } - - async clear(): Promise { - // Only clear when sessionId is using chatId - // If sessionId is specified, clearing and inserting again will error because the sessionId has been soft deleted - // If using chatId, it will not be a problem because the sessionId will always be the new chatId - if (this.isSessionIdUsingChatMessageId) { - try { - await this.zepClient.deleteMemory(this.sessionId) - } catch (error) { - console.error('Error deleting session: ', error) - } - - // Clear the superclass's chat history - await super.clear() - } - await this.chatHistory.clear() - } } module.exports = { nodeClass: ZepMemory_Memory } diff --git a/packages/components/nodes/memory/ZepMemory/zep.png b/packages/components/nodes/memory/ZepMemory/zep.png index 293be6f6de9a238631d52059b16c90aa8e395fdb..2fdb238271c40ec0de48c196b92f14115c944dbf 100644 GIT binary patch literal 25127 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 Y|Gacjls{jx3;+NC07*qoM6N<$f`z|uM*si- diff --git a/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts b/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts new file mode 100644 index 00000000..a2c2261f --- /dev/null +++ b/packages/components/nodes/vectorstores/Zep/Zep_Existing.ts @@ -0,0 +1,235 @@ +import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { ZepVectorStore, IZepConfig } from 'langchain/vectorstores/zep' +import { Embeddings } from 'langchain/embeddings/base' +import { Document } from 'langchain/document' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { IDocument, ZepClient } from '@getzep/zep-js' + +class Zep_Existing_VectorStores implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Zep Load Existing Index' + this.name = 'zepExistingIndex' + this.version = 1.0 + this.type = 'Zep' + this.icon = 'zep.png' + this.category = 'Vector Stores' + this.description = 'Load existing index from Zep (i.e: Document has been upserted)' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + description: 'Configure JWT authentication on your Zep instance (Optional)', + credentialNames: ['zepMemoryApi'] + } + this.inputs = [ + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Base URL', + name: 'baseURL', + type: 'string', + default: 'http://127.0.0.1:8000' + }, + { + label: 'Zep Collection', + name: 'zepCollection', + type: 'string', + placeholder: 'my-first-collection' + }, + { + label: 'Zep Metadata Filter', + name: 'zepMetadataFilter', + type: 'json', + optional: true, + additionalParams: true + }, + { + label: 'Embedding Dimension', + name: 'dimension', + type: 'number', + default: 1536, + additionalParams: true + }, + { + label: 'Top K', + name: 'topK', + description: 'Number of top results to fetch. Default to 4', + placeholder: '4', + type: 'number', + additionalParams: true, + optional: true + } + ] + this.outputs = [ + { + label: 'Pinecone Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Pinecone Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(ZepVectorStore)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const baseURL = nodeData.inputs?.baseURL as string + const zepCollection = nodeData.inputs?.zepCollection as string + 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) + + const zepConfig: IZepConfig & Partial = { + apiUrl: baseURL, + collectionName: zepCollection, + embeddingDimensions: dimension, + isAutoEmbedded: false + } + if (apiKey) zepConfig.apiKey = apiKey + if (zepMetadataFilter) { + const metadatafilter = typeof zepMetadataFilter === 'object' ? zepMetadataFilter : JSON.parse(zepMetadataFilter) + zepConfig.filter = metadatafilter + } + + 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 + } +} + +interface ZepFilter { + filter: Record +} + +function zepDocsToDocumentsAndScore(results: IDocument[]): [Document, number][] { + return results.map((d) => [ + new Document({ + pageContent: d.content, + metadata: d.metadata + }), + d.score ? d.score : 0 + ]) +} + +function assignMetadata(value: string | Record | object | undefined): Record | undefined { + if (typeof value === 'object' && value !== null) { + return value as Record + } + if (value !== undefined) { + console.warn('Metadata filters must be an object, Record, or undefined.') + } + return undefined +} + +class ZepExistingVS extends ZepVectorStore { + filter?: Record + args?: IZepConfig & Partial + + constructor(embeddings: Embeddings, args: IZepConfig & Partial) { + super(embeddings, args) + this.filter = args.filter + this.args = args + } + + async initalizeCollection(args: IZepConfig & Partial) { + this.client = await ZepClient.init(args.apiUrl, args.apiKey) + try { + this.collection = await this.client.document.getCollection(args.collectionName) + } catch (err) { + if (err instanceof Error) { + if (err.name === 'NotFoundError') { + await this.createNewCollection(args) + } else { + throw err + } + } + } + } + + async createNewCollection(args: IZepConfig & Partial) { + if (!args.embeddingDimensions) { + throw new Error( + `Collection ${args.collectionName} not found. You can create a new Collection by providing embeddingDimensions.` + ) + } + + this.collection = await this.client.document.addCollection({ + name: args.collectionName, + description: args.description, + metadata: args.metadata, + embeddingDimensions: args.embeddingDimensions, + isAutoEmbedded: false + }) + } + + async similaritySearchVectorWithScore( + query: number[], + k: number, + filter?: Record | undefined + ): Promise<[Document, number][]> { + if (filter && this.filter) { + throw new Error('cannot provide both `filter` and `this.filter`') + } + const _filters = filter ?? this.filter + const ANDFilters = [] + for (const filterKey in _filters) { + let filterVal = _filters[filterKey] + if (typeof filterVal === 'string') filterVal = `"${filterVal}"` + ANDFilters.push({ jsonpath: `$[*] ? (@.${filterKey} == ${filterVal})` }) + } + const newfilter = { + where: { and: ANDFilters } + } + await this.initalizeCollection(this.args!).catch((err) => { + console.error('Error initializing collection:', err) + throw err + }) + const results = await this.collection.search( + { + embedding: new Float32Array(query), + metadata: assignMetadata(newfilter) + }, + k + ) + return zepDocsToDocumentsAndScore(results) + } + + static async fromExistingIndex(embeddings: Embeddings, dbConfig: IZepConfig & Partial): Promise { + const instance = new this(embeddings, dbConfig) + return instance + } +} + +module.exports = { nodeClass: Zep_Existing_VectorStores } diff --git a/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts b/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts new file mode 100644 index 00000000..0f976d2b --- /dev/null +++ b/packages/components/nodes/vectorstores/Zep/Zep_Upsert.ts @@ -0,0 +1,133 @@ +import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { ZepVectorStore, IZepConfig } from 'langchain/vectorstores/zep' +import { Embeddings } from 'langchain/embeddings/base' +import { Document } from 'langchain/document' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { flatten } from 'lodash' + +class Zep_Upsert_VectorStores implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Zep Upsert Document' + this.name = 'zepUpsert' + this.version = 1.0 + this.type = 'Zep' + this.icon = 'zep.png' + this.category = 'Vector Stores' + this.description = 'Upsert documents to Zep' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + description: 'Configure JWT authentication on your Zep instance (Optional)', + credentialNames: ['zepMemoryApi'] + } + this.inputs = [ + { + label: 'Document', + name: 'document', + type: 'Document', + list: true + }, + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Base URL', + name: 'baseURL', + type: 'string', + default: 'http://127.0.0.1:8000' + }, + { + label: 'Zep Collection', + name: 'zepCollection', + type: 'string', + placeholder: 'my-first-collection' + }, + { + label: 'Embedding Dimension', + name: 'dimension', + type: 'number', + default: 1536, + additionalParams: true + }, + { + label: 'Top K', + name: 'topK', + description: 'Number of top results to fetch. Default to 4', + placeholder: '4', + type: 'number', + additionalParams: true, + optional: true + } + ] + this.outputs = [ + { + label: 'Zep Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Zep Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(ZepVectorStore)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + const baseURL = nodeData.inputs?.baseURL as string + const zepCollection = nodeData.inputs?.zepCollection as string + const dimension = (nodeData.inputs?.dimension as number) ?? 1536 + const docs = nodeData.inputs?.document as Document[] + const embeddings = nodeData.inputs?.embeddings as Embeddings + const topK = nodeData.inputs?.topK as string + const k = topK ? parseFloat(topK) : 4 + const output = nodeData.outputs?.output as string + + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const apiKey = getCredentialParam('apiKey', credentialData, nodeData) + + const flattenDocs = docs && docs.length ? flatten(docs) : [] + const finalDocs = [] + for (let i = 0; i < flattenDocs.length; i += 1) { + finalDocs.push(new Document(flattenDocs[i])) + } + + const zepConfig: IZepConfig = { + apiUrl: baseURL, + collectionName: zepCollection, + embeddingDimensions: dimension, + isAutoEmbedded: false + } + if (apiKey) zepConfig.apiKey = apiKey + + const vectorStore = await ZepVectorStore.fromDocuments(finalDocs, 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 + } +} + +module.exports = { nodeClass: Zep_Upsert_VectorStores } diff --git a/packages/components/nodes/vectorstores/Zep/zep.png b/packages/components/nodes/vectorstores/Zep/zep.png new file mode 100644 index 0000000000000000000000000000000000000000..2fdb238271c40ec0de48c196b92f14115c944dbf GIT binary patch literal 25127 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 av;QB=>6btFOcTZc0000 Date: Wed, 16 Aug 2023 20:07:22 -0300 Subject: [PATCH 11/24] Added BaseOptions to ChatOpenAI --- .../nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts index 9512da66..ca081ff4 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts @@ -125,6 +125,13 @@ class ChatOpenAI_ChatModels implements INode { type: 'string', optional: true, additionalParams: true + }, + { + label: 'BaseOptions', + name: 'baseOptions', + type: 'json', + optional: true, + additionalParams: true } ] } @@ -139,6 +146,7 @@ class ChatOpenAI_ChatModels implements INode { const timeout = nodeData.inputs?.timeout as string const streaming = nodeData.inputs?.streaming as boolean const basePath = nodeData.inputs?.basepath as string + const baseOptions = nodeData.inputs?.baseOptions const credentialData = await getCredentialData(nodeData.credential ?? '', options) const openAIApiKey = getCredentialParam('openAIApiKey', credentialData, nodeData) @@ -156,8 +164,18 @@ class ChatOpenAI_ChatModels implements INode { if (presencePenalty) obj.presencePenalty = parseFloat(presencePenalty) if (timeout) obj.timeout = parseInt(timeout, 10) + let parsedBaseOptions: any | undefined = undefined + + if (baseOptions) { + try { + parsedBaseOptions = typeof baseOptions === 'object' ? baseOptions : JSON.parse(baseOptions) + } catch (exception) { + throw new Error("Invalid JSON in the ChatOpenAI's BaseOptions: " + exception) + } + } const model = new ChatOpenAI(obj, { - basePath + basePath, + baseOptions: parsedBaseOptions }) return model } From c33a4a78d664839c947799e318443dcff42edd14 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 17 Aug 2023 16:15:00 +0100 Subject: [PATCH 12/24] fix source link return host name --- packages/ui/src/views/chatmessage/ChatMessage.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/views/chatmessage/ChatMessage.js b/packages/ui/src/views/chatmessage/ChatMessage.js index 98eef72a..506f02da 100644 --- a/packages/ui/src/views/chatmessage/ChatMessage.js +++ b/packages/ui/src/views/chatmessage/ChatMessage.js @@ -346,7 +346,9 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => { key={index} label={ URL - ? `${URL.pathname.substring(0, 15)}...` + ? URL.pathname.substring(0, 15) === '/' + ? URL.host + : `${URL.pathname.substring(0, 15)}...` : `${source.pageContent.substring(0, 15)}...` } component='a' From ab60a6bda1b5c6cdd1649bae21a91aca04bab6d3 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 17 Aug 2023 18:38:38 +0100 Subject: [PATCH 13/24] enable faiss streaming --- .../Faiss_Existing/Faiss_Existing.ts | 18 ++++++++++++ .../vectorstores/Faiss_Upsert/Faiss_Upsert.ts | 17 +++++++++++ packages/server/src/index.ts | 2 -- packages/server/src/utils/index.ts | 28 ++----------------- 4 files changed, 37 insertions(+), 28 deletions(-) diff --git a/packages/components/nodes/vectorstores/Faiss_Existing/Faiss_Existing.ts b/packages/components/nodes/vectorstores/Faiss_Existing/Faiss_Existing.ts index 8c8d03a8..15d476d8 100644 --- a/packages/components/nodes/vectorstores/Faiss_Existing/Faiss_Existing.ts +++ b/packages/components/nodes/vectorstores/Faiss_Existing/Faiss_Existing.ts @@ -2,6 +2,7 @@ import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/I import { FaissStore } from 'langchain/vectorstores/faiss' import { Embeddings } from 'langchain/embeddings/base' import { getBaseClasses } from '../../../src/utils' +import { Document } from 'langchain/document' class Faiss_Existing_VectorStores implements INode { label: string @@ -70,6 +71,23 @@ class Faiss_Existing_VectorStores implements INode { const vectorStore = await FaissStore.load(basePath, embeddings) + // Avoid illegal invocation error + vectorStore.similaritySearchVectorWithScore = async (query: number[], k: number) => { + const index = vectorStore.index + + if (k > index.ntotal()) { + const total = index.ntotal() + console.warn(`k (${k}) is greater than the number of elements in the index (${total}), setting k to ${total}`) + k = total + } + + const result = index.search(query, k) + return result.labels.map((id, index) => { + const uuid = vectorStore._mapping[id] + return [vectorStore.docstore.search(uuid), result.distances[index]] as [Document, number] + }) + } + if (output === 'retriever') { const retriever = vectorStore.asRetriever(k) return retriever diff --git a/packages/components/nodes/vectorstores/Faiss_Upsert/Faiss_Upsert.ts b/packages/components/nodes/vectorstores/Faiss_Upsert/Faiss_Upsert.ts index f56eccdf..c234a4f5 100644 --- a/packages/components/nodes/vectorstores/Faiss_Upsert/Faiss_Upsert.ts +++ b/packages/components/nodes/vectorstores/Faiss_Upsert/Faiss_Upsert.ts @@ -86,6 +86,23 @@ class FaissUpsert_VectorStores implements INode { const vectorStore = await FaissStore.fromDocuments(finalDocs, embeddings) await vectorStore.save(basePath) + // Avoid illegal invocation error + vectorStore.similaritySearchVectorWithScore = async (query: number[], k: number) => { + const index = vectorStore.index + + if (k > index.ntotal()) { + const total = index.ntotal() + console.warn(`k (${k}) is greater than the number of elements in the index (${total}), setting k to ${total}`) + k = total + } + + const result = index.search(query, k) + return result.labels.map((id, index) => { + const uuid = vectorStore._mapping[id] + return [vectorStore.docstore.search(uuid), result.distances[index]] as [Document, number] + }) + } + if (output === 'retriever') { const retriever = vectorStore.asRetriever(k) return retriever diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index fbb61b00..23b5bdf4 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -36,7 +36,6 @@ import { isSameOverrideConfig, replaceAllAPIKeys, isFlowValidForStream, - isVectorStoreFaiss, databaseEntities, getApiKey, transformToCredentialEntity, @@ -911,7 +910,6 @@ export class App { const nodeModule = await import(nodeInstanceFilePath) const nodeInstance = new nodeModule.nodeClass() - isStreamValid = isStreamValid && !isVectorStoreFaiss(nodeToExecuteData) logger.debug(`[server]: Running ${nodeToExecuteData.label} (${nodeToExecuteData.id})`) if (nodeToExecuteData.instance) checkMemorySessionId(nodeToExecuteData.instance, chatId) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 788b7c0e..9be26987 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -18,7 +18,7 @@ import { IComponentCredentials, ICredentialReqBody } from '../Interface' -import { cloneDeep, get, omit, merge, isEqual } from 'lodash' +import { cloneDeep, get, isEqual } from 'lodash' import { ICommonObject, getInputVariables, @@ -393,25 +393,6 @@ export const getVariableValue = ( return returnVal } -/** - * Temporarily disable streaming if vectorStore is Faiss - * @param {INodeData} flowNodeData - * @returns {boolean} - */ -export const isVectorStoreFaiss = (flowNodeData: INodeData) => { - if (flowNodeData.inputs && flowNodeData.inputs.vectorStoreRetriever) { - const vectorStoreRetriever = flowNodeData.inputs.vectorStoreRetriever - if (typeof vectorStoreRetriever === 'string' && vectorStoreRetriever.includes('faiss')) return true - if ( - typeof vectorStoreRetriever === 'object' && - vectorStoreRetriever.vectorStore && - vectorStoreRetriever.vectorStore.constructor.name === 'FaissStore' - ) - return true - } - return false -} - /** * Loop through each inputs and resolve variable if neccessary * @param {INodeData} reactFlowNodeData @@ -426,11 +407,6 @@ export const resolveVariables = ( chatHistory: IMessage[] ): INodeData => { let flowNodeData = cloneDeep(reactFlowNodeData) - if (reactFlowNodeData.instance && isVectorStoreFaiss(reactFlowNodeData)) { - // omit and merge because cloneDeep of instance gives "Illegal invocation" Exception - const flowNodeDataWithoutInstance = cloneDeep(omit(reactFlowNodeData, ['instance'])) - flowNodeData = merge(flowNodeDataWithoutInstance, { instance: reactFlowNodeData.instance }) - } const types = 'inputs' const getParamValues = (paramsObj: ICommonObject) => { @@ -819,7 +795,7 @@ export const isFlowValidForStream = (reactFlowNodes: IReactFlowNode[], endingNod isValidChainOrAgent = whitelistAgents.includes(endingNodeData.name) } - return isChatOrLLMsExist && isValidChainOrAgent && !isVectorStoreFaiss(endingNodeData) + return isChatOrLLMsExist && isValidChainOrAgent } /** From b4c2550c77dc28cc7c96c8a8a48a6b9234d1fa60 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 17 Aug 2023 21:23:40 +0100 Subject: [PATCH 14/24] add Milvus --- .../credentials/MilvusAuth.credential.ts | 31 ++ .../vectorstores/Milvus/Milvus_Existing.ts | 185 ++++++++++++ .../vectorstores/Milvus/Milvus_Upsert.ts | 281 ++++++++++++++++++ .../nodes/vectorstores/Milvus/milvus.svg | 5 + .../Milvus_Existing/Milvus_Existing.ts | 132 -------- .../vectorstores/Milvus_Existing/milvus.jpg | Bin 9320 -> 0 bytes .../Milvus_Upsert/Milvus_Upsert.ts | 148 --------- .../vectorstores/Milvus_Upsert/milvus.jpg | Bin 9320 -> 0 bytes packages/components/package.json | 1 + 9 files changed, 503 insertions(+), 280 deletions(-) create mode 100644 packages/components/credentials/MilvusAuth.credential.ts create mode 100644 packages/components/nodes/vectorstores/Milvus/Milvus_Existing.ts create mode 100644 packages/components/nodes/vectorstores/Milvus/Milvus_Upsert.ts create mode 100644 packages/components/nodes/vectorstores/Milvus/milvus.svg delete mode 100644 packages/components/nodes/vectorstores/Milvus_Existing/Milvus_Existing.ts delete mode 100644 packages/components/nodes/vectorstores/Milvus_Existing/milvus.jpg delete mode 100644 packages/components/nodes/vectorstores/Milvus_Upsert/Milvus_Upsert.ts delete mode 100644 packages/components/nodes/vectorstores/Milvus_Upsert/milvus.jpg diff --git a/packages/components/credentials/MilvusAuth.credential.ts b/packages/components/credentials/MilvusAuth.credential.ts new file mode 100644 index 00000000..b94e1fc8 --- /dev/null +++ b/packages/components/credentials/MilvusAuth.credential.ts @@ -0,0 +1,31 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class MilvusCredential implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Milvus Auth' + this.name = 'milvusAuth' + this.version = 1.0 + this.description = + 'You can find the Milvus Authentication from here page.' + this.inputs = [ + { + label: 'Milvus User', + name: 'milvusUser', + type: 'string' + }, + { + label: 'Milvus Password', + name: 'milvusPassword', + type: 'password' + } + ] + } +} + +module.exports = { credClass: MilvusCredential } diff --git a/packages/components/nodes/vectorstores/Milvus/Milvus_Existing.ts b/packages/components/nodes/vectorstores/Milvus/Milvus_Existing.ts new file mode 100644 index 00000000..514fdc73 --- /dev/null +++ b/packages/components/nodes/vectorstores/Milvus/Milvus_Existing.ts @@ -0,0 +1,185 @@ +import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { DataType, ErrorCode } from '@zilliz/milvus2-sdk-node' +import { MilvusLibArgs, Milvus } from 'langchain/vectorstores/milvus' +import { Embeddings } from 'langchain/embeddings/base' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { Document } from 'langchain/document' + +class Milvus_Existing_VectorStores implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Milvus Load Existing collection' + this.name = 'milvusExistingCollection' + this.version = 1.0 + this.type = 'Milvus' + this.icon = 'milvus.svg' + this.category = 'Vector Stores' + this.description = 'Load existing collection from Milvus (i.e: Document has been upserted)' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + credentialNames: ['milvusAuth'] + } + this.inputs = [ + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Milvus Server URL', + name: 'milvusServerUrl', + type: 'string', + placeholder: 'http://localhost:19530' + }, + { + label: 'Milvus Collection Name', + name: 'milvusCollection', + type: 'string' + } + ] + this.outputs = [ + { + label: 'Milvus Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Milvus Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(Milvus)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + // server setup + const address = nodeData.inputs?.milvusServerUrl as string + const collectionName = nodeData.inputs?.milvusCollection as string + + // embeddings + const embeddings = nodeData.inputs?.embeddings as Embeddings + const topK = nodeData.inputs?.topK as string + + // output + const output = nodeData.outputs?.output as string + + // format data + const k = topK ? parseInt(topK, 10) : 4 + + // credential + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const milvusUser = getCredentialParam('milvusUser', credentialData, nodeData) + const milvusPassword = getCredentialParam('milvusPassword', credentialData, nodeData) + + // init MilvusLibArgs + const milVusArgs: MilvusLibArgs = { + url: address, + collectionName: collectionName + } + + if (milvusUser) milVusArgs.username = milvusUser + if (milvusPassword) milVusArgs.password = milvusPassword + + const vectorStore = await Milvus.fromExistingCollection(embeddings, milVusArgs) + + // Avoid Illegal Invocation + vectorStore.similaritySearchVectorWithScore = async (query: number[], k: number, filter?: string) => { + const hasColResp = await vectorStore.client.hasCollection({ + collection_name: vectorStore.collectionName + }) + if (hasColResp.status.error_code !== ErrorCode.SUCCESS) { + throw new Error(`Error checking collection: ${hasColResp}`) + } + if (hasColResp.value === false) { + throw new Error(`Collection not found: ${vectorStore.collectionName}, please create collection before search.`) + } + + const filterStr = filter ?? '' + + await vectorStore.grabCollectionFields() + + const loadResp = await vectorStore.client.loadCollectionSync({ + collection_name: vectorStore.collectionName + }) + + if (loadResp.error_code !== ErrorCode.SUCCESS) { + throw new Error(`Error loading collection: ${loadResp}`) + } + + const outputFields = vectorStore.fields.filter((field) => field !== vectorStore.vectorField) + + const searchResp = await vectorStore.client.search({ + collection_name: vectorStore.collectionName, + search_params: { + anns_field: vectorStore.vectorField, + topk: k.toString(), + metric_type: vectorStore.indexCreateParams.metric_type, + params: vectorStore.indexSearchParams + }, + output_fields: outputFields, + vector_type: DataType.FloatVector, + vectors: [query], + filter: filterStr + }) + if (searchResp.status.error_code !== ErrorCode.SUCCESS) { + throw new Error(`Error searching data: ${JSON.stringify(searchResp)}`) + } + const results: [Document, number][] = [] + searchResp.results.forEach((result) => { + const fields = { + pageContent: '', + metadata: {} as Record + } + Object.keys(result).forEach((key) => { + if (key === vectorStore.textField) { + fields.pageContent = result[key] + } else if (vectorStore.fields.includes(key) || key === vectorStore.primaryField) { + if (typeof result[key] === 'string') { + const { isJson, obj } = checkJsonString(result[key]) + fields.metadata[key] = isJson ? obj : result[key] + } else { + fields.metadata[key] = result[key] + } + } + }) + results.push([new Document(fields), result.score]) + }) + return results + } + + if (output === 'retriever') { + const retriever = vectorStore.asRetriever(k) + return retriever + } else if (output === 'vectorStore') { + ;(vectorStore as any).k = k + return vectorStore + } + return vectorStore + } +} + +function checkJsonString(value: string): { isJson: boolean; obj: any } { + try { + const result = JSON.parse(value) + return { isJson: true, obj: result } + } catch (e) { + return { isJson: false, obj: null } + } +} + +module.exports = { nodeClass: Milvus_Existing_VectorStores } diff --git a/packages/components/nodes/vectorstores/Milvus/Milvus_Upsert.ts b/packages/components/nodes/vectorstores/Milvus/Milvus_Upsert.ts new file mode 100644 index 00000000..ca69cb39 --- /dev/null +++ b/packages/components/nodes/vectorstores/Milvus/Milvus_Upsert.ts @@ -0,0 +1,281 @@ +import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { DataType, ErrorCode, MetricType, IndexType } from '@zilliz/milvus2-sdk-node' +import { MilvusLibArgs, Milvus } from 'langchain/vectorstores/milvus' +import { Embeddings } from 'langchain/embeddings/base' +import { Document } from 'langchain/document' +import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' +import { flatten } from 'lodash' + +interface InsertRow { + [x: string]: string | number[] +} + +class Milvus_Upsert_VectorStores implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + credential: INodeParams + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'Milvus Upsert Document' + this.name = 'milvusUpsert' + this.version = 1.0 + this.type = 'Milvus' + this.icon = 'milvus.svg' + this.category = 'Vector Stores' + this.description = 'Upsert documents to Milvus' + this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + optional: true, + credentialNames: ['milvusAuth'] + } + this.inputs = [ + { + label: 'Document', + name: 'document', + type: 'Document', + list: true + }, + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Milvus Server URL', + name: 'milvusServerUrl', + type: 'string', + placeholder: 'http://localhost:19530' + }, + { + label: 'Milvus Collection Name', + name: 'milvusCollection', + type: 'string' + } + ] + this.outputs = [ + { + label: 'Milvus Retriever', + name: 'retriever', + baseClasses: this.baseClasses + }, + { + label: 'Milvus Vector Store', + name: 'vectorStore', + baseClasses: [this.type, ...getBaseClasses(Milvus)] + } + ] + } + + async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { + // server setup + const address = nodeData.inputs?.milvusServerUrl as string + const collectionName = nodeData.inputs?.milvusCollection as string + + // embeddings + const docs = nodeData.inputs?.document as Document[] + const embeddings = nodeData.inputs?.embeddings as Embeddings + const topK = nodeData.inputs?.topK as string + + // output + const output = nodeData.outputs?.output as string + + // format data + const k = topK ? parseInt(topK, 10) : 4 + + // credential + const credentialData = await getCredentialData(nodeData.credential ?? '', options) + const milvusUser = getCredentialParam('milvusUser', credentialData, nodeData) + const milvusPassword = getCredentialParam('milvusPassword', credentialData, nodeData) + + // init MilvusLibArgs + const milVusArgs: MilvusLibArgs = { + url: address, + collectionName: collectionName + } + + if (milvusUser) milVusArgs.username = milvusUser + if (milvusPassword) milVusArgs.password = milvusPassword + + const flattenDocs = docs && docs.length ? flatten(docs) : [] + const finalDocs = [] + for (let i = 0; i < flattenDocs.length; i += 1) { + finalDocs.push(new Document(flattenDocs[i])) + } + + const vectorStore = await MilvusUpsert.fromDocuments(finalDocs, embeddings, milVusArgs) + + // Avoid Illegal Invocation + vectorStore.similaritySearchVectorWithScore = async (query: number[], k: number, filter?: string) => { + const hasColResp = await vectorStore.client.hasCollection({ + collection_name: vectorStore.collectionName + }) + if (hasColResp.status.error_code !== ErrorCode.SUCCESS) { + throw new Error(`Error checking collection: ${hasColResp}`) + } + if (hasColResp.value === false) { + throw new Error(`Collection not found: ${vectorStore.collectionName}, please create collection before search.`) + } + + const filterStr = filter ?? '' + + await vectorStore.grabCollectionFields() + + const loadResp = await vectorStore.client.loadCollectionSync({ + collection_name: vectorStore.collectionName + }) + if (loadResp.error_code !== ErrorCode.SUCCESS) { + throw new Error(`Error loading collection: ${loadResp}`) + } + + const outputFields = vectorStore.fields.filter((field) => field !== vectorStore.vectorField) + + const searchResp = await vectorStore.client.search({ + collection_name: vectorStore.collectionName, + search_params: { + anns_field: vectorStore.vectorField, + topk: k.toString(), + metric_type: vectorStore.indexCreateParams.metric_type, + params: vectorStore.indexSearchParams + }, + output_fields: outputFields, + vector_type: DataType.FloatVector, + vectors: [query], + filter: filterStr + }) + if (searchResp.status.error_code !== ErrorCode.SUCCESS) { + throw new Error(`Error searching data: ${JSON.stringify(searchResp)}`) + } + const results: [Document, number][] = [] + searchResp.results.forEach((result) => { + const fields = { + pageContent: '', + metadata: {} as Record + } + Object.keys(result).forEach((key) => { + if (key === vectorStore.textField) { + fields.pageContent = result[key] + } else if (vectorStore.fields.includes(key) || key === vectorStore.primaryField) { + if (typeof result[key] === 'string') { + const { isJson, obj } = checkJsonString(result[key]) + fields.metadata[key] = isJson ? obj : result[key] + } else { + fields.metadata[key] = result[key] + } + } + }) + results.push([new Document(fields), result.score]) + }) + return results + } + + if (output === 'retriever') { + const retriever = vectorStore.asRetriever(k) + return retriever + } else if (output === 'vectorStore') { + ;(vectorStore as any).k = k + return vectorStore + } + return vectorStore + } +} + +function checkJsonString(value: string): { isJson: boolean; obj: any } { + try { + const result = JSON.parse(value) + return { isJson: true, obj: result } + } catch (e) { + return { isJson: false, obj: null } + } +} + +class MilvusUpsert extends Milvus { + async addVectors(vectors: number[][], documents: Document[]): Promise { + if (vectors.length === 0) { + return + } + await this.ensureCollection(vectors, documents) + + const insertDatas: InsertRow[] = [] + + for (let index = 0; index < vectors.length; index++) { + const vec = vectors[index] + const doc = documents[index] + const data: InsertRow = { + [this.textField]: doc.pageContent, + [this.vectorField]: vec + } + this.fields.forEach((field) => { + switch (field) { + case this.primaryField: + if (!this.autoId) { + if (doc.metadata[this.primaryField] === undefined) { + throw new Error( + `The Collection's primaryField is configured with autoId=false, thus its value must be provided through metadata.` + ) + } + data[field] = doc.metadata[this.primaryField] + } + break + case this.textField: + data[field] = doc.pageContent + break + case this.vectorField: + data[field] = vec + break + default: // metadata fields + if (doc.metadata[field] === undefined) { + throw new Error(`The field "${field}" is not provided in documents[${index}].metadata.`) + } else if (typeof doc.metadata[field] === 'object') { + data[field] = JSON.stringify(doc.metadata[field]) + } else { + data[field] = doc.metadata[field] + } + break + } + }) + + insertDatas.push(data) + } + + const descIndexResp = await this.client.describeIndex({ + collection_name: this.collectionName + }) + + if (descIndexResp.status.error_code === ErrorCode.INDEX_NOT_EXIST) { + const resp = await this.client.createIndex({ + collection_name: this.collectionName, + field_name: this.vectorField, + index_name: `myindex_${Date.now().toString()}`, + index_type: IndexType.AUTOINDEX, + metric_type: MetricType.L2 + }) + if (resp.error_code !== ErrorCode.SUCCESS) { + throw new Error(`Error creating index`) + } + } + + const insertResp = await this.client.insert({ + collection_name: this.collectionName, + fields_data: insertDatas + }) + + if (insertResp.status.error_code !== ErrorCode.SUCCESS) { + throw new Error(`Error inserting data: ${JSON.stringify(insertResp)}`) + } + + await this.client.flushSync({ collection_names: [this.collectionName] }) + } +} + +module.exports = { nodeClass: Milvus_Upsert_VectorStores } diff --git a/packages/components/nodes/vectorstores/Milvus/milvus.svg b/packages/components/nodes/vectorstores/Milvus/milvus.svg new file mode 100644 index 00000000..68dfef66 --- /dev/null +++ b/packages/components/nodes/vectorstores/Milvus/milvus.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/components/nodes/vectorstores/Milvus_Existing/Milvus_Existing.ts b/packages/components/nodes/vectorstores/Milvus_Existing/Milvus_Existing.ts deleted file mode 100644 index ebfd566c..00000000 --- a/packages/components/nodes/vectorstores/Milvus_Existing/Milvus_Existing.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' -import { Milvus, MilvusLibArgs } from 'langchain/vectorstores/milvus' -import { Embeddings } from 'langchain/embeddings/base' -import { getBaseClasses } from '../../../src/utils' - -class Milvus_Existing_VectorStores implements INode { - label: string - name: string - description: string - type: string - icon: string - category: string - baseClasses: string[] - inputs: INodeParams[] - outputs: INodeOutputsValue[] - - constructor() { - this.label = 'Milvus Load Existing Index' - this.name = 'milvusExistingIndex' - this.type = 'Milvus' - this.icon = 'milvus.jpg' - this.category = 'Vector Stores' - this.description = 'Load existing index from Milvus (i.e: Document has been upserted)' - this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] - this.inputs = [ - { - label: 'Embeddings', - name: 'embeddings', - type: 'Embeddings' - }, - { - label: 'Collection Name', - name: 'milvusCollectionName', - type: 'string', - placeholder: 'my-milvus-collection' - }, - { - label: 'Milvus URL', - name: 'milvusURL', - type: 'string', - placeholder: 'http://localhost:19530' - }, - { - label: 'Primary Field', - name: 'milvusPrimaryField', - type: 'string', - optional: true, - additionalParams: true - }, - { - label: 'Vector Field', - name: 'milvusVectorField', - type: 'string', - optional: true, - additionalParams: true - }, - { - label: 'Vector Text Field', - name: 'milvusTextField', - type: 'string', - optional: true, - additionalParams: true - }, - { - label: 'SSL', - name: 'milvusSSL', - type: 'boolean', - optional: true, - additionalParams: true - }, - { - label: 'Username', - name: 'milvusUsername', - type: 'string', - optional: true, - additionalParams: true - }, - { - label: 'Password', - name: 'milvusPassword', - type: 'password', - optional: true, - additionalParams: true - } - ] - this.outputs = [ - { - label: 'Milvus Retriever', - name: 'retriever', - baseClasses: this.baseClasses - }, - { - label: 'Milvus Vector Store', - name: 'vectorStore', - baseClasses: [this.type, ...getBaseClasses(Milvus)] - } - ] - } - - async init(nodeData: INodeData): Promise { - const collectionName = nodeData.inputs?.milvusCollectionName as string - const embeddings = nodeData.inputs?.embeddings as Embeddings - const milvusURL = nodeData.inputs?.milvusURL as string - const milvusPrimaryField = nodeData.inputs?.milvusPrimaryField as string - const milvusVectorField = nodeData.inputs?.milvusVectorField as string - const milvusTextField = nodeData.inputs?.milvusTextField as string - const milvusSSL = nodeData.inputs?.milvusSSL as boolean - const milvusUsername = nodeData.inputs?.milvusUsername as string - const milvusPassword = nodeData.inputs?.milvusPassword as string - const output = nodeData.outputs?.output as string - - const obj: MilvusLibArgs = { collectionName, url: milvusURL } - if (milvusPrimaryField) obj.primaryField = milvusPrimaryField - if (milvusVectorField) obj.vectorField = milvusVectorField - if (milvusTextField) obj.textField = milvusTextField - if (milvusSSL) obj.ssl = milvusSSL - if (milvusUsername) obj.username = milvusUsername - if (milvusPassword) obj.password = milvusPassword - - const vectorStore = await Milvus.fromExistingCollection(embeddings, obj) - - if (output === 'retriever') { - const retriever = vectorStore.asRetriever() - return retriever - } else if (output === 'vectorStore') { - return vectorStore - } - return vectorStore - } -} - -module.exports = { nodeClass: Milvus_Existing_VectorStores } diff --git a/packages/components/nodes/vectorstores/Milvus_Existing/milvus.jpg b/packages/components/nodes/vectorstores/Milvus_Existing/milvus.jpg deleted file mode 100644 index 20b6c3499cbcf1e451afa25cfc60887e38ab49a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9320 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 MV<_L`Jz!`ChE9Cxxxqn>pp7! zzD3u&z~sL9x+2qs5{=I7n}m)W)c_3A0e8G5<%RHn!j|kIQCq>MB=0UI9!y{MxpC;Z z%2|wfu6g5#h+@Ega4nWd2B{J`@+X}Q@y`$q;2lQ;EKFWfM8hb1P=YROJ$-YETR4Np z;I>@Ru$0qopabsa!OvbSKcg=m(Ew9GOD+bd7oK*^932-BW4}5&#OnI>#j50r-cSce zH6%$oNSXk&&PE!OR(m)}j+8agz+wbKMFT`F6dfr>mLy~u@hqx_)_N=5Ia&p%@1XYb zCrBc*Ss!B)TYE$?%7>2m$YA2zio|WSg#!%pUSN0KA=e7k$Wy*Pe`Blaf}tK1KhsBg z7)Iane)*Kz(GG#B%p#pp@o0Q$Zd9qXN`S6w+v z9Ywzu=j_+1;9ue3_wxK#DhPgMy6aT1lN(tzx-YH$uS^j9%+V%>#>r1DBLZx+^3azK zEGLCJ95tT4<#(v3=vVB1-XV#o9H%?qQ6R2VRC-0+zLaF5s~;>f;iNd0b240@hP{7r z@I615ect^0No6AJ!%$6J+3m=gB4!n5yzDP0Q>BJ#u16z^1A6b zGSiN7=slkjos-x`RA&lb0d8Fh+5p{HO+WZ#HFRBOU*H#K6}1SzMDJX0{zjnB z7Zu@$Sj2$><@EwxTOoT|T@ecVMOBR1ql$2D9m{A8Ci@zzS~pTdv{)Mc@Odb~xGRlU z)S&1?&s?H2&)x`EAEC;>wRuPW()Nf71=1kKD_jwhVPa8S)T4*?T)+8wSmvHxcYzSi z6zLv%x9rV&1%?Qp*bB4?(H@GlEC=hv2C4OxZD4hZru&eM^;vn@%P&3Db0o-BWFhluE0_7qe z-16_aJY|Zs-NKf^B8E5q7)c+Q^9r8}YdJVr@Nsy22aaiiRnlr%#s)7Pso@VdKD=2) zT?f9Aqj5)#uz6>RrRRb|gt-hT)NX5`k(%2N&OaJn;v!(FcLVU>fj(4S5%8GIA8X`r zgp3RWT0MJj75;8{KD51Xo?F_!N=y%+V{oXfWW}?VGx?fo>@k%hGy9}p75BwTqK=M^ z3VMUmGh%rwZbYX}O(o(|gWNR6@Wh;_WP$@`gZx39q+n<;>`oLbV=DR8hzbhKtCWyA zWbB^BbZIx`e2Xq1uH2sQp}HopLB`1LOnJ)lqP|^ zB;^d{fsW5HHzmS0e^L#rWQ7=~j;~#~u(Ef)EOPRmNmR)|Mz-igyse$U>8BrC;D`h) zcEx$i%O8=}LOS12_pOX*6Obu!bqwJuAP%+3u8plAl8zIO544VZ>mg39H1dobYJqU* z$`y8Il7^ZLRP0R1-6*Tg9UiX>!p)UWucBHaOiTIh__lOp@pKtm8y&jjOPeSoEpJ8D zfX017QnG?H_awY&X5B}bVBsjjUuTaS3sd07IL#a zdBR2NCv8lC%1`)4*;oXth`Ur#d?hT@T`aagCx?MM#_X}VZ_g{OQtH>N@f_@}0v(@d z2VS$Ll&mGB{g`;i-6gjtEsbhNsm`WQfomzwrd1kNy50bI60e;+ynp$jGKZ&k?T>*N z3{UME(*@{rHHw6%c2`Zb3D|Ujbw%uicg8D68sPzXPsdH+$zdX*ZnjPrVl+U(#nBMH&7*si;Tuh}2+k@yOl7h{=2 zf$7xKn>TcWnN%~>7Es#Kyz&#GB6ecy=%h^u*Uph5A0maI;IAY$bRmyj+4WZYvhYU( z(t+s4ulL&c&)!_#7T6&Zc5XOKD2da6EtRENo1iGr@mCbjH#HT}N; Dh=sww diff --git a/packages/components/nodes/vectorstores/Milvus_Upsert/Milvus_Upsert.ts b/packages/components/nodes/vectorstores/Milvus_Upsert/Milvus_Upsert.ts deleted file mode 100644 index 373327b5..00000000 --- a/packages/components/nodes/vectorstores/Milvus_Upsert/Milvus_Upsert.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' -import { Milvus, MilvusLibArgs } from 'langchain/vectorstores/milvus' -import { Embeddings } from 'langchain/embeddings/base' -import { getBaseClasses } from '../../../src/utils' -import { Document } from 'langchain/document' - -class Milvus_Upsert_VectorStores implements INode { - label: string - name: string - description: string - type: string - icon: string - category: string - baseClasses: string[] - inputs: INodeParams[] - outputs: INodeOutputsValue[] - - constructor() { - this.label = 'Milvus Upsert Document' - this.name = 'milvusUpsert' - this.type = 'Milvus' - this.icon = 'milvus.jpg' - this.category = 'Vector Stores' - this.description = 'Upsert documents to Milvus' - this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever'] - this.inputs = [ - { - label: 'Document', - name: 'document', - type: 'Document', - list: true - }, - { - label: 'Embeddings', - name: 'embeddings', - type: 'Embeddings' - }, - { - label: 'Collection Name', - name: 'milvusCollectionName', - type: 'string', - placeholder: 'my_milvus_collection' - }, - { - label: 'Milvus URL', - name: 'milvusURL', - type: 'string', - placeholder: 'http://localhost:19530' - }, - { - label: 'Primary Field', - name: 'milvusPrimaryField', - type: 'string', - optional: true, - additionalParams: true - }, - { - label: 'Vector Field', - name: 'milvusVectorField', - type: 'string', - optional: true, - additionalParams: true - }, - { - label: 'Vector Text Field', - name: 'milvusTextField', - type: 'string', - optional: true, - additionalParams: true - }, - { - label: 'SSL', - name: 'milvusSSL', - type: 'boolean', - optional: true, - additionalParams: true - }, - { - label: 'Username', - name: 'milvusUsername', - type: 'string', - placeholder: 'db_admin', - optional: true, - additionalParams: true - }, - { - label: 'Password', - name: 'milvusPassword', - type: 'password', - optional: true, - additionalParams: true - } - ] - this.outputs = [ - { - label: 'Milvus Retriever', - name: 'retriever', - baseClasses: this.baseClasses - }, - { - label: 'Milvus Vector Store', - name: 'vectorStore', - baseClasses: [this.type, ...getBaseClasses(Milvus)] - } - ] - } - - async init(nodeData: INodeData): Promise { - const collectionName = nodeData.inputs?.milvusCollectionName as string - const embeddings = nodeData.inputs?.embeddings as Embeddings - const milvusURL = nodeData.inputs?.milvusURL as string - const milvusPrimaryField = nodeData.inputs?.milvusPrimaryField as string - const milvusVectorField = nodeData.inputs?.milvusVectorField as string - const milvusTextField = nodeData.inputs?.milvusTextField as string - const milvusSSL = nodeData.inputs?.milvusSSL as boolean - const milvusUsername = nodeData.inputs?.milvusUsername as string - const milvusPassword = nodeData.inputs?.milvusPassword as string - const output = nodeData.outputs?.output as string - const docs = nodeData.inputs?.document as Document[] - - const flattenDocs = docs && docs.length ? docs.flat() : [] - const finalDocs = [] - for (let i = 0; i < flattenDocs.length; i += 1) { - finalDocs.push(new Document(flattenDocs[i])) - } - - const obj: MilvusLibArgs = { collectionName, url: milvusURL } - if (milvusPrimaryField) obj.primaryField = milvusPrimaryField - if (milvusVectorField) obj.vectorField = milvusVectorField - if (milvusTextField) obj.textField = milvusTextField - if (milvusSSL) obj.ssl = milvusSSL - if (milvusUsername) obj.username = milvusUsername - if (milvusPassword) obj.password = milvusPassword - - const vectorStore = await Milvus.fromDocuments(finalDocs, embeddings, obj) - console.log('vectorStore = ', vectorStore) - - if (output === 'retriever') { - const retriever = vectorStore.asRetriever() - return retriever - } else if (output === 'vectorStore') { - return vectorStore - } - return vectorStore - } -} - -module.exports = { nodeClass: Milvus_Upsert_VectorStores } diff --git a/packages/components/nodes/vectorstores/Milvus_Upsert/milvus.jpg b/packages/components/nodes/vectorstores/Milvus_Upsert/milvus.jpg deleted file mode 100644 index 20b6c3499cbcf1e451afa25cfc60887e38ab49a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9320 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 MV<_L`Jz!`ChE9Cxxxqn>pp7! zzD3u&z~sL9x+2qs5{=I7n}m)W)c_3A0e8G5<%RHn!j|kIQCq>MB=0UI9!y{MxpC;Z z%2|wfu6g5#h+@Ega4nWd2B{J`@+X}Q@y`$q;2lQ;EKFWfM8hb1P=YROJ$-YETR4Np z;I>@Ru$0qopabsa!OvbSKcg=m(Ew9GOD+bd7oK*^932-BW4}5&#OnI>#j50r-cSce zH6%$oNSXk&&PE!OR(m)}j+8agz+wbKMFT`F6dfr>mLy~u@hqx_)_N=5Ia&p%@1XYb zCrBc*Ss!B)TYE$?%7>2m$YA2zio|WSg#!%pUSN0KA=e7k$Wy*Pe`Blaf}tK1KhsBg z7)Iane)*Kz(GG#B%p#pp@o0Q$Zd9qXN`S6w+v z9Ywzu=j_+1;9ue3_wxK#DhPgMy6aT1lN(tzx-YH$uS^j9%+V%>#>r1DBLZx+^3azK zEGLCJ95tT4<#(v3=vVB1-XV#o9H%?qQ6R2VRC-0+zLaF5s~;>f;iNd0b240@hP{7r z@I615ect^0No6AJ!%$6J+3m=gB4!n5yzDP0Q>BJ#u16z^1A6b zGSiN7=slkjos-x`RA&lb0d8Fh+5p{HO+WZ#HFRBOU*H#K6}1SzMDJX0{zjnB z7Zu@$Sj2$><@EwxTOoT|T@ecVMOBR1ql$2D9m{A8Ci@zzS~pTdv{)Mc@Odb~xGRlU z)S&1?&s?H2&)x`EAEC;>wRuPW()Nf71=1kKD_jwhVPa8S)T4*?T)+8wSmvHxcYzSi z6zLv%x9rV&1%?Qp*bB4?(H@GlEC=hv2C4OxZD4hZru&eM^;vn@%P&3Db0o-BWFhluE0_7qe z-16_aJY|Zs-NKf^B8E5q7)c+Q^9r8}YdJVr@Nsy22aaiiRnlr%#s)7Pso@VdKD=2) zT?f9Aqj5)#uz6>RrRRb|gt-hT)NX5`k(%2N&OaJn;v!(FcLVU>fj(4S5%8GIA8X`r zgp3RWT0MJj75;8{KD51Xo?F_!N=y%+V{oXfWW}?VGx?fo>@k%hGy9}p75BwTqK=M^ z3VMUmGh%rwZbYX}O(o(|gWNR6@Wh;_WP$@`gZx39q+n<;>`oLbV=DR8hzbhKtCWyA zWbB^BbZIx`e2Xq1uH2sQp}HopLB`1LOnJ)lqP|^ zB;^d{fsW5HHzmS0e^L#rWQ7=~j;~#~u(Ef)EOPRmNmR)|Mz-igyse$U>8BrC;D`h) zcEx$i%O8=}LOS12_pOX*6Obu!bqwJuAP%+3u8plAl8zIO544VZ>mg39H1dobYJqU* z$`y8Il7^ZLRP0R1-6*Tg9UiX>!p)UWucBHaOiTIh__lOp@pKtm8y&jjOPeSoEpJ8D zfX017QnG?H_awY&X5B}bVBsjjUuTaS3sd07IL#a zdBR2NCv8lC%1`)4*;oXth`Ur#d?hT@T`aagCx?MM#_X}VZ_g{OQtH>N@f_@}0v(@d z2VS$Ll&mGB{g`;i-6gjtEsbhNsm`WQfomzwrd1kNy50bI60e;+ynp$jGKZ&k?T>*N z3{UME(*@{rHHw6%c2`Zb3D|Ujbw%uicg8D68sPzXPsdH+$zdX*ZnjPrVl+U(#nBMH&7*si;Tuh}2+k@yOl7h{=2 zf$7xKn>TcWnN%~>7Es#Kyz&#GB6ecy=%h^u*Uph5A0maI;IAY$bRmyj+4WZYvhYU( z(t+s4ulL&c&)!_#7T6&Zc5XOKD2da6EtRENo1iGr@mCbjH#HT}N; Dh=sww diff --git a/packages/components/package.json b/packages/components/package.json index 2192dba8..a1de20d7 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -28,6 +28,7 @@ "@types/js-yaml": "^4.0.5", "apify-client": "^2.7.1", "@types/jsdom": "^21.1.1", + "@zilliz/milvus2-sdk-node": "^2.2.24", "axios": "^0.27.2", "cheerio": "^1.0.0-rc.12", "chromadb": "^1.5.3", From 944ec729968ed042fa572e502a73e257bc89bf1f Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:26:11 +0100 Subject: [PATCH 15/24] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b8e2e8a5..13531280 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -27,7 +27,6 @@ If applicable, add screenshots to help explain your problem. If applicable, add exported flow in order to help replicating the problem. **Setup** - - Installation [e.g. docker, `npx flowise start`, `yarn start`] - Flowise Version [e.g. 1.2.11] - OS: [e.g. macOS, Windows, Linux] From 5c3037c0f3ad4955aabbd68b7d6a4583fc3d946f Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:30:02 +0100 Subject: [PATCH 16/24] Update CODE_OF_CONDUCT-ZH.md --- CODE_OF_CONDUCT-ZH.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CODE_OF_CONDUCT-ZH.md b/CODE_OF_CONDUCT-ZH.md index be6332dd..e0537da6 100644 --- a/CODE_OF_CONDUCT-ZH.md +++ b/CODE_OF_CONDUCT-ZH.md @@ -2,7 +2,7 @@ # 贡献者公约行为准则 -[English](./CODE_OF_CONDUCT.md) | 中文 +[English](<./CODE_OF_CONDUCT.md>) | 中文 ## 我们的承诺 @@ -44,6 +44,6 @@ ## 归属 -该行为准则的内容来自于[贡献者公约](http://contributor-covenant.org/)1.4 版,可在[http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4)上获取。 +该行为准则的内容来自于[贡献者公约](http://contributor-covenant.org/)1.4版,可在[http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4)上获取。 [主页]: http://contributor-covenant.org From 9f99af22ed88027e16a007fc213c8a188ded3fce Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:30:20 +0100 Subject: [PATCH 17/24] Update CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index da7a51c6..43f82993 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,6 +1,6 @@ # Contributor Covenant Code of Conduct -English | [中文](./CODE_OF_CONDUCT-ZH.md) +English | [中文](<./CODE_OF_CONDUCT-ZH.md>) ## Our Pledge From 720179a007aaba9cf4167cdb5ace5b9db7a327c5 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:31:18 +0100 Subject: [PATCH 18/24] Update README-ZH.md --- README-ZH.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README-ZH.md b/README-ZH.md index e0eb9de2..10efce8b 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -2,7 +2,7 @@ -# Flowise - 轻松构建 LLM 应用程序 +# Flowise - 轻松构建LLM应用程序 [![发布说明](https://img.shields.io/github/release/FlowiseAI/Flowise)](https://github.com/FlowiseAI/Flowise/releases) [![Discord](https://img.shields.io/discord/1087698854775881778?label=Discord&logo=discord)](https://discord.gg/jbaHfsRVBW) @@ -10,13 +10,13 @@ [![GitHub星图](https://img.shields.io/github/stars/FlowiseAI/Flowise?style=social)](https://star-history.com/#FlowiseAI/Flowise) [![GitHub分支](https://img.shields.io/github/forks/FlowiseAI/Flowise?style=social)](https://github.com/FlowiseAI/Flowise/fork) -[English](./README.md) | 中文 +[English](<./README.md>) | 中文

拖放界面构建定制化的LLM流程

-## ⚡ 快速入门 +## ⚡快速入门 下载并安装 [NodeJS](https://nodejs.org/en/download) >= 18.15.0 @@ -67,7 +67,7 @@ ## 👨‍💻 开发者 -Flowise 在一个单一的代码库中有 3 个不同的模块。 +Flowise 在一个单一的代码库中有3个不同的模块。 - `server`:用于提供 API 逻辑的 Node 后端 - `ui`:React 前端 @@ -185,4 +185,4 @@ Flowise 支持不同的环境变量来配置您的实例。您可以在 `package ## 📄 许可证 -此代码库中的源代码在[MIT 许可证](LICENSE.md)下提供。 +此代码库中的源代码在[MIT许可证](LICENSE.md)下提供。 From 9c4e7b6774d12752b260aef4849515834151a869 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:31:42 +0100 Subject: [PATCH 19/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b98a223a..36c53b4b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![GitHub star chart](https://img.shields.io/github/stars/FlowiseAI/Flowise?style=social)](https://star-history.com/#FlowiseAI/Flowise) [![GitHub fork](https://img.shields.io/github/forks/FlowiseAI/Flowise?style=social)](https://github.com/FlowiseAI/Flowise/fork) -English | [中文](./README-ZH.md) +English | [中文](<./README-ZH.md>)

Drag & drop UI to build your customized LLM flow

From 1b6d7fec1c132aeacb23e9a61559fbb5775b6bc7 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:32:08 +0100 Subject: [PATCH 20/24] Update README.md --- packages/server/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/README.md b/packages/server/README.md index de36549c..b561b0b0 100644 --- a/packages/server/README.md +++ b/packages/server/README.md @@ -2,7 +2,7 @@ # Flowise - Low-Code LLM apps builder -English | [中文](./README-ZH.md) +English | [中文](<./README-ZH.md>) ![Flowise](https://github.com/FlowiseAI/Flowise/blob/main/images/flowise.gif?raw=true) From e9fd0617dd4431594ebe004cf0583153201fa3cf Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:34:51 +0100 Subject: [PATCH 21/24] Update README-ZH.md --- packages/components/README-ZH.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/README-ZH.md b/packages/components/README-ZH.md index 2a8ba4ac..12cb240b 100644 --- a/packages/components/README-ZH.md +++ b/packages/components/README-ZH.md @@ -2,9 +2,9 @@ # 流式组件 -[English](./README.md) | 中文 +[English](<./README.md>) | 中文 -Flowise 的应用集成。包含节点和凭据。 +Flowise的应用集成。包含节点和凭据。 ![Flowise](https://github.com/FlowiseAI/Flowise/blob/main/images/flowise.gif?raw=true) @@ -16,4 +16,4 @@ npm i flowise-components ## 许可证 -此存储库中的源代码在[MIT 许可证](https://github.com/FlowiseAI/Flowise/blob/master/LICENSE.md)下提供。 +此存储库中的源代码在[MIT许可证](https://github.com/FlowiseAI/Flowise/blob/master/LICENSE.md)下提供。 From f4e15ccbc1c1510f83c1f78de403daf887abec82 Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:35:46 +0100 Subject: [PATCH 22/24] Update README.md --- packages/components/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/README.md b/packages/components/README.md index 84807188..8d561e34 100644 --- a/packages/components/README.md +++ b/packages/components/README.md @@ -2,7 +2,7 @@ # Flowise Components -English | [中文](./README-ZH.md) +English | [中文](<./README-ZH.md>) Apps integration for Flowise. Contain Nodes and Credentials. From 099e38aac8f682055c123d5bfa8ed763d8c35fde Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:36:20 +0100 Subject: [PATCH 23/24] Update README-ZH.md --- packages/ui/README-ZH.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ui/README-ZH.md b/packages/ui/README-ZH.md index 21aaf482..c6307935 100644 --- a/packages/ui/README-ZH.md +++ b/packages/ui/README-ZH.md @@ -2,9 +2,9 @@ # 流程界面 -[English](./README.md) | 中文 +[English](<./README.md>) | 中文 -Flowise 的 React 前端界面。 +Flowise的React前端界面。 ![Flowise](https://github.com/FlowiseAI/Flowise/blob/main/images/flowise.gif?raw=true) @@ -16,4 +16,4 @@ npm i flowise-ui ## 许可证 -本仓库中的源代码在[MIT 许可证](https://github.com/FlowiseAI/Flowise/blob/master/LICENSE.md)下提供。 +本仓库中的源代码在[MIT许可证](https://github.com/FlowiseAI/Flowise/blob/master/LICENSE.md)下提供。 From 405ff72e47cadb330c1c157fbf43538e33f0a35b Mon Sep 17 00:00:00 2001 From: Henry Heng Date: Thu, 17 Aug 2023 21:36:40 +0100 Subject: [PATCH 24/24] Update README.md --- packages/ui/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/README.md b/packages/ui/README.md index 257dc6f4..487172f8 100644 --- a/packages/ui/README.md +++ b/packages/ui/README.md @@ -2,7 +2,7 @@ # Flowise UI -English | [中文](./README-ZH.md) +English | [中文](<./README-ZH.md>) React frontend ui for Flowise.