import datetime from tqdm import tqdm # Pandas import pandas as pd # Expresiones regulares import re # Matplotlib, Seaborn y Plotly import matplotlib.pyplot as plt import seaborn as sns # NLTK import nltk from nltk.corpus import stopwords # spaCy import spacy # PySentimiento y Transformers from pysentimiento import create_analyzer from sentence_transformers import SentenceTransformer # Word cloud from PIL import Image import uuid import gradio as gr nltk.download('stopwords') nltk.download('punkt') ### Reformado. Antes hacia reproceso para obtener output y probas. Se puede hacer en un paso. def get_sentiment(df,column): analyzer = create_analyzer(task="sentiment", lang="es") analyzer_outputs = [] with tqdm(total=len(df), desc="Analyzing Comments") as pbar: # Iterate through each element in the DataFrame column for element in df[column]: # Perform sentiment analysis on each element result = analyzer.predict(element) # Append the result to the list analyzer_outputs.append(result) # Update the progress bar pbar.update(1) # Extracting values into columns output_list = [output.output for output in analyzer_outputs] NEU_list = [output.probas.get('NEU', None) for output in analyzer_outputs] NEG_list = [output.probas.get('NEG', None) for output in analyzer_outputs] POS_list = [output.probas.get('POS', None) for output in analyzer_outputs] # Assigning lists to DataFrame columns df['Polaridad'] = output_list df['sent_NEU'] = NEU_list df['sent_NEG'] = NEG_list df['sent_POS'] = POS_list return df ### Reformado. Antes hacia reproceso para obtener output y probas. Se puede hacer en un paso. def get_emotions(df,column): analyzer = create_analyzer(task="emotion", lang="es") analyzer_outputs = [] with tqdm(total=len(df), desc="Analyzing Comments") as pbar: # Iterate through each element in the DataFrame column for element in df[column]: # Perform sentiment analysis on each element result = analyzer.predict(element) # Append the result to the list analyzer_outputs.append(result) # Update the progress bar pbar.update(1) # Extracting values into columns output_list = [output.output for output in analyzer_outputs] anger_list = [output.probas.get('anger', None) for output in analyzer_outputs] sadness_list = [output.probas.get('sadness', None) for output in analyzer_outputs] surprise_list = [output.probas.get('surprise', None) for output in analyzer_outputs] disgust_list = [output.probas.get('disgust', None) for output in analyzer_outputs] joy_list = [output.probas.get('joy', None) for output in analyzer_outputs] fear_list = [output.probas.get('fear', None) for output in analyzer_outputs] others_list = [output.probas.get('others', None) for output in analyzer_outputs] # Assigning lists to DataFrame columns df['Emocion'] = output_list df['emo_anger'] = anger_list df['emo_sadness'] = sadness_list df['emo_surprise'] = surprise_list df['emo_disgust'] = disgust_list df['emo_joy'] = joy_list df['emo_fear'] = fear_list df['emo_others'] = others_list return df class ProcesamientoLenguaje: def __init__(self): self.nlp = spacy.load('es_core_news_md', disable=["parser", "ner"]) def postags_and_stopwords(self, texts, allowed_postags=['NOUN', 'ADJ','PROPN', 'VB', 'X']): '''Función que procesa todos los textos en un pipeline de spaCy para tokenizar y etiquetar las POS. Luego, filtra todas las palabras de longitud mayor a 2 caracteres que no sean stop words y que se encuentren dentro de las etiquetas permitidas: sustantivo, adjetivo, verbo, nombre propio y todo lo que no caiga en una categoría preestablecida (palabras OOV, nombres propios no reconocidos, etc). Devuelve los textos procesados. ''' texts_out = ' '.join([token.text for token in self.nlp(texts) if token.pos_ in allowed_postags and token.text not in stop_words and len(token.text) > 2]) return texts_out def cleaner(self, word): '''Función que toma un texto y remueve distintos símbolos y variaciones de palabras. Devuelve el string limpio. ''' word = re.sub(r'https?\S+', '', word) #remueve todas las URLs word = re.sub(r'(?::|;|=)(?:-)?(?:\)|\(|D|P)', "", word) #remueve interrogación, paréntesis, dos puntos, etc word = re.sub(r'ee.uu', 'eeuu', word, flags=re.IGNORECASE) #convierte todas las variaciones de EEUU sin importar el separador en EEUU word = re.sub(r'\#\.', '', word) word = re.sub(r'\n', ' ', word) #remueve todos los line-breaks y los reemplaza con espacios word = re.sub(r',', '', word) #remueve comas word = re.sub(r'\-', ' ', word) #remueve guiones word = re.sub(r'\.{3}', ' ', word) #remueve tres puntos word = re.sub(r'a{2,}', 'a', word) #remueve múltiples instancias de la letra a (p.ej: aaaaaaah, holaaaaaa) word = re.sub(r'é{2,}', 'é', word) #remueve múltiples instancias de la letra é (p.ej: volvééééé) word = re.sub(r'i{2,}', 'i', word) #remueve múltiples instancias de la letra i (p.ej: salíiiiiii) word = re.sub(r'ja{2,}', 'ja', word) #remueve las "risas" (p.ej: jaaaaaa) word = re.sub(r'[^\w\s@ñ]', '', word, flags=re.UNICODE) #remueve todos los símbolos no alfanuméricos excepto @ y ñ word = re.sub(r'\b@\w+\b', '', word) #remueve todos los usuarios de Twitter word = re.sub(r'\b\w{1,2}\b', '', word) #remueve todas las palabras de una o dos letras return word def grafico_pie(df, column_name='Polaridad'): file_path = f"{uuid.uuid4()}_sentimiento.jpg" plt.figure(figsize=(8, 6)) polaridad_counts = df[column_name].value_counts() plt.pie(polaridad_counts, labels=polaridad_counts.index, autopct='%1.1f%%', startangle=140) plt.title("Distribución de Polaridad") plt.savefig(file_path, bbox_inches="tight") plt.close() return file_path def grafico_barras(df, column_name='Emocion'): file_path = f"{uuid.uuid4()}_sentimiento.jpg" plt.figure(figsize=(8, 6)) ax = sns.countplot(x=column_name, data=df) for p in ax.patches: ax.annotate(format(p.get_height()), (p.get_x() + p.get_width() / 2., p.get_height()), ha = 'center', va = 'center', xytext = (0, 10), textcoords = 'offset points') plt.xlabel("Emocion") plt.ylabel("Cantidad") plt.title("Histograma de Emocion") plt.savefig(file_path, bbox_inches="tight") plt.close() return file_path pln = ProcesamientoLenguaje() stop_words = stopwords.words('spanish') # Función que lee el archivo CSV def procesar_csv(file): if file is None: return "No se ha cargado ningún archivo." df = pd.read_csv(file.name, delimiter=';') df['Fecha'] = pd.to_datetime(df['Fecha'], format='%d/%m/%y') df = get_sentiment(df, "Comentario") df = get_emotions(df, "Comentario") df['Comentario_clean'] = df['Comentario'].apply(pln.cleaner) df['Comentario_clean'] = df['Comentario_clean'].apply(lambda x: ' '.join([word for word in x.split() if word.lower() not in (stop_words)])) df['Comentario_clean'] = df['Comentario_clean'].apply(pln.postags_and_stopwords) output_file = f"{uuid.uuid4()}_processed_output.csv" df.to_csv(output_file, index=False) grafico_pie_path = grafico_pie(df) grafico_barras_path = grafico_barras(df) return df.head(10), output_file, grafico_pie_path, grafico_barras_path # Muestra las primeras filas # Crear la interfaz en Gradio interface = gr.Interface( fn=procesar_csv, inputs=gr.File(label="Archivo CSV"), outputs=[gr.Dataframe(label="Vista previa del archivo procesado"), gr.File(label="Descargar CSV procesado"), gr.Image(type="filepath", label="Gráfico de torta"), gr.Image(type="filepath", label="Gráfico de barras")], title="Cargar y visualizar CSV", description="Sube un archivo CSV para ver los primeros registros. El archivo CSV debe tener los campos Fecha y Comentario." ) # Ejecutar la app de Gradio interface.launch()