v5Dev / src /modules /semantic /semantic_interface.py
AIdeaText's picture
Upload 281 files
24060c9 verified
#modules/semantic/semantic_interface.py
import streamlit as st
from streamlit_float import *
from streamlit_antd_components import *
from streamlit.components.v1 import html
import spacy_streamlit
import io
from io import BytesIO
import base64
import matplotlib.pyplot as plt
import pandas as pd
import re
import logging
# Configuración del logger
logger = logging.getLogger(__name__)
# Importaciones locales
from .semantic_process import (
process_semantic_input,
format_semantic_results
)
from ..utils.widget_utils import generate_unique_key
from ..database.semantic_mongo_db import store_student_semantic_result
from ..database.chat_mongo_db import store_chat_history, get_chat_history
from ..semantic.semantic_agent_interaction import display_semantic_chat
from ..chatbot.sidebar_chat import display_sidebar_chat
# from ..database.semantic_export import export_user_interactions
###############################
def display_semantic_interface(lang_code, nlp_models, semantic_t):
try:
# 1. Inicializar el estado de la sesión
if 'semantic_state' not in st.session_state:
st.session_state.semantic_state = {
'analysis_count': 0,
'last_analysis': None,
'current_file': None,
'pending_analysis': False # Nuevo flag para controlar el análisis pendiente
}
# 2. Área de carga de archivo con mensaje informativo
uploaded_file = st.file_uploader(
semantic_t.get('semantic_file_uploader', 'Upload a text file for semantic analysis'),
type=['txt'],
key=f"semantic_file_uploader_{st.session_state.semantic_state['analysis_count']}"
)
# 2.1 Verificar si hay un archivo cargado y un análisis pendiente
if uploaded_file is not None and st.session_state.semantic_state.get('pending_analysis', False):
try:
with st.spinner(semantic_t.get('processing', 'Processing...')):
# Realizar análisis
text_content = uploaded_file.getvalue().decode('utf-8')
st.session_state.semantic_state['text_content'] = text_content # <-- Guardar el texto
analysis_result = process_semantic_input(
text_content,
lang_code,
nlp_models,
semantic_t
)
if analysis_result['success']:
# Guardar resultado
st.session_state.semantic_result = analysis_result
st.session_state.semantic_state['analysis_count'] += 1
st.session_state.semantic_state['current_file'] = uploaded_file.name
# Preparar datos para MongoDB
analysis_data = {
'key_concepts': analysis_result['analysis'].get('key_concepts', []),
'concept_centrality': analysis_result['analysis'].get('concept_centrality', {}),
'concept_graph': analysis_result['analysis'].get('concept_graph')
}
# Guardar en base de datos
storage_success = store_student_semantic_result(
st.session_state.username,
text_content,
analysis_result['analysis'],
lang_code # Pasamos el código de idioma directamente
)
if storage_success:
st.success(
semantic_t.get('analysis_complete',
'Análisis completado y guardado. Para realizar un nuevo análisis, cargue otro archivo.')
)
else:
st.error(semantic_t.get('error_message', 'Error saving analysis'))
else:
st.error(analysis_result['message'])
# Restablecer el flag de análisis pendiente
st.session_state.semantic_state['pending_analysis'] = False
except Exception as e:
logger.error(f"Error en análisis semántico: {str(e)}")
st.error(semantic_t.get('error_processing', f'Error processing text: {str(e)}'))
# Restablecer el flag de análisis pendiente en caso de error
st.session_state.semantic_state['pending_analysis'] = False
# 3. Columnas para los botones y mensajes
col1, col2 = st.columns([1,4])
# 4. Botón de análisis
with col1:
analyze_button = st.button(
semantic_t.get('semantic_analyze_button', 'Analyze'),
key=f"semantic_analyze_button_{st.session_state.semantic_state['analysis_count']}",
type="primary",
icon="🔍",
disabled=uploaded_file is None,
use_container_width=True
)
# 5. Procesar análisis
if analyze_button and uploaded_file is not None:
# En lugar de realizar el análisis inmediatamente, establecer el flag
st.session_state.semantic_state['pending_analysis'] = True
# Forzar la recarga de la aplicación
st.rerun()
# 6. Mostrar resultados previos o mensaje inicial
elif 'semantic_result' in st.session_state and st.session_state.semantic_result is not None:
# Mostrar mensaje sobre el análisis actual
#st.info(
# semantic_t.get('current_analysis_message',
# 'Mostrando análisis del archivo: {}. Para realizar un nuevo análisis, cargue otro archivo.'
# ).format(st.session_state.semantic_state["current_file"])
#)
display_semantic_results(
st.session_state.semantic_result,
lang_code,
semantic_t
)
# --- BOTÓN PARA ACTIVAR EL AGENTE VIRTUAL (NUEVA POSICIÓN CORRECTA) ---
if st.button("💬 Consultar con Asistente"):
if 'semantic_result' not in st.session_state:
st.error("Primero complete el análisis semántico")
return
# Guardar TODOS los datos necesarios
st.session_state.semantic_agent_data = {
'text': st.session_state.semantic_state['text_content'], # Texto completo
'metrics': st.session_state.semantic_result['analysis'], # Métricas
'graph_data': st.session_state.semantic_result['analysis'].get('concept_graph')
}
st.session_state.semantic_agent_active = True
st.rerun()
# Mostrar notificación si el agente está activo
if st.session_state.get('semantic_agent_active', False):
st.success(semantic_t.get('semantic_agent_ready_message', 'El agente virtual está listo. Abre el chat en la barra lateral.'))
else:
st.info(semantic_t.get('upload_prompt', 'Cargue un archivo para comenzar el análisis'))
except Exception as e:
logger.error(f"Error general en interfaz semántica: {str(e)}")
st.error(semantic_t.get('general_error', "Se produjo un error. Por favor, intente de nuevo."))
#######################################
def display_semantic_results(semantic_result, lang_code, semantic_t):
"""
Muestra los resultados del análisis semántico de conceptos clave.
"""
if semantic_result is None or not semantic_result['success']:
st.warning(semantic_t.get('no_results', 'No results available'))
return
analysis = semantic_result['analysis']
# Mostrar conceptos clave en formato horizontal (se mantiene igual)
st.subheader(semantic_t.get('key_concepts', 'Key Concepts'))
if 'key_concepts' in analysis and analysis['key_concepts']:
df = pd.DataFrame(
analysis['key_concepts'],
columns=[
semantic_t.get('concept', 'Concept'),
semantic_t.get('frequency', 'Frequency')
]
)
st.write(
"""
<style>
.concept-table {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 20px;
}
.concept-item {
background-color: #f0f2f6;
border-radius: 5px;
padding: 8px 12px;
display: flex;
align-items: center;
gap: 8px;
}
.concept-name {
font-weight: bold;
}
.concept-freq {
color: #666;
font-size: 0.9em;
}
</style>
<div class="concept-table">
""" +
''.join([
f'<div class="concept-item"><span class="concept-name">{concept}</span>'
f'<span class="concept-freq">({freq:.2f})</span></div>'
for concept, freq in df.values
]) +
"</div>",
unsafe_allow_html=True
)
else:
st.info(semantic_t.get('no_concepts', 'No key concepts found'))
# Gráfico de conceptos (versión modificada)
if 'concept_graph' in analysis and analysis['concept_graph'] is not None:
try:
# Sección del gráfico (sin div contenedor)
st.image(
analysis['concept_graph'],
use_container_width=True
)
# --- SOLO ESTE BLOQUE ES NUEVO ---
st.markdown("""
<style>
div[data-testid="stExpander"] div[role="button"] p {
text-align: center;
font-weight: bold;
}
</style>
""", unsafe_allow_html=True)
# ---------------------------------
# Expandible con la interpretación (se mantiene igual)
with st.expander("📊 " + semantic_t.get('semantic_graph_interpretation', "Interpretación del gráfico semántico")):
st.markdown(f"""
- 🔀 {semantic_t.get('semantic_arrow_meaning', 'Las flechas indican la dirección de la relación entre conceptos')}
- 🎨 {semantic_t.get('semantic_color_meaning', 'Los colores más intensos indican conceptos más centrales en el texto')}
- ⭕ {semantic_t.get('semantic_size_meaning', 'El tamaño de los nodos representa la frecuencia del concepto')}
- ↔️ {semantic_t.get('semantic_thickness_meaning', 'El grosor de las líneas indica la fuerza de la conexión')}
""")
# Contenedor para botones (se mantiene igual pero centrado)
st.markdown("""
<style>
.download-btn-container {
display: flex;
justify-content: center;
margin-top: 10px;
}
</style>
<div class="download-btn-container">
""", unsafe_allow_html=True)
st.download_button(
label="📥 " + semantic_t.get('download_semantic_network_graph', "Descargar gráfico de red semántica"),
data=analysis['concept_graph'],
file_name="semantic_graph.png",
mime="image/png",
use_container_width=True
)
st.markdown("</div>", unsafe_allow_html=True)
except Exception as e:
logger.error(f"Error displaying graph: {str(e)}")
st.error(semantic_t.get('graph_error', 'Error displaying the graph'))
else:
st.info(semantic_t.get('no_graph', 'No concept graph available'))