openai_client.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. # Initialiser le client OpenAI et définir les fonctions d'interaction avec l'API OpenAI.
  2. from openai import AsyncOpenAI, OpenAIError
  3. from config import OPENAI_API_KEY, PERSONALITY_PROMPT
  4. from logger import logger
  5. from utils import calculate_cost
  6. from history import add_to_conversation_history
  7. # Initialiser le client OpenAI asynchrone
  8. openai_client = AsyncOpenAI(api_key=OPENAI_API_KEY)
  9. IMAGE_ANALYSIS_MARKER = "__IMAGE_ANALYSIS__:"
  10. async def call_gpt4o_for_image_analysis(image_data, user_text=None, detail='high'):
  11. try:
  12. # Préparer le prompt
  13. if user_text:
  14. prompt = (
  15. "Tu es un expert en analyse d'images et de textes. "
  16. "On te présente une image ou un texte qui pourrait contenir des informations importantes. "
  17. f"Voici ce que l'on te décrit : \"{user_text}\". "
  18. "Analyse chaque détail de manière méticuleuse. "
  19. "Si l'image montre un environnement sans personnage, décris minutieusement les objets, leur disposition, les couleurs, textures, formes, et tout autre élément notable. "
  20. "Si du texte est présent, analyse chaque mot attentivement : style, mise en page, ou tout détail subtil qui pourrait en révéler plus sur le contexte ou l'intention. "
  21. "Si des personnages sont présents, décris-les avec précision : leur posture, apparence physique, vêtements, et fais une estimation de leurs mensurations (taille, tour de poitrine, taille, hanches, etc.). "
  22. "Sois attentif aux expressions et aux petits détails dans leur attitude ou apparence qui pourraient donner des indications supplémentaires. "
  23. "N'oublie aucun détail, car chaque aspect pourrait être révélateur dans cette analyse."
  24. )
  25. else:
  26. prompt = (
  27. "Tu es un expert en analyse d'images et de textes. "
  28. "On te présente une image ou un texte qui pourrait contenir des informations importantes. "
  29. "Analyse chaque détail de manière méticuleuse. "
  30. "Si l'image montre un environnement sans personnage, décris minutieusement les objets, leur disposition, les couleurs, textures, formes, et tout autre élément notable. "
  31. "Si du texte est présent, analyse chaque mot attentivement : style, mise en page, ou tout détail subtil qui pourrait en révéler plus sur le contexte ou l'intention. "
  32. "Si des personnages sont présents, décris-les avec précision : leur posture, apparence physique, vêtements, et fais une estimation de leurs mensurations (taille, tour de poitrine, taille, hanches, etc.). "
  33. "Sois attentif aux expressions et aux petits détails dans leur attitude ou apparence qui pourraient donner des indications supplémentaires. "
  34. "N'oublie aucun détail, car chaque aspect pourrait être révélateur dans cette analyse."
  35. )
  36. message_to_send = {
  37. "role": "user",
  38. "content": [
  39. {"type": "text", "text": prompt},
  40. {
  41. "type": "image_url",
  42. "image_url": {
  43. "url": f"data:image/jpeg;base64,{image_data}",
  44. "detail": detail
  45. }
  46. }
  47. ]
  48. }
  49. # Appel à GPT-4o
  50. response = await openai_client.chat.completions.create(
  51. model="gpt-4o",
  52. messages=[message_to_send],
  53. max_tokens=4096
  54. )
  55. if response:
  56. analysis = response.choices[0].message.content
  57. logger.info(f"Analyse de l'image par GPT-4o : {analysis}")
  58. # Calcul et affichage du coût
  59. if hasattr(response, 'usage') and response.usage:
  60. usage = {
  61. 'prompt_tokens': response.usage.prompt_tokens,
  62. 'completion_tokens': response.usage.completion_tokens
  63. }
  64. input_tokens, output_tokens, total_cost = calculate_cost(usage, model='gpt-4o')
  65. logger.info(f"Coût de l'analyse de l'image : ${total_cost:.4f} / Input: {input_tokens} / Output: {output_tokens}")
  66. else:
  67. logger.warning("Informations d'utilisation non disponibles pour le calcul du coût.")
  68. # Ajouter l'analyse à l'historique avec le marqueur
  69. analysis_message = {
  70. "role": "system",
  71. "content": f"{IMAGE_ANALYSIS_MARKER}{analysis}"
  72. }
  73. await add_to_conversation_history(analysis_message)
  74. return analysis
  75. else:
  76. return None
  77. except OpenAIError as e:
  78. logger.error(f"Erreur lors de l'analyse de l'image avec GPT-4o: {e}")
  79. return None
  80. async def call_gpt4o_mini_with_analysis(analysis_text, user_name, user_question, has_text, conversation_history):
  81. try:
  82. # Préparer le message avec le prompt de personnalité et l'analyse
  83. messages = [
  84. {"role": "system", "content": PERSONALITY_PROMPT},
  85. {
  86. "role": "system",
  87. "content": f"L'analyse de l'image fournie est la suivante :\n{analysis_text}\n\n"
  88. }
  89. ]
  90. if has_text:
  91. # Préparer le message utilisateur avec le texte
  92. user_message = {
  93. "role": "user",
  94. "content": (
  95. "Tu es Rika, une femme de 24 ans et membre à part entière du serveur Discord sur lequel tu te trouves. "
  96. f"{user_name} a posté un message contenant une image et a écrit avec : '{user_question}'.\n"
  97. "Réponds à l'utilisateur en te basant sur l'analyse, avec ta personnalité. "
  98. "Ne mentionne pas explicitement que l'analyse est pré-existante, fais comme si tu l'avais faite toi-même."
  99. )
  100. }
  101. else:
  102. # Préparer une instruction pour commenter l'image sans texte
  103. user_message = {
  104. "role": "user",
  105. "content": (
  106. "Tu es Rika, une femme de 24 ans et membre à part entière du serveur Discord sur lequel tu te trouves. "
  107. f"{user_name} a partagé une image sans texte additionnel.\n"
  108. "Commente l'image en te basant sur l'analyse, avec ta personnalité. "
  109. "Ne mentionne pas que l'analyse a été fournie à l'avance, réagis comme si tu l'avais toi-même effectuée."
  110. )
  111. }
  112. # Inclure l'historique de conversation
  113. messages += conversation_history
  114. messages.append(user_message)
  115. # Appel à GPT-4o Mini pour répondre
  116. response = await openai_client.chat.completions.create(
  117. model="gpt-4o-mini",
  118. messages=messages,
  119. max_tokens=450
  120. )
  121. if response:
  122. reply = response.choices[0].message.content
  123. # Calculer et enregistrer le coût de la réponse de GPT-4o Mini
  124. if hasattr(response, 'usage') and response.usage:
  125. usage = {
  126. 'prompt_tokens': response.usage.prompt_tokens,
  127. 'completion_tokens': response.usage.completion_tokens
  128. }
  129. input_tokens, output_tokens, total_cost = calculate_cost(usage, model='gpt-4o-mini')
  130. logger.info(f"Coût de la réponse de GPT-4o Mini : ${total_cost:.4f} / Input: {input_tokens} / Output: {output_tokens}")
  131. else:
  132. logger.warning("Informations d'utilisation non disponibles pour le calcul du coût de GPT-4o Mini.")
  133. return reply
  134. else:
  135. return None
  136. except OpenAIError as e:
  137. logger.error(f"Erreur lors de la génération de réponse avec GPT-4o Mini: {e}")
  138. return None
  139. async def call_openai_api(user_text, user_name, conversation_history, image_data=None, detail='high'):
  140. try:
  141. # Préparer le contenu pour l'appel API
  142. message_to_send = {
  143. "role": "user",
  144. "content": [
  145. {"type": "text", "text": f"{user_name} dit : {user_text}"}
  146. ]
  147. }
  148. # Inclure l'image dans l'appel API courant
  149. if image_data:
  150. message_to_send["content"].append({
  151. "type": "image_url",
  152. "image_url": {
  153. "url": f"data:image/jpeg;base64,{image_data}",
  154. "detail": detail
  155. }
  156. })
  157. # Assembler les messages avec le prompt de personnalité en premier
  158. messages = [
  159. {"role": "system", "content": PERSONALITY_PROMPT}
  160. ] + conversation_history + [message_to_send]
  161. response = await openai_client.chat.completions.create(
  162. model="gpt-4o-mini",
  163. messages=messages,
  164. max_tokens=400,
  165. temperature=1.0
  166. )
  167. if response:
  168. reply = response.choices[0].message.content
  169. # Calculer et enregistrer le coût de la réponse de GPT-4o Mini
  170. if hasattr(response, 'usage') and response.usage:
  171. usage = {
  172. 'prompt_tokens': response.usage.prompt_tokens,
  173. 'completion_tokens': response.usage.completion_tokens
  174. }
  175. input_tokens, output_tokens, total_cost = calculate_cost(usage, model='gpt-4o-mini')
  176. logger.info(f"Coût de la réponse : ${total_cost:.4f} / Input: {input_tokens} / Output: {output_tokens} / Total: {input_tokens + output_tokens}")
  177. else:
  178. logger.warning("Informations d'utilisation non disponibles pour le calcul du coût.")
  179. return response
  180. else:
  181. return None
  182. except OpenAIError as e:
  183. logger.error(f"Error calling OpenAI API: {e}")
  184. except Exception as e:
  185. logger.error(f"Error calling OpenAI API: {e}")
  186. return None