|
|
|
|
| import streamlit as st
|
| import logging
|
| from ..utils.widget_utils import generate_unique_key
|
| from .current_situation_analysis import (
|
| analyze_text_dimensions,
|
| create_vocabulary_network,
|
| create_syntax_complexity_graph,
|
| create_cohesion_heatmap
|
| )
|
|
|
| logger = logging.getLogger(__name__)
|
|
|
| def display_current_situation_interface(lang_code, nlp_models, t):
|
| """
|
| Interfaz modular para el análisis de la situación actual del estudiante.
|
| Esta función maneja la presentación y la interacción con el usuario.
|
|
|
| Args:
|
| lang_code: Código del idioma actual
|
| nlp_models: Diccionario de modelos de spaCy cargados
|
| t: Diccionario de traducciones
|
| """
|
| st.markdown("## Mi Situación Actual de Escritura")
|
|
|
|
|
| with st.container():
|
|
|
| text_col, visual_col = st.columns([1,2])
|
|
|
| with text_col:
|
|
|
| text_input = st.text_area(
|
| t.get('current_situation_input', "Ingresa tu texto para analizar:"),
|
| height=400,
|
| key=generate_unique_key("current_situation", "input")
|
| )
|
|
|
|
|
| if st.button(
|
| t.get('analyze_button', "Explorar mi escritura"),
|
| type="primary",
|
| disabled=not text_input,
|
| key=generate_unique_key("current_situation", "analyze")
|
| ):
|
| try:
|
| with st.spinner(t.get('processing', "Analizando texto...")):
|
|
|
| doc = nlp_models[lang_code](text_input)
|
| metrics = analyze_text_dimensions(doc)
|
|
|
|
|
| with visual_col:
|
| display_current_situation_visual(doc, metrics)
|
|
|
|
|
| feedback = get_claude_feedback(metrics, text_input)
|
|
|
|
|
| from ..database.current_situation_mongo_db import store_current_situation_result
|
|
|
| if st.button(t.get('analyze_button', "Explorar mi escritura")):
|
| with st.spinner(t.get('processing', "Analizando texto...")):
|
|
|
| doc = nlp_models[lang_code](text_input)
|
|
|
|
|
| try:
|
| metrics = analyze_text_dimensions(doc)
|
| except Exception as e:
|
| logger.error(f"Error en análisis: {str(e)}")
|
| st.error("Error en el análisis de dimensiones")
|
| return
|
|
|
|
|
| try:
|
| feedback = get_claude_feedback(metrics, text_input)
|
| except Exception as e:
|
| logger.error(f"Error obteniendo feedback: {str(e)}")
|
| st.error("Error obteniendo retroalimentación")
|
| return
|
|
|
|
|
| if store_current_situation_result(
|
| st.session_state.username,
|
| text_input,
|
| metrics,
|
| feedback
|
| ):
|
| st.success(t.get('save_success', "Análisis guardado"))
|
|
|
|
|
| display_current_situation_visual(doc, metrics)
|
| show_recommendations(feedback, t)
|
| else:
|
| st.error("Error al guardar el análisis")
|
|
|
| except Exception as e:
|
| logger.error(f"Error en interfaz: {str(e)}")
|
| st.error("Error general en la interfaz")
|
|
|
|
|
| def display_current_situation_visual(doc, metrics):
|
| """Visualización mejorada de resultados con interpretaciones"""
|
| try:
|
| with st.container():
|
|
|
| st.markdown("""
|
| <style>
|
| .graph-container {
|
| background-color: white;
|
| border-radius: 10px;
|
| padding: 20px;
|
| box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
| margin: 15px 0;
|
| }
|
| .interpretation-box {
|
| background-color: #f8f9fa;
|
| border-left: 4px solid #0d6efd;
|
| padding: 15px;
|
| margin: 10px 0;
|
| }
|
| .metric-indicator {
|
| font-size: 1.2em;
|
| font-weight: 500;
|
| color: #1f2937;
|
| }
|
| </style>
|
| """, unsafe_allow_html=True)
|
|
|
|
|
| with st.expander("📚 Riqueza de Vocabulario", expanded=True):
|
| st.markdown('<div class="graph-container">', unsafe_allow_html=True)
|
| vocabulary_graph = create_vocabulary_network(doc)
|
| if vocabulary_graph:
|
|
|
| st.pyplot(vocabulary_graph)
|
| plt.close(vocabulary_graph)
|
|
|
|
|
| st.markdown('<div class="interpretation-box">', unsafe_allow_html=True)
|
| st.markdown("**¿Qué significa este gráfico?**")
|
| st.markdown("""
|
| - 🔵 Los nodos azules representan palabras clave en tu texto
|
| - 📏 El tamaño de cada nodo indica su frecuencia de uso
|
| - 🔗 Las líneas conectan palabras que aparecen juntas frecuentemente
|
| - 🎨 Los colores más intensos indican palabras más centrales
|
| """)
|
| st.markdown("</div>", unsafe_allow_html=True)
|
| st.markdown("</div>", unsafe_allow_html=True)
|
|
|
|
|
| with st.expander("🏗️ Complejidad Estructural", expanded=True):
|
| st.markdown('<div class="graph-container">', unsafe_allow_html=True)
|
| syntax_graph = create_syntax_complexity_graph(doc)
|
| if syntax_graph:
|
| st.pyplot(syntax_graph)
|
| plt.close(syntax_graph)
|
|
|
| st.markdown('<div class="interpretation-box">', unsafe_allow_html=True)
|
| st.markdown("**Análisis de la estructura:**")
|
| st.markdown("""
|
| - 📊 Las barras muestran la complejidad de cada oración
|
| - 📈 Mayor altura indica estructuras más elaboradas
|
| - 🎯 La línea punteada indica el nivel óptimo de complejidad
|
| - 🔄 Variación en las alturas sugiere dinamismo en la escritura
|
| """)
|
| st.markdown("</div>", unsafe_allow_html=True)
|
| st.markdown("</div>", unsafe_allow_html=True)
|
|
|
|
|
| with st.expander("🔄 Cohesión del Texto", expanded=True):
|
| st.markdown('<div class="graph-container">', unsafe_allow_html=True)
|
| cohesion_map = create_cohesion_heatmap(doc)
|
| if cohesion_map:
|
| st.pyplot(cohesion_map)
|
| plt.close(cohesion_map)
|
|
|
| st.markdown('<div class="interpretation-box">', unsafe_allow_html=True)
|
| st.markdown("**¿Cómo leer el mapa de calor?**")
|
| st.markdown("""
|
| - 🌈 Colores más intensos indican mayor conexión entre oraciones
|
| - 📝 La diagonal muestra la coherencia interna de cada oración
|
| - 🔗 Las zonas claras sugieren oportunidades de mejorar conexiones
|
| - 🎯 Un buen texto muestra patrones de color consistentes
|
| """)
|
| st.markdown("</div>", unsafe_allow_html=True)
|
| st.markdown("</div>", unsafe_allow_html=True)
|
|
|
|
|
| with st.expander("📊 Resumen de Métricas", expanded=True):
|
| col1, col2, col3 = st.columns(3)
|
|
|
| with col1:
|
| st.metric(
|
| "Diversidad Léxica",
|
| f"{metrics['vocabulary_richness']:.2f}/1.0",
|
| help="Mide la variedad de palabras diferentes utilizadas"
|
| )
|
|
|
| with col2:
|
| st.metric(
|
| "Complejidad Estructural",
|
| f"{metrics['structural_complexity']:.2f}/1.0",
|
| help="Indica qué tan elaboradas son las estructuras de las oraciones"
|
| )
|
|
|
| with col3:
|
| st.metric(
|
| "Cohesión Textual",
|
| f"{metrics['cohesion_score']:.2f}/1.0",
|
| help="Evalúa qué tan bien conectadas están las ideas entre sí"
|
| )
|
|
|
| except Exception as e:
|
| logger.error(f"Error en visualización: {str(e)}")
|
| st.error("Error al generar las visualizaciones")
|
|
|
|
|
| def show_recommendations(feedback, t):
|
| """
|
| Muestra las recomendaciones y ejercicios personalizados para el estudiante,
|
| permitiendo el seguimiento de su progreso.
|
|
|
| Args:
|
| feedback: Diccionario con retroalimentación y ejercicios recomendados
|
| t: Diccionario de traducciones
|
| """
|
| st.markdown("### " + t.get('recommendations_title', "Recomendaciones para mejorar"))
|
|
|
| for area, exercises in feedback['recommendations'].items():
|
| with st.expander(f"💡 {area}"):
|
| try:
|
|
|
| st.markdown(exercises['description'])
|
|
|
|
|
| from ..database.current_situation_mongo_db import get_student_exercises_history
|
| exercises_history = get_student_exercises_history(st.session_state.username)
|
|
|
|
|
| completed = exercises_history.get(area, [])
|
|
|
|
|
| progress_col1, progress_col2 = st.columns([3,1])
|
| with progress_col1:
|
| st.markdown("**Ejercicio sugerido:**")
|
| st.markdown(exercises['activity'])
|
|
|
| with progress_col2:
|
|
|
| exercise_key = f"{area}_{exercises['activity']}"
|
| is_completed = exercise_key in completed
|
|
|
| if is_completed:
|
| st.success("✅ Completado")
|
| else:
|
|
|
| if st.button(
|
| t.get('mark_complete', "Marcar como completado"),
|
| key=generate_unique_key("exercise", area),
|
| type="primary"
|
| ):
|
| try:
|
| from ..database.current_situation_mongo_db import update_exercise_status
|
|
|
|
|
| success = update_exercise_status(
|
| username=st.session_state.username,
|
| area=area,
|
| exercise=exercises['activity'],
|
| completed=True
|
| )
|
|
|
| if success:
|
| st.success(t.get(
|
| 'exercise_completed',
|
| "¡Ejercicio marcado como completado!"
|
| ))
|
| st.rerun()
|
| else:
|
| st.error(t.get(
|
| 'exercise_error',
|
| "Error al actualizar el estado del ejercicio"
|
| ))
|
| except Exception as e:
|
| logger.error(f"Error actualizando estado del ejercicio: {str(e)}")
|
| st.error(t.get('update_error', "Error al actualizar el ejercicio"))
|
|
|
|
|
| if 'resources' in exercises:
|
| st.markdown("**Recursos adicionales:**")
|
| for resource in exercises['resources']:
|
| st.markdown(f"- {resource}")
|
|
|
|
|
| if is_completed:
|
| completion_date = exercises_history[exercise_key].get('completion_date')
|
| if completion_date:
|
| st.caption(
|
| t.get('completed_on', "Completado el") +
|
| f": {completion_date.strftime('%d/%m/%Y %H:%M')}"
|
| )
|
|
|
| except Exception as e:
|
| logger.error(f"Error mostrando recomendaciones para {area}: {str(e)}")
|
| st.error(t.get(
|
| 'recommendations_error',
|
| f"Error al mostrar las recomendaciones para {area}"
|
| )) |