chatbot.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import os
  2. import openai
  3. import discord
  4. import aiohttp
  5. import asyncio
  6. import base64
  7. import logging
  8. from dotenv import load_dotenv
  9. # Charger les variables d'environnement depuis le fichier .env
  10. load_dotenv()
  11. DISCORD_TOKEN = os.getenv('DISCORD_TOKEN')
  12. OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
  13. # Vérifier que les tokens sont récupérés
  14. if DISCORD_TOKEN is None or OPENAI_API_KEY is None:
  15. raise ValueError("Les tokens ne sont pas définis dans les variables d'environnement.")
  16. # Initialiser les intents
  17. intents = discord.Intents.default()
  18. intents.message_content = True # Activer l'intent pour les contenus de message
  19. # Initialiser le client Discord avec les intents modifiés
  20. client_discord = discord.Client(intents=intents)
  21. # Initialiser l'API OpenAI avec un client
  22. client_openai = openai.OpenAI(api_key=OPENAI_API_KEY)
  23. # Dictionnaire pour stocker l'historique des conversations pour chaque utilisateur
  24. conversation_history = {}
  25. # L'ID du salon spécifique où le bot est autorisé à répondre
  26. chatgpt_channel_id = 1284699709188997150 # Remplace par l'ID réel de ton salon
  27. def calculate_cost(usage):
  28. input_tokens = usage.get('prompt_tokens', 0)
  29. output_tokens = usage.get('completion_tokens', 0)
  30. # Coûts estimés
  31. input_cost = input_tokens / 1_000_000 * 5.00 # 5$ pour 1M tokens d'entrée
  32. output_cost = output_tokens / 1_000_000 * 15.00 # 15$ pour 1M tokens de sortie
  33. total_cost = input_cost + output_cost
  34. return input_tokens, output_tokens, total_cost
  35. async def read_text_file(attachment):
  36. # Télécharger et lire le contenu du fichier texte
  37. async with aiohttp.ClientSession() as session:
  38. async with session.get(attachment.url) as resp:
  39. return await resp.text()
  40. async def encode_image_from_attachment(attachment):
  41. async with aiohttp.ClientSession() as session:
  42. async with session.get(attachment.url) as resp:
  43. image_data = await resp.read()
  44. return base64.b64encode(image_data).decode('utf-8')
  45. async def call_openai_api(user_id, user_text, image_data=None):
  46. # Récupérer l'historique de la conversation pour l'utilisateur
  47. user_history = conversation_history.get(user_id, [])
  48. # Préparer le contenu de l'utilisateur
  49. user_content = [{"type": "text", "text": user_text}]
  50. if image_data:
  51. user_content.append({
  52. "type": "image_url",
  53. "image_url": {"url": f"data:image/jpeg;base64,{image_data}"}
  54. })
  55. # Ajouter le contenu à l'historique
  56. user_history.append({
  57. "role": "user",
  58. "content": user_content
  59. })
  60. payload = {
  61. "model": "gpt-4o",
  62. "messages": user_history,
  63. "max_tokens": 500,
  64. "stop": ["\n"] # Arrête la réponse à la fin d'une phrase
  65. }
  66. headers = {
  67. "Content-Type": "application/json",
  68. "Authorization": f"Bearer {OPENAI_API_KEY}"
  69. }
  70. try:
  71. async with aiohttp.ClientSession() as session:
  72. async with session.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload) as resp:
  73. result = await resp.json()
  74. if resp.status != 200:
  75. raise ValueError(f"API Error: {result.get('error', {}).get('message', 'Unknown error')}")
  76. # Calculer les coûts
  77. usage = result.get('usage', {})
  78. input_tokens, output_tokens, total_cost = calculate_cost(usage)
  79. # Afficher dans la console
  80. logging.info(f"Input Tokens: {input_tokens}")
  81. logging.info(f"Output Tokens: {output_tokens}")
  82. logging.info((f"Total Tokens: {input_tokens + output_tokens}")
  83. logging.info((f"Estimated Cost: ${total_cost:.4f}")
  84. return result
  85. except Exception as e:
  86. print(f"Error calling OpenAI API: {e}")
  87. return None
  88. @client_discord.event
  89. async def on_ready():
  90. print(f'Bot connecté en tant que {client_discord.user}')
  91. @client_discord.event
  92. async def on_message(message):
  93. # Vérifier si le message provient du canal autorisé
  94. if message.channel.id != chatgpt_channel_id:
  95. return
  96. # Vérifier si l'auteur du message est le bot lui-même
  97. if message.author == client_discord.user:
  98. return
  99. user_text = message.content.strip()
  100. image_data = None
  101. file_content = None
  102. # Extensions de fichiers autorisées
  103. allowed_extensions = ['.txt', '.py', '.html', '.css', '.js']
  104. # Vérifier s'il y a une pièce jointe
  105. if message.attachments:
  106. for attachment in message.attachments:
  107. # Vérifier si c'est un fichier avec une extension autorisée
  108. if any(attachment.filename.endswith(ext) for ext in allowed_extensions):
  109. file_content = await read_text_file(attachment)
  110. break
  111. # Vérifier si c'est une image
  112. elif attachment.content_type.startswith('image/'):
  113. image_data = await encode_image_from_attachment(attachment)
  114. break
  115. # Ajouter le contenu du fichier à la requête si présent
  116. if file_content:
  117. user_text += f"\nContenu du fichier {attachment.filename}:\n{file_content}"
  118. # Appeler l'API OpenAI
  119. result = await call_openai_api(message.author.id, user_text, image_data)
  120. if result:
  121. reply = result['choices'][0]['message']['content']
  122. await message.channel.send(reply)
  123. # Ajouter la réponse du modèle à l'historique
  124. add_to_conversation_history(message.author.id, {
  125. "role": "assistant",
  126. "content": reply
  127. })
  128. MAX_HISTORY_LENGTH = 50 # Nombre maximum de messages à conserver
  129. def add_to_conversation_history(user_id, new_message):
  130. if user_id not in conversation_history:
  131. # Ajouter la personnalité de l'IA en tant que premier message
  132. conversation_history[user_id] = [
  133. {
  134. "role": "system",
  135. "content": "Tu es une utilisatrice Discord qui parle français."
  136. "Tu ne dis jamais que tu es un IA."
  137. "Tu ne peux pas poster de message de plusieurs lignes."
  138. "Tu peux analyser des images et des pièces jointes aux formats txt, py, html, css et js."
  139. "Tu es cynique et sarcastique."
  140. "Tu apprécies les compliments."
  141. "Réponds sans poser de questions finales comme 'Avez-vous besoin de quelque chose d'autre ?'"
  142. "Privilégie des réponses courtes et percutantes."
  143. "Tu évites de générer des réponses de plus de 500 tokens."
  144. }
  145. ]
  146. conversation_history[user_id].append(new_message)
  147. # Limiter la taille de l'historique
  148. if len(conversation_history[user_id]) > MAX_HISTORY_LENGTH:
  149. # Garder le premier message de personnalité et les messages les plus récents
  150. conversation_history[user_id] = conversation_history[user_id][:1] + conversation_history[user_id][-MAX_HISTORY_LENGTH:]
  151. # Démarrer le bot Discord
  152. client_discord.run(DISCORD_TOKEN)