AIdeaText commited on
Commit
43b713a
·
verified ·
2 Parent(s): 3811fd3 57368d8

Merge branch #AIdeaText/test' into 'AIdeaText/test2'

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