Add whitelisting support

This commit is contained in:
2025-08-18 22:08:42 -03:00
parent a994c86f98
commit 118dacff20
+28 -119
View File
@@ -85,6 +85,7 @@
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use itertools::Itertools;
use linkify::LinkFinder; use linkify::LinkFinder;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
@@ -426,6 +427,26 @@ fn parse_phrases_file(file_content: &str) -> (Vec<String>, Vec<String>) {
(banned, exceptions) (banned, exceptions)
} }
fn find_with_exceptions(message: &str, pattern: &Regex, exceptions: &[String]) -> Vec<String> {
pattern
.find_iter(message)
.filter_map(|m| {
let string = message[m.start()..m.end()].to_string();
if exceptions.contains(
&string
.split_ascii_whitespace()
.join(" ")
.to_ascii_lowercase(),
) {
None
} else {
Some(string)
}
})
.collect()
}
struct HateSpeechAndSlursRule { struct HateSpeechAndSlursRule {
pattern: Regex, pattern: Regex,
exceptions: Vec<String>, exceptions: Vec<String>,
@@ -457,23 +478,7 @@ impl Rule for HateSpeechAndSlursRule {
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) { fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
( (
vec![], vec![],
self.pattern find_with_exceptions(normalized, &self.pattern, &self.exceptions),
.find_iter(normalized)
.filter_map(|m| {
let string = normalized[m.start()..m.end()].to_string();
if self.exceptions.contains(
&string
.split_ascii_whitespace()
.collect::<String>()
.to_ascii_lowercase(),
) {
None
} else {
Some(string)
}
})
.collect(),
) )
} }
} }
@@ -509,23 +514,7 @@ impl Rule for ThreatsAndSelfHarmRule {
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) { fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
( (
vec![], vec![],
self.pattern find_with_exceptions(normalized, &self.pattern, &self.exceptions),
.find_iter(normalized)
.filter_map(|m| {
let string = normalized[m.start()..m.end()].to_string();
if self.exceptions.contains(
&string
.split_ascii_whitespace()
.collect::<String>()
.to_ascii_lowercase(),
) {
None
} else {
Some(string)
}
})
.collect(),
) )
} }
} }
@@ -561,23 +550,7 @@ impl Rule for ExplicitSexualLanguageRule {
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) { fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
( (
vec![], vec![],
self.pattern find_with_exceptions(normalized, &self.pattern, &self.exceptions),
.find_iter(normalized)
.filter_map(|m| {
let string = normalized[m.start()..m.end()].to_string();
if self.exceptions.contains(
&string
.split_ascii_whitespace()
.collect::<String>()
.to_ascii_lowercase(),
) {
None
} else {
Some(string)
}
})
.collect(),
) )
} }
} }
@@ -613,23 +586,7 @@ impl Rule for SuggestiveLanguageRule {
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) { fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
( (
vec![], vec![],
self.pattern find_with_exceptions(normalized, &self.pattern, &self.exceptions),
.find_iter(normalized)
.filter_map(|m| {
let string = normalized[m.start()..m.end()].to_string();
if self.exceptions.contains(
&string
.split_ascii_whitespace()
.collect::<String>()
.to_ascii_lowercase(),
) {
None
} else {
Some(string)
}
})
.collect(),
) )
} }
} }
@@ -695,23 +652,7 @@ impl Rule for SensitiveTopicsAndTriggeringContentRule {
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) { fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
( (
vec![], vec![],
self.pattern find_with_exceptions(normalized, &self.pattern, &self.exceptions),
.find_iter(normalized)
.filter_map(|m| {
let string = normalized[m.start()..m.end()].to_string();
if self.exceptions.contains(
&string
.split_ascii_whitespace()
.collect::<String>()
.to_ascii_lowercase(),
) {
None
} else {
Some(string)
}
})
.collect(),
) )
} }
} }
@@ -746,23 +687,7 @@ impl Rule for MildSwearWordsRule {
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) { fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
( (
vec![], vec![],
self.pattern find_with_exceptions(normalized, &self.pattern, &self.exceptions),
.find_iter(normalized)
.filter_map(|m| {
let string = normalized[m.start()..m.end()].to_string();
if self.exceptions.contains(
&string
.split_ascii_whitespace()
.collect::<String>()
.to_ascii_lowercase(),
) {
None
} else {
Some(string)
}
})
.collect(),
) )
} }
} }
@@ -798,23 +723,7 @@ impl Rule for CasualInsultsAndTeasing {
fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) { fn detect(&self, _original: &str, normalized: &str) -> (Vec<String>, Vec<String>) {
( (
vec![], vec![],
self.pattern find_with_exceptions(normalized, &self.pattern, &self.exceptions),
.find_iter(normalized)
.filter_map(|m| {
let string = normalized[m.start()..m.end()].to_string();
if self.exceptions.contains(
&string
.split_ascii_whitespace()
.collect::<String>()
.to_ascii_lowercase(),
) {
None
} else {
Some(string)
}
})
.collect(),
) )
} }
} }