Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -70,12 +70,14 @@ p {
|
|
| 70 |
}
|
| 71 |
|
| 72 |
/* COMPONENTES DE ENTRADA (TEXTBOX) */
|
|
|
|
| 73 |
.gr-textbox label, .gradio-output .label {
|
| 74 |
color: #AAB7C4 !important; /* Gris medio para las etiquetas */
|
| 75 |
font-weight: bold;
|
| 76 |
font-size: 0.85em; /* Etiqueta más pequeña */
|
| 77 |
margin-bottom: 3px; /* Espacio mínimo entre etiqueta y caja */
|
| 78 |
}
|
|
|
|
| 79 |
.gr-textbox textarea {
|
| 80 |
background-color: rgba(0, 122, 204, 0.1); /* Azul Oscuro muy transparente */
|
| 81 |
border: 1px solid #007ACC; /* Borde con Azul Oscuro */
|
|
@@ -83,11 +85,18 @@ p {
|
|
| 83 |
border-radius: 5px; /* Bordes más pequeños */
|
| 84 |
padding: 6px; /* Reducir padding del textarea */
|
| 85 |
font-size: 0.9em; /* Fuente más pequeña en el textarea */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
}
|
| 87 |
|
|
|
|
| 88 |
/* BOTONES PRINCIPALES */
|
|
|
|
| 89 |
.gr-button.primary {
|
| 90 |
-
background-color: #00BFFF !important; /* Azul Brillante para el botón primario (Acento) */
|
| 91 |
color: #1E2B38 !important; /* Texto oscuro para el botón primario */
|
| 92 |
border-radius: 5px;
|
| 93 |
transition: background-color 0.3s ease;
|
|
@@ -138,18 +147,26 @@ p {
|
|
| 138 |
font-size: 1em; /* Un poco más pequeño */
|
| 139 |
font-weight: bold;
|
| 140 |
color: #FFFFFF; /* Texto blanco para todos los sentimientos */
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
}
|
| 142 |
.sentiment-display p { /* Estilo específico para el párrafo de descripción */
|
| 143 |
font-size: 0.75em; /* Tamaño más pequeño para la descripción */
|
| 144 |
margin-top: 3px;
|
| 145 |
margin-bottom: 0;
|
| 146 |
line-height: 1.2;
|
|
|
|
|
|
|
|
|
|
| 147 |
}
|
| 148 |
.sentiment-positive { background-color: #28a745; } /* Mantener estos colores por claridad de sentimiento */
|
| 149 |
.sentiment-negative { background-color: #dc3545; }
|
| 150 |
.sentiment-neutral { background-color: #007BFF; }
|
| 151 |
|
| 152 |
/* NUEVOS BOTONES DE EJEMPLO DIRECTOS (NO gr.Examples) */
|
|
|
|
| 153 |
.example-button {
|
| 154 |
background-color: #4A5B6C !important; /* Gris Claro para los botones de ejemplo */
|
| 155 |
color: #FFFFFF !important;
|
|
@@ -158,12 +175,15 @@ p {
|
|
| 158 |
padding: 5px 8px; /* Padding más pequeño */
|
| 159 |
margin: 2px; /* Margen mínimo entre botones */
|
| 160 |
transition: background-color 0.3s ease;
|
| 161 |
-
font-size: 0.
|
| 162 |
-
white-space:
|
| 163 |
-
|
|
|
|
|
|
|
| 164 |
cursor: pointer; /* Indicar que son clickeables */
|
| 165 |
flex-grow: 1; /* Permitir que los botones de ejemplo crezcan para llenar el espacio */
|
| 166 |
min-width: 80px; /* Asegurar un ancho mínimo para cada botón */
|
|
|
|
| 167 |
}
|
| 168 |
.example-button:hover {
|
| 169 |
background-color: #007ACC !important; /* Azul Oscuro al pasar el ratón por los ejemplos */
|
|
@@ -173,8 +193,9 @@ p {
|
|
| 173 |
/* Contenedor de los botones de ejemplo para forzar el "wrap" con flexbox */
|
| 174 |
.example-buttons-container {
|
| 175 |
display: flex;
|
| 176 |
-
flex-wrap: wrap; /* ¡Esto simula el wrap
|
| 177 |
justify-content: center; /* Centrar los botones si no llenan la línea */
|
|
|
|
| 178 |
margin-top: 5px; /* Pequeño margen superior */
|
| 179 |
margin-bottom: 10px; /* Pequeño margen inferior */
|
| 180 |
}
|
|
@@ -204,6 +225,31 @@ footer {
|
|
| 204 |
.gradio-app > div > :last-child:not(.gradio-container) { /* Apuntar al elemento del pie de página */
|
| 205 |
display: none !important; /* Otra forma de ocultar completamente si lo anterior no funciona */
|
| 206 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
"""
|
| 208 |
|
| 209 |
# --- Helper Function for Sentiment Interpretation ---
|
|
@@ -228,32 +274,33 @@ def interpret_sentiment(label, score):
|
|
| 228 |
emoji = "❓"
|
| 229 |
description = "Sentiment not determined."
|
| 230 |
color_class = ""
|
| 231 |
-
|
|
|
|
| 232 |
return f"<div class='sentiment-display {color_class}'>{emoji} {label.upper()} ({score:.2f})</div>" + \
|
| 233 |
-
f"<p style='color: #FFFFFF; font-size: 0.
|
| 234 |
|
| 235 |
# --- Sentiment Analysis Function ---
|
| 236 |
def analyze_sentiment(text):
|
| 237 |
if not model_loaded_successfully:
|
| 238 |
-
return (
|
| 239 |
-
"<div class='sentiment-display'>⚠️ Model Error ⚠️</div><p style='color: #FFFFFF; font-size: 0.
|
| 240 |
-
{},
|
| 241 |
-
{"error": "Model loading failed."}
|
| 242 |
)
|
| 243 |
|
| 244 |
if not text.strip():
|
| 245 |
-
return (
|
| 246 |
-
"<div class='sentiment-display'>✍️ Enter text ✍️</div><p style='color: #FFFFFF; font-size: 0.
|
| 247 |
-
{},
|
| 248 |
-
{"info": "No text entered."}
|
| 249 |
)
|
| 250 |
|
| 251 |
try:
|
| 252 |
-
results = sentiment_analyzer(text)[0]
|
| 253 |
|
| 254 |
results_sorted = sorted(results, key=lambda x: x['score'], reverse=True)
|
| 255 |
|
| 256 |
-
top_sentiment = results_sorted[0]
|
| 257 |
label = top_sentiment['label']
|
| 258 |
score = top_sentiment['score']
|
| 259 |
|
|
@@ -261,13 +308,13 @@ def analyze_sentiment(text):
|
|
| 261 |
|
| 262 |
overall_sentiment_display = interpret_sentiment(label, score)
|
| 263 |
|
| 264 |
-
return (overall_sentiment_display, confidence_scores_output, results)
|
| 265 |
|
| 266 |
except Exception as e:
|
| 267 |
-
return (
|
| 268 |
-
f"<div class='sentiment-display'>❌ Error ❌</div><p style='color: #FFFFFF; font-size: 0.
|
| 269 |
-
{},
|
| 270 |
-
{"error_message": str(e)}
|
| 271 |
)
|
| 272 |
|
| 273 |
# --- Lista completa de ejemplos para selección aleatoria ---
|
|
@@ -287,7 +334,7 @@ ALL_EXAMPLES = [
|
|
| 287 |
]
|
| 288 |
|
| 289 |
# --- Gradio Interface ---
|
| 290 |
-
with gr.Blocks(css=custom_css, theme=None) as demo:
|
| 291 |
gr.Markdown("<h1 style='color: #00BFFF;'>🌌 Sentiment Analyzer 🌌</h1>")
|
| 292 |
gr.Markdown("<p style='color: #AAB7C4;'>Analyze the emotional tone of your English text.</p>")
|
| 293 |
|
|
@@ -304,11 +351,11 @@ with gr.Blocks(css=custom_css, theme=None) as demo:
|
|
| 304 |
# --- Definir las salidas ANTES de usarlas en los eventos de los botones ---
|
| 305 |
overall_sentiment_output = gr.HTML(label="Overall Sentiment")
|
| 306 |
confidence_scores_output = gr.Label(num_top_classes=3, label="Confidence Scores", visible=False)
|
| 307 |
-
raw_output = gr.JSON(label="Raw Model Output", visible=False)
|
| 308 |
|
| 309 |
# --- Título para los ejemplos ---
|
| 310 |
gr.Markdown("<h3 style='color: #00BFFF; margin-top: 5px; margin-bottom: 5px;'>Try examples:</h3>")
|
| 311 |
-
|
| 312 |
# Contenedor para los botones de ejemplo para manejar el "wrap" vía CSS
|
| 313 |
with gr.Row(elem_classes="example-buttons-container"):
|
| 314 |
# Generar 3 botones de ejemplo aleatorios
|
|
@@ -325,10 +372,10 @@ with gr.Blocks(css=custom_css, theme=None) as demo:
|
|
| 325 |
inputs=text_input,
|
| 326 |
outputs=[overall_sentiment_output, confidence_scores_output, raw_output]
|
| 327 |
)
|
| 328 |
-
|
| 329 |
gr.Markdown("<hr>") # Separador
|
| 330 |
gr.Markdown("<h2 style='color: #00BFFF;'>📊 Results</h2>")
|
| 331 |
-
|
| 332 |
# Las salidas ya están definidas arriba, ahora solo las colocamos en el layout
|
| 333 |
# (overall_sentiment_output ya se definió, y su visibilidad y escala se controlan arriba)
|
| 334 |
# No es necesario re-definirlas aquí, solo asegurarnos de que estén en el flujo de la interfaz
|
|
@@ -345,7 +392,7 @@ with gr.Blocks(css=custom_css, theme=None) as demo:
|
|
| 345 |
fn=analyze_sentiment,
|
| 346 |
inputs=text_input,
|
| 347 |
outputs=[overall_sentiment_output, confidence_scores_output, raw_output],
|
| 348 |
-
# live=True
|
| 349 |
)
|
| 350 |
|
| 351 |
# Launch the Gradio application
|
|
|
|
| 70 |
}
|
| 71 |
|
| 72 |
/* COMPONENTES DE ENTRADA (TEXTBOX) */
|
| 73 |
+
/* Selector para el label del textbox */
|
| 74 |
.gr-textbox label, .gradio-output .label {
|
| 75 |
color: #AAB7C4 !important; /* Gris medio para las etiquetas */
|
| 76 |
font-weight: bold;
|
| 77 |
font-size: 0.85em; /* Etiqueta más pequeña */
|
| 78 |
margin-bottom: 3px; /* Espacio mínimo entre etiqueta y caja */
|
| 79 |
}
|
| 80 |
+
/* Selector para el textarea del textbox */
|
| 81 |
.gr-textbox textarea {
|
| 82 |
background-color: rgba(0, 122, 204, 0.1); /* Azul Oscuro muy transparente */
|
| 83 |
border: 1px solid #007ACC; /* Borde con Azul Oscuro */
|
|
|
|
| 85 |
border-radius: 5px; /* Bordes más pequeños */
|
| 86 |
padding: 6px; /* Reducir padding del textarea */
|
| 87 |
font-size: 0.9em; /* Fuente más pequeña en el textarea */
|
| 88 |
+
resize: vertical; /* Permite redimensionar verticalmente */
|
| 89 |
+
min-height: 50px; /* Altura mínima */
|
| 90 |
+
white-space: pre-wrap; /* Permite saltos de línea y respeta espacios */
|
| 91 |
+
word-wrap: break-word; /* Rompe palabras largas */
|
| 92 |
+
overflow-wrap: break-word; /* Estándar más moderno */
|
| 93 |
}
|
| 94 |
|
| 95 |
+
|
| 96 |
/* BOTONES PRINCIPALES */
|
| 97 |
+
/* Cambiado el color del botón primario */
|
| 98 |
.gr-button.primary {
|
| 99 |
+
background-color: #00BFFF !important; /* ¡Azul Brillante para el botón primario (Acento)! */
|
| 100 |
color: #1E2B38 !important; /* Texto oscuro para el botón primario */
|
| 101 |
border-radius: 5px;
|
| 102 |
transition: background-color 0.3s ease;
|
|
|
|
| 147 |
font-size: 1em; /* Un poco más pequeño */
|
| 148 |
font-weight: bold;
|
| 149 |
color: #FFFFFF; /* Texto blanco para todos los sentimientos */
|
| 150 |
+
/* Asegurar que el texto se envuelva */
|
| 151 |
+
white-space: normal;
|
| 152 |
+
word-wrap: break-word;
|
| 153 |
+
overflow-wrap: break-word;
|
| 154 |
}
|
| 155 |
.sentiment-display p { /* Estilo específico para el párrafo de descripción */
|
| 156 |
font-size: 0.75em; /* Tamaño más pequeño para la descripción */
|
| 157 |
margin-top: 3px;
|
| 158 |
margin-bottom: 0;
|
| 159 |
line-height: 1.2;
|
| 160 |
+
white-space: normal; /* Asegurar que el párrafo se envuelva */
|
| 161 |
+
word-wrap: break-word;
|
| 162 |
+
overflow-wrap: break-word;
|
| 163 |
}
|
| 164 |
.sentiment-positive { background-color: #28a745; } /* Mantener estos colores por claridad de sentimiento */
|
| 165 |
.sentiment-negative { background-color: #dc3545; }
|
| 166 |
.sentiment-neutral { background-color: #007BFF; }
|
| 167 |
|
| 168 |
/* NUEVOS BOTONES DE EJEMPLO DIRECTOS (NO gr.Examples) */
|
| 169 |
+
/* Ajustes para el texto de los botones de ejemplo */
|
| 170 |
.example-button {
|
| 171 |
background-color: #4A5B6C !important; /* Gris Claro para los botones de ejemplo */
|
| 172 |
color: #FFFFFF !important;
|
|
|
|
| 175 |
padding: 5px 8px; /* Padding más pequeño */
|
| 176 |
margin: 2px; /* Margen mínimo entre botones */
|
| 177 |
transition: background-color 0.3s ease;
|
| 178 |
+
font-size: 0.7em; /* ¡Tamaño de fuente más pequeño para los ejemplos! */
|
| 179 |
+
white-space: normal; /* ¡Permitir que el texto se rompa en varias líneas! */
|
| 180 |
+
word-wrap: break-word; /* Rompe palabras largas */
|
| 181 |
+
overflow-wrap: break-word; /* Estándar más moderno */
|
| 182 |
+
flex-shrink: 1; /* Permitir que se encojan si es necesario */
|
| 183 |
cursor: pointer; /* Indicar que son clickeables */
|
| 184 |
flex-grow: 1; /* Permitir que los botones de ejemplo crezcan para llenar el espacio */
|
| 185 |
min-width: 80px; /* Asegurar un ancho mínimo para cada botón */
|
| 186 |
+
text-align: center; /* Centrar el texto dentro del botón */
|
| 187 |
}
|
| 188 |
.example-button:hover {
|
| 189 |
background-color: #007ACC !important; /* Azul Oscuro al pasar el ratón por los ejemplos */
|
|
|
|
| 193 |
/* Contenedor de los botones de ejemplo para forzar el "wrap" con flexbox */
|
| 194 |
.example-buttons-container {
|
| 195 |
display: flex;
|
| 196 |
+
flex-wrap: wrap; /* ¡Esto simula el wrap! */
|
| 197 |
justify-content: center; /* Centrar los botones si no llenan la línea */
|
| 198 |
+
align-items: stretch; /* Asegura que los botones tengan la misma altura si el texto envuelve */
|
| 199 |
margin-top: 5px; /* Pequeño margen superior */
|
| 200 |
margin-bottom: 10px; /* Pequeño margen inferior */
|
| 201 |
}
|
|
|
|
| 225 |
.gradio-app > div > :last-child:not(.gradio-container) { /* Apuntar al elemento del pie de página */
|
| 226 |
display: none !important; /* Otra forma de ocultar completamente si lo anterior no funciona */
|
| 227 |
}
|
| 228 |
+
|
| 229 |
+
/* Ajustes para el contenedor de la salida de Label (para que el texto interno envuelva) */
|
| 230 |
+
.gradio-output > .label {
|
| 231 |
+
white-space: normal !important; /* Permitir que el texto envuelva */
|
| 232 |
+
word-wrap: break-word !important; /* Romper palabras largas */
|
| 233 |
+
overflow-wrap: break-word !important; /* Estándar moderno */
|
| 234 |
+
}
|
| 235 |
+
/* Asegurarse de que el texto dentro de los resultados de Gradio (si no es HTML) también envuelva */
|
| 236 |
+
.gradio-output > div {
|
| 237 |
+
white-space: normal !important;
|
| 238 |
+
word-wrap: break-word !important;
|
| 239 |
+
overflow-wrap: break-word !important;
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
/* Ajustes para el texto dentro del gr.Label (Confidence Scores) si se hace visible */
|
| 243 |
+
.gr-label-container {
|
| 244 |
+
font-size: 0.8em; /* Reducir la fuente de los scores de confianza */
|
| 245 |
+
}
|
| 246 |
+
.gr-label-container .label-text {
|
| 247 |
+
font-size: 1em !important; /* Mantener la etiqueta del score legible */
|
| 248 |
+
}
|
| 249 |
+
.gr-label-container .label-score {
|
| 250 |
+
font-size: 0.9em !important; /* Un poco más pequeño que la etiqueta */
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
"""
|
| 254 |
|
| 255 |
# --- Helper Function for Sentiment Interpretation ---
|
|
|
|
| 274 |
emoji = "❓"
|
| 275 |
description = "Sentiment not determined."
|
| 276 |
color_class = ""
|
| 277 |
+
|
| 278 |
+
# El HTML de salida también debe permitir el salto de línea y reducir la fuente del párrafo
|
| 279 |
return f"<div class='sentiment-display {color_class}'>{emoji} {label.upper()} ({score:.2f})</div>" + \
|
| 280 |
+
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>"
|
| 281 |
|
| 282 |
# --- Sentiment Analysis Function ---
|
| 283 |
def analyze_sentiment(text):
|
| 284 |
if not model_loaded_successfully:
|
| 285 |
+
return (
|
| 286 |
+
"<div class='sentiment-display'>⚠️ Model Error ⚠️</div><p style='color: #FFFFFF; font-size: 0.7em;'>Model not loaded.</p>",
|
| 287 |
+
{},
|
| 288 |
+
{"error": "Model loading failed."}
|
| 289 |
)
|
| 290 |
|
| 291 |
if not text.strip():
|
| 292 |
+
return (
|
| 293 |
+
"<div class='sentiment-display'>✍️ Enter text ✍️</div><p style='color: #FFFFFF; font-size: 0.7em;'>Type text to analyze.</p>",
|
| 294 |
+
{},
|
| 295 |
+
{"info": "No text entered."}
|
| 296 |
)
|
| 297 |
|
| 298 |
try:
|
| 299 |
+
results = sentiment_analyzer(text)[0]
|
| 300 |
|
| 301 |
results_sorted = sorted(results, key=lambda x: x['score'], reverse=True)
|
| 302 |
|
| 303 |
+
top_sentiment = results_sorted[0]
|
| 304 |
label = top_sentiment['label']
|
| 305 |
score = top_sentiment['score']
|
| 306 |
|
|
|
|
| 308 |
|
| 309 |
overall_sentiment_display = interpret_sentiment(label, score)
|
| 310 |
|
| 311 |
+
return (overall_sentiment_display, confidence_scores_output, results)
|
| 312 |
|
| 313 |
except Exception as e:
|
| 314 |
+
return (
|
| 315 |
+
f"<div class='sentiment-display'>❌ Error ❌</div><p style='color: #FFFFFF; font-size: 0.7em;'>Analysis failed.</p>",
|
| 316 |
+
{},
|
| 317 |
+
{"error_message": str(e)}
|
| 318 |
)
|
| 319 |
|
| 320 |
# --- Lista completa de ejemplos para selección aleatoria ---
|
|
|
|
| 334 |
]
|
| 335 |
|
| 336 |
# --- Gradio Interface ---
|
| 337 |
+
with gr.Blocks(css=custom_css, theme=None) as demo:
|
| 338 |
gr.Markdown("<h1 style='color: #00BFFF;'>🌌 Sentiment Analyzer 🌌</h1>")
|
| 339 |
gr.Markdown("<p style='color: #AAB7C4;'>Analyze the emotional tone of your English text.</p>")
|
| 340 |
|
|
|
|
| 351 |
# --- Definir las salidas ANTES de usarlas en los eventos de los botones ---
|
| 352 |
overall_sentiment_output = gr.HTML(label="Overall Sentiment")
|
| 353 |
confidence_scores_output = gr.Label(num_top_classes=3, label="Confidence Scores", visible=False)
|
| 354 |
+
raw_output = gr.JSON(label="Raw Model Output", visible=False)
|
| 355 |
|
| 356 |
# --- Título para los ejemplos ---
|
| 357 |
gr.Markdown("<h3 style='color: #00BFFF; margin-top: 5px; margin-bottom: 5px;'>Try examples:</h3>")
|
| 358 |
+
|
| 359 |
# Contenedor para los botones de ejemplo para manejar el "wrap" vía CSS
|
| 360 |
with gr.Row(elem_classes="example-buttons-container"):
|
| 361 |
# Generar 3 botones de ejemplo aleatorios
|
|
|
|
| 372 |
inputs=text_input,
|
| 373 |
outputs=[overall_sentiment_output, confidence_scores_output, raw_output]
|
| 374 |
)
|
| 375 |
+
|
| 376 |
gr.Markdown("<hr>") # Separador
|
| 377 |
gr.Markdown("<h2 style='color: #00BFFF;'>📊 Results</h2>")
|
| 378 |
+
|
| 379 |
# Las salidas ya están definidas arriba, ahora solo las colocamos en el layout
|
| 380 |
# (overall_sentiment_output ya se definió, y su visibilidad y escala se controlan arriba)
|
| 381 |
# No es necesario re-definirlas aquí, solo asegurarnos de que estén en el flujo de la interfaz
|
|
|
|
| 392 |
fn=analyze_sentiment,
|
| 393 |
inputs=text_input,
|
| 394 |
outputs=[overall_sentiment_output, confidence_scores_output, raw_output],
|
| 395 |
+
# live=True
|
| 396 |
)
|
| 397 |
|
| 398 |
# Launch the Gradio application
|