ACloudCenter commited on
Commit
d6f628c
·
1 Parent(s): 286b666

Show all 4 speakers in turn dropdowns, fix status animation

Browse files
Files changed (1) hide show
  1. app.py +39 -46
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
- var(--background-fill-secondary) 0%,
287
- rgba(99, 102, 241, 0.12) 50%,
288
- var(--background-fill-secondary) 100%
 
 
289
  );
290
- background-size: 200% 100%;
291
- animation: shimmer 2s ease-in-out infinite, border-rotate 3s linear infinite;
292
- border: 2px solid transparent;
293
- background-clip: padding-box;
294
- overflow: hidden;
295
  }
296
- .gen-status-active::before {
297
- content: '';
298
- position: absolute;
299
- inset: -2px;
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 spin {
321
- to { transform: rotate(360deg); }
 
 
 
 
 
 
 
 
 
 
 
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
- icon = "●"
366
- color = "#6366f1"
 
 
 
 
367
  cls = "gen-status gen-status-active"
368
 
369
  return (
 
370
  f'<div class="{cls}">'
371
- f'<span style="color:{color}; font-size:1.3em; vertical-align:middle;">{icon}</span> '
372
- f'<strong>{title}</strong>'
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
- n_speakers = max(t["speaker"] for t in turns) if turns else 1
456
- # Build speaker labels with voice gender if assigned
457
  speaker_choices = []
458
- for i in range(max(n_speakers, 1)):
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;">&#10003;</span>'
 
350
  cls = "gen-status"
351
  elif stage == "error":
352
+ icon = '<span style="color:#ef4444; font-size:1.4em; vertical-align:middle;">&#10007;</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 ""