Commit ·
d6f628c
1
Parent(s): 286b666
Show all 4 speakers in turn dropdowns, fix status animation
Browse files
app.py
CHANGED
|
@@ -278,47 +278,39 @@ CUSTOM_CSS = """
|
|
| 278 |
text-align: center;
|
| 279 |
font-size: 1.05em;
|
| 280 |
min-height: 0;
|
| 281 |
-
position: relative;
|
| 282 |
}
|
| 283 |
.gen-status-active {
|
|
|
|
| 284 |
background: linear-gradient(
|
| 285 |
90deg,
|
| 286 |
-
|
| 287 |
-
rgba(99, 102, 241, 0.
|
| 288 |
-
|
|
|
|
|
|
|
| 289 |
);
|
| 290 |
-
background-size:
|
| 291 |
-
animation:
|
| 292 |
-
|
| 293 |
-
background-clip: padding-box;
|
| 294 |
-
overflow: hidden;
|
| 295 |
}
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
position:
|
| 299 |
-
|
| 300 |
-
border-radius: 14px;
|
| 301 |
-
background: conic-gradient(
|
| 302 |
-
from 0deg,
|
| 303 |
-
#6366f1, #ec4899, #22c55e, #f59e0b, #6366f1
|
| 304 |
-
);
|
| 305 |
-
z-index: -1;
|
| 306 |
-
animation: spin 2.5s linear infinite;
|
| 307 |
-
}
|
| 308 |
-
.gen-status-active::after {
|
| 309 |
-
content: '';
|
| 310 |
-
position: absolute;
|
| 311 |
-
inset: 2px;
|
| 312 |
-
border-radius: 10px;
|
| 313 |
-
background: var(--background-fill-secondary);
|
| 314 |
-
z-index: -1;
|
| 315 |
-
}
|
| 316 |
-
@keyframes shimmer {
|
| 317 |
-
0% { background-position: 200% 0; }
|
| 318 |
-
100% { background-position: -200% 0; }
|
| 319 |
}
|
| 320 |
-
@keyframes
|
| 321 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 322 |
}
|
| 323 |
"""
|
| 324 |
|
|
@@ -354,23 +346,25 @@ def build_status_html(stage: str, status_line: str) -> str:
|
|
| 354 |
desc = status_line or default_desc or ""
|
| 355 |
|
| 356 |
if stage == "complete":
|
| 357 |
-
icon = "✓
|
| 358 |
-
color = "#22c55e"
|
| 359 |
cls = "gen-status"
|
| 360 |
elif stage == "error":
|
| 361 |
-
icon = "✗
|
| 362 |
-
color = "#ef4444"
|
| 363 |
cls = "gen-status"
|
| 364 |
else:
|
| 365 |
-
|
| 366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
cls = "gen-status gen-status-active"
|
| 368 |
|
| 369 |
return (
|
|
|
|
| 370 |
f'<div class="{cls}">'
|
| 371 |
-
f'<
|
| 372 |
-
f'<
|
| 373 |
-
f'<br><span style="opacity:0.75; font-size:0.9em;">{desc}</span>'
|
| 374 |
f'</div>'
|
| 375 |
)
|
| 376 |
|
|
@@ -452,10 +446,9 @@ def create_demo_interface():
|
|
| 452 |
)
|
| 453 |
return
|
| 454 |
|
| 455 |
-
|
| 456 |
-
# Build speaker labels with voice gender if assigned
|
| 457 |
speaker_choices = []
|
| 458 |
-
for i in range(
|
| 459 |
voice_name = AVAILABLE_VOICES[i] if i < len(AVAILABLE_VOICES) else None
|
| 460 |
gender = VOICE_GENDERS.get(voice_name, "")
|
| 461 |
tag = f" ({gender})" if gender else ""
|
|
|
|
| 278 |
text-align: center;
|
| 279 |
font-size: 1.05em;
|
| 280 |
min-height: 0;
|
|
|
|
| 281 |
}
|
| 282 |
.gen-status-active {
|
| 283 |
+
border: 2px solid #6366f1;
|
| 284 |
background: linear-gradient(
|
| 285 |
90deg,
|
| 286 |
+
rgba(99, 102, 241, 0.05) 0%,
|
| 287 |
+
rgba(99, 102, 241, 0.18) 30%,
|
| 288 |
+
rgba(236, 72, 153, 0.14) 50%,
|
| 289 |
+
rgba(99, 102, 241, 0.18) 70%,
|
| 290 |
+
rgba(99, 102, 241, 0.05) 100%
|
| 291 |
);
|
| 292 |
+
background-size: 300% 100%;
|
| 293 |
+
animation: gradient-sweep 2.5s ease-in-out infinite, border-glow 2s ease-in-out infinite;
|
| 294 |
+
box-shadow: 0 0 15px rgba(99, 102, 241, 0.15), 0 0 30px rgba(99, 102, 241, 0.05);
|
|
|
|
|
|
|
| 295 |
}
|
| 296 |
+
@keyframes gradient-sweep {
|
| 297 |
+
0% { background-position: 100% 0; }
|
| 298 |
+
50% { background-position: 0% 0; }
|
| 299 |
+
100% { background-position: 100% 0; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 300 |
}
|
| 301 |
+
@keyframes border-glow {
|
| 302 |
+
0%, 100% {
|
| 303 |
+
border-color: #6366f1;
|
| 304 |
+
box-shadow: 0 0 15px rgba(99, 102, 241, 0.15), 0 0 30px rgba(99, 102, 241, 0.05);
|
| 305 |
+
}
|
| 306 |
+
33% {
|
| 307 |
+
border-color: #ec4899;
|
| 308 |
+
box-shadow: 0 0 15px rgba(236, 72, 153, 0.2), 0 0 30px rgba(236, 72, 153, 0.08);
|
| 309 |
+
}
|
| 310 |
+
66% {
|
| 311 |
+
border-color: #22c55e;
|
| 312 |
+
box-shadow: 0 0 15px rgba(34, 197, 94, 0.2), 0 0 30px rgba(34, 197, 94, 0.08);
|
| 313 |
+
}
|
| 314 |
}
|
| 315 |
"""
|
| 316 |
|
|
|
|
| 346 |
desc = status_line or default_desc or ""
|
| 347 |
|
| 348 |
if stage == "complete":
|
| 349 |
+
icon = '<span style="color:#22c55e; font-size:1.4em; vertical-align:middle;">✓</span>'
|
|
|
|
| 350 |
cls = "gen-status"
|
| 351 |
elif stage == "error":
|
| 352 |
+
icon = '<span style="color:#ef4444; font-size:1.4em; vertical-align:middle;">✗</span>'
|
|
|
|
| 353 |
cls = "gen-status"
|
| 354 |
else:
|
| 355 |
+
# Pulsing animated dot
|
| 356 |
+
icon = (
|
| 357 |
+
'<span style="display:inline-block; width:12px; height:12px; '
|
| 358 |
+
'border-radius:50%; background:#6366f1; vertical-align:middle; '
|
| 359 |
+
'animation: dot-pulse 1.2s ease-in-out infinite;"></span>'
|
| 360 |
+
)
|
| 361 |
cls = "gen-status gen-status-active"
|
| 362 |
|
| 363 |
return (
|
| 364 |
+
f'<style>@keyframes dot-pulse {{ 0%,100% {{ opacity:1; transform:scale(1); }} 50% {{ opacity:0.4; transform:scale(0.7); }} }}</style>'
|
| 365 |
f'<div class="{cls}">'
|
| 366 |
+
f'{icon} <strong style="font-size:1.1em;">{title}</strong>'
|
| 367 |
+
f'<br><span style="opacity:0.7; font-size:0.9em;">{desc}</span>'
|
|
|
|
| 368 |
f'</div>'
|
| 369 |
)
|
| 370 |
|
|
|
|
| 446 |
)
|
| 447 |
return
|
| 448 |
|
| 449 |
+
# Always show all 4 speakers so users can reassign
|
|
|
|
| 450 |
speaker_choices = []
|
| 451 |
+
for i in range(4):
|
| 452 |
voice_name = AVAILABLE_VOICES[i] if i < len(AVAILABLE_VOICES) else None
|
| 453 |
gender = VOICE_GENDERS.get(voice_name, "")
|
| 454 |
tag = f" ({gender})" if gender else ""
|