Improved levenshtein fuzzy match
All checks were successful
Publish Library / Build NPM Project (push) Successful in 52s
Publish Library / Tag Version (push) Successful in 17s

This commit is contained in:
2026-08-01 12:00:26 -04:00
parent a1d438a20a
commit d022a5ef4d
2 changed files with 32 additions and 10 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@ztimson/ai-utils",
"version": "1.2.12",
"version": "1.2.13",
"description": "AI Utility library",
"author": "Zak Timson",
"license": "MIT",

View File

@@ -397,15 +397,37 @@ class LLM {
* @param {string} searchTerms Multiple search terms to check against target
* @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical
*/
fuzzyMatch(target: string, ...searchTerms: string[]) {
if(searchTerms.length < 2) throw new Error('Requires at least 2 strings to compare');
const vector = (text: string, dimensions: number = 10): number[] => {
return text.toLowerCase().split('').map((char, index) =>
(char.charCodeAt(0) * (index + 1)) % dimensions / dimensions).slice(0, dimensions);
}
const v = vector(target);
const similarities = searchTerms.map(t => vector(t)).map(refVector => this.cosineSimilarity(v, refVector));
return {avg: similarities.reduce((acc, s) => acc + s, 0) / similarities.length, max: Math.max(...similarities), similarities};
fuzzyMatch(target, ...searchTerms) {
if (searchTerms.length < 2) throw new Error('Requires at least 2 strings to compare');
const levenshtein = (a, b) => {
const m = a.length, n = b.length;
if (!m) return n;
if (!n) return m;
const dp = Array.from({length: m + 1}, (_, i) => [i, ...Array(n).fill(0)]);
for (let j = 0; j <= n; j++) dp[0][j] = j;
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
dp[i][j] = a[i - 1] === b[j - 1]
? dp[i - 1][j - 1]
: 1 + Math.min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[m][n];
};
const similarity = (a, b) => {
a = a.toLowerCase(); b = b.toLowerCase();
const dist = levenshtein(a, b);
return 1 - dist / Math.max(a.length, b.length, 1);
};
const similarities = searchTerms.map(t => similarity(target, t));
return {
avg: similarities.reduce((acc, s) => acc + s, 0) / similarities.length,
max: Math.max(...similarities),
similarities
};
}
/**