AIdeaText commited on
Commit
ad9c16f
1 Parent(s): d47f7a0

Update modules/ui/ui.py

Browse files
Files changed (1) hide show
  1. modules/ui/ui.py +312 -312
modules/ui/ui.py CHANGED
@@ -1,313 +1,313 @@
1
- # Importaciones generales
2
- import streamlit as st
3
- from streamlit_player import st_player
4
- import logging
5
- from datetime import datetime, timezone
6
- from dateutil.parser import parse
7
-
8
- # Configuración del logger
9
- logging.basicConfig(level=logging.INFO)
10
- logger = logging.getLogger(__name__)
11
-
12
- # Importaciones locales
13
- from session_state import initialize_session_state, logout
14
-
15
- from translations import get_translations
16
-
17
- from ..studentact.student_activities import display_student_progress
18
-
19
- from ..auth.auth import authenticate_user, authenticate_student, authenticate_admin
20
-
21
- from ..admin.admin_ui import admin_page
22
-
23
- ##Importaciones desde la configuración de bases datos #######
24
-
25
- from ..database.sql_db import (
26
- store_application_request,
27
- store_student_feedback,
28
- store_application_request
29
- )
30
-
31
- from ..database.mongo_db import (
32
- get_collection,
33
- insert_document,
34
- find_documents,
35
- update_document,
36
- delete_document
37
- )
38
-
39
- from ..database.morphosintax_mongo_db import (
40
- store_student_morphosyntax_result,
41
- get_student_morphosyntax_analysis,
42
- update_student_morphosyntax_analysis,
43
- delete_student_morphosyntax_analysis,
44
- get_student_morphosyntax_data
45
- )
46
-
47
- from ..morphosyntax.morphosyntax_interface import (
48
- display_morphosyntax_interface
49
- )
50
-
51
- def main():
52
- logger.info(f"Entrando en main() - Página actual: {st.session_state.page}")
53
-
54
- if 'nlp_models' not in st.session_state:
55
- logger.error("Los modelos NLP no están inicializados.")
56
- st.error("Los modelos NLP no están inicializados. Por favor, reinicie la aplicación.")
57
- return
58
-
59
- lang_code = st.session_state.get('lang_code', 'es')
60
- t = get_translations(lang_code)
61
-
62
- logger.info(f"Página actual antes de la lógica de enrutamiento: {st.session_state.page}")
63
-
64
- if st.session_state.get('logged_out', False):
65
- st.session_state.logged_out = False
66
- st.session_state.page = 'login'
67
- st.rerun()
68
-
69
- if not st.session_state.get('logged_in', False):
70
- logger.info("Usuario no ha iniciado sesión. Mostrando página de login/registro")
71
- login_register_page(lang_code, t)
72
- elif st.session_state.page == 'user':
73
- if st.session_state.role == 'Administrador':
74
- logger.info("Redirigiendo a la página de administrador")
75
- st.session_state.page = 'Admin'
76
- st.rerun()
77
- else:
78
- logger.info("Renderizando página de usuario")
79
- user_page(lang_code, t)
80
- elif st.session_state.page == "Admin":
81
- logger.info("Renderizando página de administrador")
82
- admin_page()
83
- else:
84
- logger.error(f"Página no reconocida: {st.session_state.page}")
85
- st.error(t.get('unrecognized_page', 'Página no reconocida'))
86
-
87
- logger.info(f"Saliendo de main() - Estado final de la sesión: {st.session_state}")
88
-
89
-
90
- def login_register_page(lang_code, t):
91
- st.title("AIdeaText")
92
- st.write(t.get("welcome_message", "Bienvenido. Por favor, inicie sesión o regístrese."))
93
-
94
- left_column, right_column = st.columns([1, 3])
95
-
96
- with left_column:
97
- tab1, tab2 = st.tabs([t.get("login", "Iniciar Sesión"), t.get("register", "Registrarse")])
98
-
99
- with tab1:
100
- login_form(lang_code, t)
101
-
102
- with tab2:
103
- register_form(lang_code, t)
104
-
105
- with right_column:
106
- display_videos_and_info(lang_code, t)
107
-
108
- def login_form(lang_code, t):
109
- with st.form("login_form"):
110
- username = st.text_input(t.get("email", "Correo electrónico"))
111
- password = st.text_input(t.get("password", "Contraseña"), type="password")
112
- submit_button = st.form_submit_button(t.get("login", "Iniciar Sesión"))
113
-
114
- if submit_button:
115
- success, role = authenticate_user(username, password)
116
- if success:
117
- st.session_state.logged_in = True
118
- st.session_state.username = username
119
- st.session_state.role = role
120
- if role == 'Administrador':
121
- st.session_state.page = 'Admin'
122
- else:
123
- st.session_state.page = 'user'
124
- logger.info(f"Usuario autenticado: {username}, Rol: {role}")
125
- st.rerun()
126
- else:
127
- st.error(t.get("invalid_credentials", "Credenciales incorrectas"))
128
-
129
- def register_form(lang_code, t):
130
- st.header(t.get("request_trial", "Solicitar prueba de la aplicación"))
131
-
132
- name = st.text_input(t.get("name", "Nombre"))
133
- lastname = st.text_input(t.get("lastname", "Apellidos"))
134
- institution = st.text_input(t.get("institution", "Institución"))
135
- current_role = st.selectbox(t.get("current_role", "Rol en la institución donde labora"),
136
- [t.get("professor", "Profesor"), t.get("student", "Estudiante"), t.get("administrative", "Administrativo")])
137
- desired_role = st.selectbox(t.get("desired_role", "Rol con el que desea registrarse en AIdeaText"),
138
- [t.get("professor", "Profesor"), t.get("student", "Estudiante")])
139
- email = st.text_input(t.get("institutional_email", "Correo electrónico de su institución"))
140
- reason = st.text_area(t.get("interest_reason", "¿Por qué estás interesado en probar AIdeaText?"))
141
-
142
- if st.button(t.get("submit_application", "Enviar solicitud")):
143
- logger.info(f"Attempting to submit application for {email}")
144
- logger.debug(f"Form data: name={name}, lastname={lastname}, email={email}, institution={institution}, current_role={current_role}, desired_role={desired_role}, reason={reason}")
145
-
146
- if not name or not lastname or not email or not institution or not reason:
147
- logger.warning("Incomplete form submission")
148
- st.error(t.get("complete_all_fields", "Por favor, completa todos los campos."))
149
- elif not is_institutional_email(email):
150
- logger.warning(f"Non-institutional email used: {email}")
151
- st.error(t.get("use_institutional_email", "Por favor, utiliza un correo electrónico institucional."))
152
- else:
153
- logger.info(f"Attempting to store application for {email}")
154
- success = store_application_request(name, lastname, email, institution, current_role, desired_role, reason)
155
- if success:
156
- st.success(t.get("application_sent", "Tu solicitud ha sido enviada. Te contactaremos pronto."))
157
- logger.info(f"Application request stored successfully for {email}")
158
- else:
159
- st.error(t.get("application_error", "Hubo un problema al enviar tu solicitud. Por favor, intenta de nuevo más tarde."))
160
- logger.error(f"Failed to store application request for {email}")
161
-
162
- def is_institutional_email(email):
163
- forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
164
- return not any(domain in email.lower() for domain in forbidden_domains)
165
-
166
- def display_videos_and_info(lang_code, t):
167
- st.header("Videos: pitch, demos, entrevistas, otros")
168
-
169
- videos = {
170
- "Presentación en PyCon Colombia, Medellín, 2024": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
171
- "Presentación fundación Ser Maaestro": "https://www.youtube.com/watch?v=imc4TI1q164",
172
- }
173
-
174
- selected_title = st.selectbox("Selecciona un video tutorial:", list(videos.keys()))
175
-
176
- if selected_title in videos:
177
- try:
178
- st_player(videos[selected_title])
179
- except Exception as e:
180
- st.error(f"Error al cargar el video: {str(e)}")
181
-
182
- st.markdown("""
183
- ## Novedades de la versión actual
184
- - Interfaz mejorada para una mejor experiencia de usuario
185
- - Optimización del análisis morfosintáctico
186
- - Soporte para múltiples idiomas
187
- """)
188
-
189
- #Después de iniciar sesión
190
-
191
- def user_page(lang_code, t):
192
- logger.info(f"Entrando en user_page para el estudiante: {st.session_state.username}")
193
-
194
- current_time = datetime.now(timezone.utc)
195
- last_fetch_time = st.session_state.get('last_data_fetch')
196
-
197
- if last_fetch_time:
198
- last_fetch_time = parse(last_fetch_time)
199
- else:
200
- last_fetch_time = datetime.min.replace(tzinfo=timezone.utc)
201
-
202
- # Comprobar si necesitamos recargar los datos del usuario
203
- if 'user_data' not in st.session_state or (current_time - last_fetch_time).total_seconds() > 60:
204
- with st.spinner(t.get('loading_data', "Cargando tus datos...")):
205
- try:
206
- st.session_state.user_data = get_student_morphosyntax_data(st.session_state.username)
207
- st.session_state.last_data_fetch = current_time.isoformat()
208
- except Exception as e:
209
- logger.error(f"Error al obtener datos del usuario: {str(e)}")
210
- st.error(t.get('data_load_error', "Hubo un problema al cargar tus datos. Por favor, intenta recargar la página."))
211
- return
212
-
213
- logger.info(f"Idioma actual: {st.session_state.lang_code}")
214
- logger.info(f"Modelos NLP cargados: {'nlp_models' in st.session_state}")
215
-
216
- languages = {'Español': 'es', 'English': 'en', 'Français': 'fr'}
217
-
218
- # Estilos CSS personalizados (mantener los estilos existentes)
219
- st.markdown("""
220
- <style>
221
- .stSelectbox > div > div {
222
- padding-top: 0px;
223
- }
224
- .stButton > button {
225
- padding-top: 2px;
226
- margin-top: 0px;
227
- }
228
- div[data-testid="stHorizontalBlock"] > div:nth-child(3) {
229
- display: flex;
230
- justify-content: flex-end;
231
- align-items: center;
232
- }
233
- </style>
234
- """, unsafe_allow_html=True)
235
-
236
- with st.container():
237
- col1, col2, col3 = st.columns([2, 2, 1])
238
- with col1:
239
- st.markdown(f"<h3 style='margin-bottom: 0; padding-top: 10px;'>{t['welcome']}, {st.session_state.username}</h3>", unsafe_allow_html=True)
240
- with col2:
241
- selected_lang = st.selectbox(
242
- t['select_language'],
243
- list(languages.keys()),
244
- index=list(languages.values()).index(st.session_state.lang_code),
245
- key=f"language_selector_{st.session_state.username}_{st.session_state.lang_code}"
246
- )
247
- new_lang_code = languages[selected_lang]
248
- if st.session_state.lang_code != new_lang_code:
249
- st.session_state.lang_code = new_lang_code
250
- st.rerun()
251
- with col3:
252
- if st.button(t['logout'], key=f"logout_button_{st.session_state.username}_{st.session_state.lang_code}"):
253
- logout()
254
- st.rerun()
255
-
256
- # Reinicializar el estado de la sesión
257
- initialize_session_state()
258
-
259
- # Recargar la aplicación
260
- st.rerun()
261
-
262
- st.markdown("---")
263
-
264
- tabs = st.tabs([
265
- t.get('morpho_tab', 'Análisis Morfosintáctico'),
266
- t.get('activities_tab', 'Mis Actividades'),
267
- t.get('feedback_tab', 'Formulario de Comentarios')
268
- ])
269
-
270
- with tabs[0]:
271
- display_morphosyntax_interface(st.session_state.lang_code, st.session_state.nlp_models, t)
272
-
273
- with tabs[1]:
274
- if 'user_data' in st.session_state and st.session_state.user_data:
275
- display_student_progress(st.session_state.username, st.session_state.lang_code, t)
276
- else:
277
- st.warning(t.get('no_data_warning', 'No se encontraron datos para este estudiante.'))
278
-
279
- with tabs[2]:
280
- display_feedback_form(st.session_state.lang_code, t)
281
-
282
- # Información de depuración
283
- with st.expander("Debug Info"):
284
- st.write(f"Página actual: {st.session_state.page}")
285
- st.write(f"Usuario: {st.session_state.get('username', 'No logueado')}")
286
- st.write(f"Rol: {st.session_state.get('role', 'No definido')}")
287
- st.write(f"Idioma: {st.session_state.lang_code}")
288
- st.write(f"Última actualización de datos: {st.session_state.get('last_data_fetch', 'Nunca')}")
289
-
290
- def display_feedback_form(lang_code, t):
291
- logging.info(f"display_feedback_form called with lang_code: {lang_code}")
292
-
293
- st.header(t['feedback_title'])
294
-
295
- name = st.text_input(t['name'])
296
- email = st.text_input(t['email'])
297
- feedback = st.text_area(t['feedback'])
298
-
299
- if st.button(t['submit']):
300
- if name and email and feedback:
301
- if store_student_feedback(st.session_state.username, name, email, feedback):
302
- st.success(t['feedback_success'])
303
- else:
304
- st.error(t['feedback_error'])
305
- else:
306
- st.warning(t['complete_all_fields'])
307
-
308
- # Definición de __all__ para especificar qué se exporta
309
- __all__ = ['main', 'login_register_page', 'initialize_session_state']
310
-
311
- # Bloque de ejecución condicional
312
- if __name__ == "__main__":
313
  main()
 
1
+ # Importaciones generales
2
+ import streamlit as st
3
+ from streamlit_player import st_player
4
+ import logging
5
+ from datetime import datetime, timezone
6
+ from dateutil.parser import parse
7
+
8
+ # Configuración del logger
9
+ logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
+
12
+ # Importaciones locales
13
+ #from session_state import initialize_session_state, logout
14
+
15
+ from translations import get_translations
16
+
17
+ from ..studentact.student_activities import display_student_progress
18
+
19
+ from ..auth.auth import authenticate_user, authenticate_student, authenticate_admin
20
+
21
+ from ..admin.admin_ui import admin_page
22
+
23
+ ##Importaciones desde la configuración de bases datos #######
24
+
25
+ from ..database.sql_db import (
26
+ store_application_request,
27
+ store_student_feedback,
28
+ store_application_request
29
+ )
30
+
31
+ from ..database.mongo_db import (
32
+ get_collection,
33
+ insert_document,
34
+ find_documents,
35
+ update_document,
36
+ delete_document
37
+ )
38
+
39
+ from ..database.morphosintax_mongo_db import (
40
+ store_student_morphosyntax_result,
41
+ get_student_morphosyntax_analysis,
42
+ update_student_morphosyntax_analysis,
43
+ delete_student_morphosyntax_analysis,
44
+ get_student_morphosyntax_data
45
+ )
46
+
47
+ from ..morphosyntax.morphosyntax_interface import (
48
+ display_morphosyntax_interface
49
+ )
50
+
51
+ def main():
52
+ logger.info(f"Entrando en main() - Página actual: {st.session_state.page}")
53
+
54
+ if 'nlp_models' not in st.session_state:
55
+ logger.error("Los modelos NLP no están inicializados.")
56
+ st.error("Los modelos NLP no están inicializados. Por favor, reinicie la aplicación.")
57
+ return
58
+
59
+ lang_code = st.session_state.get('lang_code', 'es')
60
+ t = get_translations(lang_code)
61
+
62
+ logger.info(f"Página actual antes de la lógica de enrutamiento: {st.session_state.page}")
63
+
64
+ if st.session_state.get('logged_out', False):
65
+ st.session_state.logged_out = False
66
+ st.session_state.page = 'login'
67
+ st.rerun()
68
+
69
+ if not st.session_state.get('logged_in', False):
70
+ logger.info("Usuario no ha iniciado sesión. Mostrando página de login/registro")
71
+ login_register_page(lang_code, t)
72
+ elif st.session_state.page == 'user':
73
+ if st.session_state.role == 'Administrador':
74
+ logger.info("Redirigiendo a la página de administrador")
75
+ st.session_state.page = 'Admin'
76
+ st.rerun()
77
+ else:
78
+ logger.info("Renderizando página de usuario")
79
+ user_page(lang_code, t)
80
+ elif st.session_state.page == "Admin":
81
+ logger.info("Renderizando página de administrador")
82
+ admin_page()
83
+ else:
84
+ logger.error(f"Página no reconocida: {st.session_state.page}")
85
+ st.error(t.get('unrecognized_page', 'Página no reconocida'))
86
+
87
+ logger.info(f"Saliendo de main() - Estado final de la sesión: {st.session_state}")
88
+
89
+
90
+ def login_register_page(lang_code, t):
91
+ st.title("AIdeaText")
92
+ st.write(t.get("welcome_message", "Bienvenido. Por favor, inicie sesión o regístrese."))
93
+
94
+ left_column, right_column = st.columns([1, 3])
95
+
96
+ with left_column:
97
+ tab1, tab2 = st.tabs([t.get("login", "Iniciar Sesión"), t.get("register", "Registrarse")])
98
+
99
+ with tab1:
100
+ login_form(lang_code, t)
101
+
102
+ with tab2:
103
+ register_form(lang_code, t)
104
+
105
+ with right_column:
106
+ display_videos_and_info(lang_code, t)
107
+
108
+ def login_form(lang_code, t):
109
+ with st.form("login_form"):
110
+ username = st.text_input(t.get("email", "Correo electrónico"))
111
+ password = st.text_input(t.get("password", "Contraseña"), type="password")
112
+ submit_button = st.form_submit_button(t.get("login", "Iniciar Sesión"))
113
+
114
+ if submit_button:
115
+ success, role = authenticate_user(username, password)
116
+ if success:
117
+ st.session_state.logged_in = True
118
+ st.session_state.username = username
119
+ st.session_state.role = role
120
+ if role == 'Administrador':
121
+ st.session_state.page = 'Admin'
122
+ else:
123
+ st.session_state.page = 'user'
124
+ logger.info(f"Usuario autenticado: {username}, Rol: {role}")
125
+ st.rerun()
126
+ else:
127
+ st.error(t.get("invalid_credentials", "Credenciales incorrectas"))
128
+
129
+ def register_form(lang_code, t):
130
+ st.header(t.get("request_trial", "Solicitar prueba de la aplicación"))
131
+
132
+ name = st.text_input(t.get("name", "Nombre"))
133
+ lastname = st.text_input(t.get("lastname", "Apellidos"))
134
+ institution = st.text_input(t.get("institution", "Institución"))
135
+ current_role = st.selectbox(t.get("current_role", "Rol en la institución donde labora"),
136
+ [t.get("professor", "Profesor"), t.get("student", "Estudiante"), t.get("administrative", "Administrativo")])
137
+ desired_role = st.selectbox(t.get("desired_role", "Rol con el que desea registrarse en AIdeaText"),
138
+ [t.get("professor", "Profesor"), t.get("student", "Estudiante")])
139
+ email = st.text_input(t.get("institutional_email", "Correo electrónico de su institución"))
140
+ reason = st.text_area(t.get("interest_reason", "¿Por qué estás interesado en probar AIdeaText?"))
141
+
142
+ if st.button(t.get("submit_application", "Enviar solicitud")):
143
+ logger.info(f"Attempting to submit application for {email}")
144
+ logger.debug(f"Form data: name={name}, lastname={lastname}, email={email}, institution={institution}, current_role={current_role}, desired_role={desired_role}, reason={reason}")
145
+
146
+ if not name or not lastname or not email or not institution or not reason:
147
+ logger.warning("Incomplete form submission")
148
+ st.error(t.get("complete_all_fields", "Por favor, completa todos los campos."))
149
+ elif not is_institutional_email(email):
150
+ logger.warning(f"Non-institutional email used: {email}")
151
+ st.error(t.get("use_institutional_email", "Por favor, utiliza un correo electrónico institucional."))
152
+ else:
153
+ logger.info(f"Attempting to store application for {email}")
154
+ success = store_application_request(name, lastname, email, institution, current_role, desired_role, reason)
155
+ if success:
156
+ st.success(t.get("application_sent", "Tu solicitud ha sido enviada. Te contactaremos pronto."))
157
+ logger.info(f"Application request stored successfully for {email}")
158
+ else:
159
+ st.error(t.get("application_error", "Hubo un problema al enviar tu solicitud. Por favor, intenta de nuevo más tarde."))
160
+ logger.error(f"Failed to store application request for {email}")
161
+
162
+ def is_institutional_email(email):
163
+ forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
164
+ return not any(domain in email.lower() for domain in forbidden_domains)
165
+
166
+ def display_videos_and_info(lang_code, t):
167
+ st.header("Videos: pitch, demos, entrevistas, otros")
168
+
169
+ videos = {
170
+ "Presentación en PyCon Colombia, Medellín, 2024": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
171
+ "Presentación fundación Ser Maaestro": "https://www.youtube.com/watch?v=imc4TI1q164",
172
+ }
173
+
174
+ selected_title = st.selectbox("Selecciona un video tutorial:", list(videos.keys()))
175
+
176
+ if selected_title in videos:
177
+ try:
178
+ st_player(videos[selected_title])
179
+ except Exception as e:
180
+ st.error(f"Error al cargar el video: {str(e)}")
181
+
182
+ st.markdown("""
183
+ ## Novedades de la versión actual
184
+ - Interfaz mejorada para una mejor experiencia de usuario
185
+ - Optimización del análisis morfosintáctico
186
+ - Soporte para múltiples idiomas
187
+ """)
188
+
189
+ #Después de iniciar sesión
190
+
191
+ def user_page(lang_code, t):
192
+ logger.info(f"Entrando en user_page para el estudiante: {st.session_state.username}")
193
+
194
+ current_time = datetime.now(timezone.utc)
195
+ last_fetch_time = st.session_state.get('last_data_fetch')
196
+
197
+ if last_fetch_time:
198
+ last_fetch_time = parse(last_fetch_time)
199
+ else:
200
+ last_fetch_time = datetime.min.replace(tzinfo=timezone.utc)
201
+
202
+ # Comprobar si necesitamos recargar los datos del usuario
203
+ if 'user_data' not in st.session_state or (current_time - last_fetch_time).total_seconds() > 60:
204
+ with st.spinner(t.get('loading_data', "Cargando tus datos...")):
205
+ try:
206
+ st.session_state.user_data = get_student_morphosyntax_data(st.session_state.username)
207
+ st.session_state.last_data_fetch = current_time.isoformat()
208
+ except Exception as e:
209
+ logger.error(f"Error al obtener datos del usuario: {str(e)}")
210
+ st.error(t.get('data_load_error', "Hubo un problema al cargar tus datos. Por favor, intenta recargar la página."))
211
+ return
212
+
213
+ logger.info(f"Idioma actual: {st.session_state.lang_code}")
214
+ logger.info(f"Modelos NLP cargados: {'nlp_models' in st.session_state}")
215
+
216
+ languages = {'Español': 'es', 'English': 'en', 'Français': 'fr'}
217
+
218
+ # Estilos CSS personalizados (mantener los estilos existentes)
219
+ st.markdown("""
220
+ <style>
221
+ .stSelectbox > div > div {
222
+ padding-top: 0px;
223
+ }
224
+ .stButton > button {
225
+ padding-top: 2px;
226
+ margin-top: 0px;
227
+ }
228
+ div[data-testid="stHorizontalBlock"] > div:nth-child(3) {
229
+ display: flex;
230
+ justify-content: flex-end;
231
+ align-items: center;
232
+ }
233
+ </style>
234
+ """, unsafe_allow_html=True)
235
+
236
+ with st.container():
237
+ col1, col2, col3 = st.columns([2, 2, 1])
238
+ with col1:
239
+ st.markdown(f"<h3 style='margin-bottom: 0; padding-top: 10px;'>{t['welcome']}, {st.session_state.username}</h3>", unsafe_allow_html=True)
240
+ with col2:
241
+ selected_lang = st.selectbox(
242
+ t['select_language'],
243
+ list(languages.keys()),
244
+ index=list(languages.values()).index(st.session_state.lang_code),
245
+ key=f"language_selector_{st.session_state.username}_{st.session_state.lang_code}"
246
+ )
247
+ new_lang_code = languages[selected_lang]
248
+ if st.session_state.lang_code != new_lang_code:
249
+ st.session_state.lang_code = new_lang_code
250
+ st.rerun()
251
+ with col3:
252
+ if st.button(t['logout'], key=f"logout_button_{st.session_state.username}_{st.session_state.lang_code}"):
253
+ logout()
254
+ st.rerun()
255
+
256
+ # Reinicializar el estado de la sesión
257
+ initialize_session_state()
258
+
259
+ # Recargar la aplicación
260
+ st.rerun()
261
+
262
+ st.markdown("---")
263
+
264
+ tabs = st.tabs([
265
+ t.get('morpho_tab', 'Análisis Morfosintáctico'),
266
+ t.get('activities_tab', 'Mis Actividades'),
267
+ t.get('feedback_tab', 'Formulario de Comentarios')
268
+ ])
269
+
270
+ with tabs[0]:
271
+ display_morphosyntax_interface(st.session_state.lang_code, st.session_state.nlp_models, t)
272
+
273
+ with tabs[1]:
274
+ if 'user_data' in st.session_state and st.session_state.user_data:
275
+ display_student_progress(st.session_state.username, st.session_state.lang_code, t)
276
+ else:
277
+ st.warning(t.get('no_data_warning', 'No se encontraron datos para este estudiante.'))
278
+
279
+ with tabs[2]:
280
+ display_feedback_form(st.session_state.lang_code, t)
281
+
282
+ # Información de depuración
283
+ with st.expander("Debug Info"):
284
+ st.write(f"Página actual: {st.session_state.page}")
285
+ st.write(f"Usuario: {st.session_state.get('username', 'No logueado')}")
286
+ st.write(f"Rol: {st.session_state.get('role', 'No definido')}")
287
+ st.write(f"Idioma: {st.session_state.lang_code}")
288
+ st.write(f"Última actualización de datos: {st.session_state.get('last_data_fetch', 'Nunca')}")
289
+
290
+ def display_feedback_form(lang_code, t):
291
+ logging.info(f"display_feedback_form called with lang_code: {lang_code}")
292
+
293
+ st.header(t['feedback_title'])
294
+
295
+ name = st.text_input(t['name'])
296
+ email = st.text_input(t['email'])
297
+ feedback = st.text_area(t['feedback'])
298
+
299
+ if st.button(t['submit']):
300
+ if name and email and feedback:
301
+ if store_student_feedback(st.session_state.username, name, email, feedback):
302
+ st.success(t['feedback_success'])
303
+ else:
304
+ st.error(t['feedback_error'])
305
+ else:
306
+ st.warning(t['complete_all_fields'])
307
+
308
+ # Definición de __all__ para especificar qué se exporta
309
+ __all__ = ['main', 'login_register_page', 'initialize_session_state']
310
+
311
+ # Bloque de ejecución condicional
312
+ if __name__ == "__main__":
313
  main()