Skip to content

Commit

Permalink
feat(core): Add support for Supabase Vector Store (#7152)
Browse files Browse the repository at this point in the history
Github issue / Community forum post (link here to close automatically):

Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
  • Loading branch information
OlegIvaniv authored Sep 14, 2023
1 parent 981197c commit 04efefb
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import type {
IExecuteFunctions,
INodeType,
INodeTypeDescription,
INodeExecutionData,
} from 'n8n-workflow';
import type { Embeddings } from 'langchain/embeddings/base';
import type { Document } from 'langchain/document';
import { createClient } from '@supabase/supabase-js';
import { SupabaseVectorStore } from 'langchain/vectorstores/supabase';

import { N8nJsonLoader } from '../../../utils/N8nJsonLoader';
import { N8nBinaryLoader } from '../../../utils/N8nBinaryLoader';
export class VectorStoreSupabaseInsert implements INodeType {
description: INodeTypeDescription = {
displayName: 'Supabase: Insert',
name: 'vectorStoreSupabaseInsert',
icon: 'file:supabase.svg',
group: ['transform'],
version: 1,
description:
'Insert data into Supabase Vector Store index [https://supabase.com/docs/guides/ai/langchain]',
defaults: {
name: 'Supabase: Insert',
},
codex: {
categories: ['AI'],
subcategories: {
AI: ['Vector Stores'],
},
},
credentials: [
{
name: 'supabaseApi',
required: true,
},
],
inputs: [
'main',
{
displayName: 'Document',
maxConnections: 1,
type: 'document',
required: true,
},
{
displayName: 'Embedding',
maxConnections: 1,
type: 'embedding',
required: true,
},
],
outputs: ['main'],
properties: [
{
displayName:
'Please reffer to the Supabase documentation for more information on how to setup your database as a Vector Store. https://supabase.com/docs/guides/ai/langchain',
name: 'setupNotice',
type: 'notice',
default: '',
},
{
displayName: 'Table Name',
name: 'tableName',
type: 'string',
default: '',
required: true,
description: 'Name of the table to insert into',
},
{
displayName: 'Query Name',
name: 'queryName',
type: 'string',
default: 'match_documents',
required: true,
description: 'Name of the query to use for matching documents',
},
],
};

async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
this.logger.verbose('Executing data for Supabase Insert Vector Store');

const items = this.getInputData(0);
const tableName = this.getNodeParameter('tableName', 0) as string;
const queryName = this.getNodeParameter('queryName', 0) as string;
const credentials = await this.getCredentials('supabaseApi');

const documentInput = (await this.getInputConnectionData('document', 0)) as
| N8nJsonLoader
| Array<Document<Record<string, unknown>>>;

const embeddings = (await this.getInputConnectionData('embedding', 0)) as Embeddings;
const client = createClient(credentials.host as string, credentials.serviceRole as string);

let processedDocuments: Document[];

if (documentInput instanceof N8nJsonLoader || documentInput instanceof N8nBinaryLoader) {
processedDocuments = await documentInput.process(items);
} else {
processedDocuments = documentInput;
}

await SupabaseVectorStore.fromDocuments(processedDocuments, embeddings, {
client,
tableName,
queryName,
});

const serializedDocuments = processedDocuments.map(({ metadata, pageContent }) => ({
json: { metadata, pageContent },
}));

return this.prepareOutputData(serializedDocuments);
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import type {
IExecuteFunctions,
INodeType,
INodeTypeDescription,
IDataObject,
SupplyData,
} from 'n8n-workflow';
import type { Embeddings } from 'langchain/embeddings/base';
import { createClient } from '@supabase/supabase-js';
import { SupabaseVectorStore } from 'langchain/vectorstores/supabase';

import { logWrapper } from '../../../utils/logWrapper';
export class VectorStoreSupabaseLoad implements INodeType {
description: INodeTypeDescription = {
displayName: 'Supabase: Load',
name: 'vectorStoreSupabaseLoad',
icon: 'file:supabase.svg',
group: ['transform'],
version: 1,
description: 'Load data from Supabase Vector Store index',
defaults: {
name: 'Supabase: Load',
},
codex: {
categories: ['AI'],
subcategories: {
AI: ['Vector Stores'],
},
},
credentials: [
{
name: 'supabaseApi',
required: true,
},
],
inputs: [
{
displayName: 'Embedding',
maxConnections: 1,
type: 'embedding',
required: true,
},
],
outputs: ['vectorStore'],
outputNames: ['Vector Store'],
properties: [
{
displayName: 'Table Name',
name: 'tableName',
type: 'string',
default: '',
required: true,
description: 'Name of the table to load from',
},
{
displayName: 'Query Name',
name: 'queryName',
type: 'string',
default: 'match_documents',
required: true,
description: 'Name of the query to use for matching documents',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
options: [
{
displayName: 'Metadata Filter',
name: 'filter',
type: 'string',
typeOptions: {
editor: 'json',
editorLanguage: 'json',
},
default: '',
},
],
},
],
};

async supplyData(this: IExecuteFunctions): Promise<SupplyData> {
this.logger.verbose('Supply Supabase Load Vector Store');

const tableName = this.getNodeParameter('tableName', 0) as string;
const queryName = this.getNodeParameter('queryName', 0) as string;
const options = this.getNodeParameter('options', 0, {}) as {
filter?: IDataObject;
};

const credentials = await this.getCredentials('supabaseApi');
const embeddings = (await this.getInputConnectionData('embedding', 0)) as Embeddings;

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const client = createClient(credentials.host as string, credentials.serviceRole as string);

const vectorStore = await SupabaseVectorStore.fromExistingIndex(embeddings, {
client,
tableName,
queryName,
filter: options.filter,
});

return {
response: logWrapper(vectorStore, this),
};
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion packages/@n8n/nodes-langchain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@
"dist/nodes/retrievers/RetrieverVectorStore/RetrieverVectorStore.node.js",
"dist/nodes/vector_store/InMemoryVectorStore/InMemoryVectorStore.node.js",
"dist/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.js",
"dist/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.js"
"dist/nodes/vector_store/VectorStorePineconeLoad/VectorStorePineconeLoad.node.js",
"dist/nodes/vector_store/VectorStoreSupabaseInsert/VectorStoreSupabaseInsert.node.js",
"dist/nodes/vector_store/VectorStoreSupabaseLoad/VectorStoreSupabaseLoad.node.js"
]
},
"devDependencies": {
Expand All @@ -93,6 +95,7 @@
"@gxl/epub-parser": "^2.0.4",
"@huggingface/inference": "2.6.1",
"@pinecone-database/pinecone": "^0.1.6",
"@supabase/supabase-js": "^2.33.2",
"@types/temp": "^0.9.1",
"@xata.io/cli": "^0.13.4",
"@xata.io/client": "^0.26.2",
Expand Down
Loading

0 comments on commit 04efefb

Please # to comment.