AIdeaText commited on
Commit
f8caf6d
·
verified ·
2 Parent(s): b8628a8 76a6879

Merge branch #AIdeaText/v5Dev' into 'AIdeaText/v5Prod'

Browse files
.gitattributes CHANGED
@@ -66,3 +66,4 @@ assets/img/socialmedia/AIdeaTextCard.jpg filter=lfs diff=lfs merge=lfs -text
66
  assets/img/socialmedia/Facebook_CoverPhoto_820x312.jpg filter=lfs diff=lfs merge=lfs -text
67
  assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg filter=lfs diff=lfs merge=lfs -text
68
  assets/img/socialmedia/WebSummit[[:space:]]ShowCase[[:space:]]2025.png filter=lfs diff=lfs merge=lfs -text
 
 
66
  assets/img/socialmedia/Facebook_CoverPhoto_820x312.jpg filter=lfs diff=lfs merge=lfs -text
67
  assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg filter=lfs diff=lfs merge=lfs -text
68
  assets/img/socialmedia/WebSummit[[:space:]]ShowCase[[:space:]]2025.png filter=lfs diff=lfs merge=lfs -text
69
+ assets/img/WebSummit[[:space:]]ShowCase[[:space:]]2025.png filter=lfs diff=lfs merge=lfs -text
assets/img/WebSummit ShowCase 2025.png ADDED

Git LFS Details

  • SHA256: b4ec62af719f04f7441ff508e5350b15f4afab2c34fd396cb273f2cb08370247
  • Pointer size: 132 Bytes
  • Size of remote file: 1.02 MB
modules/ui/ui.py CHANGED
@@ -1,342 +1,447 @@
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
- # Configura el logger PRIMERO, antes de cualquier uso
9
- logging.basicConfig(level=logging.INFO)
10
- logger = logging.getLogger(__name__)
11
-
12
- # Importaciones locales
13
- from session_state import initialize_session_state, logout
14
- from translations import get_translations, get_landing_translations
15
- from ..auth.auth import authenticate_user, authenticate_student, authenticate_admin
16
- from ..database.sql_db import store_application_request
17
-
18
- # Intento de importación con logger YA DEFINIDO
19
- try:
20
- from .user_page import user_page
21
- except ImportError as e:
22
- logger.error(f"No se pudo importar user_page: {str(e)}. Asegúrate de que el archivo existe.")
23
-
24
- # Función de respaldo
25
- def user_page(lang_code, t):
26
- st.error("La página de usuario no está disponible. Por favor, contacta al administrador.")
27
-
28
- from ..admin.admin_ui import admin_page
29
-
30
- #############################################################
31
- def main():
32
- logger.info(f"Entrando en main() - Página actual: {st.session_state.page}")
33
-
34
- if 'nlp_models' not in st.session_state:
35
- logger.error("Los modelos NLP no están inicializados.")
36
- st.error("Los modelos NLP no están inicializados. Por favor, reinicie la aplicación.")
37
- return
38
-
39
- lang_code = st.session_state.get('lang_code', 'es')
40
- t = get_translations(lang_code)
41
-
42
- logger.info(f"Página actual antes de la lógica de enrutamiento: {st.session_state.page}")
43
-
44
- if st.session_state.get('logged_out', False):
45
- st.session_state.logged_out = False
46
- st.session_state.page = 'login'
47
- st.rerun()
48
-
49
- if not st.session_state.get('logged_in', False):
50
- logger.info("Usuario no ha iniciado sesión. Mostrando página de login/registro")
51
- login_register_page(lang_code, t)
52
- elif st.session_state.page == 'user':
53
- if st.session_state.role == 'Administrador':
54
- logger.info("Redirigiendo a la página de administrador")
55
- st.session_state.page = 'Admin'
56
- st.rerun()
57
- else:
58
- logger.info("Renderizando página de usuario")
59
- user_page(lang_code, t)
60
- elif st.session_state.page == "Admin":
61
- logger.info("Renderizando página de administrador")
62
- admin_page()
63
- else:
64
- logger.error(f"Página no reconocida: {st.session_state.page}")
65
- st.error(t.get('unrecognized_page', 'Página no reconocida'))
66
- # Redirigir a la página de usuario en caso de error
67
- st.session_state.page = 'user'
68
- st.rerun()
69
-
70
- logger.info(f"Saliendo de main() - Estado final de la sesión: {st.session_state}")
71
-
72
- #############################################################
73
- #############################################################
74
- def login_register_page(lang_code, t):
75
- # Obtener traducciones específicas para landing page
76
- landing_t = get_landing_translations(lang_code)
77
-
78
- # Language selection dropdown at the top
79
- languages = {'Español': 'es', 'English': 'en', 'Français': 'fr', 'Português': 'pt'}
80
-
81
- # Estilo personalizado para mejorar el espaciado y alineación
82
- st.markdown("""
83
- <style>
84
- div.row-widget.stHorizontalBlock {
85
- align-items: center;
86
- }
87
- </style>
88
- """, unsafe_allow_html=True)
89
-
90
- # Crear contenedor para logos y selector de idioma usando columnas de Streamlit
91
- col1, col2, col3, col4, col5 = st.columns([0.25, 0.25, 1, 1, 1])
92
-
93
- with col1:
94
- # Logo de ALPHA
95
- st.image("https://huggingface.co/spaces/AIdeaText/v3/resolve/main/assets/img/ALPHA_Startup%20Badges.png", width=100)
96
-
97
- with col2:
98
- # Logo de AIdeaText
99
- st.image("https://huggingface.co/spaces/AIdeaText/v3/resolve/main/assets/img/AIdeaText_Logo_vectores.png", width=100)
100
-
101
- with col5:
102
- # Selector de idioma
103
- selected_lang = st.selectbox(
104
- landing_t['select_language'],
105
- list(languages.keys()),
106
- index=list(languages.values()).index(lang_code),
107
- key=f"landing_language_selector_{lang_code}"
108
- )
109
- new_lang_code = languages[selected_lang]
110
- if lang_code != new_lang_code:
111
- st.session_state.lang_code = new_lang_code
112
- st.rerun()
113
-
114
- # Main content with columns
115
- left_column, right_column = st.columns([1, 3])
116
-
117
- with left_column:
118
- tab1, tab2 = st.tabs([landing_t['login'], landing_t['register']])
119
-
120
- with tab1:
121
- login_form(lang_code, landing_t)
122
-
123
- with tab2:
124
- register_form(lang_code, landing_t)
125
-
126
- with right_column:
127
- display_videos_and_info(lang_code, landing_t)
128
-
129
- #############################################################
130
- #############################################################
131
- def login_form(lang_code, landing_t):
132
- with st.form("login_form"):
133
- username = st.text_input(landing_t['email'])
134
- password = st.text_input(landing_t['password'], type="password")
135
- submit_button = st.form_submit_button(landing_t['login_button'])
136
-
137
- if submit_button:
138
- success, role = authenticate_user(username, password)
139
- if success:
140
- st.session_state.logged_in = True
141
- st.session_state.username = username
142
- st.session_state.role = role
143
- if role == 'Administrador':
144
- st.session_state.page = 'Admin'
145
- else:
146
- st.session_state.page = 'user'
147
- logger.info(f"Usuario autenticado: {username}, Rol: {role}")
148
- st.rerun()
149
- else:
150
- st.error(landing_t['invalid_credentials'])
151
-
152
-
153
- #############################################################
154
- #############################################################
155
- def register_form(lang_code, landing_t):
156
- name = st.text_input(landing_t['name'])
157
- lastname = st.text_input(landing_t['lastname'])
158
- institution = st.text_input(landing_t['institution'])
159
- current_role = st.selectbox(landing_t['current_role'],
160
- [landing_t['professor'], landing_t['student'], landing_t['administrative']])
161
-
162
- # Definimos el rol por defecto como estudiante
163
- desired_role = landing_t['student']
164
-
165
- email = st.text_input(landing_t['institutional_email'])
166
- reason = st.text_area(landing_t['interest_reason'])
167
-
168
- if st.button(landing_t['submit_application']):
169
- logger.info(f"Intentando enviar solicitud para {email}")
170
- logger.debug(f"Datos del formulario: name={name}, lastname={lastname}, email={email}, institution={institution}, current_role={current_role}, desired_role={desired_role}, reason={reason}")
171
-
172
- if not name or not lastname or not email or not institution or not reason:
173
- logger.warning("Envío de formulario incompleto")
174
- st.error(landing_t['complete_all_fields'])
175
- elif not is_institutional_email(email):
176
- logger.warning(f"Email no institucional utilizado: {email}")
177
- st.error(landing_t['use_institutional_email'])
178
- else:
179
- logger.info(f"Intentando almacenar solicitud para {email}")
180
- success = store_application_request(name, lastname, email, institution, current_role, desired_role, reason)
181
- if success:
182
- st.success(landing_t['application_sent'])
183
- logger.info(f"Solicitud almacenada exitosamente para {email}")
184
- else:
185
- st.error(landing_t['application_error'])
186
- logger.error(f"Error al almacenar solicitud para {email}")
187
-
188
-
189
- #############################################################
190
- #############################################################
191
- def is_institutional_email(email):
192
- forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
193
- return not any(domain in email.lower() for domain in forbidden_domains)
194
-
195
-
196
- #############################################################
197
- #############################################################
198
- def display_videos_and_info(lang_code, landing_t):
199
- # Crear tabs para cada sección
200
- tab_use_case, tab_videos, tab_events, tab_gallery, tab_news = st.tabs([
201
- landing_t['use_cases'],
202
- landing_t['presentation_videos'],
203
- landing_t['academic_presentations'],
204
- landing_t['event_photos'],
205
- landing_t['version_control']
206
- ])
207
-
208
- # Tab de Casos de uso
209
- with tab_use_case:
210
- use_case_videos = {
211
- "English - Radar use chart": "https://youtu.be/fFbbtlIewgs",
212
- "English - Use AI Bot and arcs charts fuctions": "https://youtu.be/XjM-1oOl-ao",
213
- "English - Arcs use charts, example 1": "https://youtu.be/PdK_bgigVaM",
214
- "English - Arcs use charts, excample 2": "https://youtu.be/7uaV1njPOng",
215
- "Español - Uso del diagrama radar para verificar redacción": "https://www.youtube.com/watch?v=nJP6xscPLBU",
216
- "Español - Uso de los diagramas de arco, ejemplo 1": "https://www.youtube.com/watch?v=ApBIAr2S-bE",
217
- "Español - Uso de los diagramas de arco, ejemplo 2": "https://www.youtube.com/watch?v=JnP2U1Fm0rc",
218
- "Español - Uso de los diagramas de arco, ejemplo 3": "https://www.youtube.com/watch?v=waWWwPTaI-Y",
219
- "Español - Uso del bot para buscar respuestas" : "https://www.youtube.com/watch?v=GFKDS0K2s7E"
220
- }
221
-
222
- selected_title = st.selectbox(landing_t['select_use_case'], list(use_case_videos.keys()))
223
- if selected_title in use_case_videos:
224
- try:
225
- st_player(use_case_videos[selected_title])
226
- except Exception as e:
227
- st.error(f"Error al cargar el video: {str(e)}")
228
-
229
- # Tab de Videos
230
- with tab_videos:
231
- videos = {
232
- "Reel AIdeaText": "https://youtu.be/hXnwUvN1Q9Q",
233
- "Presentación en SENDA, UNAM. Ciudad de México, México" : "https://www.youtube.com/watch?v=XFLvjST2cE0",
234
- "Presentación en PyCon 2024. Colombia, Medellín": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
235
- "Presentación en Fundación Ser Maaestro. Lima, Perú": "https://www.youtube.com/watch?v=imc4TI1q164",
236
- "Presentación en Explora del IFE, TEC de Monterrey, Nuevo León, México": "https://www.youtube.com/watch?v=Fqi4Di_Rj_s",
237
- "Entrevista con el Dr. Guillermo Ruíz. Lima, Perú": "https://www.youtube.com/watch?v=_ch8cRja3oc",
238
- "Demo de la versión de escritorio.": "https://www.youtube.com/watch?v=nP6eXbog-ZY"
239
- }
240
-
241
- selected_title = st.selectbox(landing_t['select_presentation'], list(videos.keys()))
242
- if selected_title in videos:
243
- try:
244
- st_player(videos[selected_title])
245
- except Exception as e:
246
- st.error(f"Error al cargar el video: {str(e)}")
247
-
248
- # Tab de Eventos
249
- with tab_events:
250
- st.markdown("""
251
- ## 2025
252
-
253
- **El Agente Cognitivo Vinculante como Innovación en el Aprendizaje Adaptativo: el caso de AIdeaText**
254
- IFE CONFERENCE 2025. Organizado por el Instituto para el Futuro de la Educación del TEC de Monterrey.
255
- Nuevo León, México. Del 28 al 30 enero 2025
256
-
257
- ## 2024
258
- [1]
259
- AIdeaText, AIdeaText, recurso digital que emplea la técnica de Análisis de Resonancia Central para perfeccionar textos académicos**
260
- V Temporada SENDA - Organizado por el Seminario de Entornos y Narrativas Digitales en la Academia del
261
- Instituto de Investigaciones Antropológicas (IIA) de la Universidad Autonóma de México (UNAM). 22 noviembre 2024
262
-
263
- [2]
264
- Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
265
- Congreso HeETI 2024: Horizontes Expandidos de la Educación, la Tecnología y la Innovación
266
- Universidad el Claustro de Sor Juana. Del 25 al 27 septiembre 2024
267
-
268
- [3]
269
- AIdeaText, visualización de mapas semánticos**
270
- PyCon 2024, Organizado por el grupo de desarrolladores independientes de Python.
271
- Universidad EAFIT, Medellín, Colombia. Del 7 al 9 de junio de 2024.
272
-
273
- ## 2023
274
- **Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
275
- [1]
276
- XVII Congreso Nacional de Investigación Educativa - VII Encuentro de Estudiantes de Posgrado Educación.
277
- Consejo Mexicano de Investigación Educativa (COMIE)
278
- Villahermosa, Tabasco, México.
279
- Del 4 al 8 de diciembre 2023
280
-
281
- [2]
282
- XXXI Encuentro Internacional de Educación a Distancia
283
- Universidad de Guadalajara. Jalisco, México.
284
- Del 27 al 30 noviembre 2023
285
-
286
- [3]
287
- IV Temporada SENDA - Seminario de Entornos y Narrativas Digitales en la Academia
288
- Instituto de Investigaciones Antropológicas (IIA), UNAM.
289
- 22 noviembre 2023
290
-
291
- [4]
292
- 1er Congreso Internacional de Educación Digital
293
- Instituto Politécnico Nacional, sede Zacatecas. México.
294
- Del 23 al 24 de noviembre de 2023
295
-
296
- [5]
297
- La cuestión de la centralidad del maestro frente a las tecnologías digitales generativas**
298
- Innova Fórum: Ecosistemas de Aprendizaje
299
- Universidad de Guadalajara. Jalisco, México.
300
- Del 16 al 18 de mayo 2023
301
- """)
302
-
303
- # Tab de Galería
304
- with tab_gallery:
305
- # Contenedor con ancho máximo
306
- with st.container():
307
- # Dividimos en dos columnas principales
308
- col_left, col_right = st.columns(2)
309
-
310
- # Columna izquierda: Foto 1 grande
311
- with col_left:
312
- # Foto 2 arriba
313
- st.image("assets/img/socialmedia/_MG_2845.JPG",
314
- caption="MakerFaire CDMX 2024",
315
- width=480) # Ajusta este valor según necesites
316
- # use_column_width=True)
317
-
318
- # Foto 3 abajo
319
- st.image("assets/img/socialmedia/Facebook_CoverPhoto-1_820x312.jpg",
320
- caption="MakerFaire CDMX 2024",
321
- width=480) # Ajusta este valor según necesites
322
- # use_column_width=True)
323
-
324
- # Columna derecha: Fotos 2 y 3 una encima de otra
325
- with col_right:
326
- st.image("assets/img/socialmedia/_MG_2790.jpg",
327
- caption="MakerFaire CDMX 2024",
328
- width=540) # Ajusta este valor según necesites
329
-
330
-
331
- # Tab de Novedades - Usar contenido traducido
332
- with tab_news:
333
- st.markdown(f"### {landing_t['latest_version_title']}")
334
- for update in landing_t['version_updates']:
335
- st.markdown(f"- {update}")
336
-
337
- # Definición de __all__ para especificar qué se exporta
338
- __all__ = ['main', 'login_register_page', 'initialize_session_state']
339
-
340
- # Bloque de ejecución condicional
341
- if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  main()
 
1
+ # modules/ui/ui.py
2
+ import streamlit as st
3
+ from PIL import Image
4
+ import base64
5
+ from streamlit_player import st_player
6
+ import logging
7
+ from datetime import datetime
8
+ from dateutil.parser import parse
9
+
10
+ #########################################################
11
+ # Configuración de estilo CSS para el carrusel
12
+ st.markdown("""
13
+ <style>
14
+ .carousel-container {
15
+ position: relative;
16
+ max-width: 800px;
17
+ margin: 0 auto;
18
+ }
19
+ .carousel-image {
20
+ width: 100%;
21
+ border-radius: 10px;
22
+ box-shadow: 0 4px 8px rgba(0,0,0,0.2);
23
+ display: none;
24
+ }
25
+ .carousel-image.active {
26
+ display: block;
27
+ animation: fadeIn 0.5s;
28
+ }
29
+ @keyframes fadeIn {
30
+ from {opacity: 0.4;}
31
+ to {opacity: 1;}
32
+ }
33
+ .carousel-caption {
34
+ text-align: center;
35
+ margin-top: 10px;
36
+ font-size: 1.1em;
37
+ color: #333;
38
+ }
39
+ .carousel-nav {
40
+ display: flex;
41
+ justify-content: center;
42
+ margin-top: 15px;
43
+ }
44
+ .carousel-dot {
45
+ height: 12px;
46
+ width: 12px;
47
+ margin: 0 5px;
48
+ background-color: #bbb;
49
+ border-radius: 50%;
50
+ display: inline-block;
51
+ cursor: pointer;
52
+ }
53
+ .carousel-dot.active {
54
+ background-color: #717171;
55
+ }
56
+ </style>
57
+ """, unsafe_allow_html=True)
58
+
59
+ # Datos del carrusel (imágenes y descripciones)
60
+ eventos = [
61
+ {
62
+ "imagen": "assets/img/socialmedia/WebSummit ShowCase 2025.png",
63
+ "titulo": "WebSummitRio 2025, Brasil, april, 27-30",
64
+ "descripcion": "AIdeaText showcase"
65
+ }
66
+ ]
67
+
68
+ def initialize_carousel_state():
69
+ """Inicializa todas las variables de estado necesarias para el carrusel"""
70
+ if not hasattr(st.session_state, 'current_event'):
71
+ st.session_state.current_event = 0
72
+ if not hasattr(st.session_state, 'carousel_initialized'):
73
+ st.session_state.carousel_initialized = True
74
+
75
+ #####################
76
+ def show_carousel():
77
+ """Muestra el carrusel de imágenes con inicialización segura del estado"""
78
+ try:
79
+ # Inicialización segura del estado
80
+ initialize_carousel_state()
81
+
82
+ # Verificación adicional
83
+ if not hasattr(st.session_state, 'current_event'):
84
+ st.session_state.current_event = 0
85
+ st.rerun()
86
+
87
+ current_idx = st.session_state.current_event
88
+
89
+ with st.container():
90
+ #st.markdown("<h2 style='text-align: center; margin-bottom: 30px;'>Eventos Relevantes</h2>",
91
+ # unsafe_allow_html=True)
92
+
93
+ # Controles de navegación
94
+ col1, col2, col3 = st.columns([1, 6, 1])
95
+
96
+ with col1:
97
+ if st.button("◀", key="carousel_prev"):
98
+ st.session_state.current_event = (current_idx - 1) % len(eventos)
99
+ st.rerun()
100
+
101
+ with col2:
102
+ event = eventos[current_idx]
103
+ img = Image.open(event["imagen"]) if isinstance(event["imagen"], str) else event["imagen"]
104
+ st.image(
105
+ img,
106
+ use_container_width=True, # <-- Cambio realizado aquí
107
+ caption=f"{event['titulo']} - {event['descripcion']}"
108
+ )
109
+
110
+ with col3:
111
+ if st.button("▶", key="carousel_next"):
112
+ st.session_state.current_event = (current_idx + 1) % len(eventos)
113
+ st.rerun()
114
+
115
+ # Indicadores de posición
116
+ st.markdown("<div class='carousel-nav'>", unsafe_allow_html=True)
117
+ cols = st.columns(len(eventos))
118
+ for i, col in enumerate(cols):
119
+ with col:
120
+ if st.button("•", key=f"carousel_dot_{i}"):
121
+ st.session_state.current_event = i
122
+ st.rerun()
123
+ st.markdown("</div>", unsafe_allow_html=True)
124
+
125
+ except Exception as e:
126
+ st.error(f"Error al mostrar el carrusel: {str(e)}")
127
+ logger.error(f"Error en show_carousel: {str(e)}")
128
+
129
+ #########################################################
130
+
131
+
132
+ # Configura el logger PRIMERO, antes de cualquier uso
133
+ logging.basicConfig(level=logging.INFO)
134
+ logger = logging.getLogger(__name__)
135
+
136
+ # Importaciones locales
137
+ from session_state import initialize_session_state, logout
138
+ from translations import get_translations, get_landing_translations
139
+ from ..auth.auth import authenticate_user, authenticate_student, authenticate_admin
140
+ from ..database.sql_db import store_application_request
141
+
142
+ # Intento de importación con logger YA DEFINIDO
143
+ try:
144
+ from .user_page import user_page
145
+ except ImportError as e:
146
+ logger.error(f"No se pudo importar user_page: {str(e)}. Asegúrate de que el archivo existe.")
147
+
148
+ # Función de respaldo
149
+ def user_page(lang_code, t):
150
+ st.error("La página de usuario no está disponible. Por favor, contacta al administrador.")
151
+
152
+ from ..admin.admin_ui import admin_page
153
+
154
+ #############################################################
155
+ def main():
156
+ logger.info(f"Entrando en main() - Página actual: {st.session_state.page}")
157
+
158
+ if 'nlp_models' not in st.session_state:
159
+ logger.error("Los modelos NLP no están inicializados.")
160
+ st.error("Los modelos NLP no están inicializados. Por favor, reinicie la aplicación.")
161
+ return
162
+
163
+ lang_code = st.session_state.get('lang_code', 'es')
164
+ t = get_translations(lang_code)
165
+
166
+ logger.info(f"Página actual antes de la lógica de enrutamiento: {st.session_state.page}")
167
+
168
+ if st.session_state.get('logged_out', False):
169
+ st.session_state.logged_out = False
170
+ st.session_state.page = 'login'
171
+ st.rerun()
172
+
173
+ if not st.session_state.get('logged_in', False):
174
+ logger.info("Usuario no ha iniciado sesión. Mostrando página de login/registro")
175
+ login_register_page(lang_code, t)
176
+ elif st.session_state.page == 'user':
177
+ if st.session_state.role == 'Administrador':
178
+ logger.info("Redirigiendo a la página de administrador")
179
+ st.session_state.page = 'Admin'
180
+ st.rerun()
181
+ else:
182
+ logger.info("Renderizando página de usuario")
183
+ user_page(lang_code, t)
184
+ elif st.session_state.page == "Admin":
185
+ logger.info("Renderizando página de administrador")
186
+ admin_page()
187
+ else:
188
+ logger.error(f"Página no reconocida: {st.session_state.page}")
189
+ st.error(t.get('unrecognized_page', 'Página no reconocida'))
190
+ # Redirigir a la página de usuario en caso de error
191
+ st.session_state.page = 'user'
192
+ st.rerun()
193
+
194
+ logger.info(f"Saliendo de main() - Estado final de la sesión: {st.session_state}")
195
+
196
+ #############################################################
197
+ #############################################################
198
+ def login_register_page(lang_code, t):
199
+ # Obtener traducciones específicas para landing page
200
+ landing_t = get_landing_translations(lang_code)
201
+
202
+ # Language selection dropdown at the top
203
+ languages = {'Español': 'es', 'English': 'en', 'Français': 'fr', 'Português': 'pt'}
204
+
205
+ # Estilo personalizado para mejorar el espaciado y alineación
206
+ st.markdown("""
207
+ <style>
208
+ div.row-widget.stHorizontalBlock {
209
+ align-items: center;
210
+ }
211
+ </style>
212
+ """, unsafe_allow_html=True)
213
+
214
+ # Crear contenedor para logos y selector de idioma usando columnas de Streamlit
215
+ col1, col2, col3, col4, col5 = st.columns([0.25, 0.25, 1, 1, 1])
216
+
217
+ with col1:
218
+ # Logo de ALPHA
219
+ st.image("https://huggingface.co/spaces/AIdeaText/v3/resolve/main/assets/img/ALPHA_Startup%20Badges.png", width=100)
220
+
221
+ with col2:
222
+ # Logo de AIdeaText
223
+ st.image("https://huggingface.co/spaces/AIdeaText/v3/resolve/main/assets/img/AIdeaText_Logo_vectores.png", width=100)
224
+
225
+ with col5:
226
+ # Selector de idioma
227
+ selected_lang = st.selectbox(
228
+ landing_t['select_language'],
229
+ list(languages.keys()),
230
+ index=list(languages.values()).index(lang_code),
231
+ key=f"landing_language_selector_{lang_code}"
232
+ )
233
+ new_lang_code = languages[selected_lang]
234
+ if lang_code != new_lang_code:
235
+ st.session_state.lang_code = new_lang_code
236
+ st.rerun()
237
+
238
+ # Main content with columns
239
+ left_column, right_column = st.columns([1, 3])
240
+
241
+ with left_column:
242
+ tab1, tab2 = st.tabs([landing_t['login'], landing_t['register']])
243
+
244
+ with tab1:
245
+ login_form(lang_code, landing_t)
246
+
247
+ with tab2:
248
+ register_form(lang_code, landing_t)
249
+
250
+ with right_column:
251
+ display_videos_and_info(lang_code, landing_t)
252
+
253
+ #############################################################
254
+ #############################################################
255
+ def login_form(lang_code, landing_t):
256
+ with st.form("login_form"):
257
+ username = st.text_input(landing_t['email'])
258
+ password = st.text_input(landing_t['password'], type="password")
259
+ submit_button = st.form_submit_button(landing_t['login_button'])
260
+
261
+ if submit_button:
262
+ success, role = authenticate_user(username, password)
263
+ if success:
264
+ st.session_state.logged_in = True
265
+ st.session_state.username = username
266
+ st.session_state.role = role
267
+ if role == 'Administrador':
268
+ st.session_state.page = 'Admin'
269
+ else:
270
+ st.session_state.page = 'user'
271
+ logger.info(f"Usuario autenticado: {username}, Rol: {role}")
272
+ st.rerun()
273
+ else:
274
+ st.error(landing_t['invalid_credentials'])
275
+
276
+
277
+ #############################################################
278
+ #############################################################
279
+ def register_form(lang_code, landing_t):
280
+ name = st.text_input(landing_t['name'])
281
+ lastname = st.text_input(landing_t['lastname'])
282
+ institution = st.text_input(landing_t['institution'])
283
+ current_role = st.selectbox(landing_t['current_role'],
284
+ [landing_t['professor'], landing_t['student'], landing_t['administrative']])
285
+
286
+ # Definimos el rol por defecto como estudiante
287
+ desired_role = landing_t['student']
288
+
289
+ email = st.text_input(landing_t['institutional_email'])
290
+ reason = st.text_area(landing_t['interest_reason'])
291
+
292
+ if st.button(landing_t['submit_application']):
293
+ logger.info(f"Intentando enviar solicitud para {email}")
294
+ logger.debug(f"Datos del formulario: name={name}, lastname={lastname}, email={email}, institution={institution}, current_role={current_role}, desired_role={desired_role}, reason={reason}")
295
+
296
+ if not name or not lastname or not email or not institution or not reason:
297
+ logger.warning("Envío de formulario incompleto")
298
+ st.error(landing_t['complete_all_fields'])
299
+ elif not is_institutional_email(email):
300
+ logger.warning(f"Email no institucional utilizado: {email}")
301
+ st.error(landing_t['use_institutional_email'])
302
+ else:
303
+ logger.info(f"Intentando almacenar solicitud para {email}")
304
+ success = store_application_request(name, lastname, email, institution, current_role, desired_role, reason)
305
+ if success:
306
+ st.success(landing_t['application_sent'])
307
+ logger.info(f"Solicitud almacenada exitosamente para {email}")
308
+ else:
309
+ st.error(landing_t['application_error'])
310
+ logger.error(f"Error al almacenar solicitud para {email}")
311
+
312
+
313
+ #############################################################
314
+ #############################################################
315
+ def is_institutional_email(email):
316
+ forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
317
+ return not any(domain in email.lower() for domain in forbidden_domains)
318
+
319
+ #############################################################
320
+ #############################################################
321
+ def display_videos_and_info(lang_code, landing_t):
322
+ # Crear tabs para cada sección
323
+ tab_gallery, tab_use_case, tab_videos, tab_events, tab_news = st.tabs([
324
+ landing_t['event_photos'],
325
+ landing_t['use_cases'],
326
+ landing_t['presentation_videos'],
327
+ landing_t['academic_presentations'],
328
+ landing_t['version_control']
329
+ ])
330
+
331
+ # Tab de Casos de uso
332
+ with tab_use_case:
333
+ use_case_videos = {
334
+ "English - Radar use chart": "https://youtu.be/fFbbtlIewgs",
335
+ "English - Use AI Bot and arcs charts fuctions": "https://youtu.be/XjM-1oOl-ao",
336
+ "English - Arcs use charts, example 1": "https://youtu.be/PdK_bgigVaM",
337
+ "English - Arcs use charts, excample 2": "https://youtu.be/7uaV1njPOng",
338
+ "Español - Uso del diagrama radar para verificar redacción": "https://www.youtube.com/watch?v=nJP6xscPLBU",
339
+ "Español - Uso de los diagramas de arco, ejemplo 1": "https://www.youtube.com/watch?v=ApBIAr2S-bE",
340
+ "Español - Uso de los diagramas de arco, ejemplo 2": "https://www.youtube.com/watch?v=JnP2U1Fm0rc",
341
+ "Español - Uso de los diagramas de arco, ejemplo 3": "https://www.youtube.com/watch?v=waWWwPTaI-Y",
342
+ "Español - Uso del bot para buscar respuestas" : "https://www.youtube.com/watch?v=GFKDS0K2s7E"
343
+ }
344
+
345
+ selected_title = st.selectbox(landing_t['select_use_case'], list(use_case_videos.keys()))
346
+ if selected_title in use_case_videos:
347
+ try:
348
+ st_player(use_case_videos[selected_title])
349
+ except Exception as e:
350
+ st.error(f"Error al cargar el video: {str(e)}")
351
+
352
+ # Tab de Videos
353
+ with tab_videos:
354
+ videos = {
355
+ "Reel AIdeaText": "https://youtu.be/hXnwUvN1Q9Q",
356
+ "Presentación en SENDA, UNAM. Ciudad de México, México" : "https://www.youtube.com/watch?v=XFLvjST2cE0",
357
+ "Presentación en PyCon 2024. Colombia, Medellín": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
358
+ "Presentación en Fundación Ser Maaestro. Lima, Perú": "https://www.youtube.com/watch?v=imc4TI1q164",
359
+ "Presentación en Explora del IFE, TEC de Monterrey, Nuevo León, México": "https://www.youtube.com/watch?v=Fqi4Di_Rj_s",
360
+ "Entrevista con el Dr. Guillermo Ruíz. Lima, Perú": "https://www.youtube.com/watch?v=_ch8cRja3oc",
361
+ "Demo de la versión de escritorio.": "https://www.youtube.com/watch?v=nP6eXbog-ZY"
362
+ }
363
+
364
+ selected_title = st.selectbox(landing_t['select_presentation'], list(videos.keys()))
365
+ if selected_title in videos:
366
+ try:
367
+ st_player(videos[selected_title])
368
+ except Exception as e:
369
+ st.error(f"Error al cargar el video: {str(e)}")
370
+
371
+ # Tab de Eventos
372
+ with tab_events:
373
+ st.markdown("""
374
+ ## 2025
375
+
376
+ **El Agente Cognitivo Vinculante como Innovación en el Aprendizaje Adaptativo: el caso de AIdeaText**
377
+ IFE CONFERENCE 2025. Organizado por el Instituto para el Futuro de la Educación del TEC de Monterrey.
378
+ Nuevo León, México. Del 28 al 30 enero 2025
379
+
380
+ ## 2024
381
+ [1]
382
+ AIdeaText, AIdeaText, recurso digital que emplea la técnica de Análisis de Resonancia Central para perfeccionar textos académicos**
383
+ V Temporada SENDA - Organizado por el Seminario de Entornos y Narrativas Digitales en la Academia del
384
+ Instituto de Investigaciones Antropológicas (IIA) de la Universidad Autonóma de México (UNAM). 22 noviembre 2024
385
+
386
+ [2]
387
+ Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
388
+ Congreso HeETI 2024: Horizontes Expandidos de la Educación, la Tecnología y la Innovación
389
+ Universidad el Claustro de Sor Juana. Del 25 al 27 septiembre 2024
390
+
391
+ [3]
392
+ AIdeaText, visualización de mapas semánticos**
393
+ PyCon 2024, Organizado por el grupo de desarrolladores independientes de Python.
394
+ Universidad EAFIT, Medellín, Colombia. Del 7 al 9 de junio de 2024.
395
+
396
+ ## 2023
397
+ **Aproximación al Agente Cognitivo Vinculante (ACV) desde la Teoría del Actor Red (TAR)**
398
+ [1]
399
+ XVII Congreso Nacional de Investigación Educativa - VII Encuentro de Estudiantes de Posgrado Educación.
400
+ Consejo Mexicano de Investigación Educativa (COMIE)
401
+ Villahermosa, Tabasco, México.
402
+ Del 4 al 8 de diciembre 2023
403
+
404
+ [2]
405
+ XXXI Encuentro Internacional de Educación a Distancia
406
+ Universidad de Guadalajara. Jalisco, México.
407
+ Del 27 al 30 noviembre 2023
408
+
409
+ [3]
410
+ IV Temporada SENDA - Seminario de Entornos y Narrativas Digitales en la Academia
411
+ Instituto de Investigaciones Antropológicas (IIA), UNAM.
412
+ 22 noviembre 2023
413
+
414
+ [4]
415
+ 1er Congreso Internacional de Educación Digital
416
+ Instituto Politécnico Nacional, sede Zacatecas. México.
417
+ Del 23 al 24 de noviembre de 2023
418
+
419
+ [5]
420
+ La cuestión de la centralidad del maestro frente a las tecnologías digitales generativas**
421
+ Innova Fórum: Ecosistemas de Aprendizaje
422
+ Universidad de Guadalajara. Jalisco, México.
423
+ Del 16 al 18 de mayo 2023
424
+ """)
425
+
426
+ ##########################################################################################
427
+
428
+ # Tab de Galería
429
+ with tab_gallery:
430
+ show_carousel()
431
+
432
+ #############################################################
433
+ #############################################################
434
+ # Tab de Novedades - Usar contenido traducido
435
+ with tab_news:
436
+ st.markdown(f"### {landing_t['latest_version_title']}")
437
+ for update in landing_t['version_updates']:
438
+ st.markdown(f"- {update}")
439
+
440
+ #############################################################
441
+ #############################################################
442
+ # Definición de __all__ para especificar qué se exporta
443
+ __all__ = ['main', 'login_register_page', 'initialize_session_state']
444
+
445
+ # Bloque de ejecución condicional
446
+ if __name__ == "__main__":
447
  main()
requirements.txt CHANGED
@@ -24,6 +24,9 @@ numpy
24
  networkx
25
  matplotlib
26
  odfpy
 
 
 
27
  plotly
28
  pydantic
29
  python-dateutil
@@ -34,6 +37,7 @@ pymssql
34
  python-dotenv
35
  pymongo
36
  PyPDF2
 
37
  rlPyCairo
38
  requests
39
  reportlab
 
24
  networkx
25
  matplotlib
26
  odfpy
27
+
28
+ ################
29
+ pillow
30
  plotly
31
  pydantic
32
  python-dateutil
 
37
  python-dotenv
38
  pymongo
39
  PyPDF2
40
+ #########
41
  rlPyCairo
42
  requests
43
  reportlab