WALTERMAC commited on
Commit
3991e1b
verified
1 Parent(s): f483769

Update app.py

Browse files

se agrega lenmatizacion.

Files changed (1) hide show
  1. app.py +66 -123
app.py CHANGED
@@ -6,43 +6,48 @@ from transformers import pipeline
6
  import nltk
7
  from nltk.corpus import stopwords
8
  from nltk.util import ngrams
 
 
9
  from collections import Counter
10
  import plotly.express as px
 
11
 
12
- # Descargar stopwords de nltk
13
  nltk.download('stopwords')
14
  nltk.download('punkt')
15
- nltk.download('punkt_tab')
16
 
17
- # Cargar el pipeline de an谩lisis de sentimientos
 
18
  sentiment_analysis = pipeline('sentiment-analysis', model='dccuchile/bert-base-spanish-wwm-uncased')
19
 
 
 
 
 
20
  # Funci贸n para procesar el archivo .txt de WhatsApp
21
  def cargar_chat_txt(file):
22
  content = file.getvalue().decode('utf-8')
23
  lines = content.splitlines()
24
-
25
  fechas = []
26
  autores = []
27
  mensajes = []
28
 
29
- pattern = r"(\d{1,2}/\d{1,2}/\d{4}), (\d{1,2}:\d{2}\s?[ap]\.?\s?[m]\.?) - (.*?):(.*)"
30
-
31
  for line in lines:
32
  if "cifrados de extremo a extremo" in line:
33
  continue
34
-
35
  match = re.match(pattern, line.strip())
36
-
37
  if match:
38
  fecha = match.group(1)
39
  hora = match.group(2)
40
  autor = match.group(3).strip()
41
  mensaje = match.group(4).strip()
42
 
43
- hora = hora.replace("\u202f", "").strip()
44
- hora = hora.replace(".", "")
45
-
46
  fecha_hora_str = f"{fecha} {hora}"
47
 
48
  try:
@@ -54,189 +59,127 @@ def cargar_chat_txt(file):
54
  fechas.append(fecha_hora)
55
  autores.append(autor)
56
  mensajes.append(mensaje)
57
-
58
  df = pd.DataFrame({
59
  'FechaHora': fechas,
60
  'Autor': autores,
61
  'Mensaje': mensajes
62
  })
63
-
64
- if 'FechaHora' in df.columns and 'Autor' in df.columns and 'Mensaje' in df.columns:
65
  df['FechaHora'] = pd.to_datetime(df['FechaHora'])
66
  return df
67
  else:
68
  return None
69
 
70
- # Funci贸n para quitar las stopwords de los mensajes
71
- def quitar_stopwords(mensaje):
72
  stop_words = set(stopwords.words('spanish'))
73
- mensaje_tokens = nltk.word_tokenize(mensaje.lower())
74
- mensaje_filtrado = [word for word in mensaje_tokens if word not in stop_words]
75
- return ' '.join(mensaje_filtrado)
76
 
77
- # Funci贸n para extraer bigramas y trigramas
78
  def extraer_bigrams_trigrams(mensaje):
79
- tokens = nltk.word_tokenize(mensaje.lower())
80
  bigrams = list(ngrams(tokens, 2))
81
  trigrams = list(ngrams(tokens, 3))
82
  return bigrams, trigrams
83
 
84
- # Funci贸n para clasificar la urgencia basada en el autor
85
  def urgencia_por_autor(autor):
86
  autores_prioritarios = ["Jefe", "Hijo", "Mam谩", "Pap谩", "Esposa"]
87
-
88
  if any(char in autor for char in ["鉂わ笍", "馃挅", "馃挊", "馃挐", "馃挄"]):
89
- return 2 # Asignar urgencia alta si el autor tiene coraz贸n en su nombre
90
-
91
  return 2 if autor in autores_prioritarios else 0
92
 
93
- # Funci贸n para clasificar la urgencia basada en la hora
94
  def urgencia_por_hora(hora):
95
  hora = datetime.strptime(hora, "%H:%M")
96
  if hora >= datetime.strptime("20:00", "%H:%M") or hora <= datetime.strptime("05:00", "%H:%M"):
97
  return 1
98
  return 0
99
 
100
- # Funci贸n para clasificar la urgencia basada en el sentimiento
101
  def urgencia_por_sentimiento(sentimiento):
102
- if sentimiento == 'LABEL_4': # Muy negativo
103
- return 3 # Alta urgencia
104
- elif sentimiento == 'LABEL_3': # Negativo
105
- return 2 # Urgencia moderada
106
- elif sentimiento == 'LABEL_2': # Neutro
107
- return 1 # Baja urgencia
108
- elif sentimiento == 'LABEL_1': # Positivo
109
- return 1 # Baja urgencia
110
- elif sentimiento == 'LABEL_0': # Muy positivo
111
- return 0 # Sin urgencia
112
- return 0 # Si no coincide con ning煤n sentimiento, asignar baja urgencia
113
-
114
- # Funci贸n para verificar si el mensaje contiene palabras clave de urgencia
115
  def urgencia_por_palabras_clave(mensaje):
116
- palabras_clave = ["urgente", "es urgente", "es para hoy", "necesito ayuda", "por favor", "con urgencia"]
117
  mensaje = mensaje.lower()
118
-
119
- for palabra in palabras_clave:
120
- if palabra in mensaje:
121
- return 1 # Incrementa urgencia
122
- return 0 # No hay urgencia en las palabras clave
123
 
124
- # Funci贸n para verificar si el mensaje contiene palabras negativas
125
  def urgencia_por_palabras_negativas(mensaje):
126
- palabras_negativas = ["malo", "no me gusta", "odio", "peor", "terrible", "desastroso", "fatal"]
127
  mensaje = mensaje.lower()
128
-
129
- for palabra in palabras_negativas:
130
- if palabra in mensaje:
131
- return 2 # Incrementa urgencia por negatividad
132
- return 0 # No hay urgencia en las palabras negativas
133
 
134
- # Funci贸n para mapear las etiquetas del an谩lisis de sentimientos a etiquetas legibles
135
  def mapear_sentimiento(sentimiento):
136
- sentimiento_mapeado = {
137
- 'LABEL_0': 'Muy Positivo',
138
- 'LABEL_1': 'Positivo',
139
- 'LABEL_2': 'Neutro',
140
- 'LABEL_3': 'Negativo',
141
- 'LABEL_4': 'Muy Negativo'
142
- }
143
- return sentimiento_mapeado.get(sentimiento, 'Desconocido') # Si no encuentra la etiqueta, regresa "Desconocido"
144
-
145
 
146
- # Funci贸n para calcular el nivel de urgencia
147
  def calcular_urgencia(row):
148
- mensaje_filtrado = quitar_stopwords(row['Mensaje'])
149
-
150
- # Extraer bigramas y trigramas
151
  bigrams, trigrams = extraer_bigrams_trigrams(mensaje_filtrado)
152
-
153
- # An谩lisis de sentimiento
154
  result = sentiment_analysis(mensaje_filtrado)
155
  sentimiento = result[0]['label']
156
  probabilidad = result[0]['score']
157
-
158
- # Mapear el sentimiento a texto legible
159
  sentimiento_legible = mapear_sentimiento(sentimiento)
160
-
161
- # Si la probabilidad es baja, clasificar como "Neutro"
162
  if probabilidad < 0.6:
163
  sentimiento_legible = 'Neutro'
164
-
165
- # Clasificaci贸n de urgencia
166
- urgencia = urgencia_por_autor(row['Autor']) + urgencia_por_hora(row['FechaHora'].strftime('%H:%M')) + urgencia_por_sentimiento(sentimiento)
167
-
168
- urgencia += urgencia_por_palabras_clave(row['Mensaje'])
169
- urgencia += urgencia_por_palabras_negativas(row['Mensaje'])
170
-
171
- # Ahora, tambi茅n vamos a agregar la urgencia por los bigramas y trigramas
 
 
 
 
 
172
  for bigram in bigrams + trigrams:
173
  bigram_str = ' '.join(bigram)
174
- sentiment_bigram = sentiment_analysis(bigram_str)[0]['label']
175
- urgencia += urgencia_por_sentimiento(sentiment_bigram)
176
-
177
- return min(5, urgencia), sentimiento_legible # Regresamos la urgencia y el sentimiento legible
178
 
 
179
 
180
- # Funci贸n para extraer y contar bigramas y trigramas de un DataFrame
181
  def obtener_bigrams_trigrams(df):
182
- bigramas = []
183
- trigramas = []
184
-
185
  for mensaje in df['Mensaje']:
186
- bigrams, trigrams = extraer_bigrams_trigrams(mensaje)
187
- bigramas.extend([' '.join(bigram) for bigram in bigrams])
188
- trigramas.extend([' '.join(trigram) for trigram in trigrams])
189
-
190
  return bigramas, trigramas
191
 
192
- # Funci贸n para visualizar bigramas y trigramas en un gr谩fico
193
  def mostrar_grafica_bigrams_trigrams(bigramas, trigramas):
194
- # Contamos las ocurrencias de bigramas y trigramas
195
- bigram_count = Counter(bigramas).most_common(10)
196
- trigram_count = Counter(trigramas).most_common(10)
197
-
198
- # Bigramas
199
- bigram_df = pd.DataFrame(bigram_count, columns=['Bigram', 'Frecuencia'])
200
- fig_bigram = px.bar(bigram_df, x='Bigram', y='Frecuencia', title="Top 10 Bigramas m谩s comunes")
201
-
202
- # Trigramas
203
- trigram_df = pd.DataFrame(trigram_count, columns=['Trigram', 'Frecuencia'])
204
- fig_trigram = px.bar(trigram_df, x='Trigram', y='Frecuencia', title="Top 10 Trigramas m谩s comunes")
205
-
206
- return fig_bigram, fig_trigram
207
-
208
- # Streamlit application code
209
- st.title("An谩lisis de Chat de WhatsApp")
210
 
 
 
211
  uploaded_file = st.file_uploader("Sube un archivo TXT de chat de WhatsApp", type=["txt"])
212
 
213
  if uploaded_file is not None:
214
  df_chat = cargar_chat_txt(uploaded_file)
215
-
216
  if df_chat is not None and not df_chat.empty:
217
- st.write("Primeros mensajes del chat:")
218
  st.dataframe(df_chat.head())
219
-
220
- # Calcular la urgencia y sentimiento
221
  df_chat[['Urgencia', 'Sentimiento']] = df_chat.apply(calcular_urgencia, axis=1, result_type='expand')
222
-
223
- st.write("Mensajes con su nivel de urgencia y sentimiento:")
224
  st.dataframe(df_chat[['FechaHora', 'Autor', 'Mensaje', 'Urgencia', 'Sentimiento']])
225
 
226
- # Extraer bigramas y trigramas
227
  bigramas, trigramas = obtener_bigrams_trigrams(df_chat)
228
-
229
- # Mostrar gr谩ficas
230
  fig_bigram, fig_trigram = mostrar_grafica_bigrams_trigrams(bigramas, trigramas)
231
-
232
  st.plotly_chart(fig_bigram)
233
  st.plotly_chart(fig_trigram)
234
 
235
- # Visualizaci贸n del nivel de urgencia
236
  if st.button('Mostrar Gr谩fico de Urgencia'):
237
  urgencia_count = df_chat['Urgencia'].value_counts().reset_index()
238
  urgencia_count.columns = ['Urgencia', 'Cantidad']
239
- fig = px.bar(urgencia_count, x='Urgencia', y='Cantidad', title="Distribuci贸n de Niveles de Urgencia")
240
  st.plotly_chart(fig)
241
  else:
242
- st.write("No se encontraron mensajes en el archivo.")
 
6
  import nltk
7
  from nltk.corpus import stopwords
8
  from nltk.util import ngrams
9
+ from nltk.stem import WordNetLemmatizer
10
+ from nltk.tokenize import word_tokenize
11
  from collections import Counter
12
  import plotly.express as px
13
+ import emoji
14
 
15
+ # Descargar recursos de nltk
16
  nltk.download('stopwords')
17
  nltk.download('punkt')
18
+ nltk.download('wordnet')
19
 
20
+ # Inicializar herramientas NLP
21
+ lemmatizer = WordNetLemmatizer()
22
  sentiment_analysis = pipeline('sentiment-analysis', model='dccuchile/bert-base-spanish-wwm-uncased')
23
 
24
+ # Funci贸n para detectar emojis
25
+ def contiene_emojis(texto):
26
+ return any(char in emoji.EMOJI_DATA for char in texto)
27
+
28
  # Funci贸n para procesar el archivo .txt de WhatsApp
29
  def cargar_chat_txt(file):
30
  content = file.getvalue().decode('utf-8')
31
  lines = content.splitlines()
32
+
33
  fechas = []
34
  autores = []
35
  mensajes = []
36
 
37
+ pattern = r"(\d{1,2}/\d{1,2}/\d{4}), (\d{1,2}:\d{2}\s?[ap]\.\s?[m]\.) - (.*?):(.*)"
38
+
39
  for line in lines:
40
  if "cifrados de extremo a extremo" in line:
41
  continue
42
+
43
  match = re.match(pattern, line.strip())
 
44
  if match:
45
  fecha = match.group(1)
46
  hora = match.group(2)
47
  autor = match.group(3).strip()
48
  mensaje = match.group(4).strip()
49
 
50
+ hora = hora.replace("\u202f", "").strip().replace(".", "")
 
 
51
  fecha_hora_str = f"{fecha} {hora}"
52
 
53
  try:
 
59
  fechas.append(fecha_hora)
60
  autores.append(autor)
61
  mensajes.append(mensaje)
62
+
63
  df = pd.DataFrame({
64
  'FechaHora': fechas,
65
  'Autor': autores,
66
  'Mensaje': mensajes
67
  })
68
+
69
+ if not df.empty:
70
  df['FechaHora'] = pd.to_datetime(df['FechaHora'])
71
  return df
72
  else:
73
  return None
74
 
75
+ # Quitar stopwords y aplicar lematizaci贸n
76
+ def quitar_stopwords_lemmatizar(mensaje):
77
  stop_words = set(stopwords.words('spanish'))
78
+ tokens = word_tokenize(mensaje.lower())
79
+ tokens_filtrados = [lemmatizer.lemmatize(word) for word in tokens if word not in stop_words]
80
+ return ' '.join(tokens_filtrados)
81
 
82
+ # Extraer bigramas y trigramas
83
  def extraer_bigrams_trigrams(mensaje):
84
+ tokens = word_tokenize(mensaje.lower())
85
  bigrams = list(ngrams(tokens, 2))
86
  trigrams = list(ngrams(tokens, 3))
87
  return bigrams, trigrams
88
 
89
+ # Funciones de urgencia (autor, hora, sentimiento, palabras clave, etc.)
90
  def urgencia_por_autor(autor):
91
  autores_prioritarios = ["Jefe", "Hijo", "Mam谩", "Pap谩", "Esposa"]
 
92
  if any(char in autor for char in ["鉂わ笍", "馃挅", "馃挊", "馃挐", "馃挄"]):
93
+ return 2
 
94
  return 2 if autor in autores_prioritarios else 0
95
 
 
96
  def urgencia_por_hora(hora):
97
  hora = datetime.strptime(hora, "%H:%M")
98
  if hora >= datetime.strptime("20:00", "%H:%M") or hora <= datetime.strptime("05:00", "%H:%M"):
99
  return 1
100
  return 0
101
 
 
102
  def urgencia_por_sentimiento(sentimiento):
103
+ etiquetas = {'LABEL_4': 3, 'LABEL_3': 2, 'LABEL_2': 1, 'LABEL_1': 1, 'LABEL_0': 0}
104
+ return etiquetas.get(sentimiento, 0)
105
+
 
 
 
 
 
 
 
 
 
 
106
  def urgencia_por_palabras_clave(mensaje):
107
+ claves = ["urgente", "es urgente", "es para hoy", "necesito ayuda", "por favor", "con urgencia"]
108
  mensaje = mensaje.lower()
109
+ return 1 if any(clave in mensaje for clave in claves) else 0
 
 
 
 
110
 
 
111
  def urgencia_por_palabras_negativas(mensaje):
112
+ negativas = ["malo", "no me gusta", "odio", "peor", "terrible", "desastroso", "fatal"]
113
  mensaje = mensaje.lower()
114
+ return 2 if any(p in mensaje for p in negativas) else 0
 
 
 
 
115
 
 
116
  def mapear_sentimiento(sentimiento):
117
+ mapeo = {'LABEL_0': 'Muy Positivo', 'LABEL_1': 'Positivo', 'LABEL_2': 'Neutro', 'LABEL_3': 'Negativo', 'LABEL_4': 'Muy Negativo'}
118
+ return mapeo.get(sentimiento, 'Desconocido')
 
 
 
 
 
 
 
119
 
 
120
  def calcular_urgencia(row):
121
+ mensaje_filtrado = quitar_stopwords_lemmatizar(row['Mensaje'])
 
 
122
  bigrams, trigrams = extraer_bigrams_trigrams(mensaje_filtrado)
 
 
123
  result = sentiment_analysis(mensaje_filtrado)
124
  sentimiento = result[0]['label']
125
  probabilidad = result[0]['score']
 
 
126
  sentimiento_legible = mapear_sentimiento(sentimiento)
 
 
127
  if probabilidad < 0.6:
128
  sentimiento_legible = 'Neutro'
129
+
130
+ urgencia = (
131
+ urgencia_por_autor(row['Autor']) +
132
+ urgencia_por_hora(row['FechaHora'].strftime('%H:%M')) +
133
+ urgencia_por_sentimiento(sentimiento) +
134
+ urgencia_por_palabras_clave(row['Mensaje']) +
135
+ urgencia_por_palabras_negativas(row['Mensaje'])
136
+ )
137
+
138
+ # A帽adir urgencia si contiene emojis emocionales
139
+ if contiene_emojis(row['Mensaje']):
140
+ urgencia += 1
141
+
142
  for bigram in bigrams + trigrams:
143
  bigram_str = ' '.join(bigram)
144
+ sentimiento_bigram = sentiment_analysis(bigram_str)[0]['label']
145
+ urgencia += urgencia_por_sentimiento(sentimiento_bigram)
 
 
146
 
147
+ return min(5, urgencia), sentimiento_legible
148
 
149
+ # Funciones para mostrar bigramas y trigramas
150
  def obtener_bigrams_trigrams(df):
151
+ bigramas, trigramas = [], []
 
 
152
  for mensaje in df['Mensaje']:
153
+ bigs, trigs = extraer_bigrams_trigrams(mensaje)
154
+ bigramas.extend([' '.join(b) for b in bigs])
155
+ trigramas.extend([' '.join(t) for t in trigs])
 
156
  return bigramas, trigramas
157
 
 
158
  def mostrar_grafica_bigrams_trigrams(bigramas, trigramas):
159
+ bigram_df = pd.DataFrame(Counter(bigramas).most_common(10), columns=['Bigram', 'Frecuencia'])
160
+ trigram_df = pd.DataFrame(Counter(trigramas).most_common(10), columns=['Trigram', 'Frecuencia'])
161
+ return px.bar(bigram_df, x='Bigram', y='Frecuencia', title="Top 10 Bigramas"), px.bar(trigram_df, x='Trigram', y='Frecuencia', title="Top 10 Trigramas")
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
+ # App de Streamlit
164
+ st.title("An谩lisis de Chat de WhatsApp con Urgencia y Emojis")
165
  uploaded_file = st.file_uploader("Sube un archivo TXT de chat de WhatsApp", type=["txt"])
166
 
167
  if uploaded_file is not None:
168
  df_chat = cargar_chat_txt(uploaded_file)
 
169
  if df_chat is not None and not df_chat.empty:
 
170
  st.dataframe(df_chat.head())
 
 
171
  df_chat[['Urgencia', 'Sentimiento']] = df_chat.apply(calcular_urgencia, axis=1, result_type='expand')
 
 
172
  st.dataframe(df_chat[['FechaHora', 'Autor', 'Mensaje', 'Urgencia', 'Sentimiento']])
173
 
 
174
  bigramas, trigramas = obtener_bigrams_trigrams(df_chat)
 
 
175
  fig_bigram, fig_trigram = mostrar_grafica_bigrams_trigrams(bigramas, trigramas)
 
176
  st.plotly_chart(fig_bigram)
177
  st.plotly_chart(fig_trigram)
178
 
 
179
  if st.button('Mostrar Gr谩fico de Urgencia'):
180
  urgencia_count = df_chat['Urgencia'].value_counts().reset_index()
181
  urgencia_count.columns = ['Urgencia', 'Cantidad']
182
+ fig = px.bar(urgencia_count, x='Urgencia', y='Cantidad', title="Distribuci贸n de Urgencia")
183
  st.plotly_chart(fig)
184
  else:
185
+ st.write("No se encontraron mensajes v谩lidos.")