AIdeaText commited on
Commit
b41ec22
·
verified ·
1 Parent(s): e3208ab

Update modules/text_analysis/morpho_analysis.py

Browse files
Files changed (1) hide show
  1. modules/text_analysis/morpho_analysis.py +223 -256
modules/text_analysis/morpho_analysis.py CHANGED
@@ -1,256 +1,223 @@
1
- ##modules/text_analysis/morpho_analysis.py
2
-
3
- import spacy
4
- from collections import Counter
5
- from spacy import displacy
6
- import re
7
- from streamlit.components.v1 import html
8
- import base64
9
-
10
- from collections import Counter
11
- import re
12
- from ..utils.widget_utils import generate_unique_key
13
-
14
- import logging
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- # Define colors for grammatical categories
19
- POS_COLORS = {
20
- 'ADJ': '#FFA07A', # Light Salmon
21
- 'ADP': '#98FB98', # Pale Green
22
- 'ADV': '#87CEFA', # Light Sky Blue
23
- 'AUX': '#DDA0DD', # Plum
24
- 'CCONJ': '#F0E68C', # Khaki
25
- 'DET': '#FFB6C1', # Light Pink
26
- 'INTJ': '#FF6347', # Tomato
27
- 'NOUN': '#90EE90', # Light Green
28
- 'NUM': '#FAFAD2', # Light Goldenrod Yellow
29
- 'PART': '#D3D3D3', # Light Gray
30
- 'PRON': '#FFA500', # Orange
31
- 'PROPN': '#20B2AA', # Light Sea Green
32
- 'SCONJ': '#DEB887', # Burlywood
33
- 'SYM': '#7B68EE', # Medium Slate Blue
34
- 'VERB': '#FF69B4', # Hot Pink
35
- 'X': '#A9A9A9', # Dark Gray
36
- }
37
-
38
- POS_TRANSLATIONS = {
39
- 'es': {
40
- 'ADJ': 'Adjetivo',
41
- 'ADP': 'Preposición',
42
- 'ADV': 'Adverbio',
43
- 'AUX': 'Auxiliar',
44
- 'CCONJ': 'Conjunción Coordinante',
45
- 'DET': 'Determinante',
46
- 'INTJ': 'Interjección',
47
- 'NOUN': 'Sustantivo',
48
- 'NUM': 'Número',
49
- 'PART': 'Partícula',
50
- 'PRON': 'Pronombre',
51
- 'PROPN': 'Nombre Propio',
52
- 'SCONJ': 'Conjunción Subordinante',
53
- 'SYM': 'Símbolo',
54
- 'VERB': 'Verbo',
55
- 'X': 'Otro',
56
- },
57
- 'en': {
58
- 'ADJ': 'Adjective',
59
- 'ADP': 'Preposition',
60
- 'ADV': 'Adverb',
61
- 'AUX': 'Auxiliary',
62
- 'CCONJ': 'Coordinating Conjunction',
63
- 'DET': 'Determiner',
64
- 'INTJ': 'Interjection',
65
- 'NOUN': 'Noun',
66
- 'NUM': 'Number',
67
- 'PART': 'Particle',
68
- 'PRON': 'Pronoun',
69
- 'PROPN': 'Proper Noun',
70
- 'SCONJ': 'Subordinating Conjunction',
71
- 'SYM': 'Symbol',
72
- 'VERB': 'Verb',
73
- 'X': 'Other',
74
- },
75
- 'fr': {
76
- 'ADJ': 'Adjectif',
77
- 'ADP': 'Préposition',
78
- 'ADV': 'Adverbe',
79
- 'AUX': 'Auxiliaire',
80
- 'CCONJ': 'Conjonction de Coordination',
81
- 'DET': 'Déterminant',
82
- 'INTJ': 'Interjection',
83
- 'NOUN': 'Nom',
84
- 'NUM': 'Nombre',
85
- 'PART': 'Particule',
86
- 'PRON': 'Pronom',
87
- 'PROPN': 'Nom Propre',
88
- 'SCONJ': 'Conjonction de Subordination',
89
- 'SYM': 'Symbole',
90
- 'VERB': 'Verbe',
91
- 'X': 'Autre',
92
- }
93
- }
94
-
95
- #############################################################################################
96
- def get_repeated_words_colors(doc):
97
- word_counts = Counter(token.text.lower() for token in doc if token.pos_ != 'PUNCT')
98
- repeated_words = {word: count for word, count in word_counts.items() if count > 1}
99
-
100
- word_colors = {}
101
- for token in doc:
102
- if token.text.lower() in repeated_words:
103
- word_colors[token.text.lower()] = POS_COLORS.get(token.pos_, '#FFFFFF')
104
-
105
- return word_colors
106
-
107
- ######################################################################################################
108
- def highlight_repeated_words(doc, word_colors):
109
- highlighted_text = []
110
- for token in doc:
111
- if token.text.lower() in word_colors:
112
- color = word_colors[token.text.lower()]
113
- highlighted_text.append(f'<span style="background-color: {color};">{token.text}</span>')
114
- else:
115
- highlighted_text.append(token.text)
116
- return ' '.join(highlighted_text)
117
-
118
- #################################################################################################
119
-
120
- def generate_arc_diagram(doc):
121
- """
122
- Genera diagramas de arco para cada oración en el documento usando spacy-streamlit.
123
-
124
- Args:
125
- doc: Documento procesado por spaCy
126
- Returns:
127
- list: Lista de diagramas en formato HTML
128
- """
129
- arc_diagrams = []
130
- try:
131
- options = {
132
- "compact": False,
133
- "color": "#ffffff",
134
- "bg": "#0d6efd",
135
- "font": "Arial",
136
- "offset_x": 50,
137
- "distance": 100,
138
- "arrow_spacing": 12,
139
- "arrow_width": 2,
140
- "arrow_stroke": 2,
141
- "word_spacing": 25,
142
- "maxZoom": 2
143
- }
144
-
145
- for sent in doc.sents:
146
- try:
147
- # Usar el método render de displacy directamente con las opciones
148
- html = displacy.render(sent, style="dep", options=options)
149
- arc_diagrams.append(html)
150
- except Exception as e:
151
- logger.error(f"Error al renderizar oración: {str(e)}")
152
- continue
153
-
154
- return arc_diagrams
155
- except Exception as e:
156
- logger.error(f"Error general en generate_arc_diagram: {str(e)}")
157
- return None
158
-
159
-
160
- #################################################################################################
161
- def get_detailed_pos_analysis(doc):
162
- """
163
- Realiza un análisis detallado de las categorías gramaticales (POS) en el texto.
164
- """
165
- pos_counts = Counter(token.pos_ for token in doc)
166
- total_tokens = len(doc)
167
- pos_analysis = []
168
- for pos, count in pos_counts.items():
169
- percentage = (count / total_tokens) * 100
170
- pos_analysis.append({
171
- 'pos': pos,
172
- 'count': count,
173
- 'percentage': round(percentage, 2),
174
- 'examples': [token.text for token in doc if token.pos_ == pos][:5] # Primeros 5 ejemplos
175
- })
176
- return sorted(pos_analysis, key=lambda x: x['count'], reverse=True)
177
-
178
- #################################################################################################
179
- def get_morphological_analysis(doc):
180
- """
181
- Realiza un análisis morfológico detallado de las palabras en el texto.
182
- """
183
- morphology_analysis = []
184
- for token in doc:
185
- if token.pos_ in ['NOUN', 'VERB', 'ADJ', 'ADV']: # Enfocarse en categorías principales
186
- morphology_analysis.append({
187
- 'text': token.text,
188
- 'lemma': token.lemma_,
189
- 'pos': token.pos_,
190
- 'tag': token.tag_,
191
- 'dep': token.dep_,
192
- 'shape': token.shape_,
193
- 'is_alpha': token.is_alpha,
194
- 'is_stop': token.is_stop,
195
- 'morph': str(token.morph)
196
- })
197
- return morphology_analysis
198
-
199
- #################################################################################################
200
- def get_sentence_structure_analysis(doc):
201
- """
202
- Analiza la estructura de las oraciones en el texto.
203
- """
204
- sentence_analysis = []
205
- for sent in doc.sents:
206
- sentence_analysis.append({
207
- 'text': sent.text,
208
- 'root': sent.root.text,
209
- 'root_pos': sent.root.pos_,
210
- 'num_tokens': len(sent),
211
- 'num_words': len([token for token in sent if token.is_alpha]),
212
- 'subjects': [token.text for token in sent if "subj" in token.dep_],
213
- 'objects': [token.text for token in sent if "obj" in token.dep_],
214
- 'verbs': [token.text for token in sent if token.pos_ == "VERB"]
215
- })
216
- return sentence_analysis
217
-
218
- #################################################################################################
219
- def perform_advanced_morphosyntactic_analysis(text, nlp):
220
- """
221
- Realiza un análisis morfosintáctico avanzado del texto.
222
- """
223
- try:
224
- # Verificar el idioma del modelo
225
- model_lang = nlp.lang
226
- logger.info(f"Realizando análisis con modelo de idioma: {model_lang}")
227
-
228
- # Procesar el texto con el modelo específico del idioma
229
- doc = nlp(text)
230
-
231
- # Realizar análisis específico según el idioma
232
- return {
233
- 'doc': doc,
234
- 'pos_analysis': get_detailed_pos_analysis(doc),
235
- 'morphological_analysis': get_morphological_analysis(doc),
236
- 'sentence_structure': get_sentence_structure_analysis(doc),
237
- 'arc_diagrams': generate_arc_diagram(doc), # Quitamos nlp.lang
238
- 'repeated_words': get_repeated_words_colors(doc),
239
- 'highlighted_text': highlight_repeated_words(doc, get_repeated_words_colors(doc))
240
- }
241
- except Exception as e:
242
- logger.error(f"Error en análisis morfosintáctico: {str(e)}")
243
- return None
244
-
245
- # Al final del archivo morph_analysis.py
246
- __all__ = [
247
- 'perform_advanced_morphosyntactic_analysis',
248
- 'get_repeated_words_colors',
249
- 'highlight_repeated_words',
250
- 'generate_arc_diagram',
251
- 'get_detailed_pos_analysis',
252
- 'get_morphological_analysis',
253
- 'get_sentence_structure_analysis',
254
- 'POS_COLORS',
255
- 'POS_TRANSLATIONS'
256
- ]
 
1
+ ##modules/text_analysis/morpho_analysis.py
2
+
3
+ import spacy
4
+ from collections import Counter
5
+ from spacy import displacy
6
+ import re
7
+ from streamlit.components.v1 import html
8
+ import base64
9
+
10
+ from collections import Counter
11
+ import re
12
+ from ..utils.widget_utils import generate_unique_key
13
+
14
+ import logging
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ # Define colors for grammatical categories
19
+ POS_COLORS = {
20
+ 'ADJ': '#FFA07A', # Light Salmon
21
+ 'ADP': '#98FB98', # Pale Green
22
+ 'ADV': '#87CEFA', # Light Sky Blue
23
+ 'AUX': '#DDA0DD', # Plum
24
+ 'CCONJ': '#F0E68C', # Khaki
25
+ 'DET': '#FFB6C1', # Light Pink
26
+ 'INTJ': '#FF6347', # Tomato
27
+ 'NOUN': '#90EE90', # Light Green
28
+ 'NUM': '#FAFAD2', # Light Goldenrod Yellow
29
+ 'PART': '#D3D3D3', # Light Gray
30
+ 'PRON': '#FFA500', # Orange
31
+ 'PROPN': '#20B2AA', # Light Sea Green
32
+ 'SCONJ': '#DEB887', # Burlywood
33
+ 'SYM': '#7B68EE', # Medium Slate Blue
34
+ 'VERB': '#FF69B4', # Hot Pink
35
+ 'X': '#A9A9A9', # Dark Gray
36
+ }
37
+
38
+ POS_TRANSLATIONS = {
39
+ 'es': {
40
+ 'ADJ': 'Adjetivo', 'ADP': 'Preposición', 'ADV': 'Adverbio', 'AUX': 'Auxiliar',
41
+ 'CCONJ': 'Conjunción Coordinante', 'DET': 'Determinante', 'INTJ': 'Interjección',
42
+ 'NOUN': 'Sustantivo', 'NUM': 'Número', 'PART': 'Partícula', 'PRON': 'Pronombre',
43
+ 'PROPN': 'Nombre Propio', 'SCONJ': 'Conjunción Subordinante', 'SYM': 'Símbolo',
44
+ 'VERB': 'Verbo', 'X': 'Otro',
45
+ },
46
+ 'en': {
47
+ 'ADJ': 'Adjective', 'ADP': 'Preposition', 'ADV': 'Adverb', 'AUX': 'Auxiliary',
48
+ 'CCONJ': 'Coordinating Conjunction', 'DET': 'Determiner', 'INTJ': 'Interjection',
49
+ 'NOUN': 'Noun', 'NUM': 'Number', 'PART': 'Particle', 'PRON': 'Pronoun',
50
+ 'PROPN': 'Proper Noun', 'SCONJ': 'Subordinating Conjunction', 'SYM': 'Symbol',
51
+ 'VERB': 'Verb', 'X': 'Other',
52
+ },
53
+ 'uk': {
54
+ 'ADJ': 'Прикметник', 'ADP': 'Прийменник', 'ADV': 'Прислівник', 'AUX': 'Допоміжне дієслово',
55
+ 'CCONJ': 'Сурядний сполучник', 'DET': 'Означник', 'INTJ': 'Вигук',
56
+ 'NOUN': 'Іменник', 'NUM': 'Число', 'PART': 'Частка', 'PRON': 'Займенник',
57
+ 'PROPN': 'Власна назва', 'SCONJ': 'Підрядний сполучник', 'SYM': 'Символ',
58
+ 'VERB': 'Дієслово', 'X': 'Інше',
59
+ }
60
+ }
61
+
62
+ #############################################################################################
63
+ def get_repeated_words_colors(doc):
64
+ word_counts = Counter(token.text.lower() for token in doc if token.pos_ != 'PUNCT')
65
+ repeated_words = {word: count for word, count in word_counts.items() if count > 1}
66
+
67
+ word_colors = {}
68
+ for token in doc:
69
+ if token.text.lower() in repeated_words:
70
+ word_colors[token.text.lower()] = POS_COLORS.get(token.pos_, '#FFFFFF')
71
+
72
+ return word_colors
73
+
74
+ ######################################################################################################
75
+ def highlight_repeated_words(doc, word_colors):
76
+ highlighted_text = []
77
+ for token in doc:
78
+ if token.text.lower() in word_colors:
79
+ color = word_colors[token.text.lower()]
80
+ highlighted_text.append(f'<span style="background-color: {color};">{token.text}</span>')
81
+ else:
82
+ highlighted_text.append(token.text)
83
+ return ' '.join(highlighted_text)
84
+
85
+ #################################################################################################
86
+
87
+ def generate_arc_diagram(doc):
88
+ """
89
+ Genera diagramas de arco para cada oración en el documento usando spacy-streamlit.
90
+
91
+ Args:
92
+ doc: Documento procesado por spaCy
93
+ Returns:
94
+ list: Lista de diagramas en formato HTML
95
+ """
96
+ arc_diagrams = []
97
+ try:
98
+ options = {
99
+ "compact": False,
100
+ "color": "#ffffff",
101
+ "bg": "#0d6efd",
102
+ "font": "Arial",
103
+ "offset_x": 50,
104
+ "distance": 100,
105
+ "arrow_spacing": 12,
106
+ "arrow_width": 2,
107
+ "arrow_stroke": 2,
108
+ "word_spacing": 25,
109
+ "maxZoom": 2
110
+ }
111
+
112
+ for sent in doc.sents:
113
+ try:
114
+ # Usar el método render de displacy directamente con las opciones
115
+ html = displacy.render(sent, style="dep", options=options)
116
+ arc_diagrams.append(html)
117
+ except Exception as e:
118
+ logger.error(f"Error al renderizar oración: {str(e)}")
119
+ continue
120
+
121
+ return arc_diagrams
122
+ except Exception as e:
123
+ logger.error(f"Error general en generate_arc_diagram: {str(e)}")
124
+ return None
125
+
126
+
127
+ #################################################################################################
128
+ def get_detailed_pos_analysis(doc):
129
+ """
130
+ Realiza un análisis detallado de las categorías gramaticales (POS) en el texto.
131
+ """
132
+ pos_counts = Counter(token.pos_ for token in doc)
133
+ total_tokens = len(doc)
134
+ pos_analysis = []
135
+ for pos, count in pos_counts.items():
136
+ percentage = (count / total_tokens) * 100
137
+ pos_analysis.append({
138
+ 'pos': pos,
139
+ 'count': count,
140
+ 'percentage': round(percentage, 2),
141
+ 'examples': [token.text for token in doc if token.pos_ == pos][:5] # Primeros 5 ejemplos
142
+ })
143
+ return sorted(pos_analysis, key=lambda x: x['count'], reverse=True)
144
+
145
+ #################################################################################################
146
+ def get_morphological_analysis(doc):
147
+ """
148
+ Realiza un análisis morfológico detallado de las palabras en el texto.
149
+ """
150
+ morphology_analysis = []
151
+ for token in doc:
152
+ if token.pos_ in ['NOUN', 'VERB', 'ADJ', 'ADV']: # Enfocarse en categorías principales
153
+ morphology_analysis.append({
154
+ 'text': token.text,
155
+ 'lemma': token.lemma_,
156
+ 'pos': token.pos_,
157
+ 'tag': token.tag_,
158
+ 'dep': token.dep_,
159
+ 'shape': token.shape_,
160
+ 'is_alpha': token.is_alpha,
161
+ 'is_stop': token.is_stop,
162
+ 'morph': str(token.morph)
163
+ })
164
+ return morphology_analysis
165
+
166
+ #################################################################################################
167
+ def get_sentence_structure_analysis(doc):
168
+ """
169
+ Analiza la estructura de las oraciones en el texto.
170
+ """
171
+ sentence_analysis = []
172
+ for sent in doc.sents:
173
+ sentence_analysis.append({
174
+ 'text': sent.text,
175
+ 'root': sent.root.text,
176
+ 'root_pos': sent.root.pos_,
177
+ 'num_tokens': len(sent),
178
+ 'num_words': len([token for token in sent if token.is_alpha]),
179
+ 'subjects': [token.text for token in sent if "subj" in token.dep_],
180
+ 'objects': [token.text for token in sent if "obj" in token.dep_],
181
+ 'verbs': [token.text for token in sent if token.pos_ == "VERB"]
182
+ })
183
+ return sentence_analysis
184
+
185
+ #################################################################################################
186
+ def perform_advanced_morphosyntactic_analysis(text, nlp):
187
+ """
188
+ Realiza un análisis morfosintáctico avanzado del texto.
189
+ """
190
+ try:
191
+ # Verificar el idioma del modelo
192
+ model_lang = nlp.lang
193
+ logger.info(f"Realizando análisis con modelo de idioma: {model_lang}")
194
+
195
+ # Procesar el texto con el modelo específico del idioma
196
+ doc = nlp(text)
197
+
198
+ # Realizar análisis específico según el idioma
199
+ return {
200
+ 'doc': doc,
201
+ 'pos_analysis': get_detailed_pos_analysis(doc),
202
+ 'morphological_analysis': get_morphological_analysis(doc),
203
+ 'sentence_structure': get_sentence_structure_analysis(doc),
204
+ 'arc_diagrams': generate_arc_diagram(doc), # Quitamos nlp.lang
205
+ 'repeated_words': get_repeated_words_colors(doc),
206
+ 'highlighted_text': highlight_repeated_words(doc, get_repeated_words_colors(doc))
207
+ }
208
+ except Exception as e:
209
+ logger.error(f"Error en análisis morfosintáctico: {str(e)}")
210
+ return None
211
+
212
+ # Al final del archivo morph_analysis.py
213
+ __all__ = [
214
+ 'perform_advanced_morphosyntactic_analysis',
215
+ 'get_repeated_words_colors',
216
+ 'highlight_repeated_words',
217
+ 'generate_arc_diagram',
218
+ 'get_detailed_pos_analysis',
219
+ 'get_morphological_analysis',
220
+ 'get_sentence_structure_analysis',
221
+ 'POS_COLORS',
222
+ 'POS_TRANSLATIONS'
223
+ ]