zach commited on
Commit
84c63d1
·
1 Parent(s): db2bd16

Update option state to include the voice along with the provider, and update reporting of winner to include the voice name.

Browse files
Files changed (1) hide show
  1. src/app.py +52 -26
src/app.py CHANGED
@@ -41,6 +41,7 @@ from src.integrations import (
41
  text_to_speech_with_hume,
42
  )
43
  from src.theme import CustomTheme
 
44
  from src.utils import truncate_text, validate_prompt_length
45
 
46
 
@@ -124,10 +125,16 @@ def text_to_speech(prompt: str, text: str, generated_text_state: str) -> Tuple[g
124
  voice_b, audio_b = future_audio_b.result()
125
 
126
  logger.info(f'TTS generated: {provider_a}={len(audio_a)} bytes, {provider_b}={len(audio_b)} bytes')
127
- options = [(audio_a, provider_a), (audio_b, provider_b)]
 
 
 
128
  random.shuffle(options)
129
  option_a_audio, option_b_audio = options[0][0], options[1][0]
130
- options_map = { OPTION_A: options[0][1], OPTION_B: options[1][1] }
 
 
 
131
 
132
  return (
133
  gr.update(value=option_a_audio, visible=True, autoplay=True),
@@ -146,38 +153,57 @@ def text_to_speech(prompt: str, text: str, generated_text_state: str) -> Tuple[g
146
  raise gr.Error('An unexpected error ocurred. Please try again later.')
147
 
148
 
149
- def vote(vote_submitted: bool, option_mapping: dict, selected_button: str) -> Tuple[bool, gr.update, gr.update]:
150
  """
151
  Handles user voting.
152
 
153
  Args:
154
- vote_submitted (bool): True if a vote was already submitted
155
- option_mapping (dict): Maps option labels to provider names
156
- selected_button (str): The button clicked
 
 
 
 
 
157
 
158
  Returns:
159
  A tuple of:
160
- - True if the vote was accepted
161
- - Update for the selected vote button
162
- - Update for the unselected vote button
 
163
  """
164
- if not option_mapping or vote_submitted:
165
- return gr.skip(), gr.skip(), gr.skip()
166
 
167
- is_option_a = selected_button == VOTE_FOR_OPTION_A
168
- selected_option, other_option = (OPTION_A, OPTION_B) if is_option_a else (OPTION_B, OPTION_A)
169
- selected_provider = option_mapping.get(selected_option, UNKNOWN_PROVIDER)
170
- other_provider = option_mapping.get(other_option, UNKNOWN_PROVIDER)
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
  return (
173
  True,
174
- gr.update(value=f'{selected_provider} {TROPHY_EMOJI}', variant='primary', interactive=False) if is_option_a
175
- else gr.update(value=other_provider, variant='secondary', interactive=False),
176
- gr.update(value=other_provider, variant='secondary', interactive=False) if is_option_a
177
- else gr.update(value=f'{selected_provider} {TROPHY_EMOJI}', variant='primary', interactive=False),
178
  gr.update(interactive=True)
179
  )
180
 
 
181
  def reset_ui() -> Tuple[gr.update, gr.update, gr.update, gr.update, None, None, bool]:
182
  """
183
  Resets UI state before generating new text.
@@ -188,7 +214,7 @@ def reset_ui() -> Tuple[gr.update, gr.update, gr.update, gr.update, None, None,
188
  - option_b_audio_player (clear audio)
189
  - vote_button_a (disable and reset button text)
190
  - vote_button_a (disable and reset button text)
191
- - option_mapping_state (reset option map state)
192
  - option_b_audio_state (reset option B audio state)
193
  - vote_submitted_state (reset submitted vote state)
194
  """
@@ -297,8 +323,8 @@ def build_gradio_interface() -> gr.Blocks:
297
  # UI state components
298
  generated_text_state = gr.State('') # Track generated text state
299
  option_b_audio_state = gr.State() # Track generated audio for option B for playing automatically after option 1 audio finishes
300
- option_mapping_state = gr.State() # Track option map (option A and option B are randomized)
301
- vote_submitted_state = gr.State(False) # Track whether the user has voted on an option
302
 
303
  # --- Register event handlers ---
304
 
@@ -344,7 +370,7 @@ def build_gradio_interface() -> gr.Blocks:
344
  option_b_audio_player,
345
  vote_button_a,
346
  vote_button_b,
347
- option_mapping_state,
348
  option_b_audio_state,
349
  vote_submitted_state,
350
  ],
@@ -354,7 +380,7 @@ def build_gradio_interface() -> gr.Blocks:
354
  outputs=[
355
  option_a_audio_player,
356
  option_b_audio_player,
357
- option_mapping_state,
358
  option_b_audio_state,
359
  ],
360
  ).then(
@@ -370,12 +396,12 @@ def build_gradio_interface() -> gr.Blocks:
370
  # Vote button click event handlers
371
  vote_button_a.click(
372
  fn=vote,
373
- inputs=[vote_submitted_state, option_mapping_state, vote_button_a],
374
  outputs=[vote_submitted_state, vote_button_a, vote_button_b, synthesize_speech_button],
375
  )
376
  vote_button_b.click(
377
  fn=vote,
378
- inputs=[vote_submitted_state, option_mapping_state, vote_button_b],
379
  outputs=[vote_submitted_state, vote_button_a, vote_button_b, synthesize_speech_button],
380
  )
381
 
 
41
  text_to_speech_with_hume,
42
  )
43
  from src.theme import CustomTheme
44
+ from src.types import OptionMap
45
  from src.utils import truncate_text, validate_prompt_length
46
 
47
 
 
125
  voice_b, audio_b = future_audio_b.result()
126
 
127
  logger.info(f'TTS generated: {provider_a}={len(audio_a)} bytes, {provider_b}={len(audio_b)} bytes')
128
+ options = [
129
+ (audio_a, {"provider": provider_a, "voice": voice_a}),
130
+ (audio_b, {"provider": provider_b, "voice": voice_b})
131
+ ]
132
  random.shuffle(options)
133
  option_a_audio, option_b_audio = options[0][0], options[1][0]
134
+ options_map: OptionMap = {
135
+ OPTION_A: options[0][1],
136
+ OPTION_B: options[1][1]
137
+ }
138
 
139
  return (
140
  gr.update(value=option_a_audio, visible=True, autoplay=True),
 
153
  raise gr.Error('An unexpected error ocurred. Please try again later.')
154
 
155
 
156
+ def vote(vote_submitted: bool, option_map: OptionMap, selected_button: str) -> Tuple[bool, gr.update, gr.update, gr.update]:
157
  """
158
  Handles user voting.
159
 
160
  Args:
161
+ vote_submitted (bool): True if a vote was already submitted.
162
+ option_map (OptionMap): A dictionary mapping option labels to their details.
163
+ Expected structure:
164
+ {
165
+ 'Option A': '{"provider": "Hume AI", "voice": "<voice_name>"}',
166
+ 'Option B': '{"provider": "ElevenLabs", "voice": "<voice_name>"}'
167
+ }
168
+ selected_button (str): The button that was clicked.
169
 
170
  Returns:
171
  A tuple of:
172
+ - A boolean indicating if the vote was accepted.
173
+ - An update for the selected vote button (showing provider, voice, and trophy emoji).
174
+ - An update for the unselected vote button (showing provider and voice).
175
+ - An update for enabling vote interactions.
176
  """
177
+ if not option_map or vote_submitted:
178
+ return gr.skip(), gr.skip(), gr.skip(), gr.skip()
179
 
180
+ option_a_selected = selected_button == VOTE_FOR_OPTION_A
181
+ selected_option, other_option = (OPTION_A, OPTION_B) if option_a_selected else (OPTION_B, OPTION_A)
182
+
183
+ # Parse selected option details from options map
184
+ selected_details = option_map.get(selected_option, {})
185
+ selected_provider = selected_details.get('provider', UNKNOWN_PROVIDER)
186
+ selected_voice = selected_details.get('voice', '')
187
+
188
+ # Parse other option details from options map
189
+ other_details = option_map.get(other_option, {})
190
+ other_provider = other_details.get('provider', UNKNOWN_PROVIDER)
191
+ other_voice = other_details.get('voice', '')
192
+
193
+ # Build button labels, displaying the provider and voice name, appending the trophy emoji to the selected option.
194
+ selected_label = f"{selected_provider} | Voice: {selected_voice} {TROPHY_EMOJI}"
195
+ other_label = f"{other_provider} | Voice: {other_voice}"
196
 
197
  return (
198
  True,
199
+ gr.update(value=selected_label, variant='primary', interactive=False) if option_a_selected
200
+ else gr.update(value=other_label, variant='secondary', interactive=False),
201
+ gr.update(value=other_label, variant='secondary', interactive=False) if option_a_selected
202
+ else gr.update(value=selected_label, variant='primary', interactive=False),
203
  gr.update(interactive=True)
204
  )
205
 
206
+
207
  def reset_ui() -> Tuple[gr.update, gr.update, gr.update, gr.update, None, None, bool]:
208
  """
209
  Resets UI state before generating new text.
 
214
  - option_b_audio_player (clear audio)
215
  - vote_button_a (disable and reset button text)
216
  - vote_button_a (disable and reset button text)
217
+ - option_map_state (reset option map state)
218
  - option_b_audio_state (reset option B audio state)
219
  - vote_submitted_state (reset submitted vote state)
220
  """
 
323
  # UI state components
324
  generated_text_state = gr.State('') # Track generated text state
325
  option_b_audio_state = gr.State() # Track generated audio for option B for playing automatically after option 1 audio finishes
326
+ option_map_state = gr.State() # Track option map (option A and option B are randomized)
327
+ vote_submitted_state = gr.State(False) # Track whether the user has voted for an option
328
 
329
  # --- Register event handlers ---
330
 
 
370
  option_b_audio_player,
371
  vote_button_a,
372
  vote_button_b,
373
+ option_map_state,
374
  option_b_audio_state,
375
  vote_submitted_state,
376
  ],
 
380
  outputs=[
381
  option_a_audio_player,
382
  option_b_audio_player,
383
+ option_map_state,
384
  option_b_audio_state,
385
  ],
386
  ).then(
 
396
  # Vote button click event handlers
397
  vote_button_a.click(
398
  fn=vote,
399
+ inputs=[vote_submitted_state, option_map_state, vote_button_a],
400
  outputs=[vote_submitted_state, vote_button_a, vote_button_b, synthesize_speech_button],
401
  )
402
  vote_button_b.click(
403
  fn=vote,
404
+ inputs=[vote_submitted_state, option_map_state, vote_button_b],
405
  outputs=[vote_submitted_state, vote_button_a, vote_button_b, synthesize_speech_button],
406
  )
407