AIdeaText commited on
Commit
640abf8
·
verified ·
1 Parent(s): 6879677

Upload 2 files

Browse files
Files changed (2) hide show
  1. modules/ui/ui.py +344 -344
  2. modules/ui/user_page.py +349 -350
modules/ui/ui.py CHANGED
@@ -1,345 +1,345 @@
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, get_landing_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
- # Obtener traducciones específicas para landing page
79
- landing_t = get_landing_translations(lang_code)
80
-
81
- # Language selection dropdown at the top
82
- languages = {'Español': 'es', 'English': 'en', 'Français': 'fr', 'Português': 'pt'}
83
-
84
- # Estilo personalizado para mejorar el espaciado y alineación
85
- st.markdown("""
86
- <style>
87
- div.row-widget.stHorizontalBlock {
88
- align-items: center;
89
- }
90
- </style>
91
- """, unsafe_allow_html=True)
92
-
93
- # Crear contenedor para logos y selector de idioma usando columnas de Streamlit
94
- col1, col2, col3, col4, col5 = st.columns([0.25, 0.25, 1, 1, 1])
95
-
96
- with col1:
97
- # Logo de ALPHA
98
- st.image("https://huggingface.co/spaces/AIdeaText/v3/resolve/main/assets/img/ALPHA_Startup%20Badges.png", width=100)
99
-
100
- with col2:
101
- # Logo de AIdeaText
102
- st.image("https://huggingface.co/spaces/AIdeaText/v3/resolve/main/assets/img/AIdeaText_Logo_vectores.png", width=100)
103
-
104
- with col5:
105
- # Selector de idioma
106
- selected_lang = st.selectbox(
107
- landing_t['select_language'],
108
- list(languages.keys()),
109
- index=list(languages.values()).index(lang_code),
110
- key=f"landing_language_selector_{lang_code}"
111
- )
112
- new_lang_code = languages[selected_lang]
113
- if lang_code != new_lang_code:
114
- st.session_state.lang_code = new_lang_code
115
- st.rerun()
116
-
117
- # Main content with columns
118
- left_column, right_column = st.columns([1, 3])
119
-
120
- with left_column:
121
- tab1, tab2 = st.tabs([landing_t['login'], landing_t['register']])
122
-
123
- with tab1:
124
- login_form(lang_code, landing_t)
125
-
126
- with tab2:
127
- register_form(lang_code, landing_t)
128
-
129
- with right_column:
130
- display_videos_and_info(lang_code, landing_t)
131
-
132
- #############################################################
133
- #############################################################
134
- def login_form(lang_code, landing_t):
135
- with st.form("login_form"):
136
- username = st.text_input(landing_t['email'])
137
- password = st.text_input(landing_t['password'], type="password")
138
- submit_button = st.form_submit_button(landing_t['login_button'])
139
-
140
- if submit_button:
141
- success, role = authenticate_user(username, password)
142
- if success:
143
- st.session_state.logged_in = True
144
- st.session_state.username = username
145
- st.session_state.role = role
146
- if role == 'Administrador':
147
- st.session_state.page = 'Admin'
148
- else:
149
- st.session_state.page = 'user'
150
- logger.info(f"Usuario autenticado: {username}, Rol: {role}")
151
- st.rerun()
152
- else:
153
- st.error(landing_t['invalid_credentials'])
154
-
155
-
156
- #############################################################
157
- #############################################################
158
- def register_form(lang_code, landing_t):
159
- name = st.text_input(landing_t['name'])
160
- lastname = st.text_input(landing_t['lastname'])
161
- institution = st.text_input(landing_t['institution'])
162
- current_role = st.selectbox(landing_t['current_role'],
163
- [landing_t['professor'], landing_t['student'], landing_t['administrative']])
164
-
165
- # Definimos el rol por defecto como estudiante
166
- desired_role = landing_t['student']
167
-
168
- email = st.text_input(landing_t['institutional_email'])
169
- reason = st.text_area(landing_t['interest_reason'])
170
-
171
- if st.button(landing_t['submit_application']):
172
- logger.info(f"Intentando enviar solicitud para {email}")
173
- logger.debug(f"Datos del formulario: name={name}, lastname={lastname}, email={email}, institution={institution}, current_role={current_role}, desired_role={desired_role}, reason={reason}")
174
-
175
- if not name or not lastname or not email or not institution or not reason:
176
- logger.warning("Envío de formulario incompleto")
177
- st.error(landing_t['complete_all_fields'])
178
- elif not is_institutional_email(email):
179
- logger.warning(f"Email no institucional utilizado: {email}")
180
- st.error(landing_t['use_institutional_email'])
181
- else:
182
- logger.info(f"Intentando almacenar solicitud para {email}")
183
- success = store_application_request(name, lastname, email, institution, current_role, desired_role, reason)
184
- if success:
185
- st.success(landing_t['application_sent'])
186
- logger.info(f"Solicitud almacenada exitosamente para {email}")
187
- else:
188
- st.error(landing_t['application_error'])
189
- logger.error(f"Error al almacenar solicitud para {email}")
190
-
191
-
192
- #############################################################
193
- #############################################################
194
- def is_institutional_email(email):
195
- forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
196
- return not any(domain in email.lower() for domain in forbidden_domains)
197
-
198
-
199
- #############################################################
200
- #############################################################
201
- def display_videos_and_info(lang_code, landing_t):
202
- # Crear tabs para cada sección
203
- tab_use_case, tab_videos, tab_events, tab_gallery, tab_news = st.tabs([
204
- landing_t['use_cases'],
205
- landing_t['presentation_videos'],
206
- landing_t['academic_presentations'],
207
- landing_t['event_photos'],
208
- landing_t['version_control']
209
- ])
210
-
211
- # Tab de Casos de uso
212
- with tab_use_case:
213
- use_case_videos = {
214
- "English - Radar use chart": "https://youtu.be/fFbbtlIewgs",
215
- "English - Use AI Bot and arcs charts fuctions": "https://youtu.be/XjM-1oOl-ao",
216
- "English - Arcs use charts, example 1": "https://youtu.be/PdK_bgigVaM",
217
- "English - Arcs use charts, excample 2": "https://youtu.be/7uaV1njPOng",
218
- "Español - Uso del diagrama radar para verificar redacción": "https://www.youtube.com/watch?v=nJP6xscPLBU",
219
- "Español - Uso de los diagramas de arco, ejemplo 1": "https://www.youtube.com/watch?v=ApBIAr2S-bE",
220
- "Español - Uso de los diagramas de arco, ejemplo 2": "https://www.youtube.com/watch?v=JnP2U1Fm0rc",
221
- "Español - Uso de los diagramas de arco, ejemplo 3": "https://www.youtube.com/watch?v=waWWwPTaI-Y",
222
- "Español - Uso del bot para buscar respuestas" : "https://www.youtube.com/watch?v=GFKDS0K2s7E"
223
- }
224
-
225
- selected_title = st.selectbox(landing_t['select_use_case'], list(use_case_videos.keys()))
226
- if selected_title in use_case_videos:
227
- try:
228
- st_player(use_case_videos[selected_title])
229
- except Exception as e:
230
- st.error(f"Error al cargar el video: {str(e)}")
231
-
232
- # Tab de Videos
233
- with tab_videos:
234
- videos = {
235
- "Reel AIdeaText": "https://youtu.be/hXnwUvN1Q9Q",
236
- "Presentación en SENDA, UNAM. Ciudad de México, México" : "https://www.youtube.com/watch?v=XFLvjST2cE0",
237
- "Presentación en PyCon 2024. Colombia, Medellín": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
238
- "Presentación en la Fundación Ser Maaestro. Lima, Perú": "https://www.youtube.com/watch?v=imc4TI1q164",
239
- "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",
240
- "Entrevista con el Dr. Guillermo Ruíz. Lima, Perú": "https://www.youtube.com/watch?v=_ch8cRja3oc",
241
- "Demo de la versión de escritorio.": "https://www.youtube.com/watch?v=nP6eXbog-ZY"
242
- }
243
-
244
- selected_title = st.selectbox(landing_t['select_presentation'], list(videos.keys()))
245
- if selected_title in videos:
246
- try:
247
- st_player(videos[selected_title])
248
- except Exception as e:
249
- st.error(f"Error al cargar el video: {str(e)}")
250
-
251
- # Tab de Eventos
252
- with tab_events:
253
- st.markdown("""
254
- ## 2025
255
-
256
- **El Agente Cognitivo Vinculante como Innovación en el Aprendizaje Adaptativo: el caso de AIdeaText**
257
- IFE CONFERENCE 2025. Organizado por el Instituto para el Futuro de la Educación del TEC de Monterrey.
258
- Nuevo León, México. Del 28 al 30 enero 2025
259
-
260
- ## 2024
261
- [1]
262
- AIdeaText, AIdeaText, recurso digital que emplea la técnica de Análisis de Resonancia Central para perfeccionar textos académicos**
263
- V Temporada SENDA - Organizado por el Seminario de Entornos y Narrativas Digitales en la Academia del
264
- Instituto de Investigaciones Antropológicas (IIA) de la Universidad Autonóma de México (UNAM). 22 noviembre 2024
265
-
266
- [2]
267
- Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
268
- Congreso HeETI 2024: Horizontes Expandidos de la Educación, la Tecnología y la Innovación
269
- Universidad el Claustro de Sor Juana. Del 25 al 27 septiembre 2024
270
-
271
- [3]
272
- AIdeaText, visualización de mapas semánticos**
273
- PyCon 2024, Organizado por el grupo de desarrolladores independientes de Python.
274
- Universidad EAFIT, Medellín, Colombia. Del 7 al 9 de junio de 2024.
275
-
276
- ## 2023
277
- **Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
278
- [1]
279
- XVII Congreso Nacional de Investigación Educativa - VII Encuentro de Estudiantes de Posgrado Educación.
280
- Consejo Mexicano de Investigación Educativa (COMIE)
281
- Villahermosa, Tabasco, México.
282
- Del 4 al 8 de diciembre 2023
283
-
284
- [2]
285
- XXXI Encuentro Internacional de Educación a Distancia
286
- Universidad de Guadalajara. Jalisco, México.
287
- Del 27 al 30 noviembre 2023
288
-
289
- [3]
290
- IV Temporada SENDA - Seminario de Entornos y Narrativas Digitales en la Academia
291
- Instituto de Investigaciones Antropológicas (IIA), UNAM.
292
- 22 noviembre 2023
293
-
294
- [4]
295
- 1er Congreso Internacional de Educación Digital
296
- Instituto Politécnico Nacional, sede Zacatecas. México.
297
- Del 23 al 24 de noviembre de 2023
298
-
299
- [5]
300
- La cuestión de la centralidad del maestro frente a las tecnologías digitales generativas**
301
- Innova Fórum: Ecosistemas de Aprendizaje
302
- Universidad de Guadalajara. Jalisco, México.
303
- Del 16 al 18 de mayo 2023
304
- """)
305
-
306
- # Tab de Galería
307
- with tab_gallery:
308
- # Contenedor con ancho máximo
309
- with st.container():
310
- # Dividimos en dos columnas principales
311
- col_left, col_right = st.columns(2)
312
-
313
- # Columna izquierda: Foto 1 grande
314
- with col_left:
315
- # Foto 2 arriba
316
- st.image("assets/img/socialmedia/_MG_2845.JPG",
317
- caption="MakerFaire CDMX 2024",
318
- width=480) # Ajusta este valor según necesites
319
- # use_column_width=True)
320
-
321
- # Foto 3 abajo
322
- st.image("assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg",
323
- caption="MakerFaire CDMX 2024",
324
- width=480) # Ajusta este valor según necesites
325
- # use_column_width=True)
326
-
327
- # Columna derecha: Fotos 2 y 3 una encima de otra
328
- with col_right:
329
- st.image("assets/img/socialmedia/_MG_2790.jpg",
330
- caption="MakerFaire CDMX 2024",
331
- width=540) # Ajusta este valor según necesites
332
-
333
-
334
- # Tab de Novedades - Usar contenido traducido
335
- with tab_news:
336
- st.markdown(f"### {landing_t['latest_version_title']}")
337
- for update in landing_t['version_updates']:
338
- st.markdown(f"- {update}")
339
-
340
- # Definición de __all__ para especificar qué se exporta
341
- __all__ = ['main', 'login_register_page', 'initialize_session_state']
342
-
343
- # Bloque de ejecución condicional
344
- if __name__ == "__main__":
345
  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, get_landing_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
+ # Obtener traducciones específicas para landing page
79
+ landing_t = get_landing_translations(lang_code)
80
+
81
+ # Language selection dropdown at the top
82
+ languages = {'Español': 'es', 'English': 'en', 'Français': 'fr', 'Português': 'pt'}
83
+
84
+ # Estilo personalizado para mejorar el espaciado y alineación
85
+ st.markdown("""
86
+ <style>
87
+ div.row-widget.stHorizontalBlock {
88
+ align-items: center;
89
+ }
90
+ </style>
91
+ """, unsafe_allow_html=True)
92
+
93
+ # Crear contenedor para logos y selector de idioma usando columnas de Streamlit
94
+ col1, col2, col3, col4, col5 = st.columns([0.25, 0.25, 1, 1, 1])
95
+
96
+ with col1:
97
+ # Logo de ALPHA
98
+ st.image("https://huggingface.co/spaces/AIdeaText/v3/resolve/main/assets/img/ALPHA_Startup%20Badges.png", width=100)
99
+
100
+ with col2:
101
+ # Logo de AIdeaText
102
+ st.image("https://huggingface.co/spaces/AIdeaText/v3/resolve/main/assets/img/AIdeaText_Logo_vectores.png", width=100)
103
+
104
+ with col5:
105
+ # Selector de idioma
106
+ selected_lang = st.selectbox(
107
+ landing_t['select_language'],
108
+ list(languages.keys()),
109
+ index=list(languages.values()).index(lang_code),
110
+ key=f"landing_language_selector_{lang_code}"
111
+ )
112
+ new_lang_code = languages[selected_lang]
113
+ if lang_code != new_lang_code:
114
+ st.session_state.lang_code = new_lang_code
115
+ st.rerun()
116
+
117
+ # Main content with columns
118
+ left_column, right_column = st.columns([1, 3])
119
+
120
+ with left_column:
121
+ tab1, tab2 = st.tabs([landing_t['login'], landing_t['register']])
122
+
123
+ with tab1:
124
+ login_form(lang_code, landing_t)
125
+
126
+ with tab2:
127
+ register_form(lang_code, landing_t)
128
+
129
+ with right_column:
130
+ display_videos_and_info(lang_code, landing_t)
131
+
132
+ #############################################################
133
+ #############################################################
134
+ def login_form(lang_code, landing_t):
135
+ with st.form("login_form"):
136
+ username = st.text_input(landing_t['email'])
137
+ password = st.text_input(landing_t['password'], type="password")
138
+ submit_button = st.form_submit_button(landing_t['login_button'])
139
+
140
+ if submit_button:
141
+ success, role = authenticate_user(username, password)
142
+ if success:
143
+ st.session_state.logged_in = True
144
+ st.session_state.username = username
145
+ st.session_state.role = role
146
+ if role == 'Administrador':
147
+ st.session_state.page = 'Admin'
148
+ else:
149
+ st.session_state.page = 'user'
150
+ logger.info(f"Usuario autenticado: {username}, Rol: {role}")
151
+ st.rerun()
152
+ else:
153
+ st.error(landing_t['invalid_credentials'])
154
+
155
+
156
+ #############################################################
157
+ #############################################################
158
+ def register_form(lang_code, landing_t):
159
+ name = st.text_input(landing_t['name'])
160
+ lastname = st.text_input(landing_t['lastname'])
161
+ institution = st.text_input(landing_t['institution'])
162
+ current_role = st.selectbox(landing_t['current_role'],
163
+ [landing_t['professor'], landing_t['student'], landing_t['administrative']])
164
+
165
+ # Definimos el rol por defecto como estudiante
166
+ desired_role = landing_t['student']
167
+
168
+ email = st.text_input(landing_t['institutional_email'])
169
+ reason = st.text_area(landing_t['interest_reason'])
170
+
171
+ if st.button(landing_t['submit_application']):
172
+ logger.info(f"Intentando enviar solicitud para {email}")
173
+ logger.debug(f"Datos del formulario: name={name}, lastname={lastname}, email={email}, institution={institution}, current_role={current_role}, desired_role={desired_role}, reason={reason}")
174
+
175
+ if not name or not lastname or not email or not institution or not reason:
176
+ logger.warning("Envío de formulario incompleto")
177
+ st.error(landing_t['complete_all_fields'])
178
+ elif not is_institutional_email(email):
179
+ logger.warning(f"Email no institucional utilizado: {email}")
180
+ st.error(landing_t['use_institutional_email'])
181
+ else:
182
+ logger.info(f"Intentando almacenar solicitud para {email}")
183
+ success = store_application_request(name, lastname, email, institution, current_role, desired_role, reason)
184
+ if success:
185
+ st.success(landing_t['application_sent'])
186
+ logger.info(f"Solicitud almacenada exitosamente para {email}")
187
+ else:
188
+ st.error(landing_t['application_error'])
189
+ logger.error(f"Error al almacenar solicitud para {email}")
190
+
191
+
192
+ #############################################################
193
+ #############################################################
194
+ def is_institutional_email(email):
195
+ forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
196
+ return not any(domain in email.lower() for domain in forbidden_domains)
197
+
198
+
199
+ #############################################################
200
+ #############################################################
201
+ def display_videos_and_info(lang_code, landing_t):
202
+ # Crear tabs para cada sección
203
+ tab_use_case, tab_videos, tab_events, tab_gallery, tab_news = st.tabs([
204
+ landing_t['use_cases'],
205
+ landing_t['presentation_videos'],
206
+ landing_t['academic_presentations'],
207
+ landing_t['event_photos'],
208
+ landing_t['version_control']
209
+ ])
210
+
211
+ # Tab de Casos de uso
212
+ with tab_use_case:
213
+ use_case_videos = {
214
+ "English - Radar use chart": "https://youtu.be/fFbbtlIewgs",
215
+ "English - Use AI Bot and arcs charts fuctions": "https://youtu.be/XjM-1oOl-ao",
216
+ "English - Arcs use charts, example 1": "https://youtu.be/PdK_bgigVaM",
217
+ "English - Arcs use charts, excample 2": "https://youtu.be/7uaV1njPOng",
218
+ "Español - Uso del diagrama radar para verificar redacción": "https://www.youtube.com/watch?v=nJP6xscPLBU",
219
+ "Español - Uso de los diagramas de arco, ejemplo 1": "https://www.youtube.com/watch?v=ApBIAr2S-bE",
220
+ "Español - Uso de los diagramas de arco, ejemplo 2": "https://www.youtube.com/watch?v=JnP2U1Fm0rc",
221
+ "Español - Uso de los diagramas de arco, ejemplo 3": "https://www.youtube.com/watch?v=waWWwPTaI-Y",
222
+ "Español - Uso del bot para buscar respuestas" : "https://www.youtube.com/watch?v=GFKDS0K2s7E"
223
+ }
224
+
225
+ selected_title = st.selectbox(landing_t['select_use_case'], list(use_case_videos.keys()))
226
+ if selected_title in use_case_videos:
227
+ try:
228
+ st_player(use_case_videos[selected_title])
229
+ except Exception as e:
230
+ st.error(f"Error al cargar el video: {str(e)}")
231
+
232
+ # Tab de Videos
233
+ with tab_videos:
234
+ videos = {
235
+ "Reel AIdeaText": "https://youtu.be/hXnwUvN1Q9Q",
236
+ "Presentación en SENDA, UNAM. Ciudad de México, México" : "https://www.youtube.com/watch?v=XFLvjST2cE0",
237
+ "Presentación en PyCon 2024. Colombia, Medellín": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
238
+ "Presentación en Fundación Ser Maaestro. Lima, Perú": "https://www.youtube.com/watch?v=imc4TI1q164",
239
+ "Presentación en Explora del IFE, TEC de Monterrey, Nuevo León, México": "https://www.youtube.com/watch?v=Fqi4Di_Rj_s",
240
+ "Entrevista con el Dr. Guillermo Ruíz. Lima, Perú": "https://www.youtube.com/watch?v=_ch8cRja3oc",
241
+ "Demo de la versión de escritorio.": "https://www.youtube.com/watch?v=nP6eXbog-ZY"
242
+ }
243
+
244
+ selected_title = st.selectbox(landing_t['select_presentation'], list(videos.keys()))
245
+ if selected_title in videos:
246
+ try:
247
+ st_player(videos[selected_title])
248
+ except Exception as e:
249
+ st.error(f"Error al cargar el video: {str(e)}")
250
+
251
+ # Tab de Eventos
252
+ with tab_events:
253
+ st.markdown("""
254
+ ## 2025
255
+
256
+ **El Agente Cognitivo Vinculante como Innovación en el Aprendizaje Adaptativo: el caso de AIdeaText**
257
+ IFE CONFERENCE 2025. Organizado por el Instituto para el Futuro de la Educación del TEC de Monterrey.
258
+ Nuevo León, México. Del 28 al 30 enero 2025
259
+
260
+ ## 2024
261
+ [1]
262
+ AIdeaText, AIdeaText, recurso digital que emplea la técnica de Análisis de Resonancia Central para perfeccionar textos académicos**
263
+ V Temporada SENDA - Organizado por el Seminario de Entornos y Narrativas Digitales en la Academia del
264
+ Instituto de Investigaciones Antropológicas (IIA) de la Universidad Autonóma de México (UNAM). 22 noviembre 2024
265
+
266
+ [2]
267
+ Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
268
+ Congreso HeETI 2024: Horizontes Expandidos de la Educación, la Tecnología y la Innovación
269
+ Universidad el Claustro de Sor Juana. Del 25 al 27 septiembre 2024
270
+
271
+ [3]
272
+ AIdeaText, visualización de mapas semánticos**
273
+ PyCon 2024, Organizado por el grupo de desarrolladores independientes de Python.
274
+ Universidad EAFIT, Medellín, Colombia. Del 7 al 9 de junio de 2024.
275
+
276
+ ## 2023
277
+ **Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
278
+ [1]
279
+ XVII Congreso Nacional de Investigación Educativa - VII Encuentro de Estudiantes de Posgrado Educación.
280
+ Consejo Mexicano de Investigación Educativa (COMIE)
281
+ Villahermosa, Tabasco, México.
282
+ Del 4 al 8 de diciembre 2023
283
+
284
+ [2]
285
+ XXXI Encuentro Internacional de Educación a Distancia
286
+ Universidad de Guadalajara. Jalisco, México.
287
+ Del 27 al 30 noviembre 2023
288
+
289
+ [3]
290
+ IV Temporada SENDA - Seminario de Entornos y Narrativas Digitales en la Academia
291
+ Instituto de Investigaciones Antropológicas (IIA), UNAM.
292
+ 22 noviembre 2023
293
+
294
+ [4]
295
+ 1er Congreso Internacional de Educación Digital
296
+ Instituto Politécnico Nacional, sede Zacatecas. México.
297
+ Del 23 al 24 de noviembre de 2023
298
+
299
+ [5]
300
+ La cuestión de la centralidad del maestro frente a las tecnologías digitales generativas**
301
+ Innova Fórum: Ecosistemas de Aprendizaje
302
+ Universidad de Guadalajara. Jalisco, México.
303
+ Del 16 al 18 de mayo 2023
304
+ """)
305
+
306
+ # Tab de Galería
307
+ with tab_gallery:
308
+ # Contenedor con ancho máximo
309
+ with st.container():
310
+ # Dividimos en dos columnas principales
311
+ col_left, col_right = st.columns(2)
312
+
313
+ # Columna izquierda: Foto 1 grande
314
+ with col_left:
315
+ # Foto 2 arriba
316
+ st.image("assets/img/socialmedia/_MG_2845.JPG",
317
+ caption="MakerFaire CDMX 2024",
318
+ width=480) # Ajusta este valor según necesites
319
+ # use_column_width=True)
320
+
321
+ # Foto 3 abajo
322
+ st.image("assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg",
323
+ caption="MakerFaire CDMX 2024",
324
+ width=480) # Ajusta este valor según necesites
325
+ # use_column_width=True)
326
+
327
+ # Columna derecha: Fotos 2 y 3 una encima de otra
328
+ with col_right:
329
+ st.image("assets/img/socialmedia/_MG_2790.jpg",
330
+ caption="MakerFaire CDMX 2024",
331
+ width=540) # Ajusta este valor según necesites
332
+
333
+
334
+ # Tab de Novedades - Usar contenido traducido
335
+ with tab_news:
336
+ st.markdown(f"### {landing_t['latest_version_title']}")
337
+ for update in landing_t['version_updates']:
338
+ st.markdown(f"- {update}")
339
+
340
+ # Definición de __all__ para especificar qué se exporta
341
+ __all__ = ['main', 'login_register_page', 'initialize_session_state']
342
+
343
+ # Bloque de ejecución condicional
344
+ if __name__ == "__main__":
345
  main()
modules/ui/user_page.py CHANGED
@@ -1,350 +1,349 @@
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
-
 
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', 'English': 'en', 'Français': 'fr', 'Português': 'pt'}
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álisis comparado de textos'),
189
+ t.get('activities_tab', 'Registro de 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 == 2: # 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 == 3: # 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 == 4: # 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 == 5: # 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': 2,
299
+ #'discourse_live_active': 4,
300
+ 'discourse_active': 3,
301
+ 'activities_active': 4,
302
+ 'feedback_active': 5
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
+ 2: 'semantic_active',
313
+ #4: 'discourse_live_active',
314
+ 3: 'discourse_active',
315
+ 4: 'activities_active',
316
+ 5: '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'))