NickVerri commited on
Commit
faf5bd6
·
verified ·
1 Parent(s): 1e1397a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +47 -51
app.py CHANGED
@@ -8,27 +8,22 @@ import torch
8
  import numpy
9
  from datetime import timedelta
10
  from pyannote.audio import Pipeline
11
- from huggingface_hub import login, hf_hub_download
12
 
13
- # --- Fix for OMP Error (Critical for T4 Spaces) ---
14
  os.environ["OMP_NUM_THREADS"] = "1"
15
 
16
  # --- Safe Globals for PyTorch 2.6+ ---
17
  try:
18
  from pyannote.audio.core.task import Specifications, Problem, Resolution
19
- from pyannote.audio.core.model import Model
20
- from pyannote.audio.pipelines.speaker_diarization import SpeakerDiarization
21
 
22
  torch.serialization.add_safe_globals([
23
  torch.torch_version.TorchVersion,
24
  Specifications,
25
  Problem,
26
  Resolution,
27
- Model,
28
- SpeakerDiarization,
29
  numpy.dtype,
30
  torch.nn.modules.container.ModuleList,
31
- numpy.core.multiarray.scalar
32
  ])
33
  except Exception as e:
34
  print(f"Safe Globals Warning: {e}")
@@ -134,92 +129,92 @@ if uploaded_file:
134
  with status_container.container():
135
  st.write("🔄 **Processing Started...**")
136
 
 
 
 
137
  with open("temp_input", "wb") as f:
138
  f.write(uploaded_file.getbuffer())
139
 
140
  st.write("🎵 **Extracting Audio (WAV)...**")
141
- # Strict WAV (PCM)
142
  subprocess.run([
143
  "ffmpeg", "-i", "temp_input",
144
  "-vn", "-acodec", "pcm_s16le", "-ar", "16000", "-ac", "1",
145
  "temp_audio.wav", "-y"
146
- ])
147
 
148
- # 1. Diarization
149
  st.write("🗣️ **Running Speaker Diarization...**")
150
  diarization = None
 
 
151
  try:
152
- # Global Login
153
- login(token=ACTIVE_HF_TOKEN)
154
-
155
- # Load Pipeline Standard Way
156
  pipeline = Pipeline.from_pretrained("pyannote/speaker-diarization-3.1")
157
 
158
  if torch.cuda.is_available():
159
  st.write("🚀 Using GPU for Diarization")
160
  pipeline.to(torch.device("cuda"))
161
 
162
- # Run on file path
163
- diarization_output = pipeline("temp_audio.wav")
 
 
 
 
 
164
 
165
- # Handle Output Wrapper
166
- if isinstance(diarization_output, tuple):
167
- diarization = diarization_output[0]
 
 
 
 
 
 
 
 
 
 
 
 
168
  else:
169
- diarization = diarization_output
170
 
171
- # CRITICAL FIX: Extract annotation
172
- if not hasattr(diarization, "itertracks"):
173
- if hasattr(diarization_output, "annotation"):
174
- diarization = diarization_output.annotation
175
- elif hasattr(diarization_output, "get"):
176
- diarization = diarization_output.get("annotation", diarization_output)
177
-
178
  except Exception as e:
179
- st.error(f"Diarization Error: {e}")
180
- diarization = None
 
181
 
182
  # 2. Whisper Transcription
183
  st.write("📝 **Transcribing with Whisper...**")
184
  device = "cuda" if torch.cuda.is_available() else "cpu"
185
- model = whisper.load_model("medium", device=device)
186
  result = model.transcribe("temp_audio.wav", word_timestamps=True)
187
 
188
  # 3. Alignment
189
  st.write("🔗 **Aligning Speakers...**")
190
  final_segments = []
191
- speaker_turns = []
192
 
193
- if diarization:
194
- try:
195
- iterator = None
196
- if hasattr(diarization, 'itertracks'):
197
- iterator = diarization.itertracks(yield_label=True)
198
-
199
- if iterator:
200
- for turn, _, speaker_id in iterator:
201
- speaker_turns.append({"start": turn.start, "end": turn.end, "speaker": speaker_id})
202
- st.write(f"✅ Found {len(speaker_turns)} speaker turns.")
203
- else:
204
- st.warning("⚠️ Pipeline ran but returned no iterable tracks.")
205
- except Exception as e:
206
- print(f"Error iterating tracks: {e}")
207
-
208
  for segment in result['segments']:
209
  mid_time = (segment['start'] + segment['end']) / 2
210
  speaker = "Unknown"
211
 
212
  if speaker_turns:
 
213
  for turn in speaker_turns:
214
  if turn["start"] <= mid_time <= turn["end"]:
215
  speaker = turn["speaker"]
216
  break
217
 
218
- # Fallback distance matching
219
  if speaker == "Unknown":
220
- best_dist = 1.0
221
  for turn in speaker_turns:
222
- dist = min(abs(turn["start"] - mid_time), abs(turn["end"] - mid_time))
 
 
 
223
  if dist < best_dist:
224
  best_dist = dist
225
  speaker = turn["speaker"]
@@ -233,15 +228,16 @@ if uploaded_file:
233
  })
234
 
235
  st.session_state.transcript = final_segments
236
- st.success("Complete!")
237
 
238
  if "transcript" in st.session_state:
239
  st.divider()
 
240
  with st.expander("Transcript Preview (Diarized)"):
241
  for seg in st.session_state.transcript[:20]:
242
  st.markdown(f"**{seg['speaker']}:** {seg['text']}")
243
 
244
- brief = st.text_area("Creative Brief", placeholder="e.g. Focus on the yeast story.")
245
 
246
  if st.button("Step 2: Create EDL"):
247
  if not ACTIVE_GEMINI_KEY:
 
8
  import numpy
9
  from datetime import timedelta
10
  from pyannote.audio import Pipeline
11
+ from huggingface_hub import login
12
 
13
+ # --- Fix for OMP Error ---
14
  os.environ["OMP_NUM_THREADS"] = "1"
15
 
16
  # --- Safe Globals for PyTorch 2.6+ ---
17
  try:
18
  from pyannote.audio.core.task import Specifications, Problem, Resolution
 
 
19
 
20
  torch.serialization.add_safe_globals([
21
  torch.torch_version.TorchVersion,
22
  Specifications,
23
  Problem,
24
  Resolution,
 
 
25
  numpy.dtype,
26
  torch.nn.modules.container.ModuleList,
 
27
  ])
28
  except Exception as e:
29
  print(f"Safe Globals Warning: {e}")
 
129
  with status_container.container():
130
  st.write("🔄 **Processing Started...**")
131
 
132
+ # Authenticate FIRST - this is critical
133
+ login(token=ACTIVE_HF_TOKEN)
134
+
135
  with open("temp_input", "wb") as f:
136
  f.write(uploaded_file.getbuffer())
137
 
138
  st.write("🎵 **Extracting Audio (WAV)...**")
 
139
  subprocess.run([
140
  "ffmpeg", "-i", "temp_input",
141
  "-vn", "-acodec", "pcm_s16le", "-ar", "16000", "-ac", "1",
142
  "temp_audio.wav", "-y"
143
+ ], capture_output=True)
144
 
145
+ # 1. Diarization - CRITICAL FIX
146
  st.write("🗣️ **Running Speaker Diarization...**")
147
  diarization = None
148
+ speaker_turns = []
149
+
150
  try:
151
+ # Load pipeline WITHOUT any token parameter (relies on login())
 
 
 
152
  pipeline = Pipeline.from_pretrained("pyannote/speaker-diarization-3.1")
153
 
154
  if torch.cuda.is_available():
155
  st.write("🚀 Using GPU for Diarization")
156
  pipeline.to(torch.device("cuda"))
157
 
158
+ # Run diarization
159
+ st.write("⏳ Processing audio (this takes a moment)...")
160
+ diarization = pipeline("temp_audio.wav")
161
+
162
+ # Debug: Check what we got back
163
+ st.write(f"DEBUG: Diarization type = {type(diarization)}")
164
+ st.write(f"DEBUG: Has itertracks? {hasattr(diarization, 'itertracks')}")
165
 
166
+ # Extract speaker turns
167
+ if hasattr(diarization, 'itertracks'):
168
+ for turn, _, speaker_id in diarization.itertracks(yield_label=True):
169
+ speaker_turns.append({
170
+ "start": turn.start,
171
+ "end": turn.end,
172
+ "speaker": speaker_id
173
+ })
174
+ st.write(f"✅ Found {len(speaker_turns)} speaker segments")
175
+
176
+ # Show first few turns for debugging
177
+ if speaker_turns:
178
+ st.write("Sample speaker turns:")
179
+ for turn in speaker_turns[:3]:
180
+ st.write(f" {turn['speaker']}: {turn['start']:.1f}s - {turn['end']:.1f}s")
181
  else:
182
+ st.warning("⚠️ Diarization object has no itertracks method")
183
 
 
 
 
 
 
 
 
184
  except Exception as e:
185
+ st.error(f"Diarization Error: {str(e)}")
186
+ import traceback
187
+ st.code(traceback.format_exc())
188
 
189
  # 2. Whisper Transcription
190
  st.write("📝 **Transcribing with Whisper...**")
191
  device = "cuda" if torch.cuda.is_available() else "cpu"
192
+ model = whisper.load_model("base", device=device)
193
  result = model.transcribe("temp_audio.wav", word_timestamps=True)
194
 
195
  # 3. Alignment
196
  st.write("🔗 **Aligning Speakers...**")
197
  final_segments = []
 
198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  for segment in result['segments']:
200
  mid_time = (segment['start'] + segment['end']) / 2
201
  speaker = "Unknown"
202
 
203
  if speaker_turns:
204
+ # Match speaker by midpoint
205
  for turn in speaker_turns:
206
  if turn["start"] <= mid_time <= turn["end"]:
207
  speaker = turn["speaker"]
208
  break
209
 
210
+ # Fallback: find closest speaker within 1 second
211
  if speaker == "Unknown":
212
+ best_dist = 1.0
213
  for turn in speaker_turns:
214
+ dist = min(
215
+ abs(turn["start"] - mid_time),
216
+ abs(turn["end"] - mid_time)
217
+ )
218
  if dist < best_dist:
219
  best_dist = dist
220
  speaker = turn["speaker"]
 
228
  })
229
 
230
  st.session_state.transcript = final_segments
231
+ st.success(f"✓ Complete! Transcribed {len(final_segments)} segments")
232
 
233
  if "transcript" in st.session_state:
234
  st.divider()
235
+
236
  with st.expander("Transcript Preview (Diarized)"):
237
  for seg in st.session_state.transcript[:20]:
238
  st.markdown(f"**{seg['speaker']}:** {seg['text']}")
239
 
240
+ brief = st.text_area("Creative Brief", placeholder="e.g. Focus on the yeast story, remove the interviewer.")
241
 
242
  if st.button("Step 2: Create EDL"):
243
  if not ACTIVE_GEMINI_KEY: