Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	Update modules/semantic/semantic_interface.py
Browse files- modules/semantic/semantic_interface.py +295 -295
    	
        modules/semantic/semantic_interface.py
    CHANGED
    
    | @@ -1,296 +1,296 @@ | |
| 1 | 
            -
            #modules/semantic/semantic_interface.py
         | 
| 2 | 
            -
            import streamlit as st
         | 
| 3 | 
            -
            from streamlit_float import *
         | 
| 4 | 
            -
            from streamlit_antd_components import *
         | 
| 5 | 
            -
            from streamlit.components.v1 import html
         | 
| 6 | 
            -
            import spacy_streamlit
         | 
| 7 | 
            -
            import io
         | 
| 8 | 
            -
            from io import BytesIO
         | 
| 9 | 
            -
            import base64
         | 
| 10 | 
            -
            import matplotlib.pyplot as plt
         | 
| 11 | 
            -
            import pandas as pd
         | 
| 12 | 
            -
            import re
         | 
| 13 | 
            -
            import logging
         | 
| 14 | 
            -
             | 
| 15 | 
            -
            # Configuración del logger
         | 
| 16 | 
            -
            logger = logging.getLogger(__name__)
         | 
| 17 | 
            -
             | 
| 18 | 
            -
            # Importaciones locales
         | 
| 19 | 
            -
            from .semantic_process import (
         | 
| 20 | 
            -
                process_semantic_input,
         | 
| 21 | 
            -
                format_semantic_results
         | 
| 22 | 
            -
            )
         | 
| 23 | 
            -
             | 
| 24 | 
            -
            from ..utils.widget_utils import generate_unique_key
         | 
| 25 | 
            -
            from ..database.semantic_mongo_db import store_student_semantic_result
         | 
| 26 | 
            -
            from ..database.chat_mongo_db import store_chat_history, get_chat_history
         | 
| 27 | 
            -
             | 
| 28 | 
            -
            # from ..database.semantic_export import export_user_interactions
         | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
            ###############################
         | 
| 32 | 
            -
             | 
| 33 | 
            -
            # En semantic_interface.py
         | 
| 34 | 
            -
            def display_semantic_interface(lang_code, nlp_models, semantic_t):
         | 
| 35 | 
            -
                try:
         | 
| 36 | 
            -
                    # 1. Inicializar el estado de la sesión
         | 
| 37 | 
            -
                    if 'semantic_state' not in st.session_state:
         | 
| 38 | 
            -
                        st.session_state.semantic_state = {
         | 
| 39 | 
            -
                            'analysis_count': 0,
         | 
| 40 | 
            -
                            'last_analysis': None,
         | 
| 41 | 
            -
                            'current_file': None,
         | 
| 42 | 
            -
                            'pending_analysis': False  # Nuevo flag para controlar el análisis pendiente
         | 
| 43 | 
            -
                        }
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                    # 2. Área de carga de archivo con mensaje informativo
         | 
| 46 | 
            -
                    st.info(semantic_t.get('initial_instruction', 
         | 
| 47 | 
            -
                        'Para comenzar un nuevo análisis semántico, cargue un archivo de texto (.txt)'))
         | 
| 48 | 
            -
                        
         | 
| 49 | 
            -
                    uploaded_file = st.file_uploader(
         | 
| 50 | 
            -
                        semantic_t.get('semantic_file_uploader', 'Upload a text file for semantic analysis'),
         | 
| 51 | 
            -
                        type=['txt'],
         | 
| 52 | 
            -
                        key=f"semantic_file_uploader_{st.session_state.semantic_state['analysis_count']}"
         | 
| 53 | 
            -
                    )
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                    # Verificar si hay un archivo cargado y un análisis pendiente
         | 
| 56 | 
            -
                    if uploaded_file is not None and st.session_state.semantic_state.get('pending_analysis', False):
         | 
| 57 | 
            -
                        try:
         | 
| 58 | 
            -
                            with st.spinner(semantic_t.get('processing', 'Processing...')):
         | 
| 59 | 
            -
                                # Realizar análisis
         | 
| 60 | 
            -
                                text_content = uploaded_file.getvalue().decode('utf-8')
         | 
| 61 | 
            -
                                
         | 
| 62 | 
            -
                                analysis_result = process_semantic_input(
         | 
| 63 | 
            -
                                    text_content, 
         | 
| 64 | 
            -
                                    lang_code,
         | 
| 65 | 
            -
                                    nlp_models,
         | 
| 66 | 
            -
                                    semantic_t
         | 
| 67 | 
            -
                                )
         | 
| 68 | 
            -
                                
         | 
| 69 | 
            -
                                if analysis_result['success']:
         | 
| 70 | 
            -
                                    # Guardar resultado
         | 
| 71 | 
            -
                                    st.session_state.semantic_result = analysis_result
         | 
| 72 | 
            -
                                    st.session_state.semantic_state['analysis_count'] += 1
         | 
| 73 | 
            -
                                    st.session_state.semantic_state['current_file'] = uploaded_file.name
         | 
| 74 | 
            -
                                    
         | 
| 75 | 
            -
                                    # Guardar en base de datos
         | 
| 76 | 
            -
                                    storage_success = store_student_semantic_result(
         | 
| 77 | 
            -
                                        st.session_state.username,
         | 
| 78 | 
            -
                                        text_content,
         | 
| 79 | 
            -
                                        analysis_result['analysis']
         | 
| 80 | 
            -
                                    )
         | 
| 81 | 
            -
                                    
         | 
| 82 | 
            -
                                    if storage_success:
         | 
| 83 | 
            -
                                        st.success(
         | 
| 84 | 
            -
                                            semantic_t.get('analysis_complete', 
         | 
| 85 | 
            -
                                            'Análisis completado y guardado. Para realizar un nuevo análisis, cargue otro archivo.')
         | 
| 86 | 
            -
                                        )
         | 
| 87 | 
            -
                                    else:
         | 
| 88 | 
            -
                                        st.error(semantic_t.get('error_message', 'Error saving analysis'))
         | 
| 89 | 
            -
                                else:
         | 
| 90 | 
            -
                                    st.error(analysis_result['message'])
         | 
| 91 | 
            -
                                
         | 
| 92 | 
            -
                            # Restablecer el flag de análisis pendiente
         | 
| 93 | 
            -
                            st.session_state.semantic_state['pending_analysis'] = False
         | 
| 94 | 
            -
                                
         | 
| 95 | 
            -
                        except Exception as e:
         | 
| 96 | 
            -
                            logger.error(f"Error en análisis semántico: {str(e)}")
         | 
| 97 | 
            -
                            st.error(semantic_t.get('error_processing', f'Error processing text: {str(e)}'))
         | 
| 98 | 
            -
                            # Restablecer el flag de análisis pendiente en caso de error
         | 
| 99 | 
            -
                            st.session_state.semantic_state['pending_analysis'] = False
         | 
| 100 | 
            -
             | 
| 101 | 
            -
                    # 3. Columnas para los botones y mensajes
         | 
| 102 | 
            -
                    col1, col2 = st.columns([1,4])
         | 
| 103 | 
            -
                    
         | 
| 104 | 
            -
                    # 4. Botón de análisis
         | 
| 105 | 
            -
                    with col1:
         | 
| 106 | 
            -
                        analyze_button = st.button(
         | 
| 107 | 
            -
                            semantic_t.get('semantic_analyze_button', 'Analyze'),
         | 
| 108 | 
            -
                            key=f"semantic_analyze_button_{st.session_state.semantic_state['analysis_count']}",
         | 
| 109 | 
            -
                            type="primary",
         | 
| 110 | 
            -
                            icon="🔍",
         | 
| 111 | 
            -
                            disabled=uploaded_file is None,
         | 
| 112 | 
            -
                            use_container_width=True
         | 
| 113 | 
            -
                        )
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                    # 5. Procesar análisis
         | 
| 116 | 
            -
                    if analyze_button and uploaded_file is not None:
         | 
| 117 | 
            -
                        # En lugar de realizar el análisis inmediatamente, establecer el flag
         | 
| 118 | 
            -
                        st.session_state.semantic_state['pending_analysis'] = True
         | 
| 119 | 
            -
                        # Forzar la recarga de la aplicación
         | 
| 120 | 
            -
                        st.rerun()
         | 
| 121 | 
            -
                    
         | 
| 122 | 
            -
                    # 6. Mostrar resultados previos o mensaje inicial
         | 
| 123 | 
            -
                    elif 'semantic_result' in st.session_state and st.session_state.semantic_result is not None:
         | 
| 124 | 
            -
                        # Mostrar mensaje sobre el análisis actual
         | 
| 125 | 
            -
                        st.info(
         | 
| 126 | 
            -
                            semantic_t.get('current_analysis_message', 
         | 
| 127 | 
            -
                            f'Mostrando análisis del archivo: {st.session_state.semantic_state["current_file"]}. '
         | 
| 128 | 
            -
                            'Para realizar un nuevo análisis, cargue otro archivo.')
         | 
| 129 | 
            -
                        )
         | 
| 130 | 
            -
                        
         | 
| 131 | 
            -
                        display_semantic_results(
         | 
| 132 | 
            -
                            st.session_state.semantic_result,
         | 
| 133 | 
            -
                            lang_code,
         | 
| 134 | 
            -
                            semantic_t
         | 
| 135 | 
            -
                        )
         | 
| 136 | 
            -
                    else:
         | 
| 137 | 
            -
                        st.info(semantic_t.get('upload_prompt', 'Cargue un archivo para comenzar el análisis'))
         | 
| 138 | 
            -
             | 
| 139 | 
            -
                except Exception as e:
         | 
| 140 | 
            -
                    logger.error(f"Error general en interfaz semántica: {str(e)}")
         | 
| 141 | 
            -
                    st.error(semantic_t.get('general_error', "Se produjo un error. Por favor, intente de nuevo."))
         | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
            #######################################
         | 
| 145 | 
            -
            def display_semantic_results(semantic_result, lang_code, semantic_t):
         | 
| 146 | 
            -
                """
         | 
| 147 | 
            -
                Muestra los resultados del análisis semántico de conceptos clave.
         | 
| 148 | 
            -
                """
         | 
| 149 | 
            -
                if semantic_result is None or not semantic_result['success']:
         | 
| 150 | 
            -
                    st.warning(semantic_t.get('no_results', 'No results available'))
         | 
| 151 | 
            -
                    return
         | 
| 152 | 
            -
             | 
| 153 | 
            -
                analysis = semantic_result['analysis']
         | 
| 154 | 
            -
             | 
| 155 | 
            -
                # Mostrar conceptos clave en formato horizontal
         | 
| 156 | 
            -
                st.subheader(semantic_t.get('key_concepts', 'Key Concepts'))
         | 
| 157 | 
            -
                if 'key_concepts' in analysis and analysis['key_concepts']:
         | 
| 158 | 
            -
                    # Crear tabla de conceptos
         | 
| 159 | 
            -
                    df = pd.DataFrame(
         | 
| 160 | 
            -
                        analysis['key_concepts'],
         | 
| 161 | 
            -
                        columns=[
         | 
| 162 | 
            -
                            semantic_t.get('concept', 'Concept'),
         | 
| 163 | 
            -
                            semantic_t.get('frequency', 'Frequency')
         | 
| 164 | 
            -
                        ]
         | 
| 165 | 
            -
                    )
         | 
| 166 | 
            -
                    
         | 
| 167 | 
            -
                    # Convertir DataFrame a formato horizontal
         | 
| 168 | 
            -
                    st.write(
         | 
| 169 | 
            -
                        """
         | 
| 170 | 
            -
                        <style>
         | 
| 171 | 
            -
                        .concept-table {
         | 
| 172 | 
            -
                            display: flex;
         | 
| 173 | 
            -
                            flex-wrap: wrap;
         | 
| 174 | 
            -
                            gap: 10px;
         | 
| 175 | 
            -
                            margin-bottom: 20px;
         | 
| 176 | 
            -
                        }
         | 
| 177 | 
            -
                        .concept-item {
         | 
| 178 | 
            -
                            background-color: #f0f2f6;
         | 
| 179 | 
            -
                            border-radius: 5px;
         | 
| 180 | 
            -
                            padding: 8px 12px;
         | 
| 181 | 
            -
                            display: flex;
         | 
| 182 | 
            -
                            align-items: center;
         | 
| 183 | 
            -
                            gap: 8px;
         | 
| 184 | 
            -
                        }
         | 
| 185 | 
            -
                        .concept-name {
         | 
| 186 | 
            -
                            font-weight: bold;
         | 
| 187 | 
            -
                        }
         | 
| 188 | 
            -
                        .concept-freq {
         | 
| 189 | 
            -
                            color: #666;
         | 
| 190 | 
            -
                            font-size: 0.9em;
         | 
| 191 | 
            -
                        }
         | 
| 192 | 
            -
                        </style>
         | 
| 193 | 
            -
                        <div class="concept-table">
         | 
| 194 | 
            -
                        """ + 
         | 
| 195 | 
            -
                        ''.join([
         | 
| 196 | 
            -
                            f'<div class="concept-item"><span class="concept-name">{concept}</span>'
         | 
| 197 | 
            -
                            f'<span class="concept-freq">({freq:.2f})</span></div>'
         | 
| 198 | 
            -
                            for concept, freq in df.values
         | 
| 199 | 
            -
                        ]) +
         | 
| 200 | 
            -
                        "</div>",
         | 
| 201 | 
            -
                        unsafe_allow_html=True
         | 
| 202 | 
            -
                    )
         | 
| 203 | 
            -
                else:
         | 
| 204 | 
            -
                    st.info(semantic_t.get('no_concepts', 'No key concepts found'))
         | 
| 205 | 
            -
             | 
| 206 | 
            -
                # Gráfico de conceptos
         | 
| 207 | 
            -
                st.subheader(semantic_t.get('concept_graph', 'Concepts Graph'))
         | 
| 208 | 
            -
                if 'concept_graph' in analysis and analysis['concept_graph'] is not None:
         | 
| 209 | 
            -
                    try:
         | 
| 210 | 
            -
                        # Container para el grafo con estilos mejorados
         | 
| 211 | 
            -
                        st.markdown(
         | 
| 212 | 
            -
                            """
         | 
| 213 | 
            -
                            <style>
         | 
| 214 | 
            -
                            .graph-container {
         | 
| 215 | 
            -
                                background-color: white;
         | 
| 216 | 
            -
                                border-radius: 10px;
         | 
| 217 | 
            -
                                padding: 20px;
         | 
| 218 | 
            -
                                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
         | 
| 219 | 
            -
                                margin: 10px 0;
         | 
| 220 | 
            -
                            }
         | 
| 221 | 
            -
                            .button-container {
         | 
| 222 | 
            -
                                display: flex;
         | 
| 223 | 
            -
                                gap: 10px;
         | 
| 224 | 
            -
                                margin: 10px 0;
         | 
| 225 | 
            -
                            }
         | 
| 226 | 
            -
                            </style>
         | 
| 227 | 
            -
                            """,
         | 
| 228 | 
            -
                            unsafe_allow_html=True
         | 
| 229 | 
            -
                        )
         | 
| 230 | 
            -
             | 
| 231 | 
            -
                        with st.container():
         | 
| 232 | 
            -
                            st.markdown('<div class="graph-container">', unsafe_allow_html=True)
         | 
| 233 | 
            -
                            
         | 
| 234 | 
            -
                            # Mostrar grafo
         | 
| 235 | 
            -
                            graph_bytes = analysis['concept_graph']
         | 
| 236 | 
            -
                            graph_base64 = base64.b64encode(graph_bytes).decode()
         | 
| 237 | 
            -
                            st.markdown(
         | 
| 238 | 
            -
                                f'<img src="data:image/png;base64,{graph_base64}" alt="Concept Graph" style="width:100%;"/>',
         | 
| 239 | 
            -
                                unsafe_allow_html=True
         | 
| 240 | 
            -
                            )
         | 
| 241 | 
            -
                            
         | 
| 242 | 
            -
                            # Leyenda del grafo
         | 
| 243 | 
            -
                            st.caption(semantic_t.get(
         | 
| 244 | 
            -
                                'graph_description',
         | 
| 245 | 
            -
                                'Visualización de relaciones entre conceptos clave identificados en el texto.'
         | 
| 246 | 
            -
                            ))
         | 
| 247 | 
            -
                            
         | 
| 248 | 
            -
                            st.markdown('</div>', unsafe_allow_html=True)
         | 
| 249 | 
            -
             | 
| 250 | 
            -
                        # Contenedor para botones
         | 
| 251 | 
            -
                        col1, col2 = st.columns([1,4])
         | 
| 252 | 
            -
                        with col1:
         | 
| 253 | 
            -
                            st.download_button(
         | 
| 254 | 
            -
                                label="📥 " + semantic_t.get('download_graph', "Download"),
         | 
| 255 | 
            -
                                data=graph_bytes,
         | 
| 256 | 
            -
                                file_name="semantic_graph.png",
         | 
| 257 | 
            -
                                mime="image/png",
         | 
| 258 | 
            -
                                use_container_width=True
         | 
| 259 | 
            -
                            )
         | 
| 260 | 
            -
                        
         | 
| 261 | 
            -
                        # Expandible con la interpretación
         | 
| 262 | 
            -
                        with st.expander("📊 " + semantic_t.get('graph_help', "Graph Interpretation")):
         | 
| 263 | 
            -
                            st.markdown("""
         | 
| 264 | 
            -
                                - 🔀 Las flechas indican la dirección de la relación entre conceptos
         | 
| 265 | 
            -
                                - 🎨 Los colores más intensos indican conceptos más centrales en el texto
         | 
| 266 | 
            -
                                - ⭕ El tamaño de los nodos representa la frecuencia del concepto
         | 
| 267 | 
            -
                                - ↔️ El grosor de las líneas indica la fuerza de la conexión
         | 
| 268 | 
            -
                            """)
         | 
| 269 | 
            -
                    
         | 
| 270 | 
            -
                    except Exception as e:
         | 
| 271 | 
            -
                        logger.error(f"Error displaying graph: {str(e)}")
         | 
| 272 | 
            -
                        st.error(semantic_t.get('graph_error', 'Error displaying the graph'))
         | 
| 273 | 
            -
                else:
         | 
| 274 | 
            -
                    st.info(semantic_t.get('no_graph', 'No concept graph available'))
         | 
| 275 | 
            -
             | 
| 276 | 
            -
             | 
| 277 | 
            -
            ########################################################################################
         | 
| 278 | 
            -
            '''
         | 
| 279 | 
            -
                # Botón de exportación al final
         | 
| 280 | 
            -
                if 'semantic_analysis_counter' in st.session_state:
         | 
| 281 | 
            -
                    col1, col2, col3 = st.columns([2,1,2])
         | 
| 282 | 
            -
                    with col2:
         | 
| 283 | 
            -
                        if st.button(
         | 
| 284 | 
            -
                            semantic_t.get('export_button', 'Export Analysis'), 
         | 
| 285 | 
            -
                            key=f"semantic_export_{st.session_state.semantic_analysis_counter}",
         | 
| 286 | 
            -
                            use_container_width=True
         | 
| 287 | 
            -
                        ):
         | 
| 288 | 
            -
                            pdf_buffer = export_user_interactions(st.session_state.username, 'semantic')
         | 
| 289 | 
            -
                            st.download_button(
         | 
| 290 | 
            -
                                label=semantic_t.get('download_pdf', 'Download PDF'),
         | 
| 291 | 
            -
                                data=pdf_buffer,
         | 
| 292 | 
            -
                                file_name="semantic_analysis.pdf",
         | 
| 293 | 
            -
                                mime="application/pdf",
         | 
| 294 | 
            -
                                key=f"semantic_download_{st.session_state.semantic_analysis_counter}"
         | 
| 295 | 
            -
                            )
         | 
| 296 | 
             
            '''
         | 
|  | |
| 1 | 
            +
            #modules/semantic/semantic_interface.py
         | 
| 2 | 
            +
            import streamlit as st
         | 
| 3 | 
            +
            from streamlit_float import *
         | 
| 4 | 
            +
            from streamlit_antd_components import *
         | 
| 5 | 
            +
            from streamlit.components.v1 import html
         | 
| 6 | 
            +
            import spacy_streamlit
         | 
| 7 | 
            +
            import io
         | 
| 8 | 
            +
            from io import BytesIO
         | 
| 9 | 
            +
            import base64
         | 
| 10 | 
            +
            import matplotlib.pyplot as plt
         | 
| 11 | 
            +
            import pandas as pd
         | 
| 12 | 
            +
            import re
         | 
| 13 | 
            +
            import logging
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            # Configuración del logger
         | 
| 16 | 
            +
            logger = logging.getLogger(__name__)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            # Importaciones locales
         | 
| 19 | 
            +
            from .semantic_process import (
         | 
| 20 | 
            +
                process_semantic_input,
         | 
| 21 | 
            +
                format_semantic_results
         | 
| 22 | 
            +
            )
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            from ..utils.widget_utils import generate_unique_key
         | 
| 25 | 
            +
            from ..database.semantic_mongo_db import store_student_semantic_result
         | 
| 26 | 
            +
            from ..database.chat_mongo_db import store_chat_history, get_chat_history
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            # from ..database.semantic_export import export_user_interactions
         | 
| 29 | 
            +
             | 
| 30 | 
            +
             | 
| 31 | 
            +
            ###############################
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            # En semantic_interface.py
         | 
| 34 | 
            +
            def display_semantic_interface(lang_code, nlp_models, semantic_t):
         | 
| 35 | 
            +
                try:
         | 
| 36 | 
            +
                    # 1. Inicializar el estado de la sesión
         | 
| 37 | 
            +
                    if 'semantic_state' not in st.session_state:
         | 
| 38 | 
            +
                        st.session_state.semantic_state = {
         | 
| 39 | 
            +
                            'analysis_count': 0,
         | 
| 40 | 
            +
                            'last_analysis': None,
         | 
| 41 | 
            +
                            'current_file': None,
         | 
| 42 | 
            +
                            'pending_analysis': False  # Nuevo flag para controlar el análisis pendiente
         | 
| 43 | 
            +
                        }
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    # 2. Área de carga de archivo con mensaje informativo
         | 
| 46 | 
            +
                    st.info(semantic_t.get('initial_instruction', 
         | 
| 47 | 
            +
                        'Para comenzar un nuevo análisis semántico, cargue un archivo de texto (.txt)'))
         | 
| 48 | 
            +
                        
         | 
| 49 | 
            +
                    uploaded_file = st.file_uploader(
         | 
| 50 | 
            +
                        semantic_t.get('semantic_file_uploader', 'Upload a text file for semantic analysis'),
         | 
| 51 | 
            +
                        type=['txt'],
         | 
| 52 | 
            +
                        key=f"semantic_file_uploader_{st.session_state.semantic_state['analysis_count']}"
         | 
| 53 | 
            +
                    )
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    # Verificar si hay un archivo cargado y un análisis pendiente
         | 
| 56 | 
            +
                    if uploaded_file is not None and st.session_state.semantic_state.get('pending_analysis', False):
         | 
| 57 | 
            +
                        try:
         | 
| 58 | 
            +
                            with st.spinner(semantic_t.get('processing', 'Processing...')):
         | 
| 59 | 
            +
                                # Realizar análisis
         | 
| 60 | 
            +
                                text_content = uploaded_file.getvalue().decode('utf-8')
         | 
| 61 | 
            +
                                
         | 
| 62 | 
            +
                                analysis_result = process_semantic_input(
         | 
| 63 | 
            +
                                    text_content, 
         | 
| 64 | 
            +
                                    lang_code,
         | 
| 65 | 
            +
                                    nlp_models,
         | 
| 66 | 
            +
                                    semantic_t
         | 
| 67 | 
            +
                                )
         | 
| 68 | 
            +
                                
         | 
| 69 | 
            +
                                if analysis_result['success']:
         | 
| 70 | 
            +
                                    # Guardar resultado
         | 
| 71 | 
            +
                                    st.session_state.semantic_result = analysis_result
         | 
| 72 | 
            +
                                    st.session_state.semantic_state['analysis_count'] += 1
         | 
| 73 | 
            +
                                    st.session_state.semantic_state['current_file'] = uploaded_file.name
         | 
| 74 | 
            +
                                    
         | 
| 75 | 
            +
                                    # Guardar en base de datos
         | 
| 76 | 
            +
                                    storage_success = store_student_semantic_result(
         | 
| 77 | 
            +
                                        st.session_state.username,
         | 
| 78 | 
            +
                                        text_content,
         | 
| 79 | 
            +
                                        analysis_result['analysis']
         | 
| 80 | 
            +
                                    )
         | 
| 81 | 
            +
                                    
         | 
| 82 | 
            +
                                    if storage_success:
         | 
| 83 | 
            +
                                        st.success(
         | 
| 84 | 
            +
                                            semantic_t.get('analysis_complete', 
         | 
| 85 | 
            +
                                            'Análisis completado y guardado. Para realizar un nuevo análisis, cargue otro archivo.')
         | 
| 86 | 
            +
                                        )
         | 
| 87 | 
            +
                                    else:
         | 
| 88 | 
            +
                                        st.error(semantic_t.get('error_message', 'Error saving analysis'))
         | 
| 89 | 
            +
                                else:
         | 
| 90 | 
            +
                                    st.error(analysis_result['message'])
         | 
| 91 | 
            +
                                
         | 
| 92 | 
            +
                            # Restablecer el flag de análisis pendiente
         | 
| 93 | 
            +
                            st.session_state.semantic_state['pending_analysis'] = False
         | 
| 94 | 
            +
                                
         | 
| 95 | 
            +
                        except Exception as e:
         | 
| 96 | 
            +
                            logger.error(f"Error en análisis semántico: {str(e)}")
         | 
| 97 | 
            +
                            st.error(semantic_t.get('error_processing', f'Error processing text: {str(e)}'))
         | 
| 98 | 
            +
                            # Restablecer el flag de análisis pendiente en caso de error
         | 
| 99 | 
            +
                            st.session_state.semantic_state['pending_analysis'] = False
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                    # 3. Columnas para los botones y mensajes
         | 
| 102 | 
            +
                    col1, col2 = st.columns([1,4])
         | 
| 103 | 
            +
                    
         | 
| 104 | 
            +
                    # 4. Botón de análisis
         | 
| 105 | 
            +
                    with col1:
         | 
| 106 | 
            +
                        analyze_button = st.button(
         | 
| 107 | 
            +
                            semantic_t.get('semantic_analyze_button', 'Analyze'),
         | 
| 108 | 
            +
                            key=f"semantic_analyze_button_{st.session_state.semantic_state['analysis_count']}",
         | 
| 109 | 
            +
                            type="primary",
         | 
| 110 | 
            +
                            icon="🔍",
         | 
| 111 | 
            +
                            disabled=uploaded_file is None,
         | 
| 112 | 
            +
                            use_container_width=True
         | 
| 113 | 
            +
                        )
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                    # 5. Procesar análisis
         | 
| 116 | 
            +
                    if analyze_button and uploaded_file is not None:
         | 
| 117 | 
            +
                        # En lugar de realizar el análisis inmediatamente, establecer el flag
         | 
| 118 | 
            +
                        st.session_state.semantic_state['pending_analysis'] = True
         | 
| 119 | 
            +
                        # Forzar la recarga de la aplicación
         | 
| 120 | 
            +
                        st.rerun()
         | 
| 121 | 
            +
                    
         | 
| 122 | 
            +
                    # 6. Mostrar resultados previos o mensaje inicial
         | 
| 123 | 
            +
                    elif 'semantic_result' in st.session_state and st.session_state.semantic_result is not None:
         | 
| 124 | 
            +
                        # Mostrar mensaje sobre el análisis actual
         | 
| 125 | 
            +
                        st.info(
         | 
| 126 | 
            +
                            semantic_t.get('current_analysis_message', 
         | 
| 127 | 
            +
                            f'Mostrando análisis del archivo: {st.session_state.semantic_state["current_file"]}. '
         | 
| 128 | 
            +
                            'Para realizar un nuevo análisis, cargue otro archivo.')
         | 
| 129 | 
            +
                        )
         | 
| 130 | 
            +
                        
         | 
| 131 | 
            +
                        display_semantic_results(
         | 
| 132 | 
            +
                            st.session_state.semantic_result,
         | 
| 133 | 
            +
                            lang_code,
         | 
| 134 | 
            +
                            semantic_t
         | 
| 135 | 
            +
                        )
         | 
| 136 | 
            +
                    else:
         | 
| 137 | 
            +
                        st.info(semantic_t.get('upload_prompt', 'Cargue un archivo para comenzar el análisis'))
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                except Exception as e:
         | 
| 140 | 
            +
                    logger.error(f"Error general en interfaz semántica: {str(e)}")
         | 
| 141 | 
            +
                    st.error(semantic_t.get('general_error', "Se produjo un error. Por favor, intente de nuevo."))
         | 
| 142 | 
            +
             | 
| 143 | 
            +
             | 
| 144 | 
            +
            #######################################
         | 
| 145 | 
            +
            def display_semantic_results(semantic_result, lang_code, semantic_t):
         | 
| 146 | 
            +
                """
         | 
| 147 | 
            +
                Muestra los resultados del análisis semántico de conceptos clave.
         | 
| 148 | 
            +
                """
         | 
| 149 | 
            +
                if semantic_result is None or not semantic_result['success']:
         | 
| 150 | 
            +
                    st.warning(semantic_t.get('no_results', 'No results available'))
         | 
| 151 | 
            +
                    return
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                analysis = semantic_result['analysis']
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                # Mostrar conceptos clave en formato horizontal
         | 
| 156 | 
            +
                st.subheader(semantic_t.get('key_concepts', 'Key Concepts'))
         | 
| 157 | 
            +
                if 'key_concepts' in analysis and analysis['key_concepts']:
         | 
| 158 | 
            +
                    # Crear tabla de conceptos
         | 
| 159 | 
            +
                    df = pd.DataFrame(
         | 
| 160 | 
            +
                        analysis['key_concepts'],
         | 
| 161 | 
            +
                        columns=[
         | 
| 162 | 
            +
                            semantic_t.get('concept', 'Concept'),
         | 
| 163 | 
            +
                            semantic_t.get('frequency', 'Frequency')
         | 
| 164 | 
            +
                        ]
         | 
| 165 | 
            +
                    )
         | 
| 166 | 
            +
                    
         | 
| 167 | 
            +
                    # Convertir DataFrame a formato horizontal
         | 
| 168 | 
            +
                    st.write(
         | 
| 169 | 
            +
                        """
         | 
| 170 | 
            +
                        <style>
         | 
| 171 | 
            +
                        .concept-table {
         | 
| 172 | 
            +
                            display: flex;
         | 
| 173 | 
            +
                            flex-wrap: wrap;
         | 
| 174 | 
            +
                            gap: 10px;
         | 
| 175 | 
            +
                            margin-bottom: 20px;
         | 
| 176 | 
            +
                        }
         | 
| 177 | 
            +
                        .concept-item {
         | 
| 178 | 
            +
                            background-color: #f0f2f6;
         | 
| 179 | 
            +
                            border-radius: 5px;
         | 
| 180 | 
            +
                            padding: 8px 12px;
         | 
| 181 | 
            +
                            display: flex;
         | 
| 182 | 
            +
                            align-items: center;
         | 
| 183 | 
            +
                            gap: 8px;
         | 
| 184 | 
            +
                        }
         | 
| 185 | 
            +
                        .concept-name {
         | 
| 186 | 
            +
                            font-weight: bold;
         | 
| 187 | 
            +
                        }
         | 
| 188 | 
            +
                        .concept-freq {
         | 
| 189 | 
            +
                            color: #666;
         | 
| 190 | 
            +
                            font-size: 0.9em;
         | 
| 191 | 
            +
                        }
         | 
| 192 | 
            +
                        </style>
         | 
| 193 | 
            +
                        <div class="concept-table">
         | 
| 194 | 
            +
                        """ + 
         | 
| 195 | 
            +
                        ''.join([
         | 
| 196 | 
            +
                            f'<div class="concept-item"><span class="concept-name">{concept}</span>'
         | 
| 197 | 
            +
                            f'<span class="concept-freq">({freq:.2f})</span></div>'
         | 
| 198 | 
            +
                            for concept, freq in df.values
         | 
| 199 | 
            +
                        ]) +
         | 
| 200 | 
            +
                        "</div>",
         | 
| 201 | 
            +
                        unsafe_allow_html=True
         | 
| 202 | 
            +
                    )
         | 
| 203 | 
            +
                else:
         | 
| 204 | 
            +
                    st.info(semantic_t.get('no_concepts', 'No key concepts found'))
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                # Gráfico de conceptos
         | 
| 207 | 
            +
                # st.subheader(semantic_t.get('concept_graph', 'Concepts Graph'))
         | 
| 208 | 
            +
                if 'concept_graph' in analysis and analysis['concept_graph'] is not None:
         | 
| 209 | 
            +
                    try:
         | 
| 210 | 
            +
                        # Container para el grafo con estilos mejorados
         | 
| 211 | 
            +
                        st.markdown(
         | 
| 212 | 
            +
                            """
         | 
| 213 | 
            +
                            <style>
         | 
| 214 | 
            +
                            .graph-container {
         | 
| 215 | 
            +
                                background-color: white;
         | 
| 216 | 
            +
                                border-radius: 10px;
         | 
| 217 | 
            +
                                padding: 20px;
         | 
| 218 | 
            +
                                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
         | 
| 219 | 
            +
                                margin: 10px 0;
         | 
| 220 | 
            +
                            }
         | 
| 221 | 
            +
                            .button-container {
         | 
| 222 | 
            +
                                display: flex;
         | 
| 223 | 
            +
                                gap: 10px;
         | 
| 224 | 
            +
                                margin: 10px 0;
         | 
| 225 | 
            +
                            }
         | 
| 226 | 
            +
                            </style>
         | 
| 227 | 
            +
                            """,
         | 
| 228 | 
            +
                            unsafe_allow_html=True
         | 
| 229 | 
            +
                        )
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                        with st.container():
         | 
| 232 | 
            +
                            st.markdown('<div class="graph-container">', unsafe_allow_html=True)
         | 
| 233 | 
            +
                            
         | 
| 234 | 
            +
                            # Mostrar grafo
         | 
| 235 | 
            +
                            graph_bytes = analysis['concept_graph']
         | 
| 236 | 
            +
                            graph_base64 = base64.b64encode(graph_bytes).decode()
         | 
| 237 | 
            +
                            st.markdown(
         | 
| 238 | 
            +
                                f'<img src="data:image/png;base64,{graph_base64}" alt="Concept Graph" style="width:100%;"/>',
         | 
| 239 | 
            +
                                unsafe_allow_html=True
         | 
| 240 | 
            +
                            )
         | 
| 241 | 
            +
                            
         | 
| 242 | 
            +
                            # Leyenda del grafo
         | 
| 243 | 
            +
                            st.caption(semantic_t.get(
         | 
| 244 | 
            +
                                'graph_description',
         | 
| 245 | 
            +
                                'Visualización de relaciones entre conceptos clave identificados en el texto.'
         | 
| 246 | 
            +
                            ))
         | 
| 247 | 
            +
                            
         | 
| 248 | 
            +
                            st.markdown('</div>', unsafe_allow_html=True)
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                        # Contenedor para botones
         | 
| 251 | 
            +
                        col1, col2 = st.columns([1,4])
         | 
| 252 | 
            +
                        with col1:
         | 
| 253 | 
            +
                            st.download_button(
         | 
| 254 | 
            +
                                label="📥 " + semantic_t.get('download_graph', "Download"),
         | 
| 255 | 
            +
                                data=graph_bytes,
         | 
| 256 | 
            +
                                file_name="semantic_graph.png",
         | 
| 257 | 
            +
                                mime="image/png",
         | 
| 258 | 
            +
                                use_container_width=True
         | 
| 259 | 
            +
                            )
         | 
| 260 | 
            +
                        
         | 
| 261 | 
            +
                        # Expandible con la interpretación
         | 
| 262 | 
            +
                        with st.expander("📊 " + semantic_t.get('graph_help', "Graph Interpretation")):
         | 
| 263 | 
            +
                            st.markdown("""
         | 
| 264 | 
            +
                                - 🔀 Las flechas indican la dirección de la relación entre conceptos
         | 
| 265 | 
            +
                                - 🎨 Los colores más intensos indican conceptos más centrales en el texto
         | 
| 266 | 
            +
                                - ⭕ El tamaño de los nodos representa la frecuencia del concepto
         | 
| 267 | 
            +
                                - ↔️ El grosor de las líneas indica la fuerza de la conexión
         | 
| 268 | 
            +
                            """)
         | 
| 269 | 
            +
                    
         | 
| 270 | 
            +
                    except Exception as e:
         | 
| 271 | 
            +
                        logger.error(f"Error displaying graph: {str(e)}")
         | 
| 272 | 
            +
                        st.error(semantic_t.get('graph_error', 'Error displaying the graph'))
         | 
| 273 | 
            +
                else:
         | 
| 274 | 
            +
                    st.info(semantic_t.get('no_graph', 'No concept graph available'))
         | 
| 275 | 
            +
             | 
| 276 | 
            +
             | 
| 277 | 
            +
            ########################################################################################
         | 
| 278 | 
            +
            '''
         | 
| 279 | 
            +
                # Botón de exportación al final
         | 
| 280 | 
            +
                if 'semantic_analysis_counter' in st.session_state:
         | 
| 281 | 
            +
                    col1, col2, col3 = st.columns([2,1,2])
         | 
| 282 | 
            +
                    with col2:
         | 
| 283 | 
            +
                        if st.button(
         | 
| 284 | 
            +
                            semantic_t.get('export_button', 'Export Analysis'), 
         | 
| 285 | 
            +
                            key=f"semantic_export_{st.session_state.semantic_analysis_counter}",
         | 
| 286 | 
            +
                            use_container_width=True
         | 
| 287 | 
            +
                        ):
         | 
| 288 | 
            +
                            pdf_buffer = export_user_interactions(st.session_state.username, 'semantic')
         | 
| 289 | 
            +
                            st.download_button(
         | 
| 290 | 
            +
                                label=semantic_t.get('download_pdf', 'Download PDF'),
         | 
| 291 | 
            +
                                data=pdf_buffer,
         | 
| 292 | 
            +
                                file_name="semantic_analysis.pdf",
         | 
| 293 | 
            +
                                mime="application/pdf",
         | 
| 294 | 
            +
                                key=f"semantic_download_{st.session_state.semantic_analysis_counter}"
         | 
| 295 | 
            +
                            )
         | 
| 296 | 
             
            '''
         | 
