UNPKG

n8n-nodes-neo4j

Version:

n8n node for Neo4j with LangChain integration, supporting vector stores and graph operations

363 lines (362 loc) 15 kB
"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