summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-09-25 19:08:58 -0700
committerFuwn <[email protected]>2025-09-25 19:08:58 -0700
commit53e59e5ff98c343b396531be24575b353d292f8f (patch)
tree5832184e6f9c73c5cec6b6a969f577829fc24378
parentfeat(gateway:aiModeration): Ignore simple message patterns (diff)
downloadumabotdiscord-53e59e5ff98c343b396531be24575b353d292f8f.tar.xz
umabotdiscord-53e59e5ff98c343b396531be24575b353d292f8f.zip
feat(gateway:aiModeration): Optimise API costs
-rw-r--r--packages/gateway/src/listeners/aiModeration.ts257
1 files changed, 252 insertions, 5 deletions
diff --git a/packages/gateway/src/listeners/aiModeration.ts b/packages/gateway/src/listeners/aiModeration.ts
index 6abc63b..54f115b 100644
--- a/packages/gateway/src/listeners/aiModeration.ts
+++ b/packages/gateway/src/listeners/aiModeration.ts
@@ -13,6 +13,228 @@ const EXCLUDED_CATEGORIES = [
"1420604833286852608", // Staff Automation
];
const MODERATION_LOG_CHANNEL_ID = "1406422619934167106";
+const MIN_MESSAGE_LENGTH = 15;
+const MAX_SYMBOL_DENSITY = 0.6;
+const MAX_COMPLETION_TOKENS = 1000;
+const MESSAGE_HISTORY_SIZE = 10;
+const SAFE_WORDS = new Set([
+ "hello",
+ "hi",
+ "hey",
+ "bye",
+ "goodbye",
+ "thanks",
+ "thank",
+ "welcome",
+ "please",
+ "sorry",
+ "yes",
+ "no",
+ "maybe",
+ "ok",
+ "okay",
+ "sure",
+ "alright",
+ "fine",
+ "good",
+ "bad",
+ "nice",
+ "cool",
+ "awesome",
+ "great",
+ "amazing",
+ "wow",
+ "omg",
+ "lol",
+ "haha",
+ "hehe",
+ "lmao",
+ "what",
+ "why",
+ "how",
+ "when",
+ "where",
+ "who",
+ "which",
+ "this",
+ "that",
+ "these",
+ "those",
+ "here",
+ "there",
+ "everywhere",
+ "nowhere",
+ "somewhere",
+ "anywhere",
+ "up",
+ "down",
+ "left",
+ "right",
+ "forward",
+ "backward",
+ "start",
+ "stop",
+ "begin",
+ "end",
+ "finish",
+ "first",
+ "last",
+ "next",
+ "previous",
+ "same",
+ "different",
+ "similar",
+ "opposite",
+ "more",
+ "less",
+ "most",
+ "least",
+ "many",
+ "few",
+ "big",
+ "small",
+ "large",
+ "tiny",
+ "huge",
+ "mini",
+ "fast",
+ "slow",
+ "quick",
+ "rapid",
+ "hot",
+ "cold",
+ "warm",
+ "cool",
+ "new",
+ "old",
+ "young",
+ "fresh",
+ "easy",
+ "hard",
+ "simple",
+ "complex",
+ "happy",
+ "sad",
+ "angry",
+ "excited",
+ "bored",
+ "always",
+ "never",
+ "sometimes",
+ "often",
+ "rarely",
+ "today",
+ "yesterday",
+ "tomorrow",
+ "tonight",
+ "morning",
+ "afternoon",
+ "evening",
+ "night",
+ "monday",
+ "tuesday",
+ "wednesday",
+ "thursday",
+ "friday",
+ "saturday",
+ "sunday",
+ "january",
+ "february",
+ "march",
+ "april",
+ "may",
+ "june",
+ "july",
+ "august",
+ "september",
+ "october",
+ "november",
+ "december",
+ "true",
+ "false",
+ "maybe",
+ "probably",
+ "definitely",
+ "certainly",
+ "absolutely",
+ "exactly",
+ "precisely",
+ "correct",
+ "wrong",
+ "right",
+ "wrong",
+ "mistake",
+ "error",
+ "success",
+ "failure",
+ "win",
+ "lose",
+ "victory",
+ "defeat",
+ "champion",
+ "winner",
+ "loser",
+ "player",
+ "game",
+ "play",
+ "fun",
+ "boring",
+ "interesting",
+ "exciting",
+ "calm",
+ "peaceful",
+ "quiet",
+ "loud",
+ "silent",
+ "bright",
+ "dark",
+ "light",
+ "heavy",
+ "empty",
+ "full",
+ "open",
+ "closed",
+ "free",
+ "busy",
+ "available",
+ "unavailable",
+ "online",
+ "offline",
+ "active",
+ "inactive",
+ "ready",
+ "not ready",
+]);
+const LOW_RISK_PATTERNS = [
+ /^(good|bad|nice|great|awesome|terrible|amazing|wow|omg|wtf|haha|hehe|lmao|rofl)$/i,
+ /^(what|why|how|when|where|who)$/i,
+ /^(this|that|these|those)$/i,
+ /^(here|there|everywhere|nowhere)$/i,
+ /^(up|down|left|right|forward|backward)$/i,
+ /^(start|stop|begin|end|finish)$/i,
+ /^(first|last|next|previous)$/i,
+ /^(same|different|similar|opposite)$/i,
+ /^(more|less|most|least|many|few)$/i,
+ /^(big|small|large|tiny|huge|mini)$/i,
+ /^(fast|slow|quick|rapid|slowly)$/i,
+ /^(hot|cold|warm|cool|freezing)$/i,
+ /^(new|old|young|fresh|stale)$/i,
+ /^(easy|hard|simple|complex|difficult)$/i,
+ /^(happy|sad|angry|excited|bored)$/i,
+ /^(sure|maybe|perhaps|probably|definitely)$/i,
+ /^(always|never|sometimes|often|rarely)$/i,
+ /^(today|yesterday|tomorrow|tonight|morning)$/i,
+ /^(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i,
+ /^(january|february|march|april|may|june|july|august|september|october|november|december)$/i,
+ /^(ok|okay|yes|no|hi|hey|yo|lol|thanks|thx|np|cool)$/i,
+ /^(true|false|maybe|probably|definitely|certainly|absolutely)$/i,
+ /^(exactly|precisely|correct|wrong|right|mistake|error)$/i,
+ /^(success|failure|win|lose|victory|defeat|champion|winner|loser)$/i,
+ /^(player|game|play|fun|boring|interesting|exciting|calm|peaceful)$/i,
+ /^(quiet|loud|silent|bright|dark|light|heavy|empty|full)$/i,
+ /^(open|closed|free|busy|available|unavailable|online|offline)$/i,
+ /^(active|inactive|ready|not ready|working|broken|fixed|repair)$/i,
+];
const SERVER_RULES = `
# Rules
@@ -57,7 +279,7 @@ const fetchMessageContext = async (
): Promise<string> => {
try {
const messages = await channel.messages.fetch({
- limit: 20,
+ limit: MESSAGE_HISTORY_SIZE,
before: messageId,
});
const contextMessages = Array.from(messages.values())
@@ -213,7 +435,7 @@ CONTEXT UNDERSTANDING:
content: prompt,
},
],
- max_completion_tokens: 2000,
+ max_completion_tokens: MAX_COMPLETION_TOKENS,
}),
});
@@ -269,6 +491,14 @@ export const handleAIModeration = (client: Client) => {
if (!message.content && message.attachments.size === 0) return;
+ if (!message.content && message.attachments.size > 0) {
+ console.log(
+ `AI Moderation: Skipping attachment-only message (handled by iqdb)`,
+ );
+
+ return;
+ }
+
if (message.content) {
const content = message.content.trim();
@@ -281,7 +511,10 @@ export const handleAIModeration = (client: Client) => {
const shortWhitelist =
/^(ok|okay|yes|no|hi|hey|yo|lol|thanks|thx|np|cool)$/i;
- if (content.length < 10 && !shortWhitelist.test(content)) {
+ if (
+ content.length < MIN_MESSAGE_LENGTH &&
+ !shortWhitelist.test(content)
+ ) {
console.log(
`AI Moderation: Skipping short message (${content.length} chars): "${content}"`,
);
@@ -311,13 +544,27 @@ export const handleAIModeration = (client: Client) => {
const symbolDensity =
content.replace(/[\p{L}\p{N}\s]/gu, "").length / content.length;
- if (symbolDensity > 0.6 && content.length > 3) {
+ if (symbolDensity >= MAX_SYMBOL_DENSITY && content.length > 3) {
console.log(
- `AI Moderation: Skipping textmoji-like message: "${content}"`,
+ `AI Moderation: Skipping high symbol density message (${(symbolDensity * 100).toFixed(1)}%): "${content}"`,
);
return;
}
+
+ for (const pattern of LOW_RISK_PATTERNS)
+ if (pattern.test(content)) {
+ console.log(`AI Moderation: Skipping low-risk pattern: "${content}"`);
+
+ return;
+ }
+
+ if (content.length <= 20 && /^[a-zA-Z]+$/.test(content))
+ if (SAFE_WORDS.has(content.toLowerCase())) {
+ console.log(`AI Moderation: Skipping safe word: "${content}"`);
+
+ return;
+ }
}
if (message.channel.isThread()) {