diff options
| author | Fuwn <[email protected]> | 2025-09-25 19:08:58 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2025-09-25 19:08:58 -0700 |
| commit | 53e59e5ff98c343b396531be24575b353d292f8f (patch) | |
| tree | 5832184e6f9c73c5cec6b6a969f577829fc24378 | |
| parent | feat(gateway:aiModeration): Ignore simple message patterns (diff) | |
| download | umabotdiscord-53e59e5ff98c343b396531be24575b353d292f8f.tar.xz umabotdiscord-53e59e5ff98c343b396531be24575b353d292f8f.zip | |
feat(gateway:aiModeration): Optimise API costs
| -rw-r--r-- | packages/gateway/src/listeners/aiModeration.ts | 257 |
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()) { |