Docfile commited on
Commit
dfc948e
·
verified ·
1 Parent(s): 8badaaf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +163 -6
app.py CHANGED
@@ -7,11 +7,12 @@ import base64
7
  from werkzeug.utils import secure_filename
8
  import mimetypes
9
  from dotenv import load_dotenv
10
-
11
 
12
  app = Flask(__name__)
13
  app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
14
  load_dotenv()
 
15
  # Configuration du client Gemini
16
  API_KEY = os.getenv("GOOGLE_API_KEY")
17
  SYSTEM_INSTRUCTION = "Tu es un assistant intelligent et amical nommé Mariam. Tu assistes les utilisateurs au mieux de tes capacités. Tu as été créé par Aenir."
@@ -34,13 +35,75 @@ DEFAULT_TOOLS = [
34
  types.Tool(url_context=types.UrlContext())
35
  ]
36
 
37
- # Stockage des conversations (en production, utilisez une base de données)
38
  conversations = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  @app.route('/')
41
  def index():
42
  return render_template('index.html')
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  @app.route('/chat', methods=['POST'])
45
  def chat():
46
  try:
@@ -49,10 +112,13 @@ def chat():
49
  thinking_enabled = data.get('thinking_enabled', True)
50
  conversation_id = data.get('conversation_id', 'default')
51
 
 
 
 
52
  # Configuration du thinking
53
  config_dict = DEFAULT_CONFIG.copy()
54
  config_dict["system_instruction"] = SYSTEM_INSTRUCTION
55
- # <<< FIN DE LA MODIFICATION >>>
56
  if thinking_enabled:
57
  config_dict["thinking_config"] = types.ThinkingConfig(
58
  thinking_budget=-1, # Dynamic thinking
@@ -66,7 +132,6 @@ def chat():
66
  if conversation_id not in conversations:
67
  conversations[conversation_id] = client.chats.create(
68
  model=MODEL,
69
-
70
  config=generation_config
71
  )
72
 
@@ -93,6 +158,10 @@ def chat():
93
  full_response += part.text
94
  yield f"data: {json.dumps({'type': 'text', 'content': part.text})}\n\n"
95
 
 
 
 
 
96
  # Signal de fin
97
  yield f"data: {json.dumps({'type': 'end'})}\n\n"
98
 
@@ -140,6 +209,12 @@ def chat_with_file():
140
  thinking_enabled = data.get('thinking_enabled', True)
141
  conversation_id = data.get('conversation_id', 'default')
142
 
 
 
 
 
 
 
143
  # Configuration du thinking
144
  config_dict = DEFAULT_CONFIG.copy()
145
  if thinking_enabled:
@@ -150,14 +225,12 @@ def chat_with_file():
150
 
151
  config_dict["tools"] = DEFAULT_TOOLS
152
  config_dict["system_instruction"] = SYSTEM_INSTRUCTION
153
- # <<< FIN DE LA MODIFICATION >>>
154
  generation_config = types.GenerateContentConfig(**config_dict)
155
 
156
  # Gestion de la conversation
157
  if conversation_id not in conversations:
158
  conversations[conversation_id] = client.chats.create(
159
  model=MODEL,
160
-
161
  config=generation_config
162
  )
163
 
@@ -182,14 +255,21 @@ def chat_with_file():
182
  config=generation_config
183
  )
184
 
 
 
185
  for chunk in response_stream:
186
  for part in chunk.candidates[0].content.parts:
187
  if part.text:
188
  if part.thought and thinking_enabled:
189
  yield f"data: {json.dumps({'type': 'thought', 'content': part.text})}\n\n"
190
  else:
 
191
  yield f"data: {json.dumps({'type': 'text', 'content': part.text})}\n\n"
192
 
 
 
 
 
193
  yield f"data: {json.dumps({'type': 'end'})}\n\n"
194
 
195
  except Exception as e:
@@ -209,8 +289,85 @@ def reset_conversation():
209
  if conversation_id in conversations:
210
  del conversations[conversation_id]
211
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  return jsonify({'success': True})
 
 
 
 
 
 
 
 
 
 
 
213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  except Exception as e:
215
  return jsonify({'error': str(e)}), 500
216
 
 
7
  from werkzeug.utils import secure_filename
8
  import mimetypes
9
  from dotenv import load_dotenv
10
+ from datetime import datetime
11
 
12
  app = Flask(__name__)
13
  app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB max file size
14
  load_dotenv()
15
+
16
  # Configuration du client Gemini
17
  API_KEY = os.getenv("GOOGLE_API_KEY")
18
  SYSTEM_INSTRUCTION = "Tu es un assistant intelligent et amical nommé Mariam. Tu assistes les utilisateurs au mieux de tes capacités. Tu as été créé par Aenir."
 
35
  types.Tool(url_context=types.UrlContext())
36
  ]
37
 
38
+ # Stockage des conversations avec métadonnées (en production, utilisez une base de données)
39
  conversations = {}
40
+ conversation_metadata = {}
41
+
42
+ def add_message_to_history(conversation_id, role, content, has_file=False):
43
+ """Ajoute un message à l'historique de la conversation"""
44
+ if conversation_id not in conversation_metadata:
45
+ conversation_metadata[conversation_id] = {
46
+ 'id': conversation_id,
47
+ 'created_at': datetime.now().isoformat(),
48
+ 'last_activity': datetime.now().isoformat(),
49
+ 'messages': [],
50
+ 'status': 'active'
51
+ }
52
+
53
+ conversation_metadata[conversation_id]['messages'].append({
54
+ 'role': role,
55
+ 'content': content,
56
+ 'timestamp': datetime.now().isoformat(),
57
+ 'hasFile': has_file
58
+ })
59
+ conversation_metadata[conversation_id]['last_activity'] = datetime.now().isoformat()
60
 
61
  @app.route('/')
62
  def index():
63
  return render_template('index.html')
64
 
65
+ @app.route('/admin')
66
+ def admin():
67
+ """Page d'administration"""
68
+ return render_template('admin.html')
69
+
70
+ @app.route('/admin/conversations')
71
+ def get_conversations():
72
+ """API pour récupérer les conversations pour l'admin"""
73
+ try:
74
+ # Calculer les statistiques
75
+ total_conversations = len(conversation_metadata)
76
+ total_messages = sum(len(conv['messages']) for conv in conversation_metadata.values())
77
+ active_conversations = sum(1 for conv in conversation_metadata.values() if conv.get('status') == 'active')
78
+ conversations_with_files = sum(1 for conv in conversation_metadata.values()
79
+ if any(msg.get('hasFile') for msg in conv['messages']))
80
+
81
+ # Préparer les données des conversations
82
+ conversations_data = []
83
+ for conv_id, conv_data in conversation_metadata.items():
84
+ conversations_data.append({
85
+ 'id': conv_id,
86
+ 'createdAt': conv_data.get('created_at'),
87
+ 'lastActivity': conv_data.get('last_activity'),
88
+ 'status': conv_data.get('status', 'active'),
89
+ 'messages': conv_data.get('messages', [])
90
+ })
91
+
92
+ # Trier par dernière activité (plus récent en premier)
93
+ conversations_data.sort(key=lambda x: x.get('lastActivity', ''), reverse=True)
94
+
95
+ return jsonify({
96
+ 'conversations': conversations_data,
97
+ 'stats': {
98
+ 'total': total_conversations,
99
+ 'totalMessages': total_messages,
100
+ 'active': active_conversations,
101
+ 'withFiles': conversations_with_files
102
+ }
103
+ })
104
+ except Exception as e:
105
+ return jsonify({'error': str(e)}), 500
106
+
107
  @app.route('/chat', methods=['POST'])
108
  def chat():
109
  try:
 
112
  thinking_enabled = data.get('thinking_enabled', True)
113
  conversation_id = data.get('conversation_id', 'default')
114
 
115
+ # Ajouter le message de l'utilisateur à l'historique
116
+ add_message_to_history(conversation_id, 'user', message)
117
+
118
  # Configuration du thinking
119
  config_dict = DEFAULT_CONFIG.copy()
120
  config_dict["system_instruction"] = SYSTEM_INSTRUCTION
121
+
122
  if thinking_enabled:
123
  config_dict["thinking_config"] = types.ThinkingConfig(
124
  thinking_budget=-1, # Dynamic thinking
 
132
  if conversation_id not in conversations:
133
  conversations[conversation_id] = client.chats.create(
134
  model=MODEL,
 
135
  config=generation_config
136
  )
137
 
 
158
  full_response += part.text
159
  yield f"data: {json.dumps({'type': 'text', 'content': part.text})}\n\n"
160
 
161
+ # Ajouter la réponse de l'assistant à l'historique
162
+ if full_response:
163
+ add_message_to_history(conversation_id, 'assistant', full_response)
164
+
165
  # Signal de fin
166
  yield f"data: {json.dumps({'type': 'end'})}\n\n"
167
 
 
209
  thinking_enabled = data.get('thinking_enabled', True)
210
  conversation_id = data.get('conversation_id', 'default')
211
 
212
+ # Ajouter le message de l'utilisateur à l'historique (avec indication de fichier)
213
+ display_message = message if message else 'Analyse ce fichier'
214
+ if file_data:
215
+ display_message += f" [Fichier: {file_data.get('filename', 'inconnu')}]"
216
+ add_message_to_history(conversation_id, 'user', display_message, has_file=True)
217
+
218
  # Configuration du thinking
219
  config_dict = DEFAULT_CONFIG.copy()
220
  if thinking_enabled:
 
225
 
226
  config_dict["tools"] = DEFAULT_TOOLS
227
  config_dict["system_instruction"] = SYSTEM_INSTRUCTION
 
228
  generation_config = types.GenerateContentConfig(**config_dict)
229
 
230
  # Gestion de la conversation
231
  if conversation_id not in conversations:
232
  conversations[conversation_id] = client.chats.create(
233
  model=MODEL,
 
234
  config=generation_config
235
  )
236
 
 
255
  config=generation_config
256
  )
257
 
258
+ full_response = ""
259
+
260
  for chunk in response_stream:
261
  for part in chunk.candidates[0].content.parts:
262
  if part.text:
263
  if part.thought and thinking_enabled:
264
  yield f"data: {json.dumps({'type': 'thought', 'content': part.text})}\n\n"
265
  else:
266
+ full_response += part.text
267
  yield f"data: {json.dumps({'type': 'text', 'content': part.text})}\n\n"
268
 
269
+ # Ajouter la réponse de l'assistant à l'historique
270
+ if full_response:
271
+ add_message_to_history(conversation_id, 'assistant', full_response)
272
+
273
  yield f"data: {json.dumps({'type': 'end'})}\n\n"
274
 
275
  except Exception as e:
 
289
  if conversation_id in conversations:
290
  del conversations[conversation_id]
291
 
292
+ # Marquer la conversation comme terminée dans les métadonnées
293
+ if conversation_id in conversation_metadata:
294
+ conversation_metadata[conversation_id]['status'] = 'reset'
295
+ conversation_metadata[conversation_id]['last_activity'] = datetime.now().isoformat()
296
+
297
+ return jsonify({'success': True})
298
+
299
+ except Exception as e:
300
+ return jsonify({'error': str(e)}), 500
301
+
302
+ @app.route('/admin/conversations/<conversation_id>', methods=['DELETE'])
303
+ def delete_conversation(conversation_id):
304
+ """Supprimer une conversation (pour l'admin)"""
305
+ try:
306
+ if conversation_id in conversations:
307
+ del conversations[conversation_id]
308
+
309
+ if conversation_id in conversation_metadata:
310
+ del conversation_metadata[conversation_id]
311
+
312
  return jsonify({'success': True})
313
+ except Exception as e:
314
+ return jsonify({'error': str(e)}), 500
315
+
316
+ @app.route('/admin/conversations/<conversation_id>/export')
317
+ def export_conversation(conversation_id):
318
+ """Exporter une conversation en JSON"""
319
+ try:
320
+ if conversation_id not in conversation_metadata:
321
+ return jsonify({'error': 'Conversation non trouvée'}), 404
322
+
323
+ conversation_data = conversation_metadata[conversation_id]
324
 
325
+ return jsonify({
326
+ 'conversation_id': conversation_id,
327
+ 'export_date': datetime.now().isoformat(),
328
+ 'data': conversation_data
329
+ })
330
+ except Exception as e:
331
+ return jsonify({'error': str(e)}), 500
332
+
333
+ @app.route('/admin/stats')
334
+ def get_admin_stats():
335
+ """Statistiques détaillées pour l'admin"""
336
+ try:
337
+ # Statistiques générales
338
+ total_conversations = len(conversation_metadata)
339
+ total_messages = sum(len(conv['messages']) for conv in conversation_metadata.values())
340
+
341
+ # Statistiques par statut
342
+ status_stats = {}
343
+ for conv in conversation_metadata.values():
344
+ status = conv.get('status', 'active')
345
+ status_stats[status] = status_stats.get(status, 0) + 1
346
+
347
+ # Conversations avec fichiers
348
+ conversations_with_files = sum(1 for conv in conversation_metadata.values()
349
+ if any(msg.get('hasFile') for msg in conv['messages']))
350
+
351
+ # Activité par jour (derniers 7 jours)
352
+ from collections import defaultdict
353
+ daily_activity = defaultdict(int)
354
+
355
+ for conv in conversation_metadata.values():
356
+ for message in conv['messages']:
357
+ if message.get('timestamp'):
358
+ try:
359
+ date = datetime.fromisoformat(message['timestamp']).date()
360
+ daily_activity[date.isoformat()] += 1
361
+ except:
362
+ continue
363
+
364
+ return jsonify({
365
+ 'total_conversations': total_conversations,
366
+ 'total_messages': total_messages,
367
+ 'status_distribution': status_stats,
368
+ 'conversations_with_files': conversations_with_files,
369
+ 'daily_activity': dict(daily_activity)
370
+ })
371
  except Exception as e:
372
  return jsonify({'error': str(e)}), 500
373