|
|
|
|
|
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}" |
|
)) |