v3 / modules /morphosyntax /morphosyntax_interface.py
AIdeaText's picture
Update modules/morphosyntax/morphosyntax_interface.py
bffd3e5 verified
raw
history blame
19 kB
#modules/morphosyntax/morphosyntax_interface.py
import streamlit as st
import spacy_streamlit
from streamlit_float import *
from streamlit_antd_components import *
from streamlit.components.v1 import html
import base64
# Importar desde morphosyntax_process.py
from .morphosyntax_process import (
process_morphosyntactic_input,
format_analysis_results
)
from ..utils.widget_utils import generate_unique_key
from ..database.morphosintax_mongo_db import store_student_morphosyntax_result
from ..database.chat_db import store_chat_history
from ..database.morphosintaxis_export import export_user_interactions
import logging
logger = logging.getLogger(__name__)
def display_morphosyntax_interface(lang_code, nlp_models, t):
"""
Interfaz para el análisis morfosintáctico
Args:
lang_code: Código del idioma actual
nlp_models: Modelos de spaCy cargados
t: Diccionario de traducciones
"""
# Obtener el diccionario de traducciones morfosintácticas
morpho_t = t.get('MORPHOSYNTACTIC', {})
# Inicializar el estado de la entrada
input_key = f"morphosyntax_input_{lang_code}"
if input_key not in st.session_state:
st.session_state[input_key] = ""
# Campo de entrada de texto
sentence_input = st.text_area(
morpho_t.get('morpho_input_label', 'Enter text to analyze'),
height=150,
placeholder=morpho_t.get('morpho_input_placeholder', 'Enter your text here...'),
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}"])
)
# Botón de análisis
if st.button(morpho_t.get('analyze_button', 'Analyze text'), key=f"analyze_button_{lang_code}"):
current_input = st.session_state[input_key]
if current_input:
try:
# Procesar el texto
doc = nlp_models[lang_code](current_input)
# Realizar análisis morfosintáctico
advanced_analysis = perform_advanced_morphosyntactic_analysis(
current_input,
nlp_models[lang_code]
)
# Guardar resultado en el estado de la sesión
st.session_state.morphosyntax_result = {
'doc': doc,
'advanced_analysis': advanced_analysis
}
# Mostrar resultados
display_morphosyntax_results(
st.session_state.morphosyntax_result,
lang_code,
morpho_t # Pasar morpho_t en lugar de t
)
# Guardar en la base de datos
if store_morphosyntax_result(
st.session_state.username,
current_input,
get_repeated_words_colors(doc),
advanced_analysis['arc_diagram'],
advanced_analysis['pos_analysis'],
advanced_analysis['morphological_analysis'],
advanced_analysis['sentence_structure']
):
st.success(morpho_t.get('success_message', 'Analysis saved successfully'))
else:
st.error(morpho_t.get('error_message', 'Error saving analysis'))
except Exception as e:
st.error(morpho_t.get('error_processing', f'Error processing text: {str(e)}'))
else:
st.warning(morpho_t.get('warning_message', 'Please enter a text to analyze'))
# Mostrar resultados previos si existen
elif 'morphosyntax_result' in st.session_state and st.session_state.morphosyntax_result is not None:
display_morphosyntax_results(
st.session_state.morphosyntax_result,
lang_code,
morpho_t # Pasar morpho_t en lugar de t
)
else:
st.info(morpho_t.get('morpho_initial_message', 'Enter text to begin analysis'))
def display_morphosyntax_results(result, lang_code, t):
if result is None:
st.warning(t['no_results']) # Añade esta traducción a tu diccionario
return
doc = result['doc']
advanced_analysis = result['advanced_analysis']
# Mostrar leyenda (código existente)
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)
# 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
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'<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)
# Botón de exportación
if st.button(morpho_t.get('export_button', 'Export Analysis')):
pdf_buffer = export_user_interactions(st.session_state.username, 'morphosyntax')
st.download_button(
label=morpho_t.get('download_pdf', 'Download PDF'),
data=pdf_buffer,
file_name="morphosyntax_analysis.pdf",
mime="application/pdf"
)
'''
if user_input:
# Añadir el mensaje del usuario al historial
st.session_state.morphosyntax_chat_history.append({"role": "user", "content": user_input})
# Procesar el input del usuario nuevo al 26-9-2024
response, visualizations, result = process_morphosyntactic_input(user_input, lang_code, nlp_models, t)
# Mostrar indicador de carga
with st.spinner(t.get('processing', 'Processing...')):
try:
# Procesar el input del usuario
response, visualizations, result = process_morphosyntactic_input(user_input, lang_code, nlp_models, t)
# Añadir la respuesta al historial
message = {
"role": "assistant",
"content": response
}
if visualizations:
message["visualizations"] = visualizations
st.session_state.morphosyntax_chat_history.append(message)
# Mostrar la respuesta más reciente
with st.chat_message("assistant"):
st.write(response)
if visualizations:
for i, viz in enumerate(visualizations):
st.markdown(f"**Oración {i+1} del párrafo analizado**")
st.components.v1.html(
f"""
<div style="width: 100%; overflow-x: auto; white-space: nowrap;">
<div style="min-width: 1200px;">
{viz}
</div>
</div>
""",
height=350,
scrolling=True
)
if i < len(visualizations) - 1:
st.markdown("---") # Separador entre diagramas
# Si es un análisis, guardarlo en la base de datos
if user_input.startswith('/analisis_morfosintactico') and result:
store_morphosyntax_result(
st.session_state.username,
user_input.split('[', 1)[1].rsplit(']', 1)[0], # texto analizado
result.get('repeated_words', {}),
visualizations,
result.get('pos_analysis', []),
result.get('morphological_analysis', []),
result.get('sentence_structure', [])
)
except Exception as e:
st.error(f"{t['error_processing']}: {str(e)}")
# Forzar la actualización de la interfaz
st.rerun()
# Botón para limpiar el historial del chat
if st.button(t['clear_chat'], key=generate_unique_key('morphosyntax', 'clear_chat')):
st.session_state.morphosyntax_chat_history = []
st.rerun()
'''
'''
############ MODULO PARA DEPURACIÓN Y PRUEBAS #####################################################
def display_morphosyntax_interface(lang_code, nlp_models, t):
st.subheader(t['morpho_title'])
text_input = st.text_area(
t['warning_message'],
height=150,
key=generate_unique_key("morphosyntax", "text_area")
)
if st.button(
t['results_title'],
key=generate_unique_key("morphosyntax", "analyze_button")
):
if text_input:
# Aquí iría tu lógica de análisis morfosintáctico
# Por ahora, solo mostraremos un mensaje de placeholder
st.info(t['analysis_placeholder'])
else:
st.warning(t['no_text_warning'])
###
#################################################
'''