File size: 17,028 Bytes
3bc0305 3dc2123 c13ab36 b516a41 3dc2123 9d5b24b 51ebb55 94adeb8 3dc2123 c13ab36 51ebb55 fbfc3a2 3dc2123 51ebb55 fbfc3a2 3dc2123 7e669a3 51ebb55 7e669a3 51ebb55 17c021b 7e669a3 51ebb55 7e669a3 51ebb55 7e669a3 51ebb55 7e669a3 17c021b 7e669a3 51ebb55 7e669a3 51ebb55 17c021b 51ebb55 7e669a3 17c021b 7e669a3 17c021b 7e669a3 17c021b 7e669a3 532ce4d 17c021b 7e669a3 17c021b 7e669a3 17c021b 532ce4d 17c021b 7e669a3 17c021b 7e669a3 532ce4d 51ebb55 7e669a3 532ce4d 7e669a3 532ce4d 51ebb55 532ce4d 17c021b 7e669a3 51ebb55 7e669a3 17c021b 7e669a3 51ebb55 17c021b 51ebb55 7e669a3 51ebb55 17c021b 7e669a3 17c021b 7e669a3 cd5851e 7e669a3 51ebb55 7e669a3 51ebb55 7e669a3 51ebb55 17c021b 532ce4d 51ebb55 7e669a3 532ce4d 17c021b 7e669a3 b516a41 532ce4d b516a41 17c021b 7e669a3 17c021b 532ce4d b516a41 cd5851e 532ce4d 17c021b b516a41 17c021b 7e669a3 cd5851e 532ce4d cd5851e 532ce4d cd5851e 7e669a3 17c021b 7e669a3 51ebb55 7e669a3 51ebb55 7e669a3 532ce4d 51ebb55 8a03f45 51ebb55 810cb59 51ebb55 8a03f45 51ebb55 810cb59 51ebb55 8a03f45 51ebb55 810cb59 51ebb55 810cb59 51ebb55 532ce4d 51ebb55 532ce4d 51ebb55 3dc2123 51ebb55 532ce4d 3dce035 51ebb55 532ce4d 3dce035 51ebb55 532ce4d 51ebb55 532ce4d 51ebb55 532ce4d 5dc3c79 51ebb55 532ce4d 3dce035 51ebb55 810cb59 b516a41 810cb59 51ebb55 532ce4d 17c021b 810cb59 8a03f45 b516a41 8a03f45 b516a41 8a03f45 22c09c7 532ce4d 22c09c7 cd5851e 532ce4d cd5851e b516a41 cd5851e b516a41 532ce4d cd5851e 810cb59 532ce4d 22c09c7 8a03f45 9d5b24b 8a03f45 51ebb55 8a03f45 51ebb55 8a03f45 51ebb55 8a03f45 532ce4d 51ebb55 9d5b24b 51ebb55 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
import gradio as gr
from transformers import pipeline
import os
import random
# Añade esto para verificar la versión de Gradio en tiempo de ejecución
print(f"Gradio version at runtime: {gr.__version__}")
# --- Model Loading ---
MODEL_ID = "Light-Dav/sentiment-analysis-full-project"
try:
sentiment_analyzer = pipeline("sentiment-analysis", model=MODEL_ID, top_k=None)
model_loaded_successfully = True
print("Sentiment analysis model loaded successfully.")
except Exception as e:
print(f"Error loading model: {e}")
sentiment_analyzer = None
model_loaded_successfully = False
print("Sentiment analysis model failed to load. Please check MODEL_ID and network connection.")
# --- Custom CSS with the NEW COLOR PALETTE and MAXIMUM COMPACTNESS ---
custom_css = """
/* RESETEO BÁSICO Y FONDOS GENERALES */
body {
background-color: #1E2B38; /* Fondo General Oscuro */
color: #FFFFFF; /* Blanco para texto principal */
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
padding: 0;
margin: 0;
overflow: hidden; /* Ocultar scrollbar si hay un pequeño desbordamiento */
height: 100vh; /* Asegurar que el body ocupe toda la altura del viewport */
display: flex;
flex-direction: column;
}
/* CONTENEDOR PRINCIPAL DE GRADIO */
.gradio-container {
box-shadow: 0 2px 4px rgba(0, 122, 204, 0.1); /* Sombra más sutil */
border-radius: 6px; /* Borde más pequeño */
overflow: hidden;
background-color: #1E2B38; /* Fondo de la tarjeta, coincide con el body */
padding: 10px; /* Reducir padding general del contenedor */
margin-bottom: 5px; /* Reducir margen inferior */
border: 1px solid #007ACC; /* Borde sutil con Azul Oscuro */
flex-grow: 1; /* Permite que el contenedor ocupe el espacio disponible */
display: flex;
flex-direction: column;
}
/* AJUSTES DE TÍTULOS Y PÁRRAFOS */
h1, h2, h3 {
color: #00BFFF; /* Azul Brillante para títulos */
text-align: center;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
animation: fadeIn 1s ease-in-out;
margin-top: 5px; /* Margen superior muy pequeño */
margin-bottom: 8px; /* Margen inferior reducido */
font-size: 1.4em; /* h1 más pequeño */
}
h2 { font-size: 1.1em; } /* h2 más pequeño */
h3 { font-size: 0.95em; } /* h3 más pequeño, casi texto normal */
p {
color: #AAB7C4; /* Gris medio para texto secundario */
text-align: center;
margin-bottom: 10px; /* Margen debajo de los párrafos reducido */
font-size: 0.8em; /* Tamaño de fuente más pequeño para párrafos */
line-height: 1.3; /* Espaciado entre líneas para legibilidad */
}
/* COMPONENTES DE ENTRADA (TEXTBOX) */
/* Selector para el label del textbox */
.gr-textbox label, .gradio-output .label {
color: #AAB7C4 !important; /* Gris medio para las etiquetas */
font-weight: bold;
font-size: 0.85em; /* Etiqueta más pequeña */
margin-bottom: 3px; /* Espacio mínimo entre etiqueta y caja */
}
/* Selector para el textarea del textbox */
.gr-textbox textarea {
background-color: rgba(0, 122, 204, 0.1); /* Azul Oscuro muy transparente */
border: 1px solid #007ACC; /* Borde con Azul Oscuro */
color: #FFFFFF; /* Texto blanco en el textarea */
border-radius: 5px; /* Bordes más pequeños */
padding: 6px; /* Reducir padding del textarea */
font-size: 0.9em; /* Fuente más pequeña en el textarea */
resize: vertical; /* Permite redimensionar verticalmente */
min-height: 50px; /* Altura mínima */
white-space: pre-wrap; /* Permite saltos de línea y respeta espacios */
word-wrap: break-word; /* Rompe palabras largas */
overflow-wrap: break-word; /* Estándar más moderno */
}
/* BOTONES PRINCIPALES */
/* Cambiado el color del botón primario */
.gr-button.primary {
background-color: #00BFFF !important; /* ¡Azul Brillante para el botón primario (Acento)! */
color: #1E2B38 !important; /* Texto oscuro para el botón primario */
border-radius: 5px;
transition: background-color 0.3s ease;
padding: 7px 12px; /* Padding más pequeño del botón */
font-size: 0.9em; /* Un poco más pequeño para el botón */
font-weight: bold;
margin-top: 8px; /* Reducir margen superior */
margin-bottom: 5px; /* Añadir un pequeño margen inferior */
}
.gr-button.primary:hover {
background-color: #007ACC !important; /* Azul Oscuro al pasar el ratón */
color: #FFFFFF !important; /* Texto blanco al pasar el ratón */
}
/* COMPONENTES DE SALIDA (HTML, LABEL, JSON) */
.gradio-output {
border: 1px solid #4A5B6C; /* Borde sutil con Gris Claro */
border-radius: 5px; /* Borde más pequeño */
padding: 8px; /* Reducir padding de la salida */
margin-top: 8px; /* Reducir margen superior */
background-color: rgba(0, 122, 204, 0.08); /* Fondo más sutil para la salida */
color: #FFFFFF; /* Texto blanco en la salida */
flex-grow: 1; /* Permitir que ocupe el espacio restante */
display: flex;
flex-direction: column;
justify-content: center; /* Centrar verticalmente el contenido */
min-height: 80px; /* Altura mínima para asegurar visibilidad */
width: 100%; /* Asegurar que ocupe todo el ancho disponible */
box-sizing: border-box; /* Incluir padding y borde en el ancho */
}
.gradio-output .label-text {
color: #00BFFF !important; /* Color de acento para el texto del label (LABEL_1, LABEL_0, etc.) */
font-weight: bold;
}
.gradio-output .label-score {
color: #FFFFFF !important; /* Blanco para el score del label */
}
.gradio-output .label-container {
padding-bottom: 5px !important; /* Reducir padding entre elementos del label */
}
/* DISPLAY DE SENTIMIENTO (DENTRO DE HTML OUTPUT) */
.sentiment-display {
text-align: center;
padding: 6px; /* Reducir padding */
border-radius: 4px; /* Borde más pequeño */
margin-top: 3px; /* Margen muy pequeño */
font-size: 1em; /* Un poco más pequeño */
font-weight: bold;
color: #FFFFFF; /* Texto blanco para todos los sentimientos */
/* Asegurar que el texto se envuelva */
white-space: normal;
word-wrap: break-word;
overflow-wrap: break-word;
}
.sentiment-display p { /* Estilo específico para el párrafo de descripción */
font-size: 0.75em; /* Tamaño más pequeño para la descripción */
margin-top: 3px;
margin-bottom: 0;
line-height: 1.2;
white-space: normal; /* Asegurar que el párrafo se envuelva */
word-wrap: break-word;
overflow-wrap: break-word;
}
.sentiment-positive { background-color: #28a745; } /* Mantener estos colores por claridad de sentimiento */
.sentiment-negative { background-color: #dc3545; }
.sentiment-neutral { background-color: #007BFF; }
/* NUEVOS BOTONES DE EJEMPLO DIRECTOS (NO gr.Examples) */
/* Ajustes para el texto de los botones de ejemplo */
.example-button {
background-color: #4A5B6C !important; /* Gris Claro para los botones de ejemplo */
color: #FFFFFF !important;
border: 1px solid #4A5B6C;
border-radius: 3px; /* Borde más pequeño */
padding: 5px 8px; /* Padding más pequeño */
margin: 2px; /* Margen mínimo entre botones */
transition: background-color 0.3s ease;
font-size: 0.7em; /* ¡Tamaño de fuente más pequeño para los ejemplos! */
white-space: normal; /* ¡Permitir que el texto se rompa en varias líneas! */
word-wrap: break-word; /* Rompe palabras largas */
overflow-wrap: break-word; /* Estándar más moderno */
flex-shrink: 1; /* Permitir que se encojan si es necesario */
cursor: pointer; /* Indicar que son clickeables */
flex-grow: 1; /* Permitir que los botones de ejemplo crezcan para llenar el espacio */
min-width: 80px; /* Asegurar un ancho mínimo para cada botón */
text-align: center; /* Centrar el texto dentro del botón */
}
.example-button:hover {
background-color: #007ACC !important; /* Azul Oscuro al pasar el ratón por los ejemplos */
border-color: #00BFFF !important;
}
/* Contenedor de los botones de ejemplo para forzar el "wrap" con flexbox */
.example-buttons-container {
display: flex;
flex-wrap: wrap; /* ¡Esto simula el wrap! */
justify-content: center; /* Centrar los botones si no llenan la línea */
align-items: stretch; /* Asegura que los botones tengan la misma altura si el texto envuelve */
margin-top: 5px; /* Pequeño margen superior */
margin-bottom: 10px; /* Pequeño margen inferior */
}
/* LÍNEAS DIVISORIAS */
hr {
border-top: 1px solid #4A5B6C; /* Línea divisoria con Gris Claro */
margin-top: 10px; /* Reducir margen superior */
margin-bottom: 10px; /* Reducir margen inferior */
}
/* ANIMACIÓN */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* OCULTAR EL PIE DE PÁGINA DE GRADIO (CRUCIAL PARA IFRAMES PEQUEÑOS) */
footer {
opacity: 0; /* Hacerlo invisible */
height: 0 !important; /* Eliminar su altura */
margin: 0 !important; /* Eliminar sus márgenes */
padding: 0 !important; /* Eliminar su padding */
pointer-events: none; /* No interactuable */
visibility: hidden; /* Asegurar que no ocupe espacio visual */
}
.gradio-app > div > :last-child:not(.gradio-container) { /* Apuntar al elemento del pie de página */
display: none !important; /* Otra forma de ocultar completamente si lo anterior no funciona */
}
/* Ajustes para el contenedor de la salida de Label (para que el texto interno envuelva) */
.gradio-output > .label {
white-space: normal !important; /* Permitir que el texto envuelva */
word-wrap: break-word !important; /* Romper palabras largas */
overflow-wrap: break-word !important; /* Estándar moderno */
}
/* Asegurarse de que el texto dentro de los resultados de Gradio (si no es HTML) también envuelva */
.gradio-output > div {
white-space: normal !important;
word-wrap: break-word !important;
overflow-wrap: break-word !important;
}
/* Ajustes para el texto dentro del gr.Label (Confidence Scores) si se hace visible */
.gr-label-container {
font-size: 0.8em; /* Reducir la fuente de los scores de confianza */
}
.gr-label-container .label-text {
font-size: 1em !important; /* Mantener la etiqueta del score legible */
}
.gr-label-container .label-score {
font-size: 0.9em !important; /* Un poco más pequeño que la etiqueta */
}
"""
# --- Helper Function for Sentiment Interpretation ---
def interpret_sentiment(label, score):
emoji = ""
description = ""
color_class = ""
if label.lower() == "positive" or label.lower() == "label_2":
emoji = "😊"
description = "Positive sentiment detected."
color_class = "sentiment-positive"
elif label.lower() == "negative" or label.lower() == "label_0":
emoji = "😠"
description = "Negative sentiment detected."
color_class = "sentiment-negative"
elif label.lower() == "neutral" or label.lower() == "label_1":
emoji = "😐"
description = "Neutral sentiment detected."
color_class = "sentiment-neutral"
else:
emoji = "❓"
description = "Sentiment not determined."
color_class = ""
# El HTML de salida también debe permitir el salto de línea y reducir la fuente del párrafo
return f"<div class='sentiment-display {color_class}'>{emoji} {label.upper()} ({score:.2f})</div>" + \
f"<p style='color: #FFFFFF; font-size: 0.7em; margin-top: 3px; margin-bottom: 0; line-height: 1.2; white-space: normal; word-wrap: break-word;'>{description}</p>"
# --- Sentiment Analysis Function ---
def analyze_sentiment(text):
if not model_loaded_successfully:
return (
"<div class='sentiment-display'>⚠️ Model Error ⚠️</div><p style='color: #FFFFFF; font-size: 0.7em;'>Model not loaded.</p>",
{},
{"error": "Model loading failed."}
)
if not text.strip():
return (
"<div class='sentiment-display'>✍️ Enter text ✍️</div><p style='color: #FFFFFF; font-size: 0.7em;'>Type text to analyze.</p>",
{},
{"info": "No text entered."}
)
try:
results = sentiment_analyzer(text)[0]
results_sorted = sorted(results, key=lambda x: x['score'], reverse=True)
top_sentiment = results_sorted[0]
label = top_sentiment['label']
score = top_sentiment['score']
confidence_scores_output = {item['label']: item['score'] for item in results}
overall_sentiment_display = interpret_sentiment(label, score)
return (overall_sentiment_display, confidence_scores_output, results)
except Exception as e:
return (
f"<div class='sentiment-display'>❌ Error ❌</div><p style='color: #FFFFFF; font-size: 0.7em;'>Analysis failed.</p>",
{},
{"error_message": str(e)}
)
# --- Lista completa de ejemplos para selección aleatoria ---
ALL_EXAMPLES = [
"The product quality is absolutely outstanding and worth every penny!",
"I found the customer support unhelpful and quite rude, a terrible experience.",
"The new software update introduced several bugs, making it very unstable.",
"This book is a captivating read, I couldn't put it down!",
"The delivery was late, and the package arrived damaged.",
"Despite the bad reviews, I thoroughly enjoyed the film and its unique plot.",
"The instructions were unclear, leading to a lot of confusion during assembly.",
"What a delicious meal! Every dish was prepared to perfection.",
"I'm very disappointed with the recent policy changes; they are unfair.",
"The new art exhibition is thought-provoking and visually stunning.",
"Traffic was unexpectedly heavy, causing significant delays.",
"Overall, a solid performance, though there's room for improvement."
]
# --- Gradio Interface ---
with gr.Blocks(css=custom_css, theme=None) as demo:
gr.Markdown("<h1 style='color: #00BFFF;'>🌌 Sentiment Analyzer 🌌</h1>")
gr.Markdown("<p style='color: #AAB7C4;'>Analyze the emotional tone of your English text.</p>")
with gr.Column(elem_classes="gradio-container"):
text_input = gr.Textbox(
lines=2,
placeholder="Type your English text here...",
label="Your Text",
interactive=True,
value=random.choice(ALL_EXAMPLES) # Establece un ejemplo aleatorio inicial
)
analyze_btn = gr.Button("Analyze Sentiment", variant="primary")
# --- Definir las salidas ANTES de usarlas en los eventos de los botones ---
overall_sentiment_output = gr.HTML(label="Overall Sentiment")
confidence_scores_output = gr.Label(num_top_classes=3, label="Confidence Scores", visible=False)
raw_output = gr.JSON(label="Raw Model Output", visible=False)
# --- Título para los ejemplos ---
gr.Markdown("<h3 style='color: #00BFFF; margin-top: 5px; margin-bottom: 5px;'>Try examples:</h3>")
# Contenedor para los botones de ejemplo para manejar el "wrap" vía CSS
with gr.Row(elem_classes="example-buttons-container"):
# Generar 3 botones de ejemplo aleatorios
for example_text in random.sample(ALL_EXAMPLES, 3):
gr.Button(
example_text,
elem_classes="example-button"
).click(
fn=lambda x: x, # Función simple para pasar el texto del botón al textbox
inputs=[gr.State(example_text)], # Usamos gr.State para pasar el texto del botón
outputs=text_input,
).then(
fn=analyze_sentiment, # Luego de cargar el texto, ejecuta el análisis
inputs=text_input,
outputs=[overall_sentiment_output, confidence_scores_output, raw_output]
)
gr.Markdown("<hr>") # Separador
gr.Markdown("<h2 style='color: #00BFFF;'>📊 Results</h2>")
# Las salidas ya están definidas arriba, ahora solo las colocamos en el layout
# (overall_sentiment_output ya se definió, y su visibilidad y escala se controlan arriba)
# No es necesario re-definirlas aquí, solo asegurarnos de que estén en el flujo de la interfaz
# (Gradio las "conoce" porque ya han sido creadas).
pass # No es necesario poner nada aquí, ya las variables fueron declaradas arriba
# --- Event Listeners ---
analyze_btn.click(
fn=analyze_sentiment,
inputs=text_input,
outputs=[overall_sentiment_output, confidence_scores_output, raw_output]
)
text_input.change(
fn=analyze_sentiment,
inputs=text_input,
outputs=[overall_sentiment_output, confidence_scores_output, raw_output],
# live=True
)
# Launch the Gradio application
demo.launch() |