NickVerri commited on
Commit
880bb62
·
verified ·
1 Parent(s): 23975a0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +64 -58
app.py CHANGED
@@ -120,11 +120,15 @@ def generate_cmx_edl(edl_title, segments, source_name, fps=25, start_offset=0.0)
120
  reel_id = source_name.replace(" ", "_")[:8] # EDL reel IDs are traditionally short max 8 chars
121
 
122
  for i, seg in enumerate(segments, 1):
 
 
 
 
123
  # Add offset to source time
124
- src_in = format_timecode(seg['src_start'] + start_offset, fps)
125
- src_out = format_timecode(seg['src_end'] + start_offset, fps)
126
 
127
- duration = seg['src_end'] - seg['src_start']
128
  rec_in = format_timecode(rec_start, fps)
129
  rec_out = format_timecode(rec_start + duration, fps)
130
 
@@ -132,7 +136,7 @@ def generate_cmx_edl(edl_title, segments, source_name, fps=25, start_offset=0.0)
132
  edl_lines.append(f"* FROM CLIP NAME: {source_name}")
133
  edl_lines.append(f"* {seg.get('note', 'Clip')}\n")
134
 
135
- gap = seg.get('gap', 0.0)
136
  rec_start += duration + gap
137
 
138
  return "\n".join(edl_lines)
@@ -177,8 +181,11 @@ def generate_xml(sequence_name, segments, source_name, fps=25, start_offset=0.0)
177
 
178
  timeline_head_frames = 0
179
  for i, seg in enumerate(segments, 1):
180
- src_in_frames = seconds_to_frames(seg['src_start'], fps) + start_offset_frames
181
- src_out_frames = seconds_to_frames(seg['src_end'], fps) + start_offset_frames
 
 
 
182
  duration_frames = src_out_frames - src_in_frames
183
 
184
  tl_start = timeline_head_frames
@@ -216,7 +223,7 @@ def generate_xml(sequence_name, segments, source_name, fps=25, start_offset=0.0)
216
  lines.append('\t\t\t\t\t</file>')
217
  lines.append('\t\t\t\t</clipitem>')
218
 
219
- gap_frames = seconds_to_frames(seg.get('gap', 0.0), fps)
220
  timeline_head_frames = tl_end + gap_frames
221
 
222
  lines.append('\t\t\t</track>')
@@ -228,8 +235,11 @@ def generate_xml(sequence_name, segments, source_name, fps=25, start_offset=0.0)
228
 
229
  timeline_head_frames = 0
230
  for i, seg in enumerate(segments, 1):
231
- src_in_frames = seconds_to_frames(seg['src_start'], fps) + start_offset_frames
232
- src_out_frames = seconds_to_frames(seg['src_end'], fps) + start_offset_frames
 
 
 
233
  duration_frames = src_out_frames - src_in_frames
234
  tl_start = timeline_head_frames
235
  tl_end = tl_start + duration_frames
@@ -241,9 +251,9 @@ def generate_xml(sequence_name, segments, source_name, fps=25, start_offset=0.0)
241
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
242
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
243
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
244
- lines.append('\t\t\t\t\t<sourcetrack><mediatype>audio</mediatype><trackindex>1</trackindex></souretrack>')
245
  lines.append('\t\t\t\t</clipitem>')
246
- timeline_head_frames = tl_end + seconds_to_frames(seg.get('gap', 0.0), fps)
247
 
248
  lines.append('\t\t\t</track>')
249
  lines.append('\t\t</audio>')
@@ -357,52 +367,47 @@ st.markdown("""
357
  st.divider()
358
 
359
  with st.sidebar:
360
- st.header("Project Settings")
361
- fps_options = [23.98, 24, 25, 29.97, 30, 50, 59.94, 60]
362
- fps = st.selectbox("Timeline FPS", fps_options, index=2)
363
-
364
- st.header("Source Timecode")
365
- st.info("Set this if your source file should reference a specific time-of-day timecode (e.g. for MP3s).")
366
- source_start_tc = st.text_input("Source Start Timecode", value="00:00:00:00", help="Format: HH:MM:SS:FF")
367
-
368
- st.header("Export Settings")
369
- export_format = st.radio("Output Format", ["EDL", "XML (Multicam)"], index=0)
370
-
371
- input_label = "EDL Reel Name"
372
- input_help = "Leave empty to use the uploaded file name."
373
- if export_format == "XML (Multicam)":
374
- input_label = "Multicam Sequence Name"
375
- input_help = "EXACT name of your Multicam Clip in Resolve."
376
-
377
- st.info("💡 **Conform Helper**")
378
- custom_reel_name = st.text_input(
379
- input_label,
380
- placeholder="e.g. Interview_Day1_Multi",
381
- help=input_help
382
- )
 
 
383
 
384
- st.header("Model Settings")
385
- model_size = st.selectbox("Whisper Model", ["large-v2", "medium", "base"], index=0)
386
-
387
- language_map = {
388
- "Auto-Detect": None,
389
- "English": "en",
390
- "Spanish": "es",
391
- "French": "fr",
392
- "German": "de",
393
- "Italian": "it",
394
- "Portuguese": "pt"
395
- }
396
- selected_lang_label = st.selectbox("Audio Language", list(language_map.keys()), index=1)
397
- target_language = language_map[selected_lang_label]
398
-
399
- num_speakers = st.number_input("Speakers (0=Auto)", min_value=0, value=0)
400
-
401
- st.divider()
402
- if ACTIVE_HF_TOKEN == "PASTE_YOUR_HF_TOKEN_HERE":
403
- st.warning("⚠️ HF_TOKEN not set in Secrets!")
404
- else:
405
- st.success("✅ HF_TOKEN Loaded")
406
 
407
  uploaded_file = st.file_uploader("Upload Video/Audio Clip", type=["mp4", "m4a", "wav", "mp3", "mov"])
408
 
@@ -437,9 +442,10 @@ if uploaded_file:
437
  if device == "cpu": st.warning("⚠️ No GPU detected.")
438
 
439
  # Phase 2
440
- status_text.markdown(f"**Phase 2/4: Transcribing (Whisper {model_size})... This is the longest step.**")
441
  compute_type = "float16" if device == "cuda" else "int8"
442
- model = whisperx.load_model(model_size, device, compute_type=compute_type)
 
443
  audio = whisperx.load_audio("temp_audio.wav")
444
  result = model.transcribe(audio, batch_size=16, language=target_language)
445
  del model
 
120
  reel_id = source_name.replace(" ", "_")[:8] # EDL reel IDs are traditionally short max 8 chars
121
 
122
  for i, seg in enumerate(segments, 1):
123
+ # Fallback to 'start'/'end' if 'src_start'/'src_end' are missing, and force float
124
+ src_start_val = float(seg.get('src_start', seg.get('start', 0.0)))
125
+ src_end_val = float(seg.get('src_end', seg.get('end', 0.0)))
126
+
127
  # Add offset to source time
128
+ src_in = format_timecode(src_start_val + start_offset, fps)
129
+ src_out = format_timecode(src_end_val + start_offset, fps)
130
 
131
+ duration = src_end_val - src_start_val
132
  rec_in = format_timecode(rec_start, fps)
133
  rec_out = format_timecode(rec_start + duration, fps)
134
 
 
136
  edl_lines.append(f"* FROM CLIP NAME: {source_name}")
137
  edl_lines.append(f"* {seg.get('note', 'Clip')}\n")
138
 
139
+ gap = float(seg.get('gap', 0.0))
140
  rec_start += duration + gap
141
 
142
  return "\n".join(edl_lines)
 
181
 
182
  timeline_head_frames = 0
183
  for i, seg in enumerate(segments, 1):
184
+ src_start_val = float(seg.get('src_start', seg.get('start', 0.0)))
185
+ src_end_val = float(seg.get('src_end', seg.get('end', 0.0)))
186
+
187
+ src_in_frames = seconds_to_frames(src_start_val, fps) + start_offset_frames
188
+ src_out_frames = seconds_to_frames(src_end_val, fps) + start_offset_frames
189
  duration_frames = src_out_frames - src_in_frames
190
 
191
  tl_start = timeline_head_frames
 
223
  lines.append('\t\t\t\t\t</file>')
224
  lines.append('\t\t\t\t</clipitem>')
225
 
226
+ gap_frames = seconds_to_frames(float(seg.get('gap', 0.0)), fps)
227
  timeline_head_frames = tl_end + gap_frames
228
 
229
  lines.append('\t\t\t</track>')
 
235
 
236
  timeline_head_frames = 0
237
  for i, seg in enumerate(segments, 1):
238
+ src_start_val = float(seg.get('src_start', seg.get('start', 0.0)))
239
+ src_end_val = float(seg.get('src_end', seg.get('end', 0.0)))
240
+
241
+ src_in_frames = seconds_to_frames(src_start_val, fps) + start_offset_frames
242
+ src_out_frames = seconds_to_frames(src_end_val, fps) + start_offset_frames
243
  duration_frames = src_out_frames - src_in_frames
244
  tl_start = timeline_head_frames
245
  tl_end = tl_start + duration_frames
 
251
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
252
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
253
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
254
+ lines.append('\t\t\t\t\t<sourcetrack><mediatype>audio</mediatype><trackindex>1</trackindex></sourcetrack>')
255
  lines.append('\t\t\t\t</clipitem>')
256
+ timeline_head_frames = tl_end + seconds_to_frames(float(seg.get('gap', 0.0)), fps)
257
 
258
  lines.append('\t\t\t</track>')
259
  lines.append('\t\t</audio>')
 
367
  st.divider()
368
 
369
  with st.sidebar:
370
+ # Use containers so we can render Clip Settings visually above Project Settings,
371
+ # but still evaluate Export Settings first (needed to determine dynamic text labels).
372
+ clip_settings_container = st.container()
373
+ project_settings_container = st.container()
374
+
375
+ with project_settings_container:
376
+ st.header("Project Settings")
377
+ export_format = st.radio("Output Format", ["EDL", "XML (Multicam)"], index=0)
378
+
379
+ fps_options = [23.98, 24, 25, 29.97, 30, 50, 59.94, 60]
380
+ fps = st.selectbox("Timeline FPS", fps_options, index=2)
381
+
382
+ language_map = {
383
+ "Auto-Detect": None,
384
+ "English": "en",
385
+ "Spanish": "es",
386
+ "French": "fr",
387
+ "German": "de",
388
+ "Italian": "it",
389
+ "Portuguese": "pt"
390
+ }
391
+ selected_lang_label = st.selectbox("Audio Language", list(language_map.keys()), index=1)
392
+ target_language = language_map[selected_lang_label]
393
+
394
+ num_speakers = st.number_input("Speakers (0=Auto)", min_value=0, value=0)
395
 
396
+ with clip_settings_container:
397
+ st.header("Clip Settings")
398
+ source_start_tc = st.text_input("Source Start Timecode", value="00:00:00:00", help="Format: HH:MM:SS:FF")
399
+
400
+ input_label = "EDL Reel Name"
401
+ input_help = "Leave empty to use the uploaded file name."
402
+ if export_format == "XML (Multicam)":
403
+ input_label = "Multicam Sequence Name"
404
+ input_help = "EXACT name of your Multicam Clip in Resolve."
405
+
406
+ custom_reel_name = st.text_input(
407
+ input_label,
408
+ placeholder="e.g. Interview_Day1_Multi",
409
+ help=input_help
410
+ )
 
 
 
 
 
 
 
411
 
412
  uploaded_file = st.file_uploader("Upload Video/Audio Clip", type=["mp4", "m4a", "wav", "mp3", "mov"])
413
 
 
442
  if device == "cpu": st.warning("⚠️ No GPU detected.")
443
 
444
  # Phase 2
445
+ status_text.markdown("**Phase 2/4: Transcribing (Whisper)... This is the longest step.**")
446
  compute_type = "float16" if device == "cuda" else "int8"
447
+ # Default model size hardcoded to 'large-v2' to keep high quality while removing the sidebar toggle
448
+ model = whisperx.load_model("large-v2", device, compute_type=compute_type)
449
  audio = whisperx.load_audio("temp_audio.wav")
450
  result = model.transcribe(audio, batch_size=16, language=target_language)
451
  del model