AIdeaText commited on
Commit
3004ff5
·
verified ·
1 Parent(s): 609ba78

Create current_situation_interface.py

Browse files
modules/studentact/current_situation_interface.py ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # modules/studentact/current_situation_interface.py
2
+
3
+ import streamlit as st
4
+ import logging
5
+ from ..utils.widget_utils import generate_unique_key
6
+ import matplotlib.pyplot as plt
7
+ import numpy as np
8
+ from ..database.current_situation_mongo_db import store_current_situation_result
9
+
10
+ from .current_situation_analysis import (
11
+ analyze_text_dimensions,
12
+ analyze_clarity,
13
+ analyze_vocabulary_diversity,
14
+ analyze_cohesion,
15
+ analyze_structure,
16
+ get_dependency_depths,
17
+ normalize_score,
18
+ generate_sentence_graphs,
19
+ generate_word_connections,
20
+ generate_connection_paths,
21
+ create_vocabulary_network,
22
+ create_syntax_complexity_graph,
23
+ create_cohesion_heatmap,
24
+ )
25
+
26
+ # Configuración del estilo de matplotlib para el gráfico de radar
27
+ plt.rcParams['font.family'] = 'sans-serif'
28
+ plt.rcParams['axes.grid'] = True
29
+ plt.rcParams['axes.spines.top'] = False
30
+ plt.rcParams['axes.spines.right'] = False
31
+
32
+ logger = logging.getLogger(__name__)
33
+ ####################################
34
+
35
+ TEXT_TYPES = {
36
+ 'academic_article': {
37
+ 'name': 'Artículo Académico',
38
+ 'thresholds': {
39
+ 'vocabulary': {'min': 0.70, 'target': 0.85},
40
+ 'structure': {'min': 0.75, 'target': 0.90},
41
+ 'cohesion': {'min': 0.65, 'target': 0.80},
42
+ 'clarity': {'min': 0.70, 'target': 0.85}
43
+ }
44
+ },
45
+ 'student_essay': {
46
+ 'name': 'Trabajo Universitario',
47
+ 'thresholds': {
48
+ 'vocabulary': {'min': 0.60, 'target': 0.75},
49
+ 'structure': {'min': 0.65, 'target': 0.80},
50
+ 'cohesion': {'min': 0.55, 'target': 0.70},
51
+ 'clarity': {'min': 0.60, 'target': 0.75}
52
+ }
53
+ },
54
+ 'general_communication': {
55
+ 'name': 'Comunicación General',
56
+ 'thresholds': {
57
+ 'vocabulary': {'min': 0.50, 'target': 0.65},
58
+ 'structure': {'min': 0.55, 'target': 0.70},
59
+ 'cohesion': {'min': 0.45, 'target': 0.60},
60
+ 'clarity': {'min': 0.50, 'target': 0.65}
61
+ }
62
+ }
63
+ }
64
+ ####################################
65
+
66
+ def display_current_situation_interface(lang_code, nlp_models, t):
67
+ """
68
+ Interfaz simplificada con gráfico de radar para visualizar métricas.
69
+ """
70
+ # Inicializar estados si no existen
71
+ if 'text_input' not in st.session_state:
72
+ st.session_state.text_input = ""
73
+ if 'text_area' not in st.session_state: # Añadir inicialización de text_area
74
+ st.session_state.text_area = ""
75
+ if 'show_results' not in st.session_state:
76
+ st.session_state.show_results = False
77
+ if 'current_doc' not in st.session_state:
78
+ st.session_state.current_doc = None
79
+ if 'current_metrics' not in st.session_state:
80
+ st.session_state.current_metrics = None
81
+
82
+ try:
83
+ # Container principal con dos columnas
84
+ with st.container():
85
+ input_col, results_col = st.columns([1,2])
86
+
87
+ with input_col:
88
+ # Text area con manejo de estado
89
+ text_input = st.text_area(
90
+ t.get('input_prompt', "Escribe o pega tu texto aquí:"),
91
+ height=400,
92
+ key="text_area",
93
+ value=st.session_state.text_input,
94
+ help="Este texto será analizado para darte recomendaciones personalizadas"
95
+ )
96
+
97
+ # Función para manejar cambios de texto
98
+ if text_input != st.session_state.text_input:
99
+ st.session_state.text_input = text_input
100
+ st.session_state.show_results = False
101
+
102
+ if st.button(
103
+ t.get('analyze_button', "Analizar mi escritura"),
104
+ type="primary",
105
+ disabled=not text_input.strip(),
106
+ use_container_width=True,
107
+ ):
108
+ try:
109
+ with st.spinner(t.get('processing', "Analizando...")):
110
+ doc = nlp_models[lang_code](text_input)
111
+ metrics = analyze_text_dimensions(doc)
112
+
113
+ storage_success = store_current_situation_result(
114
+ username=st.session_state.username,
115
+ text=text_input,
116
+ metrics=metrics,
117
+ feedback=None
118
+ )
119
+
120
+ if not storage_success:
121
+ logger.warning("No se pudo guardar el análisis en la base de datos")
122
+
123
+ st.session_state.current_doc = doc
124
+ st.session_state.current_metrics = metrics
125
+ st.session_state.show_results = True
126
+
127
+ except Exception as e:
128
+ logger.error(f"Error en análisis: {str(e)}")
129
+ st.error(t.get('analysis_error', "Error al analizar el texto"))
130
+
131
+ # Mostrar resultados en la columna derecha
132
+ with results_col:
133
+ if st.session_state.show_results and st.session_state.current_metrics is not None:
134
+ # Primero los radio buttons para tipo de texto
135
+ st.markdown("### Tipo de texto")
136
+ text_type = st.radio(
137
+ "",
138
+ options=list(TEXT_TYPES.keys()),
139
+ format_func=lambda x: TEXT_TYPES[x]['name'],
140
+ horizontal=True,
141
+ key="text_type_radio",
142
+ help="Selecciona el tipo de texto para ajustar los criterios de evaluación"
143
+ )
144
+
145
+ st.session_state.current_text_type = text_type
146
+
147
+ # Luego mostrar los resultados
148
+ display_results(
149
+ metrics=st.session_state.current_metrics,
150
+ text_type=text_type
151
+ )
152
+
153
+ except Exception as e:
154
+ logger.error(f"Error en interfaz principal: {str(e)}")
155
+ st.error("Ocurrió un error al cargar la interfaz")
156
+
157
+ ###################################3333
158
+
159
+ def display_results(metrics, text_type=None):
160
+ """
161
+ Muestra los resultados del análisis: métricas verticalmente y gráfico radar.
162
+ """
163
+ try:
164
+ # Usar valor por defecto si no se especifica tipo
165
+ text_type = text_type or 'student_essay'
166
+
167
+ # Obtener umbrales según el tipo de texto
168
+ thresholds = TEXT_TYPES[text_type]['thresholds']
169
+
170
+ # Crear dos columnas para las métricas y el gráfico
171
+ metrics_col, graph_col = st.columns([1, 1.5])
172
+
173
+ # Columna de métricas
174
+ with metrics_col:
175
+ metrics_config = [
176
+ {
177
+ 'label': "Vocabulario",
178
+ 'key': 'vocabulary',
179
+ 'value': metrics['vocabulary']['normalized_score'],
180
+ 'help': "Riqueza y variedad del vocabulario",
181
+ 'thresholds': thresholds['vocabulary']
182
+ },
183
+ {
184
+ 'label': "Estructura",
185
+ 'key': 'structure',
186
+ 'value': metrics['structure']['normalized_score'],
187
+ 'help': "Organización y complejidad de oraciones",
188
+ 'thresholds': thresholds['structure']
189
+ },
190
+ {
191
+ 'label': "Cohesión",
192
+ 'key': 'cohesion',
193
+ 'value': metrics['cohesion']['normalized_score'],
194
+ 'help': "Conexión y fluidez entre ideas",
195
+ 'thresholds': thresholds['cohesion']
196
+ },
197
+ {
198
+ 'label': "Claridad",
199
+ 'key': 'clarity',
200
+ 'value': metrics['clarity']['normalized_score'],
201
+ 'help': "Facilidad de comprensión del texto",
202
+ 'thresholds': thresholds['clarity']
203
+ }
204
+ ]
205
+
206
+ # Mostrar métricas
207
+ for metric in metrics_config:
208
+ value = metric['value']
209
+ if value < metric['thresholds']['min']:
210
+ status = "⚠️ Por mejorar"
211
+ color = "inverse"
212
+ elif value < metric['thresholds']['target']:
213
+ status = "📈 Aceptable"
214
+ color = "off"
215
+ else:
216
+ status = "✅ Óptimo"
217
+ color = "normal"
218
+
219
+ st.metric(
220
+ metric['label'],
221
+ f"{value:.2f}",
222
+ f"{status} (Meta: {metric['thresholds']['target']:.2f})",
223
+ delta_color=color,
224
+ help=metric['help']
225
+ )
226
+ st.markdown("<div style='margin-bottom: 0.5rem;'></div>", unsafe_allow_html=True)
227
+
228
+ # Gráfico radar en la columna derecha
229
+ with graph_col:
230
+ display_radar_chart(metrics_config, thresholds)
231
+
232
+ except Exception as e:
233
+ logger.error(f"Error mostrando resultados: {str(e)}")
234
+ st.error("Error al mostrar los resultados")
235
+
236
+
237
+ ######################################
238
+ def display_radar_chart(metrics_config, thresholds):
239
+ """
240
+ Muestra el gráfico radar con los resultados.
241
+ """
242
+ try:
243
+ # Preparar datos para el gráfico
244
+ categories = [m['label'] for m in metrics_config]
245
+ values_user = [m['value'] for m in metrics_config]
246
+ min_values = [m['thresholds']['min'] for m in metrics_config]
247
+ target_values = [m['thresholds']['target'] for m in metrics_config]
248
+
249
+ # Crear y configurar gráfico
250
+ fig = plt.figure(figsize=(8, 8))
251
+ ax = fig.add_subplot(111, projection='polar')
252
+
253
+ # Configurar radar
254
+ angles = [n / float(len(categories)) * 2 * np.pi for n in range(len(categories))]
255
+ angles += angles[:1]
256
+ values_user += values_user[:1]
257
+ min_values += min_values[:1]
258
+ target_values += target_values[:1]
259
+
260
+ # Configurar ejes
261
+ ax.set_xticks(angles[:-1])
262
+ ax.set_xticklabels(categories, fontsize=10)
263
+ circle_ticks = np.arange(0, 1.1, 0.2)
264
+ ax.set_yticks(circle_ticks)
265
+ ax.set_yticklabels([f'{tick:.1f}' for tick in circle_ticks], fontsize=8)
266
+ ax.set_ylim(0, 1)
267
+
268
+ # Dibujar áreas de umbrales
269
+ ax.plot(angles, min_values, '#e74c3c', linestyle='--', linewidth=1, label='Mínimo', alpha=0.5)
270
+ ax.plot(angles, target_values, '#2ecc71', linestyle='--', linewidth=1, label='Meta', alpha=0.5)
271
+ ax.fill_between(angles, target_values, [1]*len(angles), color='#2ecc71', alpha=0.1)
272
+ ax.fill_between(angles, [0]*len(angles), min_values, color='#e74c3c', alpha=0.1)
273
+
274
+ # Dibujar valores del usuario
275
+ ax.plot(angles, values_user, '#3498db', linewidth=2, label='Tu escritura')
276
+ ax.fill(angles, values_user, '#3498db', alpha=0.2)
277
+
278
+ # Ajustar leyenda
279
+ ax.legend(
280
+ loc='upper right',
281
+ bbox_to_anchor=(1.3, 1.1), # Cambiado de (0.1, 0.1) a (1.3, 1.1)
282
+ fontsize=10,
283
+ frameon=True,
284
+ facecolor='white',
285
+ edgecolor='none',
286
+ shadow=True
287
+ )
288
+
289
+ plt.tight_layout()
290
+ st.pyplot(fig)
291
+ plt.close()
292
+
293
+ except Exception as e:
294
+ logger.error(f"Error mostrando gráfico radar: {str(e)}")
295
+ st.error("Error al mostrar el gráfico")
296
+ #######################################