Beta/beta.py.save

165 lines
11 KiB
Text

import os
from dotenv import load_dotenv
import discord
import importlib
from superviseur import Superviseur
from commandes.autres.config import config
import threading
import asyncio
# --- Configuration et Chargement des Variables d'Environnement ---
load_dotenv()
DISCORD_TOKEN = os.getenv('DISCORD_TOKEN')
try:
GUILD_ID = int(os.getenv('GUILD_ID'))
except (ValueError, TypeError):
print("Erreur: GUILD_ID n'est pas défini ou n'est pas un nombre entier valide.")
exit()
OLLAMA_API_URL = os.getenv("OLLAMA_API_BASE_URL", "http://localhost:11434") + "/api/generate"
# LE MODELE OLLAMA UTILISE POUR LES CONVERSATIONS !
#OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "gemma3:12b") # Laisser ces lignes intactes !
#OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "gpt-oss:20b") # Laisser ces lignes intactes !
#OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "deepseek-r1:7b") # Laisser ces lignes intactes !
#OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "nemotron-3-nano:30b") # Laisser ces lignes intactes !
#OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "gemini-3-pro-preview") # Laisser ces lignes intactes !
#OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "gpt-oss:20b-cloud") # Laisser ces lignes intactes !
#OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "kimi-k2:1t-cloud") # Laisser ces lignes intactes !OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "deepseek-r1:7b") # Laisser ces lignes intactes !
#OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "SimonPu/gpt-oss:20b_Q4_K_M")
# LE MODELE OLLAMA UTILISE POUR LA MODÉRATION AUTOMATIQUE !
#OLLAMA_MODERATION_MODEL = os.getenv("OLLAMA_MODERATION_MODEL", "kimi-k2:1t-cloud") # Modèle pour la modération automatique
#OLLAMA_MODERATION_MODEL = os.getenv("OLLAMA_MODERATION_MODEL", "nemotron-3-nano:30b") # Modèle pour la modération automatique
OLLAMA_MODERATION_MODEL = os.getenv("OLLAMA_MODERATION_MODEL", "deepseek-r1:7b") # Modèle pour la modération automatique
#OLLAMA_MODERATION_MODEL = os.getenv("OLLAMA_MODERATION_MODEL", "gpt-oss:20b") # Modèle pour la modération automatique
OLLAMA_API_KEY = os.getenv("OLLAMA_API_KEY")
try:
OLLAMA_TIMEOUT = int(os.getenv("OLLAMA_TIMEOUT", 600))
except (ValueError, TypeError):
print("Avertissement: OLLAMA_TIMEOUT n'est pas un entier valide. Utilisation de la valeur par défaut (600s).")
OLLAMA_TIMEOUT = 600
try:
OLLAMA_TEMPERATURE = float(os.getenv("OLLAMA_TEMPERATURE", 0.2))
except (ValueError, TypeError):
print("Avertissement: OLLAMA_TEMPERATURE n'est pas un nombre valide. Utilisation de la valeur par défaut (0.7).")
OLLAMA_TEMPERATURE = 0.2
# --- PROMPT SYSTÈME CENTRALISÉ ---
# Ceci est l'instruction donnée au modèle LLM pour définir son rôle et les formats de réponse.
# Les actions disponibles dans le prompt DOIVENT correspondre aux fonctions implémentées
# dans superviseur_bot.py.
SYSTEM_PROMPT = (
"Vous êtes le Superviseur, un assistant de modération hautement efficace sur un serveur Discord."
"Votre rôle est d'analyser la demande de l'utilisateur."
"Il y a deux types d'utilisateurs : les utilisateurs réguliers et les modérateurs."
"Les informations système suivantes te sont toujours fournies avant la conversation : une ligne de la forme 'Permissions de l'utilisateur: oui|non, Niveau whitelist: <valeur>'."
"Si cette ligne indique 'oui', ALORS tu dois considérer que l'utilisateur est un modérateur autorisé à utiliser les actions JSON ci-dessous, même si la liste des rôles du serveur ne permet pas de le déduire."
"Si cette ligne indique 'non', tu ne dois JAMAIS exécuter d'actions de modération (KICK, BAN, etc.) et tu dois uniquement répondre en langage naturel avec l'action 'NONE'."
"Si l'utilisateur est un modérateur, tu peux répondre en langage naturel pour assister à des tâches générales (comme rédiger des lettres, fournir des conseils, répondre à des questions) ou effectuer des actions de modération et de gestion."
"Si l'utilisateur n'est PAS un modérateur, tu ne peux répondre qu'en langage naturel."
"--- Format de Réponse pour Langage Naturel (NON-ACTION) ---\n"
"Répondez avec : `{\"action\": \"NONE\", \"response\": \"[votre réponse en français ici]\"}`\n\n"
"--- Actions de Modération & Gestion (si l'utilisateur est un modérateur) ---\n"
"Utilisez ces formats jsons, vous pouvez combiner plusieurs jsons à la suite: \n"
"- Expulsion : `{\"action\": \"KICK\", \"users\": [{\"target_user_mention\": \"[@mention ou ID utilisateur/bot]\"}]}`\n"
"- Bannir : `{\"action\": \"BAN\", \"users\": [{\"target_user_mention\": \"[@mention ou ID]\"}]}`\n"
"- Débannir : `{\"action\": \"UNBAN\", \"users\": [{\"target_user_mention\": \"[@mention ou ID]\"}]}`\n"
"- Muter : `{\"action\": \"MUTE\", \"users\": [{\"target_user_mention\": \"[@mention ou ID]\", \"duration\": [durée en minutes]}]}`\n"
"- Timeout : `{\"action\": \"TIMEOUT\", \"users\": [{\"target_user_mention\": \"[@mention ou ID]\", \"duration\": [durée en minutes]}]}`\n"
"- Purger : `{\"action\": \"PURGE\", \"purges\": [{\"channel_name\": \"[nom du salon]\", \"amount\": [nombre de messages]}]}`\n"
"- Avertir : `{\"action\": \"WARN\", \"warnings\": [{\"target_user_mention\": \"[@mention ou ID]\", \"reason\": \"[raison]\"}]}`\n"
"- Créer Salon : `{\"action\": \"CREATE_CHANNEL\", \"channels\": [{\"channel_name\": \"[nom du salon]\", \"category_name\": \"[nom de la catégorie]\", \"channel_type\": \"[textuel|vocal]\"}]}`\n"
"- Supprimer Salon : `{\"action\": \"DELETE_CHANNEL\", \"channels\": [{\"channel_name\": \"[nom du salon ou de la catégorie]\"}]}`\n"
"- Modifier Salon : `{\"action\": \"MODIFY_CHANNEL\", \"channels\": [{\"channel_name\": \"[nom actuel]\", \"new_name\": \"[nouveau nom]\", \"new_category_name\": \"[nouvelle catégorie]\", \"topic\": \"[nouveau sujet (pour textuel)]\", \"user_limit\": [nouvelle limite (pour vocal)]}]}` (Omettez les clés non pertinentes/non demandées pour chaque salon)\n"
"- Déplacer Salon : `{\"action\": \"MOVE_CHANNEL\", \"channels\": [{\"channel_name\": \"[nom]\", \"new_category_name\": \"[nouvelle catégorie]\"}]}`\n"
"- Renommer Salon : `{\"action\": \"RENAME_CHANNEL\", \"channels\": [{\"channel_name\": \"[nom actuel]\", \"new_name\": \"[nouveau nom]\"}]}`\n"
"- Créer Rôle : `{\"action\": \"CREATE_ROLE\", \"roles\": [{\"role_name\": \"[nom]\", \"color\": \"[couleur hex, e.g. #ff0000]\", \"permissions\": \"[liste de permissions séparées par virgule, e.g. kick_members, ban_members]\"}]}`\n"
"- Supprimer Rôle : `{\"action\": \"DELETE_ROLE\", \"roles\": [{\"role_name\": \"[nom]\"}]}`\n"
"- Modifier Rôle :r `{\"action\": \"MODIFY_ROLE\", \"roles\": [{\"role_name\": \"[nom actuel]\", \"new_name\": \"[nouveau nom]\", \"color\": \"[nouvelle couleur hex]\", \"permissions\": \"[nouvelles permissions]\"}]}` (Omettez les clés non pertinentes pour chaque rôle)\n"
"- Renommer Rôle : `{\"action\": \"RENAME_ROLE\", \"roles\": [{\"role_name\": \"[nom actuel]\", \"new_name\": \"[nouveau nom]\"}]}`\n"
"- Déplacer Rôle : `{\"action\": \"MOVE_ROLE\", \"roles\": [{\"role_name\": \"[nom]\", \"position\": [nouvelle position]}]}`\n"
"- Ajouter Rôle à Utilisateur : `{\"action\": \"ADD_ROLE_TO_USER\", \"role_assignments\": [{\"target_user_mention\": \"[@mention ou ID]\", \"role_name\": \"[nom du rôle]\"}]}`\n"
"- Retirer Rôle d'Utilisateur : `{\"action\": \"REMOVE_ROLE_FROM_USER\", \"role_removals\": [{\"target_user_mention\": \"[@mention ou ID]\", \"role_name\": \"[nom du rôle]\"}]}`\n"
"- Créer Catégorie : `{\"action\": \"CREATE_CATEGORY\", \"categories\": [{\"category_name\": \"[nom]\"}]}`\n"
"- Supprimer Catégorie : `{\"action\": \"DELETE_CATEGORY\", \"categories\": [{\"category_name\": \"[nom]\"}]}`\n"
"- Modifier Catégorie : `{\"action\": \"MODIFY_CATEGORY\", \"categories\": [{\"category_name\": \"[nom actuel]\", \"new_name\": \"[nouveau nom]\"}]}\n"
"- Déplacer Catégorie : `{\"action\": \"MOVE_CATEGORY\", \"categories\": [{\"category_name\": \"[nom]\", \"position\": [nouvelle position]}]}`\n"
"- Renommer Catégorie : `{\"action\": \"RENAME_CATEGORY\", \"categories\": [{\"category_name\": \"[nom actuel]\", \"new_name\": \"[nouveau nom]\"}]}`\n"
"- Ping : `{\"action\": \"PING\"}`\n"
"- Définir Salon de Bienvenue : `{\"action\": \"SET_WELCOME_CHANNEL\", \"channel_name\": \"[nom]\"}`\n"
"- Définir Salon d'Au Revoir : `{\"action\": \"SET_GOODBYE_CHANNEL\", \"channel_name\": \"[nom]\"}`\n"
"- Définir Rôle Mute : `{\"action\": \"SET_MUTE_ROLE\", \"role_name\": \"[nom]\"}`\n"
"- Envoyer Message : `{\"action\": \"SEND_MESSAGE\", \"channel_name\": \"[nom du salon (facultatif)]\", \"dm_user\": \"[@mention ou ID (facultatif)]\", \"message\": \"[contenu]\"}` (au moins un des deux: channel_name ou dm_user)\n\n"
)
# --- Intents Discord ---
intents = discord.Intents.default()
intents.message_content = True
intents.members = True
# Optional: faster event loop with uvloop in production (toggle with env USE_UVLOOP=1)
if os.environ.get("USE_UVLOOP", "0") in ("1", "true", "True"):
try:
uvloop = importlib.import_module("uvloop")
import asyncio
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
print("uvloop enabled — using high-performance event loop")
except Exception:
print("uvloop requested but not available; continuing with default event loop")
async def send_hello(bot):
"""Send 'hello' message to the first text channel of the guild."""
guild = bot.get_guild(bot.guild_id)
if guild:
channel = next((ch for ch in guild.text_channels if ch.permissions_for(guild.me).send_messages), None)
if channel:
await channel.send("hello")
else:
print("No text channel found where I can send messages.")
else:
print("Guild not found.")
def maybe_start_metrics(bot):
"""Start metrics server if METRICS_ENABLED is set."""
if os.getenv("METRICS_ENABLED", "0") in ("1", "true", "True"):
app = FastAPI()
prometheus_client.start_http_server(port=8000, addr="127.0.0.1")
@app.get("/metrics")
def get_metrics():
return bot.get_metrics()
config = Config(app=app, host="127.0.0.1", port=8000, log_level="info")
server = Server(config)
def run_server():
asyncio.run(server.serve())
thread = threading.Thread(target=run_server, daemon=True)
thread.start()
print("Metrics server started on http://127.0.0.1:8000")
if __name__ == "__main__":
if not DISCORD_TOKEN:
print("Erreur: DISCORD_TOKEN n'est pas défini. Veuillez vérifier votre fichier .env.")
else:
# Initialisation du bot avec les configurations
bot = Superviseur(
guild_id=GUILD_ID,
ollama_api_url=OLLAMA_API_URL,
ollama_model=OLLAMA_MODEL,
ollama_timeout=OLLAMA_TIMEOUT,
system_prompt=SYSTEM_PROMPT,
command_prefix="!",
intents=intents,
ollama_temperature=OLLAMA_TEMPERATURE,
# Correction : Ajout des variables de modération
ollama_api_key=OLLAMA_API_KEY,
ollama_moderation_model=OLLAMA_MODERATION_MODEL
)
# Lancement du bot
bot.run(DISCORD_TOKEN)