chatbot.py 7.0 KB

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