UNPKG

n8n-nodes-rckflr-cosine-similarity

Version:

A custom n8n node to calculate cosine similarity between two arrays of vectors.

95 lines 4.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CosineSimilarity = void 0; const n8n_workflow_1 = require("n8n-workflow"); function cosineSimilarity(vecA, vecB) { const dotProduct = vecA.reduce((sum, val, i) => sum + val * vecB[i], 0); const magnitudeA = Math.sqrt(vecA.reduce((sum, val) => sum + val * val, 0)); const magnitudeB = Math.sqrt(vecB.reduce((sum, val) => sum + val * val, 0)); return dotProduct / (magnitudeA * magnitudeB); } class CosineSimilarity { constructor() { this.description = { displayName: 'Cosine Similarity', name: 'cosineSimilarity', group: ['transform'], version: 1, description: 'Calculates cosine similarity between two arrays of vectors', defaults: { name: 'Cosine Similarity', }, inputs: ['main'], outputs: ['main'], properties: [ { displayName: 'Array of Vectors A', name: 'vectorsA', type: 'json', default: '', description: 'Enter the first array of vectors (e.g., [[1,2,3],[4,5,6]])', }, { displayName: 'Array of Vectors B', name: 'vectorsB', type: 'json', default: '', description: 'Enter the second array of vectors (e.g., [[7,8,9],[10,11,12]])', }, { displayName: 'Similarity Threshold', name: 'threshold', type: 'number', typeOptions: { minValue: 0, maxValue: 1, }, default: 0.5, description: 'Minimum cosine similarity to include in the output (0 to 1)', }, ], }; } async execute() { let vectorsA = this.getNodeParameter('vectorsA', 0); let vectorsB = this.getNodeParameter('vectorsB', 0); const threshold = this.getNodeParameter('threshold', 0); try { if (typeof vectorsA === 'string') vectorsA = JSON.parse(vectorsA); if (typeof vectorsB === 'string') vectorsB = JSON.parse(vectorsB); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid JSON format for vector arrays.'); } if (!Array.isArray(vectorsA) || vectorsA.length === 0) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Array A must be a valid array of vectors.'); } if (!Array.isArray(vectorsB) || vectorsB.length === 0) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Array B must be a valid array of vectors.'); } if (!vectorsA.every(Array.isArray) || !vectorsB.every(Array.isArray)) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Each element of the arrays must be a vector (another array).'); } const dimensionA = vectorsA[0].length; const dimensionB = vectorsB[0].length; if (!vectorsA.every(vec => vec.length === dimensionA) || !vectorsB.every(vec => vec.length === dimensionB)) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'All vectors must have the same dimension.'); } const result = []; for (const vecA of vectorsA) { for (const vecB of vectorsB) { if (vecA.length !== vecB.length) continue; const similarity = cosineSimilarity(vecA, vecB); if (similarity >= threshold) { result.push({ vectorA: vecA, vectorB: vecB, similarity }); } } } return [[{ json: { matches: result } }]]; } } exports.CosineSimilarity = CosineSimilarity; //# sourceMappingURL=CosineSimilarity.node.js.map