n8n-nodes-neo4j
Version:
n8n node for Neo4j with LangChain integration, supporting vector stores and graph operations
363 lines (362 loc) • 15 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Neo4j = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const neo4j_graph_1 = require("@langchain/community/graphs/neo4j_graph");
const neo4j_vector_1 = require("@langchain/community/vectorstores/neo4j_vector");
class Neo4j {
constructor() {
this.description = {
displayName: 'Neo4j',
name: 'neo4j',
icon: 'file:neo4j.svg',
usableAsTool: true,
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Work with Neo4j database',
defaults: {
name: 'Neo4j',
},
inputs: `={{
((parameters) => {
const mode = parameters?.mode;
const resource = parameters?.resource;
const inputs = [{ displayName: "", type: "${"main"}"}]
if (resource === 'vectorStore') {
inputs.push({ displayName: "Embedding", type: "${"ai_embedding"}", required: true, maxConnections: 1})
}
return inputs
})($parameter)
}}`,
outputs: ["main"],
credentials: [
{
name: 'neo4jApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Vector Store',
value: 'vectorStore',
},
{
name: 'Graph Database',
value: 'graphDb',
},
],
default: 'vectorStore',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: ['vectorStore'],
},
},
options: [
{
name: 'Similarity Search',
value: 'similaritySearch',
},
{
name: 'Add Texts',
value: 'addTexts',
}
],
default: 'similaritySearch',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: ['graphDb'],
},
},
options: [
{
name: 'Execute Query',
value: 'executeQuery',
},
{
name: 'Create Node',
value: 'createNode',
},
{
name: 'Create Relationship',
value: 'createRelationship',
},
{
name: 'Get Schema',
value: 'getSchema',
},
],
default: 'executeQuery',
},
{
displayName: 'Index Name',
name: 'indexName',
type: 'string',
required: false,
displayOptions: {
show: {
resource: ['vectorStore', 'graphDb']
},
},
default: 'vector',
description: 'The index name to use',
},
{
displayName: 'Query Text',
name: 'queryText',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['vectorStore'],
operation: ['similaritySearch'],
},
},
default: '',
description: 'The text to search for similar vectors',
},
{
displayName: 'Options',
name: 'moreOptions',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
resource: ['vectorStore'],
operation: ['similaritySearch'],
},
},
options: [
{
displayName: 'Distance Metric',
name: 'distanceMetric',
type: 'options',
default: 'COSINE',
description: 'The distance metric to use',
options: [
{
name: 'Cosine',
value: 'COSINE',
},
{
name: 'Euclidean',
value: 'EUCLIDEAN_DISTANCE',
},
{
name: 'Max Inner Product',
value: 'MAX_INNER_PRODUCT',
},
{
name: 'Dot Product',
value: 'DOT_PRODUCT',
},
{
name: 'Jaccard',
value: 'JACCARD',
}
],
},
{
displayName: 'Metadata Filter',
name: 'metadataFilter',
type: 'json',
default: '{}',
description: 'JSON object to filter results by metadata properties',
},
{
displayName: 'Retrieval Query',
name: 'retrievalQuery',
type: 'string',
default: '',
description: 'The Cypher query to execute',
},
],
},
{
displayName: 'Texts',
name: 'texts',
type: 'string',
typeOptions: {
multipleValues: true,
},
required: true,
displayOptions: {
show: {
resource: ['vectorStore'],
operation: ['addTexts'],
},
},
default: [],
description: 'The texts to add to the vector store',
},
{
displayName: 'As String',
name: 'schemaAsString',
type: 'boolean',
required: true,
displayOptions: {
show: {
resource: ['graphDb'],
operation: ['getSchema'],
},
},
default: false,
description: 'Whether to return the schema as a string or object',
},
{
displayName: 'Cypher Query',
name: 'cypherQuery',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['graphDb'],
operation: ['executeQuery'],
},
},
default: '',
description: 'The Cypher query to execute',
},
{
displayName: 'Node Label',
name: 'nodeLabel',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['graphDb'],
operation: ['createNode'],
},
},
default: '',
description: 'The label for the node',
},
{
displayName: 'Node Properties',
name: 'nodeProperties',
type: 'string',
required: true,
displayOptions: {
show: {
resource: ['graphDb'],
operation: ['createNode'],
},
},
default: '{}',
description: 'The properties of the node as JSON string',
},
],
};
}
async execute() {
const credentials = await this.getCredentials('neo4jApi');
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
console.log(resource + " - " + operation);
const config = {
url: credentials.uri,
username: credentials.username,
password: credentials.password,
database: credentials.database,
textNodeProperties: ["text"],
};
try {
if (resource === 'vectorStore') {
const embeddings = (await this.getInputConnectionData("ai_embedding", 0));
const moreOptions = this.getNodeParameter('moreOptions', 0);
const config_vector = {
...config,
retrievalQuery: moreOptions.retrievalQuery ? moreOptions.retrievalQuery : undefined,
distanceMetric: moreOptions.distanceMetric ? moreOptions.distanceMetric : 'COSINE',
embeddingNodeProperty: "embedding",
searchType: "vector",
};
const vectorStore = await neo4j_vector_1.Neo4jVectorStore.fromExistingIndex(embeddings, config_vector);
try {
if (operation === 'similaritySearch') {
const queryText = this.getNodeParameter('queryText', 0);
const moreOptions = this.getNodeParameter('moreOptions', 0);
const metadataFilter = moreOptions.metadataFilter ? JSON.parse(moreOptions.metadataFilter) : {};
const queryEmbedding = await embeddings.embedQuery(queryText);
const results = await vectorStore.similaritySearchVectorWithScore(queryEmbedding, 4, '', metadataFilter);
return [this.helpers.returnJsonArray(results.map(([doc, score]) => ({
content: doc.pageContent,
score: score,
...doc.metadata
})))];
}
if (operation === 'addTexts') {
const texts = this.getNodeParameter('texts', 0);
await vectorStore.addDocuments(texts.map(text => ({ pageContent: text, metadata: {} })));
return [this.helpers.returnJsonArray([{ success: true }])];
}
}
finally {
await vectorStore.close();
}
}
if (resource === 'graphDb') {
const graph = await neo4j_graph_1.Neo4jGraph.initialize(config);
try {
if (operation === 'getSchema') {
const asString = this.getNodeParameter('schemaAsString', 0);
if (asString) {
const result = {
"schema": await graph.getSchema()
};
return [this.helpers.returnJsonArray([JSON.parse(JSON.stringify(result))])];
}
else {
const result = await graph.getStructuredSchema();
return [this.helpers.returnJsonArray([JSON.parse(JSON.stringify(result))])];
}
}
if (operation === 'executeQuery') {
const cypherQuery = this.getNodeParameter('cypherQuery', 0);
const result = await graph.query(cypherQuery);
console.log(result);
return [this.helpers.returnJsonArray(result)];
}
if (operation === 'createNode') {
const nodeLabel = this.getNodeParameter('nodeLabel', 0);
const nodeProperties = JSON.parse(this.getNodeParameter('nodeProperties', 0));
const query = `CREATE (n:${nodeLabel} $props) RETURN n`;
const result = await graph.query(query, { props: nodeProperties });
return [this.helpers.returnJsonArray(result)];
}
if (operation === 'createRelationship') {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Create relationship operation not implemented yet');
}
}
finally {
await graph.close();
}
}
}
catch (error) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error);
}
finally {
}
return [[]];
}
}
exports.Neo4j = Neo4j;
//# sourceMappingURL=Neo4j.node.js.map