AIdeaText commited on
Commit
5b1c944
·
verified ·
1 Parent(s): ae58da9

Update modules/text_analysis/discourse_analysis.py

Browse files
modules/text_analysis/discourse_analysis.py CHANGED
@@ -1,271 +1,307 @@
1
- # modules/text_analysis/discourse_analysis.py
2
- # Configuración de matplotlib
3
-
4
- import streamlit as st
5
- import spacy
6
- import networkx as nx
7
- import matplotlib.pyplot as plt
8
- import pandas as pd
9
- import numpy as np
10
- import logging
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
- from .semantic_analysis import (
15
- create_concept_graph,
16
- visualize_concept_graph,
17
- identify_key_concepts
18
- )
19
-
20
- from .stopwords import (
21
- get_custom_stopwords,
22
- process_text,
23
- get_stopwords_for_spacy
24
- )
25
-
26
- #####################
27
- # Define colors for grammatical categories
28
- POS_COLORS = {
29
- 'ADJ': '#FFA07A', 'ADP': '#98FB98', 'ADV': '#87CEFA', 'AUX': '#DDA0DD',
30
- 'CCONJ': '#F0E68C', 'DET': '#FFB6C1', 'INTJ': '#FF6347', 'NOUN': '#90EE90',
31
- 'NUM': '#FAFAD2', 'PART': '#D3D3D3', 'PRON': '#FFA500', 'PROPN': '#20B2AA',
32
- 'SCONJ': '#DEB887', 'SYM': '#7B68EE', 'VERB': '#FF69B4', 'X': '#A9A9A9',
33
- }
34
-
35
- POS_TRANSLATIONS = {
36
- 'es': {
37
- 'ADJ': 'Adjetivo', 'ADP': 'Preposición', 'ADV': 'Adverbio', 'AUX': 'Auxiliar',
38
- 'CCONJ': 'Conjunción Coordinante', 'DET': 'Determinante', 'INTJ': 'Interjección',
39
- 'NOUN': 'Sustantivo', 'NUM': 'Número', 'PART': 'Partícula', 'PRON': 'Pronombre',
40
- 'PROPN': 'Nombre Propio', 'SCONJ': 'Conjunción Subordinante', 'SYM': 'Símbolo',
41
- 'VERB': 'Verbo', 'X': 'Otro',
42
- },
43
- 'en': {
44
- 'ADJ': 'Adjective', 'ADP': 'Preposition', 'ADV': 'Adverb', 'AUX': 'Auxiliary',
45
- 'CCONJ': 'Coordinating Conjunction', 'DET': 'Determiner', 'INTJ': 'Interjection',
46
- 'NOUN': 'Noun', 'NUM': 'Number', 'PART': 'Particle', 'PRON': 'Pronoun',
47
- 'PROPN': 'Proper Noun', 'SCONJ': 'Subordinating Conjunction', 'SYM': 'Symbol',
48
- 'VERB': 'Verb', 'X': 'Other',
49
- },
50
- 'fr': {
51
- 'ADJ': 'Adjectif', 'ADP': 'Préposition', 'ADV': 'Adverbe', 'AUX': 'Auxiliaire',
52
- 'CCONJ': 'Conjonction de Coordination', 'DET': 'Déterminant', 'INTJ': 'Interjection',
53
- 'NOUN': 'Nom', 'NUM': 'Nombre', 'PART': 'Particule', 'PRON': 'Pronom',
54
- 'PROPN': 'Nom Propre', 'SCONJ': 'Conjonction de Subordination', 'SYM': 'Symbole',
55
- 'VERB': 'Verbe', 'X': 'Autre',
56
- }
57
- }
58
-
59
- ENTITY_LABELS = {
60
- 'es': {
61
- "Personas": "lightblue",
62
- "Lugares": "lightcoral",
63
- "Inventos": "lightgreen",
64
- "Fechas": "lightyellow",
65
- "Conceptos": "lightpink"
66
- },
67
- 'en': {
68
- "People": "lightblue",
69
- "Places": "lightcoral",
70
- "Inventions": "lightgreen",
71
- "Dates": "lightyellow",
72
- "Concepts": "lightpink"
73
- },
74
- 'fr': {
75
- "Personnes": "lightblue",
76
- "Lieux": "lightcoral",
77
- "Inventions": "lightgreen",
78
- "Dates": "lightyellow",
79
- "Concepts": "lightpink"
80
- }
81
- }
82
-
83
-
84
- #################
85
- def compare_semantic_analysis(text1, text2, nlp, lang):
86
- """
87
- Realiza el análisis semántico comparativo entre dos textos
88
- """
89
- try:
90
- logger.info(f"Iniciando análisis comparativo para idioma: {lang}")
91
-
92
- # Obtener stopwords
93
- stopwords = get_custom_stopwords(lang)
94
- logger.info(f"Obtenidas {len(stopwords)} stopwords para el idioma {lang}")
95
-
96
- # Procesar los textos
97
- doc1 = nlp(text1)
98
- doc2 = nlp(text2)
99
-
100
- # Identificar conceptos clave
101
- logger.info("Identificando conceptos clave del primer texto...")
102
- key_concepts1 = identify_key_concepts(doc1, stopwords=stopwords, min_freq=2, min_length=3)
103
-
104
- logger.info("Identificando conceptos clave del segundo texto...")
105
- key_concepts2 = identify_key_concepts(doc2, stopwords=stopwords, min_freq=2, min_length=3)
106
-
107
- if not key_concepts1 or not key_concepts2:
108
- raise ValueError("No se pudieron identificar conceptos clave en uno o ambos textos")
109
-
110
- # Crear grafos
111
- logger.info("Creando grafos de conceptos...")
112
- G1 = create_concept_graph(doc1, key_concepts1)
113
- G2 = create_concept_graph(doc2, key_concepts2)
114
-
115
- # Visualizar grafos
116
- logger.info("Visualizando grafos...")
117
-
118
- # Primer grafo
119
- plt.figure(figsize=(12, 8))
120
- fig1 = visualize_concept_graph(G1, lang)
121
- plt.title("Análisis del primer texto", pad=20)
122
- plt.tight_layout()
123
-
124
- # Segundo grafo
125
- plt.figure(figsize=(12, 8))
126
- fig2 = visualize_concept_graph(G2, lang)
127
- plt.title("Análisis del segundo texto", pad=20)
128
- plt.tight_layout()
129
-
130
- logger.info("Análisis comparativo completado exitosamente")
131
- return fig1, fig2, key_concepts1, key_concepts2
132
-
133
- except Exception as e:
134
- logger.error(f"Error en compare_semantic_analysis: {str(e)}")
135
- plt.close('all') # Limpiar recursos en caso de error
136
- raise
137
- finally:
138
- plt.close('all') # Asegurar limpieza en todos los casos
139
-
140
-
141
- ############################################
142
- def create_concept_table(key_concepts):
143
- """
144
- Crea una tabla de conceptos clave con sus frecuencias
145
- Args:
146
- key_concepts: Lista de tuplas (concepto, frecuencia)
147
- Returns:
148
- pandas.DataFrame: Tabla formateada de conceptos
149
- """
150
- try:
151
- if not key_concepts:
152
- logger.warning("Lista de conceptos vacía")
153
- return pd.DataFrame(columns=['Concepto', 'Frecuencia'])
154
-
155
- df = pd.DataFrame(key_concepts, columns=['Concepto', 'Frecuencia'])
156
- df['Frecuencia'] = df['Frecuencia'].round(2)
157
- return df
158
- except Exception as e:
159
- logger.error(f"Error en create_concept_table: {str(e)}")
160
- return pd.DataFrame(columns=['Concepto', 'Frecuencia'])
161
-
162
-
163
- ##########################################################
164
- def perform_discourse_analysis(text1, text2, nlp, lang):
165
- """
166
- Realiza el análisis completo del discurso
167
- """
168
- try:
169
- logger.info("Iniciando análisis del discurso...")
170
-
171
- # Verificar inputs
172
- if not text1 or not text2:
173
- raise ValueError("Los textos de entrada no pueden estar vacíos")
174
-
175
- if not nlp:
176
- raise ValueError("Modelo de lenguaje no inicializado")
177
-
178
- # Realizar análisis comparativo
179
- try:
180
- fig1, fig2, key_concepts1, key_concepts2 = compare_semantic_analysis(
181
- text1, text2, nlp, lang
182
- )
183
- except Exception as e:
184
- logger.error(f"Error en el análisis comparativo: {str(e)}")
185
- raise
186
-
187
- # Crear tablas de resultados
188
- try:
189
- table1 = create_concept_table(key_concepts1)
190
- table2 = create_concept_table(key_concepts2)
191
- except Exception as e:
192
- logger.error(f"Error creando tablas de conceptos: {str(e)}")
193
- raise
194
-
195
- result = {
196
- 'graph1': fig1,
197
- 'graph2': fig2,
198
- 'key_concepts1': key_concepts1,
199
- 'key_concepts2': key_concepts2,
200
- 'table1': table1,
201
- 'table2': table2,
202
- 'success': True
203
- }
204
-
205
- logger.info("Análisis del discurso completado exitosamente")
206
- return result
207
-
208
- except Exception as e:
209
- logger.error(f"Error en perform_discourse_analysis: {str(e)}")
210
- return {
211
- 'success': False,
212
- 'error': str(e)
213
- }
214
- finally:
215
- plt.close('all') # Asegurar limpieza en todos los casos
216
-
217
- #################################################################
218
- def create_concept_table(key_concepts):
219
- """
220
- Crea una tabla de conceptos clave con sus frecuencias
221
- Args:
222
- key_concepts: Lista de tuplas (concepto, frecuencia)
223
- Returns:
224
- pandas.DataFrame: Tabla formateada de conceptos
225
- """
226
- try:
227
- df = pd.DataFrame(key_concepts, columns=['Concepto', 'Frecuencia'])
228
- df['Frecuencia'] = df['Frecuencia'].round(2)
229
- return df
230
- except Exception as e:
231
- logger.error(f"Error en create_concept_table: {str(e)}")
232
- raise
233
-
234
- #################
235
- def perform_discourse_analysis(text1, text2, nlp, lang):
236
- """
237
- Realiza el análisis completo del discurso
238
- Args:
239
- text1: Primer texto a analizar
240
- text2: Segundo texto a analizar
241
- nlp: Modelo de spaCy cargado
242
- lang: Código de idioma
243
- Returns:
244
- dict: Resultados del análisis
245
- """
246
- try:
247
- # Realizar análisis comparativo
248
- fig1, fig2, key_concepts1, key_concepts2 = compare_semantic_analysis(
249
- text1, text2, nlp, lang
250
- )
251
-
252
- # Crear tablas de resultados
253
- table1 = create_concept_table(key_concepts1)
254
- table2 = create_concept_table(key_concepts2)
255
-
256
- return {
257
- 'graph1': fig1,
258
- 'graph2': fig2,
259
- 'key_concepts1': key_concepts1,
260
- 'key_concepts2': key_concepts2,
261
- 'table1': table1,
262
- 'table2': table2,
263
- 'success': True
264
- }
265
-
266
- except Exception as e:
267
- logger.error(f"Error en perform_discourse_analysis: {str(e)}")
268
- return {
269
- 'success': False,
270
- 'error': str(e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  }
 
1
+ # modules/text_analysis/discourse_analysis.py
2
+ # Configuración de matplotlib
3
+
4
+ import streamlit as st
5
+ import spacy
6
+ import networkx as nx
7
+ import matplotlib.pyplot as plt
8
+ import pandas as pd
9
+ import numpy as np
10
+ import logging
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ from .semantic_analysis import (
15
+ create_concept_graph,
16
+ visualize_concept_graph,
17
+ identify_key_concepts
18
+ )
19
+
20
+ from .stopwords import (
21
+ get_custom_stopwords,
22
+ process_text,
23
+ get_stopwords_for_spacy
24
+ )
25
+
26
+ def fig_to_bytes(fig):
27
+ """
28
+ Convierte una figura de matplotlib a bytes en formato PNG.
29
+
30
+ Args:
31
+ fig: Figura de matplotlib
32
+
33
+ Returns:
34
+ bytes: Representación en bytes de la figura en formato PNG
35
+ """
36
+ try:
37
+ import io
38
+ buf = io.BytesIO()
39
+ fig.savefig(buf, format='png', dpi=100, bbox_inches='tight')
40
+ buf.seek(0)
41
+ return buf.getvalue()
42
+ except Exception as e:
43
+ logger.error(f"Error al convertir figura a bytes: {str(e)}")
44
+ return None
45
+
46
+ #####################
47
+ # Define colors for grammatical categories
48
+ POS_COLORS = {
49
+ 'ADJ': '#FFA07A', 'ADP': '#98FB98', 'ADV': '#87CEFA', 'AUX': '#DDA0DD',
50
+ 'CCONJ': '#F0E68C', 'DET': '#FFB6C1', 'INTJ': '#FF6347', 'NOUN': '#90EE90',
51
+ 'NUM': '#FAFAD2', 'PART': '#D3D3D3', 'PRON': '#FFA500', 'PROPN': '#20B2AA',
52
+ 'SCONJ': '#DEB887', 'SYM': '#7B68EE', 'VERB': '#FF69B4', 'X': '#A9A9A9',
53
+ }
54
+
55
+ POS_TRANSLATIONS = {
56
+ 'es': {
57
+ 'ADJ': 'Adjetivo', 'ADP': 'Preposición', 'ADV': 'Adverbio', 'AUX': 'Auxiliar',
58
+ 'CCONJ': 'Conjunción Coordinante', 'DET': 'Determinante', 'INTJ': 'Interjección',
59
+ 'NOUN': 'Sustantivo', 'NUM': 'Número', 'PART': 'Partícula', 'PRON': 'Pronombre',
60
+ 'PROPN': 'Nombre Propio', 'SCONJ': 'Conjunción Subordinante', 'SYM': 'Símbolo',
61
+ 'VERB': 'Verbo', 'X': 'Otro',
62
+ },
63
+ 'en': {
64
+ 'ADJ': 'Adjective', 'ADP': 'Preposition', 'ADV': 'Adverb', 'AUX': 'Auxiliary',
65
+ 'CCONJ': 'Coordinating Conjunction', 'DET': 'Determiner', 'INTJ': 'Interjection',
66
+ 'NOUN': 'Noun', 'NUM': 'Number', 'PART': 'Particle', 'PRON': 'Pronoun',
67
+ 'PROPN': 'Proper Noun', 'SCONJ': 'Subordinating Conjunction', 'SYM': 'Symbol',
68
+ 'VERB': 'Verb', 'X': 'Other',
69
+ },
70
+ 'fr': {
71
+ 'ADJ': 'Adjectif', 'ADP': 'Préposition', 'ADV': 'Adverbe', 'AUX': 'Auxiliaire',
72
+ 'CCONJ': 'Conjonction de Coordination', 'DET': 'Déterminant', 'INTJ': 'Interjection',
73
+ 'NOUN': 'Nom', 'NUM': 'Nombre', 'PART': 'Particule', 'PRON': 'Pronom',
74
+ 'PROPN': 'Nom Propre', 'SCONJ': 'Conjonction de Subordination', 'SYM': 'Symbole',
75
+ 'VERB': 'Verbe', 'X': 'Autre',
76
+ }
77
+ }
78
+
79
+ ENTITY_LABELS = {
80
+ 'es': {
81
+ "Personas": "lightblue",
82
+ "Lugares": "lightcoral",
83
+ "Inventos": "lightgreen",
84
+ "Fechas": "lightyellow",
85
+ "Conceptos": "lightpink"
86
+ },
87
+ 'en': {
88
+ "People": "lightblue",
89
+ "Places": "lightcoral",
90
+ "Inventions": "lightgreen",
91
+ "Dates": "lightyellow",
92
+ "Concepts": "lightpink"
93
+ },
94
+ 'fr': {
95
+ "Personnes": "lightblue",
96
+ "Lieux": "lightcoral",
97
+ "Inventions": "lightgreen",
98
+ "Dates": "lightyellow",
99
+ "Concepts": "lightpink"
100
+ }
101
+ }
102
+
103
+
104
+ #################
105
+ def compare_semantic_analysis(text1, text2, nlp, lang):
106
+ """
107
+ Realiza el análisis semántico comparativo entre dos textos
108
+ """
109
+ try:
110
+ logger.info(f"Iniciando análisis comparativo para idioma: {lang}")
111
+
112
+ # Obtener stopwords
113
+ stopwords = get_custom_stopwords(lang)
114
+ logger.info(f"Obtenidas {len(stopwords)} stopwords para el idioma {lang}")
115
+
116
+ # Procesar los textos
117
+ doc1 = nlp(text1)
118
+ doc2 = nlp(text2)
119
+
120
+ # Identificar conceptos clave
121
+ logger.info("Identificando conceptos clave del primer texto...")
122
+ key_concepts1 = identify_key_concepts(doc1, stopwords=stopwords, min_freq=2, min_length=3)
123
+
124
+ logger.info("Identificando conceptos clave del segundo texto...")
125
+ key_concepts2 = identify_key_concepts(doc2, stopwords=stopwords, min_freq=2, min_length=3)
126
+
127
+ if not key_concepts1 or not key_concepts2:
128
+ raise ValueError("No se pudieron identificar conceptos clave en uno o ambos textos")
129
+
130
+ # Crear grafos
131
+ logger.info("Creando grafos de conceptos...")
132
+ G1 = create_concept_graph(doc1, key_concepts1)
133
+ G2 = create_concept_graph(doc2, key_concepts2)
134
+
135
+ # Visualizar grafos
136
+ logger.info("Visualizando grafos...")
137
+
138
+ # Primer grafo
139
+ plt.figure(figsize=(12, 8))
140
+ fig1 = visualize_concept_graph(G1, lang)
141
+ plt.title("Análisis del primer texto", pad=20)
142
+ plt.tight_layout()
143
+
144
+ # Segundo grafo
145
+ plt.figure(figsize=(12, 8))
146
+ fig2 = visualize_concept_graph(G2, lang)
147
+ plt.title("Análisis del segundo texto", pad=20)
148
+ plt.tight_layout()
149
+
150
+ logger.info("Análisis comparativo completado exitosamente")
151
+ return fig1, fig2, key_concepts1, key_concepts2
152
+
153
+ except Exception as e:
154
+ logger.error(f"Error en compare_semantic_analysis: {str(e)}")
155
+ plt.close('all') # Limpiar recursos en caso de error
156
+ raise
157
+ finally:
158
+ plt.close('all') # Asegurar limpieza en todos los casos
159
+
160
+
161
+ ############################################
162
+ def create_concept_table(key_concepts):
163
+ """
164
+ Crea una tabla de conceptos clave con sus frecuencias
165
+ Args:
166
+ key_concepts: Lista de tuplas (concepto, frecuencia)
167
+ Returns:
168
+ pandas.DataFrame: Tabla formateada de conceptos
169
+ """
170
+ try:
171
+ if not key_concepts:
172
+ logger.warning("Lista de conceptos vacía")
173
+ return pd.DataFrame(columns=['Concepto', 'Frecuencia'])
174
+
175
+ df = pd.DataFrame(key_concepts, columns=['Concepto', 'Frecuencia'])
176
+ df['Frecuencia'] = df['Frecuencia'].round(2)
177
+ return df
178
+ except Exception as e:
179
+ logger.error(f"Error en create_concept_table: {str(e)}")
180
+ return pd.DataFrame(columns=['Concepto', 'Frecuencia'])
181
+
182
+
183
+ ##########################################################
184
+ def perform_discourse_analysis(text1, text2, nlp, lang):
185
+ """
186
+ Realiza el análisis completo del discurso
187
+ Args:
188
+ text1: Primer texto a analizar
189
+ text2: Segundo texto a analizar
190
+ nlp: Modelo de spaCy cargado
191
+ lang: Código de idioma
192
+ Returns:
193
+ dict: Resultados del análisis con gráficos convertidos a bytes
194
+ """
195
+ try:
196
+ logger.info("Iniciando análisis del discurso...")
197
+
198
+ # Verificar inputs
199
+ if not text1 or not text2:
200
+ raise ValueError("Los textos de entrada no pueden estar vacíos")
201
+
202
+ if not nlp:
203
+ raise ValueError("Modelo de lenguaje no inicializado")
204
+
205
+ # Realizar análisis comparativo
206
+ fig1, fig2, key_concepts1, key_concepts2 = compare_semantic_analysis(
207
+ text1, text2, nlp, lang
208
+ )
209
+
210
+ logger.info("Análisis comparativo completado, convirtiendo figuras a bytes...")
211
+
212
+ # Convertir figuras a bytes para almacenamiento
213
+ graph1_bytes = fig_to_bytes(fig1)
214
+ graph2_bytes = fig_to_bytes(fig2)
215
+
216
+ logger.info(f"Figura 1 convertida a {len(graph1_bytes) if graph1_bytes else 0} bytes")
217
+ logger.info(f"Figura 2 convertida a {len(graph2_bytes) if graph2_bytes else 0} bytes")
218
+
219
+ # Crear tablas de resultados
220
+ table1 = create_concept_table(key_concepts1)
221
+ table2 = create_concept_table(key_concepts2)
222
+
223
+ # Cerrar figuras para liberar memoria
224
+ plt.close(fig1)
225
+ plt.close(fig2)
226
+
227
+ result = {
228
+ 'graph1': graph1_bytes, # Bytes en lugar de figura
229
+ 'graph2': graph2_bytes, # Bytes en lugar de figura
230
+ 'combined_graph': None, # No hay gráfico combinado por ahora
231
+ 'key_concepts1': key_concepts1,
232
+ 'key_concepts2': key_concepts2,
233
+ 'table1': table1,
234
+ 'table2': table2,
235
+ 'success': True
236
+ }
237
+
238
+ logger.info("Análisis del discurso completado y listo para almacenamiento")
239
+ return result
240
+
241
+ except Exception as e:
242
+ logger.error(f"Error en perform_discourse_analysis: {str(e)}")
243
+ # Asegurar limpieza de recursos
244
+ plt.close('all')
245
+ return {
246
+ 'success': False,
247
+ 'error': str(e)
248
+ }
249
+ finally:
250
+ # Asegurar limpieza en todos los casos
251
+ plt.close('all')
252
+
253
+ #################################################################
254
+ def create_concept_table(key_concepts):
255
+ """
256
+ Crea una tabla de conceptos clave con sus frecuencias
257
+ Args:
258
+ key_concepts: Lista de tuplas (concepto, frecuencia)
259
+ Returns:
260
+ pandas.DataFrame: Tabla formateada de conceptos
261
+ """
262
+ try:
263
+ df = pd.DataFrame(key_concepts, columns=['Concepto', 'Frecuencia'])
264
+ df['Frecuencia'] = df['Frecuencia'].round(2)
265
+ return df
266
+ except Exception as e:
267
+ logger.error(f"Error en create_concept_table: {str(e)}")
268
+ raise
269
+
270
+ #################
271
+ def perform_discourse_analysis(text1, text2, nlp, lang):
272
+ """
273
+ Realiza el análisis completo del discurso
274
+ Args:
275
+ text1: Primer texto a analizar
276
+ text2: Segundo texto a analizar
277
+ nlp: Modelo de spaCy cargado
278
+ lang: Código de idioma
279
+ Returns:
280
+ dict: Resultados del análisis
281
+ """
282
+ try:
283
+ # Realizar análisis comparativo
284
+ fig1, fig2, key_concepts1, key_concepts2 = compare_semantic_analysis(
285
+ text1, text2, nlp, lang
286
+ )
287
+
288
+ # Crear tablas de resultados
289
+ table1 = create_concept_table(key_concepts1)
290
+ table2 = create_concept_table(key_concepts2)
291
+
292
+ return {
293
+ 'graph1': fig1,
294
+ 'graph2': fig2,
295
+ 'key_concepts1': key_concepts1,
296
+ 'key_concepts2': key_concepts2,
297
+ 'table1': table1,
298
+ 'table2': table2,
299
+ 'success': True
300
+ }
301
+
302
+ except Exception as e:
303
+ logger.error(f"Error en perform_discourse_analysis: {str(e)}")
304
+ return {
305
+ 'success': False,
306
+ 'error': str(e)
307
  }