amanetize commited on
Commit
3314beb
·
verified ·
1 Parent(s): 1715c77

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. app.py +4 -2
  2. frontend/layout.py +34 -11
  3. frontend/live.py +5 -1
app.py CHANGED
@@ -1,9 +1,11 @@
1
  import traceback
2
  import numpy as np
 
3
  from backend.orchestrator import run_pipeline
4
  from backend.presets import list_presets
5
  from frontend.layout import build_app
6
 
 
7
  def _warmup() -> None:
8
  sr = 16000
9
  dummy = np.zeros(sr, dtype=np.float32)
@@ -12,9 +14,9 @@ def _warmup() -> None:
12
  continue
13
  try:
14
  run_pipeline(preset['config'], dummy, sample_rate=sr, preset_label=preset['label'])
15
- print(f"[warmup] ready: {preset['label']}")
16
  except Exception as exc:
17
- print(f"[warmup] skipped {preset['label']}: {exc}")
18
  traceback.print_exc()
19
  print('[warmup] done')
20
  if __name__ == '__main__':
 
1
  import traceback
2
  import numpy as np
3
+ import spaces
4
  from backend.orchestrator import run_pipeline
5
  from backend.presets import list_presets
6
  from frontend.layout import build_app
7
 
8
+ @spaces.GPU
9
  def _warmup() -> None:
10
  sr = 16000
11
  dummy = np.zeros(sr, dtype=np.float32)
 
14
  continue
15
  try:
16
  run_pipeline(preset['config'], dummy, sample_rate=sr, preset_label=preset['label'])
17
+ print(f'[warmup] ready: {preset['label']}')
18
  except Exception as exc:
19
+ print(f'[warmup] skipped {preset['label']}: {exc}')
20
  traceback.print_exc()
21
  print('[warmup] done')
22
  if __name__ == '__main__':
frontend/layout.py CHANGED
@@ -24,21 +24,32 @@ def _sample_clip_choices() -> list[tuple[str, str]]:
24
  choices = []
25
  for bucket in BUCKET_ORDER:
26
  for i, entry in enumerate(by_bucket.get(bucket, []), start=1):
27
- label = f"{BUCKET_LABEL.get(bucket, bucket.title())} {i} - {entry['duration_seconds']}s"
28
  choices.append((label, entry['filename']))
29
  for bucket, entries in by_bucket.items():
30
  if bucket in BUCKET_ORDER:
31
  continue
32
  for i, entry in enumerate(entries, start=1):
33
- choices.append((f"{bucket.title()} {i} - {entry['duration_seconds']}s", entry['filename']))
34
  return choices
35
 
36
- def _preset_choices() -> list[str]:
37
- return [live.DISPLAY_NAME.get(p['label'], p['label']) for p in live.public_presets()]
38
 
39
- def _default_active() -> list[str]:
40
- choices = _preset_choices()
41
- return [choices[0]] if choices else []
 
 
 
 
 
 
 
 
 
 
 
42
 
43
  def _param_relevance(active_display_names: list[str]) -> tuple[bool, bool]:
44
  display_to_internal = {v: k for k, v in live.DISPLAY_NAME.items()}
@@ -51,8 +62,19 @@ def build_app() -> gr.Blocks:
51
  with gr.Blocks(title='Turn Detection - Live Dashboard') as demo:
52
  gr.Markdown('# Turn Detection - Live Dashboard\nSpeak, or replay a clip, and watch how different models judge whether the speaker is **done talking** vs. **still going** - plotted directly against the waveform as audio arrives.')
53
  session_state = gr.State(live.new_session_state)
 
54
  with gr.Row():
55
- active_presets = gr.CheckboxGroup(choices=_preset_choices(), value=_default_active(), label='Models to compare')
 
 
 
 
 
 
 
 
 
 
56
  with gr.Row():
57
  threshold_slider = gr.Slider(0.0, 1.0, value=live.DEFAULT_DECISION_THRESHOLD, step=0.01, label='Decision threshold - probability above this = "complete"')
58
  cadence_slider = gr.Slider(0, 5000, value=live.DEFAULT_CADENCE_MS, step=100, label='Update cadence (ms) - how often each model re-checks (slower models may still lag behind this)')
@@ -75,7 +97,8 @@ def build_app() -> gr.Blocks:
75
  chart = gr.Plot(value=live.render_chart(live.new_session_state(), [], live.DEFAULT_DECISION_THRESHOLD), label=None)
76
  with gr.Accordion('History (this session)', open=False):
77
  log_table = gr.Dataframe(headers=LOG_HEADERS, value=[], label=None)
78
- active_presets.change(lambda active: (gr.update(interactive=_param_relevance(active)[0]), gr.update(interactive=_param_relevance(active)[1])), inputs=active_presets, outputs=[acoustic_weight_slider, temperature_slider])
 
79
 
80
  def replay_clip(clip_filename, uploaded_path, active_display_names, acoustic_weight, temperature, threshold, cadence_ms, smoothing):
81
  path = uploaded_path or (str(config.SAMPLE_CLIPS_DIR / clip_filename) if clip_filename else None)
@@ -91,7 +114,7 @@ def build_app() -> gr.Blocks:
91
  state, fig, log_rows = live.process_chunk(state, (sr, chunk), active_display_names, acoustic_weight, temperature, threshold, cadence_ms, smoothing)
92
  yield (state, fig, log_rows)
93
  time.sleep(chunk_duration_s)
94
- replay_btn.click(replay_clip, inputs=[replay_clip_dropdown, replay_upload, active_presets, acoustic_weight_slider, temperature_slider, threshold_slider, cadence_slider, smoothing_slider], outputs=[session_state, chart, log_table])
95
- mic.stream(fn=live.process_chunk, inputs=[session_state, mic, active_presets, acoustic_weight_slider, temperature_slider, threshold_slider, cadence_slider, smoothing_slider], outputs=[session_state, chart, log_table], stream_every=1.0, time_limit=None)
96
  clear_btn.click(live.clear_session, inputs=session_state, outputs=[session_state, chart, log_table])
97
  return demo
 
24
  choices = []
25
  for bucket in BUCKET_ORDER:
26
  for i, entry in enumerate(by_bucket.get(bucket, []), start=1):
27
+ label = f'{BUCKET_LABEL.get(bucket, bucket.title())} {i} - {entry['duration_seconds']}s'
28
  choices.append((label, entry['filename']))
29
  for bucket, entries in by_bucket.items():
30
  if bucket in BUCKET_ORDER:
31
  continue
32
  for i, entry in enumerate(entries, start=1):
33
+ choices.append((f'{bucket.title()} {i} - {entry['duration_seconds']}s', entry['filename']))
34
  return choices
35
 
36
+ def _all_public_presets() -> list[dict]:
37
+ return live.all_public_presets()
38
 
39
+ def _preset_display_order() -> list[str]:
40
+ return [live.DISPLAY_NAME.get(p['label'], p['label']) for p in _all_public_presets()]
41
+
42
+ def _default_active_display_names() -> list[str]:
43
+ target = 'Whisper-Tiny + Mean-Pool + Linear (trained)'
44
+ name = live.DISPLAY_NAME.get(target, target)
45
+ names = _preset_display_order()
46
+ return [name] if name in names else [names[0]] if names else []
47
+
48
+ def _on_preset_change(*values: bool) -> tuple[list[str], dict, dict]:
49
+ names = _preset_display_order()
50
+ active = [n for n, v in zip(names, values) if v]
51
+ ac, se = _param_relevance(active)
52
+ return (active, gr.update(interactive=ac), gr.update(interactive=se))
53
 
54
  def _param_relevance(active_display_names: list[str]) -> tuple[bool, bool]:
55
  display_to_internal = {v: k for k, v in live.DISPLAY_NAME.items()}
 
62
  with gr.Blocks(title='Turn Detection - Live Dashboard') as demo:
63
  gr.Markdown('# Turn Detection - Live Dashboard\nSpeak, or replay a clip, and watch how different models judge whether the speaker is **done talking** vs. **still going** - plotted directly against the waveform as audio arrives.')
64
  session_state = gr.State(live.new_session_state)
65
+ active_state = gr.State(_default_active_display_names())
66
  with gr.Row():
67
+ with gr.Column(scale=1, min_width=280):
68
+ gr.Markdown('### Models to compare')
69
+ gr.Markdown('*Greyed models are not built yet (future work).*')
70
+ default_active = _default_active_display_names()
71
+ preset_checkboxes = []
72
+ for preset in _all_public_presets():
73
+ label = preset['label']
74
+ disp = live.DISPLAY_NAME.get(label, label)
75
+ available = bool(preset.get('available'))
76
+ cb_label = disp if available else f'{disp} (future)'
77
+ preset_checkboxes.append(gr.Checkbox(label=cb_label, value=disp in default_active, interactive=available))
78
  with gr.Row():
79
  threshold_slider = gr.Slider(0.0, 1.0, value=live.DEFAULT_DECISION_THRESHOLD, step=0.01, label='Decision threshold - probability above this = "complete"')
80
  cadence_slider = gr.Slider(0, 5000, value=live.DEFAULT_CADENCE_MS, step=100, label='Update cadence (ms) - how often each model re-checks (slower models may still lag behind this)')
 
97
  chart = gr.Plot(value=live.render_chart(live.new_session_state(), [], live.DEFAULT_DECISION_THRESHOLD), label=None)
98
  with gr.Accordion('History (this session)', open=False):
99
  log_table = gr.Dataframe(headers=LOG_HEADERS, value=[], label=None)
100
+ for cb in preset_checkboxes:
101
+ cb.change(_on_preset_change, inputs=preset_checkboxes, outputs=[active_state, acoustic_weight_slider, temperature_slider])
102
 
103
  def replay_clip(clip_filename, uploaded_path, active_display_names, acoustic_weight, temperature, threshold, cadence_ms, smoothing):
104
  path = uploaded_path or (str(config.SAMPLE_CLIPS_DIR / clip_filename) if clip_filename else None)
 
114
  state, fig, log_rows = live.process_chunk(state, (sr, chunk), active_display_names, acoustic_weight, temperature, threshold, cadence_ms, smoothing)
115
  yield (state, fig, log_rows)
116
  time.sleep(chunk_duration_s)
117
+ replay_btn.click(replay_clip, inputs=[replay_clip_dropdown, replay_upload, active_state, acoustic_weight_slider, temperature_slider, threshold_slider, cadence_slider, smoothing_slider], outputs=[session_state, chart, log_table])
118
+ mic.stream(fn=live.process_chunk, inputs=[session_state, mic, active_state, acoustic_weight_slider, temperature_slider, threshold_slider, cadence_slider, smoothing_slider], outputs=[session_state, chart, log_table], stream_every=1.0, time_limit=None)
119
  clear_btn.click(live.clear_session, inputs=session_state, outputs=[session_state, chart, log_table])
120
  return demo
frontend/live.py CHANGED
@@ -25,6 +25,10 @@ def public_presets() -> list[dict]:
25
  by_label = {p['label']: p for p in list_presets()}
26
  return [by_label[label] for label in PUBLIC_PRESET_ORDER if label in by_label and by_label[label]['available']]
27
 
 
 
 
 
28
  def uses_acoustic_weight(label: str) -> bool:
29
  by_label = {p['label']: p for p in list_presets()}
30
  preset = by_label.get(label)
@@ -123,7 +127,7 @@ def render_chart(state: dict[str, Any], active_labels: list[str], threshold: flo
123
  has_probability = any((e['probability'] is not None for e in history))
124
  if not has_probability:
125
  last = history[-1]
126
- verdict_only_lines.append(f"{display_name}: {(last['decision'] or '-').upper()}")
127
  continue
128
  xs = [e['buffer_seconds'] for e in history if e['probability'] is not None]
129
  ys_raw = [e['probability'] for e in history if e['probability'] is not None]
 
25
  by_label = {p['label']: p for p in list_presets()}
26
  return [by_label[label] for label in PUBLIC_PRESET_ORDER if label in by_label and by_label[label]['available']]
27
 
28
+ def all_public_presets() -> list[dict]:
29
+ by_label = {p['label']: p for p in list_presets()}
30
+ return [by_label[label] for label in PUBLIC_PRESET_ORDER if label in by_label]
31
+
32
  def uses_acoustic_weight(label: str) -> bool:
33
  by_label = {p['label']: p for p in list_presets()}
34
  preset = by_label.get(label)
 
127
  has_probability = any((e['probability'] is not None for e in history))
128
  if not has_probability:
129
  last = history[-1]
130
+ verdict_only_lines.append(f'{display_name}: {(last['decision'] or '-').upper()}')
131
  continue
132
  xs = [e['buffer_seconds'] for e in history if e['probability'] is not None]
133
  ys_raw = [e['probability'] for e in history if e['probability'] is not None]