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
|