NickVerri commited on
Commit
20e9ceb
·
verified ·
1 Parent(s): f5f4019

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +13 -11
app.py CHANGED
@@ -119,7 +119,12 @@ def generate_cmx_edl(edl_title, segments, source_name, fps=25):
119
  edl_lines.append(f"{i:03} {reel_id} V C {src_in} {src_out} {rec_in} {rec_out}")
120
  edl_lines.append(f"* FROM CLIP NAME: {source_name}")
121
  edl_lines.append(f"* {seg.get('note', 'Clip')}\n")
122
- rec_start += duration
 
 
 
 
 
123
  return "\n".join(edl_lines)
124
 
125
  def call_gemini_for_edl(transcript_data, story_prompt, api_key):
@@ -129,15 +134,19 @@ def call_gemini_for_edl(transcript_data, story_prompt, api_key):
129
 
130
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent?key={api_key}"
131
 
 
132
  system_prompt = (
133
  "You are an expert Documentary Senior Editor. Use the provided transcript JSON "
134
  "(which includes Speaker IDs and word-level timestamps) to create a condensed story. "
135
- "Output ONLY a valid JSON array of segments with 'src_start', 'src_end', and 'note'. "
136
  "CRITICAL RULES:\n"
137
  "1. IGNORE ALL INTERVIEWER COMMENTS: Do not include any speech or segments where the interviewer is speaking.\n"
138
  "2. REMOVE FLUFF: Delete 'um', 'ah', repeats, and irrelevant filler.\n"
139
  "3. NARRATIVE FLOW: Focus on the subject's high-energy responses and narrative hooks.\n"
140
- "4. TIMESTAMP INTEGRITY: Use only the exact word-level start and end times from the data."
 
 
 
141
  )
142
 
143
  prompt_text = f"Creative Brief: {story_prompt}\n\nTranscript Data:\n{json.dumps(transcript_data)}"
@@ -219,17 +228,14 @@ if uploaded_file:
219
  if not ACTIVE_HF_TOKEN or "PASTE_YOUR_HF_TOKEN" in ACTIVE_HF_TOKEN:
220
  st.error("Please provide a valid Hugging Face Token in the Sidebar/Secrets.")
221
  else:
222
- # Create a dedicated container for the progress UI so it stays at the top
223
  progress_container = st.container()
224
  with progress_container:
225
  st.info("🤖 **Junior Editor is processing your file...**")
226
-
227
- # Create the visual elements
228
  status_text = st.empty()
229
  progress_bar = st.progress(0)
230
 
231
  try:
232
- # Phase 1: Save File & Extract Audio
233
  status_text.markdown("**Phase 1/4: Extracting Audio...**")
234
  with open("temp_input", "wb") as f:
235
  f.write(uploaded_file.getbuffer())
@@ -241,7 +247,6 @@ if uploaded_file:
241
  ])
242
  progress_bar.progress(25)
243
 
244
- # Setup Device
245
  device = "cuda" if torch.cuda.is_available() else "cpu"
246
  if device == "cpu":
247
  st.warning("⚠️ No GPU detected. This will be slow.")
@@ -253,11 +258,8 @@ if uploaded_file:
253
  model = whisperx.load_model(model_size, device, compute_type=compute_type)
254
  audio = whisperx.load_audio("temp_audio.wav")
255
 
256
- # This step takes the most time. It will sit at 25% until complete.
257
- # This is safer than chunking manually which can cause transcription errors.
258
  result = model.transcribe(audio, batch_size=16, language=target_language)
259
 
260
- # Cleanup VRAM
261
  del model
262
  gc.collect()
263
  torch.cuda.empty_cache()
 
119
  edl_lines.append(f"{i:03} {reel_id} V C {src_in} {src_out} {rec_in} {rec_out}")
120
  edl_lines.append(f"* FROM CLIP NAME: {source_name}")
121
  edl_lines.append(f"* {seg.get('note', 'Clip')}\n")
122
+
123
+ # --- NEW LOGIC: Support Gaps ---
124
+ # Add the duration of this clip AND any requested gap to the record timeline
125
+ gap = seg.get('gap', 0.0)
126
+ rec_start += duration + gap
127
+
128
  return "\n".join(edl_lines)
129
 
130
  def call_gemini_for_edl(transcript_data, story_prompt, api_key):
 
134
 
135
  url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent?key={api_key}"
136
 
137
+ # --- UPDATED SYSTEM PROMPT ---
138
  system_prompt = (
139
  "You are an expert Documentary Senior Editor. Use the provided transcript JSON "
140
  "(which includes Speaker IDs and word-level timestamps) to create a condensed story. "
141
+ "Output ONLY a valid JSON array of segments with 'src_start', 'src_end', 'note', and optionally 'gap'. "
142
  "CRITICAL RULES:\n"
143
  "1. IGNORE ALL INTERVIEWER COMMENTS: Do not include any speech or segments where the interviewer is speaking.\n"
144
  "2. REMOVE FLUFF: Delete 'um', 'ah', repeats, and irrelevant filler.\n"
145
  "3. NARRATIVE FLOW: Focus on the subject's high-energy responses and narrative hooks.\n"
146
+ "4. TIMESTAMP INTEGRITY: Use only the exact word-level start and end times from the data.\n"
147
+ "5. PACING: Group related clips together so they flow seamlessly. HOWEVER, between distinct ideas or sections, "
148
+ "add a 'gap': 1.0 property (float, in seconds) to the segment preceding the break. "
149
+ "This will leave blank space on the timeline to signal a topic change."
150
  )
151
 
152
  prompt_text = f"Creative Brief: {story_prompt}\n\nTranscript Data:\n{json.dumps(transcript_data)}"
 
228
  if not ACTIVE_HF_TOKEN or "PASTE_YOUR_HF_TOKEN" in ACTIVE_HF_TOKEN:
229
  st.error("Please provide a valid Hugging Face Token in the Sidebar/Secrets.")
230
  else:
 
231
  progress_container = st.container()
232
  with progress_container:
233
  st.info("🤖 **Junior Editor is processing your file...**")
 
 
234
  status_text = st.empty()
235
  progress_bar = st.progress(0)
236
 
237
  try:
238
+ # Phase 1: Save File
239
  status_text.markdown("**Phase 1/4: Extracting Audio...**")
240
  with open("temp_input", "wb") as f:
241
  f.write(uploaded_file.getbuffer())
 
247
  ])
248
  progress_bar.progress(25)
249
 
 
250
  device = "cuda" if torch.cuda.is_available() else "cpu"
251
  if device == "cpu":
252
  st.warning("⚠️ No GPU detected. This will be slow.")
 
258
  model = whisperx.load_model(model_size, device, compute_type=compute_type)
259
  audio = whisperx.load_audio("temp_audio.wav")
260
 
 
 
261
  result = model.transcribe(audio, batch_size=16, language=target_language)
262
 
 
263
  del model
264
  gc.collect()
265
  torch.cuda.empty_cache()