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 filesThe 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>
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 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(
|
|
|
|
|
|
|
|
|
|
| 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(
|
|
|
|
|
|
|
|
|
|
| 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(
|
|
|
|
|
|
|
|
|
|
| 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} {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 & 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 & 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 |
|