AIdeaText commited on
Commit
59df544
verified
2 Parent(s): 427dbb7 d382018

Merge branch #AIdeaText/v3' into 'AIdeaText/v4'

Browse files
app.py CHANGED
@@ -57,8 +57,9 @@ from modules.utils.widget_utils import generate_unique_key
57
 
58
  # Importaciones de interfaces
59
  from modules.morphosyntax.morphosyntax_interface import (
60
- display_morphosyntax_interface,
61
- display_morphosyntax_results
 
62
  )
63
 
64
  from modules.semantic.semantic_interface import (
 
57
 
58
  # Importaciones de interfaces
59
  from modules.morphosyntax.morphosyntax_interface import (
60
+ display_morphosyntax_interface,
61
+ display_arc_diagram
62
+ #display_morphosyntax_results
63
  )
64
 
65
  from modules.semantic.semantic_interface import (
modules/__init__.py CHANGED
@@ -134,10 +134,27 @@ def load_database_functions():
134
  get_student_situation_history,
135
  update_exercise_status
136
  )
 
 
 
 
 
 
 
 
 
 
137
 
138
  from .database.chat_mongo_db import store_chat_history, get_chat_history
139
 
140
  return {
 
 
 
 
 
 
 
141
  'store_current_situation_result': store_current_situation_result,
142
  'verify_storage': verify_storage,
143
  'get_recent_sessions': get_recent_sessions,
@@ -192,13 +209,9 @@ def load_student_activities_v2_functions():
192
 
193
  def load_morphosyntax_functions():
194
  from .morphosyntax.morphosyntax_interface import (
195
- cache_analysis_results,
196
- get_cached_analysis,
197
- arc_analysis_state,
198
- reset_morpho_state,
199
- display_original_analysis,
200
- display_iteration_analysis,
201
- display_morphosyntax_interface,
202
  display_morphosyntax_results
203
  )
204
  from .morphosyntax.morphosyntax_process import (
@@ -208,14 +221,12 @@ def load_morphosyntax_functions():
208
  )
209
 
210
  return {
211
- 'cache_analysis_results': cache_analysis_results,
212
- 'get_cached_analysis': get_cached_analysis,
213
- 'arc_analysis_state': arc_analysis_state,
214
- 'reset_morpho_state': reset_morpho_state,
215
- 'display_original_analysis': display_original_analysis,
216
- 'display_iteration_analysis': display_iteration_analysis,
217
  'display_morphosyntax_interface': display_morphosyntax_interface,
218
- 'display_morphosyntax_results': display_morphosyntax_results,
219
  'process_morphosyntactic_input': process_morphosyntactic_input,
220
  'format_analysis_results': format_analysis_results,
221
  'perform_advanced_morphosyntactic_analysis': perform_advanced_morphosyntactic_analysis
 
134
  get_student_situation_history,
135
  update_exercise_status
136
  )
137
+
138
+ # Importar nuevas funciones de an谩lisis morfosint谩ctico iterativo
139
+ from .morphosyntax_iterative_mongo_db import (
140
+ store_student_morphosyntax_base,
141
+ store_student_morphosyntax_iteration,
142
+ get_student_morphosyntax_analysis,
143
+ update_student_morphosyntax_analysis,
144
+ delete_student_morphosyntax_analysis,
145
+ get_student_morphosyntax_data
146
+ )
147
 
148
  from .database.chat_mongo_db import store_chat_history, get_chat_history
149
 
150
  return {
151
+ # Nuevas funciones morfosint谩cticas iterativas
152
+ 'store_student_morphosyntax_base': store_student_morphosyntax_base,
153
+ 'store_student_morphosyntax_iteration': store_student_morphosyntax_iteration,
154
+ 'get_student_morphosyntax_iterative_analysis': get_student_morphosyntax_analysis, # Renombrada para evitar conflicto
155
+ 'update_student_morphosyntax_iterative': update_student_morphosyntax_analysis, # Renombrada para evitar conflicto
156
+ 'delete_student_morphosyntax_iterative': delete_student_morphosyntax_analysis, # Renombrada para evitar conflicto
157
+ 'get_student_morphosyntax_iterative_data': get_student_morphosyntax_data,
158
  'store_current_situation_result': store_current_situation_result,
159
  'verify_storage': verify_storage,
160
  'get_recent_sessions': get_recent_sessions,
 
209
 
210
  def load_morphosyntax_functions():
211
  from .morphosyntax.morphosyntax_interface import (
212
+ initialize_arc_analysis_state,
213
+ reset_arc_analysis_state,
214
+ display_arc_diagrams,
 
 
 
 
215
  display_morphosyntax_results
216
  )
217
  from .morphosyntax.morphosyntax_process import (
 
221
  )
222
 
223
  return {
224
+ #Interface
225
+ 'initialize_arc_analysis_state': initialize_arc_analysis_state,
226
+ 'reset_arc_analysis_state': reset_morpho_state,
227
+ 'display_arc_diagrams': display_arc_diagrams,
 
 
228
  'display_morphosyntax_interface': display_morphosyntax_interface,
229
+ #Process
230
  'process_morphosyntactic_input': process_morphosyntactic_input,
231
  'format_analysis_results': format_analysis_results,
232
  'perform_advanced_morphosyntactic_analysis': perform_advanced_morphosyntactic_analysis
modules/database/morphosyntax_iterative_mongo_db.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # modules/database/morphosyntax_iterative_mongo_db.py
2
+
3
+
4
+ from datetime import datetime, timezone
5
+ import logging
6
+ from bson import ObjectId # <--- Importar ObjectId
7
+ from .mongo_db import get_collection, insert_document, find_documents, update_document, delete_document
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ BASE_COLLECTION = 'student_morphosyntax_analysis_base'
12
+ ITERATION_COLLECTION = 'student_morphosyntax_iterations'
13
+
14
+ def store_student_morphosyntax_base(username, text, arc_diagrams):
15
+ """Almacena el an谩lisis morfosint谩ctico base y retorna su ObjectId."""
16
+ try:
17
+ base_document = {
18
+ 'username': username,
19
+ 'timestamp': datetime.now(timezone.utc).isoformat(),
20
+ 'text': text,
21
+ 'arc_diagrams': arc_diagrams,
22
+ 'analysis_type': 'morphosyntax_base',
23
+ 'has_iterations': False
24
+ }
25
+ collection = get_collection(BASE_COLLECTION)
26
+ result = collection.insert_one(base_document)
27
+
28
+ logger.info(f"An谩lisis base guardado para {username}")
29
+ # Retornamos el ObjectId directamente (NO str)
30
+ return result.inserted_id
31
+
32
+ except Exception as e:
33
+ logger.error(f"Error almacenando an谩lisis base: {str(e)}")
34
+ return None
35
+
36
+ def store_student_morphosyntax_iteration(username, base_id, original_text, iteration_text, arc_diagrams):
37
+ """
38
+ Almacena una iteraci贸n de an谩lisis morfosint谩ctico.
39
+ base_id: ObjectId de la base (o string convertible a ObjectId).
40
+ """
41
+ try:
42
+ # Convertir a ObjectId si viene como string
43
+ if isinstance(base_id, str):
44
+ base_id = ObjectId(base_id)
45
+
46
+ iteration_document = {
47
+ 'username': username,
48
+ 'base_id': base_id, # Guardar el ObjectId en la iteraci贸n
49
+ 'timestamp': datetime.now(timezone.utc).isoformat(),
50
+ 'original_text': original_text,
51
+ 'iteration_text': iteration_text,
52
+ 'arc_diagrams': arc_diagrams,
53
+ 'analysis_type': 'morphosyntax_iteration'
54
+ }
55
+ collection = get_collection(ITERATION_COLLECTION)
56
+ result = collection.insert_one(iteration_document)
57
+
58
+ # Actualizar documento base (usando ObjectId)
59
+ base_collection = get_collection(BASE_COLLECTION)
60
+ base_collection.update_one(
61
+ {'_id': base_id, 'username': username},
62
+ {'$set': {'has_iterations': True}}
63
+ )
64
+
65
+ logger.info(f"Iteraci贸n guardada para {username}, base_id: {base_id}")
66
+ return result.inserted_id # Retornar el ObjectId de la iteraci贸n
67
+
68
+ except Exception as e:
69
+ logger.error(f"Error almacenando iteraci贸n: {str(e)}")
70
+ return None
71
+
72
+ def get_student_morphosyntax_analysis(username, limit=10):
73
+ """
74
+ Obtiene los an谩lisis base y sus iteraciones.
75
+ Returns: Lista de an谩lisis con sus iteraciones.
76
+ """
77
+ try:
78
+ base_collection = get_collection(BASE_COLLECTION)
79
+ base_query = {
80
+ "username": username,
81
+ "analysis_type": "morphosyntax_base"
82
+ }
83
+ base_analyses = list(
84
+ base_collection.find(base_query).sort("timestamp", -1).limit(limit)
85
+ )
86
+
87
+ # Para cada an谩lisis base, obtener sus iteraciones
88
+ iteration_collection = get_collection(ITERATION_COLLECTION)
89
+ for analysis in base_analyses:
90
+ base_id = analysis['_id']
91
+ # Buscar iteraciones con base_id = ObjectId
92
+ iterations = list(
93
+ iteration_collection.find({"base_id": base_id}).sort("timestamp", -1)
94
+ )
95
+ analysis['iterations'] = iterations
96
+
97
+ return base_analyses
98
+
99
+ except Exception as e:
100
+ logger.error(f"Error obteniendo an谩lisis: {str(e)}")
101
+ return []
102
+
103
+ def update_student_morphosyntax_analysis(analysis_id, is_base, update_data):
104
+ """
105
+ Actualiza un an谩lisis base o iteraci贸n.
106
+ analysis_id puede ser un ObjectId o string.
107
+ """
108
+ from bson import ObjectId
109
+
110
+ try:
111
+ collection_name = BASE_COLLECTION if is_base else ITERATION_COLLECTION
112
+ collection = get_collection(collection_name)
113
+
114
+ if isinstance(analysis_id, str):
115
+ analysis_id = ObjectId(analysis_id)
116
+
117
+ query = {"_id": analysis_id}
118
+ update = {"$set": update_data}
119
+
120
+ result = update_document(collection_name, query, update)
121
+ return result
122
+
123
+ except Exception as e:
124
+ logger.error(f"Error actualizando an谩lisis: {str(e)}")
125
+ return False
126
+
127
+ def delete_student_morphosyntax_analysis(analysis_id, is_base):
128
+ """
129
+ Elimina un an谩lisis base o iteraci贸n.
130
+ Si es base, tambi茅n elimina todas sus iteraciones.
131
+ """
132
+ from bson import ObjectId
133
+
134
+ try:
135
+ if isinstance(analysis_id, str):
136
+ analysis_id = ObjectId(analysis_id)
137
+
138
+ if is_base:
139
+ # Eliminar iteraciones vinculadas
140
+ iteration_collection = get_collection(ITERATION_COLLECTION)
141
+ iteration_collection.delete_many({"base_id": analysis_id})
142
+
143
+ # Luego eliminar el an谩lisis base
144
+ collection = get_collection(BASE_COLLECTION)
145
+ else:
146
+ collection = get_collection(ITERATION_COLLECTION)
147
+
148
+ query = {"_id": analysis_id}
149
+ result = delete_document(collection.name, query)
150
+ return result
151
+
152
+ except Exception as e:
153
+ logger.error(f"Error eliminando an谩lisis: {str(e)}")
154
+ return False
155
+
156
+ def get_student_morphosyntax_data(username):
157
+ """
158
+ Obtiene todos los datos de an谩lisis morfosint谩ctico de un estudiante.
159
+ Returns: Diccionario con todos los an谩lisis y sus iteraciones.
160
+ """
161
+ try:
162
+ analyses = get_student_morphosyntax_analysis(username, limit=None)
163
+ return {
164
+ 'entries': analyses,
165
+ 'total_analyses': len(analyses),
166
+ 'has_iterations': any(a.get('has_iterations', False) for a in analyses)
167
+ }
168
+
169
+ except Exception as e:
170
+ logger.error(f"Error obteniendo datos del estudiante: {str(e)}")
171
+ return {'entries': [], 'total_analyses': 0, 'has_iterations': False}
modules/morphosyntax/__init__.py CHANGED
@@ -1,6 +1,7 @@
1
  from .morphosyntax_interface import (
2
- display_morphosyntax_interface,
3
- display_morphosyntax_results
 
4
  )
5
 
6
  from .morphosyntax_process import (
@@ -15,7 +16,8 @@ from .morphosyntax_process import (
15
 
16
  __all__ = [
17
  'display_morphosyntax_interface',
18
- 'display_morphosyntax_results',
 
19
  'process_morphosyntactic_input',
20
  'format_analysis_results',
21
  'perform_advanced_morphosyntactic_analysis',
 
1
  from .morphosyntax_interface import (
2
+ display_morphosyntax_interface,
3
+ display_arc_diagram
4
+ # display_morphosyntax_results
5
  )
6
 
7
  from .morphosyntax_process import (
 
16
 
17
  __all__ = [
18
  'display_morphosyntax_interface',
19
+ 'display_arc_diagram',
20
+ #'display_morphosyntax_results',
21
  'process_morphosyntactic_input',
22
  'format_analysis_results',
23
  'perform_advanced_morphosyntactic_analysis',
modules/morphosyntax/morphosyntax_interface.py CHANGED
@@ -1,319 +1,228 @@
1
- #modules/morphosyntax/morphosyntax_interface.py
2
 
3
- #Importaciones generales
4
  import streamlit as st
5
- from streamlit_float import *
6
- from streamlit_antd_components import *
7
- from streamlit.components.v1 import html
8
- import spacy
9
- from spacy import displacy
10
- import spacy_streamlit
11
- import pandas as pd
12
- import base64
13
  import re
 
 
14
 
15
- #Importaciones locales
16
- from .morphosyntax_process import (
17
- process_morphosyntactic_input,
18
- format_analysis_results,
19
- perform_advanced_morphosyntactic_analysis,
20
- get_repeated_words_colors,
21
- highlight_repeated_words,
22
- POS_COLORS,
23
- POS_TRANSLATIONS
24
  )
25
 
26
- from ..utils.widget_utils import generate_unique_key
27
- from ..database.morphosintax_mongo_db import store_student_morphosyntax_result
28
- from ..database.chat_mongo_db import store_chat_history, get_chat_history
29
-
30
- import logging
31
  logger = logging.getLogger(__name__)
32
 
33
  ###########################################################################
34
  def initialize_arc_analysis_state():
35
- """Inicializa el estado del an谩lisis de arcos y el cach茅 si no existen"""
36
- # Inicializar estado de an谩lisis
37
- if 'arc_analysis_state' not in st.session_state:
38
  st.session_state.arc_analysis_state = {
39
- 'original_text': '',
40
- 'original_analysis': None,
41
- 'iteration_text': '',
42
- 'iteration_analysis': None,
43
- 'analysis_count': 0
44
  }
45
- logger.info("Estado de an谩lisis de arcos inicializado")
46
-
47
- # Inicializar cach茅 de an谩lisis
48
- if 'analysis_cache' not in st.session_state:
49
- st.session_state.analysis_cache = {}
50
- logger.info("Cach茅 de an谩lisis inicializado")
51
 
52
  ###########################################################################
 
 
 
 
 
 
 
 
 
 
53
 
54
- def reset_morpho_state():
55
- """Resetea el estado del an谩lisis morfosint谩ctico"""
56
- if 'arc_analysis_state' in st.session_state:
57
- st.session_state.arc_analysis_state = {
58
- 'original_text': '',
59
- 'original_analysis': None,
60
- 'iteration_text': '',
61
- 'iteration_analysis': None,
62
- 'analysis_count': 0
63
- }
64
- ############################################################################
65
-
66
- def display_original_analysis(container, analysis, lang_code, morpho_t):
67
- """Muestra el an谩lisis original en el contenedor especificado"""
68
- with container:
69
- st.subheader("An谩lisis Original")
70
- display_morphosyntax_results(analysis, lang_code, morpho_t)
71
-
72
- def display_iteration_analysis(container, analysis, lang_code, morpho_t):
73
- """Muestra el an谩lisis de cambios en el contenedor especificado"""
74
- with container:
75
- st.subheader("An谩lisis de Cambios")
76
- display_morphosyntax_results(analysis, lang_code, morpho_t)
77
-
78
- ############################################################################
79
-
80
- def cache_analysis_results(key, result):
81
- """Almacena resultados de an谩lisis en cach茅"""
82
- if not hasattr(st.session_state, 'analysis_cache'):
83
- initialize_arc_analysis_state()
84
- st.session_state.analysis_cache[key] = result
85
- logger.info(f"Resultado almacenado en cach茅 con clave: {key}")
86
-
87
- def get_cached_analysis(key):
88
- """Recupera resultados de an谩lisis del cach茅"""
89
- if not hasattr(st.session_state, 'analysis_cache'):
90
- initialize_arc_analysis_state()
91
- return None
92
- return st.session_state.analysis_cache.get(key)
93
-
94
-
95
- ############################################################################
96
- def display_morphosyntax_interface(lang_code, nlp_models, morpho_t):
97
  try:
98
- # CSS para layout estable
99
- st.markdown("""
100
- <style>
101
- .stTextArea textarea {
102
- font-size: 1rem;
103
- line-height: 1.5;
104
- min-height: 100px !important;
105
- height: 100px !important;
106
- }
107
- .arc-diagram-container {
108
- width: 100%;
109
- padding: 0.5rem;
110
- margin: 0.5rem 0;
111
- }
112
- </style>
113
- """, unsafe_allow_html=True)
114
-
115
- # Inicializar estado y mantener tab activo
116
- st.session_state.tab_states['morpho_active'] = True
117
- st.session_state.selected_tab = 1
118
- initialize_arc_analysis_state()
119
-
120
- # Crear subtabs
121
- subtabs = st.tabs([
122
- "An谩lisis de Diagramas de Arco",
123
- "An谩lisis de Categor铆as",
124
- "An谩lisis Morfol贸gico"
125
- ])
126
-
127
- # Tab de Diagramas de Arco
128
- with subtabs[0]:
129
- # Bot贸n de reset
130
- col1, col2, col3 = st.columns([2,1,2])
131
- with col1:
132
- if st.button("Nuevo An谩lisis", type="secondary", use_container_width=True):
133
- reset_morpho_state()
134
- st.rerun()
135
 
136
- # Contenedores separados para cada tipo de an谩lisis
137
- original_input_container = st.container()
138
- original_diagram_container = st.container()
139
- iteration_input_container = st.container()
140
- iteration_diagram_container = st.container()
141
 
142
- # Secci贸n de an谩lisis original
143
- with original_input_container:
144
- text_key = f"original_text_{st.session_state.arc_analysis_state['analysis_count']}"
145
- text_input = st.text_area(
146
- "",
147
- value=st.session_state.arc_analysis_state['original_text'],
148
- key=text_key,
149
- height=100
150
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
- col1, col2, col3 = st.columns([2,1,2])
153
- with col1:
154
- analyze_button = st.button(
155
- "Analizar Texto Original",
156
- type="primary",
157
- key=f"analyze_original_{st.session_state.arc_analysis_state['analysis_count']}",
158
- use_container_width=True
159
  )
160
-
161
- # Procesar texto original
162
- if analyze_button and text_input.strip():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  try:
164
- doc = nlp_models[lang_code](text_input)
165
- analysis = perform_advanced_morphosyntactic_analysis(
166
- text_input,
 
 
 
 
 
167
  nlp_models[lang_code]
168
  )
169
-
170
- st.session_state.arc_analysis_state.update({
171
- 'original_text': text_input,
172
- 'original_analysis': {'doc': doc, 'analysis': analysis},
173
- 'iteration_text': text_input,
174
- 'analysis_count': st.session_state.arc_analysis_state['analysis_count'] + 1
175
- })
176
-
177
- if store_student_morphosyntax_result(
178
  username=st.session_state.username,
179
- text=text_input,
180
- arc_diagrams=analysis['arc_diagrams']
181
- ):
182
- display_original_analysis(
183
- original_diagram_container,
184
- st.session_state.arc_analysis_state['original_analysis'],
185
- lang_code,
186
- morpho_t
187
- )
188
-
189
- except Exception as e:
190
- st.error("Error al procesar texto original")
191
- logger.error(f"Error al procesar texto original: {str(e)}")
192
-
193
- # Secci贸n de iteraci贸n
194
- if st.session_state.arc_analysis_state.get('original_analysis'):
195
- with iteration_input_container:
196
- st.markdown("---")
197
-
198
- # Formulario de iteraci贸n
199
- with st.form(key="iteration_form"):
200
- iteration_text = st.text_area(
201
- "",
202
- value=st.session_state.arc_analysis_state.get('iteration_text', ''),
203
- key=f"iteration_{st.session_state.arc_analysis_state['analysis_count']}",
204
- height=100
205
- )
206
-
207
- # Bot贸n de an谩lisis dentro del formulario
208
- submitted = st.form_submit_button(
209
- "Analizar Cambios",
210
- type="primary",
211
- use_container_width=True
212
- )
213
-
214
- # Cuando se env铆a el formulario
215
- if submitted and iteration_text.strip():
216
- try:
217
- # Verificar si ya existe en cach茅
218
- cache_key = f"iter_{iteration_text}"
219
- cached_result = get_cached_analysis(cache_key)
220
-
221
- if cached_result:
222
- logger.info("Usando resultado cacheado")
223
- doc_iter = cached_result['doc']
224
- analysis_iter = cached_result['analysis']
225
- else:
226
- logger.info("Generando nuevo an谩lisis")
227
- doc_iter = nlp_models[lang_code](iteration_text)
228
- analysis_iter = perform_advanced_morphosyntactic_analysis(
229
- iteration_text,
230
- nlp_models[lang_code]
231
- )
232
- # Guardar en cach茅
233
- cache_analysis_results(cache_key, {
234
- 'doc': doc_iter,
235
- 'analysis': analysis_iter
236
- })
237
-
238
- # Actualizar estado
239
- st.session_state.arc_analysis_state.update({
240
- 'iteration_text': iteration_text,
241
- 'iteration_analysis': {'doc': doc_iter, 'analysis': analysis_iter}
242
- })
243
-
244
- if store_student_morphosyntax_result(
245
- username=st.session_state.username,
246
- text=iteration_text,
247
- arc_diagrams=analysis_iter['arc_diagrams']
248
- ):
249
- # Mostrar an谩lisis en columnas
250
- col1, col2 = st.columns(2)
251
-
252
- # Mostrar ambos an谩lisis
253
- with col1:
254
- display_original_analysis(
255
- original_diagram_container,
256
- st.session_state.arc_analysis_state['original_analysis'],
257
- lang_code,
258
- morpho_t
259
- )
260
-
261
- with col2:
262
- display_iteration_analysis(
263
- iteration_diagram_container,
264
- {'doc': doc_iter, 'analysis': analysis_iter},
265
- lang_code,
266
- morpho_t
267
- )
268
-
269
- except Exception as e:
270
- st.error("Error al procesar iteraci贸n")
271
- logger.error(f"Error al procesar iteraci贸n: {str(e)}")
272
-
273
- # Otros subtabs...
274
- with subtabs[1]:
275
- st.info("An谩lisis de Categor铆as en desarrollo...")
276
-
277
- with subtabs[2]:
278
- st.info("An谩lisis Morfol贸gico en desarrollo...")
279
-
280
- except Exception as e:
281
- st.error("Error general en la interfaz")
282
- logger.error(f"Error general en la interfaz: {str(e)}")
283
-
284
- ############################################################################
285
-
286
- def display_morphosyntax_results(result, lang_code, morpho_t):
287
- """
288
- Muestra solo el diagrama de arco.
289
- Args:
290
- result: Diccionario con el documento procesado y su an谩lisis
291
- lang_code: C贸digo del idioma
292
- morpho_t: Diccionario de traducciones
293
- """
294
- if result is None:
295
- return
296
-
297
- try:
298
- doc = result['doc']
299
- sentences = list(doc.sents)
300
- for i, sent in enumerate(sentences):
301
- try:
302
- st.subheader(f"{morpho_t.get('sentence', 'Sentence')} {i+1}")
303
- html = displacy.render(sent, style="dep", options={
304
- "distance": 100,
305
- "arrow_spacing": 20,
306
- "word_spacing": 30
307
- })
308
- html = html.replace('height="375"', 'height="200"')
309
- html = re.sub(r'<svg[^>]*>', lambda m: m.group(0).replace('height="450"', 'height="300"'), html)
310
- html = re.sub(r'<g [^>]*transform="translate\((\d+),(\d+)\)"',
311
- lambda m: f'<g transform="translate({m.group(1)},50)"', html)
312
- html = f'<div class="arc-diagram-container">{html}</div>'
313
- st.write(html, unsafe_allow_html=True)
314
- except Exception as e:
315
- logger.error(f"Error en diagrama {i}: {str(e)}")
316
- continue
317
- except Exception as e:
318
- logger.error(f"Error en display_morphosyntax_results: {str(e)}")
319
-
 
1
+ # modules/morphosyntax/morphosyntax_interface.py
2
 
 
3
  import streamlit as st
 
 
 
 
 
 
 
 
4
  import re
5
+ import logging
6
+ from spacy import displacy
7
 
8
+ # Funciones de an谩lisis y DB que ya tienes en tus m贸dulos
9
+ from ..morphosyntax.morphosyntax_process import perform_advanced_morphosyntactic_analysis
10
+ from ..database.morphosyntax_iterative_mongo_db import (
11
+ store_student_morphosyntax_base,
12
+ store_student_morphosyntax_iteration,
 
 
 
 
13
  )
14
 
 
 
 
 
 
15
  logger = logging.getLogger(__name__)
16
 
17
  ###########################################################################
18
  def initialize_arc_analysis_state():
19
+ """Inicializa el estado de an谩lisis de arcos (base e iteraciones) si no existe."""
20
+ if "arc_analysis_state" not in st.session_state:
 
21
  st.session_state.arc_analysis_state = {
22
+ "base_id": None,
23
+ "base_text": "",
24
+ "base_diagram": None,
25
+ "iteration_text": "",
26
+ "iteration_diagram": None,
27
  }
28
+ logger.info("Estado de an谩lisis de arcos inicializado.")
 
 
 
 
 
29
 
30
  ###########################################################################
31
+ def reset_arc_analysis_state():
32
+ """Resetea completamente el estado de an谩lisis de arcos."""
33
+ st.session_state.arc_analysis_state = {
34
+ "base_id": None,
35
+ "base_text": "",
36
+ "base_diagram": None,
37
+ "iteration_text": "",
38
+ "iteration_diagram": None,
39
+ }
40
+ logger.info("Estado de arcos reseteado.")
41
 
42
+ ###########################################################################
43
+ def display_arc_diagram(doc):
44
+ """
45
+ Genera y retorna el HTML del diagrama de arco para un Doc de spaCy.
46
+ No imprime directamente; retorna el HTML para usar con st.write(...).
47
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  try:
49
+ diagram_html = ""
50
+ for sent in doc.sents:
51
+ svg_html = displacy.render(
52
+ sent,
53
+ style="dep",
54
+ options={
55
+ "distance": 100,
56
+ "arrow_spacing": 20,
57
+ "word_spacing": 30
58
+ }
59
+ )
60
+ # Ajustar tama帽os
61
+ svg_html = svg_html.replace('height="375"', 'height="200"')
62
+ svg_html = re.sub(
63
+ r'<svg[^>]*>',
64
+ lambda m: m.group(0).replace('height="450"', 'height="300"'),
65
+ svg_html
66
+ )
67
+ svg_html = re.sub(
68
+ r'<g [^>]*transform="translate\((\d+),(\d+)\)"',
69
+ lambda m: f'<g transform="translate({m.group(1)},50)"',
70
+ svg_html
71
+ )
72
+ # Envolver en contenedor
73
+ diagram_html += f'<div class="arc-diagram-container">{svg_html}</div>'
74
+ return diagram_html
 
 
 
 
 
 
 
 
 
 
 
75
 
76
+ except Exception as e:
77
+ logger.error(f"Error en display_arc_diagram: {str(e)}")
78
+ return "<p style='color:red;'>Error generando diagrama</p>"
 
 
79
 
80
+ ###########################################################################
81
+ def display_morphosyntax_interface(lang_code, nlp_models, morpho_t):
82
+ """
83
+ Interfaz principal para la visualizaci贸n de diagramas de arco
84
+ (Texto Base vs Iteraciones).
85
+ """
86
+ # CSS para layout vertical y estable
87
+ st.markdown("""
88
+ <style>
89
+ .stTextArea textarea {
90
+ font-size: 1rem;
91
+ line-height: 1.5;
92
+ min-height: 100px !important;
93
+ height: 100px !important;
94
+ }
95
+ .arc-diagram-container {
96
+ width: 100%;
97
+ padding: 0.5rem;
98
+ margin: 0.5rem 0;
99
+ }
100
+ .divider {
101
+ height: 3px;
102
+ border: none;
103
+ background-color: #333;
104
+ margin: 2rem 0;
105
+ }
106
+ </style>
107
+ """, unsafe_allow_html=True)
108
+
109
+ # 1) Inicializar estados
110
+ initialize_arc_analysis_state()
111
+ arc_state = st.session_state.arc_analysis_state
112
+
113
+ # 2) Creamos pesta帽as: "Texto Base" y "Iteraciones"
114
+ tabs = st.tabs(["Texto Base", "Iteraciones"])
115
+
116
+ # =================== PESTA脩A 1: Texto Base ==========================
117
+ with tabs[0]:
118
+ st.subheader("An谩lisis de Texto Base")
119
+
120
+ # Bot贸n para iniciar nuevo an谩lisis
121
+ if st.button("Nuevo An谩lisis", key="btn_reset_base"):
122
+ # Si requieres recargar la app por completo, podr铆as descomentar:
123
+ # st.experimental_rerun()
124
+ reset_arc_analysis_state()
125
+
126
+ # Textarea de texto base
127
+ arc_state["base_text"] = st.text_area(
128
+ "Ingrese su texto inicial",
129
+ value=arc_state["base_text"],
130
+ key="base_text_input",
131
+ height=150
132
+ )
133
+
134
+ # Bot贸n para analizar texto base
135
+ if st.button("Analizar Texto Base", key="btn_analyze_base"):
136
+ if not arc_state["base_text"].strip():
137
+ st.warning("Ingrese un texto para analizar.")
138
+ else:
139
+ try:
140
+ # Procesar con spaCy
141
+ doc = nlp_models[lang_code](arc_state["base_text"])
142
+ base_arc_html = display_arc_diagram(doc)
143
+ arc_state["base_diagram"] = base_arc_html
144
 
145
+ # Guardar en Mongo
146
+ analysis = perform_advanced_morphosyntactic_analysis(
147
+ arc_state["base_text"],
148
+ nlp_models[lang_code]
 
 
 
149
  )
150
+ base_id = store_student_morphosyntax_base(
151
+ username=st.session_state.username,
152
+ text=arc_state["base_text"],
153
+ arc_diagrams=analysis["arc_diagrams"]
154
+ )
155
+ if base_id:
156
+ arc_state["base_id"] = base_id
157
+ st.success(f"An谩lisis base guardado. ID: {base_id}")
158
+
159
+ except Exception as exc:
160
+ st.error("Error procesando texto base")
161
+ logger.error(f"Error en an谩lisis base: {str(exc)}")
162
+
163
+ # Mostrar diagrama base
164
+ if arc_state["base_diagram"]:
165
+ st.markdown("<hr class='divider'>", unsafe_allow_html=True)
166
+ st.markdown("#### Diagrama de Arco (Texto Base)")
167
+ st.write(arc_state["base_diagram"], unsafe_allow_html=True)
168
+
169
+ # ================== PESTA脩A 2: Iteraciones ==========================
170
+ with tabs[1]:
171
+ st.subheader("An谩lisis de Cambios / Iteraciones")
172
+
173
+ # Verificar que exista un texto base
174
+ if not arc_state["base_id"]:
175
+ st.info("Primero analiza un texto base en la pesta帽a anterior.")
176
+ return
177
+
178
+ # --- 1) Mostrar SIEMPRE el diagrama base arriba ---
179
+ st.markdown("#### Diagrama de Arco (Texto Base)")
180
+ if arc_state["base_diagram"]:
181
+ st.write(arc_state["base_diagram"], unsafe_allow_html=True)
182
+ else:
183
+ st.info("No hay diagrama base disponible.")
184
+
185
+ # --- 2) Caja de texto para la iteraci贸n ---
186
+ st.markdown("<hr class='divider'>", unsafe_allow_html=True)
187
+ st.subheader("Texto de Iteraci贸n")
188
+ arc_state["iteration_text"] = st.text_area(
189
+ "Ingrese su nueva versi贸n / iteraci贸n",
190
+ value=arc_state["iteration_text"],
191
+ height=150
192
+ )
193
+
194
+ # Bot贸n para analizar iteraci贸n
195
+ if st.button("Analizar Cambios", key="btn_analyze_iteration"):
196
+ if not arc_state["iteration_text"].strip():
197
+ st.warning("Ingrese texto de iteraci贸n.")
198
+ else:
199
  try:
200
+ # Procesar con spaCy
201
+ doc_iter = nlp_models[lang_code](arc_state["iteration_text"])
202
+ arc_html_iter = display_arc_diagram(doc_iter)
203
+ arc_state["iteration_diagram"] = arc_html_iter
204
+
205
+ # Guardar en Mongo
206
+ analysis_iter = perform_advanced_morphosyntactic_analysis(
207
+ arc_state["iteration_text"],
208
  nlp_models[lang_code]
209
  )
210
+ iteration_id = store_student_morphosyntax_iteration(
 
 
 
 
 
 
 
 
211
  username=st.session_state.username,
212
+ base_id=arc_state["base_id"],
213
+ original_text=arc_state["base_text"],
214
+ iteration_text=arc_state["iteration_text"],
215
+ arc_diagrams=analysis_iter["arc_diagrams"]
216
+ )
217
+ if iteration_id:
218
+ st.success(f"Iteraci贸n guardada. ID: {iteration_id}")
219
+
220
+ except Exception as exc:
221
+ st.error("Error procesando iteraci贸n")
222
+ logger.error(f"Error en iteraci贸n: {str(exc)}")
223
+
224
+ # --- 3) Mostrar diagrama de iteraci贸n debajo ---
225
+ if arc_state["iteration_diagram"]:
226
+ st.markdown("<hr class='divider'>", unsafe_allow_html=True)
227
+ st.markdown("#### Diagrama de Arco (Iteraci贸n)")
228
+ st.write(arc_state["iteration_diagram"], unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
modules/morphosyntax/morphosyntax_interface_vOk-30-12-24.py ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # modules/morphosyntax/morphosyntax_interface.py
2
+
3
+ import streamlit as st
4
+ import re
5
+ import logging
6
+ from spacy import displacy
7
+
8
+ # Se asume que la funci贸n perform_advanced_morphosyntactic_analysis
9
+ # y los m茅todos store_student_morphosyntax_base/iteration existen.
10
+ from ..morphosyntax.morphosyntax_process import perform_advanced_morphosyntactic_analysis
11
+ from ..database.morphosyntax_iterative_mongo_db import (
12
+ store_student_morphosyntax_base,
13
+ store_student_morphosyntax_iteration,
14
+ )
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ ###########################################################################
19
+ def initialize_arc_analysis_state():
20
+ """
21
+ Inicializa el estado de an谩lisis de arcos (base e iteraciones) si no existe.
22
+ """
23
+ if "arc_analysis_state" not in st.session_state:
24
+ st.session_state.arc_analysis_state = {
25
+ "base_id": None,
26
+ "base_text": "",
27
+ "base_diagram": None,
28
+ "iteration_text": "",
29
+ "iteration_diagram": None,
30
+ }
31
+ logger.info("Estado de an谩lisis de arcos inicializado.")
32
+
33
+ ###########################################################################
34
+ def reset_arc_analysis_state():
35
+ """
36
+ Resetea completamente el estado de an谩lisis de arcos.
37
+ """
38
+ st.session_state.arc_analysis_state = {
39
+ "base_id": None,
40
+ "base_text": "",
41
+ "base_diagram": None,
42
+ "iteration_text": "",
43
+ "iteration_diagram": None,
44
+ }
45
+ logger.info("Estado de arcos reseteado.")
46
+
47
+ ###########################################################################
48
+ def display_arc_diagram(doc):
49
+ """
50
+ Genera y retorna el HTML del diagrama de arco para un `Doc` de spaCy.
51
+ No imprime directamente en pantalla; regresa el HTML para
52
+ usar con `st.write(..., unsafe_allow_html=True)`.
53
+ """
54
+ try:
55
+ diagram_html = ""
56
+ for sent in doc.sents:
57
+ svg_html = displacy.render(
58
+ sent,
59
+ style="dep",
60
+ options={
61
+ "distance": 100,
62
+ "arrow_spacing": 20,
63
+ "word_spacing": 30
64
+ }
65
+ )
66
+ # Ajustar tama帽os
67
+ svg_html = svg_html.replace('height="375"', 'height="200"')
68
+ svg_html = re.sub(
69
+ r'<svg[^>]*>',
70
+ lambda m: m.group(0).replace('height="450"', 'height="300"'),
71
+ svg_html
72
+ )
73
+ svg_html = re.sub(
74
+ r'<g [^>]*transform="translate\((\d+),(\d+)\)"',
75
+ lambda m: f'<g transform="translate({m.group(1)},50)"',
76
+ svg_html
77
+ )
78
+ # Envolver en contenedor
79
+ diagram_html += f'<div class="arc-diagram-container">{svg_html}</div>'
80
+ return diagram_html
81
+
82
+ except Exception as e:
83
+ logger.error(f"Error en display_arc_diagram: {str(e)}")
84
+ return "<p style='color:red;'>Error generando diagrama</p>"
85
+
86
+ ###########################################################################
87
+ def display_morphosyntax_interface(lang_code, nlp_models, morpho_t):
88
+ """
89
+ Interfaz principal para la visualizaci贸n de diagramas de arco
90
+ (Texto Base vs Iteraciones).
91
+ """
92
+ # CSS para layout vertical y estable
93
+ st.markdown("""
94
+ <style>
95
+ .stTextArea textarea {
96
+ font-size: 1rem;
97
+ line-height: 1.5;
98
+ min-height: 100px !important;
99
+ height: 100px !important;
100
+ }
101
+ .arc-diagram-container {
102
+ width: 100%;
103
+ padding: 0.5rem;
104
+ margin: 0.5rem 0;
105
+ }
106
+ .divider {
107
+ height: 3px;
108
+ border: none;
109
+ background-color: #333;
110
+ margin: 2rem 0;
111
+ }
112
+ </style>
113
+ """, unsafe_allow_html=True)
114
+
115
+ # 1) Inicializar estados
116
+ initialize_arc_analysis_state()
117
+ arc_state = st.session_state.arc_analysis_state
118
+
119
+ # 2) Creamos pesta帽as: "Texto Base" y "Iteraciones"
120
+ tabs = st.tabs(["Texto Base", "Iteraciones"])
121
+
122
+ # =================== PESTA脩A 1: Texto Base ==========================
123
+ with tabs[0]:
124
+ st.subheader("An谩lisis de Texto Base")
125
+
126
+ # Bot贸n para iniciar nuevo an谩lisis
127
+ if st.button("Nuevo An谩lisis", key="btn_reset_base"):
128
+ # Solo limpiamos el estado; si requieres forzar reload,
129
+ # descomenta la siguiente l铆nea:
130
+ # st.experimental_rerun()
131
+ reset_arc_analysis_state()
132
+
133
+ # Textarea de texto base
134
+ arc_state["base_text"] = st.text_area(
135
+ "Ingrese su texto inicial",
136
+ value=arc_state["base_text"],
137
+ key="base_text_input",
138
+ height=150
139
+ )
140
+
141
+ # Bot贸n para analizar texto base
142
+ if st.button("Analizar Texto Base", key="btn_analyze_base"):
143
+ if not arc_state["base_text"].strip():
144
+ st.warning("Ingrese un texto para analizar.")
145
+ else:
146
+ try:
147
+ # Procesar con spaCy
148
+ doc = nlp_models[lang_code](arc_state["base_text"])
149
+ # Generar HTML del arco
150
+ arc_html = display_arc_diagram(doc)
151
+ arc_state["base_diagram"] = arc_html
152
+
153
+ # Guardar en Mongo
154
+ analysis = perform_advanced_morphosyntactic_analysis(
155
+ arc_state["base_text"],
156
+ nlp_models[lang_code]
157
+ )
158
+ base_id = store_student_morphosyntax_base(
159
+ username=st.session_state.username,
160
+ text=arc_state["base_text"],
161
+ arc_diagrams=analysis["arc_diagrams"]
162
+ )
163
+ if base_id:
164
+ arc_state["base_id"] = base_id
165
+ st.success(f"An谩lisis base guardado. ID: {base_id}")
166
+
167
+ except Exception as exc:
168
+ st.error("Error procesando texto base")
169
+ logger.error(f"Error en an谩lisis base: {str(exc)}")
170
+
171
+ # Mostrar diagrama base
172
+ if arc_state["base_diagram"]:
173
+ st.markdown("<hr class='divider'>", unsafe_allow_html=True)
174
+ st.markdown("#### Diagrama de Arco (Texto Base)")
175
+ st.write(arc_state["base_diagram"], unsafe_allow_html=True)
176
+
177
+ # ================== PESTA脩A 2: Iteraciones ==========================
178
+ with tabs[1]:
179
+ st.subheader("An谩lisis de Cambios / Iteraciones")
180
+
181
+ # Verificar que exista texto base analizado
182
+ if not arc_state["base_id"]:
183
+ st.info("Primero analiza un texto base en la pesta帽a anterior.")
184
+ return
185
+
186
+ # Mostrar texto base como referencia (solo lectura)
187
+ st.text_area(
188
+ "Texto Base (solo lectura)",
189
+ value=arc_state["base_text"],
190
+ height=80,
191
+ disabled=True
192
+ )
193
+
194
+ # Caja de texto para la iteraci贸n
195
+ arc_state["iteration_text"] = st.text_area(
196
+ "Texto de Iteraci贸n",
197
+ value=arc_state["iteration_text"],
198
+ height=150
199
+ )
200
+
201
+ # Bot贸n analizar iteraci贸n
202
+ if st.button("Analizar Cambios", key="btn_analyze_iteration"):
203
+ if not arc_state["iteration_text"].strip():
204
+ st.warning("Ingrese texto de iteraci贸n.")
205
+ else:
206
+ try:
207
+ # Procesar con spaCy
208
+ doc_iter = nlp_models[lang_code](arc_state["iteration_text"])
209
+ arc_html_iter = display_arc_diagram(doc_iter)
210
+ arc_state["iteration_diagram"] = arc_html_iter
211
+
212
+ # Guardar en Mongo
213
+ analysis_iter = perform_advanced_morphosyntactic_analysis(
214
+ arc_state["iteration_text"],
215
+ nlp_models[lang_code]
216
+ )
217
+ iteration_id = store_student_morphosyntax_iteration(
218
+ username=st.session_state.username,
219
+ base_id=arc_state["base_id"],
220
+ original_text=arc_state["base_text"],
221
+ iteration_text=arc_state["iteration_text"],
222
+ arc_diagrams=analysis_iter["arc_diagrams"]
223
+ )
224
+ if iteration_id:
225
+ st.success(f"Iteraci贸n guardada. ID: {iteration_id}")
226
+
227
+ except Exception as exc:
228
+ st.error("Error procesando iteraci贸n")
229
+ logger.error(f"Error en iteraci贸n: {str(exc)}")
230
+
231
+ # Mostrar diagrama de iteraci贸n
232
+ if arc_state["iteration_diagram"]:
233
+ st.markdown("<hr class='divider'>", unsafe_allow_html=True)
234
+ st.markdown("#### Diagrama de Arco (Iteraci贸n)")
235
+ st.write(arc_state["iteration_diagram"], unsafe_allow_html=True)
236
+
237
+ # Comparaci贸n vertical (uno abajo del otro)
238
+ if arc_state["base_diagram"] and arc_state["iteration_diagram"]:
239
+ st.markdown("<hr class='divider'>", unsafe_allow_html=True)
240
+ st.markdown("### Comparaci贸n Vertical: Base vs. Iteraci贸n")
241
+
242
+ st.markdown("**Diagrama Base**")
243
+ st.write(arc_state["base_diagram"], unsafe_allow_html=True)
244
+
245
+ st.markdown("---")
246
+ st.markdown("**Diagrama Iterado**")
247
+ st.write(arc_state["iteration_diagram"], unsafe_allow_html=True)
modules/ui/ui.py CHANGED
@@ -58,7 +58,7 @@ from ..database.chat_mongo_db import store_chat_history, get_chat_history
58
  ##Importaciones desde los an谩lisis #######
59
  from ..morphosyntax.morphosyntax_interface import (
60
  display_morphosyntax_interface,
61
- display_morphosyntax_results
62
  )
63
 
64
  from ..semantic.semantic_interface import (
 
58
  ##Importaciones desde los an谩lisis #######
59
  from ..morphosyntax.morphosyntax_interface import (
60
  display_morphosyntax_interface,
61
+ display_arc_diagram
62
  )
63
 
64
  from ..semantic.semantic_interface import (