# Importaciones generales import streamlit as st import re import io from io import BytesIO import base64 import matplotlib.pyplot as plt import pandas as pd 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 ###################################################### # 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 import ( get_student_data, store_application_request, store_morphosyntax_result, store_semantic_result, store_discourse_analysis_result, store_chat_history, create_admin_user, create_student_user, store_user_feedback ) ###################################################### # 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 ) ###################################################### from ..text_analysis.discourse_analysis import ( compare_semantic_analysis, perform_discourse_analysis ) ###################################################### from ..chatbot.chatbot import ( initialize_chatbot, get_chatbot_response ) ################################################################################################## 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}") ################################################################################################## 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(): username = st.text_input("Correo electrónico", key="login_username") password = st.text_input("Contraseña", type="password", key="login_password") if st.button("Iniciar Sesión", key="login_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' print(f"Inicio de sesión exitoso. Usuario: {username}, Rol: {role}") print(f"Estado de sesión después de login: {st.session_state}") st.rerun() else: st.error("Credenciales incorrectas") ################################################################################################## 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 user_page(): st.title("Bienvenido a AIdeaText") st.write(f"Hola, {st.session_state.username}") # Aquí puedes añadir las funcionalidades para el usuario estudiante # Por ejemplo: tabs = st.tabs(["Análisis Morfosintáctico", "Análisis Semántico", "Análisis del Discurso", "Chat", "Mi Progreso", "Formulario de Retroalimentación"]) with tabs[0]: display_morphosyntax_analysis_interface(nlp_models, 'es') # Asumiendo que 'es' es el idioma por defecto with tabs[1]: display_semantic_analysis_interface(nlp_models, 'es') with tabs[2]: display_discourse_analysis_interface(nlp_models, 'es') with tabs[3]: display_chatbot_interface('es') with tabs[4]: display_student_progress(st.session_state.username, 'es') with tabs[5]: display_feedback_form('es') ################################################################################################## def display_videos_and_info(): st.header("Videos: pitch, demos, entrevistas, otros") videos = { "Intro AideaText": "https://www.youtube.com/watch?v=UA-md1VxaRc", "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 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 display_feedback_form(lang_code): translations = { 'es': { 'title': "Formulario de Retroalimentación", 'name': "Nombre", 'email': "Correo electrónico", 'feedback': "Tu retroalimentación", 'submit': "Enviar", 'success': "¡Gracias por tu retroalimentación!", 'error': "Hubo un problema al enviar el formulario. Por favor, intenta de nuevo." }, # ... (traducciones para otros idiomas) } t = translations[lang_code] st.header(t['title']) name = st.text_input(t['name']) email = st.text_input(t['email']) feedback = st.text_area(t['feedback']) if st.button(t['submit']): 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 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) ################################################################################ def display_student_progress(username, lang_code='es'): 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'] st.write(f"Número total de entradas semánticas: {len(semantic_entries)}") for entry in semantic_entries: st.subheader(f"Análisis del {entry['timestamp']}") st.write(f"Archivo analizado: {entry.get('filename', 'Nombre no disponible')}") st.write(f"Claves disponibles en esta entrada: {', '.join(entry.keys())}") # Verificar si 'relations_graph' está en entry antes de intentar acceder if 'network_diagram' in entry: try: logger.info(f"Longitud de la imagen recuperada: {len(entry['network_diagram'])}") st.image(f"data:image/png;base64,{entry['network_diagram']}") except Exception as e: st.error(f"No se pudo mostrar la imagen: {str(e)}") st.write("Datos de la imagen (para depuración):") st.write(entry['network_diagram'][:100] + "...") else: logger.warning(f"No se encontró 'relations_graph' en la entrada: {entry.keys()}") st.write("No se encontró el gráfico para este análisis.") ########################################################## 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']}") st.write(f"Archivo patrón: {entry.get('filename1', 'Nombre no disponible')}") st.write(f"Archivo comparado: {entry.get('filename2', 'Nombre no disponible')}") try: # Intentar obtener y combinar las dos imágenes if 'graph1' in entry and 'graph2' in entry: img1 = Image.open(BytesIO(base64.b64decode(entry['graph1']))) img2 = Image.open(BytesIO(base64.b64decode(entry['graph2']))) # Crear una nueva imagen combinada total_width = img1.width + img2.width max_height = max(img1.height, img2.height) combined_img = Image.new('RGB', (total_width, max_height)) # Pegar las dos imágenes lado a lado combined_img.paste(img1, (0, 0)) combined_img.paste(img2, (img1.width, 0)) # Convertir la imagen combinada a bytes buffered = BytesIO() combined_img.save(buffered, format="PNG") img_str = base64.b64encode(buffered.getvalue()).decode() # Mostrar la imagen combinada st.image(f"data:image/png;base64,{img_str}") elif 'combined_graph' in entry: # Si ya existe una imagen combinada, mostrarla directamente img_bytes = base64.b64decode(entry['combined_graph']) st.image(img_bytes) 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) ################################################################################################## def display_morphosyntax_analysis_interface(nlp_models, lang_code): translations = { 'es': { 'title': "AIdeaText - Análisis morfológico y sintáctico", 'input_label': "Ingrese un texto para analizar (máximo 5,000 palabras", 'input_placeholder': "Esta funcionalidad le ayudará con dos competencias:\n" "[1] \"Escribe diversos tipos de textos en su lengua materna\"\n" "[2] \"Lee diversos tipos de textos escritos en su lengua materna\"\n\n" "Ingrese su texto aquí para analizar...", 'analyze_button': "Analizar texto", 'repeated_words': "Palabras repetidas", 'legend': "Leyenda: Categorías gramaticales", 'arc_diagram': "Análisis sintáctico: Diagrama de arco", 'sentence': "Oración", 'success_message': "Análisis guardado correctamente.", 'error_message': "Hubo un problema al guardar el análisis. Por favor, inténtelo de nuevo.", 'warning_message': "Por favor, ingrese un texto para analizar.", 'pos_analysis': "Análisis de categorías gramaticales", 'morphological_analysis': "Análisis morfológico", 'sentence_structure': "Estructura de oraciones", 'word': "Palabra", 'count': "Cantidad", 'percentage': "Porcentaje", 'examples': "Ejemplos", 'lemma': "Lema", 'tag': "Etiqueta", 'dep': "Dependencia", 'morph': "Morfología", 'root': "Raíz", 'subjects': "Sujetos", 'objects': "Objetos", 'verbs': "Verbos", 'grammatical_category': "Categoría gramatical", 'dependency': "Dependencia", 'morphology': "Morfología" }, 'en': { 'title': "AIdeaText - Morphological and Syntactic Analysis", 'input_label': "Enter a text to analyze (max 5,000 words):", 'input_placeholder': "This functionality will help you with two competencies:\n" "[1] \"Write various types of texts in your native language\"\n" "[2] \"Read various types of written texts in your native language\"\n\n" "Enter your text here to analyze...", 'analyze_button': "Analyze text", 'repeated_words': "Repeated words", 'legend': "Legend: Grammatical categories", 'arc_diagram': "Syntactic analysis: Arc diagram", 'sentence': "Sentence", 'success_message': "Analysis saved successfully.", 'error_message': "There was a problem saving the analysis. Please try again.", 'warning_message': "Please enter a text to analyze.", 'pos_analysis': "Part of Speech Analysis", 'morphological_analysis': "Morphological Analysis", 'sentence_structure': "Sentence Structure", 'word': "Word", 'count': "Count", 'percentage': "Percentage", 'examples': "Examples", 'lemma': "Lemma", 'tag': "Tag", 'dep': "Dependency", 'morph': "Morphology", 'root': "Root", 'subjects': "Subjects", 'objects': "Objects", 'verbs': "Verbs", 'grammatical_category': "Grammatical category", 'dependency': "Dependency", 'morphology': "Morphology" }, 'fr': { 'title': "AIdeaText - Analyse morphologique et syntaxique", 'input_label': "Entrez un texte à analyser (max 5 000 mots) :", 'input_placeholder': "Cette fonctionnalité vous aidera avec deux compétences :\n" "[1] \"Écrire divers types de textes dans votre langue maternelle\"\n" "[2] \"Lire divers types de textes écrits dans votre langue maternelle\"\n\n" "Entrez votre texte ici pour l'analyser...", 'analyze_button': "Analyser le texte", 'repeated_words': "Mots répétés", 'legend': "Légende : Catégories grammaticales", 'arc_diagram': "Analyse syntaxique : Diagramme en arc", 'sentence': "Phrase", 'success_message': "Analyse enregistrée avec succès.", 'error_message': "Un problème est survenu lors de l'enregistrement de l'analyse. Veuillez réessayer.", 'warning_message': "Veuillez entrer un texte à analyser.", 'pos_analysis': "Analyse des parties du discours", 'morphological_analysis': "Analyse morphologique", 'sentence_structure': "Structure des phrases", 'word': "Mot", 'count': "Nombre", 'percentage': "Pourcentage", 'examples': "Exemples", 'lemma': "Lemme", 'tag': "Étiquette", 'dep': "Dépendance", 'morph': "Morphologie", 'root': "Racine", 'subjects': "Sujets", 'objects': "Objets", 'verbs': "Verbes", 'grammatical_category': "Catégorie grammaticale", 'dependency': "Dépendance", 'morphology': "Morphologie" } } t = translations[lang_code] input_key = f"morphosyntax_input_{lang_code}" if input_key not in st.session_state: st.session_state[input_key] = "" sentence_input = st.text_area( t['input_label'], height=150, placeholder=t['input_placeholder'], value=st.session_state[input_key], key=f"text_area_{lang_code}", on_change=lambda: setattr(st.session_state, input_key, st.session_state[f"text_area_{lang_code}"]) ) if st.button(t['analyze_button'], key=f"analyze_button_{lang_code}"): current_input = st.session_state[input_key] if current_input: doc = nlp_models[lang_code](current_input) # Análisis morfosintáctico avanzado advanced_analysis = perform_advanced_morphosyntactic_analysis(current_input, nlp_models[lang_code]) # 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"
{POS_TRANSLATIONS[lang_code][pos]}
" legend_html += "
" st.markdown(legend_html, unsafe_allow_html=True) # Mostrar análisis de palabras repetidas (código existente) word_colors = get_repeated_words_colors(doc) with st.expander(t['repeated_words'], expanded=True): highlighted_text = highlight_repeated_words(doc, word_colors) st.markdown(highlighted_text, unsafe_allow_html=True) # Mostrar estructura de oraciones with st.expander(t['sentence_structure'], expanded=True): for i, sent_analysis in enumerate(advanced_analysis['sentence_structure']): sentence_str = ( f"**{t['sentence']} {i+1}** " f"{t['root']}: {sent_analysis['root']} ({sent_analysis['root_pos']}) -- " f"{t['subjects']}: {', '.join(sent_analysis['subjects'])} -- " f"{t['objects']}: {', '.join(sent_analysis['objects'])} -- " f"{t['verbs']}: {', '.join(sent_analysis['verbs'])}" ) st.markdown(sentence_str) # Mostrar análisis de categorías gramaticales # Mostrar análisis morfológico # Mostrar análisis de categorías gramaticales # Mostrar análisis morfológico col1, col2 = st.columns(2) with col1: with st.expander(t['pos_analysis'], expanded=True): pos_df = pd.DataFrame(advanced_analysis['pos_analysis']) # Traducir las etiquetas POS a sus nombres en el idioma seleccionado pos_df['pos'] = pos_df['pos'].map(lambda x: POS_TRANSLATIONS[lang_code].get(x, x)) # Renombrar las columnas para mayor claridad pos_df = pos_df.rename(columns={ 'pos': t['grammatical_category'], 'count': t['count'], 'percentage': t['percentage'], 'examples': t['examples'] }) # Mostrar el dataframe st.dataframe(pos_df) with col2: with st.expander(t['morphological_analysis'], expanded=True): morph_df = pd.DataFrame(advanced_analysis['morphological_analysis']) # Definir el mapeo de columnas column_mapping = { 'text': t['word'], 'lemma': t['lemma'], 'pos': t['grammatical_category'], 'dep': t['dependency'], 'morph': t['morphology'] } # Renombrar las columnas existentes morph_df = morph_df.rename(columns={col: new_name for col, new_name in column_mapping.items() if col in morph_df.columns}) # Traducir las categorías gramaticales morph_df[t['grammatical_category']] = morph_df[t['grammatical_category']].map(lambda x: POS_TRANSLATIONS[lang_code].get(x, x)) # Traducir las dependencias dep_translations = { 'es': { 'ROOT': 'RAÍZ', 'nsubj': 'sujeto nominal', 'obj': 'objeto', 'iobj': 'objeto indirecto', 'csubj': 'sujeto clausal', 'ccomp': 'complemento clausal', 'xcomp': 'complemento clausal abierto', 'obl': 'oblicuo', 'vocative': 'vocativo', 'expl': 'expletivo', 'dislocated': 'dislocado', 'advcl': 'cláusula adverbial', 'advmod': 'modificador adverbial', 'discourse': 'discurso', 'aux': 'auxiliar', 'cop': 'cópula', 'mark': 'marcador', 'nmod': 'modificador nominal', 'appos': 'aposición', 'nummod': 'modificador numeral', 'acl': 'cláusula adjetiva', 'amod': 'modificador adjetival', 'det': 'determinante', 'clf': 'clasificador', 'case': 'caso', 'conj': 'conjunción', 'cc': 'coordinante', 'fixed': 'fijo', 'flat': 'plano', 'compound': 'compuesto', 'list': 'lista', 'parataxis': 'parataxis', 'orphan': 'huérfano', 'goeswith': 'va con', 'reparandum': 'reparación', 'punct': 'puntuación' }, 'en': { 'ROOT': 'ROOT', 'nsubj': 'nominal subject', 'obj': 'object', 'iobj': 'indirect object', 'csubj': 'clausal subject', 'ccomp': 'clausal complement', 'xcomp': 'open clausal complement', 'obl': 'oblique', 'vocative': 'vocative', 'expl': 'expletive', 'dislocated': 'dislocated', 'advcl': 'adverbial clause modifier', 'advmod': 'adverbial modifier', 'discourse': 'discourse element', 'aux': 'auxiliary', 'cop': 'copula', 'mark': 'marker', 'nmod': 'nominal modifier', 'appos': 'appositional modifier', 'nummod': 'numeric modifier', 'acl': 'clausal modifier of noun', 'amod': 'adjectival modifier', 'det': 'determiner', 'clf': 'classifier', 'case': 'case marking', 'conj': 'conjunct', 'cc': 'coordinating conjunction', 'fixed': 'fixed multiword expression', 'flat': 'flat multiword expression', 'compound': 'compound', 'list': 'list', 'parataxis': 'parataxis', 'orphan': 'orphan', 'goeswith': 'goes with', 'reparandum': 'reparandum', 'punct': 'punctuation' }, 'fr': { 'ROOT': 'RACINE', 'nsubj': 'sujet nominal', 'obj': 'objet', 'iobj': 'objet indirect', 'csubj': 'sujet phrastique', 'ccomp': 'complément phrastique', 'xcomp': 'complément phrastique ouvert', 'obl': 'oblique', 'vocative': 'vocatif', 'expl': 'explétif', 'dislocated': 'disloqué', 'advcl': 'clause adverbiale', 'advmod': 'modifieur adverbial', 'discourse': 'élément de discours', 'aux': 'auxiliaire', 'cop': 'copule', 'mark': 'marqueur', 'nmod': 'modifieur nominal', 'appos': 'apposition', 'nummod': 'modifieur numéral', 'acl': 'clause relative', 'amod': 'modifieur adjectival', 'det': 'déterminant', 'clf': 'classificateur', 'case': 'marqueur de cas', 'conj': 'conjonction', 'cc': 'coordination', 'fixed': 'expression figée', 'flat': 'construction plate', 'compound': 'composé', 'list': 'liste', 'parataxis': 'parataxe', 'orphan': 'orphelin', 'goeswith': 'va avec', 'reparandum': 'réparation', 'punct': 'ponctuation' } } morph_df[t['dependency']] = morph_df[t['dependency']].map(lambda x: dep_translations[lang_code].get(x, x)) # Traducir la morfología def translate_morph(morph_string, lang_code): morph_translations = { 'es': { 'Gender': 'Género', 'Number': 'Número', 'Case': 'Caso', 'Definite': 'Definido', 'PronType': 'Tipo de Pronombre', 'Person': 'Persona', 'Mood': 'Modo', 'Tense': 'Tiempo', 'VerbForm': 'Forma Verbal', 'Voice': 'Voz', 'Fem': 'Femenino', 'Masc': 'Masculino', 'Sing': 'Singular', 'Plur': 'Plural', 'Ind': 'Indicativo', 'Sub': 'Subjuntivo', 'Imp': 'Imperativo', 'Inf': 'Infinitivo', 'Part': 'Participio', 'Ger': 'Gerundio', 'Pres': 'Presente', 'Past': 'Pasado', 'Fut': 'Futuro', 'Perf': 'Perfecto', 'Imp': 'Imperfecto' }, 'en': { 'Gender': 'Gender', 'Number': 'Number', 'Case': 'Case', 'Definite': 'Definite', 'PronType': 'Pronoun Type', 'Person': 'Person', 'Mood': 'Mood', 'Tense': 'Tense', 'VerbForm': 'Verb Form', 'Voice': 'Voice', 'Fem': 'Feminine', 'Masc': 'Masculine', 'Sing': 'Singular', 'Plur': 'Plural', 'Ind': 'Indicative', 'Sub': 'Subjunctive', 'Imp': 'Imperative', 'Inf': 'Infinitive', 'Part': 'Participle', 'Ger': 'Gerund', 'Pres': 'Present', 'Past': 'Past', 'Fut': 'Future', 'Perf': 'Perfect', 'Imp': 'Imperfect' }, 'fr': { 'Gender': 'Genre', 'Number': 'Nombre', 'Case': 'Cas', 'Definite': 'Défini', 'PronType': 'Type de Pronom', 'Person': 'Personne', 'Mood': 'Mode', 'Tense': 'Temps', 'VerbForm': 'Forme Verbale', 'Voice': 'Voix', 'Fem': 'Féminin', 'Masc': 'Masculin', 'Sing': 'Singulier', 'Plur': 'Pluriel', 'Ind': 'Indicatif', 'Sub': 'Subjonctif', 'Imp': 'Impératif', 'Inf': 'Infinitif', 'Part': 'Participe', 'Ger': 'Gérondif', 'Pres': 'Présent', 'Past': 'Passé', 'Fut': 'Futur', 'Perf': 'Parfait', 'Imp': 'Imparfait' } } for key, value in morph_translations[lang_code].items(): morph_string = morph_string.replace(key, value) return morph_string morph_df[t['morphology']] = morph_df[t['morphology']].apply(lambda x: translate_morph(x, lang_code)) # Seleccionar y ordenar las columnas a mostrar columns_to_display = [t['word'], t['lemma'], t['grammatical_category'], t['dependency'], t['morphology']] columns_to_display = [col for col in columns_to_display if col in morph_df.columns] # Mostrar el DataFrame st.dataframe(morph_df[columns_to_display]) # Mostrar diagramas de arco (código existente) with st.expander(t['arc_diagram'], expanded=True): sentences = list(doc.sents) arc_diagrams = [] for i, sent in enumerate(sentences): st.subheader(f"{t['sentence']} {i+1}") html = displacy.render(sent, style="dep", options={"distance": 100}) html = html.replace('height="375"', 'height="200"') html = re.sub(r']*>', lambda m: m.group(0).replace('height="450"', 'height="300"'), html) html = re.sub(r']*transform="translate\((\d+),(\d+)\)"', lambda m: f'window.scrollTo(0,document.body.scrollHeight);', unsafe_allow_html=True) ###################################################### if __name__ == "__main__": main()