jayaspjacob Claude Opus 4.8 (1M context) commited on
Commit
32a688b
·
1 Parent(s): 165b02d

Sync the header cast chip with the picked voices

Browse files

The top-right "Nova × Atlas" chip was static. Make it reflect the actual
voice picks: the header is rebuilt from the selected voices (with matching
avatar colors) whenever a voice dropdown or the speaker-count slider
changes, across all three page headers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +41 -5
app.py CHANGED
@@ -78,6 +78,7 @@ def _sample_path(voice_id):
78
 
79
  # Selectable library voices (those with a bundled sample), by display name.
80
  _VOICE_NAME_TO_ID = {name: vid for vid, name, *_ in VOICE_LIBRARY if vid}
 
81
  LIBRARY_VOICE_NAMES = list(_VOICE_NAME_TO_ID.keys())
82
  _VOICE_DEFAULTS = ["Nova", "Atlas", "Echo", "Sage"]
83
 
@@ -615,13 +616,20 @@ LOGO_HTML = """
615
  """
616
 
617
 
618
- def _header(title: str, sub: str) -> str:
 
 
 
 
 
 
 
619
  return f"""
620
  <div class='pf-header'>
621
  <div><h1>{title}</h1><div class='sub'>{sub}</div></div>
622
  <div class='pf-status'>
623
  <span class='pf-pill'><span class='pf-dot'></span> All systems live</span>
624
- <span class='pf-voicepill'>{_avatar('N',0,24)}{_avatar('A',1,24)}&nbsp; Nova × Atlas</span>
625
  </div>
626
  </div>
627
  """
@@ -654,7 +662,10 @@ def build_ui():
654
  with gr.Column(elem_id="pf-main"):
655
  # ===================== CREATE PAGE =====================
656
  with gr.Column(visible=True) as page_create:
657
- gr.HTML(_header("Create", "Type a topic — Podify writes &amp; voices it"))
 
 
 
658
 
659
  # ---------- STEP 1: topic ----------
660
  with gr.Column(visible=True) as step1:
@@ -759,7 +770,10 @@ def build_ui():
759
 
760
  # ===================== VOICES PAGE =====================
761
  with gr.Column(visible=False) as page_voices:
762
- gr.HTML(_header("Voices", "Browse the library or clone your own"))
 
 
 
763
  with gr.Row():
764
  with gr.Column(scale=2, elem_classes=["pf-card"]):
765
  gr.HTML("<div class='pf-eyebrow'>VOICE LAB</div>"
@@ -803,7 +817,10 @@ def build_ui():
803
 
804
  # ===================== LIBRARY PAGE =====================
805
  with gr.Column(visible=False) as page_library:
806
- gr.HTML(_header("Library", "Every episode you've produced"))
 
 
 
807
  lib_header = gr.HTML(
808
  "<div class='pf-step-h'><span class='t'>▥ Your episodes</span>"
809
  "<span class='h'>0</span></div>"
@@ -849,6 +866,25 @@ def build_ui():
849
  inputs=[num_speakers], outputs=voice_pickers,
850
  )
851
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
852
  setup_outputs = [lines_state, speakers_state]
853
  step_views = [step1, step2, step3, step_loading]
854
 
 
78
 
79
  # Selectable library voices (those with a bundled sample), by display name.
80
  _VOICE_NAME_TO_ID = {name: vid for vid, name, *_ in VOICE_LIBRARY if vid}
81
+ _VOICE_AVATAR_IDX = {name: idx for vid, name, meta, idx, chips in VOICE_LIBRARY if vid}
82
  LIBRARY_VOICE_NAMES = list(_VOICE_NAME_TO_ID.keys())
83
  _VOICE_DEFAULTS = ["Nova", "Atlas", "Echo", "Sage"]
84
 
 
616
  """
617
 
618
 
619
+ def _voice_chip(voices=None) -> str:
620
+ names = [n for n in (voices or []) if n] or ["Nova", "Atlas"]
621
+ names = names[:MAX_SPEAKERS]
622
+ avatars = "".join(_avatar(n, _VOICE_AVATAR_IDX.get(n, i), 24) for i, n in enumerate(names))
623
+ return f"<span class='pf-voicepill'>{avatars}&nbsp; {html.escape(' × '.join(names))}</span>"
624
+
625
+
626
+ def _header(title: str, sub: str, voices=None) -> str:
627
  return f"""
628
  <div class='pf-header'>
629
  <div><h1>{title}</h1><div class='sub'>{sub}</div></div>
630
  <div class='pf-status'>
631
  <span class='pf-pill'><span class='pf-dot'></span> All systems live</span>
632
+ {_voice_chip(voices)}
633
  </div>
634
  </div>
635
  """
 
662
  with gr.Column(elem_id="pf-main"):
663
  # ===================== CREATE PAGE =====================
664
  with gr.Column(visible=True) as page_create:
665
+ create_header = gr.HTML(
666
+ _header("Create", "Type a topic — Podify writes &amp; voices it",
667
+ voices=_VOICE_DEFAULTS[:2])
668
+ )
669
 
670
  # ---------- STEP 1: topic ----------
671
  with gr.Column(visible=True) as step1:
 
770
 
771
  # ===================== VOICES PAGE =====================
772
  with gr.Column(visible=False) as page_voices:
773
+ voices_header = gr.HTML(
774
+ _header("Voices", "Browse the library or clone your own",
775
+ voices=_VOICE_DEFAULTS[:2])
776
+ )
777
  with gr.Row():
778
  with gr.Column(scale=2, elem_classes=["pf-card"]):
779
  gr.HTML("<div class='pf-eyebrow'>VOICE LAB</div>"
 
817
 
818
  # ===================== LIBRARY PAGE =====================
819
  with gr.Column(visible=False) as page_library:
820
+ library_header = gr.HTML(
821
+ _header("Library", "Every episode you've produced",
822
+ voices=_VOICE_DEFAULTS[:2])
823
+ )
824
  lib_header = gr.HTML(
825
  "<div class='pf-step-h'><span class='t'>▥ Your episodes</span>"
826
  "<span class='h'>0</span></div>"
 
866
  inputs=[num_speakers], outputs=voice_pickers,
867
  )
868
 
869
+ # keep the header cast chip in sync with the picked voices (all pages)
870
+ def _refresh_headers(n, *names):
871
+ sel = [names[i] for i in range(int(n)) if i < len(names) and names[i]]
872
+ return (
873
+ gr.update(value=_header("Create",
874
+ "Type a topic — Podify writes &amp; voices it", sel)),
875
+ gr.update(value=_header("Voices",
876
+ "Browse the library or clone your own", sel)),
877
+ gr.update(value=_header("Library",
878
+ "Every episode you've produced", sel)),
879
+ )
880
+
881
+ _header_outputs = [create_header, voices_header, library_header]
882
+ num_speakers.change(_refresh_headers, inputs=[num_speakers] + voice_pickers,
883
+ outputs=_header_outputs)
884
+ for _vp in voice_pickers:
885
+ _vp.change(_refresh_headers, inputs=[num_speakers] + voice_pickers,
886
+ outputs=_header_outputs)
887
+
888
  setup_outputs = [lines_state, speakers_state]
889
  step_views = [step1, step2, step3, step_loading]
890