AIdeaText commited on
Commit
8a9afa6
verified
1 Parent(s): e060f7e

Update modules/studentact/student_activities_v2.py

Browse files
modules/studentact/student_activities_v2.py CHANGED
@@ -1,4 +1,4 @@
1
- ##############
2
  ###modules/studentact/student_activities_v2.py
3
 
4
  import streamlit as st
@@ -21,8 +21,8 @@ from ..database.morphosintax_mongo_db import get_student_morphosyntax_analysis
21
  from ..database.semantic_mongo_db import get_student_semantic_analysis
22
  from ..database.discourse_mongo_db import get_student_discourse_analysis
23
  from ..database.chat_mongo_db import get_chat_history
24
- from ..database.current_situation_mongo_db import get_current_situation_analysis # Nueva importaci贸n
25
- from ..database.claude_recommendations_mongo_db import get_claude_recommendations # Actualizada
26
 
27
  logger = logging.getLogger(__name__)
28
 
@@ -39,16 +39,16 @@ def display_student_activities(username: str, lang_code: str, t: dict):
39
  try:
40
  st.header(t.get('activities_title', 'Mis Actividades'))
41
 
42
- # Tabs para diferentes tipos de an谩lisis (a帽adimos la nueva tab)
43
  tabs = st.tabs([
44
- t.get('current_situation_activities', 'Mi Situaci贸n Actual'), # Nueva pesta帽a
45
  t.get('morpho_activities', 'An谩lisis Morfosint谩ctico'),
46
  t.get('semantic_activities', 'An谩lisis Sem谩ntico'),
47
  t.get('discourse_activities', 'An谩lisis del Discurso'),
48
  t.get('chat_activities', 'Conversaciones con el Asistente')
49
  ])
50
 
51
- # Tab de Situaci贸n Actual (nueva)
52
  with tabs[0]:
53
  display_current_situation_activities(username, t)
54
 
@@ -212,101 +212,6 @@ def display_discourse_activities(username: str, t: dict):
212
  logger.error(f"Error mostrando an谩lisis del discurso: {str(e)}")
213
  st.error(t.get('error_discourse', 'Error al mostrar an谩lisis del discurso'))
214
 
215
-
216
- ###################################################################################
217
- # Nueva funci贸n para mostrar las actividades de Situaci贸n Actual
218
- def display_current_situation_activities(username: str, t: dict):
219
- """Muestra actividades de an谩lisis de situaci贸n actual con recomendaciones de Claude"""
220
- try:
221
- logger.info(f"Recuperando an谩lisis de situaci贸n actual para {username}")
222
- analyses = get_current_situation_analysis(username)
223
-
224
- if not analyses:
225
- logger.info("No se encontraron an谩lisis de situaci贸n actual")
226
- st.info(t.get('no_current_situation', 'No hay an谩lisis de situaci贸n actual registrados'))
227
- return
228
-
229
- logger.info(f"Procesando {len(analyses)} an谩lisis de situaci贸n actual")
230
-
231
- for analysis in analyses:
232
- try:
233
- # Verificar campos necesarios
234
- if not all(key in analysis for key in ['timestamp', 'feedback']):
235
- logger.warning(f"An谩lisis incompleto: {analysis.keys()}")
236
- continue
237
-
238
- # Formatear fecha
239
- timestamp = datetime.fromisoformat(analysis['timestamp'].replace('Z', '+00:00'))
240
- formatted_date = timestamp.strftime("%d/%m/%Y %H:%M:%S")
241
-
242
- # Crear expander con t铆tulo que incluye informaci贸n del tipo de texto si est谩 disponible
243
- title = f"{t.get('analysis_date', 'Fecha')}: {formatted_date}"
244
- if 'text_type' in analysis:
245
- text_type_display = {
246
- 'academic_article': t.get('academic_article', 'Art铆culo acad茅mico'),
247
- 'university_work': t.get('university_work', 'Trabajo universitario'),
248
- 'general_communication': t.get('general_communication', 'Comunicaci贸n general')
249
- }.get(analysis['text_type'], analysis['text_type'])
250
- title += f" - {text_type_display}"
251
-
252
- with st.expander(title, expanded=False):
253
- # Mostrar el texto original analizado
254
- st.subheader(t.get('analyzed_text', 'Texto analizado'))
255
- st.text_area(
256
- "",
257
- value=analysis.get('text', ''),
258
- height=100,
259
- disabled=True,
260
- label_visibility="collapsed"
261
- )
262
-
263
- # Mostrar las recomendaciones generadas por Claude
264
- st.subheader(t.get('recommendations', 'Recomendaciones'))
265
-
266
- # Dar formato a las recomendaciones en un contenedor estilizado
267
- st.markdown(f"""
268
- <div style="padding: 20px; border-radius: 10px;
269
- background-color: #f8f9fa; margin-bottom: 20px;">
270
- {analysis['feedback']}
271
- </div>
272
- """, unsafe_allow_html=True)
273
-
274
- # Mostrar m茅tricas adicionales si est谩n disponibles
275
- if 'metrics' in analysis and analysis['metrics']:
276
- with st.expander(t.get('metrics_details', 'Detalles de m茅tricas')):
277
- # Convertir m茅tricas a dataframe para mejor visualizaci贸n
278
- metrics_df = pd.DataFrame([
279
- {"M茅trica": k, "Valor": v}
280
- for k, v in analysis['metrics'].items()
281
- if k not in ['test_type', 'timestamp'] and not isinstance(v, dict)
282
- ])
283
- st.dataframe(metrics_df, use_container_width=True)
284
-
285
- except Exception as e:
286
- logger.error(f"Error procesando an谩lisis individual de situaci贸n actual: {str(e)}")
287
- continue
288
-
289
- except Exception as e:
290
- logger.error(f"Error mostrando an谩lisis de situaci贸n actual: {str(e)}")
291
- st.error(t.get('error_current_situation', 'Error al mostrar an谩lisis de situaci贸n actual'))
292
-
293
-
294
- #################################################################################
295
- def display_discourse_comparison(analysis: dict, t: dict):
296
- """Muestra la comparaci贸n de an谩lisis del discurso"""
297
- st.subheader(t.get('comparison_results', 'Resultados de la comparaci贸n'))
298
-
299
- col1, col2 = st.columns(2)
300
- with col1:
301
- st.markdown(f"**{t.get('concepts_text_1', 'Conceptos Texto 1')}**")
302
- df1 = pd.DataFrame(analysis['key_concepts1'])
303
- st.dataframe(df1)
304
-
305
- with col2:
306
- st.markdown(f"**{t.get('concepts_text_2', 'Conceptos Texto 2')}**")
307
- df2 = pd.DataFrame(analysis['key_concepts2'])
308
- st.dataframe(df2)
309
-
310
  #################################################################################
311
  def display_chat_activities(username: str, t: dict):
312
  """
@@ -357,83 +262,203 @@ def display_chat_activities(username: str, t: dict):
357
  logger.error(f"Error mostrando historial del chat: {str(e)}")
358
  st.error(t.get('error_chat', 'Error al mostrar historial del chat'))
359
 
360
- ##############################################################################################
361
- # Nueva funci贸n para mostrar las actividades de Situaci贸n Actual
362
  def display_current_situation_activities(username: str, t: dict):
363
- """Muestra actividades de an谩lisis de situaci贸n actual con recomendaciones de Claude"""
 
 
 
364
  try:
 
 
 
 
365
  logger.info(f"Recuperando recomendaciones de Claude para {username}")
366
- recommendations = get_claude_recommendations(username)
367
 
368
- if not recommendations:
369
- logger.info("No se encontraron recomendaciones de Claude")
370
- st.info(t.get('no_recommendations', 'No hay recomendaciones de Claude registradas'))
 
371
  return
372
-
373
- logger.info(f"Procesando {len(recommendations)} recomendaciones de Claude")
374
 
375
- for recommendation in recommendations:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  try:
377
- # Verificar campos necesarios
378
- if not all(key in recommendation for key in ['timestamp', 'feedback']):
379
- logger.warning(f"Recomendaci贸n incompleta: {recommendation.keys()}")
 
 
 
380
  continue
381
 
382
- # Formatear fecha
383
- timestamp = datetime.fromisoformat(recommendation['timestamp'].replace('Z', '+00:00'))
384
- formatted_date = timestamp.strftime("%d/%m/%Y %H:%M:%S")
385
 
386
- # Crear expander con t铆tulo que incluye informaci贸n del tipo de texto si est谩 disponible
387
- title = f"{t.get('recommendation_date', 'Fecha')}: {formatted_date}"
388
- if 'text_type' in recommendation:
 
 
 
 
 
 
 
 
 
 
389
  text_type_display = {
390
  'academic_article': t.get('academic_article', 'Art铆culo acad茅mico'),
391
- 'university_work': t.get('university_work', 'Trabajo universitario'),
392
  'general_communication': t.get('general_communication', 'Comunicaci贸n general')
393
- }.get(recommendation['text_type'], recommendation['text_type'])
394
  title += f" - {text_type_display}"
395
 
 
396
  with st.expander(title, expanded=False):
397
- # Mostrar el texto original analizado
398
  st.subheader(t.get('analyzed_text', 'Texto analizado'))
399
  st.text_area(
400
- "",
401
- value=recommendation.get('text', ''),
402
  height=100,
403
  disabled=True,
404
  label_visibility="collapsed"
405
  )
406
 
407
- # Mostrar las recomendaciones generadas por Claude
408
- st.subheader(t.get('recommendations', 'Recomendaciones de Claude'))
409
-
410
- # Dar formato a las recomendaciones en un contenedor estilizado
411
- st.markdown(f"""
412
- <div style="padding: 20px; border-radius: 10px;
413
- background-color: #f8f9fa; margin-bottom: 20px;">
414
- {recommendation.get('feedback', 'No hay recomendaciones disponibles')}
415
- </div>
416
- """, unsafe_allow_html=True)
417
 
418
- # Mostrar m茅tricas adicionales si est谩n disponibles
419
- if 'metrics' in recommendation and recommendation['metrics']:
420
- with st.expander(t.get('metrics_details', 'Detalles de m茅tricas')):
421
- # Crear un DataFrame para mejor visualizaci贸n
422
- metrics_data = []
423
- for key, value in recommendation['metrics'].items():
424
- if not isinstance(value, dict) and key not in ['test_type', 'timestamp']:
425
- metrics_data.append({"M茅trica": key, "Valor": value})
426
 
427
- if metrics_data:
428
- metrics_df = pd.DataFrame(metrics_data)
429
- st.dataframe(metrics_df, use_container_width=True)
430
- else:
431
- st.info(t.get('no_metrics', 'No hay m茅tricas disponibles'))
432
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
  except Exception as e:
434
- logger.error(f"Error procesando recomendaci贸n individual: {str(e)}")
435
  continue
436
-
437
  except Exception as e:
438
- logger.error(f"Error mostrando recomendaciones de Claude: {str(e)}")
439
- st.error(t.get('error_recommendations', 'Error al mostrar recomendaciones de Claude'))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##############
2
  ###modules/studentact/student_activities_v2.py
3
 
4
  import streamlit as st
 
21
  from ..database.semantic_mongo_db import get_student_semantic_analysis
22
  from ..database.discourse_mongo_db import get_student_discourse_analysis
23
  from ..database.chat_mongo_db import get_chat_history
24
+ from ..database.current_situation_mongo_db import get_current_situation_analysis
25
+ from ..database.claude_recommendations_mongo_db import get_claude_recommendations
26
 
27
  logger = logging.getLogger(__name__)
28
 
 
39
  try:
40
  st.header(t.get('activities_title', 'Mis Actividades'))
41
 
42
+ # Tabs para diferentes tipos de an谩lisis
43
  tabs = st.tabs([
44
+ t.get('current_situation_activities', 'Mi Situaci贸n Actual'),
45
  t.get('morpho_activities', 'An谩lisis Morfosint谩ctico'),
46
  t.get('semantic_activities', 'An谩lisis Sem谩ntico'),
47
  t.get('discourse_activities', 'An谩lisis del Discurso'),
48
  t.get('chat_activities', 'Conversaciones con el Asistente')
49
  ])
50
 
51
+ # Tab de Situaci贸n Actual
52
  with tabs[0]:
53
  display_current_situation_activities(username, t)
54
 
 
212
  logger.error(f"Error mostrando an谩lisis del discurso: {str(e)}")
213
  st.error(t.get('error_discourse', 'Error al mostrar an谩lisis del discurso'))
214
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  #################################################################################
216
  def display_chat_activities(username: str, t: dict):
217
  """
 
262
  logger.error(f"Error mostrando historial del chat: {str(e)}")
263
  st.error(t.get('error_chat', 'Error al mostrar historial del chat'))
264
 
265
+ #################################################################################
 
266
  def display_current_situation_activities(username: str, t: dict):
267
+ """
268
+ Muestra an谩lisis de situaci贸n actual junto con las recomendaciones de Claude
269
+ unificando la informaci贸n de ambas colecciones.
270
+ """
271
  try:
272
+ # Recuperar datos de ambas colecciones
273
+ logger.info(f"Recuperando an谩lisis de situaci贸n actual para {username}")
274
+ situation_analyses = get_current_situation_analysis(username)
275
+
276
  logger.info(f"Recuperando recomendaciones de Claude para {username}")
277
+ claude_recommendations = get_claude_recommendations(username)
278
 
279
+ # Verificar si hay alg煤n tipo de an谩lisis disponible
280
+ if not situation_analyses and not claude_recommendations:
281
+ logger.info("No se encontraron an谩lisis de situaci贸n actual ni recomendaciones")
282
+ st.info(t.get('no_current_situation', 'No hay an谩lisis de situaci贸n actual registrados'))
283
  return
 
 
284
 
285
+ # Crear un diccionario para indexar an谩lisis por timestamp
286
+ # Esto permite emparejar diagn贸sticos y recomendaciones del mismo momento
287
+ logger.info("Creando 铆ndice temporal de an谩lisis")
288
+ analyses_by_timestamp = {}
289
+
290
+ # Indexar an谩lisis de situaci贸n actual
291
+ for analysis in situation_analyses:
292
+ if 'timestamp' in analysis:
293
+ # Normalizar el formato de timestamp para comparaci贸n
294
+ timestamp_key = analysis['timestamp'].split('.')[0] # Remover milisegundos
295
+ if timestamp_key not in analyses_by_timestamp:
296
+ analyses_by_timestamp[timestamp_key] = {'situation': analysis}
297
+
298
+ # Indexar recomendaciones de Claude
299
+ for recommendation in claude_recommendations:
300
+ if 'timestamp' in recommendation:
301
+ # Normalizar el formato de timestamp para comparaci贸n
302
+ timestamp_key = recommendation['timestamp'].split('.')[0] # Remover milisegundos
303
+ if timestamp_key in analyses_by_timestamp:
304
+ analyses_by_timestamp[timestamp_key]['recommendation'] = recommendation
305
+ else:
306
+ analyses_by_timestamp[timestamp_key] = {'recommendation': recommendation}
307
+
308
+ # Si no hay an谩lisis despu茅s de la indexaci贸n
309
+ if not analyses_by_timestamp:
310
+ st.info(t.get('no_paired_analyses', 'No hay an谩lisis disponibles'))
311
+ return
312
+
313
+ # Convertir a lista ordenada por timestamp (m谩s reciente primero)
314
+ paired_analyses = sorted(
315
+ analyses_by_timestamp.items(),
316
+ key=lambda x: x[0],
317
+ reverse=True
318
+ )
319
+
320
+ logger.info(f"Procesando {len(paired_analyses)} pares de an谩lisis")
321
+
322
+ # Mostrar cada par de an谩lisis
323
+ for timestamp_key, analysis_pair in paired_analyses:
324
  try:
325
+ # Obtener datos de situaci贸n y recomendaci贸n
326
+ situation_data = analysis_pair.get('situation', {})
327
+ recommendation_data = analysis_pair.get('recommendation', {})
328
+
329
+ # Si no hay ning煤n dato, continuar al siguiente
330
+ if not situation_data and not recommendation_data:
331
  continue
332
 
333
+ # Determinar qu茅 texto mostrar (priorizar el de la situaci贸n)
334
+ text_to_show = situation_data.get('text', recommendation_data.get('text', ''))
335
+ text_type = situation_data.get('text_type', recommendation_data.get('text_type', ''))
336
 
337
+ # Formatear fecha para mostrar
338
+ try:
339
+ # Usar timestamp de situation_data si est谩 disponible, sino usar el de recommendation_data
340
+ timestamp_str = situation_data.get('timestamp', recommendation_data.get('timestamp', timestamp_key))
341
+ timestamp = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
342
+ formatted_date = timestamp.strftime("%d/%m/%Y %H:%M:%S")
343
+ except Exception as date_error:
344
+ logger.error(f"Error formateando fecha: {str(date_error)}")
345
+ formatted_date = timestamp_key
346
+
347
+ # Determinar el t铆tulo del expander
348
+ title = f"{t.get('analysis_date', 'Fecha')}: {formatted_date}"
349
+ if text_type:
350
  text_type_display = {
351
  'academic_article': t.get('academic_article', 'Art铆culo acad茅mico'),
352
+ 'student_essay': t.get('student_essay', 'Trabajo universitario'),
353
  'general_communication': t.get('general_communication', 'Comunicaci贸n general')
354
+ }.get(text_type, text_type)
355
  title += f" - {text_type_display}"
356
 
357
+ # Mostrar el an谩lisis en un expander
358
  with st.expander(title, expanded=False):
359
+ # Mostrar texto analizado
360
  st.subheader(t.get('analyzed_text', 'Texto analizado'))
361
  st.text_area(
362
+ "",
363
+ value=text_to_show,
364
  height=100,
365
  disabled=True,
366
  label_visibility="collapsed"
367
  )
368
 
369
+ # Crear tabs para separar diagn贸stico y recomendaciones
370
+ diagnosis_tab, recommendations_tab = st.tabs([
371
+ t.get('diagnosis_tab', 'Diagn贸stico'),
372
+ t.get('recommendations_tab', 'Recomendaciones')
373
+ ])
 
 
 
 
 
374
 
375
+ # Tab de diagn贸stico
376
+ with diagnosis_tab:
377
+ if situation_data and 'metrics' in situation_data:
378
+ metrics = situation_data['metrics']
 
 
 
 
379
 
380
+ # Dividir en dos columnas
381
+ col1, col2 = st.columns(2)
382
+
383
+ # Principales m茅tricas en formato de tarjetas
384
+ with col1:
385
+ st.subheader(t.get('key_metrics', 'M茅tricas clave'))
386
+
387
+ # Mostrar cada m茅trica principal
388
+ for metric_name, metric_data in metrics.items():
389
+ if isinstance(metric_data, dict) and 'normalized_score' in metric_data:
390
+ score = metric_data['normalized_score']
391
+
392
+ # Determinar color y emoji basado en la puntuaci贸n
393
+ if score < 0.5:
394
+ emoji = "馃敶"
395
+ color = "#ffcccc" # light red
396
+ elif score < 0.75:
397
+ emoji = "馃煛"
398
+ color = "#ffffcc" # light yellow
399
+ else:
400
+ emoji = "馃煝"
401
+ color = "#ccffcc" # light green
402
+
403
+ # Mostrar la m茅trica con estilo
404
+ st.markdown(f"""
405
+ <div style="background-color:{color}; padding:10px; border-radius:5px; margin-bottom:10px;">
406
+ <b>{emoji} {metric_name.capitalize()}:</b> {score:.2f}
407
+ </div>
408
+ """, unsafe_allow_html=True)
409
+
410
+ # Mostrar detalles adicionales si est谩n disponibles
411
+ with col2:
412
+ st.subheader(t.get('details', 'Detalles'))
413
+
414
+ # Recursivamente mostrar detalles de las m茅tricas
415
+ for metric_name, metric_data in metrics.items():
416
+ if isinstance(metric_data, dict) and 'details' in metric_data and metric_data['details']:
417
+ with st.expander(f"{metric_name.capitalize()} - {t.get('details', 'Detalles')}"):
418
+ # Mostrar detalles como JSON
419
+ st.json(metric_data['details'])
420
+ else:
421
+ st.info(t.get('no_diagnosis', 'No hay datos de diagn贸stico disponibles'))
422
+
423
+ # Tab de recomendaciones
424
+ with recommendations_tab:
425
+ if recommendation_data and 'recommendations' in recommendation_data:
426
+ st.markdown(f"""
427
+ <div style="padding: 20px; border-radius: 10px;
428
+ background-color: #f8f9fa; margin-bottom: 20px;">
429
+ {recommendation_data['recommendations']}
430
+ </div>
431
+ """, unsafe_allow_html=True)
432
+ elif recommendation_data and 'feedback' in recommendation_data:
433
+ st.markdown(f"""
434
+ <div style="padding: 20px; border-radius: 10px;
435
+ background-color: #f8f9fa; margin-bottom: 20px;">
436
+ {recommendation_data['feedback']}
437
+ </div>
438
+ """, unsafe_allow_html=True)
439
+ else:
440
+ st.info(t.get('no_recommendations', 'No hay recomendaciones disponibles'))
441
+
442
  except Exception as e:
443
+ logger.error(f"Error procesando par de an谩lisis: {str(e)}")
444
  continue
445
+
446
  except Exception as e:
447
+ logger.error(f"Error mostrando actividades de situaci贸n actual: {str(e)}")
448
+ st.error(t.get('error_current_situation', 'Error al mostrar an谩lisis de situaci贸n actual'))
449
+
450
+ #################################################################################
451
+ def display_discourse_comparison(analysis: dict, t: dict):
452
+ """Muestra la comparaci贸n de an谩lisis del discurso"""
453
+ st.subheader(t.get('comparison_results', 'Resultados de la comparaci贸n'))
454
+
455
+ col1, col2 = st.columns(2)
456
+ with col1:
457
+ st.markdown(f"**{t.get('concepts_text_1', 'Conceptos Texto 1')}**")
458
+ df1 = pd.DataFrame(analysis['key_concepts1'])
459
+ st.dataframe(df1)
460
+
461
+ with col2:
462
+ st.markdown(f"**{t.get('concepts_text_2', 'Conceptos Texto 2')}**")
463
+ df2 = pd.DataFrame(analysis['key_concepts2'])
464
+ st.dataframe(df2)