#Importaciones generales import streamlit as st import re import io import base64 import matplotlib.pyplot as plt import pandas as pd from streamlit_player import st_player # Necesitarás instalar esta librería: pip install streamlit-player from spacy import displacy #Importaciones locales #Importaciones locales de autenticación y base de datos from .auth import authenticate_user, register_user, get_user_role from .database import get_student_data, store_morphosyntax_result, store_semantic_result #Importacoines locales funciones de análisis from .morpho_analysis import generate_arc_diagram, get_repeated_words_colors, highlight_repeated_words, POS_COLORS, POS_TRANSLATIONS from .semantic_analysis import visualize_semantic_relations, perform_semantic_analysis from .discourse_analysis import compare_semantic_analysis, perform_discourse_analysis #from .discourse_analysis import discourse_graph ################################################################################################## def login_register_page(): st.title("AIdeaText") # Dividir la pantalla en dos columnas left_column, right_column = st.columns([1, 3]) # 25% izquierda, 75% derecha # Sección izquierda para login y registro with left_column: tab1, tab2 = st.tabs(["Iniciar Sesión", "Registrarse"]) with tab1: login_form() with tab2: register_form() # Sección derecha para videos de YouTube with right_column: st.header("Videos: pitch, demos, entrevistas, otros") # Diccionario de videos de YouTube con títulos amigables videos = { "Intro AideaText": "https://www.youtube.com/watch?v=UA-md1VxaRc", "Pitch que facilitó acceder a la segunda fase de IFE Explora del TEC de Monterrey": "https://www.youtube.com/watch?v=Fqi4Di_Rj_s", "Entrevista con el doctor Guillermo Ruíz, EduMate Lima Perú" : "https://www.youtube.com/watch?v=_ch8cRja3oc", "Demo versión desktop de AIdeaText": "https://www.youtube.com/watch?v=nP6eXbog-ZY" } # Selector de video video_titles = list(videos.keys()) if video_titles: selected_title = st.selectbox("Selecciona un video tutorial:", video_titles) # Obtener la URL correspondiente al título seleccionado if selected_title in videos: selected_video = videos[selected_title] # Reproductor de YouTube try: st_player(selected_video) except Exception as e: st.error(f"Error al cargar el video: {str(e)}") else: st.warning("El video seleccionado no está disponible.") else: st.warning("No hay videos disponibles para mostrar.") # Información adicional 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 login_form(): username = st.text_input("Usuario") password = st.text_input("Contraseña", type='password') captcha_answer = st.text_input("Captcha: ¿Cuánto es 2 + 3?") if st.button("Iniciar Sesión"): if captcha_answer == "5": if authenticate_user(username, password): st.success(f"Bienvenido, {username}!") st.session_state.logged_in = True st.session_state.username = username st.session_state.role = get_user_role(username) st.experimental_rerun() else: st.error("Usuario o contraseña incorrectos") else: st.error("Captcha incorrecto") ################################################################################################## def register_form(): new_username = st.text_input("Nuevo Usuario") new_password = st.text_input("Nueva Contraseña", type='password') carrera = st.text_input("Carrera") captcha_answer = st.text_input("Captcha: ¿Cuánto es 3 + 4?") if st.button("Registrarse"): if captcha_answer == "7": additional_info = {'carrera': carrera} if register_user(new_username, new_password, additional_info): st.success("Registro exitoso. Por favor, inicia sesión.") else: st.error("El usuario ya existe o ocurrió un error durante el registro") else: st.error("Captcha incorrecto") ################################################################################################## def display_chat_interface(): st.markdown("### Chat con AIdeaText") if 'chat_history' not in st.session_state: st.session_state.chat_history = [] for i, (role, text) in enumerate(st.session_state.chat_history): if role == "user": st.text_area(f"Tú:", value=text, height=50, key=f"user_message_{i}", disabled=True) else: st.text_area(f"AIdeaText:", value=text, height=50, key=f"bot_message_{i}", disabled=True) user_input = st.text_input("Escribe tu mensaje aquí:") if st.button("Enviar"): if user_input: st.session_state.chat_history.append(("user", user_input)) response = get_chatbot_response(user_input) st.session_state.chat_history.append(("bot", response)) st.experimental_rerun() ################################################################################################## def display_student_progress(username, lang_code='es'): student_data = get_student_data(username) if student_data is None: 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}") if student_data['entries_count'] > 0: if 'word_count' in student_data and student_data['word_count']: st.subheader("Total de palabras por categoría gramatical") df = pd.DataFrame(list(student_data['word_count'].items()), columns=['category', 'count']) df['label'] = df.apply(lambda x: f"{POS_TRANSLATIONS[lang_code].get(x['category'], x['category'])}", axis=1) df = df.sort_values('count', ascending=False) fig, ax = plt.subplots(figsize=(12, 6)) bars = ax.bar(df['label'], df['count'], color=[POS_COLORS.get(cat, '#CCCCCC') for cat in df['category']]) ax.set_xlabel('Categoría Gramatical') ax.set_ylabel('Cantidad de Palabras') ax.set_title('Total de palabras por categoría gramatical') plt.xticks(rotation=45, ha='right') for bar in bars: height = bar.get_height() ax.text(bar.get_x() + bar.get_width()/2., height, f'{height}', ha='center', va='bottom') plt.tight_layout() buf = io.BytesIO() fig.savefig(buf, format='png') buf.seek(0) st.image(buf, use_column_width=True) else: st.info("No hay datos de conteo de palabras disponibles.") st.header("Diagramas de Arco") with st.expander("Ver todos los Diagramas de Arco"): for i, entry in enumerate(student_data['entries']): if 'arc_diagrams' in entry and entry['arc_diagrams']: st.subheader(f"Entrada {i+1} - {entry['timestamp']}") st.write(entry['arc_diagrams'][0], unsafe_allow_html=True) st.header("Diagramas de Red") with st.expander("Ver todos los Diagramas de Red"): for i, entry in enumerate(student_data['entries']): if 'network_diagram' in entry and entry['network_diagram']: st.subheader(f"Entrada {i+1} - {entry['timestamp']}") try: image_bytes = base64.b64decode(entry['network_diagram']) st.image(image_bytes) except Exception as e: st.error(f"Error al mostrar el diagrama de red: {str(e)}") else: st.warning("No se encontraron entradas para este estudiante.") st.info("Intenta realizar algunos análisis de texto primero.") ################################################################################################## 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áx. 5,000 palabras):", 'input_placeholder': "El objetivo de esta aplicación es que mejore sus habilidades de redacción...", '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" }, 'en': { 'title': "AIdeaText - Morphological and Syntactic Analysis", 'input_label': "Enter a text to analyze (max 5,000 words):", 'input_placeholder': "The goal of this app is for you to improve your writing skills...", 'analyze_button': "Analyze text", 'repeated_words': "Repeated words", 'legend': "Legend: Grammatical categories", 'arc_diagram': "Syntactic analysis: Arc diagram", 'sentence': "Sentence" }, 'fr': { 'title': "AIdeaText - Analyse morphologique et syntaxique", 'input_label': "Entrez un texte à analyser (max 5 000 mots) :", 'input_placeholder': "Le but de cette application est d'améliorer vos compétences en rédaction...", '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" } } t = translations[lang_code] input_key = f"morphosyntax_input_{lang_code}" # Inicializar la clave en session_state si no existe if input_key not in st.session_state: st.session_state[input_key] = "" # Función para actualizar el estado del input def update_input(): st.session_state[input_key] = st.session_state[f"text_area_{lang_code}"] 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=update_input ) 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) 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) st.markdown(f"##### {t['legend']}") legend_html = "<div style='display: flex; flex-wrap: wrap;'>" for pos, color in POS_COLORS.items(): if pos in POS_TRANSLATIONS[lang_code]: legend_html += f"<div style='margin-right: 10px;'><span style='background-color: {color}; padding: 2px 5px;'>{POS_TRANSLATIONS[lang_code][pos]}</span></div>" legend_html += "</div>" st.markdown(legend_html, unsafe_allow_html=True) 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'<svg[^>]*>', lambda m: m.group(0).replace('height="450"', 'height="300"'), html) html = re.sub(r'<g [^>]*transform="translate\((\d+),(\d+)\)"', lambda m: f'<g transform="translate({m.group(1)},50)"', html) st.write(html, unsafe_allow_html=True) arc_diagrams.append(html) if store_morphosyntax_result( st.session_state.username, current_input, word_colors, arc_diagrams, ): st.success("Análisis guardado correctamente.") else: st.error("Hubo un problema al guardar el análisis. Por favor, inténtelo de nuevo.") else: st.warning("Por favor, ingrese un texto para analizar.") ############################################################################################################### def display_semantic_analysis_interface(nlp_models, lang_code): translations = { 'es': { 'title': "AIdeaText - Análisis semántico", 'file_uploader': "Cargar archivo de texto", 'analyze_button': "Analizar texto", 'semantic_relations': "Relaciones Semánticas Relevantes", }, 'en': { 'title': "AIdeaText - Semantic Analysis", 'file_uploader': "Upload text file", 'analyze_button': "Analyze text", 'semantic_relations': "Relevant Semantic Relations", }, 'fr': { 'title': "AIdeaText - Analyse sémantique", 'file_uploader': "Télécharger le fichier texte", 'analyze_button': "Analyser le texte", 'semantic_relations': "Relations Sémantiques Pertinentes", } } t = translations[lang_code] st.header(t['title']) uploaded_file = st.file_uploader(t['file_uploader'], type=['txt']) if uploaded_file is not None: text_content = uploaded_file.getvalue().decode('utf-8') if st.button(t['analyze_button']): relations_graph = perform_semantic_analysis(text_content, nlp_models[lang_code], lang_code) with st.expander(t['semantic_relations'], expanded=True): st.pyplot(relations_graph) ################################################################################################## def display_discourse_analysis_interface(nlp_models, lang_code): translations = { 'es': { 'title': "AIdeaText - Análisis del discurso", 'file_uploader1': "Cargar archivo de texto 1 (Patrón)", 'file_uploader2': "Cargar archivo de texto 2 (Comparación)", 'analyze_button': "Analizar textos", 'comparison': "Comparación de Relaciones Semánticas", }, 'en': { 'title': "AIdeaText - Discourse Analysis", 'file_uploader1': "Upload text file 1 (Pattern)", 'file_uploader2': "Upload text file 2 (Comparison)", 'analyze_button': "Analyze texts", 'comparison': "Comparison of Semantic Relations", }, 'fr': { 'title': "AIdeaText - Analyse du discours", 'file_uploader1': "Télécharger le fichier texte 1 (Modèle)", 'file_uploader2': "Télécharger le fichier texte 2 (Comparaison)", 'analyze_button': "Analyser les textes", 'comparison': "Comparaison des Relations Sémantiques", } } t = translations[lang_code] st.header(t['title']) col1, col2 = st.columns(2) with col1: uploaded_file1 = st.file_uploader(t['file_uploader1'], type=['txt']) with col2: uploaded_file2 = st.file_uploader(t['file_uploader2'], type=['txt']) if uploaded_file1 is not None and uploaded_file2 is not None: text_content1 = uploaded_file1.getvalue().decode('utf-8') text_content2 = uploaded_file2.getvalue().decode('utf-8') if st.button(t['analyze_button']): graph1, graph2 = perform_discourse_analysis(text_content1, text_content2, nlp_models[lang_code], lang_code) st.subheader(t['comparison']) col1, col2 = st.columns(2) with col1: st.pyplot(graph1) with col2: st.pyplot(graph2) ################################################################################################## def get_chatbot_response(input_text): # Esta función debe ser implementada o importada de otro módulo # Por ahora, retornamos un mensaje genérico return "Lo siento, el chatbot no está disponible en este momento."