Skip to content

Commit b0e6d4a

Browse files
authored
Merge pull request #913 from vectara/vectara-upload-files
Add Vectara upload file component
2 parents b193782 + d3d18a8 commit b0e6d4a

File tree

9 files changed

+331
-218
lines changed

9 files changed

+331
-218
lines changed

packages/components/nodes/agents/BabyAGI/BabyAGI.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { INode, INodeData, INodeParams } from '../../../src/Interface'
22
import { BabyAGI } from './core'
33
import { BaseChatModel } from 'langchain/chat_models/base'
4-
import { VectorStore } from 'langchain/vectorstores'
4+
import { VectorStore } from 'langchain/vectorstores/base'
55

66
class BabyAGI_Agents implements INode {
77
label: string

packages/components/nodes/chains/VectorDBQAChain/VectorDBQAChain.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Inter
22
import { getBaseClasses } from '../../../src/utils'
33
import { VectorDBQAChain } from 'langchain/chains'
44
import { BaseLanguageModel } from 'langchain/base_language'
5-
import { VectorStore } from 'langchain/vectorstores'
5+
import { VectorStore } from 'langchain/vectorstores/base'
66
import { ConsoleCallbackHandler, CustomChainHandler, additionalCallbacks } from '../../../src/handler'
77

88
class VectorDBQAChain_Chains implements INode {

packages/components/nodes/vectorstores/Vectara_Existing/Vectara_Existing.ts renamed to packages/components/nodes/vectorstores/Vectara/Vectara_Existing.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class VectaraExisting_VectorStores implements INode {
9292
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
9393
const apiKey = getCredentialParam('apiKey', credentialData, nodeData)
9494
const customerId = getCredentialParam('customerID', credentialData, nodeData)
95-
const corpusId = getCredentialParam('corpusID', credentialData, nodeData)
95+
const corpusId = getCredentialParam('corpusID', credentialData, nodeData).split(',')
9696

9797
const vectaraMetadataFilter = nodeData.inputs?.filter as string
9898
const sentencesBefore = nodeData.inputs?.sentencesBefore as number
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
2+
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
3+
import { VectaraStore, VectaraLibArgs, VectaraFilter, VectaraContextConfig, VectaraFile } from 'langchain/vectorstores/vectara'
4+
5+
class VectaraUpload_VectorStores implements INode {
6+
label: string
7+
name: string
8+
version: number
9+
description: string
10+
type: string
11+
icon: string
12+
category: string
13+
baseClasses: string[]
14+
inputs: INodeParams[]
15+
credential: INodeParams
16+
outputs: INodeOutputsValue[]
17+
18+
constructor() {
19+
this.label = 'Vectara Upload File'
20+
this.name = 'vectaraUpload'
21+
this.version = 1.0
22+
this.type = 'Vectara'
23+
this.icon = 'vectara.png'
24+
this.category = 'Vector Stores'
25+
this.description = 'Upload files to Vectara'
26+
this.baseClasses = [this.type, 'VectorStoreRetriever', 'BaseRetriever']
27+
this.credential = {
28+
label: 'Connect Credential',
29+
name: 'credential',
30+
type: 'credential',
31+
credentialNames: ['vectaraApi']
32+
}
33+
this.inputs = [
34+
{
35+
label: 'File',
36+
name: 'file',
37+
description:
38+
'File to upload to Vectara. Supported file types: https://docs.vectara.com/docs/api-reference/indexing-apis/file-upload/file-upload-filetypes',
39+
type: 'file'
40+
},
41+
{
42+
label: 'Vectara Metadata Filter',
43+
name: 'filter',
44+
description:
45+
'Filter to apply to Vectara metadata. Refer to the <a target="_blank" href="https://docs.flowiseai.com/vector-stores/vectara">documentation</a> on how to use Vectara filters with Flowise.',
46+
type: 'string',
47+
additionalParams: true,
48+
optional: true
49+
},
50+
{
51+
label: 'Sentences Before',
52+
name: 'sentencesBefore',
53+
description: 'Number of sentences to fetch before the matched sentence. Defaults to 2.',
54+
type: 'number',
55+
additionalParams: true,
56+
optional: true
57+
},
58+
{
59+
label: 'Sentences After',
60+
name: 'sentencesAfter',
61+
description: 'Number of sentences to fetch after the matched sentence. Defaults to 2.',
62+
type: 'number',
63+
additionalParams: true,
64+
optional: true
65+
},
66+
{
67+
label: 'Lambda',
68+
name: 'lambda',
69+
description:
70+
'Improves retrieval accuracy by adjusting the balance (from 0 to 1) between neural search and keyword-based search factors.',
71+
type: 'number',
72+
additionalParams: true,
73+
optional: true
74+
},
75+
{
76+
label: 'Top K',
77+
name: 'topK',
78+
description: 'Number of top results to fetch. Defaults to 4',
79+
placeholder: '4',
80+
type: 'number',
81+
additionalParams: true,
82+
optional: true
83+
}
84+
]
85+
this.outputs = [
86+
{
87+
label: 'Vectara Retriever',
88+
name: 'retriever',
89+
baseClasses: this.baseClasses
90+
},
91+
{
92+
label: 'Vectara Vector Store',
93+
name: 'vectorStore',
94+
baseClasses: [this.type, ...getBaseClasses(VectaraStore)]
95+
}
96+
]
97+
}
98+
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
99+
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
100+
const apiKey = getCredentialParam('apiKey', credentialData, nodeData)
101+
const customerId = getCredentialParam('customerID', credentialData, nodeData)
102+
const corpusId = getCredentialParam('corpusID', credentialData, nodeData).split(',')
103+
104+
const fileBase64 = nodeData.inputs?.file
105+
const vectaraMetadataFilter = nodeData.inputs?.filter as string
106+
const sentencesBefore = nodeData.inputs?.sentencesBefore as number
107+
const sentencesAfter = nodeData.inputs?.sentencesAfter as number
108+
const lambda = nodeData.inputs?.lambda as number
109+
const output = nodeData.outputs?.output as string
110+
const topK = nodeData.inputs?.topK as string
111+
const k = topK ? parseInt(topK, 10) : 4
112+
113+
const vectaraArgs: VectaraLibArgs = {
114+
apiKey: apiKey,
115+
customerId: customerId,
116+
corpusId: corpusId
117+
}
118+
119+
const vectaraFilter: VectaraFilter = {}
120+
if (vectaraMetadataFilter) vectaraFilter.filter = vectaraMetadataFilter
121+
if (lambda) vectaraFilter.lambda = lambda
122+
123+
const vectaraContextConfig: VectaraContextConfig = {}
124+
if (sentencesBefore) vectaraContextConfig.sentencesBefore = sentencesBefore
125+
if (sentencesAfter) vectaraContextConfig.sentencesAfter = sentencesAfter
126+
vectaraFilter.contextConfig = vectaraContextConfig
127+
128+
let files: string[] = []
129+
130+
if (fileBase64.startsWith('[') && fileBase64.endsWith(']')) {
131+
files = JSON.parse(fileBase64)
132+
} else {
133+
files = [fileBase64]
134+
}
135+
136+
const vectaraFiles: VectaraFile[] = []
137+
for (const file of files) {
138+
const splitDataURI = file.split(',')
139+
splitDataURI.pop()
140+
const bf = Buffer.from(splitDataURI.pop() || '', 'base64')
141+
const blob = new Blob([bf])
142+
vectaraFiles.push({ blob: blob, fileName: getFileName(file) })
143+
}
144+
145+
const vectorStore = new VectaraStore(vectaraArgs)
146+
await vectorStore.addFiles(vectaraFiles)
147+
148+
if (output === 'retriever') {
149+
const retriever = vectorStore.asRetriever(k, vectaraFilter)
150+
return retriever
151+
} else if (output === 'vectorStore') {
152+
;(vectorStore as any).k = k
153+
return vectorStore
154+
}
155+
return vectorStore
156+
}
157+
}
158+
159+
const getFileName = (fileBase64: string) => {
160+
let fileNames = []
161+
if (fileBase64.startsWith('[') && fileBase64.endsWith(']')) {
162+
const files = JSON.parse(fileBase64)
163+
for (const file of files) {
164+
const splitDataURI = file.split(',')
165+
const filename = splitDataURI[splitDataURI.length - 1].split(':')[1]
166+
fileNames.push(filename)
167+
}
168+
return fileNames.join(', ')
169+
} else {
170+
const splitDataURI = fileBase64.split(',')
171+
const filename = splitDataURI[splitDataURI.length - 1].split(':')[1]
172+
return filename
173+
}
174+
}
175+
176+
module.exports = { nodeClass: VectaraUpload_VectorStores }

packages/components/nodes/vectorstores/Vectara_Upsert/Vectara_Upsert.ts renamed to packages/components/nodes/vectorstores/Vectara/Vectara_Upsert.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class VectaraUpsert_VectorStores implements INode {
101101
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
102102
const apiKey = getCredentialParam('apiKey', credentialData, nodeData)
103103
const customerId = getCredentialParam('customerID', credentialData, nodeData)
104-
const corpusId = getCredentialParam('corpusID', credentialData, nodeData)
104+
const corpusId = getCredentialParam('corpusID', credentialData, nodeData).split(',')
105105

106106
const docs = nodeData.inputs?.document as Document[]
107107
const embeddings = {} as Embeddings

packages/components/nodes/vectorstores/Vectara_Existing/vectara.png renamed to packages/components/nodes/vectorstores/Vectara/vectara.png

File renamed without changes.
-65.6 KB
Binary file not shown.

packages/components/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"google-auth-library": "^9.0.0",
4343
"graphql": "^16.6.0",
4444
"html-to-text": "^9.0.5",
45-
"langchain": "^0.0.145",
45+
"langchain": "^0.0.147",
4646
"langfuse-langchain": "^1.0.14-alpha.0",
4747
"langsmith": "^0.0.32",
4848
"linkifyjs": "^4.1.1",

0 commit comments

Comments
 (0)