AIdeaText commited on
Commit
9dd968e
·
verified ·
1 Parent(s): be0c7a2

Upload 2 files

Browse files
Files changed (2) hide show
  1. modules/ui/ui.py +310 -310
  2. modules/ui/user_page.py +350 -349
modules/ui/ui.py CHANGED
@@ -1,311 +1,311 @@
1
- # modules/ui/ui.py
2
- import streamlit as st
3
- from streamlit_player import st_player
4
- import logging
5
- from datetime import datetime
6
- from dateutil.parser import parse
7
-
8
- # Importaciones locales
9
- #
10
- from session_state import initialize_session_state, logout
11
- #
12
- from translations import get_translations
13
- #
14
- from ..auth.auth import authenticate_user, authenticate_student, authenticate_admin
15
- #
16
- from ..database.sql_db import store_application_request
17
-
18
- #from .user_page import user_page
19
- try:
20
- from .user_page import user_page
21
- except ImportError:
22
- logger.error("No se pudo importar user_page. Asegúrate de que el archivo existe.")
23
- # Definir una función de respaldo
24
- def user_page(lang_code, t):
25
- st.error("La página de usuario no está disponible. Por favor, contacta al administrador.")
26
-
27
- from ..admin.admin_ui import admin_page
28
-
29
- # Configuración del logger
30
- logging.basicConfig(level=logging.INFO)
31
- logger = logging.getLogger(__name__)
32
-
33
- #############################################################
34
- def main():
35
- logger.info(f"Entrando en main() - Página actual: {st.session_state.page}")
36
-
37
- if 'nlp_models' not in st.session_state:
38
- logger.error("Los modelos NLP no están inicializados.")
39
- st.error("Los modelos NLP no están inicializados. Por favor, reinicie la aplicación.")
40
- return
41
-
42
- lang_code = st.session_state.get('lang_code', 'es')
43
- t = get_translations(lang_code)
44
-
45
- logger.info(f"Página actual antes de la lógica de enrutamiento: {st.session_state.page}")
46
-
47
- if st.session_state.get('logged_out', False):
48
- st.session_state.logged_out = False
49
- st.session_state.page = 'login'
50
- st.rerun()
51
-
52
- if not st.session_state.get('logged_in', False):
53
- logger.info("Usuario no ha iniciado sesión. Mostrando página de login/registro")
54
- login_register_page(lang_code, t)
55
- elif st.session_state.page == 'user':
56
- if st.session_state.role == 'Administrador':
57
- logger.info("Redirigiendo a la página de administrador")
58
- st.session_state.page = 'Admin'
59
- st.rerun()
60
- else:
61
- logger.info("Renderizando página de usuario")
62
- user_page(lang_code, t)
63
- elif st.session_state.page == "Admin":
64
- logger.info("Renderizando página de administrador")
65
- admin_page()
66
- else:
67
- logger.error(f"Página no reconocida: {st.session_state.page}")
68
- st.error(t.get('unrecognized_page', 'Página no reconocida'))
69
- # Redirigir a la página de usuario en caso de error
70
- st.session_state.page = 'user'
71
- st.rerun()
72
-
73
- logger.info(f"Saliendo de main() - Estado final de la sesión: {st.session_state}")
74
-
75
- #############################################################
76
- #############################################################
77
- def login_register_page(lang_code, t):
78
- # st.title("AIdeaText")
79
- # st.write(t.get("welcome_message", "Bienvenido. Por favor, inicie sesión o regístrese."))
80
-
81
- left_column, right_column = st.columns([1, 3])
82
-
83
- with left_column:
84
- tab1, tab2 = st.tabs([t.get("login", "Iniciar Sesión"),
85
- t.get("register", "Registrarse")])
86
-
87
- with tab1:
88
- login_form(lang_code, t)
89
-
90
- with tab2:
91
- register_form(lang_code, t)
92
-
93
- with right_column:
94
- display_videos_and_info(lang_code, t)
95
-
96
- #############################################################
97
- #############################################################
98
- def login_form(lang_code, t):
99
- with st.form("login_form"):
100
- username = st.text_input(t.get("email", "Correo electrónico"))
101
- password = st.text_input(t.get("password", "Contraseña"), type="password")
102
- submit_button = st.form_submit_button(t.get("login", "Iniciar Sesión"))
103
-
104
- if submit_button:
105
- success, role = authenticate_user(username, password)
106
- if success:
107
- st.session_state.logged_in = True
108
- st.session_state.username = username
109
- st.session_state.role = role
110
- if role == 'Administrador':
111
- st.session_state.page = 'Admin'
112
- else:
113
- st.session_state.page = 'user'
114
- logger.info(f"Usuario autenticado: {username}, Rol: {role}")
115
- st.rerun()
116
- else:
117
- st.error(t.get("invalid_credentials", "Credenciales incorrectas"))
118
-
119
-
120
- #############################################################
121
- #############################################################
122
- def register_form(lang_code, t):
123
- # st.header(t.get("request_trial", "Solicitar prueba de la aplicación"))
124
- name = st.text_input(t.get("name", "Nombre"))
125
- lastname = st.text_input(t.get("lastname", "Apellidos"))
126
- institution = st.text_input(t.get("institution", "Institución"))
127
- current_role = st.selectbox(t.get("current_role", "Rol en la institución donde labora"),
128
- [t.get("professor", "Profesor"), t.get("student", "Estudiante"), t.get("administrative", "Administrativo")])
129
-
130
- # Definimos el rol por defecto como estudiante
131
- desired_role = t.get("student", "Estudiante")
132
-
133
- email = st.text_input(t.get("institutional_email", "Correo electrónico de su institución"))
134
- reason = st.text_area(t.get("interest_reason", "¿Por qué estás interesado en probar AIdeaText?"))
135
-
136
- if st.button(t.get("submit_application", "Enviar solicitud")):
137
- logger.info(f"Attempting to submit application for {email}")
138
- logger.debug(f"Form data: name={name}, lastname={lastname}, email={email}, institution={institution}, current_role={current_role}, desired_role={desired_role}, reason={reason}")
139
-
140
- if not name or not lastname or not email or not institution or not reason:
141
- logger.warning("Incomplete form submission")
142
- st.error(t.get("complete_all_fields", "Por favor, completa todos los campos."))
143
- elif not is_institutional_email(email):
144
- logger.warning(f"Non-institutional email used: {email}")
145
- st.error(t.get("use_institutional_email", "Por favor, utiliza un correo electrónico institucional."))
146
- else:
147
- logger.info(f"Attempting to store application for {email}")
148
- success = store_application_request(name, lastname, email, institution, current_role, desired_role, reason)
149
- if success:
150
- st.success(t.get("application_sent", "Tu solicitud ha sido enviada. Te contactaremos pronto."))
151
- logger.info(f"Application request stored successfully for {email}")
152
- else:
153
- st.error(t.get("application_error", "Hubo un problema al enviar tu solicitud. Por favor, intenta de nuevo más tarde."))
154
- logger.error(f"Failed to store application request for {email}")
155
-
156
-
157
- #############################################################
158
- #############################################################
159
- def is_institutional_email(email):
160
- forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
161
- return not any(domain in email.lower() for domain in forbidden_domains)
162
-
163
-
164
- #############################################################
165
- #############################################################
166
- def display_videos_and_info(lang_code, t):
167
- # Crear tabs para cada sección
168
- tab_use_case, tab_videos, tab_events, tab_gallery, tab_news = st.tabs([
169
- "Casos de uso",
170
- "Videos de presentaciones",
171
- "Ponencias académicas",
172
- "Fotos de eventos",
173
- "Control de versiones"
174
- ])
175
-
176
- # Tab de Casos de uso
177
- with tab_use_case:
178
- use_case_videos = {
179
- "English - Radar use chart": "https://youtu.be/fFbbtlIewgs",
180
- "English - Use AI Bot and arcs charts fuctions": "https://youtu.be/XjM-1oOl-ao",
181
- "English - Arcs use charts, example 1": "https://youtu.be/PdK_bgigVaM",
182
- "English - Arcs use charts, excample 2": "https://youtu.be/7uaV1njPOng",
183
- "Español - Uso del diagrama radar para verificar redacción": "https://www.youtube.com/watch?v=nJP6xscPLBU",
184
- "Español - Uso de los diagramas de arco, ejemplo 1": "https://www.youtube.com/watch?v=ApBIAr2S-bE",
185
- "Español - Uso de los diagramas de arco, ejemplo 2": "https://www.youtube.com/watch?v=JnP2U1Fm0rc",
186
- "Español - Uso de los diagramas de arco, ejemplo 3": "https://www.youtube.com/watch?v=waWWwPTaI-Y",
187
- "Español - Uso del bot para buscar respuestas" : "https://www.youtube.com/watch?v=GFKDS0K2s7E"
188
- }
189
-
190
- selected_title = st.selectbox("Selecciona un caso de uso en español o en inglés:", list(use_case_videos.keys()))
191
- if selected_title in use_case_videos:
192
- try:
193
- st_player(use_case_videos[selected_title])
194
- except Exception as e:
195
- st.error(f"Error al cargar el video: {str(e)}")
196
-
197
- # Tab de Videos
198
- with tab_videos:
199
- videos = {
200
- "Reel AIdeaText": "https://youtu.be/hXnwUvN1Q9Q",
201
- "Presentación en SENDA, UNAM. Ciudad de México, México" : "https://www.youtube.com/watch?v=XFLvjST2cE0",
202
- "Presentación en PyCon 2024. Colombia, Medellín": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
203
- "Presentación en la Fundación Ser Maaestro. Lima, Perú": "https://www.youtube.com/watch?v=imc4TI1q164",
204
- "Presentación en el programa de incubación Explora del IFE, TEC de Monterrey, Nuevo León, México": "https://www.youtube.com/watch?v=Fqi4Di_Rj_s",
205
- "Entrevista con el Dr. Guillermo Ruíz. Lima, Perú": "https://www.youtube.com/watch?v=_ch8cRja3oc",
206
- "Demo de la versión de escritorio.": "https://www.youtube.com/watch?v=nP6eXbog-ZY"
207
- }
208
-
209
- selected_title = st.selectbox("Selecciona una conferencia:", list(videos.keys()))
210
- if selected_title in videos:
211
- try:
212
- st_player(videos[selected_title])
213
- except Exception as e:
214
- st.error(f"Error al cargar el video: {str(e)}")
215
-
216
- # Tab de Eventos
217
- with tab_events:
218
- st.markdown("""
219
- ## 2025
220
-
221
- **El Agente Cognitivo Vinculante como Innovación en el Aprendizaje Adaptativo: el caso de AIdeaText**
222
- IFE CONFERENCE 2025. Organizado por el Instituto para el Futuro de la Educación del TEC de Monterrey.
223
- Nuevo León, México. Del 28 al 30 enero 2025
224
-
225
- ## 2024
226
- [1]
227
- AIdeaText, AIdeaText, recurso digital que emplea la técnica de Análisis de Resonancia Central para perfeccionar textos académicos**
228
- V Temporada SENDA - Organizado por el Seminario de Entornos y Narrativas Digitales en la Academia del
229
- Instituto de Investigaciones Antropológicas (IIA) de la Universidad Autonóma de México (UNAM). 22 noviembre 2024
230
-
231
- [2]
232
- Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
233
- Congreso HeETI 2024: Horizontes Expandidos de la Educación, la Tecnología y la Innovación
234
- Universidad el Claustro de Sor Juana. Del 25 al 27 septiembre 2024
235
- [3]
236
- AIdeaText, visualización de mapas semánticos**
237
- PyCon 2024, Organizado por el grupo de desarrolladores independientes de Python.
238
- Universidad EAFIT, Medellín, Colombia. Del 7 al 9 de junio de 2024.
239
-
240
- ## 2023
241
- **Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
242
- [1]
243
- XVII Congreso Nacional de Investigación Educativa - VII Encuentro de Estudiantes de Posgrado Educación.
244
- Consejo Mexicano de Investigación Educativa (COMIE)
245
- Villahermosa, Tabasco, México.
246
- Del 4 al 8 de diciembre 2023
247
- [2]
248
- XXXI Encuentro Internacional de Educación a Distancia
249
- Universidad de Guadalajara. Jalisco, México.
250
- Del 27 al 30 noviembre 2023
251
- [3]
252
- IV Temporada SENDA - Seminario de Entornos y Narrativas Digitales en la Academia
253
- Instituto de Investigaciones Antropológicas (IIA), UNAM.
254
- 22 noviembre 2023
255
- [4]
256
- 1er Congreso Internacional de Educación Digital
257
- Instituto Politécnico Nacional, sede Zacatecas. México.
258
- Del 23 al 24 de noviembre de 2023
259
-
260
- [5]
261
- La cuestión de la centralidad del maestro frente a las tecnologías digitales generativas**
262
- Innova Fórum: Ecosistemas de Aprendizaje
263
- Universidad de Guadalajara. Jalisco, México.
264
- Del 16 al 18 de mayo 2023
265
- """)
266
-
267
- # Tab de Galería
268
- with tab_gallery:
269
- # Contenedor con ancho máximo
270
- with st.container():
271
- # Dividimos en dos columnas principales
272
- col_left, col_right = st.columns(2)
273
-
274
- # Columna izquierda: Foto 1 grande
275
- with col_left:
276
- # Foto 2 arriba
277
- st.image("assets/img/socialmedia/_MG_2845.JPG",
278
- caption="MakerFaire CDMX 2024",
279
- width=480) # Ajusta este valor según necesites
280
- # use_column_width=True)
281
-
282
- # Foto 3 abajo
283
- st.image("assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg",
284
- caption="MakerFaire CDMX 2024",
285
- width=480) # Ajusta este valor según necesites
286
- # use_column_width=True)
287
-
288
- # Columna derecha: Fotos 2 y 3 una encima de otra
289
- with col_right:
290
- st.image("assets/img/socialmedia/_MG_2790.jpg",
291
- caption="MakerFaire CDMX 2024",
292
- width=540) # Ajusta este valor según necesites
293
-
294
-
295
- # Tab de Novedades
296
- with tab_news:
297
- st.markdown("""
298
- ### Novedades de la versión actual
299
- - Interfaz mejorada para una mejor experiencia de usuario
300
- - Optimización del análisis morfosintáctico
301
- - Soporte para múltiples idiomas
302
- - Nuevo módulo de análisis del discurso
303
- - Sistema de chat integrado para soporte
304
- """)
305
-
306
- # Definición de __all__ para especificar qué se exporta
307
- __all__ = ['main', 'login_register_page', 'initialize_session_state']
308
-
309
- # Bloque de ejecución condicional
310
- if __name__ == "__main__":
311
  main()
 
1
+ # modules/ui/ui.py
2
+ import streamlit as st
3
+ from streamlit_player import st_player
4
+ import logging
5
+ from datetime import datetime
6
+ from dateutil.parser import parse
7
+
8
+ # Importaciones locales
9
+ #
10
+ from session_state import initialize_session_state, logout
11
+ #
12
+ from translations import get_translations
13
+ #
14
+ from ..auth.auth import authenticate_user, authenticate_student, authenticate_admin
15
+ #
16
+ from ..database.sql_db import store_application_request
17
+
18
+ #from .user_page import user_page
19
+ try:
20
+ from .user_page import user_page
21
+ except ImportError:
22
+ logger.error("No se pudo importar user_page. Asegúrate de que el archivo existe.")
23
+ # Definir una función de respaldo
24
+ def user_page(lang_code, t):
25
+ st.error("La página de usuario no está disponible. Por favor, contacta al administrador.")
26
+
27
+ from ..admin.admin_ui import admin_page
28
+
29
+ # Configuración del logger
30
+ logging.basicConfig(level=logging.INFO)
31
+ logger = logging.getLogger(__name__)
32
+
33
+ #############################################################
34
+ def main():
35
+ logger.info(f"Entrando en main() - Página actual: {st.session_state.page}")
36
+
37
+ if 'nlp_models' not in st.session_state:
38
+ logger.error("Los modelos NLP no están inicializados.")
39
+ st.error("Los modelos NLP no están inicializados. Por favor, reinicie la aplicación.")
40
+ return
41
+
42
+ lang_code = st.session_state.get('lang_code', 'es')
43
+ t = get_translations(lang_code)
44
+
45
+ logger.info(f"Página actual antes de la lógica de enrutamiento: {st.session_state.page}")
46
+
47
+ if st.session_state.get('logged_out', False):
48
+ st.session_state.logged_out = False
49
+ st.session_state.page = 'login'
50
+ st.rerun()
51
+
52
+ if not st.session_state.get('logged_in', False):
53
+ logger.info("Usuario no ha iniciado sesión. Mostrando página de login/registro")
54
+ login_register_page(lang_code, t)
55
+ elif st.session_state.page == 'user':
56
+ if st.session_state.role == 'Administrador':
57
+ logger.info("Redirigiendo a la página de administrador")
58
+ st.session_state.page = 'Admin'
59
+ st.rerun()
60
+ else:
61
+ logger.info("Renderizando página de usuario")
62
+ user_page(lang_code, t)
63
+ elif st.session_state.page == "Admin":
64
+ logger.info("Renderizando página de administrador")
65
+ admin_page()
66
+ else:
67
+ logger.error(f"Página no reconocida: {st.session_state.page}")
68
+ st.error(t.get('unrecognized_page', 'Página no reconocida'))
69
+ # Redirigir a la página de usuario en caso de error
70
+ st.session_state.page = 'user'
71
+ st.rerun()
72
+
73
+ logger.info(f"Saliendo de main() - Estado final de la sesión: {st.session_state}")
74
+
75
+ #############################################################
76
+ #############################################################
77
+ def login_register_page(lang_code, t):
78
+ # st.title("AIdeaText")
79
+ # st.write(t.get("welcome_message", "Bienvenido. Por favor, inicie sesión o regístrese."))
80
+
81
+ left_column, right_column = st.columns([1, 3])
82
+
83
+ with left_column:
84
+ tab1, tab2 = st.tabs([t.get("login", "Iniciar Sesión"),
85
+ t.get("register", "Registrarse")])
86
+
87
+ with tab1:
88
+ login_form(lang_code, t)
89
+
90
+ with tab2:
91
+ register_form(lang_code, t)
92
+
93
+ with right_column:
94
+ display_videos_and_info(lang_code, t)
95
+
96
+ #############################################################
97
+ #############################################################
98
+ def login_form(lang_code, t):
99
+ with st.form("login_form"):
100
+ username = st.text_input(t.get("email", "Correo electrónico"))
101
+ password = st.text_input(t.get("password", "Contraseña"), type="password")
102
+ submit_button = st.form_submit_button(t.get("login", "Iniciar Sesión"))
103
+
104
+ if submit_button:
105
+ success, role = authenticate_user(username, password)
106
+ if success:
107
+ st.session_state.logged_in = True
108
+ st.session_state.username = username
109
+ st.session_state.role = role
110
+ if role == 'Administrador':
111
+ st.session_state.page = 'Admin'
112
+ else:
113
+ st.session_state.page = 'user'
114
+ logger.info(f"Usuario autenticado: {username}, Rol: {role}")
115
+ st.rerun()
116
+ else:
117
+ st.error(t.get("invalid_credentials", "Credenciales incorrectas"))
118
+
119
+
120
+ #############################################################
121
+ #############################################################
122
+ def register_form(lang_code, t):
123
+ # st.header(t.get("request_trial", "Solicitar prueba de la aplicación"))
124
+ name = st.text_input(t.get("name", "Nombre"))
125
+ lastname = st.text_input(t.get("lastname", "Apellidos"))
126
+ institution = st.text_input(t.get("institution", "Institución"))
127
+ current_role = st.selectbox(t.get("current_role", "Rol en la institución donde labora"),
128
+ [t.get("professor", "Profesor"), t.get("student", "Estudiante"), t.get("administrative", "Administrativo")])
129
+
130
+ # Definimos el rol por defecto como estudiante
131
+ desired_role = t.get("student", "Estudiante")
132
+
133
+ email = st.text_input(t.get("institutional_email", "Correo electrónico de su institución"))
134
+ reason = st.text_area(t.get("interest_reason", "¿Por qué estás interesado en probar AIdeaText?"))
135
+
136
+ if st.button(t.get("submit_application", "Enviar solicitud")):
137
+ logger.info(f"Attempting to submit application for {email}")
138
+ logger.debug(f"Form data: name={name}, lastname={lastname}, email={email}, institution={institution}, current_role={current_role}, desired_role={desired_role}, reason={reason}")
139
+
140
+ if not name or not lastname or not email or not institution or not reason:
141
+ logger.warning("Incomplete form submission")
142
+ st.error(t.get("complete_all_fields", "Por favor, completa todos los campos."))
143
+ elif not is_institutional_email(email):
144
+ logger.warning(f"Non-institutional email used: {email}")
145
+ st.error(t.get("use_institutional_email", "Por favor, utiliza un correo electrónico institucional."))
146
+ else:
147
+ logger.info(f"Attempting to store application for {email}")
148
+ success = store_application_request(name, lastname, email, institution, current_role, desired_role, reason)
149
+ if success:
150
+ st.success(t.get("application_sent", "Tu solicitud ha sido enviada. Te contactaremos pronto."))
151
+ logger.info(f"Application request stored successfully for {email}")
152
+ else:
153
+ st.error(t.get("application_error", "Hubo un problema al enviar tu solicitud. Por favor, intenta de nuevo más tarde."))
154
+ logger.error(f"Failed to store application request for {email}")
155
+
156
+
157
+ #############################################################
158
+ #############################################################
159
+ def is_institutional_email(email):
160
+ forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
161
+ return not any(domain in email.lower() for domain in forbidden_domains)
162
+
163
+
164
+ #############################################################
165
+ #############################################################
166
+ def display_videos_and_info(lang_code, t):
167
+ # Crear tabs para cada sección
168
+ tab_use_case, tab_videos, tab_events, tab_gallery, tab_news = st.tabs([
169
+ "Casos de uso",
170
+ "Videos de presentaciones",
171
+ "Ponencias académicas",
172
+ "Fotos de eventos",
173
+ "Control de versiones"
174
+ ])
175
+
176
+ # Tab de Casos de uso
177
+ with tab_use_case:
178
+ use_case_videos = {
179
+ "English - Radar use chart": "https://youtu.be/fFbbtlIewgs",
180
+ "English - Use AI Bot and arcs charts fuctions": "https://youtu.be/XjM-1oOl-ao",
181
+ "English - Arcs use charts, example 1": "https://youtu.be/PdK_bgigVaM",
182
+ "English - Arcs use charts, excample 2": "https://youtu.be/7uaV1njPOng",
183
+ "Español - Uso del diagrama radar para verificar redacción": "https://www.youtube.com/watch?v=nJP6xscPLBU",
184
+ "Español - Uso de los diagramas de arco, ejemplo 1": "https://www.youtube.com/watch?v=ApBIAr2S-bE",
185
+ "Español - Uso de los diagramas de arco, ejemplo 2": "https://www.youtube.com/watch?v=JnP2U1Fm0rc",
186
+ "Español - Uso de los diagramas de arco, ejemplo 3": "https://www.youtube.com/watch?v=waWWwPTaI-Y",
187
+ "Español - Uso del bot para buscar respuestas" : "https://www.youtube.com/watch?v=GFKDS0K2s7E"
188
+ }
189
+
190
+ selected_title = st.selectbox("Selecciona un caso de uso en español o en inglés:", list(use_case_videos.keys()))
191
+ if selected_title in use_case_videos:
192
+ try:
193
+ st_player(use_case_videos[selected_title])
194
+ except Exception as e:
195
+ st.error(f"Error al cargar el video: {str(e)}")
196
+
197
+ # Tab de Videos
198
+ with tab_videos:
199
+ videos = {
200
+ "Reel AIdeaText": "https://youtu.be/hXnwUvN1Q9Q",
201
+ "Presentación en SENDA, UNAM. Ciudad de México, México" : "https://www.youtube.com/watch?v=XFLvjST2cE0",
202
+ "Presentación en PyCon 2024. Colombia, Medellín": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
203
+ "Presentación en la Fundación Ser Maaestro. Lima, Perú": "https://www.youtube.com/watch?v=imc4TI1q164",
204
+ "Presentación en el programa de incubación Explora del IFE, TEC de Monterrey, Nuevo León, México": "https://www.youtube.com/watch?v=Fqi4Di_Rj_s",
205
+ "Entrevista con el Dr. Guillermo Ruíz. Lima, Perú": "https://www.youtube.com/watch?v=_ch8cRja3oc",
206
+ "Demo de la versión de escritorio.": "https://www.youtube.com/watch?v=nP6eXbog-ZY"
207
+ }
208
+
209
+ selected_title = st.selectbox("Selecciona una conferencia:", list(videos.keys()))
210
+ if selected_title in videos:
211
+ try:
212
+ st_player(videos[selected_title])
213
+ except Exception as e:
214
+ st.error(f"Error al cargar el video: {str(e)}")
215
+
216
+ # Tab de Eventos
217
+ with tab_events:
218
+ st.markdown("""
219
+ ## 2025
220
+
221
+ **El Agente Cognitivo Vinculante como Innovación en el Aprendizaje Adaptativo: el caso de AIdeaText**
222
+ IFE CONFERENCE 2025. Organizado por el Instituto para el Futuro de la Educación del TEC de Monterrey.
223
+ Nuevo León, México. Del 28 al 30 enero 2025
224
+
225
+ ## 2024
226
+ [1]
227
+ AIdeaText, AIdeaText, recurso digital que emplea la técnica de Análisis de Resonancia Central para perfeccionar textos académicos**
228
+ V Temporada SENDA - Organizado por el Seminario de Entornos y Narrativas Digitales en la Academia del
229
+ Instituto de Investigaciones Antropológicas (IIA) de la Universidad Autonóma de México (UNAM). 22 noviembre 2024
230
+
231
+ [2]
232
+ Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
233
+ Congreso HeETI 2024: Horizontes Expandidos de la Educación, la Tecnología y la Innovación
234
+ Universidad el Claustro de Sor Juana. Del 25 al 27 septiembre 2024
235
+ [3]
236
+ AIdeaText, visualización de mapas semánticos**
237
+ PyCon 2024, Organizado por el grupo de desarrolladores independientes de Python.
238
+ Universidad EAFIT, Medellín, Colombia. Del 7 al 9 de junio de 2024.
239
+
240
+ ## 2023
241
+ **Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
242
+ [1]
243
+ XVII Congreso Nacional de Investigación Educativa - VII Encuentro de Estudiantes de Posgrado Educación.
244
+ Consejo Mexicano de Investigación Educativa (COMIE)
245
+ Villahermosa, Tabasco, México.
246
+ Del 4 al 8 de diciembre 2023
247
+ [2]
248
+ XXXI Encuentro Internacional de Educación a Distancia
249
+ Universidad de Guadalajara. Jalisco, México.
250
+ Del 27 al 30 noviembre 2023
251
+ [3]
252
+ IV Temporada SENDA - Seminario de Entornos y Narrativas Digitales en la Academia
253
+ Instituto de Investigaciones Antropológicas (IIA), UNAM.
254
+ 22 noviembre 2023
255
+ [4]
256
+ 1er Congreso Internacional de Educación Digital
257
+ Instituto Politécnico Nacional, sede Zacatecas. México.
258
+ Del 23 al 24 de noviembre de 2023
259
+
260
+ [5]
261
+ La cuestión de la centralidad del maestro frente a las tecnologías digitales generativas**
262
+ Innova Fórum: Ecosistemas de Aprendizaje
263
+ Universidad de Guadalajara. Jalisco, México.
264
+ Del 16 al 18 de mayo 2023
265
+ """)
266
+
267
+ # Tab de Galería
268
+ with tab_gallery:
269
+ # Contenedor con ancho máximo
270
+ with st.container():
271
+ # Dividimos en dos columnas principales
272
+ col_left, col_right = st.columns(2)
273
+
274
+ # Columna izquierda: Foto 1 grande
275
+ with col_left:
276
+ # Foto 2 arriba
277
+ st.image("assets/img/socialmedia/_MG_2845.JPG",
278
+ caption="MakerFaire CDMX 2024",
279
+ width=480) # Ajusta este valor según necesites
280
+ # use_column_width=True)
281
+
282
+ # Foto 3 abajo
283
+ st.image("assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg",
284
+ caption="MakerFaire CDMX 2024",
285
+ width=480) # Ajusta este valor según necesites
286
+ # use_column_width=True)
287
+
288
+ # Columna derecha: Fotos 2 y 3 una encima de otra
289
+ with col_right:
290
+ st.image("assets/img/socialmedia/_MG_2790.jpg",
291
+ caption="MakerFaire CDMX 2024",
292
+ width=540) # Ajusta este valor según necesites
293
+
294
+
295
+ # Tab de Novedades
296
+ with tab_news:
297
+ st.markdown("""
298
+ ### Novedades de la versión actual
299
+ - Interfaz mejorada para una mejor experiencia de usuario
300
+ - Optimización del análisis morfosintáctico
301
+ - Soporte para múltiples idiomas
302
+ - Nuevo módulo de análisis del discurso
303
+ - Sistema de chat integrado para soporte
304
+ """)
305
+
306
+ # Definición de __all__ para especificar qué se exporta
307
+ __all__ = ['main', 'login_register_page', 'initialize_session_state']
308
+
309
+ # Bloque de ejecución condicional
310
+ if __name__ == "__main__":
311
  main()
modules/ui/user_page.py CHANGED
@@ -1,349 +1,350 @@
1
- import streamlit as st
2
- import logging
3
- from datetime import datetime, timezone
4
- from dateutil.parser import parse
5
-
6
- # Configuración del logger
7
- logging.basicConfig(level=logging.INFO)
8
- logger = logging.getLogger(__name__)
9
-
10
- #Importaciones locales.
11
-
12
- from ..utils.widget_utils import generate_unique_key
13
- from session_state import initialize_session_state, logout
14
-
15
- from translations import get_translations
16
-
17
- from ..auth.auth import authenticate_user, authenticate_student, authenticate_admin
18
-
19
- from ..admin.admin_ui import admin_page
20
-
21
- from ..chatbot import display_sidebar_chat
22
-
23
- # Students activities
24
- from ..studentact.student_activities_v2 import display_student_activities
25
- from ..studentact.current_situation_interface import display_current_situation_interface
26
- from ..studentact.current_situation_analysis import analyze_text_dimensions
27
-
28
-
29
- ##Importaciones desde la configuración de bases datos #######
30
-
31
- from ..database.sql_db import (
32
- get_user,
33
- get_admin_user,
34
- get_student_user,
35
- get_teacher_user,
36
- create_user,
37
- create_student_user,
38
- create_teacher_user,
39
- create_admin_user,
40
- update_student_user, # Agregada
41
- delete_student_user, # Agregada
42
- record_login,
43
- record_logout,
44
- get_recent_sessions,
45
- get_user_total_time,
46
- store_application_request,
47
- store_student_feedback
48
- )
49
-
50
- from ..database.mongo_db import (
51
- get_collection,
52
- insert_document,
53
- find_documents,
54
- update_document,
55
- delete_document
56
- )
57
-
58
- from ..database.morphosintax_mongo_db import (
59
- store_student_morphosyntax_result,
60
- get_student_morphosyntax_analysis,
61
- update_student_morphosyntax_analysis,
62
- delete_student_morphosyntax_analysis,
63
- get_student_morphosyntax_data
64
- )
65
-
66
- from ..database.chat_mongo_db import store_chat_history, get_chat_history
67
-
68
- ##Importaciones desde los análisis #######
69
- from ..morphosyntax.morphosyntax_interface import (
70
- display_morphosyntax_interface,
71
- display_arc_diagram
72
- )
73
-
74
- from ..semantic.semantic_interface import (
75
- display_semantic_interface,
76
- display_semantic_results
77
- )
78
-
79
- from ..semantic.semantic_live_interface import display_semantic_live_interface
80
-
81
- from ..discourse.discourse_live_interface import display_discourse_live_interface
82
-
83
- from ..discourse.discourse_interface import ( # Agregar esta importación
84
- display_discourse_interface,
85
- display_discourse_results
86
- )
87
-
88
-
89
-
90
- ####################################################################################
91
- def user_page(lang_code, t):
92
- logger.info(f"Entrando en user_page para el estudiante: {st.session_state.username}")
93
-
94
- # Inicializar el tab seleccionado si no existe
95
- if 'selected_tab' not in st.session_state:
96
- st.session_state.selected_tab = 0
97
-
98
- # Inicializar el estado del análisis en vivo
99
- if 'semantic_live_active' not in st.session_state:
100
- st.session_state.semantic_live_active = False
101
-
102
- # Manejar la carga inicial de datos del usuario
103
- if 'user_data' not in st.session_state:
104
- with st.spinner(t.get('loading_data', "Cargando tus datos...")):
105
- try:
106
- st.session_state.user_data = get_student_morphosyntax_data(st.session_state.username)
107
- st.session_state.last_data_fetch = datetime.now(timezone.utc).isoformat()
108
- except Exception as e:
109
- logger.error(f"Error al obtener datos del usuario: {str(e)}")
110
- st.error(t.get('data_load_error', "Hubo un problema al cargar tus datos. Por favor, intenta recargar la página."))
111
- return
112
-
113
- logger.info(f"Idioma actual: {st.session_state.lang_code}")
114
- logger.info(f"Modelos NLP cargados: {'nlp_models' in st.session_state}")
115
-
116
- # Configuración de idiomas disponibles
117
- languages = {'Español': 'es', 'Português': 'pt', 'English': 'en', 'Français': 'fr'}
118
-
119
- # Estilos CSS personalizados
120
- st.markdown("""
121
- <style>
122
- .stSelectbox > div > div {
123
- padding-top: 0px;
124
- }
125
- .stButton > button {
126
- padding-top: 2px;
127
- margin-top: 0px;
128
- }
129
- div[data-testid="stHorizontalBlock"] > div:nth-child(3) {
130
- display: flex;
131
- justify-content: flex-end;
132
- align-items: center;
133
- }
134
- </style>
135
- """, unsafe_allow_html=True)
136
-
137
- # Barra superior con información del usuario y controles
138
- with st.container():
139
- col1, col2, col3 = st.columns([2, 2, 1])
140
- with col1:
141
- st.markdown(f"<h3 style='margin-bottom: 0; padding-top: 10px;'>{t['welcome']}, {st.session_state.username}</h3>",
142
- unsafe_allow_html=True)
143
- with col2:
144
- selected_lang = st.selectbox(
145
- t['select_language'],
146
- list(languages.keys()),
147
- index=list(languages.values()).index(st.session_state.lang_code),
148
- key=f"language_selector_{st.session_state.username}_{st.session_state.lang_code}"
149
- )
150
- new_lang_code = languages[selected_lang]
151
- if st.session_state.lang_code != new_lang_code:
152
- st.session_state.lang_code = new_lang_code
153
- st.rerun()
154
- with col3:
155
- if st.button(t['logout'],
156
- key=f"logout_button_{st.session_state.username}_{st.session_state.lang_code}"):
157
- st.session_state.clear()
158
- st.rerun()
159
-
160
- st.markdown("---")
161
-
162
- # Asegurarse de que tenemos las traducciones del chatbot
163
- chatbot_t = t.get('CHATBOT_TRANSLATIONS', {}).get(lang_code, {})
164
-
165
- # Mostrar chatbot en sidebar
166
- display_sidebar_chat(lang_code, chatbot_t)
167
-
168
- # Inicializar estados para todos los tabs
169
- if 'tab_states' not in st.session_state:
170
- st.session_state.tab_states = {
171
- 'current_situation_active': False,
172
- 'morpho_active': False,
173
- 'semantic_live_active': False,
174
- 'semantic_active': False,
175
- 'discourse_live_active': False,
176
- 'discourse_active': False,
177
- 'activities_active': False,
178
- 'feedback_active': False
179
- }
180
-
181
- # Sistema de tabs
182
- tab_names = [
183
- t.get('current_situation_tab', "Mi Situación Actual"),
184
- t.get('morpho_tab', 'Análisis Morfosintáctico'),
185
- t.get('semantic_live_tab', 'Análisis Semántico Vivo'),
186
- t.get('semantic_tab', 'Análisis Semántico'),
187
- t.get('discourse_live_tab', 'Análisis de Discurso Vivo'),
188
- t.get('discourse_tab', 'Análsis de Discurso'),
189
- t.get('activities_tab', 'Mis Actividades'),
190
- t.get('feedback_tab', 'Formulario de Comentarios')
191
- ]
192
-
193
- tabs = st.tabs(tab_names)
194
-
195
- # Manejar el contenido de cada tab
196
- for index, tab in enumerate(tabs):
197
- with tab:
198
- try:
199
- # Actualizar el tab seleccionado solo si no hay un análisis activo
200
- if tab.selected and st.session_state.selected_tab != index:
201
- can_switch = True
202
- for state_key in st.session_state.tab_states.keys():
203
- if st.session_state.tab_states[state_key] and index != get_tab_index(state_key):
204
- can_switch = False
205
- break
206
- if can_switch:
207
- st.session_state.selected_tab = index
208
-
209
- if index == 0: # Situación actual
210
- st.session_state.tab_states['current_situation_active'] = True
211
- display_current_situation_interface(
212
- st.session_state.lang_code,
213
- st.session_state.nlp_models,
214
- t # Pasamos todo el diccionario de traducciones
215
- )
216
-
217
- elif index == 1: # Morfosintáctico
218
- st.session_state.tab_states['morpho_active'] = True
219
- display_morphosyntax_interface(
220
- st.session_state.lang_code,
221
- st.session_state.nlp_models,
222
- t # Pasamos todo el diccionario de traducciones
223
- )
224
-
225
- elif index == 2: # Semántico Vivo
226
- st.session_state.tab_states['semantic_live_active'] = True
227
- display_semantic_live_interface(
228
- st.session_state.lang_code,
229
- st.session_state.nlp_models,
230
- t # Pasamos todo el diccionario de traducciones
231
- )
232
-
233
- elif index == 3: # Semántico
234
- st.session_state.tab_states['semantic_active'] = True
235
- display_semantic_interface(
236
- st.session_state.lang_code,
237
- st.session_state.nlp_models,
238
- t # Pasamos todo el diccionario de traducciones
239
- )
240
-
241
- elif index == 4: # Discurso Vivo
242
- st.session_state.tab_states['discourse_live_active'] = True
243
- display_discourse_live_interface(
244
- st.session_state.lang_code,
245
- st.session_state.nlp_models,
246
- t # Pasamos todo el diccionario de traducciones
247
- )
248
-
249
- elif index == 5: # Discurso
250
- st.session_state.tab_states['discourse_active'] = True
251
- display_discourse_interface(
252
- st.session_state.lang_code,
253
- st.session_state.nlp_models,
254
- t # Pasamos todo el diccionario de traducciones
255
- )
256
-
257
- elif index == 6: # Actividades
258
- st.session_state.tab_states['activities_active'] = True
259
- display_student_activities(
260
- username=st.session_state.username,
261
- lang_code=st.session_state.lang_code,
262
- t=t # Pasamos todo el diccionario de traducciones
263
- )
264
-
265
- elif index == 7: # Feedback
266
- st.session_state.tab_states['feedback_active'] = True
267
- display_feedback_form(
268
- st.session_state.lang_code,
269
- t # Ya estaba recibiendo el diccionario completo
270
- )
271
-
272
- except Exception as e:
273
- # Desactivar el estado en caso de error
274
- state_key = get_state_key_for_index(index)
275
- if state_key:
276
- st.session_state.tab_states[state_key] = False
277
- logger.error(f"Error en tab {index}: {str(e)}")
278
- st.error(t.get('tab_error', 'Error al cargar esta sección'))
279
-
280
- # Panel de depuración (solo visible en desarrollo)
281
- if st.session_state.get('debug_mode', False):
282
- with st.expander("Debug Info"):
283
- st.write(f"Página actual: {st.session_state.page}")
284
- st.write(f"Usuario: {st.session_state.get('username', 'No logueado')}")
285
- st.write(f"Rol: {st.session_state.get('role', 'No definido')}")
286
- st.write(f"Idioma: {st.session_state.lang_code}")
287
- st.write(f"Tab seleccionado: {st.session_state.selected_tab}")
288
- st.write(f"Última actualización de datos: {st.session_state.get('last_data_fetch', 'Nunca')}")
289
- st.write(f"Traducciones disponibles: {list(t.keys())}")
290
-
291
-
292
- def get_tab_index(state_key):
293
- """Obtiene el índice del tab basado en la clave de estado"""
294
- index_map = {
295
- 'current_situation_active': 0,
296
- 'morpho_active': 1,
297
- 'semantic_live_active': 2,
298
- 'semantic_active': 3,
299
- 'discourse_live_active': 4,
300
- 'discourse_active': 5,
301
- 'activities_active': 6,
302
- 'feedback_active': 7
303
- }
304
- return index_map.get(state_key, -1)
305
-
306
- def get_state_key_for_index(index):
307
- """Obtiene la clave de estado basada en el índice del tab"""
308
- state_map = {
309
- 0: 'current_situation_active',
310
- 1: 'morpho_active',
311
- 2: 'semantic_live_active',
312
- 3: 'semantic_active',
313
- 4: 'discourse_live_active',
314
- 5: 'discourse_active',
315
- 6: 'activities_active',
316
- 7: 'feedback_active'
317
- }
318
- return state_map.get(index)
319
-
320
- def display_feedback_form(lang_code, t):
321
- """
322
- Muestra el formulario de retroalimentación
323
- Args:
324
- lang_code: Código de idioma
325
- t: Diccionario de traducciones
326
- """
327
- logging.info(f"display_feedback_form called with lang_code: {lang_code}")
328
-
329
- # Obtener traducciones específicas para el formulario de feedback
330
- feedback_t = t.get('FEEDBACK', {})
331
-
332
- # Si no hay traducciones específicas, usar el diccionario general
333
- if not feedback_t:
334
- feedback_t = t
335
-
336
- st.header(feedback_t.get('feedback_title', 'Formulario de Opinión'))
337
-
338
- name = st.text_input(feedback_t.get('name', 'Nombre'))
339
- email = st.text_input(feedback_t.get('email', 'Correo electrónico'))
340
- feedback = st.text_area(feedback_t.get('feedback', 'Retroalimentación'))
341
-
342
- if st.button(feedback_t.get('submit', 'Enviar')):
343
- if name and email and feedback:
344
- if store_student_feedback(st.session_state.username, name, email, feedback):
345
- st.success(feedback_t.get('feedback_success', 'Gracias por tu respuesta'))
346
- else:
347
- st.error(feedback_t.get('feedback_error', 'Hubo un problema al enviar el formulario. Por favor, intenta de nuevo.'))
348
- else:
349
- st.warning(feedback_t.get('complete_all_fields', 'Por favor, completa todos los campos'))
 
 
1
+ import streamlit as st
2
+ import logging
3
+ from datetime import datetime, timezone
4
+ from dateutil.parser import parse
5
+
6
+ # Configuración del logger
7
+ logging.basicConfig(level=logging.INFO)
8
+ logger = logging.getLogger(__name__)
9
+
10
+ #Importaciones locales.
11
+
12
+ from ..utils.widget_utils import generate_unique_key
13
+ from session_state import initialize_session_state, logout
14
+
15
+ from translations import get_translations
16
+
17
+ from ..auth.auth import authenticate_user, authenticate_student, authenticate_admin
18
+
19
+ from ..admin.admin_ui import admin_page
20
+
21
+ from ..chatbot import display_sidebar_chat
22
+
23
+ # Students activities
24
+ from ..studentact.student_activities_v2 import display_student_activities
25
+ from ..studentact.current_situation_interface import display_current_situation_interface
26
+ from ..studentact.current_situation_analysis import analyze_text_dimensions
27
+
28
+
29
+ ##Importaciones desde la configuración de bases datos #######
30
+
31
+ from ..database.sql_db import (
32
+ get_user,
33
+ get_admin_user,
34
+ get_student_user,
35
+ get_teacher_user,
36
+ create_user,
37
+ create_student_user,
38
+ create_teacher_user,
39
+ create_admin_user,
40
+ update_student_user, # Agregada
41
+ delete_student_user, # Agregada
42
+ record_login,
43
+ record_logout,
44
+ get_recent_sessions,
45
+ get_user_total_time,
46
+ store_application_request,
47
+ store_student_feedback
48
+ )
49
+
50
+ from ..database.mongo_db import (
51
+ get_collection,
52
+ insert_document,
53
+ find_documents,
54
+ update_document,
55
+ delete_document
56
+ )
57
+
58
+ from ..database.morphosintax_mongo_db import (
59
+ store_student_morphosyntax_result,
60
+ get_student_morphosyntax_analysis,
61
+ update_student_morphosyntax_analysis,
62
+ delete_student_morphosyntax_analysis,
63
+ get_student_morphosyntax_data
64
+ )
65
+
66
+ from ..database.chat_mongo_db import store_chat_history, get_chat_history
67
+
68
+ ##Importaciones desde los análisis #######
69
+ from ..morphosyntax.morphosyntax_interface import (
70
+ display_morphosyntax_interface,
71
+ display_arc_diagram
72
+ )
73
+
74
+ from ..semantic.semantic_interface import (
75
+ display_semantic_interface,
76
+ display_semantic_results
77
+ )
78
+
79
+ from ..semantic.semantic_live_interface import display_semantic_live_interface
80
+
81
+ from ..discourse.discourse_live_interface import display_discourse_live_interface
82
+
83
+ from ..discourse.discourse_interface import ( # Agregar esta importación
84
+ display_discourse_interface,
85
+ display_discourse_results
86
+ )
87
+
88
+
89
+
90
+ ####################################################################################
91
+ def user_page(lang_code, t):
92
+ logger.info(f"Entrando en user_page para el estudiante: {st.session_state.username}")
93
+
94
+ # Inicializar el tab seleccionado si no existe
95
+ if 'selected_tab' not in st.session_state:
96
+ st.session_state.selected_tab = 0
97
+
98
+ # Inicializar el estado del análisis en vivo
99
+ if 'semantic_live_active' not in st.session_state:
100
+ st.session_state.semantic_live_active = False
101
+
102
+ # Manejar la carga inicial de datos del usuario
103
+ if 'user_data' not in st.session_state:
104
+ with st.spinner(t.get('loading_data', "Cargando tus datos...")):
105
+ try:
106
+ st.session_state.user_data = get_student_morphosyntax_data(st.session_state.username)
107
+ st.session_state.last_data_fetch = datetime.now(timezone.utc).isoformat()
108
+ except Exception as e:
109
+ logger.error(f"Error al obtener datos del usuario: {str(e)}")
110
+ st.error(t.get('data_load_error', "Hubo un problema al cargar tus datos. Por favor, intenta recargar la página."))
111
+ return
112
+
113
+ logger.info(f"Idioma actual: {st.session_state.lang_code}")
114
+ logger.info(f"Modelos NLP cargados: {'nlp_models' in st.session_state}")
115
+
116
+ # Configuración de idiomas disponibles
117
+ languages = {'Español': 'es', 'Português': 'pt', 'English': 'en', 'Français': 'fr'}
118
+
119
+ # Estilos CSS personalizados
120
+ st.markdown("""
121
+ <style>
122
+ .stSelectbox > div > div {
123
+ padding-top: 0px;
124
+ }
125
+ .stButton > button {
126
+ padding-top: 2px;
127
+ margin-top: 0px;
128
+ }
129
+ div[data-testid="stHorizontalBlock"] > div:nth-child(3) {
130
+ display: flex;
131
+ justify-content: flex-end;
132
+ align-items: center;
133
+ }
134
+ </style>
135
+ """, unsafe_allow_html=True)
136
+
137
+ # Barra superior con información del usuario y controles
138
+ with st.container():
139
+ col1, col2, col3 = st.columns([2, 2, 1])
140
+ with col1:
141
+ st.markdown(f"<h3 style='margin-bottom: 0; padding-top: 10px;'>{t['welcome']}, {st.session_state.username}</h3>",
142
+ unsafe_allow_html=True)
143
+ with col2:
144
+ selected_lang = st.selectbox(
145
+ t['select_language'],
146
+ list(languages.keys()),
147
+ index=list(languages.values()).index(st.session_state.lang_code),
148
+ key=f"language_selector_{st.session_state.username}_{st.session_state.lang_code}"
149
+ )
150
+ new_lang_code = languages[selected_lang]
151
+ if st.session_state.lang_code != new_lang_code:
152
+ st.session_state.lang_code = new_lang_code
153
+ st.rerun()
154
+ with col3:
155
+ if st.button(t['logout'],
156
+ key=f"logout_button_{st.session_state.username}_{st.session_state.lang_code}"):
157
+ st.session_state.clear()
158
+ st.rerun()
159
+
160
+ st.markdown("---")
161
+
162
+ # Asegurarse de que tenemos las traducciones del chatbot
163
+ chatbot_t = t.get('CHATBOT_TRANSLATIONS', {}).get(lang_code, {})
164
+
165
+ # Mostrar chatbot en sidebar
166
+ display_sidebar_chat(lang_code, chatbot_t)
167
+
168
+ # Inicializar estados para todos los tabs
169
+ if 'tab_states' not in st.session_state:
170
+ st.session_state.tab_states = {
171
+ 'current_situation_active': False,
172
+ 'morpho_active': False,
173
+ 'semantic_live_active': False,
174
+ 'semantic_active': False,
175
+ 'discourse_live_active': False,
176
+ 'discourse_active': False,
177
+ 'activities_active': False,
178
+ 'feedback_active': False
179
+ }
180
+
181
+ # Sistema de tabs
182
+ tab_names = [
183
+ t.get('current_situation_tab', "Mi Situación Actual"),
184
+ t.get('morpho_tab', 'Análisis Morfosintáctico'),
185
+ t.get('semantic_live_tab', 'Análisis Semántico Vivo'),
186
+ t.get('semantic_tab', 'Análisis Semántico'),
187
+ t.get('discourse_live_tab', 'Análisis de Discurso Vivo'),
188
+ t.get('discourse_tab', 'Análsis de Discurso'),
189
+ t.get('activities_tab', 'Mis Actividades'),
190
+ t.get('feedback_tab', 'Formulario de Comentarios')
191
+ ]
192
+
193
+ tabs = st.tabs(tab_names)
194
+
195
+ # Manejar el contenido de cada tab
196
+ for index, tab in enumerate(tabs):
197
+ with tab:
198
+ try:
199
+ # Actualizar el tab seleccionado solo si no hay un análisis activo
200
+ if tab.selected and st.session_state.selected_tab != index:
201
+ can_switch = True
202
+ for state_key in st.session_state.tab_states.keys():
203
+ if st.session_state.tab_states[state_key] and index != get_tab_index(state_key):
204
+ can_switch = False
205
+ break
206
+ if can_switch:
207
+ st.session_state.selected_tab = index
208
+
209
+ if index == 0: # Situación actual
210
+ st.session_state.tab_states['current_situation_active'] = True
211
+ display_current_situation_interface(
212
+ st.session_state.lang_code,
213
+ st.session_state.nlp_models,
214
+ t # Pasamos todo el diccionario de traducciones
215
+ )
216
+
217
+ elif index == 1: # Morfosintáctico
218
+ st.session_state.tab_states['morpho_active'] = True
219
+ display_morphosyntax_interface(
220
+ st.session_state.lang_code,
221
+ st.session_state.nlp_models,
222
+ t # Pasamos todo el diccionario de traducciones
223
+ )
224
+
225
+ elif index == 2: # Semántico Vivo
226
+ st.session_state.tab_states['semantic_live_active'] = True
227
+ display_semantic_live_interface(
228
+ st.session_state.lang_code,
229
+ st.session_state.nlp_models,
230
+ t # Pasamos todo el diccionario de traducciones
231
+ )
232
+
233
+ elif index == 3: # Semántico
234
+ st.session_state.tab_states['semantic_active'] = True
235
+ display_semantic_interface(
236
+ st.session_state.lang_code,
237
+ st.session_state.nlp_models,
238
+ t # Pasamos todo el diccionario de traducciones
239
+ )
240
+
241
+ elif index == 4: # Discurso Vivo
242
+ st.session_state.tab_states['discourse_live_active'] = True
243
+ display_discourse_live_interface(
244
+ st.session_state.lang_code,
245
+ st.session_state.nlp_models,
246
+ t # Pasamos todo el diccionario de traducciones
247
+ )
248
+
249
+ elif index == 5: # Discurso
250
+ st.session_state.tab_states['discourse_active'] = True
251
+ display_discourse_interface(
252
+ st.session_state.lang_code,
253
+ st.session_state.nlp_models,
254
+ t # Pasamos todo el diccionario de traducciones
255
+ )
256
+
257
+ elif index == 6: # Actividades
258
+ st.session_state.tab_states['activities_active'] = True
259
+ display_student_activities(
260
+ username=st.session_state.username,
261
+ lang_code=st.session_state.lang_code,
262
+ t=t # Pasamos todo el diccionario de traducciones
263
+ )
264
+
265
+ elif index == 7: # Feedback
266
+ st.session_state.tab_states['feedback_active'] = True
267
+ display_feedback_form(
268
+ st.session_state.lang_code,
269
+ t # Ya estaba recibiendo el diccionario completo
270
+ )
271
+
272
+ except Exception as e:
273
+ # Desactivar el estado en caso de error
274
+ state_key = get_state_key_for_index(index)
275
+ if state_key:
276
+ st.session_state.tab_states[state_key] = False
277
+ logger.error(f"Error en tab {index}: {str(e)}")
278
+ st.error(t.get('tab_error', 'Error al cargar esta sección'))
279
+
280
+ # Panel de depuración (solo visible en desarrollo)
281
+ if st.session_state.get('debug_mode', False):
282
+ with st.expander("Debug Info"):
283
+ st.write(f"Página actual: {st.session_state.page}")
284
+ st.write(f"Usuario: {st.session_state.get('username', 'No logueado')}")
285
+ st.write(f"Rol: {st.session_state.get('role', 'No definido')}")
286
+ st.write(f"Idioma: {st.session_state.lang_code}")
287
+ st.write(f"Tab seleccionado: {st.session_state.selected_tab}")
288
+ st.write(f"Última actualización de datos: {st.session_state.get('last_data_fetch', 'Nunca')}")
289
+ st.write(f"Traducciones disponibles: {list(t.keys())}")
290
+
291
+
292
+ def get_tab_index(state_key):
293
+ """Obtiene el índice del tab basado en la clave de estado"""
294
+ index_map = {
295
+ 'current_situation_active': 0,
296
+ 'morpho_active': 1,
297
+ 'semantic_live_active': 2,
298
+ 'semantic_active': 3,
299
+ 'discourse_live_active': 4,
300
+ 'discourse_active': 5,
301
+ 'activities_active': 6,
302
+ 'feedback_active': 7
303
+ }
304
+ return index_map.get(state_key, -1)
305
+
306
+ def get_state_key_for_index(index):
307
+ """Obtiene la clave de estado basada en el índice del tab"""
308
+ state_map = {
309
+ 0: 'current_situation_active',
310
+ 1: 'morpho_active',
311
+ 2: 'semantic_live_active',
312
+ 3: 'semantic_active',
313
+ 4: 'discourse_live_active',
314
+ 5: 'discourse_active',
315
+ 6: 'activities_active',
316
+ 7: 'feedback_active'
317
+ }
318
+ return state_map.get(index)
319
+
320
+ def display_feedback_form(lang_code, t):
321
+ """
322
+ Muestra el formulario de retroalimentación
323
+ Args:
324
+ lang_code: Código de idioma
325
+ t: Diccionario de traducciones
326
+ """
327
+ logging.info(f"display_feedback_form called with lang_code: {lang_code}")
328
+
329
+ # Obtener traducciones específicas para el formulario de feedback
330
+ feedback_t = t.get('FEEDBACK', {})
331
+
332
+ # Si no hay traducciones específicas, usar el diccionario general
333
+ if not feedback_t:
334
+ feedback_t = t
335
+
336
+ st.header(feedback_t.get('feedback_title', 'Formulario de Opinión'))
337
+
338
+ name = st.text_input(feedback_t.get('name', 'Nombre'))
339
+ email = st.text_input(feedback_t.get('email', 'Correo electrónico'))
340
+ feedback = st.text_area(feedback_t.get('feedback', 'Retroalimentación'))
341
+
342
+ if st.button(feedback_t.get('submit', 'Enviar')):
343
+ if name and email and feedback:
344
+ if store_student_feedback(st.session_state.username, name, email, feedback):
345
+ st.success(feedback_t.get('feedback_success', 'Gracias por tu respuesta'))
346
+ else:
347
+ st.error(feedback_t.get('feedback_error', 'Hubo un problema al enviar el formulario. Por favor, intenta de nuevo.'))
348
+ else:
349
+ st.warning(feedback_t.get('complete_all_fields', 'Por favor, completa todos los campos'))
350
+