duongthienz commited on
Commit
8eede89
·
verified ·
1 Parent(s): e442c0e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -24
app.py CHANGED
@@ -57,48 +57,70 @@ def apply_speaker_renames_to_df(df, fileIndex, column="task"):
57
  def extract_speaker_clip(audio_path, annotation, speaker, clip_duration=5):
58
  """
59
  Extract a clip of up to clip_duration seconds for the given speaker.
60
- Prefers the first segment >= clip_duration seconds; falls back to the longest segment.
61
- Returns bytes (WAV) or None on failure.
62
  """
 
63
  try:
64
- import io
65
- # Collect all segments for this speaker
66
- speaker_segments = [
67
- (seg.start, seg.end)
68
- for seg, _, label in annotation.itertracks(yield_label=True)
69
- if label == speaker
70
- ]
 
 
71
  if not speaker_segments:
72
- return None
73
 
74
- # Prefer first segment long enough for a full clip
75
  chosen_start, chosen_end = None, None
76
  for start, end in speaker_segments:
77
  if (end - start) >= clip_duration:
78
  chosen_start, chosen_end = start, start + clip_duration
79
  break
80
-
81
- # Fall back: use the longest segment available
82
  if chosen_start is None:
83
  longest = max(speaker_segments, key=lambda s: s[1] - s[0])
84
  chosen_start, chosen_end = longest
85
 
86
- # Load audio and slice the clip
87
- waveform, sample_rate = torchaudio.load(audio_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  start_frame = int(chosen_start * sample_rate)
89
  end_frame = min(int(chosen_end * sample_rate), waveform.shape[-1])
90
  clip = waveform[:, start_frame:end_frame]
91
 
92
- # Encode as WAV in memory
93
  buffer = io.BytesIO()
94
  torchaudio.save(buffer, clip, sample_rate, format="wav")
95
  buffer.seek(0)
96
- return buffer.read()
 
97
  except Exception as e:
98
- import traceback
99
- print(f"extract_speaker_clip error for {speaker}: {e}")
100
- traceback.print_exc()
101
- return None
102
 
103
  @st.cache_data
104
  def convert_df(df):
@@ -669,15 +691,15 @@ try:
669
  for sp in speakerNames:
670
  _display = get_display_name(sp, currFileIndex)
671
  st.sidebar.markdown(f"**{_display}**")
672
- _clip_bytes = extract_speaker_clip(
673
  _curr_audio_path, currAnnotation, sp, clip_duration=5
674
  )
675
  if _clip_bytes:
676
  st.sidebar.audio(_clip_bytes, format="audio/wav")
677
  else:
678
- st.sidebar.caption("_(No audio segment found)_")
679
  else:
680
- st.sidebar.caption("_(Audio file not available for preview)_")
681
 
682
  st.sidebar.divider()
683
  st.sidebar.subheader("Rename Speakers")
 
57
  def extract_speaker_clip(audio_path, annotation, speaker, clip_duration=5):
58
  """
59
  Extract a clip of up to clip_duration seconds for the given speaker.
60
+ Returns (bytes, None) on success, or (None, error_string) on failure.
 
61
  """
62
+ import io, traceback
63
  try:
64
+ # --- Step 1: collect segments for this speaker ---
65
+ speaker_segments = []
66
+ try:
67
+ for seg, _, label in annotation.itertracks(yield_label=True):
68
+ if label == speaker:
69
+ speaker_segments.append((seg.start, seg.end))
70
+ except Exception as e:
71
+ return None, f"itertracks failed: {e}"
72
+
73
  if not speaker_segments:
74
+ return None, f"No segments found for speaker '{speaker}' in annotation"
75
 
76
+ # --- Step 2: pick best segment ---
77
  chosen_start, chosen_end = None, None
78
  for start, end in speaker_segments:
79
  if (end - start) >= clip_duration:
80
  chosen_start, chosen_end = start, start + clip_duration
81
  break
 
 
82
  if chosen_start is None:
83
  longest = max(speaker_segments, key=lambda s: s[1] - s[0])
84
  chosen_start, chosen_end = longest
85
 
86
+ # --- Step 3: load audio with torchaudio, fallback to soundfile ---
87
+ waveform, sample_rate = None, None
88
+ load_errors = []
89
+ try:
90
+ waveform, sample_rate = torchaudio.load(audio_path)
91
+ except Exception as e:
92
+ load_errors.append(f"torchaudio.load: {e}")
93
+
94
+ if waveform is None:
95
+ try:
96
+ import soundfile as sf
97
+ import numpy as np
98
+ data, sample_rate = sf.read(audio_path, dtype='float32')
99
+ if data.ndim == 1:
100
+ data = data[np.newaxis, :]
101
+ else:
102
+ data = data.T
103
+ waveform = torch.from_numpy(data)
104
+ except Exception as e:
105
+ load_errors.append(f"soundfile: {e}")
106
+
107
+ if waveform is None:
108
+ return None, "Could not load audio: " + " | ".join(load_errors)
109
+
110
+ # --- Step 4: slice and encode ---
111
  start_frame = int(chosen_start * sample_rate)
112
  end_frame = min(int(chosen_end * sample_rate), waveform.shape[-1])
113
  clip = waveform[:, start_frame:end_frame]
114
 
 
115
  buffer = io.BytesIO()
116
  torchaudio.save(buffer, clip, sample_rate, format="wav")
117
  buffer.seek(0)
118
+ return buffer.read(), None
119
+
120
  except Exception as e:
121
+ msg = traceback.format_exc()
122
+ print(f"extract_speaker_clip unexpected error for {speaker}: {msg}")
123
+ return None, str(e)
 
124
 
125
  @st.cache_data
126
  def convert_df(df):
 
691
  for sp in speakerNames:
692
  _display = get_display_name(sp, currFileIndex)
693
  st.sidebar.markdown(f"**{_display}**")
694
+ _clip_bytes, _clip_err = extract_speaker_clip(
695
  _curr_audio_path, currAnnotation, sp, clip_duration=5
696
  )
697
  if _clip_bytes:
698
  st.sidebar.audio(_clip_bytes, format="audio/wav")
699
  else:
700
+ st.sidebar.error(f"Clip error: {_clip_err}")
701
  else:
702
+ st.sidebar.warning(f"Audio file not found at path: {_curr_audio_path}")
703
 
704
  st.sidebar.divider()
705
  st.sidebar.subheader("Rename Speakers")