import logging import re logger = logging.getLogger('Superviseur') class HeuristicsManager: """Handles parsing and computing heuristic risk scores for messages.""" def __init__(self, bot): self.bot = bot def assess_risk(self, message) -> bool: """ Fast Python-side risk assessment to decide if we should AI-analyze fully. Returns True if message is 'risky' enough to warrant LLM usage. """ score = 0 content = message.content # CLEAN content for heuristic analysis (ignore mentions in the score) # We use a copy to avoid modifying the original message object scoring_content = re.sub(r'<@!?\d+>', '', content).strip() if not scoring_content: scoring_content = content # 1. Content Scoring score = 0 # Proactive Analysis: base score if message has substance if len(content) > 10: score += 15 scoring_content = content scoring_content_lower = scoring_content.lower() # CAPS LOCK detection (> 35% caps on messages > 4 chars) if len(scoring_content) > 4: caps_ratio = sum(1 for c in scoring_content if c.isupper()) / len(scoring_content) if caps_ratio > 0.35: score += 35 # Heavy weight logger.debug(f"◈ HEURISTIC: CAPS detected ({caps_ratio:.2f}) on '{scoring_content[:15]}...'") # Profanity / Trigger words (lightweight list) triggers = [ "raid", "hack", "pute", "connard", "fdp", "tg", "merde", "nazi", "hitler", "suicide", "bomb", "token", "grab", "nitro", "steam", "discord.gift", "free", "@everyone", "@here", "detruire", "detruit", "destruction", "kill" ] for t in triggers: if t in scoring_content_lower: score += 50 logger.debug(f"◈ HEURISTIC: Trigger word '{t}' detected") break # Link spam detection if "http" in scoring_content_lower: score += 20 # Length anomaly if len(scoring_content) > 300: score += 20 # 3. Gibberish / Randomness detection (Entropy) if len(scoring_content) > 8: unique_chars = len(set(scoring_content_lower)) diversity_ratio = unique_chars / len(scoring_content) if diversity_ratio < 0.35: # Increased threshold score += 25 logger.debug(f"◈ HEURISTIC: Low diversity detected ({diversity_ratio:.2f})") # Too many non-alphanumeric chars (excluding spaces) symbols = len(re.findall(r'[^a-zA-Z0-9\s]', scoring_content)) symbol_ratio = symbols / len(scoring_content) if symbol_ratio > 0.15: # Lowered threshold for symbols score += 30 logger.debug(f"◈ HEURISTIC: High symbol ratio detected ({symbol_ratio:.2f})") # 4. Leetspeak / Digits in words detection if len(re.findall(r'[a-zA-Z][0-9][a-zA-Z]', scoring_content)) > 0: score += 25 logger.debug("◈ HEURISTIC: Leetspeak patterns detected") # 5. Long word detection (No spaces) words = scoring_content.split() if any(len(w) > 25 for w in words): score += 30 logger.debug("◈ HEURISTIC: Unusually long word detected") # 3. Mention Spam # Fallback detection if library fails to populate message.mentions mention_count = len(message.mentions) if mention_count == 0: mention_count = len(re.findall(r'<@!?\d+>', content)) if mention_count > 3: score += 40 logger.debug(f"◈ HEURISTIC: Mention spam detected ({mention_count} mentions)") # 4. Keyword Detection (Sensitivity helper) if score < 45: for trigger in ["analyse", "écouter", "surveille", "check"]: if trigger in scoring_content_lower: score += 30 break # Threshold decision # Very sensitive threshold to capture more nuances (as requested) logger.info(f"◈ MODERATION RISK: Score Final = {score}/15") return score >= 15