Zachary Greathouse commited on
Commit
9f24752
·
unverified ·
2 Parent(s): d5a40dd 7c16ebc

Merge pull request #6 from HumeAI/zg/updates-for-launch

Browse files
Files changed (3) hide show
  1. src/app.py +46 -14
  2. src/assets/styles.css +65 -1
  3. src/constants.py +2 -2
src/app.py CHANGED
@@ -87,7 +87,7 @@ class App:
87
  character_description: str,
88
  text: str,
89
  generated_text_state: str,
90
- ) -> Tuple[gr.Audio, gr.Audio, OptionMap, bool, str, str]:
91
  """
92
  Synthesizes two text-to-speech outputs, updates UI state components, and returns additional TTS metadata.
93
 
@@ -113,6 +113,7 @@ class App:
113
  - bool: Flag indicating whether the text was modified.
114
  - str: The original text that was synthesized.
115
  - str: The original character description.
 
116
 
117
  Raises:
118
  gr.Error: If any API or unexpected errors occur during the TTS synthesis process.
@@ -147,12 +148,13 @@ class App:
147
  options_map: OptionMap = create_shuffled_tts_options(option_a, option_b)
148
 
149
  return (
150
- gr.update(value=options_map["option_a"]["audio_file_path"], visible=True, autoplay=True),
151
- gr.update(value=options_map["option_b"]["audio_file_path"], visible=True),
152
  options_map,
153
  text_modified,
154
  text,
155
  character_description,
 
156
  )
157
  except ElevenLabsError as ee:
158
  logger.error(f"ElevenLabsError while synthesizing speech from text: {ee!s}")
@@ -287,7 +289,7 @@ class App:
287
  gr.update(interactive=False), # disable Select B Button
288
  )
289
 
290
- def _enable_ui(self) -> Tuple[
291
  gr.Button,
292
  gr.Dropdown,
293
  gr.Textbox,
@@ -307,8 +309,8 @@ class App:
307
  gr.update(interactive=True), # enable Generate Text button
308
  gr.update(interactive=True), # enable Input Text input
309
  gr.update(interactive=True), # enable Synthesize Speech Button
310
- gr.update(interactive=True), # enable Select A Button
311
- gr.update(interactive=True), # enable Select B Button
312
  )
313
 
314
  def _reset_voting_ui(self) -> Tuple[
@@ -319,7 +321,8 @@ class App:
319
  gr.Textbox,
320
  gr.Textbox,
321
  OptionMap,
322
- bool
 
323
  ]:
324
  """
325
  Resets voting UI state and clear audio players
@@ -337,6 +340,7 @@ class App:
337
  gr.update(visible=False, elem_classes=[]), # hide vote result B and clear custom styling
338
  default_option_map, # Reset option_map_state as a default OptionMap
339
  False, # Reset vote_submitted_state
 
340
  )
341
 
342
  def _build_heading_section(self) -> Tuple[gr.HTML, gr.Button, gr.HTML]:
@@ -345,7 +349,29 @@ class App:
345
  """
346
  with gr.Row():
347
  with gr.Column(scale=5):
348
- title = gr.HTML("<h1>Expressive TTS Arena</h1>")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
  randomize_all_button = gr.Button("🎲 Randomize All", variant="primary", scale=1)
350
  instructions = gr.HTML(
351
  """
@@ -371,7 +397,7 @@ class App:
371
  </ol>
372
  """
373
  )
374
- return (title, randomize_all_button, instructions)
375
 
376
  def _build_input_section(self) -> Tuple[gr.Dropdown, gr.Textbox, gr.Button, gr.Textbox, gr.Button]:
377
  """
@@ -474,7 +500,7 @@ class App:
474
  # --- UI components ---
475
 
476
  (
477
- title,
478
  randomize_all_button,
479
  instructions,
480
  ) = self._build_heading_section()
@@ -508,6 +534,8 @@ class App:
508
  option_map_state = gr.State({}) # OptionMap state as a dictionary
509
  # Track whether the user has voted for an option
510
  vote_submitted_state = gr.State(False)
 
 
511
 
512
  # --- Register event handlers ---
513
 
@@ -543,6 +571,7 @@ class App:
543
  vote_result_b,
544
  option_map_state,
545
  vote_submitted_state,
 
546
  ],
547
  ).then(
548
  fn=self._randomize_character_description,
@@ -562,10 +591,11 @@ class App:
562
  text_modified_state,
563
  text_state,
564
  character_description_state,
 
565
  ],
566
  ).then(
567
  fn=self._enable_ui,
568
- inputs=[],
569
  outputs=[
570
  randomize_all_button,
571
  sample_character_description_dropdown,
@@ -606,7 +636,7 @@ class App:
606
  outputs=[text_input, generated_text_state],
607
  ).then(
608
  fn=self._enable_ui,
609
- inputs=[],
610
  outputs=[
611
  randomize_all_button,
612
  sample_character_description_dropdown,
@@ -642,7 +672,7 @@ class App:
642
  outputs=[text_input, generated_text_state],
643
  ).then(
644
  fn=self._enable_ui,
645
- inputs=[],
646
  outputs=[
647
  randomize_all_button,
648
  sample_character_description_dropdown,
@@ -685,6 +715,7 @@ class App:
685
  vote_result_b,
686
  option_map_state,
687
  vote_submitted_state,
 
688
  ],
689
  ).then(
690
  fn=self._synthesize_speech,
@@ -696,10 +727,11 @@ class App:
696
  text_modified_state,
697
  text_state,
698
  character_description_state,
 
699
  ],
700
  ).then(
701
  fn=self._enable_ui,
702
- inputs=[],
703
  outputs=[
704
  randomize_all_button,
705
  sample_character_description_dropdown,
 
87
  character_description: str,
88
  text: str,
89
  generated_text_state: str,
90
+ ) -> Tuple[gr.Audio, gr.Audio, OptionMap, bool, str, str, bool]:
91
  """
92
  Synthesizes two text-to-speech outputs, updates UI state components, and returns additional TTS metadata.
93
 
 
113
  - bool: Flag indicating whether the text was modified.
114
  - str: The original text that was synthesized.
115
  - str: The original character description.
116
+ - bool: Flag indicating whether the vote buttons should be enabled
117
 
118
  Raises:
119
  gr.Error: If any API or unexpected errors occur during the TTS synthesis process.
 
148
  options_map: OptionMap = create_shuffled_tts_options(option_a, option_b)
149
 
150
  return (
151
+ gr.update(value=options_map["option_a"]["audio_file_path"], autoplay=True),
152
+ gr.update(value=options_map["option_b"]["audio_file_path"]),
153
  options_map,
154
  text_modified,
155
  text,
156
  character_description,
157
+ True,
158
  )
159
  except ElevenLabsError as ee:
160
  logger.error(f"ElevenLabsError while synthesizing speech from text: {ee!s}")
 
289
  gr.update(interactive=False), # disable Select B Button
290
  )
291
 
292
+ def _enable_ui(self, should_enable_vote_buttons) -> Tuple[
293
  gr.Button,
294
  gr.Dropdown,
295
  gr.Textbox,
 
309
  gr.update(interactive=True), # enable Generate Text button
310
  gr.update(interactive=True), # enable Input Text input
311
  gr.update(interactive=True), # enable Synthesize Speech Button
312
+ gr.update(interactive=should_enable_vote_buttons), # enable Select A Button
313
+ gr.update(interactive=should_enable_vote_buttons), # enable Select B Button
314
  )
315
 
316
  def _reset_voting_ui(self) -> Tuple[
 
321
  gr.Textbox,
322
  gr.Textbox,
323
  OptionMap,
324
+ bool,
325
+ bool,
326
  ]:
327
  """
328
  Resets voting UI state and clear audio players
 
340
  gr.update(visible=False, elem_classes=[]), # hide vote result B and clear custom styling
341
  default_option_map, # Reset option_map_state as a default OptionMap
342
  False, # Reset vote_submitted_state
343
+ False, # Reset should_enable_vote_buttons state
344
  )
345
 
346
  def _build_heading_section(self) -> Tuple[gr.HTML, gr.Button, gr.HTML]:
 
349
  """
350
  with gr.Row():
351
  with gr.Column(scale=5):
352
+ title_with_social_links = gr.HTML(
353
+ """
354
+ <div class="title-container">
355
+ <h1>Expressive TTS Arena</h1>
356
+ <div class="social-links">
357
+ <a
358
+ href="https://discord.com/invite/humeai"
359
+ target="_blank"
360
+ id="discord-link"
361
+ title="Join our Discord"
362
+ aria-label="Join our Discord server"
363
+ ></a>
364
+ <a
365
+ href="https://github.com/HumeAI/expressive-tts-arena"
366
+ target="_blank"
367
+ id="github-link"
368
+ title="View on GitHub"
369
+ aria-label="View project on GitHub"
370
+ ></a>
371
+ </div>
372
+ </div>
373
+ """
374
+ )
375
  randomize_all_button = gr.Button("🎲 Randomize All", variant="primary", scale=1)
376
  instructions = gr.HTML(
377
  """
 
397
  </ol>
398
  """
399
  )
400
+ return (title_with_social_links, randomize_all_button, instructions)
401
 
402
  def _build_input_section(self) -> Tuple[gr.Dropdown, gr.Textbox, gr.Button, gr.Textbox, gr.Button]:
403
  """
 
500
  # --- UI components ---
501
 
502
  (
503
+ title_with_social_links,
504
  randomize_all_button,
505
  instructions,
506
  ) = self._build_heading_section()
 
534
  option_map_state = gr.State({}) # OptionMap state as a dictionary
535
  # Track whether the user has voted for an option
536
  vote_submitted_state = gr.State(False)
537
+ # Track whether the vote buttons should be enabled
538
+ should_enable_vote_buttons = gr.State(False)
539
 
540
  # --- Register event handlers ---
541
 
 
571
  vote_result_b,
572
  option_map_state,
573
  vote_submitted_state,
574
+ should_enable_vote_buttons,
575
  ],
576
  ).then(
577
  fn=self._randomize_character_description,
 
591
  text_modified_state,
592
  text_state,
593
  character_description_state,
594
+ should_enable_vote_buttons,
595
  ],
596
  ).then(
597
  fn=self._enable_ui,
598
+ inputs=[should_enable_vote_buttons],
599
  outputs=[
600
  randomize_all_button,
601
  sample_character_description_dropdown,
 
636
  outputs=[text_input, generated_text_state],
637
  ).then(
638
  fn=self._enable_ui,
639
+ inputs=[should_enable_vote_buttons],
640
  outputs=[
641
  randomize_all_button,
642
  sample_character_description_dropdown,
 
672
  outputs=[text_input, generated_text_state],
673
  ).then(
674
  fn=self._enable_ui,
675
+ inputs=[should_enable_vote_buttons],
676
  outputs=[
677
  randomize_all_button,
678
  sample_character_description_dropdown,
 
715
  vote_result_b,
716
  option_map_state,
717
  vote_submitted_state,
718
+ should_enable_vote_buttons,
719
  ],
720
  ).then(
721
  fn=self._synthesize_speech,
 
727
  text_modified_state,
728
  text_state,
729
  character_description_state,
730
+ should_enable_vote_buttons,
731
  ],
732
  ).then(
733
  fn=self._enable_ui,
734
+ inputs=[should_enable_vote_buttons],
735
  outputs=[
736
  randomize_all_button,
737
  sample_character_description_dropdown,
src/assets/styles.css CHANGED
@@ -1,14 +1,78 @@
1
- /* Remove Gradio footer from UI */
2
  footer.svelte-1byz9vf {
3
  display: none !important;
4
  }
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  #vote-result-a textarea,
7
  #vote-result-b textarea {
8
  font-size: 16px !important;
9
  font-weight: bold !important;
10
  }
11
 
 
12
  #vote-result-a.winner textarea,
13
  #vote-result-b.winner textarea {
14
  background: #EA580C;
 
1
+ /* Remove Gradio footer */
2
  footer.svelte-1byz9vf {
3
  display: none !important;
4
  }
5
 
6
+ /* Remove unnecessary padding from HTML containers */
7
+ .html-container.svelte-phx28p.padding {
8
+ padding: 0px !important;
9
+ }
10
+
11
+ /* Title container styling */
12
+ .title-container {
13
+ display: flex;
14
+ align-items: center;
15
+ height: 40px !important;
16
+ overflow: visible !important;
17
+ }
18
+
19
+ .title-container h1 {
20
+ margin: 0 !important;
21
+ margin-right: auto !important;
22
+ }
23
+
24
+ /* Social links container */
25
+ .social-links {
26
+ display: flex;
27
+ align-items: center;
28
+ gap: 8px;
29
+ margin-right: 8px;
30
+ overflow: visible !important;
31
+ }
32
+
33
+ /* Social media icons common styles */
34
+ #github-link,
35
+ #discord-link {
36
+ display: inline-block !important;
37
+ width: 30px !important;
38
+ height: 30px !important;
39
+ background-size: cover !important;
40
+ background-position: center !important;
41
+ background-repeat: no-repeat !important;
42
+ transition: transform 0.2s ease-in-out !important;
43
+ border-radius: 50% !important;
44
+ flex-shrink: 0 !important;
45
+ }
46
+
47
+ /* Hover effect for social media icons */
48
+ #github-link:hover,
49
+ #discord-link:hover {
50
+ transform: scale(1.1);
51
+ }
52
+
53
+ /* Discord icon specific styling */
54
+ #discord-link {
55
+ background-image: url(
56
+ 'https://assets-global.website-files.com/6257adef93867e50d84d30e2/636e0a6a49cf127bf92de1e2_icon_clyde_blurple_RGB.png'
57
+ ) !important;
58
+ background-size: 90% !important;
59
+ }
60
+
61
+ /* GitHub icon specific styling */
62
+ #github-link {
63
+ background-image: url(
64
+ 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png'
65
+ ) !important;
66
+ }
67
+
68
+ /* Vote result styling */
69
  #vote-result-a textarea,
70
  #vote-result-b textarea {
71
  font-size: 16px !important;
72
  font-weight: bold !important;
73
  }
74
 
75
+ /* Winner styling */
76
  #vote-result-a.winner textarea,
77
  #vote-result-b.winner textarea {
78
  background: #EA580C;
src/constants.py CHANGED
@@ -47,8 +47,8 @@ SAMPLE_CHARACTER_DESCRIPTIONS: dict = {
47
  "auditory experience."
48
  ),
49
  "🎬 Noir Detective": (
50
- "A film portrayal of a 1940s private investigator narrating with a low, gravelly voice and deliberate pacing. "
51
- "Speaks with a cynical, world-weary tone that drops lower when delivering key observations."
52
  ),
53
  "🕯️ Victorian Ghost Storyteller": (
54
  "The speaker is a Victorian-era raconteur speaking with a refined British accent and formal, precise diction. "
 
47
  "auditory experience."
48
  ),
49
  "🎬 Noir Detective": (
50
+ "A noir film portrayal of a 1940s private investigator narrating with a low, gravelly voice and deliberate "
51
+ "pacing. Speaks with a cynical, world-weary tone that drops lower when delivering key observations."
52
  ),
53
  "🕯️ Victorian Ghost Storyteller": (
54
  "The speaker is a Victorian-era raconteur speaking with a refined British accent and formal, precise diction. "