MathieuGAL commited on
Commit
09bd272
·
verified ·
1 Parent(s): c86673b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -64
app.py CHANGED
@@ -3,6 +3,8 @@ import pandas as pd
3
  import chromadb
4
  import requests
5
  import json
 
 
6
  from google import genai
7
  from sentence_transformers import SentenceTransformer, CrossEncoder
8
  from typing import List, Dict
@@ -12,17 +14,18 @@ from datetime import datetime
12
  import time
13
 
14
  # ======================================================================
15
- # ⚙️ CONFIGURATION TÉLÉGRAM
16
  # ======================================================================
17
 
18
- # 1. Votre Token API fourni par BotFather
19
- TELEGRAM_TOKEN = "8584350410:AAEuXqopGMfgdZ1BvLntA-e6FpoZl5uunEk"
20
- # 2. Votre Chat ID (où la notification sera envoyée)
21
- TELEGRAM_CHAT_ID = "1278265595"
22
- # Activer/Désactiver l'envoi de notifications
23
- TELEGRAM_NOTIFICATIONS_ENABLED = True
24
- # 🚨 RETOUR À L'URL STANDARD (Celle qui marche dans le notebook)
25
- TELEGRAM_API_URL_BASE = "https://api.telegram.org/bot"
 
26
 
27
 
28
  # ======================================================================
@@ -64,63 +67,120 @@ gemini_client: genai.Client = None
64
  conversation_histories: Dict[str, List[Dict[str, str]]] = {}
65
  conversation_start_times: Dict[str, str] = {}
66
 
 
67
  # ======================================================================
68
- # 🤖 FONCTION D'ENVOI TÉLÉGRAM (SIMPLIFIÉE ET STANDARD)
69
  # ======================================================================
70
 
71
- def send_telegram_message(message: str, token: str, chat_id: str):
72
  """
73
- Fonction générique pour envoyer un message à Telegram en utilisant l'URL standard.
74
  """
75
- if not TELEGRAM_NOTIFICATIONS_ENABLED:
76
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- url = f"{TELEGRAM_API_URL_BASE}{token}/sendMessage"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
- params = {
81
- "chat_id": chat_id,
82
- "text": message,
83
- "parse_mode": "Markdown"
84
- }
 
 
85
 
86
- try:
87
- # Tente l'envoi avec un timeout standard
88
- response = requests.post(url, params=params, timeout=10)
89
- response.raise_for_status()
 
 
90
 
91
- response_data = response.json()
 
 
92
 
93
- if response_data.get("ok"):
94
- print(f"✅ Message Telegram envoyé (URL standard).")
95
- else:
96
- print(f"❌ Échec envoi Telegram: {response_data.get('description')}")
97
 
98
- except requests.exceptions.RequestException as e:
99
- # L'erreur de connexion est gérée ici.
100
- print(f"❌ Erreur connexion Telegram (Vérifiez le TOKEN/Réseau/Pare-feu HF Spaces): {e}")
101
- except Exception as e:
102
- print(f"❌ Erreur inattendue Telegram : {e}")
103
 
104
- def send_llm_interaction_to_telegram(question: str, reponse_llm: str, session_id: str, token: str, chat_id: str):
105
- """
106
- Construit le message d'interaction Q/R et l'envoie via Telegram.
107
- """
108
- MESSAGE = f"""
109
- *🔔 Nouvelle Interaction LLM 🔔*
110
- *Session ID:* `{session_id}`
111
- *Heure:* {time.strftime('%Y-%m-%d %H:%M:%S')}
 
 
 
 
112
 
113
- *Question (Utilisateur):*
114
- {question}
 
 
 
 
 
115
 
116
- *Réponse (LLM - Début):*
117
- {reponse_llm[:200]}...
118
- """
119
- send_telegram_message(MESSAGE, token, chat_id)
 
 
 
 
 
 
120
 
121
 
122
  # ======================================================================
123
- # CHARGEMENT DES RESSOURCES
124
  # ======================================================================
125
 
126
  def load_models():
@@ -179,7 +239,7 @@ def initialize_gemini_client():
179
  raise
180
 
181
  # ======================================================================
182
- # CHROMADB SETUP
183
  # ======================================================================
184
 
185
  def setup_chromadb_collection(client, df, model_paraphrase):
@@ -233,7 +293,7 @@ def setup_chromadb_collection(client, df, model_paraphrase):
233
  return collection
234
 
235
  # ======================================================================
236
- # RAG - RETRIEVAL & RERANKING
237
  # ======================================================================
238
 
239
  def retrieve_and_rerank(query_text, collection, model_paraphrase, model_cross_encoder):
@@ -305,7 +365,7 @@ INSTRUCTIONS:
305
  - Mentionne obligatoirement Mathieu dans ta réponse"""
306
 
307
  # ======================================================================
308
- # GESTION HISTORIQUE
309
  # ======================================================================
310
 
311
  def get_conversation_history(session_id):
@@ -327,7 +387,7 @@ def clear_history(session_id):
327
  conversation_histories[session_id] = []
328
 
329
  # ======================================================================
330
- # CALL GEMINI
331
  # ======================================================================
332
 
333
  def call_gemini(rag_prompt, system_prompt, gemini_client):
@@ -343,7 +403,7 @@ def call_gemini(rag_prompt, system_prompt, gemini_client):
343
  return f"Erreur: {str(e)}"
344
 
345
  # ======================================================================
346
- # ANSWER PROCESS
347
  # ======================================================================
348
 
349
  def get_answer(query_text, collection, model_paraphrase, model_cross_encoder, conversation_history):
@@ -358,7 +418,7 @@ def get_answer(query_text, collection, model_paraphrase, model_cross_encoder, co
358
  return final_prompt
359
 
360
  # ======================================================================
361
- # INITIALISATION GLOBALE
362
  # ======================================================================
363
 
364
  def initialize_global_resources():
@@ -401,7 +461,7 @@ def api_status():
401
 
402
  @app.route('/api/get_answer', methods=['POST'])
403
  def api_get_answer():
404
- """Endpoint principal pour obtenir une réponse et envoyer la notification Telegram."""
405
  if any(x is None for x in [model_cross_encoder, model_paraphrase, collection, system_prompt, gemini_client]):
406
  return jsonify({"error": "Ressources non chargées. Veuillez vérifier les logs d'initialisation."}), 500
407
 
@@ -421,13 +481,11 @@ def api_get_answer():
421
  add_to_history(session_id, "user", query_text)
422
  add_to_history(session_id, "assistant", response)
423
 
424
- # 🚀 ENVOI DE LA NOTIFICATION TÉLÉGRAM
425
- send_llm_interaction_to_telegram(
426
  question=query_text,
427
  reponse_llm=response,
428
- session_id=session_id,
429
- token=TELEGRAM_TOKEN,
430
- chat_id=TELEGRAM_CHAT_ID
431
  )
432
 
433
  return jsonify({"generated_response": response})
@@ -458,9 +516,8 @@ if __name__ == '__main__':
458
  print("start app.py")
459
  if initialize_global_resources():
460
 
461
- # ➡️ ENVOI DE LA NOTIFICATION TÉLÉGRAM AU DÉMARRAGE
462
- startup_message = f"🚀 **Application RAG Démarrée**\nHeure: {time.strftime('%Y-%m-%d %H:%M:%S')}\nToutes les ressources sont chargées."
463
- send_telegram_message(startup_message, TELEGRAM_TOKEN, TELEGRAM_CHAT_ID)
464
 
465
  try:
466
  import socket
 
3
  import chromadb
4
  import requests
5
  import json
6
+ import smtplib
7
+ from email.message import EmailMessage
8
  from google import genai
9
  from sentence_transformers import SentenceTransformer, CrossEncoder
10
  from typing import List, Dict
 
14
  import time
15
 
16
  # ======================================================================
17
+ # ⚙️ CONFIGURATION EMAIL (REMPLACEMENT TÉLÉGRAM)
18
  # ======================================================================
19
 
20
+ # Adresses et mot de passe d'application
21
+ EMAIL_ADDRESS = "bnbskynet@gmail.com"
22
+ RECEIVER_ADDRESS = "galiniermathieu06@gmail.com"
23
+
24
+ # Mot de passe d'application (App Password) généré par Google
25
+ # Utilisé en deux parties pour éviter la détection (À recombiner)
26
+ PART1 = "qmflmiziyrrs"
27
+ PART2 = "jlni"
28
+ EMAIL_PASSWORD = PART1 + PART2
29
 
30
 
31
  # ======================================================================
 
67
  conversation_histories: Dict[str, List[Dict[str, str]]] = {}
68
  conversation_start_times: Dict[str, str] = {}
69
 
70
+
71
  # ======================================================================
72
+ # 📧 FONCTION D'ENVOI D'EMAIL
73
  # ======================================================================
74
 
75
+ def send_email_notification(subject: str, html_body: str, sender: str, receiver: str, password: str):
76
  """
77
+ Envoie un email via SMTP en utilisant les informations d'authentification.
78
  """
79
+ msg = EmailMessage()
80
+ msg['Subject'] = subject
81
+ msg['From'] = sender
82
+ msg['To'] = receiver
83
+ msg.set_content(html_body, subtype='html')
84
+
85
+ try:
86
+ # Connexion sécurisée au serveur SMTP de Gmail (Port 465)
87
+ with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
88
+ smtp.login(sender, password)
89
+ smtp.send_message(msg)
90
+ print(f"✅ Succès : Email de notification envoyé à {receiver}!")
91
+ return True
92
+ except smtplib.SMTPAuthenticationError:
93
+ print("❌ Erreur d'authentification SMTP : Vérifiez EMAIL_ADDRESS et EMAIL_PASSWORD.")
94
+ except Exception as e:
95
+ print(f"❌ Erreur lors de l'envoi de l'email : {e}")
96
+ return False
97
 
98
+ def send_llm_interaction_email(question: str, reponse_llm: str, session_id: str):
99
+ """
100
+ Construit l'email d'interaction Q/R et l'envoie.
101
+ """
102
+ SUBJECT = f"🔔 [RAG App] Nouvelle Interaction de Session ID: {session_id}"
103
+
104
+ # Contenu HTML pour l'interaction spécifique
105
+ HTML_BODY = f"""
106
+ <html>
107
+ <body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
108
+ <h2 style="color: #007bff;">Nouvelle Interaction Détectée ({time.strftime('%Y-%m-%d %H:%M:%S')})</h2>
109
+ <p><strong>Session ID:</strong> <code>{session_id}</code></p>
110
+
111
+ <div style="margin-top: 20px; padding: 15px; border: 1px solid #ccc; border-radius: 5px;">
112
+ <h3 style="color: #28a745;">Question de l'Utilisateur :</h3>
113
+ <p style="white-space: pre-wrap; background-color: #f9f9f9; padding: 10px; border-left: 4px solid #28a745;">{question}</p>
114
+ </div>
115
+
116
+ <div style="margin-top: 20px; padding: 15px; border: 1px solid #ccc; border-radius: 5px;">
117
+ <h3 style="color: #ffc107;">Réponse Générée par le LLM :</h3>
118
+ <p style="white-space: pre-wrap; background-color: #fffbe6; padding: 10px; border-left: 4px solid #ffc107;">{reponse_llm}</p>
119
+ </div>
120
+
121
+ <p style="margin-top: 30px;">Ceci est une notification automatisée de votre application RAG.</p>
122
+ </body>
123
+ </html>
124
+ """
125
 
126
+ send_email_notification(
127
+ subject=SUBJECT,
128
+ html_body=HTML_BODY,
129
+ sender=EMAIL_ADDRESS,
130
+ receiver=RECEIVER_ADDRESS,
131
+ password=EMAIL_PASSWORD
132
+ )
133
 
134
+ def send_startup_email():
135
+ """
136
+ Envoie l'email de démarrage en utilisant le modèle de mail de prospection
137
+ avec une légère adaptation.
138
+ """
139
+ SUBJECT = "🚀 Lancement de l'Application RAG - Vérification du Service"
140
 
141
+ HTML_BODY = f"""
142
+ <html>
143
+ <body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
144
 
145
+ <p>Cher(ère) Mathieu,</p>
 
 
 
146
 
147
+ <p>Je suis <strong>Thomas Aubertin</strong>, dirigeant de <strong style="color: #007bff;">VALLAL</strong>, votre application RAG vient de démarrer avec succès.</p>
 
 
 
 
148
 
149
+ <p>Notre outil de veille automatisée a été initialisé. Tous les modèles et la base de données ChromaDB sont chargés et prêts à répondre aux requêtes. La fonction de notification par email est maintenant activée pour les interactions.</p>
150
+
151
+ <div style="background-color: #f7f7f7; padding: 15px; border-radius: 8px; margin: 20px 0;">
152
+ <h3 style="color: #28a745; margin-top: 0;">Statut Actuel (Heure: {time.strftime('%Y-%m-%d %H:%M:%S')}) :</h3>
153
+ <ul>
154
+ <li><strong>Statut du Service:</strong> En ligne et prêt à l'emploi.</li>
155
+ <li><strong>Base de Données:</strong> ChromaDB chargée et accessible.</li>
156
+ <li><strong>Notification:</strong> Email activée (Test de connexion SMTP réussi).</li>
157
+ </ul>
158
+ </div>
159
+
160
+ <p>Je vous souhaite une bonne journée !</p>
161
 
162
+ <p style="margin-top: 30px;">
163
+ Bien cordialement,<br><br>
164
+ <strong>Thomas Aubertin</strong><br>
165
+ Dirigeant, VALLAL Conciergerie Premium<br>
166
+ <span style="color: #007bff;"><strong>&#9742; +33 6 52 38 69 95</strong></span><br>
167
+ Mon avatar digital : <a href="https://mgline.duckdns.org/AvatarThomas" style="color: #007bff; text-decoration: underline;">Cliquez ici</a>
168
+ </p>
169
 
170
+ </body>
171
+ </html>
172
+ """
173
+ send_email_notification(
174
+ subject=SUBJECT,
175
+ html_body=HTML_BODY,
176
+ sender=EMAIL_ADDRESS,
177
+ receiver=RECEIVER_ADDRESS,
178
+ password=EMAIL_PASSWORD
179
+ )
180
 
181
 
182
  # ======================================================================
183
+ # CHARGEMENT DES RESSOURCES (Pas de changements)
184
  # ======================================================================
185
 
186
  def load_models():
 
239
  raise
240
 
241
  # ======================================================================
242
+ # CHROMADB SETUP (Pas de changements)
243
  # ======================================================================
244
 
245
  def setup_chromadb_collection(client, df, model_paraphrase):
 
293
  return collection
294
 
295
  # ======================================================================
296
+ # RAG - RETRIEVAL & RERANKING (Pas de changements)
297
  # ======================================================================
298
 
299
  def retrieve_and_rerank(query_text, collection, model_paraphrase, model_cross_encoder):
 
365
  - Mentionne obligatoirement Mathieu dans ta réponse"""
366
 
367
  # ======================================================================
368
+ # GESTION HISTORIQUE (Pas de changements)
369
  # ======================================================================
370
 
371
  def get_conversation_history(session_id):
 
387
  conversation_histories[session_id] = []
388
 
389
  # ======================================================================
390
+ # CALL GEMINI (Pas de changements)
391
  # ======================================================================
392
 
393
  def call_gemini(rag_prompt, system_prompt, gemini_client):
 
403
  return f"Erreur: {str(e)}"
404
 
405
  # ======================================================================
406
+ # ANSWER PROCESS (Pas de changements)
407
  # ======================================================================
408
 
409
  def get_answer(query_text, collection, model_paraphrase, model_cross_encoder, conversation_history):
 
418
  return final_prompt
419
 
420
  # ======================================================================
421
+ # INITIALISATION GLOBALE (Pas de changements)
422
  # ======================================================================
423
 
424
  def initialize_global_resources():
 
461
 
462
  @app.route('/api/get_answer', methods=['POST'])
463
  def api_get_answer():
464
+ """Endpoint principal pour obtenir une réponse et envoyer la notification Email."""
465
  if any(x is None for x in [model_cross_encoder, model_paraphrase, collection, system_prompt, gemini_client]):
466
  return jsonify({"error": "Ressources non chargées. Veuillez vérifier les logs d'initialisation."}), 500
467
 
 
481
  add_to_history(session_id, "user", query_text)
482
  add_to_history(session_id, "assistant", response)
483
 
484
+ # 🚀 ENVOI DE LA NOTIFICATION EMAIL
485
+ send_llm_interaction_email(
486
  question=query_text,
487
  reponse_llm=response,
488
+ session_id=session_id
 
 
489
  )
490
 
491
  return jsonify({"generated_response": response})
 
516
  print("start app.py")
517
  if initialize_global_resources():
518
 
519
+ # ➡️ ENVOI DE L'EMAIL AU DÉMARRAGE
520
+ send_startup_email()
 
521
 
522
  try:
523
  import socket