llm-guard
Version:
A TypeScript library for validating and securing LLM prompts
114 lines (113 loc) • 4.15 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RelevanceGuard = void 0;
const base_1 = require("./base");
class RelevanceGuard extends base_1.BaseGuard {
constructor(enabled = true, options = {}) {
super(enabled);
this.minLength = options.minLength || 10;
this.maxLength = options.maxLength || 5000;
this.minWords = options.minWords || 3;
this.maxWords = options.maxWords || 1000;
this.commonFillerWords = new Set([
'um', 'uh', 'ah', 'er', 'like', 'you know', 'sort of', 'kind of',
'basically', 'literally', 'actually', 'so', 'well', 'right'
]);
}
calculateRelevanceScore(text) {
let score = 1.0;
// Check length
if (text.length < this.minLength) {
score -= 0.3;
}
if (text.length > this.maxLength) {
score -= 0.2;
}
// Check word count
const words = text.split(/\s+/).filter(word => word.length > 0);
if (words.length < this.minWords) {
score -= 0.3;
}
if (words.length > this.maxWords) {
score -= 0.2;
}
// Check for filler words
let fillerWordCount = 0;
for (const word of words) {
if (this.commonFillerWords.has(word.toLowerCase())) {
fillerWordCount++;
}
}
// Reduce score based on filler word ratio
const fillerRatio = fillerWordCount / words.length;
if (fillerRatio > 0.3) {
score -= fillerRatio * 0.5;
}
// Check for repetitive content
const repeatedPhrases = this.findRepeatedPhrases(text);
score -= repeatedPhrases * 0.1;
return Math.max(0, score);
}
findRepeatedPhrases(text) {
const words = text.toLowerCase().split(/\s+/);
const phrases = new Map();
let repeatedCount = 0;
// Check for 2-3 word phrases
for (let i = 0; i < words.length - 1; i++) {
const phrase2 = `${words[i]} ${words[i + 1]}`;
phrases.set(phrase2, (phrases.get(phrase2) || 0) + 1);
if (i < words.length - 2) {
const phrase3 = `${words[i]} ${words[i + 1]} ${words[i + 2]}`;
phrases.set(phrase3, (phrases.get(phrase3) || 0) + 1);
}
}
// Count phrases that appear more than once
for (const count of phrases.values()) {
if (count > 1) {
repeatedCount++;
}
}
return repeatedCount;
}
async validate(text) {
if (!this.isEnabled()) {
return this.createResult(true);
}
const score = this.calculateRelevanceScore(text);
const isRelevant = score >= 0.6;
const details = [];
// Add length details
if (text.length < this.minLength) {
details.push({
rule: 'relevance_length',
message: `Text is too short (${text.length} chars, minimum ${this.minLength})`,
matched: text
});
}
if (text.length > this.maxLength) {
details.push({
rule: 'relevance_length',
message: `Text is too long (${text.length} chars, maximum ${this.maxLength})`,
matched: text
});
}
// Add word count details
const words = text.split(/\s+/).filter(word => word.length > 0);
if (words.length < this.minWords) {
details.push({
rule: 'relevance_word_count',
message: `Text has too few words (${words.length}, minimum ${this.minWords})`,
matched: text
});
}
if (words.length > this.maxWords) {
details.push({
rule: 'relevance_word_count',
message: `Text has too many words (${words.length}, maximum ${this.maxWords})`,
matched: text
});
}
return this.createResult(isRelevant, score, details);
}
}
exports.RelevanceGuard = RelevanceGuard;