AIdeaText commited on
Commit
4ba62c6
·
verified ·
1 Parent(s): d24f3ab

Create ui.py

Browse files
Files changed (1) hide show
  1. modules/ui/ui.py +1140 -0
modules/ui/ui.py ADDED
@@ -0,0 +1,1140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Importaciones generales
2
+ import streamlit as st
3
+ import re
4
+ import io
5
+ from io import BytesIO
6
+ import base64
7
+ import matplotlib.pyplot as plt
8
+ import plotly.graph_objects as go
9
+ import pandas as pd
10
+ import numpy as np
11
+ import time
12
+ from datetime import datetime
13
+ from streamlit_player import st_player # Necesitarás instalar esta librería: pip install streamlit-player
14
+ from spacy import displacy
15
+ import logging
16
+
17
+ ######################################################
18
+ # Configuración del logger
19
+ logging.basicConfig(level=logging.INFO)
20
+ logger = logging.getLogger(__name__)
21
+
22
+ ######################################################
23
+ # Importaciones locales
24
+ from ..email.email import send_email_notification
25
+
26
+ ######################################################
27
+ # Importaciones locales de autenticación y base de datos
28
+ from ..auth.auth import (
29
+ authenticate_user,
30
+ register_user
31
+ )
32
+
33
+ ######################################################
34
+ from ..database.database import (
35
+ get_student_data,
36
+ store_application_request,
37
+ store_morphosyntax_result,
38
+ store_semantic_result,
39
+ store_discourse_analysis_result,
40
+ store_chat_history,
41
+ create_admin_user,
42
+ create_student_user,
43
+ store_user_feedback
44
+ )
45
+
46
+ ######################################################
47
+ # Importaciones locales de uiadmin
48
+ from ..admin.admin_ui import admin_page
49
+
50
+ ######################################################
51
+ # Importaciones locales funciones de análisis
52
+ from ..text_analysis.morpho_analysis import (
53
+ generate_arc_diagram,
54
+ get_repeated_words_colors,
55
+ highlight_repeated_words,
56
+ POS_COLORS,
57
+ POS_TRANSLATIONS,
58
+ perform_advanced_morphosyntactic_analysis
59
+ )
60
+
61
+ ######################################################
62
+ from ..text_analysis.semantic_analysis import (
63
+ #visualize_semantic_relations,
64
+ perform_semantic_analysis,
65
+ create_concept_graph,
66
+ visualize_concept_graph
67
+ )
68
+
69
+ ######################################################
70
+ from ..text_analysis.discourse_analysis import (
71
+ perform_discourse_analysis,
72
+ display_discourse_analysis_results
73
+ )
74
+
75
+ ######################################################
76
+ from ..chatbot.chatbot import (
77
+ initialize_chatbot,
78
+ get_chatbot_response
79
+ )
80
+
81
+ ##################################################################################################
82
+ def initialize_session_state():
83
+ if 'initialized' not in st.session_state:
84
+ st.session_state.clear()
85
+ st.session_state.initialized = True
86
+ st.session_state.logged_in = False
87
+ st.session_state.page = 'login'
88
+ st.session_state.username = None
89
+ st.session_state.role = None
90
+
91
+ ##################################################################################################
92
+ def main():
93
+ initialize_session_state()
94
+
95
+ print(f"Página actual: {st.session_state.page}")
96
+ print(f"Rol del usuario: {st.session_state.role}")
97
+
98
+ if st.session_state.page == 'login':
99
+ login_register_page()
100
+ elif st.session_state.page == 'admin':
101
+ print("Intentando mostrar página de admin")
102
+ admin_page()
103
+ elif st.session_state.page == 'user':
104
+ user_page()
105
+ else:
106
+ print(f"Página no reconocida: {st.session_state.page}")
107
+
108
+ print(f"Estado final de la sesión: {st.session_state}")
109
+
110
+ ##################################################################################################
111
+ def login_register_page():
112
+ st.title("AIdeaText")
113
+
114
+ left_column, right_column = st.columns([1, 3])
115
+
116
+ with left_column:
117
+ tab1, tab2 = st.tabs(["Iniciar Sesión", "Registrarse"])
118
+
119
+ with tab1:
120
+ login_form()
121
+
122
+ with tab2:
123
+ register_form()
124
+
125
+ with right_column:
126
+ display_videos_and_info()
127
+
128
+ ##################################################################################################
129
+
130
+ def login_form():
131
+ username = st.text_input("Correo electrónico", key="login_username")
132
+ password = st.text_input("Contraseña", type="password", key="login_password")
133
+
134
+ if st.button("Iniciar Sesión", key="login_button"):
135
+ success, role = authenticate_user(username, password)
136
+ if success:
137
+ st.session_state.logged_in = True
138
+ st.session_state.username = username
139
+ st.session_state.role = role
140
+ st.session_state.page = 'admin' if role == 'Administrador' else 'user'
141
+ print(f"Inicio de sesión exitoso. Usuario: {username}, Rol: {role}")
142
+ print(f"Estado de sesión después de login: {st.session_state}")
143
+ st.rerun()
144
+ else:
145
+ st.error("Credenciales incorrectas")
146
+
147
+ ##################################################################################################
148
+ def admin_page():
149
+ st.title("Panel de Administración")
150
+ st.write(f"Bienvenida, {st.session_state.username}")
151
+
152
+ st.header("Crear Nuevo Usuario Estudiante")
153
+ new_username = st.text_input("Correo electrónico del nuevo usuario", key="admin_new_username")
154
+ new_password = st.text_input("Contraseña", type="password", key="admin_new_password")
155
+ if st.button("Crear Usuario", key="admin_create_user"):
156
+ if create_student_user(new_username, new_password):
157
+ st.success(f"Usuario estudiante {new_username} creado exitosamente")
158
+ else:
159
+ st.error("Error al crear el usuario estudiante")
160
+
161
+ # Aquí puedes añadir más funcionalidades para el panel de administración
162
+
163
+ ##################################################################################################
164
+ def user_page():
165
+ # Asumimos que el idioma seleccionado está almacenado en st.session_state.lang_code
166
+ # Si no está definido, usamos 'es' como valor predeterminado
167
+ lang_code = st.session_state.get('lang_code', 'es')
168
+
169
+ translations = {
170
+ 'es': {
171
+ 'welcome': "Bienvenido a AIdeaText",
172
+ 'hello': "Hola",
173
+ 'tabs': ["Análisis Morfosintáctico", "Análisis Semántico", "Análisis del Discurso", "Chat", "Mi Progreso", "Formulario de Retroalimentación"]
174
+ },
175
+ 'en': {
176
+ 'welcome': "Welcome to AIdeaText",
177
+ 'hello': "Hello",
178
+ 'tabs': ["Morphosyntactic Analysis", "Semantic Analysis", "Discourse Analysis", "Chat", "My Progress", "Feedback Form"]
179
+ },
180
+ 'fr': {
181
+ 'welcome': "Bienvenue à AIdeaText",
182
+ 'hello': "Bonjour",
183
+ 'tabs': ["Analyse Morphosyntaxique", "Analyse Sémantique", "Analyse du Discours", "Chat", "Mon Progrès", "Formulaire de Rétroaction"]
184
+ }
185
+ }
186
+
187
+ t = translations[lang_code]
188
+
189
+ st.title(t['welcome'])
190
+ st.write(f"{t['hello']}, {st.session_state.username}")
191
+
192
+ tabs = st.tabs(t['tabs'])
193
+
194
+ with tabs[0]:
195
+ display_morphosyntax_analysis_interface(nlp_models, lang_code)
196
+ with tabs[1]:
197
+ display_semantic_analysis_interface(nlp_models, lang_code)
198
+ with tabs[2]:
199
+ display_discourse_analysis_interface(nlp_models, lang_code)
200
+ with tabs[3]:
201
+ display_chatbot_interface(lang_code)
202
+ with tabs[4]:
203
+ display_student_progress(st.session_state.username, lang_code)
204
+ with tabs[5]:
205
+ display_feedback_form(lang_code)
206
+
207
+ ##################################################################################################
208
+ def display_videos_and_info():
209
+ st.header("Videos: pitch, demos, entrevistas, otros")
210
+
211
+ videos = {
212
+ "Intro AideaText": "https://www.youtube.com/watch?v=UA-md1VxaRc",
213
+ "Presentación fundación Ser Maaestro": "https://www.youtube.com/watch?v=imc4TI1q164",
214
+ "Pitch IFE Explora": "https://www.youtube.com/watch?v=Fqi4Di_Rj_s",
215
+ "Entrevista Dr. Guillermo Ruíz": "https://www.youtube.com/watch?v=_ch8cRja3oc",
216
+ "Demo versión desktop": "https://www.youtube.com/watch?v=nP6eXbog-ZY"
217
+ }
218
+
219
+ selected_title = st.selectbox("Selecciona un video tutorial:", list(videos.keys()))
220
+
221
+ if selected_title in videos:
222
+ try:
223
+ st_player(videos[selected_title])
224
+ except Exception as e:
225
+ st.error(f"Error al cargar el video: {str(e)}")
226
+
227
+ st.markdown("""
228
+ ## Novedades de la versión actual
229
+ - Nueva función de análisis semántico
230
+ - Soporte para múltiples idiomas
231
+ - Interfaz mejorada para una mejor experiencia de usuario
232
+ """)
233
+
234
+ ##################################################################################################
235
+ def register_form():
236
+ st.header("Solicitar prueba de la aplicación")
237
+
238
+ name = st.text_input("Nombre completo")
239
+ email = st.text_input("Correo electrónico institucional")
240
+ institution = st.text_input("Institución")
241
+ role = st.selectbox("Rol", ["Estudiante", "Profesor", "Investigador", "Otro"])
242
+ reason = st.text_area("¿Por qué estás interesado en probar AIdeaText?")
243
+
244
+ if st.button("Enviar solicitud"):
245
+ logger.info(f"Attempting to submit application for {email}")
246
+ logger.debug(f"Form data: name={name}, email={email}, institution={institution}, role={role}, reason={reason}")
247
+
248
+ if not name or not email or not institution or not reason:
249
+ logger.warning("Incomplete form submission")
250
+ st.error("Por favor, completa todos los campos.")
251
+ elif not is_institutional_email(email):
252
+ logger.warning(f"Non-institutional email used: {email}")
253
+ st.error("Por favor, utiliza un correo electrónico institucional.")
254
+ else:
255
+ logger.info(f"Attempting to store application for {email}")
256
+ success = store_application_request(name, email, institution, role, reason)
257
+ if success:
258
+ st.success("Tu solicitud ha sido enviada. Te contactaremos pronto.")
259
+ logger.info(f"Application request stored successfully for {email}")
260
+ else:
261
+ st.error("Hubo un problema al enviar tu solicitud. Por favor, intenta de nuevo más tarde.")
262
+ logger.error(f"Failed to store application request for {email}")
263
+
264
+ ################################################################################
265
+ def display_feedback_form(lang_code):
266
+ logging.info(f"display_feedback_form called with lang_code: {lang_code}")
267
+ translations = {
268
+ 'es': {
269
+ 'title': "Formulario de Retroalimentación",
270
+ 'name': "Nombre",
271
+ 'email': "Correo electrónico",
272
+ 'feedback': "Tu retroalimentación",
273
+ 'submit': "Enviar",
274
+ 'success': "¡Gracias por tu retroalimentación!",
275
+ 'error': "Hubo un problema al enviar el formulario. Por favor, intenta de nuevo."
276
+ },
277
+ 'en': {
278
+ 'title': "Feedback Form",
279
+ 'name': "Name",
280
+ 'email': "Email",
281
+ 'feedback': "Your feedback",
282
+ 'submit': "Submit",
283
+ 'success': "Thank you for your feedback!",
284
+ 'error': "There was a problem submitting the form. Please try again."
285
+ },
286
+ 'fr': {
287
+ 'title': "Formulaire de Rétroaction",
288
+ 'name': "Nom",
289
+ 'email': "Adresse e-mail",
290
+ 'feedback': "Votre rétroaction",
291
+ 'submit': "Envoyer",
292
+ 'success': "Merci pour votre rétroaction !",
293
+ 'error': "Un problème est survenu lors de l'envoi du formulaire. Veuillez réessayer."
294
+ }
295
+ }
296
+
297
+ t = translations[lang_code]
298
+
299
+ st.header(t['title'])
300
+
301
+ name = st.text_input(t['name'])
302
+ email = st.text_input(t['email'])
303
+ feedback = st.text_area(t['feedback'])
304
+
305
+ if st.button(t['submit']):
306
+ if name and email and feedback:
307
+ if store_user_feedback(st.session_state.username, name, email, feedback):
308
+ st.success(t['success'])
309
+ else:
310
+ st.error(t['error'])
311
+ else:
312
+ st.warning("Por favor, completa todos los campos.")
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
+ def display_student_progress(username, lang_code='es'):
321
+ student_data = get_student_data(username)
322
+
323
+ if student_data is None or len(student_data['entries']) == 0:
324
+ st.warning("No se encontraron datos para este estudiante.")
325
+ st.info("Intenta realizar algunos análisis de texto primero.")
326
+ return
327
+
328
+ st.title(f"Progreso de {username}")
329
+
330
+ with st.expander("Resumen de Actividades y Progreso", expanded=True):
331
+ # Resumen de actividades
332
+ total_entries = len(student_data['entries'])
333
+ st.write(f"Total de análisis realizados: {total_entries}")
334
+
335
+ # Gráfico de tipos de análisis
336
+ analysis_types = [entry['analysis_type'] for entry in student_data['entries']]
337
+ analysis_counts = pd.Series(analysis_types).value_counts()
338
+
339
+ fig, ax = plt.subplots()
340
+ analysis_counts.plot(kind='bar', ax=ax)
341
+ ax.set_title("Tipos de análisis realizados")
342
+ ax.set_xlabel("Tipo de análisis")
343
+ ax.set_ylabel("Cantidad")
344
+ st.pyplot(fig)
345
+
346
+ # Progreso a lo largo del tiempo
347
+ dates = [datetime.fromisoformat(entry['timestamp']) for entry in student_data['entries']]
348
+ analysis_counts = pd.Series(dates).value_counts().sort_index()
349
+
350
+ fig, ax = plt.subplots()
351
+ analysis_counts.plot(kind='line', ax=ax)
352
+ ax.set_title("Análisis realizados a lo largo del tiempo")
353
+ ax.set_xlabel("Fecha")
354
+ ax.set_ylabel("Cantidad de análisis")
355
+ st.pyplot(fig)
356
+
357
+ ##########################################################
358
+ with st.expander("Histórico de Análisis Morfosintácticos"):
359
+ morphosyntax_entries = [entry for entry in student_data['entries'] if entry['analysis_type'] == 'morphosyntax']
360
+ for entry in morphosyntax_entries:
361
+ st.subheader(f"Análisis del {entry['timestamp']}")
362
+ if entry['arc_diagrams']:
363
+ st.write(entry['arc_diagrams'][0], unsafe_allow_html=True)
364
+
365
+
366
+ ##########################################################
367
+ with st.expander("Histórico de Análisis Semánticos"):
368
+ semantic_entries = [entry for entry in student_data['entries'] if entry['analysis_type'] == 'semantic']
369
+ st.write(f"Número total de entradas semánticas: {len(semantic_entries)}")
370
+ for entry in semantic_entries:
371
+ st.subheader(f"Análisis del {entry['timestamp']}")
372
+ st.write(f"Archivo analizado: {entry.get('filename', 'Nombre no disponible')}")
373
+ st.write(f"Claves disponibles en esta entrada: {', '.join(entry.keys())}")
374
+
375
+ # Verificar si 'relations_graph' está en entry antes de intentar acceder
376
+ if 'network_diagram' in entry:
377
+ try:
378
+ logger.info(f"Longitud de la imagen recuperada: {len(entry['network_diagram'])}")
379
+ st.image(f"data:image/png;base64,{entry['network_diagram']}")
380
+ except Exception as e:
381
+ st.error(f"No se pudo mostrar la imagen: {str(e)}")
382
+ st.write("Datos de la imagen (para depuración):")
383
+ st.write(entry['network_diagram'][:100] + "...")
384
+ else:
385
+ logger.warning(f"No se encontró 'relations_graph' en la entrada: {entry.keys()}")
386
+ st.write("No se encontró el gráfico para este análisis.")
387
+
388
+ ##########################################################
389
+ with st.expander("Histórico de Análisis Discursivos"):
390
+ discourse_entries = [entry for entry in student_data['entries'] if entry['analysis_type'] == 'discourse']
391
+ for entry in discourse_entries:
392
+ st.subheader(f"Análisis del {entry['timestamp']}")
393
+ st.write(f"Archivo patrón: {entry.get('filename1', 'Nombre no disponible')}")
394
+ st.write(f"Archivo comparado: {entry.get('filename2', 'Nombre no disponible')}")
395
+
396
+ try:
397
+ # Intentar obtener y combinar las dos imágenes
398
+ if 'graph1' in entry and 'graph2' in entry:
399
+ img1 = Image.open(BytesIO(base64.b64decode(entry['graph1'])))
400
+ img2 = Image.open(BytesIO(base64.b64decode(entry['graph2'])))
401
+
402
+ # Crear una nueva imagen combinada
403
+ total_width = img1.width + img2.width
404
+ max_height = max(img1.height, img2.height)
405
+ combined_img = Image.new('RGB', (total_width, max_height))
406
+
407
+ # Pegar las dos imágenes lado a lado
408
+ combined_img.paste(img1, (0, 0))
409
+ combined_img.paste(img2, (img1.width, 0))
410
+
411
+ # Convertir la imagen combinada a bytes
412
+ buffered = BytesIO()
413
+ combined_img.save(buffered, format="PNG")
414
+ img_str = base64.b64encode(buffered.getvalue()).decode()
415
+
416
+ # Mostrar la imagen combinada
417
+ st.image(f"data:image/png;base64,{img_str}")
418
+ elif 'combined_graph' in entry:
419
+ # Si ya existe una imagen combinada, mostrarla directamente
420
+ img_bytes = base64.b64decode(entry['combined_graph'])
421
+ st.image(img_bytes)
422
+ else:
423
+ st.write("No se encontraron gráficos para este análisis.")
424
+ except Exception as e:
425
+ st.error(f"No se pudieron mostrar los gráficos: {str(e)}")
426
+ st.write("Datos de los gráficos (para depuración):")
427
+ if 'graph1' in entry:
428
+ st.write("Graph 1:", entry['graph1'][:100] + "...")
429
+ if 'graph2' in entry:
430
+ st.write("Graph 2:", entry['graph2'][:100] + "...")
431
+ if 'combined_graph' in entry:
432
+ st.write("Combined Graph:", entry['combined_graph'][:100] + "...")
433
+
434
+
435
+ ##########################################################
436
+ with st.expander("Histórico de Conversaciones con el ChatBot"):
437
+ if 'chat_history' in student_data:
438
+ for i, chat in enumerate(student_data['chat_history']):
439
+ st.subheader(f"Conversación {i+1} - {chat['timestamp']}")
440
+ for message in chat['messages']:
441
+ if message['role'] == 'user':
442
+ st.write("Usuario: " + message['content'])
443
+ else:
444
+ st.write("Asistente: " + message['content'])
445
+ st.write("---")
446
+ else:
447
+ st.write("No se encontraron conversaciones con el ChatBot.")
448
+
449
+ # Añadir logs para depuración
450
+ if st.checkbox("Mostrar datos de depuración"):
451
+ st.write("Datos del estudiante (para depuración):")
452
+ st.json(student_data)
453
+
454
+ ##################################################################################################
455
+ def display_morphosyntax_analysis_interface(nlp_models, lang_code):
456
+ translations = {
457
+ 'es': {
458
+ 'title': "AIdeaText - Análisis morfológico y sintáctico",
459
+ 'input_label': "Ingrese un texto para analizar (máximo 5,000 palabras",
460
+ 'input_placeholder': "Esta funcionalidad le ayudará con dos competencias:\n"
461
+ "[1] \"Escribe diversos tipos de textos en su lengua materna\"\n"
462
+ "[2] \"Lee diversos tipos de textos escritos en su lengua materna\"\n\n"
463
+ "Ingrese su texto aquí para analizar...",
464
+ 'analyze_button': "Analizar texto",
465
+ 'repeated_words': "Palabras repetidas",
466
+ 'legend': "Leyenda: Categorías gramaticales",
467
+ 'arc_diagram': "Análisis sintáctico: Diagrama de arco",
468
+ 'sentence': "Oración",
469
+ 'success_message': "Análisis guardado correctamente.",
470
+ 'error_message': "Hubo un problema al guardar el análisis. Por favor, inténtelo de nuevo.",
471
+ 'warning_message': "Por favor, ingrese un texto para analizar.",
472
+ 'initial_message': "Ingrese un texto y presione 'Analizar texto' para comenzar.",
473
+ 'no_results': "No hay resultados disponibles. Por favor, realice un análisis primero.",
474
+ 'pos_analysis': "Análisis de categorías gramaticales",
475
+ 'morphological_analysis': "Análisis morfológico",
476
+ 'sentence_structure': "Estructura de oraciones",
477
+ 'word': "Palabra",
478
+ 'count': "Cantidad",
479
+ 'percentage': "Porcentaje",
480
+ 'examples': "Ejemplos",
481
+ 'lemma': "Lema",
482
+ 'tag': "Etiqueta",
483
+ 'dep': "Dependencia",
484
+ 'morph': "Morfología",
485
+ 'root': "Raíz",
486
+ 'subjects': "Sujetos",
487
+ 'objects': "Objetos",
488
+ 'verbs': "Verbos",
489
+ 'grammatical_category': "Categoría gramatical",
490
+ 'dependency': "Dependencia",
491
+ 'morphology': "Morfología"
492
+ },
493
+ 'en': {
494
+ 'title': "AIdeaText - Morphological and Syntactic Analysis",
495
+ 'input_label': "Enter a text to analyze (max 5,000 words):",
496
+ 'input_placeholder': "This functionality will help you with two competencies:\n"
497
+ "[1] \"Write various types of texts in your native language\"\n"
498
+ "[2] \"Read various types of written texts in your native language\"\n\n"
499
+ "Enter your text here to analyze...",
500
+ 'analyze_button': "Analyze text",
501
+ 'repeated_words': "Repeated words",
502
+ 'legend': "Legend: Grammatical categories",
503
+ 'arc_diagram': "Syntactic analysis: Arc diagram",
504
+ 'sentence': "Sentence",
505
+ 'success_message': "Analysis saved successfully.",
506
+ 'error_message': "There was a problem saving the analysis. Please try again.",
507
+ 'warning_message': "Please enter a text to analyze.",
508
+ 'initial_message': "Enter a text and press 'Analyze text' to start.",
509
+ 'no_results': "No results available. Please perform an analysis first.",
510
+ 'pos_analysis': "Part of Speech Analysis",
511
+ 'morphological_analysis': "Morphological Analysis",
512
+ 'sentence_structure': "Sentence Structure",
513
+ 'word': "Word",
514
+ 'count': "Count",
515
+ 'percentage': "Percentage",
516
+ 'examples': "Examples",
517
+ 'lemma': "Lemma",
518
+ 'tag': "Tag",
519
+ 'dep': "Dependency",
520
+ 'morph': "Morphology",
521
+ 'root': "Root",
522
+ 'subjects': "Subjects",
523
+ 'objects': "Objects",
524
+ 'verbs': "Verbs",
525
+ 'grammatical_category': "Grammatical category",
526
+ 'dependency': "Dependency",
527
+ 'morphology': "Morphology"
528
+ },
529
+ 'fr': {
530
+ 'title': "AIdeaText - Analyse morphologique et syntaxique",
531
+ 'input_label': "Entrez un texte à analyser (max 5 000 mots) :",
532
+ 'input_placeholder': "Cette fonctionnalité vous aidera avec deux compétences :\n"
533
+ "[1] \"Écrire divers types de textes dans votre langue maternelle\"\n"
534
+ "[2] \"Lire divers types de textes écrits dans votre langue maternelle\"\n\n"
535
+ "Entrez votre texte ici pour l'analyser...",
536
+ 'analyze_button': "Analyser le texte",
537
+ 'repeated_words': "Mots répétés",
538
+ 'legend': "Légende : Catégories grammaticales",
539
+ 'arc_diagram': "Analyse syntaxique : Diagramme en arc",
540
+ 'sentence': "Phrase",
541
+ 'success_message': "Analyse enregistrée avec succès.",
542
+ 'error_message': "Un problème est survenu lors de l'enregistrement de l'analyse. Veuillez réessayer.",
543
+ 'warning_message': "Veuillez entrer un texte à analyser.",
544
+ 'initial_message': "Entrez un texte et appuyez sur 'Analyser le texte' pour commencer.",
545
+ 'no_results': "Aucun résultat disponible. Veuillez d'abord effectuer une analyse.",
546
+ 'pos_analysis': "Analyse des parties du discours",
547
+ 'morphological_analysis': "Analyse morphologique",
548
+ 'sentence_structure': "Structure des phrases",
549
+ 'word': "Mot",
550
+ 'count': "Nombre",
551
+ 'percentage': "Pourcentage",
552
+ 'examples': "Exemples",
553
+ 'lemma': "Lemme",
554
+ 'tag': "Étiquette",
555
+ 'dep': "Dépendance",
556
+ 'morph': "Morphologie",
557
+ 'root': "Racine",
558
+ 'subjects': "Sujets",
559
+ 'objects': "Objets",
560
+ 'verbs': "Verbes",
561
+ 'grammatical_category': "Catégorie grammaticale",
562
+ 'dependency': "Dépendance",
563
+ 'morphology': "Morphologie"
564
+ }
565
+ }
566
+
567
+ t = translations[lang_code]
568
+
569
+ input_key = f"morphosyntax_input_{lang_code}"
570
+
571
+ if input_key not in st.session_state:
572
+ st.session_state[input_key] = ""
573
+
574
+ sentence_input = st.text_area(
575
+ t['input_label'],
576
+ height=150,
577
+ placeholder=t['input_placeholder'],
578
+ value=st.session_state[input_key],
579
+ key=f"text_area_{lang_code}",
580
+ on_change=lambda: setattr(st.session_state, input_key, st.session_state[f"text_area_{lang_code}"])
581
+ )
582
+
583
+ if st.button(t['analyze_button'], key=f"analyze_button_{lang_code}"):
584
+ current_input = st.session_state[input_key]
585
+ if current_input:
586
+ doc = nlp_models[lang_code](current_input)
587
+
588
+ # Análisis morfosintáctico avanzado
589
+ advanced_analysis = perform_advanced_morphosyntactic_analysis(current_input, nlp_models[lang_code])
590
+
591
+ # Guardar el resultado en el estado de la sesión
592
+ st.session_state.morphosyntax_result = {
593
+ 'doc': doc,
594
+ 'advanced_analysis': advanced_analysis
595
+ }
596
+
597
+ # Mostrar resultados
598
+ display_morphosyntax_results(st.session_state.morphosyntax_result, lang_code, t)
599
+
600
+ # Guardar resultados
601
+ if store_morphosyntax_result(
602
+ st.session_state.username,
603
+ current_input,
604
+ get_repeated_words_colors(doc),
605
+ advanced_analysis['arc_diagram'],
606
+ advanced_analysis['pos_analysis'],
607
+ advanced_analysis['morphological_analysis'],
608
+ advanced_analysis['sentence_structure']
609
+ ):
610
+ st.success(t['success_message'])
611
+ else:
612
+ st.error(t['error_message'])
613
+ else:
614
+ st.warning(t['warning_message'])
615
+ elif 'morphosyntax_result' in st.session_state and st.session_state.morphosyntax_result is not None:
616
+
617
+ # Si hay un resultado guardado, mostrarlo
618
+ display_morphosyntax_results(st.session_state.morphosyntax_result, lang_code, t)
619
+ else:
620
+ st.info(t['initial_message']) # Añade esta traducción a tu diccionario
621
+
622
+ def display_morphosyntax_results(result, lang_code, t):
623
+ if result is None:
624
+ st.warning(t['no_results']) # Añade esta traducción a tu diccionario
625
+ return
626
+
627
+ doc = result['doc']
628
+ advanced_analysis = result['advanced_analysis']
629
+
630
+ # Mostrar leyenda (código existente)
631
+ st.markdown(f"##### {t['legend']}")
632
+ legend_html = "<div style='display: flex; flex-wrap: wrap;'>"
633
+ for pos, color in POS_COLORS.items():
634
+ if pos in POS_TRANSLATIONS[lang_code]:
635
+ legend_html += f"<div style='margin-right: 10px;'><span style='background-color: {color}; padding: 2px 5px;'>{POS_TRANSLATIONS[lang_code][pos]}</span></div>"
636
+ legend_html += "</div>"
637
+ st.markdown(legend_html, unsafe_allow_html=True)
638
+
639
+ # Mostrar análisis de palabras repetidas (código existente)
640
+ word_colors = get_repeated_words_colors(doc)
641
+ with st.expander(t['repeated_words'], expanded=True):
642
+ highlighted_text = highlight_repeated_words(doc, word_colors)
643
+ st.markdown(highlighted_text, unsafe_allow_html=True)
644
+
645
+ # Mostrar estructura de oraciones
646
+ with st.expander(t['sentence_structure'], expanded=True):
647
+ for i, sent_analysis in enumerate(advanced_analysis['sentence_structure']):
648
+ sentence_str = (
649
+ f"**{t['sentence']} {i+1}** "
650
+ f"{t['root']}: {sent_analysis['root']} ({sent_analysis['root_pos']}) -- "
651
+ f"{t['subjects']}: {', '.join(sent_analysis['subjects'])} -- "
652
+ f"{t['objects']}: {', '.join(sent_analysis['objects'])} -- "
653
+ f"{t['verbs']}: {', '.join(sent_analysis['verbs'])}"
654
+ )
655
+ st.markdown(sentence_str)
656
+
657
+ # Mostrar análisis de categorías gramaticales # Mostrar análisis morfológico
658
+ col1, col2 = st.columns(2)
659
+
660
+ with col1:
661
+ with st.expander(t['pos_analysis'], expanded=True):
662
+ pos_df = pd.DataFrame(advanced_analysis['pos_analysis'])
663
+
664
+ # Traducir las etiquetas POS a sus nombres en el idioma seleccionado
665
+ pos_df['pos'] = pos_df['pos'].map(lambda x: POS_TRANSLATIONS[lang_code].get(x, x))
666
+
667
+ # Renombrar las columnas para mayor claridad
668
+ pos_df = pos_df.rename(columns={
669
+ 'pos': t['grammatical_category'],
670
+ 'count': t['count'],
671
+ 'percentage': t['percentage'],
672
+ 'examples': t['examples']
673
+ })
674
+
675
+ # Mostrar el dataframe
676
+ st.dataframe(pos_df)
677
+
678
+ with col2:
679
+ with st.expander(t['morphological_analysis'], expanded=True):
680
+ morph_df = pd.DataFrame(advanced_analysis['morphological_analysis'])
681
+
682
+ # Definir el mapeo de columnas
683
+ column_mapping = {
684
+ 'text': t['word'],
685
+ 'lemma': t['lemma'],
686
+ 'pos': t['grammatical_category'],
687
+ 'dep': t['dependency'],
688
+ 'morph': t['morphology']
689
+ }
690
+
691
+ # Renombrar las columnas existentes
692
+ morph_df = morph_df.rename(columns={col: new_name for col, new_name in column_mapping.items() if col in morph_df.columns})
693
+
694
+ # Traducir las categorías gramaticales
695
+ morph_df[t['grammatical_category']] = morph_df[t['grammatical_category']].map(lambda x: POS_TRANSLATIONS[lang_code].get(x, x))
696
+
697
+ # Traducir las dependencias
698
+ dep_translations = {
699
+ 'es': {
700
+ 'ROOT': 'RAÍZ', 'nsubj': 'sujeto nominal', 'obj': 'objeto', 'iobj': 'objeto indirecto',
701
+ 'csubj': 'sujeto clausal', 'ccomp': 'complemento clausal', 'xcomp': 'complemento clausal abierto',
702
+ 'obl': 'oblicuo', 'vocative': 'vocativo', 'expl': 'expletivo', 'dislocated': 'dislocado',
703
+ 'advcl': 'cláusula adverbial', 'advmod': 'modificador adverbial', 'discourse': 'discurso',
704
+ 'aux': 'auxiliar', 'cop': 'cópula', 'mark': 'marcador', 'nmod': 'modificador nominal',
705
+ 'appos': 'aposición', 'nummod': 'modificador numeral', 'acl': 'cláusula adjetiva',
706
+ 'amod': 'modificador adjetival', 'det': 'determinante', 'clf': 'clasificador',
707
+ 'case': 'caso', 'conj': 'conjunción', 'cc': 'coordinante', 'fixed': 'fijo',
708
+ 'flat': 'plano', 'compound': 'compuesto', 'list': 'lista', 'parataxis': 'parataxis',
709
+ 'orphan': 'huérfano', 'goeswith': 'va con', 'reparandum': 'reparación', 'punct': 'puntuación'
710
+ },
711
+ 'en': {
712
+ 'ROOT': 'ROOT', 'nsubj': 'nominal subject', 'obj': 'object',
713
+ 'iobj': 'indirect object', 'csubj': 'clausal subject', 'ccomp': 'clausal complement', 'xcomp': 'open clausal complement',
714
+ 'obl': 'oblique', 'vocative': 'vocative', 'expl': 'expletive', 'dislocated': 'dislocated', 'advcl': 'adverbial clause modifier',
715
+ 'advmod': 'adverbial modifier', 'discourse': 'discourse element', 'aux': 'auxiliary', 'cop': 'copula', 'mark': 'marker',
716
+ 'nmod': 'nominal modifier', 'appos': 'appositional modifier', 'nummod': 'numeric modifier', 'acl': 'clausal modifier of noun',
717
+ 'amod': 'adjectival modifier', 'det': 'determiner', 'clf': 'classifier', 'case': 'case marking',
718
+ 'conj': 'conjunct', 'cc': 'coordinating conjunction', 'fixed': 'fixed multiword expression',
719
+ 'flat': 'flat multiword expression', 'compound': 'compound', 'list': 'list', 'parataxis': 'parataxis', 'orphan': 'orphan',
720
+ 'goeswith': 'goes with', 'reparandum': 'reparandum', 'punct': 'punctuation'
721
+ },
722
+ 'fr': {
723
+ 'ROOT': 'RACINE', 'nsubj': 'sujet nominal', 'obj': 'objet', 'iobj': 'objet indirect',
724
+ 'csubj': 'sujet phrastique', 'ccomp': 'complément phrastique', 'xcomp': 'complément phrastique ouvert', 'obl': 'oblique',
725
+ 'vocative': 'vocatif', 'expl': 'explétif', 'dislocated': 'disloqué', 'advcl': 'clause adverbiale', 'advmod': 'modifieur adverbial',
726
+ 'discourse': 'élément de discours', 'aux': 'auxiliaire', 'cop': 'copule', 'mark': 'marqueur', 'nmod': 'modifieur nominal',
727
+ 'appos': 'apposition', 'nummod': 'modifieur numéral', 'acl': 'clause relative', 'amod': 'modifieur adjectival', 'det': 'déterminant',
728
+ 'clf': 'classificateur', 'case': 'marqueur de cas', 'conj': 'conjonction', 'cc': 'coordination', 'fixed': 'expression figée',
729
+ 'flat': 'construction plate', 'compound': 'composé', 'list': 'liste', 'parataxis': 'parataxe', 'orphan': 'orphelin',
730
+ 'goeswith': 'va avec', 'reparandum': 'réparation', 'punct': 'ponctuation'
731
+ }
732
+ }
733
+ morph_df[t['dependency']] = morph_df[t['dependency']].map(lambda x: dep_translations[lang_code].get(x, x))
734
+
735
+ # Traducir la morfología
736
+ def translate_morph(morph_string, lang_code):
737
+ morph_translations = {
738
+ 'es': {
739
+ 'Gender': 'Género', 'Number': 'Número', 'Case': 'Caso', 'Definite': 'Definido',
740
+ 'PronType': 'Tipo de Pronombre', 'Person': 'Persona', 'Mood': 'Modo',
741
+ 'Tense': 'Tiempo', 'VerbForm': 'Forma Verbal', 'Voice': 'Voz',
742
+ 'Fem': 'Femenino', 'Masc': 'Masculino', 'Sing': 'Singular', 'Plur': 'Plural',
743
+ 'Ind': 'Indicativo', 'Sub': 'Subjuntivo', 'Imp': 'Imperativo', 'Inf': 'Infinitivo',
744
+ 'Part': 'Participio', 'Ger': 'Gerundio', 'Pres': 'Presente', 'Past': 'Pasado',
745
+ 'Fut': 'Futuro', 'Perf': 'Perfecto', 'Imp': 'Imperfecto'
746
+ },
747
+ 'en': {
748
+ 'Gender': 'Gender', 'Number': 'Number', 'Case': 'Case', 'Definite': 'Definite', 'PronType': 'Pronoun Type', 'Person': 'Person',
749
+ 'Mood': 'Mood', 'Tense': 'Tense', 'VerbForm': 'Verb Form', 'Voice': 'Voice',
750
+ 'Fem': 'Feminine', 'Masc': 'Masculine', 'Sing': 'Singular', 'Plur': 'Plural', 'Ind': 'Indicative',
751
+ 'Sub': 'Subjunctive', 'Imp': 'Imperative', 'Inf': 'Infinitive', 'Part': 'Participle',
752
+ 'Ger': 'Gerund', 'Pres': 'Present', 'Past': 'Past', 'Fut': 'Future', 'Perf': 'Perfect', 'Imp': 'Imperfect'
753
+ },
754
+ 'fr': {
755
+ 'Gender': 'Genre', 'Number': 'Nombre', 'Case': 'Cas', 'Definite': 'Défini', 'PronType': 'Type de Pronom',
756
+ 'Person': 'Personne', 'Mood': 'Mode', 'Tense': 'Temps', 'VerbForm': 'Forme Verbale', 'Voice': 'Voix',
757
+ 'Fem': 'Féminin', 'Masc': 'Masculin', 'Sing': 'Singulier', 'Plur': 'Pluriel', 'Ind': 'Indicatif',
758
+ 'Sub': 'Subjonctif', 'Imp': 'Impératif', 'Inf': 'Infinitif', 'Part': 'Participe',
759
+ 'Ger': 'Gérondif', 'Pres': 'Présent', 'Past': 'Passé', 'Fut': 'Futur', 'Perf': 'Parfait', 'Imp': 'Imparfait'
760
+ }
761
+ }
762
+ for key, value in morph_translations[lang_code].items():
763
+ morph_string = morph_string.replace(key, value)
764
+ return morph_string
765
+
766
+ morph_df[t['morphology']] = morph_df[t['morphology']].apply(lambda x: translate_morph(x, lang_code))
767
+
768
+ # Seleccionar y ordenar las columnas a mostrar
769
+ columns_to_display = [t['word'], t['lemma'], t['grammatical_category'], t['dependency'], t['morphology']]
770
+ columns_to_display = [col for col in columns_to_display if col in morph_df.columns]
771
+
772
+ # Mostrar el DataFrame
773
+ st.dataframe(morph_df[columns_to_display])
774
+
775
+ # Mostrar diagramas de arco (código existente)
776
+ with st.expander(t['arc_diagram'], expanded=True):
777
+ sentences = list(doc.sents)
778
+ arc_diagrams = []
779
+ for i, sent in enumerate(sentences):
780
+ st.subheader(f"{t['sentence']} {i+1}")
781
+ html = displacy.render(sent, style="dep", options={"distance": 100})
782
+ html = html.replace('height="375"', 'height="200"')
783
+ html = re.sub(r'<svg[^>]*>', lambda m: m.group(0).replace('height="450"', 'height="300"'), html)
784
+ html = re.sub(r'<g [^>]*transform="translate\((\d+),(\d+)\)"', lambda m: f'<g transform="translate({m.group(1)},50)"', html)
785
+ st.write(html, unsafe_allow_html=True)
786
+ arc_diagrams.append(html)
787
+
788
+ ###############################################################################################################
789
+ def display_semantic_analysis_interface(nlp_models, lang_code):
790
+ translations = {
791
+ 'es': {
792
+ 'title': "AIdeaText - Análisis semántico",
793
+ 'text_input_label': "Ingrese un texto para analizar (máx. 5,000 palabras):",
794
+ 'text_input_placeholder': "El objetivo de esta aplicación es que mejore sus habilidades de redacción...",
795
+ 'file_uploader': "O cargue un archivo de texto",
796
+ 'analyze_button': "Analizar texto",
797
+ 'conceptual_relations': "Relaciones Conceptuales",
798
+ 'identified_entities': "Entidades Identificadas",
799
+ 'key_concepts': "Conceptos Clave",
800
+ 'success_message': "Análisis semántico guardado correctamente.",
801
+ 'error_message': "Hubo un problema al guardar el análisis semántico. Por favor, inténtelo de nuevo.",
802
+ 'warning_message': "Por favor, ingrese un texto o cargue un archivo para analizar.",
803
+ 'initial_message': "Ingrese un texto y presione 'Analizar texto' para comenzar.",
804
+ 'no_results': "No hay resultados disponibles. Por favor, realice un análisis primero."
805
+ },
806
+ 'en': {
807
+ 'title': "AIdeaText - Semantic Analysis",
808
+ 'text_input_label': "Enter a text to analyze (max. 5,000 words):",
809
+ 'text_input_placeholder': "The goal of this application is to improve your writing skills...",
810
+ 'file_uploader': "Or upload a text file",
811
+ 'analyze_button': "Analyze text",
812
+ 'conceptual_relations': "Conceptual Relations",
813
+ 'identified_entities': "Identified Entities",
814
+ 'key_concepts': "Key Concepts",
815
+ 'success_message': "Semantic analysis saved successfully.",
816
+ 'error_message': "There was a problem saving the semantic analysis. Please try again.",
817
+ 'warning_message': "Please enter a text or upload a file to analyze.",
818
+ 'initial_message': "Enter a text and press 'Analyze text' to start.",
819
+ 'no_results': "No results available. Please perform an analysis first."
820
+ },
821
+ 'fr': {
822
+ 'title': "AIdeaText - Analyse sémantique",
823
+ 'text_input_label': "Entrez un texte à analyser (max. 5 000 mots) :",
824
+ 'text_input_placeholder': "L'objectif de cette application est d'améliorer vos compétences en rédaction...",
825
+ 'file_uploader': "Ou téléchargez un fichier texte",
826
+ 'analyze_button': "Analyser le texte",
827
+ 'conceptual_relations': "Relations Conceptuelles",
828
+ 'identified_entities': "Entités Identifiées",
829
+ 'key_concepts': "Concepts Clés",
830
+ 'success_message': "Analyse sémantique enregistrée avec succès.",
831
+ 'error_message': "Un problème est survenu lors de l'enregistrement de l'analyse sémantique. Veuillez réessayer.",
832
+ 'warning_message': "Veuillez entrer un texte ou télécharger un fichier à analyser.",
833
+ 'initial_message': "Entrez un texte et appuyez sur 'Analyser le texte' pour commencer.",
834
+ 'no_results': "Aucun résultat disponible. Veuillez d'abord effectuer une analyse."
835
+ }
836
+ }
837
+
838
+ t = translations[lang_code]
839
+
840
+ st.header(t['title'])
841
+
842
+ # Opción para introducir texto
843
+ text_input = st.text_area(
844
+ t['text_input_label'],
845
+ height=150,
846
+ placeholder=t['text_input_placeholder'],
847
+ )
848
+
849
+ # Opción para cargar archivo
850
+ uploaded_file = st.file_uploader(t['file_uploader'], type=['txt'])
851
+
852
+ if st.button(t['analyze_button']):
853
+ if text_input or uploaded_file is not None:
854
+ if uploaded_file:
855
+ text_content = uploaded_file.getvalue().decode('utf-8')
856
+ else:
857
+ text_content = text_input
858
+
859
+ # Realizar el análisis
860
+ analysis_result = perform_semantic_analysis(text_content, nlp_models[lang_code], lang_code)
861
+
862
+ # Guardar el resultado en el estado de la sesión
863
+ st.session_state.semantic_result = analysis_result
864
+
865
+ # Mostrar resultados
866
+ display_semantic_results(st.session_state.semantic_result, lang_code, t)
867
+
868
+ # Guardar el resultado del análisis
869
+ if store_semantic_result(st.session_state.username, text_content, analysis_result):
870
+ st.success(t['success_message'])
871
+ else:
872
+ st.error(t['error_message'])
873
+ else:
874
+ st.warning(t['warning_message'])
875
+
876
+ elif 'semantic_result' in st.session_state:
877
+
878
+ # Si hay un resultado guardado, mostrarlo
879
+ display_semantic_results(st.session_state.semantic_result, lang_code, t)
880
+
881
+ else:
882
+ st.info(t['initial_message']) # Asegúrate de que 'initial_message' esté en tus traducciones
883
+
884
+ def display_semantic_results(result, lang_code, t):
885
+ if result is None:
886
+ st.warning(t['no_results']) # Asegúrate de que 'no_results' esté en tus traducciones
887
+ return
888
+
889
+ # Mostrar conceptos clave
890
+ with st.expander(t['key_concepts'], expanded=True):
891
+ concept_text = " | ".join([f"{concept} ({frequency:.2f})" for concept, frequency in result['key_concepts']])
892
+ st.write(concept_text)
893
+
894
+ # Mostrar el gráfico de relaciones conceptuales
895
+ with st.expander(t['conceptual_relations'], expanded=True):
896
+ st.pyplot(result['relations_graph'])
897
+
898
+ ##################################################################################################
899
+ def display_discourse_analysis_interface(nlp_models, lang_code):
900
+ translations = {
901
+ 'es': {
902
+ 'title': "AIdeaText - Análisis del discurso",
903
+ 'file_uploader1': "Cargar archivo de texto 1 (Patrón)",
904
+ 'file_uploader2': "Cargar archivo de texto 2 (Comparación)",
905
+ 'analyze_button': "Analizar textos",
906
+ 'comparison': "Comparación de Relaciones Semánticas",
907
+ 'success_message': "Análisis del discurso guardado correctamente.",
908
+ 'error_message': "Hubo un problema al guardar el análisis del discurso. Por favor, inténtelo de nuevo.",
909
+ 'warning_message': "Por favor, cargue ambos archivos para analizar.",
910
+ 'initial_message': "Ingrese un texto y presione 'Analizar texto' para comenzar.",
911
+ 'no_results': "No hay resultados disponibles. Por favor, realice un análisis primero.",
912
+ 'key_concepts': "Conceptos Clave",
913
+ 'graph_not_available': "El gráfico no está disponible.",
914
+ 'concepts_not_available': "Los conceptos clave no están disponibles.",
915
+ 'comparison_not_available': "La comparación no está disponible."
916
+ },
917
+ 'en': {
918
+ 'title': "AIdeaText - Discourse Analysis",
919
+ 'file_uploader1': "Upload text file 1 (Pattern)",
920
+ 'file_uploader2': "Upload text file 2 (Comparison)",
921
+ 'analyze_button': "Analyze texts",
922
+ 'comparison': "Comparison of Semantic Relations",
923
+ 'success_message': "Discourse analysis saved successfully.",
924
+ 'error_message': "There was a problem saving the discourse analysis. Please try again.",
925
+ 'warning_message': "Please upload both files to analyze.",
926
+ 'initial_message': "Enter a text and press 'Analyze text' to start.",
927
+ 'no_results': "No results available. Please perform an analysis first.",
928
+ 'key_concepts': "Key Concepts",
929
+ 'graph_not_available': "The graph is not available.",
930
+ 'concepts_not_available': "Key concepts are not available.",
931
+ 'comparison_not_available': "The comparison is not available."
932
+ },
933
+ 'fr': {
934
+ 'title': "AIdeaText - Analyse du discours",
935
+ 'file_uploader1': "Télécharger le fichier texte 1 (Modèle)",
936
+ 'file_uploader2': "Télécharger le fichier texte 2 (Comparaison)",
937
+ 'analyze_button': "Analyser les textes",
938
+ 'comparison': "Comparaison des Relations Sémantiques",
939
+ 'success_message': "Analyse du discours enregistrée avec succès.",
940
+ 'error_message': "Un problème est survenu lors de l'enregistrement de l'analyse du discours. Veuillez réessayer.",
941
+ 'warning_message': "Veuillez télécharger les deux fichiers à analyser.",
942
+ 'initial_message': "Entrez un texte et appuyez sur 'Analyser le texte' pour commencer.",
943
+ 'no_results': "Aucun résultat disponible. Veuillez d'abord effectuer une analyse.",
944
+ 'key_concepts': "Concepts Clés",
945
+ 'graph_not_available': "Le graphique n'est pas disponible.",
946
+ 'concepts_not_available': "Les concepts clés ne sont pas disponibles.",
947
+ 'comparison_not_available': "La comparaison n'est pas disponible."
948
+ }
949
+ }
950
+
951
+ t = translations[lang_code]
952
+ st.header(t['title'])
953
+
954
+ col1, col2 = st.columns(2)
955
+ with col1:
956
+ uploaded_file1 = st.file_uploader(t['file_uploader1'], type=['txt'])
957
+ with col2:
958
+ uploaded_file2 = st.file_uploader(t['file_uploader2'], type=['txt'])
959
+
960
+ if st.button(t['analyze_button']):
961
+ if uploaded_file1 is not None and uploaded_file2 is not None:
962
+ text_content1 = uploaded_file1.getvalue().decode('utf-8')
963
+ text_content2 = uploaded_file2.getvalue().decode('utf-8')
964
+
965
+ # Realizar el análisis
966
+ analysis_result = perform_discourse_analysis(text_content1, text_content2, nlp_models[lang_code], lang_code)
967
+
968
+ # Guardar el resultado en el estado de la sesión
969
+ st.session_state.discourse_result = analysis_result
970
+
971
+ # Mostrar los resultados del análisis
972
+ display_discourse_results(st.session_state.discourse_result, lang_code, t)
973
+
974
+ # Guardar el resultado del análisis
975
+ if store_discourse_analysis_result(st.session_state.username, text_content1, text_content2, analysis_result):
976
+ st.success(t['success_message'])
977
+ else:
978
+ st.error(t['error_message'])
979
+ else:
980
+ st.warning(t['warning_message'])
981
+ elif 'discourse_result' in st.session_state and st.session_state.discourse_result is not None:
982
+ # Si hay un resultado guardado, mostrarlo
983
+ display_discourse_results(st.session_state.discourse_result, lang_code, t)
984
+ else:
985
+ st.info(t['initial_message']) # Asegúrate de que 'initial_message' esté en tus traducciones
986
+
987
+ #################################################
988
+ def display_discourse_results(result, lang_code, t):
989
+ if result is None:
990
+ st.warning(t.get('no_results', "No hay resultados disponibles."))
991
+ return
992
+
993
+ col1, col2 = st.columns(2)
994
+
995
+ with col1:
996
+ with st.expander(t.get('file_uploader1', "Documento 1"), expanded=True):
997
+ if 'graph1' in result:
998
+ st.pyplot(result['graph1'])
999
+ else:
1000
+ st.warning(t.get('graph_not_available', "El gráfico no está disponible."))
1001
+ st.subheader(t.get('key_concepts', "Conceptos Clave"))
1002
+ if 'key_concepts1' in result:
1003
+ df1 = pd.DataFrame(result['key_concepts1'], columns=['Concepto', 'Frecuencia'])
1004
+ df1['Frecuencia'] = df1['Frecuencia'].round(2)
1005
+ st.table(df1)
1006
+ else:
1007
+ st.warning(t.get('concepts_not_available', "Los conceptos clave no están disponibles."))
1008
+
1009
+ with col2:
1010
+ with st.expander(t.get('file_uploader2', "Documento 2"), expanded=True):
1011
+ if 'graph2' in result:
1012
+ st.pyplot(result['graph2'])
1013
+ else:
1014
+ st.warning(t.get('graph_not_available', "El gráfico no está disponible."))
1015
+ st.subheader(t.get('key_concepts', "Conceptos Clave"))
1016
+ if 'key_concepts2' in result:
1017
+ df2 = pd.DataFrame(result['key_concepts2'], columns=['Concepto', 'Frecuencia'])
1018
+ df2['Frecuencia'] = df2['Frecuencia'].round(2)
1019
+ st.table(df2)
1020
+ else:
1021
+ st.warning(t.get('concepts_not_available', "Los conceptos clave no están disponibles."))
1022
+
1023
+ # Relación de conceptos entre ambos documentos (Diagrama de Sankey)
1024
+ st.subheader(t.get('comparison', "Relación de conceptos entre ambos documentos"))
1025
+ if 'key_concepts1' in result and 'key_concepts2' in result:
1026
+ df1 = pd.DataFrame(result['key_concepts1'], columns=['Concepto', 'Frecuencia'])
1027
+ df2 = pd.DataFrame(result['key_concepts2'], columns=['Concepto', 'Frecuencia'])
1028
+
1029
+ # Crear el diagrama de Sankey
1030
+ source = [t.get('file_uploader1', "Documento 1")] * len(df1) + [concept for concept in df1['Concepto']]
1031
+ target = [concept for concept in df1['Concepto']] + [t.get('file_uploader2', "Documento 2")] * len(df2)
1032
+ value = list(df1['Frecuencia']) + list(df2['Frecuencia'])
1033
+
1034
+ fig = go.Figure(data=[go.Sankey(
1035
+ node = dict(
1036
+ pad = 15,
1037
+ thickness = 20,
1038
+ line = dict(color = "black", width = 0.5),
1039
+ label = [t.get('file_uploader1', "Documento 1"), t.get('file_uploader2', "Documento 2")] + list(df1['Concepto']) + list(df2['Concepto']),
1040
+ color = "blue"
1041
+ ),
1042
+ link = dict(
1043
+ source = [0] * len(df1) + list(range(2, 2 + len(df1))),
1044
+ target = list(range(2, 2 + len(df1))) + [1] * len(df2),
1045
+ value = value
1046
+ ))])
1047
+
1048
+ fig.update_layout(title_text="Relación de conceptos entre documentos", font_size=10)
1049
+ st.plotly_chart(fig, use_container_width=True)
1050
+ else:
1051
+ st.warning(t.get('comparison_not_available', "La comparación no está disponible."))
1052
+
1053
+ # Aquí puedes agregar el código para mostrar los gráficos si es necesario
1054
+
1055
+ ##################################################################################################
1056
+ #def display_saved_discourse_analysis(analysis_data):
1057
+ # img_bytes = base64.b64decode(analysis_data['combined_graph'])
1058
+ # img = plt.imread(io.BytesIO(img_bytes), format='png')
1059
+
1060
+ # st.image(img, use_column_width=True)
1061
+ # st.write("Texto del documento patrón:")
1062
+ # st.write(analysis_data['text1'])
1063
+ # st.write("Texto del documento comparado:")
1064
+ # st.write(analysis_data['text2'])
1065
+
1066
+ ##################################################################################################
1067
+ def display_chatbot_interface(lang_code):
1068
+ translations = {
1069
+ 'es': {
1070
+ 'title': "Expertos en Vacaciones",
1071
+ 'input_placeholder': "Escribe tu mensaje aquí...",
1072
+ 'initial_message': "¡Hola! ¿Cómo podemos ayudarte?"
1073
+ },
1074
+ 'en': {
1075
+ 'title': "Vacation Experts",
1076
+ 'input_placeholder': "Type your message here...",
1077
+ 'initial_message': "Hi! How can we help you?"
1078
+ },
1079
+ 'fr': {
1080
+ 'title': "Experts en Vacances",
1081
+ 'input_placeholder': "Écrivez votre message ici...",
1082
+ 'initial_message': "Bonjour! Comment pouvons-nous vous aider?"
1083
+ }
1084
+ }
1085
+ t = translations[lang_code]
1086
+ st.title(t['title'])
1087
+
1088
+ if 'chatbot' not in st.session_state:
1089
+ st.session_state.chatbot = initialize_chatbot()
1090
+ if 'messages' not in st.session_state:
1091
+ st.session_state.messages = [{"role": "assistant", "content": t['initial_message']}]
1092
+
1093
+ # Contenedor principal para el chat
1094
+ chat_container = st.container()
1095
+
1096
+ # Mostrar mensajes existentes
1097
+ with chat_container:
1098
+ for message in st.session_state.messages:
1099
+ with st.chat_message(message["role"]):
1100
+ st.markdown(message["content"])
1101
+
1102
+ # Área de entrada del usuario
1103
+ user_input = st.chat_input(t['input_placeholder'])
1104
+
1105
+ if user_input:
1106
+ # Agregar mensaje del usuario
1107
+ st.session_state.messages.append({"role": "user", "content": user_input})
1108
+
1109
+ # Mostrar mensaje del usuario
1110
+ with chat_container:
1111
+ with st.chat_message("user"):
1112
+ st.markdown(user_input)
1113
+
1114
+ # Generar respuesta del chatbot
1115
+ with chat_container:
1116
+ with st.chat_message("assistant"):
1117
+ message_placeholder = st.empty()
1118
+ full_response = ""
1119
+ for chunk in get_chatbot_response(st.session_state.chatbot, user_input, lang_code):
1120
+ full_response += chunk
1121
+ message_placeholder.markdown(full_response + "▌")
1122
+ message_placeholder.markdown(full_response)
1123
+
1124
+ # Agregar respuesta del asistente a los mensajes
1125
+ st.session_state.messages.append({"role": "assistant", "content": full_response})
1126
+
1127
+ # Guardar la conversación en la base de datos
1128
+ try:
1129
+ store_chat_history(st.session_state.username, st.session_state.messages)
1130
+ st.success("Conversación guardada exitosamente")
1131
+ except Exception as e:
1132
+ st.error(f"Error al guardar la conversación: {str(e)}")
1133
+ logger.error(f"Error al guardar el historial de chat para {st.session_state.username}: {str(e)}")
1134
+
1135
+ # Scroll al final del chat
1136
+ st.markdown('<script>window.scrollTo(0,document.body.scrollHeight);</script>', unsafe_allow_html=True)
1137
+
1138
+ ######################################################
1139
+ if __name__ == "__main__":
1140
+ main()