AIdeaText commited on
Commit
fa1b8f7
·
verified ·
1 Parent(s): 212dd92

Create ui.py

Browse files
Files changed (1) hide show
  1. modules/ui/ui.py +823 -0
modules/ui/ui.py ADDED
@@ -0,0 +1,823 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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, Rio, Brasil, april, 27-30",
64
+ "descripcion": "AIdeaText showcase"
65
+ },
66
+
67
+ {
68
+ "imagen": "assets/img/socialmedia/image_pycon_2024.png",
69
+ "titulo": "PyCon 2024, Medellin, Colombia, june, 7-9",
70
+ "descripcion": "AIdeaText showcase"
71
+ },
72
+
73
+ {
74
+ "imagen": "assets/img/socialmedia/_MG_2845.JPG",
75
+ "titulo": "MakerFaire 2024, Mexico City, Mexico, octuber, 12-13",
76
+ "descripcion": "AIdeaText showcase"
77
+ }
78
+ ]
79
+
80
+ #####################
81
+ def initialize_carousel_state():
82
+ """Inicializa todas las variables de estado necesarias para el carrusel"""
83
+ if not hasattr(st.session_state, 'current_event'):
84
+ st.session_state.current_event = 0
85
+ if not hasattr(st.session_state, 'carousel_initialized'):
86
+ st.session_state.carousel_initialized = True
87
+
88
+ #####################
89
+ def show_carousel():
90
+ """Muestra el carrusel de imágenes con inicialización segura del estado"""
91
+ try:
92
+ # Inicialización segura del estado
93
+ initialize_carousel_state()
94
+
95
+ # Verificación adicional
96
+ if not hasattr(st.session_state, 'current_event'):
97
+ st.session_state.current_event = 0
98
+ st.rerun()
99
+
100
+ current_idx = st.session_state.current_event
101
+
102
+ with st.container():
103
+ #st.markdown("<h2 style='text-align: center; margin-bottom: 30px;'>Eventos Relevantes</h2>",
104
+ # unsafe_allow_html=True)
105
+
106
+ # Controles de navegación
107
+ col1, col2, col3 = st.columns([1, 6, 1])
108
+
109
+ with col1:
110
+ if st.button("◀", key="carousel_prev"):
111
+ st.session_state.current_event = (current_idx - 1) % len(eventos)
112
+ st.rerun()
113
+
114
+ with col2:
115
+ event = eventos[current_idx]
116
+ img = Image.open(event["imagen"]) if isinstance(event["imagen"], str) else event["imagen"]
117
+ st.image(
118
+ img,
119
+ use_container_width=True, # <-- Cambio realizado aquí
120
+ caption=f"{event['titulo']} - {event['descripcion']}"
121
+ )
122
+
123
+ with col3:
124
+ if st.button("▶", key="carousel_next"):
125
+ st.session_state.current_event = (current_idx + 1) % len(eventos)
126
+ st.rerun()
127
+
128
+ # Indicadores de posición (solo visuales, no botones)
129
+ st.markdown("<div class='carousel-nav'>", unsafe_allow_html=True)
130
+ for i in range(len(eventos)):
131
+ active_class = "carousel-dot active" if i == current_idx else "carousel-dot"
132
+ st.markdown(f"<span class='{active_class}'></span>", unsafe_allow_html=True)
133
+ st.markdown("</div>", unsafe_allow_html=True)
134
+
135
+ except Exception as e:
136
+ st.error(f"Error al mostrar el carrusel: {str(e)}")
137
+ logger.error(f"Error en show_carousel: {str(e)}")
138
+
139
+ #########################################################
140
+ # Configura el logger PRIMERO, antes de cualquier uso
141
+ logging.basicConfig(level=logging.INFO)
142
+ logger = logging.getLogger(__name__)
143
+
144
+ #########################################################
145
+ # Importaciones locales
146
+ from session_state import initialize_session_state, logout
147
+ from translations import get_translations, get_landing_translations
148
+ from ..auth.auth import authenticate_user, authenticate_student, authenticate_admin
149
+ from ..database.sql_db import store_application_request
150
+ from ..admin.admin_ui import admin_page
151
+
152
+ #########################################################
153
+ # Intento de importación con logger YA DEFINIDO
154
+ try:
155
+ from .user_page import user_page
156
+ except ImportError as e:
157
+ logger.error(f"No se pudo importar user_page: {str(e)}. Asegúrate de que el archivo existe.")
158
+
159
+ # Función de respaldo
160
+ def user_page(lang_code, t):
161
+ st.error("La página de usuario no está disponible. Por favor, contacta al administrador.")
162
+
163
+ #############################################################
164
+ def main():
165
+ logger.info(f"Entrando en main() - Página actual: {st.session_state.page}")
166
+
167
+ if 'nlp_models' not in st.session_state:
168
+ logger.error("Los modelos NLP no están inicializados.")
169
+ st.error("Los modelos NLP no están inicializados. Por favor, reinicie la aplicación.")
170
+ return
171
+
172
+ lang_code = st.session_state.get('lang_code', 'en')
173
+ t = get_translations(lang_code)
174
+
175
+ logger.info(f"Página actual antes de la lógica de enrutamiento: {st.session_state.page}")
176
+
177
+ if st.session_state.get('logged_out', False):
178
+ st.session_state.logged_out = False
179
+ st.session_state.page = 'login'
180
+ st.rerun()
181
+
182
+ if not st.session_state.get('logged_in', False):
183
+ logger.info("Usuario no ha iniciado sesión. Mostrando página de login/registro")
184
+ login_register_page(lang_code, t)
185
+ elif st.session_state.page == 'user':
186
+ if st.session_state.role == 'Administrador':
187
+ logger.info("Redirigiendo a la página de administrador")
188
+ st.session_state.page = 'Admin'
189
+ st.rerun()
190
+ else:
191
+ logger.info("Renderizando página de usuario")
192
+ user_page(lang_code, t)
193
+ elif st.session_state.page == "Admin":
194
+ logger.info("Renderizando página de administrador")
195
+ admin_page()
196
+ else:
197
+ logger.error(f"Página no reconocida: {st.session_state.page}")
198
+ st.error(t.get('unrecognized_page', 'Página no reconocida'))
199
+ # Redirigir a la página de usuario en caso de error
200
+ st.session_state.page = 'user'
201
+ st.rerun()
202
+
203
+ logger.info(f"Saliendo de main() - Estado final de la sesión: {st.session_state}")
204
+
205
+ #############################################################
206
+ #############################################################
207
+
208
+ def login_register_page(lang_code, t):
209
+ # Obtener traducciones específicas para landing page
210
+ landing_t = get_landing_translations(lang_code)
211
+
212
+ # Language selection dropdown at the top
213
+ languages = {
214
+ 'English': 'en',
215
+ 'Español': 'es',
216
+ 'Français': 'fr',
217
+ 'Português': 'pt'
218
+ }
219
+
220
+ # Estilo personalizado para mejorar el espaciado y alineación
221
+ st.markdown("""
222
+ <style>
223
+ div.row-widget.stHorizontalBlock {
224
+ align-items: center;
225
+ }
226
+ /* Resaltar el tab de registro */
227
+ .stTabs [data-baseweb="tab-list"] {
228
+ gap: 0px;
229
+ }
230
+ .stTabs [data-baseweb="tab"] {
231
+ padding: 10px 20px;
232
+ font-weight: 600;
233
+ }
234
+ .stTabs [aria-selected="true"] {
235
+ background-color: #1E3A8A;
236
+ color: white !important;
237
+ border-radius: 5px 5px 0 0;
238
+ }
239
+ /* Estilo para contenedor de inicio */
240
+ .start-container {
241
+ background: linear-gradient(135deg, #1E3A8A 0%, #3730A3 100%);
242
+ color: white;
243
+ padding: 15px;
244
+ border-radius: 10px 10px 0 0;
245
+ text-align: center;
246
+ margin-bottom: 10px;
247
+ }
248
+ .language-inline {
249
+ display: inline-block;
250
+ margin-left: 10px;
251
+ vertical-align: middle;
252
+ }
253
+
254
+ /* CENTRAR EL LOGO - NUEVO ESTILO */
255
+ .logo-center-container {
256
+ display: flex;
257
+ justify-content: center;
258
+ align-items: center;
259
+ margin: 20px 0 30px 0;
260
+ width: 100%;
261
+ }
262
+ .logo-center-container img {
263
+ display: block;
264
+ margin: 0 auto;
265
+ }
266
+ /* Centrar el contenedor de imagen de Streamlit */
267
+ [data-testid="stImage"] {
268
+ text-align: center;
269
+ margin: 0 auto;
270
+ }
271
+ /* Forzar centrado del logo */
272
+ div.stImage {
273
+ text-align: center;
274
+ }
275
+ div.stImage > img {
276
+ margin: 0 auto;
277
+ display: block;
278
+ }
279
+
280
+ </style>
281
+ """, unsafe_allow_html=True)
282
+
283
+ # ============================================
284
+ # [1] LOGO AIdeaText CENTRADO - UNA SOLA FILA
285
+ # ============================================
286
+ # Opción 1: Usar columnas para centrar
287
+ st.markdown("""
288
+ <div style="text-align: center; margin: 20px 0 30px 0;">
289
+ <img src="https://huggingface.co/spaces/AIdeaText/v5Prod/resolve/main/assets/img/AIdeaText_Logo_vectores.png"
290
+ width="200" style="display: block; margin: 0 auto;">
291
+ </div>
292
+ """, unsafe_allow_html=True)
293
+
294
+ st.markdown("---")
295
+ #######################################################################
296
+
297
+ # Main content with columns
298
+ left_column, right_column = st.columns([1, 3])
299
+
300
+ with left_column:
301
+
302
+ # ============================================
303
+ # [2] CONTENEDOR "COMIENZA" CON SELECTOR DE IDIOMA
304
+ # ============================================
305
+ st.markdown("""
306
+ <div class="start-container">
307
+ <h3 style='margin: 0;'>
308
+ 🚀 Comienza en
309
+ <span class="language-inline">
310
+ """, unsafe_allow_html=True)
311
+
312
+ # Selector de idioma inline
313
+ selected_lang = st.selectbox(
314
+ "",
315
+ list(languages.keys()),
316
+ index=list(languages.keys()).index('English'), # [3.2] Inglés por defecto
317
+ label_visibility="collapsed",
318
+ key="landing_language_selector"
319
+ )
320
+
321
+ st.markdown("""
322
+ </span>
323
+ </h3>
324
+ </div>
325
+ """, unsafe_allow_html=True)
326
+
327
+ new_lang_code = languages[selected_lang]
328
+ if lang_code != new_lang_code:
329
+ st.session_state.lang_code = new_lang_code
330
+ st.rerun()
331
+
332
+ # Crear tabs - REGISTRO siempre primero
333
+ tab_titles = [f"📝 {landing_t['register']}", f"🔐 {landing_t['login']}"]
334
+ tabs = st.tabs(tab_titles)
335
+
336
+ # TAB 1: FORMULARIO DE REGISTRO (Siempre visible por defecto)
337
+ with tabs[0]:
338
+ register_form(lang_code, landing_t)
339
+
340
+ # TAB 2: FORMULARIO DE LOGIN
341
+ with tabs[1]:
342
+ login_form(lang_code, landing_t)
343
+
344
+ with right_column:
345
+ display_videos_and_info(lang_code, landing_t)
346
+
347
+
348
+ #############################################################
349
+ #############################################################
350
+ def login_form(lang_code, landing_t):
351
+ with st.form("login_form"):
352
+ username = st.text_input(landing_t['email'])
353
+ password = st.text_input(landing_t['password'], type="password")
354
+ submit_button = st.form_submit_button(landing_t['login_button'])
355
+
356
+ if submit_button:
357
+ success, role = authenticate_user(username, password)
358
+ if success:
359
+ st.session_state.logged_in = True
360
+ st.session_state.username = username
361
+ st.session_state.role = role
362
+ if role == 'Administrador':
363
+ st.session_state.page = 'Admin'
364
+ else:
365
+ st.session_state.page = 'user'
366
+ logger.info(f"Usuario autenticado: {username}, Rol: {role}")
367
+ st.rerun()
368
+ else:
369
+ st.error(landing_t['invalid_credentials'])
370
+
371
+ #############################################################
372
+
373
+ def register_form(lang_code, landing_t):
374
+ """Formulario de registro simplificado - SOLO 3 CAMPOS"""
375
+
376
+ # Verificar si acabamos de registrar exitosamente
377
+ if 'just_registered' in st.session_state and st.session_state.just_registered:
378
+ st.success("✅ ¡Registro exitoso! Tu solicitud ha sido enviada.")
379
+ st.info("Por favor revisa tu correo para más instrucciones.")
380
+
381
+ # Botón para limpiar y empezar de nuevo
382
+ if st.button("Hacer otro registro"):
383
+ del st.session_state.just_registered
384
+ st.rerun()
385
+ return
386
+
387
+ # Solo 3 campos requeridos
388
+ name = st.text_input("Nombre completo *", key="reg_name")
389
+ email = st.text_input("Correo institucional *", key="reg_email")
390
+ institution = st.text_input("Institución educativa *", key="reg_institution")
391
+
392
+ # Botón simplificado
393
+ if st.button(landing_t['submit_application'], type="primary"):
394
+ logger.info(f"Intentando enviar solicitud para {email}")
395
+
396
+ # Validaciones básicas
397
+ if not name or not email or not institution:
398
+ st.error("Por favor completa los campos obligatorios (*)")
399
+ return
400
+
401
+ if not is_institutional_email(email):
402
+ st.error("Por favor usa un correo institucional (no gmail, hotmail, etc.)")
403
+ return
404
+
405
+ # Enviar solicitud
406
+ success = store_application_request(
407
+ name=name,
408
+ lastname="",
409
+ email=email,
410
+ institution=institution,
411
+ current_role="Estudiante",
412
+ desired_role="Estudiante",
413
+ reason="Nuevo registro"
414
+ )
415
+
416
+ if success:
417
+ # Marcar que acabamos de registrar
418
+ st.session_state.just_registered = True
419
+ logger.info(f"Solicitud almacenada exitosamente para {email}")
420
+
421
+ # Mostrar mensaje y recargar
422
+ st.success("✅ ¡Tu solicitud ha sido enviada! Recibirás un correo con instrucciones.")
423
+ st.balloons()
424
+
425
+ # Recargar después de 2 segundos
426
+ import time
427
+ time.sleep(2)
428
+ st.rerun()
429
+ else:
430
+ st.error("❌ Hubo un error al enviar tu solicitud. Por favor, inténtalo de nuevo.")
431
+ logger.error(f"Error al almacenar solicitud para {email}")
432
+
433
+
434
+ #############################################################
435
+ #############################################################
436
+ def is_institutional_email(email):
437
+ forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
438
+ return not any(domain in email.lower() for domain in forbidden_domains)
439
+
440
+ #############################################################
441
+ #############################################################
442
+
443
+ def display_videos_and_info(lang_code, landing_t):
444
+ # ============================================
445
+ # NUEVO ORDEN DE TABS CON 6 OPCIONES
446
+ # ============================================
447
+ tab_about, tab_programs, tab_competitions, tab_use_case, tab_presentations, tab_gallery = st.tabs([
448
+ "👥 About Us",
449
+ "🏆 Current Programs",
450
+ "💰 Competitions",
451
+ "🎯 Use Cases",
452
+ "🎬 Pitches & Presentations",
453
+ "📸 Events & Recognition"
454
+ ])
455
+
456
+ # ============================================
457
+ # ESTILOS GLOBALES PARA CONSISTENCIA
458
+ # ============================================
459
+ st.markdown("""
460
+ <style>
461
+ /* Estilos para títulos consistentes */
462
+ .tab-title {
463
+ font-size: 1.8em;
464
+ font-weight: 700;
465
+ color: #1E3A8A;
466
+ margin-bottom: 20px;
467
+ padding-bottom: 10px;
468
+ border-bottom: 3px solid #1E3A8A;
469
+ }
470
+ .section-title {
471
+ font-size: 1.4em;
472
+ font-weight: 600;
473
+ color: #374151;
474
+ margin: 25px 0 15px 0;
475
+ }
476
+ .subsection-title {
477
+ font-size: 1.2em;
478
+ font-weight: 600;
479
+ color: #4B5563;
480
+ margin: 20px 0 10px 0;
481
+ }
482
+ .content-text {
483
+ font-size: 1em;
484
+ line-height: 1.6;
485
+ color: #6B7280;
486
+ }
487
+ .highlight-box {
488
+ background-color: #F3F4F6;
489
+ border-left: 4px solid #1E3A8A;
490
+ padding: 15px;
491
+ margin: 15px 0;
492
+ border-radius: 0 5px 5px 0;
493
+ }
494
+ .logo-grid {
495
+ display: flex;
496
+ align-items: center;
497
+ margin: 15px 0;
498
+ padding: 15px;
499
+ background: white;
500
+ border-radius: 8px;
501
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
502
+ }
503
+ </style>
504
+ """, unsafe_allow_html=True)
505
+
506
+ # ============================================
507
+ # TAB 1: 👥 ABOUT US
508
+ # ============================================
509
+ with tab_about:
510
+ # NO repetir "About Us" - el tab ya lo dice
511
+ about_texts = {
512
+ 'en': """
513
+ <div class="content-text">
514
+ <div class="highlight-box">
515
+ <strong>AIdeaText</strong> is a digital technology company for human cognitive development based in Mexico.
516
+ Our solution has its core business in <strong>Semantic Reasoning Graphs (SRGs)</strong>, a technological
517
+ configuration that makes the critical thinking process visible, connecting educational
518
+ training with business needs by implementing a cognitive development measurement system
519
+ based on advanced natural language processing.
520
+ </div>
521
+
522
+ <div class="section-title">Validation & Stage</div>
523
+ We have been validated by the <strong>NVIDIA Inception</strong> program for emerging companies and are in
524
+ an advanced development stage with a <a href="https://youtu.be/_4WMufl6MTA" target="_blank">functional MVP Demo</a><br> and a scalable <a href="https://youtu.be/Nt7IEas_P54" target="_blank"> business model</a>
525
+ in Latin America.
526
+
527
+ <div class="section-title">Mission & Vision</div>
528
+ <em>The real transformation happens when we stop grading what students produce and start assessing how they think. <em>
529
+ <strong>Mission:</strong> To transform how the world measures and develops critical thinking.<br>
530
+ <strong>Vision:</strong> To be the global standard for cognitive development assessment.
531
+
532
+ <div class="section-title">Key Differentiators</div>
533
+ • <strong>First cognitive development measurement system</strong> based on NLP<br>
534
+ • <strong>Semantic Reasoning Graphs</strong> make thinking visible<br>
535
+ • <strong>Validated by NVIDIA</strong> Inception Program<br>
536
+ • <strong>Scalable model</strong> for Latin American education market
537
+ """
538
+ }
539
+
540
+ about_content = about_texts.get(lang_code, about_texts['en'])
541
+ st.markdown(about_content, unsafe_allow_html=True)
542
+
543
+ # ============================================
544
+ # TAB 2: 🏆 CURRENT PROGRAMS
545
+ # ============================================
546
+ with tab_programs:
547
+ # NO repetir "Current Programs" - el tab ya lo dice
548
+
549
+ st.markdown('<div class="section-title">NVIDIA Inception Program</div>', unsafe_allow_html=True)
550
+
551
+ # Fila 1: NVIDIA Inception
552
+ col_nvidia_logo, col_nvidia_text = st.columns([1, 3])
553
+ with col_nvidia_logo:
554
+ st.image("https://huggingface.co/spaces/AIdeaText/v5Prod/resolve/main/assets/img/socialmedia/nvidia/nvidia-inception-program-badge-rgb-for-screen.png",
555
+ width=300)
556
+ with col_nvidia_text:
557
+ st.markdown("""
558
+ <div class="content-text">
559
+ <strong>Exclusive program for AI and Deep Tech startups</strong>
560
+
561
+ <p>Inception is a free program that guides AI startups through the NVIDIA platform and ecosystem.
562
+ From prototype to production, Inception meets you where you are, with member benefits to help
563
+ you discover new AI opportunities, build with world-class technologies, and grow your business.
564
+ More info: [https://www.nvidia.com/en-us/startups/]</p>
565
+
566
+ <em>Status: Active Member</em>
567
+ </div>
568
+ """, unsafe_allow_html=True)
569
+
570
+ st.markdown("---")
571
+
572
+ st.markdown('<div class="section-title">incMTY Accelerator</div>', unsafe_allow_html=True)
573
+
574
+ # Fila 2: incMTY
575
+ col_inc_logo, col_inc_text = st.columns([1, 3])
576
+ with col_inc_logo:
577
+ st.image("https://huggingface.co/spaces/AIdeaText/v5Dev/resolve/main/assets/img/Logo_incMTY.png",
578
+ width=250)
579
+ with col_inc_text:
580
+ st.markdown("""
581
+ <div class="content-text">
582
+ <strong>Deep Tech acceleration program</strong>
583
+
584
+ <p>PotencIA MX Accelerator will boost 30 organizations through a virtual acceleration program.
585
+ After two high-impact bootcamps in Monterrey and Mexico City, the selected startups and SMEs will begin
586
+ a six-month acceleration program. During this time, they will develop solutions with Open Source LLMs like Llama de Meta
587
+ and receive mentorship, specialized services, and strategy and growth workshops. The program will culminate in Demo Day 2026,
588
+ where the most outstanding organizations will be recognized: one startup will receive a business development trip with ecosystem partners,
589
+ and one SME will be offered soft landing support in new markets.</p>
590
+
591
+ <em>Status: Current member</em>
592
+ </div>
593
+ """, unsafe_allow_html=True)
594
+
595
+ # ============================================
596
+ # TAB 3: 💰 COMPETITIONS
597
+ # ============================================
598
+ with tab_competitions:
599
+ # NO repetir "Competitions" - el tab ya lo dice
600
+
601
+ competitions_text = {
602
+ 'en': """
603
+ <div class="content-text">
604
+ <div class="highlight-box">
605
+ Competing for <strong>$950K USD</strong> in prizes across multiple prestigious competitions.
606
+ </div>
607
+
608
+ <details class="competition-details">
609
+ <summary class="competition-summary">
610
+ <strong>NVIDIA Inception Demo Pitch – GTC 2026</strong> - March 16–19 in San Jose, California
611
+ </summary>
612
+ <div class="competition-content">
613
+ <p>This is a unique opportunity for startups leveraging NVIDIA technologies in innovative ways to showcase their work.
614
+ By completing the form below, you'll be considered to present a live, 5-minute demo or pitch at GTC,
615
+ highlighting your startup's progress and how NVIDIA technology is accelerating your success.</p>
616
+ <p>More info: https://www.nvidia.com/gtc/?ncid=GTC-NV7HIY70L</p>
617
+ </div>
618
+ </details>
619
+
620
+ <details class="competition-details">
621
+ <summary class="competition-summary">
622
+ <strong>Kaggle/Google Tunix Hackathon</strong> - Explainable AI Models
623
+ </summary>
624
+ <div class="competition-content">
625
+ <p>Most open-source or open-weight language models can give you an answer. But they typically don't 'show their work'
626
+ - the steps they went through to arrive at that conclusion in a consistent manner. Here, you'll use Tunix,
627
+ Google's new JAX-native library for LLM post-training, to train a model to show its work by laying out a
628
+ reasoning trace before landing on an answer.</p>
629
+ <p>More info: https://kaggle.com/competitions/google-tunix-hackathon</p>
630
+ </div>
631
+ </details>
632
+
633
+ <details class="competition-details">
634
+ <summary class="competition-summary">
635
+ <strong>Tools Competition – Dataset Track</strong> - Datasets for Education Innovation
636
+ </summary>
637
+ <div class="competition-content">
638
+ <p>The 2026 Tools Competition launches at a time of rapid change, rising urgency,
639
+ and widespread demand for understanding and direction amidst evolving technology.
640
+ Learners of all ages face new demands driven by AI,
641
+ shifting labor markets, and persistent inequities. From early learning to workforce development,
642
+ they need tools that are more effective, inclusive, and future-ready.</p>
643
+ <p>More info: https://tools-competition.org/26-overview/</p>
644
+ </div>
645
+ </details>
646
+ </div>
647
+ """
648
+ }
649
+
650
+ # Si necesitas agregar estilos CSS para los detalles
651
+ st.markdown("""
652
+ <style>
653
+ .competition-details {
654
+ margin-bottom: 15px;
655
+ border: 1px solid #e0e0e0;
656
+ border-radius: 8px;
657
+ padding: 5px;
658
+ }
659
+
660
+ .competition-summary {
661
+ padding: 12px 15px;
662
+ background-color: #f8f9fa;
663
+ cursor: pointer;
664
+ font-weight: 500;
665
+ border-radius: 6px;
666
+ transition: background-color 0.3s;
667
+ }
668
+
669
+ .competition-summary:hover {
670
+ background-color: #e9ecef;
671
+ }
672
+
673
+ .competition-content {
674
+ padding: 15px;
675
+ background-color: white;
676
+ border-top: 1px solid #e0e0e0;
677
+ border-radius: 0 0 8px 8px;
678
+ }
679
+
680
+ .competition-content p {
681
+ margin-bottom: 8px;
682
+ }
683
+ </style>
684
+ """, unsafe_allow_html=True)
685
+
686
+ content = competitions_text.get(lang_code, competitions_text['en'])
687
+ st.markdown(content, unsafe_allow_html=True)
688
+
689
+ #st.markdown("---")
690
+ #if st.button("🎯 Apply as Beta Tester", use_container_width=True):
691
+ # st.info("Beta tester program launching Q1 2025")
692
+
693
+ # ============================================
694
+ # TAB 4: 🎯 USE CASES
695
+ # ============================================
696
+ with tab_use_case:
697
+ # NO repetir "Use Cases" - el tab ya lo dice
698
+
699
+ st.markdown("""
700
+ <div class="content-text">
701
+ Select a demonstration to see practical applications of our technology:
702
+ </div>
703
+ """, unsafe_allow_html=True)
704
+
705
+ use_case_videos = {
706
+ "📊 Semantic Analysis Example in portuguese ": "https://youtu.be/_4WMufl6MTA",
707
+ "💻 Firs Demo - Standalone version ": "https://www.youtube.com/watch?v=nP6eXbog-ZY"
708
+ }
709
+
710
+ selected_title = st.selectbox(
711
+ "Select demonstration:" if lang_code == 'en' else "Selecciona demostración:",
712
+ list(use_case_videos.keys())
713
+ )
714
+
715
+ if selected_title in use_case_videos:
716
+ try:
717
+ st_player(
718
+ use_case_videos[selected_title],
719
+ height=400,
720
+ playing=False,
721
+ controls=True,
722
+ light=True
723
+ )
724
+ except Exception as e:
725
+ st.error(f"Error loading video: {str(e)}" if lang_code == 'en' else f"Error al cargar el video: {str(e)}")
726
+
727
+ # Información adicional sobre casos de uso
728
+ st.markdown("""
729
+ <div class="content-text">
730
+ <div class="section-title">Applications</div>
731
+
732
+ <strong>For Students:</strong>
733
+ • Visualize thinking processes
734
+ • Receive immediate feedback
735
+ • Improve academic writing
736
+ • Track cognitive progress
737
+
738
+ <strong>For Educators:</strong>
739
+ • Assess deep understanding
740
+ • Identify individual needs
741
+ • Personalize teaching
742
+ • Save grading time
743
+
744
+ <strong>For Institutions:</strong>
745
+ • Measure cognitive development
746
+ • Improve academic outcomes
747
+ • Validated educational innovation
748
+ • Data for research
749
+ </div>
750
+ """, unsafe_allow_html=True)
751
+
752
+ # ============================================
753
+ # TAB 5: 🎬 PITCHES & PRESENTATIONS
754
+ # ============================================
755
+ with tab_presentations:
756
+ # NO repetir "Pitches & Presentations" - el tab ya lo dice
757
+
758
+ st.markdown("""
759
+ <div class="content-text">
760
+ Watch our key pitches, demonstrations, and conference presentations:
761
+ </div>
762
+ """, unsafe_allow_html=True)
763
+
764
+ videos = {
765
+ "🎬 Pitch - PotencIA MX - ": "https://youtu.be/Nt7IEas_P54",
766
+ "🏆 Conference - SENDA UNAM ": "https://www.youtube.com/watch?v=XFLvjST2cE0",
767
+ "🐍 Conferente - PyCon 2024 ": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
768
+ "👨‍🏫 Conference - Ser Maaestro Foundation ": "https://www.youtube.com/watch?v=imc4TI1q164",
769
+ "🚀 Pitch - Explora - IFE - TEC de Monterrey ": "https://www.youtube.com/watch?v=Fqi4Di_Rj_s",
770
+ "🎙️ Interview with Dr. Guillermo Ruíz ": "https://www.youtube.com/watch?v=_ch8cRja3oc"
771
+ }
772
+
773
+ selected_title = st.selectbox(
774
+ "Select video:" if lang_code == 'en' else "Selecciona video:",
775
+ list(videos.keys())
776
+ )
777
+
778
+ if selected_title in videos:
779
+ try:
780
+ st_player(
781
+ videos[selected_title],
782
+ height=400,
783
+ playing=False,
784
+ controls=True,
785
+ light=True
786
+ )
787
+ except Exception as e:
788
+ st.error(f"Error loading video: {str(e)}" if lang_code == 'en' else f"Error al cargar el video: {str(e)}")
789
+
790
+ # Próximos eventos
791
+ st.markdown("""
792
+ <div class="content-text">
793
+ <div class="section-title">Upcoming Events</div>
794
+
795
+ <strong>Confirmed next events for 2026</strong>
796
+ • <strong>Stay in touch<br>
797
+
798
+ <em>Confirmed participation in showcases and panels.</em>
799
+ </div>
800
+ """, unsafe_allow_html=True)
801
+
802
+ # ============================================
803
+ # TAB 6: 📸 EVENTS & RECOGNITION
804
+ # ============================================
805
+ with tab_gallery:
806
+ # NO repetir "Events & Recognition" - el tab ya lo dice
807
+
808
+ st.markdown("""
809
+ <div class="content-text">
810
+ Gallery of our participation in events and recognition received:
811
+ </div>
812
+ """, unsafe_allow_html=True)
813
+
814
+ show_carousel()
815
+
816
+ #############################################################
817
+ #############################################################
818
+ # Definición de __all__ para especificar qué se exporta
819
+ __all__ = ['main', 'login_register_page', 'initialize_session_state']
820
+
821
+ # Bloque de ejecución condicional
822
+ if __name__ == "__main__":
823
+ main()