# Importaciones generales
import sys
import streamlit as st
from translations import get_translations
import re
import io
from io import BytesIO
import base64
import matplotlib.pyplot as plt
import plotly.graph_objects as go
import pandas as pd
import numpy as np
import time
from datetime import datetime
from streamlit_player import st_player # Necesitarás instalar esta librería: pip install streamlit-player
from spacy import displacy
import logging
import random
######################################################
# Configuración del logger
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
######################################################
# Importaciones locales
from ..email.email import send_email_notification
######################################################
# Importaciones locales de autenticación y base de datos
from ..auth.auth import (
authenticate_user,
register_user
)
######################################################
from ..database.database_oldFromV2 import (
create_admin_user,
create_student_user,
get_user,
get_student_data,
store_file_contents, #gestión archivos
retrieve_file_contents, #gestión archivos
get_user_files, #gestión archivos
delete_file, # #gestión archivos
store_application_request, # form
store_user_feedback, # form
store_morphosyntax_result,
store_semantic_result,
store_discourse_analysis_result,
store_chat_history,
export_analysis_and_chat
)
######################################################
# Importaciones locales de uiadmin
from ..admin.admin_ui import admin_page
######################################################
# Importaciones locales funciones de análisis
from ..text_analysis.morpho_analysis import (
generate_arc_diagram,
get_repeated_words_colors,
highlight_repeated_words,
POS_COLORS,
POS_TRANSLATIONS,
perform_advanced_morphosyntactic_analysis
)
######################################################
from ..text_analysis.semantic_analysis import (
#visualize_semantic_relations,
perform_semantic_analysis,
create_concept_graph,
visualize_concept_graph
)
######################################################
from ..text_analysis.discourse_analysis import (
perform_discourse_analysis,
display_discourse_analysis_results
)
######################################################
from ..chatbot.chatbot import (
initialize_chatbot,
process_morphosyntactic_input,
process_semantic_input,
process_discourse_input,
process_chat_input,
get_connectors,
handle_semantic_commands,
generate_topics_visualization,
extract_topics,
get_semantic_chatbot_response
)
#####################-- Funciones de inicialización y configuración--- ##############################################################################
def initialize_session_state():
if 'initialized' not in st.session_state:
st.session_state.clear()
st.session_state.initialized = True
st.session_state.logged_in = False
st.session_state.page = 'login'
st.session_state.username = None
st.session_state.role = None
def main():
initialize_session_state()
print(f"Página actual: {st.session_state.page}")
print(f"Rol del usuario: {st.session_state.role}")
if st.session_state.page == 'login':
login_register_page()
elif st.session_state.page == 'admin':
print("Intentando mostrar página de admin")
admin_page()
elif st.session_state.page == 'user':
user_page()
else:
print(f"Página no reconocida: {st.session_state.page}")
print(f"Estado final de la sesión: {st.session_state}")
#############################--- # Funciones de autenticación y registro --- #####################################################################
def login_register_page():
st.title("AIdeaText")
left_column, right_column = st.columns([1, 3])
with left_column:
tab1, tab2 = st.tabs(["Iniciar Sesión", "Registrarse"])
with tab1:
login_form()
with tab2:
register_form()
with right_column:
display_videos_and_info()
def login_form():
with st.form("login_form"):
username = st.text_input("Correo electrónico")
password = st.text_input("Contraseña", type="password")
submit_button = st.form_submit_button("Iniciar Sesión")
if submit_button:
success, role = authenticate_user(username, password)
if success:
st.session_state.logged_in = True
st.session_state.username = username
st.session_state.role = role
st.session_state.page = 'admin' if role == 'Administrador' else 'user'
st.experimental_rerun()
else:
st.error("Credenciales incorrectas")
def register_form():
st.header("Solicitar prueba de la aplicación")
name = st.text_input("Nombre completo")
email = st.text_input("Correo electrónico institucional")
institution = st.text_input("Institución")
role = st.selectbox("Rol", ["Estudiante", "Profesor", "Investigador", "Otro"])
reason = st.text_area("¿Por qué estás interesado en probar AIdeaText?")
if st.button("Enviar solicitud"):
logger.info(f"Attempting to submit application for {email}")
logger.debug(f"Form data: name={name}, email={email}, institution={institution}, role={role}, reason={reason}")
if not name or not email or not institution or not reason:
logger.warning("Incomplete form submission")
st.error("Por favor, completa todos los campos.")
elif not is_institutional_email(email):
logger.warning(f"Non-institutional email used: {email}")
st.error("Por favor, utiliza un correo electrónico institucional.")
else:
logger.info(f"Attempting to store application for {email}")
success = store_application_request(name, email, institution, role, reason)
if success:
st.success("Tu solicitud ha sido enviada. Te contactaremos pronto.")
logger.info(f"Application request stored successfully for {email}")
else:
st.error("Hubo un problema al enviar tu solicitud. Por favor, intenta de nuevo más tarde.")
logger.error(f"Failed to store application request for {email}")
def is_institutional_email(email):
forbidden_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com']
return not any(domain in email.lower() for domain in forbidden_domains)
###########################################--- Funciones de interfaz general --- ######################################################
def user_page():
# Asumimos que el idioma seleccionado está almacenado en st.session_state.lang_code
# Si no está definido, usamos 'es' como valor predeterminado
t = get_translations(lang_code)
st.title(t['welcome'])
st.write(f"{t['hello']}, {st.session_state.username}")
# Dividir la pantalla en dos columnas
col1, col2 = st.columns(2)
with col1:
st.subheader(t['chat_title'])
display_chatbot_interface(lang_code)
with col2:
st.subheader(t['results_title'])
if 'current_analysis' in st.session_state and st.session_state.current_analysis is not None:
display_analysis_results(st.session_state.current_analysis, lang_code)
if st.button(t['export_button']):
if export_analysis_and_chat(st.session_state.username, st.session_state.current_analysis, st.session_state.messages):
st.success(t['export_success'])
else:
st.error(t['export_error'])
else:
st.info(t['no_analysis'])
def admin_page():
st.title("Panel de Administración")
st.write(f"Bienvenida, {st.session_state.username}")
st.header("Crear Nuevo Usuario Estudiante")
new_username = st.text_input("Correo electrónico del nuevo usuario", key="admin_new_username")
new_password = st.text_input("Contraseña", type="password", key="admin_new_password")
if st.button("Crear Usuario", key="admin_create_user"):
if create_student_user(new_username, new_password):
st.success(f"Usuario estudiante {new_username} creado exitosamente")
else:
st.error("Error al crear el usuario estudiante")
# Aquí puedes añadir más funcionalidades para el panel de administración
def display_videos_and_info():
st.header("Videos: pitch, demos, entrevistas, otros")
videos = {
"Presentación en PyCon Colombia, Medellín, 2024": "https://www.youtube.com/watch?v=Jn545-IKx5Q",
"Presentación fundación Ser Maaestro": "https://www.youtube.com/watch?v=imc4TI1q164",
"Pitch IFE Explora": "https://www.youtube.com/watch?v=Fqi4Di_Rj_s",
"Entrevista Dr. Guillermo Ruíz": "https://www.youtube.com/watch?v=_ch8cRja3oc",
"Demo versión desktop": "https://www.youtube.com/watch?v=nP6eXbog-ZY"
}
selected_title = st.selectbox("Selecciona un video tutorial:", list(videos.keys()))
if selected_title in videos:
try:
st_player(videos[selected_title])
except Exception as e:
st.error(f"Error al cargar el video: {str(e)}")
st.markdown("""
## Novedades de la versión actual
- Nueva función de análisis semántico
- Soporte para múltiples idiomas
- Interfaz mejorada para una mejor experiencia de usuario
""")
def display_feedback_form(lang_code, t):
logging.info(f"display_feedback_form called with lang_code: {lang_code}")
st.header(t['title'])
name = st.text_input(t['name'], key=f"feedback_name_{lang_code}")
email = st.text_input(t['email'], key=f"feedback_email_{lang_code}")
feedback = st.text_area(t['feedback'], key=f"feedback_text_{lang_code}")
if st.button(t['submit'], key=f"feedback_submit_{lang_code}"):
if name and email and feedback:
if store_user_feedback(st.session_state.username, name, email, feedback):
st.success(t['success'])
else:
st.error(t['error'])
else:
st.warning("Por favor, completa todos los campos.")
def display_student_progress(username, lang_code, t):
student_data = get_student_data(username)
if student_data is None or len(student_data['entries']) == 0:
st.warning("No se encontraron datos para este estudiante.")
st.info("Intenta realizar algunos análisis de texto primero.")
return
st.title(f"Progreso de {username}")
with st.expander("Resumen de Actividades y Progreso", expanded=True):
# Resumen de actividades
total_entries = len(student_data['entries'])
st.write(f"Total de análisis realizados: {total_entries}")
# Gráfico de tipos de análisis
analysis_types = [entry['analysis_type'] for entry in student_data['entries']]
analysis_counts = pd.Series(analysis_types).value_counts()
fig, ax = plt.subplots()
analysis_counts.plot(kind='bar', ax=ax)
ax.set_title("Tipos de análisis realizados")
ax.set_xlabel("Tipo de análisis")
ax.set_ylabel("Cantidad")
st.pyplot(fig)
# Progreso a lo largo del tiempo
dates = [datetime.fromisoformat(entry['timestamp']) for entry in student_data['entries']]
analysis_counts = pd.Series(dates).value_counts().sort_index()
fig, ax = plt.subplots()
analysis_counts.plot(kind='line', ax=ax)
ax.set_title("Análisis realizados a lo largo del tiempo")
ax.set_xlabel("Fecha")
ax.set_ylabel("Cantidad de análisis")
st.pyplot(fig)
##########################################################
with st.expander("Histórico de Análisis Morfosintácticos"):
morphosyntax_entries = [entry for entry in student_data['entries'] if entry['analysis_type'] == 'morphosyntax']
for entry in morphosyntax_entries:
st.subheader(f"Análisis del {entry['timestamp']}")
if entry['arc_diagrams']:
st.write(entry['arc_diagrams'][0], unsafe_allow_html=True)
##########################################################
with st.expander("Histórico de Análisis Semánticos"):
semantic_entries = [entry for entry in student_data['entries'] if entry['analysis_type'] == 'semantic']
for entry in semantic_entries:
st.subheader(f"Análisis del {entry['timestamp']}")
# Mostrar conceptos clave
if 'key_concepts' in entry:
st.write("Conceptos clave:")
concepts_str = " | ".join([f"{concept} ({frequency:.2f})" for concept, frequency in entry['key_concepts']])
#st.write("Conceptos clave:")
#st.write(concepts_str)
st.markdown(f"
{concepts_str}
", unsafe_allow_html=True)
# Mostrar gráfico
if 'graph' in entry:
try:
img_bytes = base64.b64decode(entry['graph'])
st.image(img_bytes, caption="Gráfico de relaciones conceptuales")
except Exception as e:
st.error(f"No se pudo mostrar el gráfico: {str(e)}")
##########################################################
with st.expander("Histórico de Análisis Discursivos"):
discourse_entries = [entry for entry in student_data['entries'] if entry['analysis_type'] == 'discourse']
for entry in discourse_entries:
st.subheader(f"Análisis del {entry['timestamp']}")
# Mostrar conceptos clave para ambos documentos
if 'key_concepts1' in entry:
concepts_str1 = " | ".join([f"{concept} ({frequency:.2f})" for concept, frequency in entry['key_concepts1']])
st.write("Conceptos clave del documento 1:")
#st.write(concepts_str1)
st.markdown(f"
{concepts_str1}
", unsafe_allow_html=True)
if 'key_concepts2' in entry:
concepts_str2 = " | ".join([f"{concept} ({frequency:.2f})" for concept, frequency in entry['key_concepts2']])
st.write("Conceptos clave del documento 2:")
#st.write(concepts_str2)
st.markdown(f"
{concepts_str2}
", unsafe_allow_html=True)
try:
if 'combined_graph' in entry and entry['combined_graph']:
img_bytes = base64.b64decode(entry['combined_graph'])
st.image(img_bytes)
elif 'graph1' in entry and 'graph2' in entry:
col1, col2 = st.columns(2)
with col1:
if entry['graph1']:
img_bytes1 = base64.b64decode(entry['graph1'])
st.image(img_bytes1)
with col2:
if entry['graph2']:
img_bytes2 = base64.b64decode(entry['graph2'])
st.image(img_bytes2)
else:
st.write("No se encontraron gráficos para este análisis.")
except Exception as e:
st.error(f"No se pudieron mostrar los gráficos: {str(e)}")
st.write("Datos de los gráficos (para depuración):")
if 'graph1' in entry:
st.write("Graph 1:", entry['graph1'][:100] + "...")
if 'graph2' in entry:
st.write("Graph 2:", entry['graph2'][:100] + "...")
if 'combined_graph' in entry:
st.write("Combined Graph:", entry['combined_graph'][:100] + "...")
##########################################################
with st.expander("Histórico de Conversaciones con el ChatBot"):
if 'chat_history' in student_data:
for i, chat in enumerate(student_data['chat_history']):
st.subheader(f"Conversación {i+1} - {chat['timestamp']}")
for message in chat['messages']:
if message['role'] == 'user':
st.write("Usuario: " + message['content'])
else:
st.write("Asistente: " + message['content'])
st.write("---")
else:
st.write("No se encontraron conversaciones con el ChatBot.")
# Añadir logs para depuración
if st.checkbox("Mostrar datos de depuración"):
st.write("Datos del estudiante (para depuración):")
st.json(student_data)
#####################--- Funciones de manejo de archivos --- #############################################################################
def handle_file_upload(username, lang_code, nlp_models, t, analysis_type):
st.subheader(t['get_text']('file_upload_section', analysis_type.upper(), 'File Upload'))
uploaded_file = st.file_uploader(
t['get_text']('file_uploader', analysis_type.upper(), 'Upload a file'),
type=['txt', 'pdf', 'docx', 'doc', 'odt']
)
if uploaded_file is not None:
file_contents = read_file_contents(uploaded_file)
if store_file_contents(username, uploaded_file.name, file_contents, analysis_type):
st.success(t['get_text']('file_upload_success', analysis_type.upper(), 'File uploaded successfully'))
return file_contents, uploaded_file.name
else:
st.error(t['get_text']('file_upload_error', analysis_type.upper(), 'Error uploading file'))
return None, None
def read_file_contents(uploaded_file):
# Implementar la lógica para leer diferentes tipos de archivos
# Por ahora, asumimos que es un archivo de texto
return uploaded_file.getvalue().decode('utf-8')
######################--- Funciones generales de análisis ---########################################################
def display_analysis_results(analysis, lang_code, t):
if analysis is None:
st.warning(t.get('no_analysis', "No hay análisis disponible."))
return
if not isinstance(analysis, dict):
st.error(f"Error: El resultado del análisis no es un diccionario. Tipo actual: {type(analysis)}")
return
if 'type' not in analysis:
st.error("Error: El resultado del análisis no contiene la clave 'type'")
st.write("Claves presentes en el resultado:", list(analysis.keys()))
return
if analysis['type'] == 'morphosyntactic':
st.subheader(t.get('morphosyntactic_title', "Análisis Morfosintáctico"))
display_morphosyntax_results(analysis['result'], lang_code, t)
elif analysis['type'] == 'semantic':
st.subheader(t.get('semantic_title', "Análisis Semántico"))
display_semantic_results(analysis['result'], lang_code, t)
elif analysis['type'] == 'discourse':
st.subheader(t.get('discourse_title', "Análisis del Discurso"))
display_discourse_results(analysis['result'], lang_code, t)
else:
st.warning(t.get('no_analysis', "No hay análisis disponible."))
# Mostrar el contenido completo del análisis para depuración
st.write("Contenido completo del análisis:", analysis)
def handle_user_input(user_input, lang_code, nlp_models, analysis_type, file_contents=None):
response = process_chat_input(user_input, lang_code, nlp_models, analysis_type, file_contents, t)
# Procesa la respuesta y actualiza la interfaz de usuario
###################################--- Funciones específicas de análisis morfosintáctico ---################################################################
def display_morphosyntax_analysis_interface(user_input, nlp_models, lang_code, t):
logging.info(f"Displaying morphosyntax analysis interface. Language code: {lang_code}")
# Inicializar el historial del chat si no existe
if 'morphosyntax_chat_history' not in st.session_state:
initial_message = t['get_text']('initial_message', 'MORPHOSYNTACTIC',
"Este es un chatbot para análisis morfosintáctico. Para generar un diagrama de arco, "
"use el comando /analisis_morfosintactico seguido del texto entre corchetes.")
st.session_state.morphosyntax_chat_history = [{"role": "assistant", "content": initial_message}]
# Contenedor para el chat
chat_container = st.container()
# Mostrar el historial del chat
with chat_container:
for message in st.session_state.morphosyntax_chat_history:
with st.chat_message(message["role"]):
st.write(message["content"])
if "visualization" in message:
st.components.v1.html(message["visualization"], height=450, scrolling=True)
# Input del usuario
user_input = st.chat_input(t['get_text']('chat_placeholder', 'MORPHOSYNTACTIC',
"Ingrese su mensaje o use /analisis_morfosintactico [texto] para analizar"))
if user_input:
# Añadir el mensaje del usuario al historial
st.session_state.morphosyntax_chat_history.append({"role": "user", "content": user_input})
# Procesar el input del usuario
if user_input.startswith('/analisis_morfosintactico'):
text_to_analyze = user_input.split('[', 1)[1].rsplit(']', 1)[0]
try:
result = perform_advanced_morphosyntactic_analysis(text_to_analyze, nlp_models[lang_code])
# Guardar el resultado en el estado de la sesión
st.session_state.current_analysis = {
'type': 'morphosyntactic',
'result': result
}
# Añadir el resultado al historial del chat
response = t['get_text']('analysis_completed', 'MORPHOSYNTACTIC', 'Análisis morfosintáctico completado.')
st.session_state.morphosyntax_chat_history.append({
"role": "assistant",
"content": response,
"visualization": result['arc_diagram'][0] if result['arc_diagram'] else None
})
# Guardar resultados en la base de datos
if store_morphosyntax_result(
st.session_state.username,
text_to_analyze,
get_repeated_words_colors(nlp_models[lang_code](text_to_analyze)),
result['arc_diagram'],
result['pos_analysis'],
result['morphological_analysis'],
result['sentence_structure']
):
st.success(t['get_text']('success_message', 'MORPHOSYNTACTIC', 'Análisis guardado correctamente.'))
else:
st.error(t['get_text']('error_message', 'MORPHOSYNTACTIC', 'Hubo un problema al guardar el análisis.'))
except Exception as e:
error_message = t['get_text']('analysis_error', 'MORPHOSYNTACTIC', f'Ocurrió un error durante el análisis: {str(e)}')
st.session_state.morphosyntax_chat_history.append({"role": "assistant", "content": error_message})
logging.error(f"Error in morphosyntactic analysis: {str(e)}")
else:
# Aquí puedes procesar otros tipos de inputs del usuario si es necesario
response = t['get_text']('command_not_recognized', 'MORPHOSYNTACTIC',
"Comando no reconocido. Use /analisis_morfosintactico [texto] para realizar un análisis.")
st.session_state.morphosyntax_chat_history.append({"role": "assistant", "content": response})
# Forzar la actualización de la interfaz
st.experimental_rerun()
logging.info("Morphosyntax analysis interface displayed successfully")
#################################################################################################
def display_morphosyntax_results(result, lang_code, t):
if result is None:
st.warning(t['no_results']) # Añade esta traducción a tu diccionario
return
# doc = result['doc']
# advanced_analysis = result['advanced_analysis']
advanced_analysis = result
# Mostrar leyenda (código existente)
st.markdown(f"##### {t['legend']}")
legend_html = "
"
for pos, color in POS_COLORS.items():
if pos in POS_TRANSLATIONS[lang_code]:
legend_html += f"