NickVerri commited on
Commit
1e1397a
Β·
verified Β·
1 Parent(s): 3b35b38

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -44
app.py CHANGED
@@ -6,12 +6,13 @@ 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 for PyTorch 2.6+ ---
16
  try:
17
  from pyannote.audio.core.task import Specifications, Problem, Resolution
@@ -43,7 +44,7 @@ ACTIVE_HF_TOKEN = ENV_HF_TOKEN if ENV_HF_TOKEN else HARDCODED_HF_TOKEN
43
  ACTIVE_GEMINI_KEY = ENV_GEMINI_KEY if ENV_GEMINI_KEY else HARDCODED_GEMINI_KEY
44
 
45
  def format_timecode(seconds, fps=25):
46
- """Converts seconds to HH:MM:SS:FF for Resolve/Premiere."""
47
  td = timedelta(seconds=seconds)
48
  total_seconds = int(td.total_seconds())
49
  hours = total_seconds // 3600
@@ -129,14 +130,15 @@ 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",
@@ -144,60 +146,41 @@ if uploaded_file:
144
  ])
145
 
146
  # 1. Diarization
147
- st.write("πŸ—£οΈ **Running Speaker Diarization (GPU Mode)...**")
148
  diarization = None
149
  try:
150
- # Load Config Manually
151
- config_path = hf_hub_download(
152
- repo_id="pyannote/speaker-diarization-3.1",
153
- filename="config.yaml",
154
- token=ACTIVE_HF_TOKEN
155
- )
156
- pipeline = Pipeline.from_pretrained(config_path)
157
-
158
- # Load Audio into Memory
159
- waveform, sample_rate = torchaudio.load("temp_audio.wav")
160
 
161
- # Verify Audio is not silent
162
- max_amp = waveform.abs().max().item()
163
- print(f"DEBUG: Audio Loaded. Shape: {waveform.shape}, Max Amp: {max_amp}")
164
- if max_amp == 0:
165
- st.error("Audio is silent! Check FFmpeg conversion.")
166
 
167
- # Move Pipeline AND Data to GPU
168
  if torch.cuda.is_available():
169
- device = torch.device("cuda")
170
- st.write("πŸš€ GPU Detected & Active")
171
- pipeline.to(device)
172
- waveform = waveform.to(device)
173
- else:
174
- st.warning("⚠️ No GPU detected. Running slow on CPU.")
175
-
176
- # Run Pipeline on Tensor
177
- # Passing dictionary ensures pyannote doesn't try to reload from disk
178
- diarization_output = pipeline({"waveform": waveform, "sample_rate": sample_rate})
179
 
180
- # Debug Structure
181
- print(f"DEBUG: Output Type: {type(diarization_output)}")
182
- print(f"DEBUG: Output Dir: {dir(diarization_output)}")
183
-
184
- # Robust Unwrap
185
  if isinstance(diarization_output, tuple):
186
  diarization = diarization_output[0]
187
  else:
188
  diarization = diarization_output
189
 
190
- # Final Extraction Attempt
191
  if not hasattr(diarization, "itertracks"):
192
  if hasattr(diarization_output, "annotation"):
193
  diarization = diarization_output.annotation
 
 
194
 
195
  except Exception as e:
196
  st.error(f"Diarization Error: {e}")
197
  diarization = None
198
 
199
  # 2. Whisper Transcription
200
- st.write("πŸ“ **Transcribing with Whisper (GPU Mode)...**")
201
  device = "cuda" if torch.cuda.is_available() else "cpu"
202
  model = whisper.load_model("medium", device=device)
203
  result = model.transcribe("temp_audio.wav", word_timestamps=True)
@@ -209,7 +192,6 @@ if uploaded_file:
209
 
210
  if diarization:
211
  try:
212
- # Iterate safely
213
  iterator = None
214
  if hasattr(diarization, 'itertracks'):
215
  iterator = diarization.itertracks(yield_label=True)
@@ -219,9 +201,9 @@ if uploaded_file:
219
  speaker_turns.append({"start": turn.start, "end": turn.end, "speaker": speaker_id})
220
  st.write(f"βœ… Found {len(speaker_turns)} speaker turns.")
221
  else:
222
- st.warning("⚠️ Pipeline ran but returned no tracks.")
223
  except Exception as e:
224
- st.error(f"Error iterating tracks: {e}")
225
 
226
  for segment in result['segments']:
227
  mid_time = (segment['start'] + segment['end']) / 2
@@ -233,6 +215,7 @@ if uploaded_file:
233
  speaker = turn["speaker"]
234
  break
235
 
 
236
  if speaker == "Unknown":
237
  best_dist = 1.0
238
  for turn in speaker_turns:
 
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 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
 
44
  ACTIVE_GEMINI_KEY = ENV_GEMINI_KEY if ENV_GEMINI_KEY else HARDCODED_GEMINI_KEY
45
 
46
  def format_timecode(seconds, fps=25):
47
+ """Converts seconds to HH:MM:SS:FF."""
48
  td = timedelta(seconds=seconds)
49
  total_seconds = int(td.total_seconds())
50
  hours = total_seconds // 3600
 
130
  if not ACTIVE_HF_TOKEN or "PASTE_YOUR_HF_TOKEN" in ACTIVE_HF_TOKEN:
131
  st.error("Please provide a valid Hugging Face Token.")
132
  else:
133
+ status_container = st.empty()
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",
 
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)
 
192
 
193
  if diarization:
194
  try:
 
195
  iterator = None
196
  if hasattr(diarization, 'itertracks'):
197
  iterator = diarization.itertracks(yield_label=True)
 
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
 
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: