AIdeaText commited on
Commit
3f5892f
verified
1 Parent(s): 6c561c5

Update modules/studentact/student_activities_v2.py

Browse files
modules/studentact/student_activities_v2.py CHANGED
@@ -81,12 +81,12 @@ def display_student_activities(username: str, lang_code: str, t: dict):
81
  def display_current_situation_activities(username: str, t: dict):
82
  """
83
  Muestra an谩lisis de situaci贸n actual junto con las recomendaciones de Claude
84
- unificando la informaci贸n de ambas colecciones.
85
  """
86
  try:
87
  # Recuperar datos de ambas colecciones
88
  logger.info(f"Recuperando an谩lisis de situaci贸n actual para {username}")
89
- situation_analyses = get_current_situation_analysis(username, limit=5)
90
 
91
  # Verificar si hay datos
92
  if situation_analyses:
@@ -113,49 +113,90 @@ def display_current_situation_activities(username: str, t: dict):
113
  st.info(t.get('no_current_situation', 'No hay an谩lisis de situaci贸n actual registrados'))
114
  return
115
 
116
- # Crear un diccionario para indexar an谩lisis por timestamp
117
- # Esto permite emparejar diagn贸sticos y recomendaciones del mismo momento
118
- logger.info("Creando 铆ndice temporal de an谩lisis")
119
- analyses_by_timestamp = {}
120
 
121
- # Indexar an谩lisis de situaci贸n actual
 
122
  for analysis in situation_analyses:
123
  if 'timestamp' in analysis:
124
- # Normalizar el formato de timestamp para comparaci贸n
125
- timestamp_key = analysis['timestamp'].split('.')[0] # Remover milisegundos
126
- if timestamp_key not in analyses_by_timestamp:
127
- analyses_by_timestamp[timestamp_key] = {'situation': analysis}
 
 
128
 
129
- # Indexar recomendaciones de Claude
130
  for recommendation in claude_recommendations:
131
  if 'timestamp' in recommendation:
132
- # Normalizar el formato de timestamp para comparaci贸n
133
- timestamp_key = recommendation['timestamp'].split('.')[0] # Remover milisegundos
134
- if timestamp_key in analyses_by_timestamp:
135
- analyses_by_timestamp[timestamp_key]['recommendation'] = recommendation
136
- else:
137
- analyses_by_timestamp[timestamp_key] = {'recommendation': recommendation}
138
 
139
- # Si no hay an谩lisis despu茅s de la indexaci贸n
140
- if not analyses_by_timestamp:
141
- st.info(t.get('no_paired_analyses', 'No hay an谩lisis disponibles'))
142
- return
 
 
 
 
 
 
 
 
 
143
 
144
- # Convertir a lista ordenada por timestamp (m谩s reciente primero)
145
- paired_analyses = sorted(
146
- analyses_by_timestamp.items(),
147
- key=lambda x: x[0],
148
- reverse=True
149
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
- logger.info(f"Procesando {len(paired_analyses)} pares de an谩lisis")
152
 
153
- # Mostrar cada par de an谩lisis
154
- for i, (timestamp_key, analysis_pair) in enumerate(paired_analyses):
155
  try:
156
  # Obtener datos de situaci贸n y recomendaci贸n
157
  situation_data = analysis_pair.get('situation', {})
158
  recommendation_data = analysis_pair.get('recommendation', {})
 
159
 
160
  # Si no hay ning煤n dato, continuar al siguiente
161
  if not situation_data and not recommendation_data:
@@ -167,10 +208,9 @@ def display_current_situation_activities(username: str, t: dict):
167
 
168
  # Formatear fecha para mostrar
169
  try:
170
- # Usar timestamp de situation_data si est谩 disponible, sino usar el de recommendation_data
171
- timestamp_str = situation_data.get('timestamp', recommendation_data.get('timestamp', timestamp_key))
172
- timestamp = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
173
- formatted_date = timestamp.strftime("%d/%m/%Y %H:%M:%S")
174
  except Exception as date_error:
175
  logger.error(f"Error formateando fecha: {str(date_error)}")
176
  formatted_date = timestamp_key
@@ -185,8 +225,15 @@ def display_current_situation_activities(username: str, t: dict):
185
  }.get(text_type, text_type)
186
  title += f" - {text_type_display}"
187
 
 
 
 
 
 
 
 
188
  # Usar un ID 煤nico para cada expander
189
- expander_id = f"analysis_{i}_{timestamp_key}"
190
 
191
  # Mostrar el an谩lisis en un expander
192
  with st.expander(title, expanded=False):
@@ -212,9 +259,6 @@ def display_current_situation_activities(username: str, t: dict):
212
  if situation_data and 'metrics' in situation_data:
213
  metrics = situation_data['metrics']
214
 
215
- # Imprimir estructura real para depuraci贸n
216
- st.write("Estructura de m茅tricas:", metrics)
217
-
218
  # Dividir en dos columnas
219
  col1, col2 = st.columns(2)
220
 
@@ -235,9 +279,8 @@ def display_current_situation_activities(username: str, t: dict):
235
  score = metric_data['score']
236
  elif 'value' in metric_data:
237
  score = metric_data['value']
238
- # Agregar fallback para valores num茅ricos directos
239
- elif isinstance(metric_data, (int, float)):
240
- score = metric_data
241
 
242
  if score is not None:
243
  # Asegurarse de que score es num茅rico
@@ -263,11 +306,10 @@ def display_current_situation_activities(username: str, t: dict):
263
  # Si no es num茅rico, mostrar como texto
264
  st.markdown(f"""
265
  <div style="background-color:#f0f0f0; padding:10px; border-radius:5px; margin-bottom:10px;">
266
- <b>鈩癸笍 {metric_name.capitalize()}:</b> {score}
267
  </div>
268
  """, unsafe_allow_html=True)
269
  except Exception as e:
270
- st.error(f"Error procesando m茅trica {metric_name}: {str(e)}")
271
  logger.error(f"Error procesando m茅trica {metric_name}: {str(e)}")
272
 
273
  # Mostrar detalles adicionales si est谩n disponibles
@@ -288,16 +330,12 @@ def display_current_situation_activities(username: str, t: dict):
288
  if k not in ['normalized_score', 'score', 'value']}
289
 
290
  if details:
291
- detail_key = f"details_{metric_name}_{timestamp_key}_{i}"
292
  st.write(f"**{metric_name.capitalize()}**")
293
  st.json(details, expanded=False)
294
  except Exception as e:
295
- st.error(f"Error mostrando detalles de {metric_name}: {str(e)}")
296
  logger.error(f"Error mostrando detalles de {metric_name}: {str(e)}")
297
  else:
298
  st.info(t.get('no_diagnosis', 'No hay datos de diagn贸stico disponibles'))
299
- if situation_data:
300
- logger.warning(f"Claves disponibles en situation_data: {list(situation_data.keys())}")
301
 
302
  # Tab de recomendaciones
303
  with recommendations_tab:
 
81
  def display_current_situation_activities(username: str, t: dict):
82
  """
83
  Muestra an谩lisis de situaci贸n actual junto con las recomendaciones de Claude
84
+ unificando la informaci贸n de ambas colecciones y emparej谩ndolas por cercan铆a temporal.
85
  """
86
  try:
87
  # Recuperar datos de ambas colecciones
88
  logger.info(f"Recuperando an谩lisis de situaci贸n actual para {username}")
89
+ situation_analyses = get_current_situation_analysis(username, limit=10)
90
 
91
  # Verificar si hay datos
92
  if situation_analyses:
 
113
  st.info(t.get('no_current_situation', 'No hay an谩lisis de situaci贸n actual registrados'))
114
  return
115
 
116
+ # Crear pares combinados emparejando diagn贸sticos y recomendaciones cercanos en tiempo
117
+ logger.info("Creando emparejamientos temporales de an谩lisis")
 
 
118
 
119
+ # Convertir timestamps a objetos datetime para comparaci贸n
120
+ situation_times = []
121
  for analysis in situation_analyses:
122
  if 'timestamp' in analysis:
123
+ try:
124
+ timestamp_str = analysis['timestamp']
125
+ dt = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
126
+ situation_times.append((dt, analysis))
127
+ except Exception as e:
128
+ logger.error(f"Error parseando timestamp de situaci贸n: {str(e)}")
129
 
130
+ recommendation_times = []
131
  for recommendation in claude_recommendations:
132
  if 'timestamp' in recommendation:
133
+ try:
134
+ timestamp_str = recommendation['timestamp']
135
+ dt = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
136
+ recommendation_times.append((dt, recommendation))
137
+ except Exception as e:
138
+ logger.error(f"Error parseando timestamp de recomendaci贸n: {str(e)}")
139
 
140
+ # Ordenar por tiempo
141
+ situation_times.sort(key=lambda x: x[0], reverse=True)
142
+ recommendation_times.sort(key=lambda x: x[0], reverse=True)
143
+
144
+ # Crear pares combinados
145
+ combined_items = []
146
+
147
+ # Primero, procesar todas las situaciones encontrando la recomendaci贸n m谩s cercana
148
+ for sit_time, situation in situation_times:
149
+ # Buscar la recomendaci贸n m谩s cercana en tiempo
150
+ best_match = None
151
+ min_diff = timedelta(minutes=30) # M谩xima diferencia de tiempo aceptable (30 minutos)
152
+ best_rec_time = None
153
 
154
+ for rec_time, recommendation in recommendation_times:
155
+ time_diff = abs(sit_time - rec_time)
156
+ if time_diff < min_diff:
157
+ min_diff = time_diff
158
+ best_match = recommendation
159
+ best_rec_time = rec_time
160
+
161
+ # Crear un elemento combinado
162
+ if best_match:
163
+ timestamp_key = sit_time.isoformat()
164
+ combined_items.append((timestamp_key, {
165
+ 'situation': situation,
166
+ 'recommendation': best_match,
167
+ 'time_diff': min_diff.total_seconds()
168
+ }))
169
+ # Eliminar la recomendaci贸n usada para no reutilizarla
170
+ recommendation_times = [(t, r) for t, r in recommendation_times if t != best_rec_time]
171
+ logger.info(f"Emparejado: Diagn贸stico {sit_time} con Recomendaci贸n {best_rec_time} (diferencia: {min_diff})")
172
+ else:
173
+ # Si no hay recomendaci贸n cercana, solo incluir la situaci贸n
174
+ timestamp_key = sit_time.isoformat()
175
+ combined_items.append((timestamp_key, {
176
+ 'situation': situation
177
+ }))
178
+ logger.info(f"Sin emparejar: Diagn贸stico {sit_time} sin recomendaci贸n cercana")
179
+
180
+ # Agregar recomendaciones restantes sin situaci贸n
181
+ for rec_time, recommendation in recommendation_times:
182
+ timestamp_key = rec_time.isoformat()
183
+ combined_items.append((timestamp_key, {
184
+ 'recommendation': recommendation
185
+ }))
186
+ logger.info(f"Sin emparejar: Recomendaci贸n {rec_time} sin diagn贸stico cercano")
187
+
188
+ # Ordenar por tiempo (m谩s reciente primero)
189
+ combined_items.sort(key=lambda x: x[0], reverse=True)
190
 
191
+ logger.info(f"Procesando {len(combined_items)} elementos combinados")
192
 
193
+ # Mostrar cada par combinado
194
+ for i, (timestamp_key, analysis_pair) in enumerate(combined_items):
195
  try:
196
  # Obtener datos de situaci贸n y recomendaci贸n
197
  situation_data = analysis_pair.get('situation', {})
198
  recommendation_data = analysis_pair.get('recommendation', {})
199
+ time_diff = analysis_pair.get('time_diff')
200
 
201
  # Si no hay ning煤n dato, continuar al siguiente
202
  if not situation_data and not recommendation_data:
 
208
 
209
  # Formatear fecha para mostrar
210
  try:
211
+ # Usar timestamp del key que ya es un formato ISO
212
+ dt = datetime.fromisoformat(timestamp_key)
213
+ formatted_date = dt.strftime("%d/%m/%Y %H:%M:%S")
 
214
  except Exception as date_error:
215
  logger.error(f"Error formateando fecha: {str(date_error)}")
216
  formatted_date = timestamp_key
 
225
  }.get(text_type, text_type)
226
  title += f" - {text_type_display}"
227
 
228
+ # A帽adir indicador de emparejamiento si existe
229
+ if time_diff is not None:
230
+ if time_diff < 60: # menos de un minuto
231
+ title += f" 馃攧 (emparejados)"
232
+ else:
233
+ title += f" 馃攧 (emparejados, diferencia: {int(time_diff//60)} min)"
234
+
235
  # Usar un ID 煤nico para cada expander
236
+ expander_id = f"analysis_{i}_{timestamp_key.replace(':', '_')}"
237
 
238
  # Mostrar el an谩lisis en un expander
239
  with st.expander(title, expanded=False):
 
259
  if situation_data and 'metrics' in situation_data:
260
  metrics = situation_data['metrics']
261
 
 
 
 
262
  # Dividir en dos columnas
263
  col1, col2 = st.columns(2)
264
 
 
279
  score = metric_data['score']
280
  elif 'value' in metric_data:
281
  score = metric_data['value']
282
+ elif isinstance(metric_data, (int, float)):
283
+ score = metric_data
 
284
 
285
  if score is not None:
286
  # Asegurarse de que score es num茅rico
 
306
  # Si no es num茅rico, mostrar como texto
307
  st.markdown(f"""
308
  <div style="background-color:#f0f0f0; padding:10px; border-radius:5px; margin-bottom:10px;">
309
+ <b>鈩癸笍 {metric_name.capitalize()}:</b> {str(score)}
310
  </div>
311
  """, unsafe_allow_html=True)
312
  except Exception as e:
 
313
  logger.error(f"Error procesando m茅trica {metric_name}: {str(e)}")
314
 
315
  # Mostrar detalles adicionales si est谩n disponibles
 
330
  if k not in ['normalized_score', 'score', 'value']}
331
 
332
  if details:
 
333
  st.write(f"**{metric_name.capitalize()}**")
334
  st.json(details, expanded=False)
335
  except Exception as e:
 
336
  logger.error(f"Error mostrando detalles de {metric_name}: {str(e)}")
337
  else:
338
  st.info(t.get('no_diagnosis', 'No hay datos de diagn贸stico disponibles'))
 
 
339
 
340
  # Tab de recomendaciones
341
  with recommendations_tab: