Beta/commandes/security/auto_moderation.py

199 lines
8.9 KiB
Python
Raw Permalink Normal View History

2026-02-06 22:23:20 +01:00
"""
Module de modération automatique pour Superviseur Bot
Gère la détection et sanction des messages inappropriés automatiquement sur tous les messages
"""
import discord
import aiohttp
import json
import os
from datetime import datetime
WARNINGS_FILE = 'warnings.json'
def load_warnings():
"""Charge les avertissements depuis le fichier JSON"""
if os.path.exists(WARNINGS_FILE):
with open(WARNINGS_FILE, 'r', encoding='utf-8') as f:
content = f.read().strip()
if content:
return json.loads(content)
return {}
def save_warnings(warnings):
"""Sauvegarde les avertissements dans le fichier JSON"""
with open(WARNINGS_FILE, 'w', encoding='utf-8') as f:
json.dump(warnings, f, indent=4, ensure_ascii=False)
async def check_message_content_global(bot, content):
"""
Vérifie le contenu d'un message pour tout contenu inapproprié
Utilise une liste locale de mots inappropriés pour performance optimale
"""
# Liste optimisée de mots inappropriés (mots-clés critiques seulement pour performance)
bad_words = {
# Mots critiques (haute sévérité)
'nigger', 'nigga', 'pédé', 'bougnoul', 'viol', 'pédophile', 'inceste', 'naziste', 'hitler',
'suicide', 'se tuer', 'se suicider', 'tuer', 'assassiner', 'meurtre',
# Gros mots courants
'fuck', 'shit', 'asshole', 'bitch', 'dick', 'pussy', 'cunt', 'motherfucker',
'merde', 'putain', 'salope', 'connard', 'enculé', 'bordel', 'emmerde',
'ta gueule', 'va te faire foutre', 'va te faire enculer', 'va chier', 'crève',
'branleur', 'sucer', 'pipe', 'pétasse', 'garce', 'traînée', 'salopard', 'ordure',
'fumier', 'pourri', 'dégueulasse', 'gueule', 'gueuler',
# Insultes
'con', 'abruti', 'débile', 'crétin', 'imbécile', 'loser', 'nullos', 'naze',
'ridicule', 'pathétique', 'minable', 'nul', 'inutile', 'incapable', 'bon à rien',
# NSFW/sexuel
'sexe', 'porn', 'porno', 'bite', 'seins', 'sodomie', 'agression sexuelle',
'harceleur', 'stalker',
# Discrimination
'raciste', 'antisémite', 'fasciste', 'gay', 'homo', 'féminin',
# Drogues
'drogue', 'cocaine', 'héroine', 'cannabis', 'ecstasy', 'lsd', 'crack', 'speed',
'amphétamine', 'steroide', 'anabolisant',
# Autres
'cancer', 'maladie grave', 'crever', 'mourir'
}
content_lower = content.lower()
detected_bad_words = []
# Recherche rapide avec set pour performance
for bad_word in bad_words:
bad_word_lower = bad_word.lower()
# Recherche insensible à la casse avec délimiteurs pour éviter faux positifs
if f" {bad_word_lower} " in f" {content_lower} " or content_lower == bad_word_lower:
detected_bad_words.append(bad_word)
# Continue pour lister tous les mots détectés, mais limite à 3 pour performance
if len(detected_bad_words) >= 3:
break
if detected_bad_words:
severity = "high" if any(word in ['nigger', 'nigga', 'pédé', 'bougnoul', 'viol', 'pédophile', 'inceste', 'naziste', 'hitler', 'suicide', 'se tuer', 'tuer', 'assassiner', 'meurtre'] for word in detected_bad_words) else "medium"
return {
"inappropriate": True,
"severity": severity,
"reason": f"Mots inappropriés détectés: {', '.join(detected_bad_words[:3])}",
"bad_words": detected_bad_words[:3]
}
return {"inappropriate": False}
async def warn_and_check_ban_global(message, reason, message_deleted=False):
"""
Émet un avertissement et vérifie si l'utilisateur doit être banni (3+ avertissements)
"""
guild_id = str(message.guild.id)
all_warnings = load_warnings()
if guild_id not in all_warnings:
all_warnings[guild_id] = {}
user_id_str = str(message.author.id)
if user_id_str not in all_warnings[guild_id]:
all_warnings[guild_id][user_id_str] = []
# Ajouter l'avertissement
all_warnings[guild_id][user_id_str].append({
'reason': reason,
'timestamp': datetime.now().isoformat(),
'issued_by': 'AUTOMATIC_MODERATION'
})
warning_count = len(all_warnings[guild_id][user_id_str])
save_warnings(all_warnings)
from commandes.autres.logger import action_logger
action_logger.log_action('AUTOMATIC_MODERATION', str(message.author), str(message.guild), {
'reason': reason,
'warning_count': warning_count,
'original_message': message.content
}, True)
# Vérifier si bannissement automatique nécessaire
if warning_count >= 3:
try:
await message.author.ban(reason=f"Bannissement automatique: 3 avertissements accumulés. Dernière raison: {reason}")
embed = discord.Embed(
title="🚫 Bannissement automatique",
description=f"{message.author.mention}, vous avez été banni pour accumulation d'avertissements (3+ avertissements).\n**Dernière raison:** {reason}",
color=discord.Color.red()
)
embed.set_footer(text=f"Total d'avertissements: {warning_count}")
await message.channel.send(embed=embed)
return True # Utilisateur banni
except discord.Forbidden:
embed = discord.Embed(
title="Ban requis",
description=f"{message.author.mention} a 3+ avertissements, mais le bot n'a pas les permissions de bannir.\n**Agissez manuellement!**",
color=discord.Color.red()
)
embed.set_footer(text=f"Total d'avertissements: {warning_count}")
await message.channel.send(embed=embed)
return False
else:
# Envoyer message d'avertissement
deletion_text = "Votre message a été supprimé pour contenu inapproprié." if message_deleted else "Mots inappropriés détectés dans votre message."
warning_message = f"⚠️ **Avertissement automatique** {message.author.mention}\n{deletion_text}\n**Raison:** {reason}\n**Avertissements totaux:** {warning_count}\n**Avant bannissement:** {3 - warning_count} avertissement(s)\n*Modération automatique par IA*"
await message.channel.send(warning_message)
return False
async def moderate_message(bot, message):
"""
Fonction principale de modération automatique d'un message
Retourne True si le message a été modéré (et donc supprimé), False sinon
"""
# Préparer le contenu à analyser
content_to_check = message.content
if message.attachments:
for attachment in message.attachments:
if attachment.content_type and attachment.content_type.startswith('image/'):
if not content_to_check.strip():
content_to_check = f"[Image: {attachment.filename}]"
else:
content_to_check += f" [Image: {attachment.filename}]"
# Analyser le contenu
if content_to_check.strip():
print(f"[MODERATION] Analysing message from {message.author}: '{content_to_check}'")
moderation_result = await check_message_content_global(bot, content_to_check)
print(f"[MODERATION] Result: {moderation_result}")
bad_words = moderation_result.get('bad_words', [])
inappropriate = moderation_result.get('inappropriate', False)
print(f"[MODERATION] bad_words: {bad_words}, inappropriate: {inappropriate}")
# Toujours donner un avertissement si des mots inappropriés sont détectés
if bad_words:
reason = f"Mots inappropriés détectés: {', '.join(bad_words[:5])}"
print(f"[MODERATION] Processing bad words, reason: {reason}")
if inappropriate:
print(f"[MODERATION] Message inappropriate, deleting...")
try:
await message.delete()
print(f"[MODERATION] Message deleted successfully")
except discord.Forbidden:
print(f"[MODERATION] Forbidden to delete message")
pass # Impossible de supprimer
except Exception as e:
print(f"[MODERATION] Error deleting message: {e}")
await warn_and_check_ban_global(message, reason, message_deleted=True)
print(f"[MODERATION] Warning sent and ban checked, returning True")
return True # Message modéré
else:
print(f"[MODERATION] Not inappropriate, sending warning without deletion")
await warn_and_check_ban_global(message, reason, message_deleted=False)
return False # Message autorisé
# Test function pour vérifier la fonctionnalité
async def test_auto_moderation():
"""Fonction de test pour vérifier que les avertissements sont toujours donnés"""
print("Test auto-moderation: vérification que les avertissements sont donnés pour les mots inappropriés")
# Cette fonction peut être appelée pour tester manuellement si nécessaire