|
|
@@ -28,7 +28,7 @@ logger.addHandler(console_handler)
|
|
|
load_dotenv()
|
|
|
|
|
|
# Version du bot
|
|
|
-VERSION = "4.2.0" # Modifiable selon la version actuelle
|
|
|
+VERSION = "4.3.1" # Modifiable selon la version actuelle
|
|
|
|
|
|
# Récupérer les variables d'environnement avec validation
|
|
|
def get_env_variable(var_name, is_critical=True, default=None, var_type=str):
|
|
|
@@ -124,26 +124,21 @@ async def on_ready():
|
|
|
logger.info(f'Le bot est connecté en tant que {bot.user}')
|
|
|
global conversation_history
|
|
|
conversation_history = load_history()
|
|
|
- # Récupérer le canal spécifié
|
|
|
channel = bot.get_channel(CHANNEL_ID)
|
|
|
if channel is not None:
|
|
|
- # Trouver la guilde (serveur) à laquelle appartient le canal
|
|
|
guild = channel.guild
|
|
|
if guild is not None:
|
|
|
- # Récupérer le membre du bot sur cette guilde
|
|
|
bot_member = guild.me
|
|
|
- # Récupérer le pseudo du bot sur cette guilde
|
|
|
bot_nickname = bot_member.display_name
|
|
|
else:
|
|
|
- bot_nickname = bot.user.name # Utiliser le nom global si la guilde n'est pas trouvée
|
|
|
- # Créer un embed avec le pseudo du bot
|
|
|
+ bot_nickname = bot.user.name
|
|
|
embed = discord.Embed(
|
|
|
title="Bot en ligne",
|
|
|
description=f"{bot_nickname} est désormais en ligne. Version {VERSION}.",
|
|
|
color=discord.Color.green()
|
|
|
)
|
|
|
- # Envoyer l'embed dans le canal
|
|
|
await channel.send(embed=embed)
|
|
|
+ await bot.tree.sync() # Synchroniser les commandes slash
|
|
|
|
|
|
def call_mistral_api(prompt, history, image_url=None, user_id=None, username=None):
|
|
|
headers = {
|
|
|
@@ -226,9 +221,9 @@ def call_mistral_api(prompt, history, image_url=None, user_id=None, username=Non
|
|
|
logger.error(f"Erreur lors de l'appel API: {e}")
|
|
|
return "Désolé, une erreur réseau est survenue lors de la communication avec l'API."
|
|
|
|
|
|
-@bot.command(name='reset')
|
|
|
-async def reset_history(ctx):
|
|
|
- channel_id = str(ctx.channel.id)
|
|
|
+@bot.tree.command(name="reset", description="Réinitialise l'historique de conversation")
|
|
|
+async def reset_history_slash(interaction: discord.Interaction):
|
|
|
+ channel_id = str(interaction.channel.id)
|
|
|
if channel_id in conversation_history:
|
|
|
# Conserver le même ID de conversation mais vider les messages
|
|
|
if "messages" in conversation_history[channel_id]:
|
|
|
@@ -239,7 +234,7 @@ async def reset_history(ctx):
|
|
|
"messages": []
|
|
|
}
|
|
|
save_history(conversation_history)
|
|
|
- await ctx.send("L'historique de conversation a été réinitialisé.")
|
|
|
+ await interaction.response.send_message("L'historique de conversation a été réinitialisé.")
|
|
|
else:
|
|
|
conversation_id = str(len(conversation_history) + 1)
|
|
|
conversation_history[channel_id] = {
|
|
|
@@ -247,18 +242,18 @@ async def reset_history(ctx):
|
|
|
"messages": []
|
|
|
}
|
|
|
save_history(conversation_history)
|
|
|
- await ctx.send("Aucun historique de conversation trouvé pour ce channel. Créé un nouvel historique.")
|
|
|
+ await interaction.response.send_message("Aucun historique de conversation trouvé pour ce channel. Créé un nouvel historique.")
|
|
|
|
|
|
@bot.event
|
|
|
async def on_message(message):
|
|
|
# Ignorer les messages du bot lui-même
|
|
|
if message.author == bot.user:
|
|
|
return
|
|
|
-
|
|
|
+
|
|
|
# Vérifier si le message provient du channel spécifique
|
|
|
if message.channel.id != CHANNEL_ID:
|
|
|
return
|
|
|
-
|
|
|
+
|
|
|
# Vérifier si le message contient des stickers
|
|
|
if message.stickers:
|
|
|
# Obtenir le serveur (guild) du message
|
|
|
@@ -285,10 +280,10 @@ async def on_message(message):
|
|
|
await message.channel.send("Aucun sticker personnalisé trouvé sur ce serveur.")
|
|
|
else:
|
|
|
await message.channel.send("Ce message ne provient pas d'un serveur.")
|
|
|
- return
|
|
|
-
|
|
|
+ return
|
|
|
+
|
|
|
# Vérifier si le message contient uniquement un emoji personnalisé
|
|
|
- emoji_pattern = re.compile(r'^<a?:\w+:\d+>$|^[\u2600-\u27BF\u1F300-\u1F6FF\u1F900-\u1F9FF]+$', re.UNICODE)
|
|
|
+ emoji_pattern = re.compile(r'^<a?:\w+:\d+>$')
|
|
|
content = message.content.strip()
|
|
|
if emoji_pattern.match(content):
|
|
|
guild = message.guild
|
|
|
@@ -304,33 +299,46 @@ async def on_message(message):
|
|
|
else:
|
|
|
await message.channel.send("Aucun emoji personnalisé trouvé sur ce serveur.")
|
|
|
return
|
|
|
-
|
|
|
- # Si le message commence par le préfixe du bot, traiter comme une commande
|
|
|
- if message.content.startswith('!'):
|
|
|
- await bot.process_commands(message)
|
|
|
- return
|
|
|
-
|
|
|
+
|
|
|
# Résolution des mentions dans le message
|
|
|
resolved_content = message.content
|
|
|
for user in message.mentions:
|
|
|
# Remplacer chaque mention par le nom d'utilisateur
|
|
|
resolved_content = resolved_content.replace(f"<@{user.id}>", f"@{user.display_name}")
|
|
|
-
|
|
|
- # Vérifier les pièces jointes pour les images
|
|
|
+
|
|
|
+ # Vérifier les pièces jointes pour les images et autres fichiers
|
|
|
if message.attachments:
|
|
|
image_count = 0
|
|
|
+ non_image_files = []
|
|
|
too_large_images = []
|
|
|
max_size = 5 * 1024 * 1024 # 5 Mo en octets
|
|
|
-
|
|
|
for attachment in message.attachments:
|
|
|
+ is_image = False
|
|
|
+ # Vérifier le content_type si disponible
|
|
|
if attachment.content_type and attachment.content_type.startswith('image/'):
|
|
|
+ is_image = True
|
|
|
+ else:
|
|
|
+ # Si content_type n'est pas disponible ou pas une image, vérifier l'extension
|
|
|
+ image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.tiff', '.svg']
|
|
|
+ if any(attachment.filename.lower().endswith(ext) for ext in image_extensions):
|
|
|
+ is_image = True
|
|
|
+
|
|
|
+ if is_image:
|
|
|
image_count += 1
|
|
|
if attachment.size > max_size:
|
|
|
too_large_images.append(attachment.filename)
|
|
|
+ else:
|
|
|
+ non_image_files.append(attachment.filename)
|
|
|
+
|
|
|
+ # Vérifier la présence de fichiers non-image
|
|
|
+ if non_image_files:
|
|
|
+ file_list = ", ".join(non_image_files)
|
|
|
+ await message.channel.send(f"Erreur : Les fichiers suivants ne sont pas des images et ne sont pas pris en charge : {file_list}. Veuillez envoyer uniquement des images.")
|
|
|
+ return
|
|
|
|
|
|
# Vérifier le nombre d'images
|
|
|
if image_count > 1:
|
|
|
- await message.channel.send("Erreur : Vous ne pouvez pas envoyer plus de trois images dans un seul message. Veuillez diviser votre envoi en plusieurs messages.")
|
|
|
+ await message.channel.send("Erreur : Vous ne pouvez pas envoyer plus d'une image en un seul message.")
|
|
|
return
|
|
|
|
|
|
# Vérifier la taille des images
|
|
|
@@ -342,7 +350,6 @@ async def on_message(message):
|
|
|
# Récupérer ou initialiser l'historique pour ce channel
|
|
|
channel_id = str(message.channel.id)
|
|
|
global conversation_history
|
|
|
- # Charger l'historique actuel
|
|
|
conversation_history = load_history()
|
|
|
if channel_id not in conversation_history:
|
|
|
conversation_id = str(len(conversation_history) + 1)
|
|
|
@@ -350,9 +357,9 @@ async def on_message(message):
|
|
|
"conversation_id": conversation_id,
|
|
|
"messages": []
|
|
|
}
|
|
|
- # Assurer que la clé messages existe
|
|
|
if "messages" not in conversation_history[channel_id]:
|
|
|
conversation_history[channel_id]["messages"] = []
|
|
|
+
|
|
|
# Traitement des images dans le message
|
|
|
image_url = None
|
|
|
if message.attachments:
|
|
|
@@ -360,6 +367,7 @@ async def on_message(message):
|
|
|
if attachment.content_type and attachment.content_type.startswith('image/'):
|
|
|
image_url = attachment.url
|
|
|
break
|
|
|
+
|
|
|
# Utiliser le contenu résolu (avec les mentions remplacées)
|
|
|
prompt = resolved_content
|
|
|
# Indiquer que le bot est en train de taper
|