llmverify
Version:
AI Output Verification Toolkit — Local-first LLM safety, hallucination detection, PII redaction, prompt injection defense, and runtime monitoring. Zero telemetry. OWASP LLM Top 10 aligned.
107 lines • 12.2 kB
JavaScript
;
/**
* Text Similarity Utilities
*
* Simple similarity measures for consistency checking.
*
* @module utils/similarity
* @author Haiec
* @license MIT
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.jaccardSimilarity = jaccardSimilarity;
exports.cosineSimilarity = cosineSimilarity;
exports.levenshteinDistance = levenshteinDistance;
exports.levenshteinSimilarity = levenshteinSimilarity;
exports.combinedSimilarity = combinedSimilarity;
/**
* Calculate Jaccard similarity between two texts
*/
function jaccardSimilarity(text1, text2) {
const words1 = new Set(text1.toLowerCase().split(/\s+/));
const words2 = new Set(text2.toLowerCase().split(/\s+/));
const intersection = new Set([...words1].filter(x => words2.has(x)));
const union = new Set([...words1, ...words2]);
if (union.size === 0)
return 1;
return intersection.size / union.size;
}
/**
* Calculate cosine similarity using word frequency vectors
*/
function cosineSimilarity(text1, text2) {
const freq1 = getWordFrequency(text1);
const freq2 = getWordFrequency(text2);
const allWords = new Set([...Object.keys(freq1), ...Object.keys(freq2)]);
let dotProduct = 0;
let norm1 = 0;
let norm2 = 0;
for (const word of allWords) {
const v1 = freq1[word] || 0;
const v2 = freq2[word] || 0;
dotProduct += v1 * v2;
norm1 += v1 * v1;
norm2 += v2 * v2;
}
if (norm1 === 0 || norm2 === 0)
return 0;
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
/**
* Get word frequency map
*/
function getWordFrequency(text) {
const words = text.toLowerCase().split(/\s+/);
const freq = {};
for (const word of words) {
if (word.length > 0) {
freq[word] = (freq[word] || 0) + 1;
}
}
return freq;
}
/**
* Calculate Levenshtein distance between two strings
*/
function levenshteinDistance(str1, str2) {
const m = str1.length;
const n = str2.length;
const dp = Array(m + 1)
.fill(null)
.map(() => Array(n + 1).fill(0));
for (let i = 0; i <= m; i++)
dp[i][0] = i;
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++) {
if (str1[i - 1] === str2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
}
else {
dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
}
}
}
return dp[m][n];
}
/**
* Calculate normalized Levenshtein similarity (0-1)
*/
function levenshteinSimilarity(str1, str2) {
const maxLen = Math.max(str1.length, str2.length);
if (maxLen === 0)
return 1;
const distance = levenshteinDistance(str1, str2);
return 1 - distance / maxLen;
}
/**
* Combined similarity score using multiple methods
*/
function combinedSimilarity(text1, text2) {
const jaccard = jaccardSimilarity(text1, text2);
const cosine = cosineSimilarity(text1, text2);
// Weighted average
return jaccard * 0.4 + cosine * 0.6;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2ltaWxhcml0eS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9zaW1pbGFyaXR5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7R0FRRzs7QUFLSCw4Q0FVQztBQUtELDRDQXNCQztBQXFCRCxrREEwQkM7QUFLRCxzREFNQztBQUtELGdEQU1DO0FBN0dEOztHQUVHO0FBQ0gsU0FBZ0IsaUJBQWlCLENBQUMsS0FBYSxFQUFFLEtBQWE7SUFDNUQsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ3pELE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUV6RCxNQUFNLFlBQVksR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckUsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFFOUMsSUFBSSxLQUFLLENBQUMsSUFBSSxLQUFLLENBQUM7UUFBRSxPQUFPLENBQUMsQ0FBQztJQUUvQixPQUFPLFlBQVksQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztBQUN4QyxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixnQkFBZ0IsQ0FBQyxLQUFhLEVBQUUsS0FBYTtJQUMzRCxNQUFNLEtBQUssR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN0QyxNQUFNLEtBQUssR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUV0QyxNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRXpFLElBQUksVUFBVSxHQUFHLENBQUMsQ0FBQztJQUNuQixJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7SUFDZCxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7SUFFZCxLQUFLLE1BQU0sSUFBSSxJQUFJLFFBQVEsRUFBRSxDQUFDO1FBQzVCLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUIsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUU1QixVQUFVLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQztRQUN0QixLQUFLLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQztRQUNqQixLQUFLLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQztJQUNuQixDQUFDO0lBRUQsSUFBSSxLQUFLLEtBQUssQ0FBQyxJQUFJLEtBQUssS0FBSyxDQUFDO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFFekMsT0FBTyxVQUFVLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUM1RCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLGdCQUFnQixDQUFDLElBQVk7SUFDcEMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM5QyxNQUFNLElBQUksR0FBMkIsRUFBRSxDQUFDO0lBRXhDLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7UUFDekIsSUFBSSxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3BCLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDckMsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLG1CQUFtQixDQUFDLElBQVksRUFBRSxJQUFZO0lBQzVELE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDdEIsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUV0QixNQUFNLEVBQUUsR0FBZSxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFDO1NBQ1YsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFbkMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUU7UUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFO1FBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUUxQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDNUIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQzVCLElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ2hDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUM5QixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUNyQixFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUNaLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQ1osRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQ2pCLENBQUM7WUFDSixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNsQixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixxQkFBcUIsQ0FBQyxJQUFZLEVBQUUsSUFBWTtJQUM5RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2xELElBQUksTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLENBQUMsQ0FBQztJQUUzQixNQUFNLFFBQVEsR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDakQsT0FBTyxDQUFDLEdBQUcsUUFBUSxHQUFHLE1BQU0sQ0FBQztBQUMvQixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixrQkFBa0IsQ0FBQyxLQUFhLEVBQUUsS0FBYTtJQUM3RCxNQUFNLE9BQU8sR0FBRyxpQkFBaUIsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDaEQsTUFBTSxNQUFNLEdBQUcsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBRTlDLG1CQUFtQjtJQUNuQixPQUFPLE9BQU8sR0FBRyxHQUFHLEdBQUcsTUFBTSxHQUFHLEdBQUcsQ0FBQztBQUN0QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUZXh0IFNpbWlsYXJpdHkgVXRpbGl0aWVzXG4gKiBcbiAqIFNpbXBsZSBzaW1pbGFyaXR5IG1lYXN1cmVzIGZvciBjb25zaXN0ZW5jeSBjaGVja2luZy5cbiAqIFxuICogQG1vZHVsZSB1dGlscy9zaW1pbGFyaXR5XG4gKiBAYXV0aG9yIEhhaWVjXG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG4vKipcbiAqIENhbGN1bGF0ZSBKYWNjYXJkIHNpbWlsYXJpdHkgYmV0d2VlbiB0d28gdGV4dHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGphY2NhcmRTaW1pbGFyaXR5KHRleHQxOiBzdHJpbmcsIHRleHQyOiBzdHJpbmcpOiBudW1iZXIge1xuICBjb25zdCB3b3JkczEgPSBuZXcgU2V0KHRleHQxLnRvTG93ZXJDYXNlKCkuc3BsaXQoL1xccysvKSk7XG4gIGNvbnN0IHdvcmRzMiA9IG5ldyBTZXQodGV4dDIudG9Mb3dlckNhc2UoKS5zcGxpdCgvXFxzKy8pKTtcbiAgXG4gIGNvbnN0IGludGVyc2VjdGlvbiA9IG5ldyBTZXQoWy4uLndvcmRzMV0uZmlsdGVyKHggPT4gd29yZHMyLmhhcyh4KSkpO1xuICBjb25zdCB1bmlvbiA9IG5ldyBTZXQoWy4uLndvcmRzMSwgLi4ud29yZHMyXSk7XG4gIFxuICBpZiAodW5pb24uc2l6ZSA9PT0gMCkgcmV0dXJuIDE7XG4gIFxuICByZXR1cm4gaW50ZXJzZWN0aW9uLnNpemUgLyB1bmlvbi5zaXplO1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZSBjb3NpbmUgc2ltaWxhcml0eSB1c2luZyB3b3JkIGZyZXF1ZW5jeSB2ZWN0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb3NpbmVTaW1pbGFyaXR5KHRleHQxOiBzdHJpbmcsIHRleHQyOiBzdHJpbmcpOiBudW1iZXIge1xuICBjb25zdCBmcmVxMSA9IGdldFdvcmRGcmVxdWVuY3kodGV4dDEpO1xuICBjb25zdCBmcmVxMiA9IGdldFdvcmRGcmVxdWVuY3kodGV4dDIpO1xuICBcbiAgY29uc3QgYWxsV29yZHMgPSBuZXcgU2V0KFsuLi5PYmplY3Qua2V5cyhmcmVxMSksIC4uLk9iamVjdC5rZXlzKGZyZXEyKV0pO1xuICBcbiAgbGV0IGRvdFByb2R1Y3QgPSAwO1xuICBsZXQgbm9ybTEgPSAwO1xuICBsZXQgbm9ybTIgPSAwO1xuICBcbiAgZm9yIChjb25zdCB3b3JkIG9mIGFsbFdvcmRzKSB7XG4gICAgY29uc3QgdjEgPSBmcmVxMVt3b3JkXSB8fCAwO1xuICAgIGNvbnN0IHYyID0gZnJlcTJbd29yZF0gfHwgMDtcbiAgICBcbiAgICBkb3RQcm9kdWN0ICs9IHYxICogdjI7XG4gICAgbm9ybTEgKz0gdjEgKiB2MTtcbiAgICBub3JtMiArPSB2MiAqIHYyO1xuICB9XG4gIFxuICBpZiAobm9ybTEgPT09IDAgfHwgbm9ybTIgPT09IDApIHJldHVybiAwO1xuICBcbiAgcmV0dXJuIGRvdFByb2R1Y3QgLyAoTWF0aC5zcXJ0KG5vcm0xKSAqIE1hdGguc3FydChub3JtMikpO1xufVxuXG4vKipcbiAqIEdldCB3b3JkIGZyZXF1ZW5jeSBtYXBcbiAqL1xuZnVuY3Rpb24gZ2V0V29yZEZyZXF1ZW5jeSh0ZXh0OiBzdHJpbmcpOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+IHtcbiAgY29uc3Qgd29yZHMgPSB0ZXh0LnRvTG93ZXJDYXNlKCkuc3BsaXQoL1xccysvKTtcbiAgY29uc3QgZnJlcTogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHt9O1xuICBcbiAgZm9yIChjb25zdCB3b3JkIG9mIHdvcmRzKSB7XG4gICAgaWYgKHdvcmQubGVuZ3RoID4gMCkge1xuICAgICAgZnJlcVt3b3JkXSA9IChmcmVxW3dvcmRdIHx8IDApICsgMTtcbiAgICB9XG4gIH1cbiAgXG4gIHJldHVybiBmcmVxO1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZSBMZXZlbnNodGVpbiBkaXN0YW5jZSBiZXR3ZWVuIHR3byBzdHJpbmdzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsZXZlbnNodGVpbkRpc3RhbmNlKHN0cjE6IHN0cmluZywgc3RyMjogc3RyaW5nKTogbnVtYmVyIHtcbiAgY29uc3QgbSA9IHN0cjEubGVuZ3RoO1xuICBjb25zdCBuID0gc3RyMi5sZW5ndGg7XG4gIFxuICBjb25zdCBkcDogbnVtYmVyW11bXSA9IEFycmF5KG0gKyAxKVxuICAgIC5maWxsKG51bGwpXG4gICAgLm1hcCgoKSA9PiBBcnJheShuICsgMSkuZmlsbCgwKSk7XG4gIFxuICBmb3IgKGxldCBpID0gMDsgaSA8PSBtOyBpKyspIGRwW2ldWzBdID0gaTtcbiAgZm9yIChsZXQgaiA9IDA7IGogPD0gbjsgaisrKSBkcFswXVtqXSA9IGo7XG4gIFxuICBmb3IgKGxldCBpID0gMTsgaSA8PSBtOyBpKyspIHtcbiAgICBmb3IgKGxldCBqID0gMTsgaiA8PSBuOyBqKyspIHtcbiAgICAgIGlmIChzdHIxW2kgLSAxXSA9PT0gc3RyMltqIC0gMV0pIHtcbiAgICAgICAgZHBbaV1bal0gPSBkcFtpIC0gMV1baiAtIDFdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZHBbaV1bal0gPSAxICsgTWF0aC5taW4oXG4gICAgICAgICAgZHBbaSAtIDFdW2pdLFxuICAgICAgICAgIGRwW2ldW2ogLSAxXSxcbiAgICAgICAgICBkcFtpIC0gMV1baiAtIDFdXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICByZXR1cm4gZHBbbV1bbl07XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlIG5vcm1hbGl6ZWQgTGV2ZW5zaHRlaW4gc2ltaWxhcml0eSAoMC0xKVxuICovXG5leHBvcnQgZnVuY3Rpb24gbGV2ZW5zaHRlaW5TaW1pbGFyaXR5KHN0cjE6IHN0cmluZywgc3RyMjogc3RyaW5nKTogbnVtYmVyIHtcbiAgY29uc3QgbWF4TGVuID0gTWF0aC5tYXgoc3RyMS5sZW5ndGgsIHN0cjIubGVuZ3RoKTtcbiAgaWYgKG1heExlbiA9PT0gMCkgcmV0dXJuIDE7XG4gIFxuICBjb25zdCBkaXN0YW5jZSA9IGxldmVuc2h0ZWluRGlzdGFuY2Uoc3RyMSwgc3RyMik7XG4gIHJldHVybiAxIC0gZGlzdGFuY2UgLyBtYXhMZW47XG59XG5cbi8qKlxuICogQ29tYmluZWQgc2ltaWxhcml0eSBzY29yZSB1c2luZyBtdWx0aXBsZSBtZXRob2RzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21iaW5lZFNpbWlsYXJpdHkodGV4dDE6IHN0cmluZywgdGV4dDI6IHN0cmluZyk6IG51bWJlciB7XG4gIGNvbnN0IGphY2NhcmQgPSBqYWNjYXJkU2ltaWxhcml0eSh0ZXh0MSwgdGV4dDIpO1xuICBjb25zdCBjb3NpbmUgPSBjb3NpbmVTaW1pbGFyaXR5KHRleHQxLCB0ZXh0Mik7XG4gIFxuICAvLyBXZWlnaHRlZCBhdmVyYWdlXG4gIHJldHVybiBqYWNjYXJkICogMC40ICsgY29zaW5lICogMC42O1xufVxuIl19