NickVerri commited on
Commit
6fe6f80
·
verified ·
1 Parent(s): 3baa5bf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -60
app.py CHANGED
@@ -6,28 +6,21 @@ import os
6
  import requests
7
  import torch
8
  import numpy
9
- import torchaudio
10
- import torchaudio.transforms as T
11
  from datetime import timedelta
12
  from pyannote.audio import Pipeline
13
- from huggingface_hub import login, hf_hub_download
14
 
15
  # --- Safe Globals ---
16
  try:
17
  from pyannote.audio.core.task import Specifications, Problem, Resolution
18
- from pyannote.audio.core.model import Model
19
- from pyannote.audio.pipelines.speaker_diarization import SpeakerDiarization
20
 
21
  torch.serialization.add_safe_globals([
22
  torch.torch_version.TorchVersion,
23
  Specifications,
24
  Problem,
25
  Resolution,
26
- Model,
27
- SpeakerDiarization,
28
  numpy.dtype,
29
  torch.nn.modules.container.ModuleList,
30
- numpy.core.multiarray.scalar
31
  ])
32
  except Exception as e:
33
  print(f"Safe Globals Warning: {e}")
@@ -129,94 +122,79 @@ if uploaded_file:
129
  if not ACTIVE_HF_TOKEN or "PASTE_YOUR_HF_TOKEN" in ACTIVE_HF_TOKEN:
130
  st.error("Please provide a valid Hugging Face Token.")
131
  else:
132
- with st.spinner("Processing... This may take a moment."):
133
- # Authenticate Globally
134
- login(token=ACTIVE_HF_TOKEN)
135
-
136
  with open("temp_input", "wb") as f:
137
  f.write(uploaded_file.getbuffer())
138
 
139
- # Convert to strict WAV using FFmpeg
140
  subprocess.run([
141
  "ffmpeg", "-i", "temp_input",
142
  "-vn", "-acodec", "pcm_s16le", "-ar", "16000", "-ac", "1",
143
  "temp_audio.wav", "-y"
144
- ])
145
 
146
- # 1. Diarization
147
  diarization = None
 
 
148
  try:
149
- # Load Config Manually
150
- config_path = hf_hub_download(
151
- repo_id="pyannote/speaker-diarization-3.1",
152
- filename="config.yaml",
153
- token=ACTIVE_HF_TOKEN
154
- )
155
- pipeline = Pipeline.from_pretrained(config_path)
156
 
157
- # Load Audio into Memory (Fix for file read issues)
158
- waveform, sample_rate = torchaudio.load("temp_audio.wav")
 
 
 
159
 
160
- # Move to GPU if available
161
  if torch.cuda.is_available():
162
  pipeline.to(torch.device("cuda"))
163
- waveform = waveform.to(torch.device("cuda"))
164
-
165
- # Run Pipeline on Tensor
166
- diarization_output = pipeline({"waveform": waveform, "sample_rate": sample_rate})
167
 
168
- # Unwrap result
169
- if isinstance(diarization_output, tuple):
170
- diarization = diarization_output[0]
 
 
 
 
 
 
 
 
 
171
  else:
172
- diarization = diarization_output
173
 
174
- # Extract Annotation object
175
- if not hasattr(diarization, "itertracks"):
176
- if hasattr(diarization_output, "annotation"):
177
- diarization = diarization_output.annotation
178
-
179
  except Exception as e:
180
  st.error(f"Diarization Error: {e}")
181
- diarization = None
182
 
183
  # 2. Whisper Transcription
184
- model = whisper.load_model("medium", device="cuda" if torch.cuda.is_available() else "cpu")
 
185
  result = model.transcribe("temp_audio.wav", word_timestamps=True)
186
 
187
  # 3. Alignment
188
  final_segments = []
189
- speaker_turns = []
190
 
191
- if diarization:
192
- try:
193
- # Iterate safely
194
- iterator = None
195
- if hasattr(diarization, 'itertracks'):
196
- iterator = diarization.itertracks(yield_label=True)
197
-
198
- if iterator:
199
- for turn, _, speaker_id in iterator:
200
- speaker_turns.append({"start": turn.start, "end": turn.end, "speaker": speaker_id})
201
- except Exception as e:
202
- print(f"Error iterating tracks: {e}")
203
-
204
  for segment in result['segments']:
205
  mid_time = (segment['start'] + segment['end']) / 2
206
  speaker = "Unknown"
207
 
208
  if speaker_turns:
209
- # Match speaker
210
  for turn in speaker_turns:
211
  if turn["start"] <= mid_time <= turn["end"]:
212
  speaker = turn["speaker"]
213
  break
214
 
215
- # Fallback distance matching
216
  if speaker == "Unknown":
217
- best_dist = 1.0
218
  for turn in speaker_turns:
219
- dist = min(abs(turn["start"] - mid_time), abs(turn["end"] - mid_time))
 
 
 
220
  if dist < best_dist:
221
  best_dist = dist
222
  speaker = turn["speaker"]
@@ -230,15 +208,16 @@ if uploaded_file:
230
  })
231
 
232
  st.session_state.transcript = final_segments
233
- st.success("Complete!")
234
 
235
  if "transcript" in st.session_state:
236
  st.divider()
 
237
  with st.expander("Transcript Preview (Diarized)"):
238
  for seg in st.session_state.transcript[:20]:
239
  st.markdown(f"**{seg['speaker']}:** {seg['text']}")
240
 
241
- brief = st.text_area("Creative Brief", placeholder="e.g. Focus on the yeast story.")
242
 
243
  if st.button("Step 2: Create EDL"):
244
  if not ACTIVE_GEMINI_KEY:
 
6
  import requests
7
  import torch
8
  import numpy
 
 
9
  from datetime import timedelta
10
  from pyannote.audio import Pipeline
11
+ from huggingface_hub import hf_hub_download
12
 
13
  # --- Safe Globals ---
14
  try:
15
  from pyannote.audio.core.task import Specifications, Problem, Resolution
 
 
16
 
17
  torch.serialization.add_safe_globals([
18
  torch.torch_version.TorchVersion,
19
  Specifications,
20
  Problem,
21
  Resolution,
 
 
22
  numpy.dtype,
23
  torch.nn.modules.container.ModuleList,
 
24
  ])
25
  except Exception as e:
26
  print(f"Safe Globals Warning: {e}")
 
122
  if not ACTIVE_HF_TOKEN or "PASTE_YOUR_HF_TOKEN" in ACTIVE_HF_TOKEN:
123
  st.error("Please provide a valid Hugging Face Token.")
124
  else:
125
+ with st.spinner("Processing... This may take a few minutes."):
 
 
 
126
  with open("temp_input", "wb") as f:
127
  f.write(uploaded_file.getbuffer())
128
 
129
+ # Convert to WAV
130
  subprocess.run([
131
  "ffmpeg", "-i", "temp_input",
132
  "-vn", "-acodec", "pcm_s16le", "-ar", "16000", "-ac", "1",
133
  "temp_audio.wav", "-y"
134
+ ], capture_output=True)
135
 
136
+ # 1. Diarization - FIXED VERSION
137
  diarization = None
138
+ speaker_turns = []
139
+
140
  try:
141
+ st.write("Loading diarization pipeline...")
 
 
 
 
 
 
142
 
143
+ # THE KEY FIX: Use direct from_pretrained with token
144
+ pipeline = Pipeline.from_pretrained(
145
+ "pyannote/speaker-diarization-3.1",
146
+ use_auth_token=ACTIVE_HF_TOKEN
147
+ )
148
 
 
149
  if torch.cuda.is_available():
150
  pipeline.to(torch.device("cuda"))
 
 
 
 
151
 
152
+ st.write("Running speaker diarization...")
153
+ diarization = pipeline("temp_audio.wav")
154
+
155
+ # Extract speaker turns
156
+ if diarization and hasattr(diarization, 'itertracks'):
157
+ for turn, _, speaker_id in diarization.itertracks(yield_label=True):
158
+ speaker_turns.append({
159
+ "start": turn.start,
160
+ "end": turn.end,
161
+ "speaker": speaker_id
162
+ })
163
+ st.write(f"✓ Found {len(speaker_turns)} speaker segments")
164
  else:
165
+ st.warning("Diarization completed but no speaker turns detected")
166
 
 
 
 
 
 
167
  except Exception as e:
168
  st.error(f"Diarization Error: {e}")
169
+ st.write("Continuing without speaker identification...")
170
 
171
  # 2. Whisper Transcription
172
+ st.write("Transcribing audio...")
173
+ model = whisper.load_model("base")
174
  result = model.transcribe("temp_audio.wav", word_timestamps=True)
175
 
176
  # 3. Alignment
177
  final_segments = []
 
178
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  for segment in result['segments']:
180
  mid_time = (segment['start'] + segment['end']) / 2
181
  speaker = "Unknown"
182
 
183
  if speaker_turns:
184
+ # Match speaker by midpoint
185
  for turn in speaker_turns:
186
  if turn["start"] <= mid_time <= turn["end"]:
187
  speaker = turn["speaker"]
188
  break
189
 
190
+ # Fallback: find closest speaker within 1 second
191
  if speaker == "Unknown":
192
+ best_dist = 1.0
193
  for turn in speaker_turns:
194
+ dist = min(
195
+ abs(turn["start"] - mid_time),
196
+ abs(turn["end"] - mid_time)
197
+ )
198
  if dist < best_dist:
199
  best_dist = dist
200
  speaker = turn["speaker"]
 
208
  })
209
 
210
  st.session_state.transcript = final_segments
211
+ st.success(f"✓ Processing complete! Transcribed {len(final_segments)} segments")
212
 
213
  if "transcript" in st.session_state:
214
  st.divider()
215
+
216
  with st.expander("Transcript Preview (Diarized)"):
217
  for seg in st.session_state.transcript[:20]:
218
  st.markdown(f"**{seg['speaker']}:** {seg['text']}")
219
 
220
+ brief = st.text_area("Creative Brief", placeholder="e.g. Focus on the yeast story, remove the interviewer.")
221
 
222
  if st.button("Step 2: Create EDL"):
223
  if not ACTIVE_GEMINI_KEY: