AIdeaText commited on
Commit
157ed85
verified
1 Parent(s): ba0d9d4

Update modules/studentact/student_activities_v2.py

Browse files
modules/studentact/student_activities_v2.py CHANGED
@@ -17,7 +17,7 @@ import seaborn as sns
17
  import logging
18
 
19
  # Importaciones de la base de datos
20
- 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
@@ -78,395 +78,6 @@ def display_student_activities(username: str, lang_code: str, t: dict):
78
  st.error(t.get('error_loading_activities', 'Error al cargar las actividades'))
79
 
80
 
81
- ###############################################################################################
82
-
83
- def display_current_situation_activities(username: str, t: dict):
84
- """
85
- Muestra an谩lisis de situaci贸n actual junto con las recomendaciones de Claude
86
- unificando la informaci贸n de ambas colecciones y emparej谩ndolas por cercan铆a temporal.
87
- """
88
- try:
89
- # Recuperar datos de ambas colecciones
90
- logger.info(f"Recuperando an谩lisis de situaci贸n actual para {username}")
91
- situation_analyses = get_current_situation_analysis(username, limit=10)
92
-
93
- # Verificar si hay datos
94
- if situation_analyses:
95
- logger.info(f"Recuperados {len(situation_analyses)} an谩lisis de situaci贸n")
96
- # Depurar para ver la estructura de datos
97
- for i, analysis in enumerate(situation_analyses):
98
- logger.info(f"An谩lisis #{i+1}: Claves disponibles: {list(analysis.keys())}")
99
- if 'metrics' in analysis:
100
- logger.info(f"M茅tricas disponibles: {list(analysis['metrics'].keys())}")
101
- else:
102
- logger.warning("No se encontraron an谩lisis de situaci贸n actual")
103
-
104
- logger.info(f"Recuperando recomendaciones de Claude para {username}")
105
- claude_recommendations = get_claude_recommendations(username)
106
-
107
- if claude_recommendations:
108
- logger.info(f"Recuperadas {len(claude_recommendations)} recomendaciones de Claude")
109
- else:
110
- logger.warning("No se encontraron recomendaciones de Claude")
111
-
112
- # Verificar si hay alg煤n tipo de an谩lisis disponible
113
- if not situation_analyses and not claude_recommendations:
114
- logger.info("No se encontraron an谩lisis de situaci贸n actual ni recomendaciones")
115
- st.info(t.get('no_current_situation', 'No hay an谩lisis de situaci贸n actual registrados'))
116
- return
117
-
118
- # Crear pares combinados emparejando diagn贸sticos y recomendaciones cercanos en tiempo
119
- logger.info("Creando emparejamientos temporales de an谩lisis")
120
-
121
- # Convertir timestamps a objetos datetime para comparaci贸n
122
- situation_times = []
123
- for analysis in situation_analyses:
124
- if 'timestamp' in analysis:
125
- try:
126
- timestamp_str = analysis['timestamp']
127
- dt = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
128
- situation_times.append((dt, analysis))
129
- except Exception as e:
130
- logger.error(f"Error parseando timestamp de situaci贸n: {str(e)}")
131
-
132
- recommendation_times = []
133
- for recommendation in claude_recommendations:
134
- if 'timestamp' in recommendation:
135
- try:
136
- timestamp_str = recommendation['timestamp']
137
- dt = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
138
- recommendation_times.append((dt, recommendation))
139
- except Exception as e:
140
- logger.error(f"Error parseando timestamp de recomendaci贸n: {str(e)}")
141
-
142
- # Ordenar por tiempo
143
- situation_times.sort(key=lambda x: x[0], reverse=True)
144
- recommendation_times.sort(key=lambda x: x[0], reverse=True)
145
-
146
- # Crear pares combinados
147
- combined_items = []
148
-
149
- # Primero, procesar todas las situaciones encontrando la recomendaci贸n m谩s cercana
150
- for sit_time, situation in situation_times:
151
- # Buscar la recomendaci贸n m谩s cercana en tiempo
152
- best_match = None
153
- min_diff = timedelta(minutes=30) # M谩xima diferencia de tiempo aceptable (30 minutos)
154
- best_rec_time = None
155
-
156
- for rec_time, recommendation in recommendation_times:
157
- time_diff = abs(sit_time - rec_time)
158
- if time_diff < min_diff:
159
- min_diff = time_diff
160
- best_match = recommendation
161
- best_rec_time = rec_time
162
-
163
- # Crear un elemento combinado
164
- if best_match:
165
- timestamp_key = sit_time.isoformat()
166
- combined_items.append((timestamp_key, {
167
- 'situation': situation,
168
- 'recommendation': best_match,
169
- 'time_diff': min_diff.total_seconds()
170
- }))
171
- # Eliminar la recomendaci贸n usada para no reutilizarla
172
- recommendation_times = [(t, r) for t, r in recommendation_times if t != best_rec_time]
173
- logger.info(f"Emparejado: Diagn贸stico {sit_time} con Recomendaci贸n {best_rec_time} (diferencia: {min_diff})")
174
- else:
175
- # Si no hay recomendaci贸n cercana, solo incluir la situaci贸n
176
- timestamp_key = sit_time.isoformat()
177
- combined_items.append((timestamp_key, {
178
- 'situation': situation
179
- }))
180
- logger.info(f"Sin emparejar: Diagn贸stico {sit_time} sin recomendaci贸n cercana")
181
-
182
- # Agregar recomendaciones restantes sin situaci贸n
183
- for rec_time, recommendation in recommendation_times:
184
- timestamp_key = rec_time.isoformat()
185
- combined_items.append((timestamp_key, {
186
- 'recommendation': recommendation
187
- }))
188
- logger.info(f"Sin emparejar: Recomendaci贸n {rec_time} sin diagn贸stico cercano")
189
-
190
- # Ordenar por tiempo (m谩s reciente primero)
191
- combined_items.sort(key=lambda x: x[0], reverse=True)
192
-
193
- logger.info(f"Procesando {len(combined_items)} elementos combinados")
194
-
195
- # Mostrar cada par combinado
196
- for i, (timestamp_key, analysis_pair) in enumerate(combined_items):
197
- try:
198
- # Obtener datos de situaci贸n y recomendaci贸n
199
- situation_data = analysis_pair.get('situation', {})
200
- recommendation_data = analysis_pair.get('recommendation', {})
201
- time_diff = analysis_pair.get('time_diff')
202
-
203
- # Si no hay ning煤n dato, continuar al siguiente
204
- if not situation_data and not recommendation_data:
205
- continue
206
-
207
- # Determinar qu茅 texto mostrar (priorizar el de la situaci贸n)
208
- text_to_show = situation_data.get('text', recommendation_data.get('text', ''))
209
- text_type = situation_data.get('text_type', recommendation_data.get('text_type', ''))
210
-
211
- # Formatear fecha para mostrar
212
- try:
213
- # Usar timestamp del key que ya es un formato ISO
214
- dt = datetime.fromisoformat(timestamp_key)
215
- formatted_date = dt.strftime("%d/%m/%Y %H:%M:%S")
216
- except Exception as date_error:
217
- logger.error(f"Error formateando fecha: {str(date_error)}")
218
- formatted_date = timestamp_key
219
-
220
- # Determinar el t铆tulo del expander
221
- title = f"{t.get('analysis_date', 'Fecha')}: {formatted_date}"
222
- if text_type:
223
- text_type_display = {
224
- 'academic_article': t.get('academic_article', 'Art铆culo acad茅mico'),
225
- 'student_essay': t.get('student_essay', 'Trabajo universitario'),
226
- 'general_communication': t.get('general_communication', 'Comunicaci贸n general')
227
- }.get(text_type, text_type)
228
- title += f" - {text_type_display}"
229
-
230
- # A帽adir indicador de emparejamiento si existe
231
- if time_diff is not None:
232
- if time_diff < 60: # menos de un minuto
233
- title += f" 馃攧 (emparejados)"
234
- else:
235
- title += f" 馃攧 (emparejados, diferencia: {int(time_diff//60)} min)"
236
-
237
- # Usar un ID 煤nico para cada expander
238
- expander_id = f"analysis_{i}_{timestamp_key.replace(':', '_')}"
239
-
240
- # Mostrar el an谩lisis en un expander
241
- with st.expander(title, expanded=False):
242
- # Mostrar texto analizado con key 煤nico
243
- st.subheader(t.get('analyzed_text', 'Texto analizado'))
244
- st.text_area(
245
- "Text Content",
246
- value=text_to_show,
247
- height=100,
248
- disabled=True,
249
- label_visibility="collapsed",
250
- key=f"text_area_{expander_id}"
251
- )
252
-
253
- # Crear tabs para separar diagn贸stico y recomendaciones
254
- diagnosis_tab, recommendations_tab = st.tabs([
255
- t.get('diagnosis_tab', 'Diagn贸stico'),
256
- t.get('recommendations_tab', 'Recomendaciones')
257
- ])
258
-
259
- # Tab de diagn贸stico
260
- with diagnosis_tab:
261
- if situation_data and 'metrics' in situation_data:
262
- metrics = situation_data['metrics']
263
-
264
- # Dividir en dos columnas
265
- col1, col2 = st.columns(2)
266
-
267
- # Principales m茅tricas en formato de tarjetas
268
- with col1:
269
- st.subheader(t.get('key_metrics', 'M茅tricas clave'))
270
-
271
- # Mostrar cada m茅trica principal
272
- for metric_name, metric_data in metrics.items():
273
- try:
274
- # Determinar la puntuaci贸n
275
- score = None
276
- if isinstance(metric_data, dict):
277
- # Intentar diferentes nombres de campo
278
- if 'normalized_score' in metric_data:
279
- score = metric_data['normalized_score']
280
- elif 'score' in metric_data:
281
- score = metric_data['score']
282
- elif 'value' in metric_data:
283
- score = metric_data['value']
284
- elif isinstance(metric_data, (int, float)):
285
- score = metric_data
286
-
287
- if score is not None:
288
- # Asegurarse de que score es num茅rico
289
- if isinstance(score, (int, float)):
290
- # Determinar color y emoji basado en la puntuaci贸n
291
- if score < 0.5:
292
- emoji = "馃敶"
293
- color = "#ffcccc" # light red
294
- elif score < 0.75:
295
- emoji = "馃煛"
296
- color = "#ffffcc" # light yellow
297
- else:
298
- emoji = "馃煝"
299
- color = "#ccffcc" # light green
300
-
301
- # Mostrar la m茅trica con estilo
302
- st.markdown(f"""
303
- <div style="background-color:{color}; padding:10px; border-radius:5px; margin-bottom:10px;">
304
- <b>{emoji} {metric_name.capitalize()}:</b> {score:.2f}
305
- </div>
306
- """, unsafe_allow_html=True)
307
- else:
308
- # Si no es num茅rico, mostrar como texto
309
- st.markdown(f"""
310
- <div style="background-color:#f0f0f0; padding:10px; border-radius:5px; margin-bottom:10px;">
311
- <b>鈩癸笍 {metric_name.capitalize()}:</b> {str(score)}
312
- </div>
313
- """, unsafe_allow_html=True)
314
- except Exception as e:
315
- logger.error(f"Error procesando m茅trica {metric_name}: {str(e)}")
316
-
317
- # Mostrar detalles adicionales si est谩n disponibles
318
- with col2:
319
- st.subheader(t.get('details', 'Detalles'))
320
-
321
- # Para cada m茅trica, mostrar sus detalles si existen
322
- for metric_name, metric_data in metrics.items():
323
- try:
324
- if isinstance(metric_data, dict):
325
- # Mostrar detalles directamente o buscar en subcampos
326
- details = None
327
- if 'details' in metric_data and metric_data['details']:
328
- details = metric_data['details']
329
- else:
330
- # Crear un diccionario con los detalles excluyendo 'normalized_score' y similares
331
- details = {k: v for k, v in metric_data.items()
332
- if k not in ['normalized_score', 'score', 'value']}
333
-
334
- if details:
335
- st.write(f"**{metric_name.capitalize()}**")
336
- st.json(details, expanded=False)
337
- except Exception as e:
338
- logger.error(f"Error mostrando detalles de {metric_name}: {str(e)}")
339
- else:
340
- st.info(t.get('no_diagnosis', 'No hay datos de diagn贸stico disponibles'))
341
-
342
- # Tab de recomendaciones
343
- with recommendations_tab:
344
- if recommendation_data and 'recommendations' in recommendation_data:
345
- st.markdown(f"""
346
- <div style="padding: 20px; border-radius: 10px;
347
- background-color: #f8f9fa; margin-bottom: 20px;">
348
- {recommendation_data['recommendations']}
349
- </div>
350
- """, unsafe_allow_html=True)
351
- elif recommendation_data and 'feedback' in recommendation_data:
352
- st.markdown(f"""
353
- <div style="padding: 20px; border-radius: 10px;
354
- background-color: #f8f9fa; margin-bottom: 20px;">
355
- {recommendation_data['feedback']}
356
- </div>
357
- """, unsafe_allow_html=True)
358
- else:
359
- st.info(t.get('no_recommendations', 'No hay recomendaciones disponibles'))
360
-
361
- except Exception as e:
362
- logger.error(f"Error procesando par de an谩lisis: {str(e)}")
363
- continue
364
-
365
- except Exception as e:
366
- logger.error(f"Error mostrando actividades de situaci贸n actual: {str(e)}")
367
- st.error(t.get('error_current_situation', 'Error al mostrar an谩lisis de situaci贸n actual'))
368
-
369
- ###############################################################################################
370
-
371
- def display_morphosyntax_activities(username: str, t: dict):
372
- """
373
- Muestra actividades de an谩lisis morfosint谩ctico, incluyendo base e iteraciones
374
- desde las nuevas colecciones: student_morphosyntax_analysis_base y student_morphosyntax_iterations
375
- """
376
- try:
377
- # Importaci贸n inline para evitar problemas de circularidad
378
- # Utilizamos la funci贸n de la nueva estructura de DB iterativa
379
- from ..database.morphosyntax_iterative_mongo_db import get_student_morphosyntax_analysis
380
-
381
- logger.info(f"Recuperando an谩lisis morfosint谩ctico para {username}")
382
-
383
- # Esta funci贸n ahora trae tanto las bases como sus iteraciones
384
- base_analyses = get_student_morphosyntax_analysis(username)
385
-
386
- if not base_analyses:
387
- logger.info("No se encontraron an谩lisis morfosint谩cticos")
388
- st.info(t.get('no_morpho_analyses', 'No hay an谩lisis morfosint谩cticos registrados'))
389
- return
390
-
391
- logger.info(f"Procesando {len(base_analyses)} an谩lisis morfosint谩cticos base")
392
-
393
- # Procesar cada an谩lisis base con sus iteraciones
394
- for base_analysis in base_analyses:
395
- try:
396
- # Formatear fecha
397
- timestamp = datetime.fromisoformat(base_analysis['timestamp'].replace('Z', '+00:00'))
398
- formatted_date = timestamp.strftime("%d/%m/%Y %H:%M:%S")
399
-
400
- # T铆tulo del expander: incluir informaci贸n de si tiene iteraciones
401
- expander_title = f"{t.get('analysis_date', 'Fecha')}: {formatted_date}"
402
- if base_analysis.get('has_iterations', False):
403
- expander_title += f" ({t.get('has_iterations', 'Con iteraciones')})"
404
-
405
- with st.expander(expander_title, expanded=False):
406
- # Mostrar texto base
407
- st.subheader(t.get('base_text', 'Texto original'))
408
- st.text_area(
409
- "Base Text Content",
410
- value=base_analysis.get('text', ''),
411
- height=100,
412
- disabled=True,
413
- label_visibility="collapsed",
414
- key=f"base_text_{str(base_analysis['_id'])}"
415
- )
416
-
417
- # Mostrar diagrama de arco base si existe
418
- if 'arc_diagrams' in base_analysis and base_analysis['arc_diagrams']:
419
- st.subheader(t.get('syntactic_diagrams', 'Diagrama sint谩ctico (original)'))
420
- # Mostrar cada diagrama (normalmente solo uno por oraci贸n)
421
- for diagram in base_analysis['arc_diagrams']:
422
- st.write(diagram, unsafe_allow_html=True)
423
-
424
- # Procesar iteraciones si existen
425
- if 'iterations' in base_analysis and base_analysis['iterations']:
426
- st.markdown("---") # L铆nea divisoria
427
- st.subheader(t.get('iterations', 'Versiones mejoradas'))
428
-
429
- # Crear tabs para cada iteraci贸n
430
- iteration_tabs = st.tabs([
431
- f"{t.get('iteration', 'Versi贸n')} {i+1}"
432
- for i in range(len(base_analysis['iterations']))
433
- ])
434
-
435
- # Mostrar cada iteraci贸n en su propia pesta帽a
436
- for i, (tab, iteration) in enumerate(zip(iteration_tabs, base_analysis['iterations'])):
437
- with tab:
438
- # Timestamp de la iteraci贸n
439
- iter_timestamp = datetime.fromisoformat(
440
- iteration['timestamp'].replace('Z', '+00:00'))
441
- iter_formatted_date = iter_timestamp.strftime("%d/%m/%Y %H:%M:%S")
442
- st.caption(f"{t.get('iteration_date', 'Fecha de versi贸n')}: {iter_formatted_date}")
443
-
444
- # Texto de la iteraci贸n
445
- st.text_area(
446
- f"Iteration Text {i+1}",
447
- value=iteration.get('iteration_text', ''),
448
- height=100,
449
- disabled=True,
450
- label_visibility="collapsed",
451
- key=f"iter_text_{str(iteration['_id'])}"
452
- )
453
-
454
- # Diagrama de arco de la iteraci贸n
455
- if 'arc_diagrams' in iteration and iteration['arc_diagrams']:
456
- st.subheader(t.get('iteration_diagram', 'Diagrama sint谩ctico (mejorado)'))
457
- for diagram in iteration['arc_diagrams']:
458
- st.write(diagram, unsafe_allow_html=True)
459
-
460
- except Exception as e:
461
- logger.error(f"Error procesando an谩lisis morfosint谩ctico: {str(e)}")
462
- st.error(t.get('error_processing_analysis', 'Error procesando este an谩lisis'))
463
- continue
464
-
465
- except Exception as e:
466
- logger.error(f"Error mostrando an谩lisis morfosint谩ctico: {str(e)}")
467
- st.error(t.get('error_morpho', 'Error al mostrar an谩lisis morfosint谩ctico'))
468
-
469
-
470
  ###############################################################################################
471
 
472
  def display_semantic_activities(username: str, t: dict):
 
17
  import logging
18
 
19
  # Importaciones de la base de datos
20
+ # 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
 
78
  st.error(t.get('error_loading_activities', 'Error al cargar las actividades'))
79
 
80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  ###############################################################################################
82
 
83
  def display_semantic_activities(username: str, t: dict):