Spaces:
Sleeping
Sleeping
Download user_interface.py from MARIAFG/SentimentAnalysis: direct link, hf CLI and curl.
- Browser
- Download file 7.81 kB
-
https://huggingface.co/spaces/MARIAFG/SentimentAnalysis/resolve/main/user_interface.py
- Command line
-
hf download hf://spaces/MARIAFG/SentimentAnalysis/user_interface.py
-
curl -L -o user_interface.py https://huggingface.co/spaces/MARIAFG/SentimentAnalysis/resolve/main/user_interface.py
7.81 kB
| # ============================================================ | |
| # Maestría de Ciencia de Datos | |
| # | |
| # Curso: Transformers | |
| # | |
| # Autores: | |
| # - Samir Mateo Sierra Blanco | |
| # - Maria Fernanda González Acevedo | |
| # ============================================================ | |
| # Se importan las librerías necesarias | |
| import gradio as gr | |
| # Se importa la función de análisis desarrollada en sentiment_analyzer.py | |
| from sentiment_analyzer import analyze_sentiment | |
| # ------------------------------------------------------------ | |
| # Configuración visual | |
| # ------------------------------------------------------------ | |
| # Colores asociados a cada sentimiento (tonos sobrios, aptos para presentación académica) | |
| SENTIMENT_STYLES = { | |
| "Positivo": {"color": "#1B6B4A", "background": "#EAF4EF"}, | |
| "Neutral": {"color": "#4A5568", "background": "#EFF1F4"}, | |
| "Negativo": {"color": "#9B2C2C", "background": "#FBECEC"}, | |
| } | |
| # Tema base de Gradio: tonos azules y grises, tipografía Inter | |
| THEME = gr.themes.Base( | |
| primary_hue="blue", | |
| neutral_hue="slate", | |
| font=[gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"], | |
| ) | |
| # Estilos CSS adicionales para el encabezado y la tarjeta de resultado | |
| CSS = """ | |
| .gradio-container { max-width: 1100px !important; margin: 0 auto !important; } | |
| .app-header { | |
| background: #1F3A5F; | |
| padding: 28px 32px; | |
| border-radius: 8px; | |
| margin-bottom: 12px; | |
| } | |
| .app-header .eyebrow { | |
| color: #B8C7DB !important; | |
| font-size: 0.8rem; | |
| letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| margin: 0 0 6px 0; | |
| } | |
| .app-header h1 { | |
| color: #FFFFFF !important; | |
| font-size: 1.7rem; | |
| font-weight: 600; | |
| margin: 0 0 8px 0; | |
| } | |
| .app-header .subtitle { | |
| color: #D5DEEA !important; | |
| font-size: 0.95rem; | |
| margin: 0; | |
| } | |
| .result-card { | |
| padding: 24px 28px; | |
| border-radius: 8px; | |
| border: 1px solid #D9DEE5; | |
| min-height: 260px; | |
| } | |
| .result-card .caption { | |
| color: #5B6572 !important; | |
| font-size: 0.78rem; | |
| letter-spacing: 0.06em; | |
| text-transform: uppercase; | |
| margin: 0 0 4px 0; | |
| } | |
| .result-card .sentiment { | |
| font-size: 2rem; | |
| font-weight: 700; | |
| margin: 0 0 6px 0; | |
| } | |
| .result-card .stars { | |
| font-size: 1.4rem; | |
| letter-spacing: 3px; | |
| margin: 0 0 4px 0; | |
| } | |
| .result-card .meta { | |
| color: #4A5568 !important; | |
| font-size: 0.9rem; | |
| margin: 0 0 18px 0; | |
| } | |
| .bar-track { | |
| background: #D9DEE5; | |
| border-radius: 4px; | |
| height: 10px; | |
| overflow: hidden; | |
| margin-bottom: 6px; | |
| } | |
| .bar-fill { height: 100%; border-radius: 4px; } | |
| .placeholder-text { color: #6B7280 !important; font-size: 0.95rem; } | |
| """ | |
| # ------------------------------------------------------------ | |
| # Contenido estático | |
| # ------------------------------------------------------------ | |
| HEADER_HTML = """ | |
| <div class="app-header"> | |
| <p class="eyebrow">Maestría en Ciencia de Datos · Curso: Transformers</p> | |
| <h1>Análisis de Sentimiento en Textos en Español</h1> | |
| <p class="subtitle"> | |
| Clasificación con un modelo BERT multilingüe preentrenado | |
| (nlptown/bert-base-multilingual-uncased-sentiment). | |
| </p> | |
| </div> | |
| """ | |
| EMPTY_RESULT_HTML = """ | |
| <div class="result-card"> | |
| <p class="caption">Resultado</p> | |
| <p class="placeholder-text"> | |
| Ingrese un texto y presione "Analizar sentimiento" para ver la clasificación. | |
| </p> | |
| </div> | |
| """ | |
| EXAMPLES = [ | |
| ["El servicio fue excelente, la atención fue rápida y el personal muy amable."], | |
| ["Es un producto aceptable, cumple su función pero nada más."], | |
| ["Una experiencia terrible, el pedido llegó tarde y en mal estado."], | |
| ["La película tiene buenos momentos, aunque el final me decepcionó bastante."], | |
| ] | |
| METHODOLOGY_NOTE = """ | |
| **Modelo.** `nlptown/bert-base-multilingual-uncased-sentiment`, un modelo BERT | |
| multilingüe ajustado (*fine-tuned*) para predecir una calificación de 1 a 5 estrellas | |
| a partir de reseñas de productos. | |
| **Reglas de conversión a tres clases.** 1 y 2 estrellas se clasifican como *Negativo*, | |
| 3 estrellas como *Neutral* y 4 y 5 estrellas como *Positivo*. | |
| **Limitaciones.** El modelo fue entrenado con reseñas de productos, por lo que su | |
| desempeño puede disminuir en otros dominios (política, textos formales, ironía). | |
| La clase *Neutral* es una aproximación: corresponde a la calificación intermedia de | |
| una escala de estrellas, no a una categoría de neutralidad entrenada de forma explícita. | |
| La confianza mostrada es la probabilidad de la clase predicha, no una medida de | |
| exactitud garantizada. | |
| """ | |
| # ------------------------------------------------------------ | |
| # Lógica de la interfaz | |
| # ------------------------------------------------------------ | |
| def build_result_html(result: dict) -> str: | |
| """Construye la tarjeta HTML a partir del diccionario devuelto por analyze_sentiment.""" | |
| style = SENTIMENT_STYLES[result["sentiment"]] | |
| # La etiqueta del modelo tiene la forma "4 stars"; se extrae el número | |
| stars = int(result["label"].split()[0]) | |
| star_text = "★" * stars + "☆" * (5 - stars) | |
| confidence = result["score"] * 100 | |
| return f""" | |
| <div class="result-card" style="background: {style['background']}; | |
| border-left: 6px solid {style['color']};"> | |
| <p class="caption">Sentimiento predominante</p> | |
| <p class="sentiment" style="color: {style['color']};">{result['sentiment']}</p> | |
| <p class="stars" style="color: {style['color']};">{star_text}</p> | |
| <p class="meta">Clase del modelo: {result['label']}</p> | |
| <p class="caption">Confianza del modelo</p> | |
| <div class="bar-track"> | |
| <div class="bar-fill" style="width: {confidence:.1f}%; | |
| background: {style['color']};"></div> | |
| </div> | |
| <p class="meta">{confidence:.1f} %</p> | |
| </div> | |
| """ | |
| def classify_text(text: str) -> str: | |
| """Recibe el texto de la caja, llama al analizador y devuelve HTML para mostrar.""" | |
| # Se valida que el usuario haya escrito algo antes de llamar al modelo | |
| if not text or not text.strip(): | |
| return EMPTY_RESULT_HTML | |
| # analyze_sentiment devuelve una lista; como se envía un solo texto, se toma el primer elemento | |
| result = analyze_sentiment(text)[0] | |
| return build_result_html(result) | |
| def clear_all(): | |
| """Restablece la caja de texto y el panel de resultado.""" | |
| return "", EMPTY_RESULT_HTML | |
| # Se construye la función que crea la interfaz de usuario | |
| def create_interface() -> gr.Blocks: | |
| with gr.Blocks(title="Análisis de Sentimiento en Español") as demo: | |
| gr.HTML(HEADER_HTML) | |
| with gr.Row(equal_height=False): | |
| # Columna izquierda: entrada | |
| with gr.Column(scale=1): | |
| text_input = gr.Textbox( | |
| label="Texto en español", | |
| placeholder="Escriba o pegue aquí el texto que desea analizar...", | |
| lines=8, | |
| max_lines=14, | |
| ) | |
| with gr.Row(): | |
| clear_button = gr.Button("Limpiar", variant="secondary") | |
| submit_button = gr.Button("Analizar sentimiento", variant="primary") | |
| # Columna derecha: resultado | |
| with gr.Column(scale=1): | |
| result_output = gr.HTML(value=EMPTY_RESULT_HTML) | |
| gr.Examples( | |
| examples=EXAMPLES, | |
| inputs=text_input, | |
| label="Ejemplos de texto", | |
| ) | |
| with gr.Accordion("Nota metodológica", open=False): | |
| gr.Markdown(METHODOLOGY_NOTE) | |
| # Conexión de eventos: qué función se ejecuta al interactuar con cada componente | |
| submit_button.click(fn=classify_text, inputs=text_input, outputs=result_output) | |
| clear_button.click(fn=clear_all, inputs=None, outputs=[text_input, result_output]) | |
| return demo |