forked from FlowiseAI/Flowise
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Voyage AI - Credentials, Embeddings and Rerank (FlowiseAI#2015)
* Voyage AI - Credentials and Embeddings * reranker and fixes for embeddings
- Loading branch information
1 parent
6fd0fe6
commit 794818b
Showing
6 changed files
with
297 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { INodeParams, INodeCredential } from '../src/Interface' | ||
|
||
class VoyageAIApi implements INodeCredential { | ||
label: string | ||
name: string | ||
version: number | ||
description: string | ||
inputs: INodeParams[] | ||
|
||
constructor() { | ||
this.label = 'Voyage AI API' | ||
this.name = 'voyageAIApi' | ||
this.version = 1.0 | ||
this.description = | ||
'Refer to <a target="_blank" href="https://docs.voyageai.com/install/#authentication-with-api-keys">official guide</a> on how to get an API Key' | ||
this.inputs = [ | ||
{ | ||
label: 'Voyage AI Endpoint', | ||
name: 'endpoint', | ||
type: 'string', | ||
default: 'https://api.voyageai.com/v1/embeddings' | ||
}, | ||
{ | ||
label: 'Voyage AI API Key', | ||
name: 'apiKey', | ||
type: 'password' | ||
} | ||
] | ||
} | ||
} | ||
|
||
module.exports = { credClass: VoyageAIApi } |
84 changes: 84 additions & 0 deletions
84
packages/components/nodes/embeddings/VoyageAIEmbedding/VoyageAIEmbedding.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface' | ||
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils' | ||
import { VoyageEmbeddings, VoyageEmbeddingsParams } from 'langchain/embeddings/voyage' | ||
|
||
class VoyageAIEmbedding_Embeddings implements INode { | ||
label: string | ||
name: string | ||
version: number | ||
type: string | ||
icon: string | ||
category: string | ||
description: string | ||
baseClasses: string[] | ||
credential: INodeParams | ||
inputs: INodeParams[] | ||
|
||
constructor() { | ||
this.label = 'VoyageAI Embeddings' | ||
this.name = 'voyageAIEmbeddings' | ||
this.version = 1.0 | ||
this.type = 'VoyageAIEmbeddings' | ||
this.icon = 'voyageai.png' | ||
this.category = 'Embeddings' | ||
this.description = 'Voyage AI API to generate embeddings for a given text' | ||
this.baseClasses = [this.type, ...getBaseClasses(VoyageEmbeddings)] | ||
this.credential = { | ||
label: 'Connect Credential', | ||
name: 'credential', | ||
type: 'credential', | ||
credentialNames: ['voyageAIApi'] | ||
} | ||
this.inputs = [ | ||
{ | ||
label: 'Model Name', | ||
name: 'modelName', | ||
type: 'options', | ||
options: [ | ||
{ | ||
label: 'voyage-2', | ||
name: 'voyage-2', | ||
description: 'Base generalist embedding model optimized for both latency and quality' | ||
}, | ||
{ | ||
label: 'voyage-code-2', | ||
name: 'voyage-code-2', | ||
description: 'Optimized for code retrieval' | ||
}, | ||
{ | ||
label: 'voyage-large-2', | ||
name: 'voyage-large-2', | ||
description: 'Powerful generalist embedding model' | ||
}, | ||
{ | ||
label: 'voyage-lite-02-instruct', | ||
name: 'voyage-lite-02-instruct', | ||
description: 'Instruction-tuned for classification, clustering, and sentence textual similarity tasks' | ||
} | ||
], | ||
default: 'voyage-2', | ||
optional: true | ||
} | ||
] | ||
} | ||
|
||
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> { | ||
const modelName = nodeData.inputs?.modelName as string | ||
|
||
const credentialData = await getCredentialData(nodeData.credential ?? '', options) | ||
const voyageAiApiKey = getCredentialParam('apiKey', credentialData, nodeData) | ||
const voyageAiEndpoint = getCredentialParam('endpoint', credentialData, nodeData) | ||
|
||
const obj: Partial<VoyageEmbeddingsParams> & { apiKey?: string } = { | ||
apiKey: voyageAiApiKey | ||
} | ||
|
||
if (modelName) obj.modelName = modelName | ||
|
||
const model = new VoyageEmbeddings(obj) | ||
if (voyageAiEndpoint) model.apiUrl = voyageAiEndpoint | ||
return model | ||
} | ||
} | ||
|
||
module.exports = { nodeClass: VoyageAIEmbedding_Embeddings } |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions
52
packages/components/nodes/retrievers/VoyageAIRetriever/VoyageAIRerank.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import axios from 'axios' | ||
import { Callbacks } from '@langchain/core/callbacks/manager' | ||
import { Document } from '@langchain/core/documents' | ||
import { BaseDocumentCompressor } from 'langchain/retrievers/document_compressors' | ||
|
||
export class VoyageAIRerank extends BaseDocumentCompressor { | ||
private voyageAIAPIKey: any | ||
private readonly VOYAGEAI_RERANK_API_URL = 'https://api.voyageai.com/v1/rerank' | ||
private model: string = 'rerank-lite-1' | ||
private readonly k: number | ||
|
||
constructor(voyageAIAPIKey: string, model: string, k: number) { | ||
super() | ||
this.voyageAIAPIKey = voyageAIAPIKey | ||
this.model = model | ||
this.k = k | ||
} | ||
async compressDocuments( | ||
documents: Document<Record<string, any>>[], | ||
query: string, | ||
_?: Callbacks | undefined | ||
): Promise<Document<Record<string, any>>[]> { | ||
// avoid empty api call | ||
if (documents.length === 0) { | ||
return [] | ||
} | ||
const config = { | ||
headers: { | ||
Authorization: `Bearer ${this.voyageAIAPIKey}`, | ||
'Content-Type': 'application/json', | ||
Accept: 'application/json' | ||
} | ||
} | ||
const data = { | ||
model: this.model, | ||
query: query, | ||
documents: documents.map((doc) => doc.pageContent) | ||
} | ||
try { | ||
let returnedDocs = await axios.post(this.VOYAGEAI_RERANK_API_URL, data, config) | ||
const finalResults: Document<Record<string, any>>[] = [] | ||
returnedDocs.data.results.forEach((result: any) => { | ||
const doc = documents[result.index] | ||
doc.metadata.relevance_score = result.relevance_score | ||
finalResults.push(doc) | ||
}) | ||
return finalResults.splice(0, this.k) | ||
} catch (error) { | ||
return documents | ||
} | ||
} | ||
} |
129 changes: 129 additions & 0 deletions
129
packages/components/nodes/retrievers/VoyageAIRetriever/VoyageAIRerankRetriever.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import { BaseRetriever } from '@langchain/core/retrievers' | ||
import { VectorStoreRetriever } from '@langchain/core/vectorstores' | ||
import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression' | ||
import { VoyageAIRerank } from './VoyageAIRerank' | ||
import { getCredentialData, getCredentialParam, handleEscapeCharacters } from '../../../src' | ||
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' | ||
|
||
class VoyageAIRerankRetriever_Retrievers implements INode { | ||
label: string | ||
name: string | ||
version: number | ||
description: string | ||
type: string | ||
icon: string | ||
category: string | ||
baseClasses: string[] | ||
inputs: INodeParams[] | ||
credential: INodeParams | ||
badge: string | ||
outputs: INodeOutputsValue[] | ||
|
||
constructor() { | ||
this.label = 'Voyage AI Rerank Retriever' | ||
this.name = 'voyageAIRerankRetriever' | ||
this.version = 1.0 | ||
this.type = 'VoyageAIRerankRetriever' | ||
this.icon = 'voyageai.png' | ||
this.category = 'Retrievers' | ||
this.badge = 'NEW' | ||
this.description = 'Voyage AI Rerank indexes the documents from most to least semantically relevant to the query.' | ||
this.baseClasses = [this.type, 'BaseRetriever'] | ||
this.credential = { | ||
label: 'Connect Credential', | ||
name: 'credential', | ||
type: 'credential', | ||
credentialNames: ['voyageAIApi'] | ||
} | ||
this.inputs = [ | ||
{ | ||
label: 'Vector Store Retriever', | ||
name: 'baseRetriever', | ||
type: 'VectorStoreRetriever' | ||
}, | ||
{ | ||
label: 'Model Name', | ||
name: 'model', | ||
type: 'options', | ||
options: [ | ||
{ | ||
label: 'rerank-lite-1', | ||
name: 'rerank-lite-1' | ||
} | ||
], | ||
default: 'rerank-lite-1', | ||
optional: true | ||
}, | ||
{ | ||
label: 'Query', | ||
name: 'query', | ||
type: 'string', | ||
description: 'Query to retrieve documents from retriever. If not specified, user question will be used', | ||
optional: true, | ||
acceptVariable: true | ||
}, | ||
{ | ||
label: 'Top K', | ||
name: 'topK', | ||
description: 'Number of top results to fetch. Default to the TopK of the Base Retriever', | ||
placeholder: '4', | ||
type: 'number', | ||
additionalParams: true, | ||
optional: true | ||
} | ||
] | ||
this.outputs = [ | ||
{ | ||
label: 'Voyage AI Rerank Retriever', | ||
name: 'retriever', | ||
baseClasses: this.baseClasses | ||
}, | ||
{ | ||
label: 'Document', | ||
name: 'document', | ||
description: 'Array of document objects containing metadata and pageContent', | ||
baseClasses: ['Document', 'json'] | ||
}, | ||
{ | ||
label: 'Text', | ||
name: 'text', | ||
description: 'Concatenated string from pageContent of documents', | ||
baseClasses: ['string', 'json'] | ||
} | ||
] | ||
} | ||
|
||
async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> { | ||
const baseRetriever = nodeData.inputs?.baseRetriever as BaseRetriever | ||
const model = nodeData.inputs?.model as string | ||
const query = nodeData.inputs?.query as string | ||
const credentialData = await getCredentialData(nodeData.credential ?? '', options) | ||
const voyageAiApiKey = getCredentialParam('apiKey', credentialData, nodeData) | ||
const topK = nodeData.inputs?.topK as string | ||
const k = topK ? parseFloat(topK) : (baseRetriever as VectorStoreRetriever).k ?? 4 | ||
const output = nodeData.outputs?.output as string | ||
|
||
const voyageAICompressor = new VoyageAIRerank(voyageAiApiKey, model, k) | ||
|
||
const retriever = new ContextualCompressionRetriever({ | ||
baseCompressor: voyageAICompressor, | ||
baseRetriever: baseRetriever | ||
}) | ||
|
||
if (output === 'retriever') return retriever | ||
else if (output === 'document') return await retriever.getRelevantDocuments(query ? query : input) | ||
else if (output === 'text') { | ||
let finaltext = '' | ||
|
||
const docs = await retriever.getRelevantDocuments(query ? query : input) | ||
|
||
for (const doc of docs) finaltext += `${doc.pageContent}\n` | ||
|
||
return handleEscapeCharacters(finaltext, false) | ||
} | ||
|
||
return retriever | ||
} | ||
} | ||
|
||
module.exports = { nodeClass: VoyageAIRerankRetriever_Retrievers } |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.