198 lines
8.9 KiB
Python
198 lines
8.9 KiB
Python
"""
|
|
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 = 'data/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
|