NickVerri commited on
Commit
6449789
·
verified ·
1 Parent(s): 7b1e992

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -30
app.py CHANGED
@@ -179,6 +179,7 @@ def generate_xml(sequence_name, segments, source_name, fps=25, start_offset=0.0)
179
  lines.append('\t\t\t</format>')
180
  lines.append('\t\t\t<track>')
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)))
@@ -195,8 +196,8 @@ def generate_xml(sequence_name, segments, source_name, fps=25, start_offset=0.0)
195
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
196
 
197
  lines.append(f'\t\t\t\t<clipitem id="clipitem-v-{i}">')
198
- lines.append(f'\t\t\t\t\t<name>{clip_note}</name>')
199
- lines.append(f'\t\t\t\t\t<duration>{duration_frames + src_in_frames}</duration>')
200
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
201
  lines.append(f'\t\t\t\t\t<start>{tl_start}</start>')
202
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
@@ -205,22 +206,33 @@ def generate_xml(sequence_name, segments, source_name, fps=25, start_offset=0.0)
205
  lines.append(f'\t\t\t\t\t<masterclipid>{master_id}</masterclipid>')
206
 
207
  # --- ROBUST FILE DEFINITION ---
208
- lines.append(f'\t\t\t\t\t<file id="{master_id}">')
209
- lines.append(f'\t\t\t\t\t\t<name>{source_name}</name>')
210
- lines.append(f'\t\t\t\t\t\t<pathurl>{path_url}</pathurl>')
211
- lines.append(f'\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
212
- lines.append(f'\t\t\t\t\t\t<duration>8640000</duration>')
213
- lines.append(f'\t\t\t\t\t\t<timecode>')
214
- lines.append(f'\t\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
215
- lines.append(f'\t\t\t\t\t\t\t<string>{start_tc_string}</string>')
216
- lines.append(f'\t\t\t\t\t\t\t<frame>{start_offset_frames}</frame>')
217
- lines.append(f'\t\t\t\t\t\t\t<displayformat>NDF</displayformat>')
218
- lines.append(f'\t\t\t\t\t\t</timecode>')
219
- lines.append('\t\t\t\t\t\t<media>')
220
- lines.append('\t\t\t\t\t\t\t<video><samplecharacteristics><width>1920</width><height>1080</height></samplecharacteristics></video>')
221
- lines.append('\t\t\t\t\t\t\t<audio><samplecharacteristics><depth>16</depth><samplerate>48000</samplerate></samplecharacteristics><channelcount>2</channelcount></audio>')
222
- lines.append('\t\t\t\t\t\t</media>')
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)
@@ -245,12 +257,15 @@ def generate_xml(sequence_name, segments, source_name, fps=25, start_offset=0.0)
245
  tl_end = tl_start + duration_frames
246
 
247
  lines.append(f'\t\t\t\t<clipitem id="clipitem-a-{i}">')
 
248
  lines.append(f'\t\t\t\t\t<masterclipid>{master_id}</masterclipid>')
 
249
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
250
  lines.append(f'\t\t\t\t\t<start>{tl_start}</start>')
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)
@@ -311,8 +326,8 @@ def call_gemini_for_edl(transcript_data, story_prompt, api_key):
311
  "gemini-2.5-pro"
312
  ]
313
 
314
- # Try the final/stable endpoint first, fallback to beta if features aren't promoted yet
315
- endpoints_to_try = ["v1", "v1beta"]
316
  last_error = ""
317
 
318
  for model_name in models_to_try:
@@ -327,13 +342,13 @@ def call_gemini_for_edl(transcript_data, story_prompt, api_key):
327
  result_json = res.json()
328
  raw_text = result_json['candidates'][0]['content']['parts'][0]['text']
329
  cleaned_text = clean_json_response(raw_text)
330
- return json.loads(cleaned_text)
331
 
332
  # Handle High Demand (503) or Rate Limits (429)
333
  elif res.status_code in [503, 429]:
334
  last_error = f"Model {model_name} busy ({res.status_code}) on {api_version}."
335
  st.warning(f"Debug: {last_error} Skipping to next model...")
336
- break # Break inner loop: No point trying v1beta if v1 is rate limited. Move to next model.
337
 
338
  # Handle endpoints that don't exist (404) or API rejections (400)
339
  else:
@@ -343,7 +358,7 @@ def call_gemini_for_edl(transcript_data, story_prompt, api_key):
343
  error_details = res.text
344
  last_error = f"Model {model_name} rejected request ({res.status_code}) on {api_version}: {error_details}"
345
  st.warning(f"Debug: {last_error} Trying fallback endpoint/model...")
346
- continue # Try v1beta, or the next model
347
 
348
  except json.JSONDecodeError:
349
  last_error = f"Model {model_name} returned invalid JSON on {api_version}."
@@ -360,7 +375,7 @@ def call_gemini_for_edl(transcript_data, story_prompt, api_key):
360
 
361
  # If the loop finishes without returning, all models failed
362
  st.error(f"All Gemini models failed or are currently experiencing high demand. Last error: {last_error}")
363
- return None
364
 
365
  # --- Streamlit UI ---
366
  st.set_page_config(page_title="Junior Editor", layout="wide")
@@ -525,21 +540,28 @@ if uploaded_file:
525
  # Parse the offset from sidebar input
526
  offset_sec = timecode_to_seconds(source_start_tc, fps)
527
 
528
- edl_segments = call_gemini_for_edl(st.session_state.transcript, brief, ACTIVE_GEMINI_KEY)
 
529
  if edl_segments:
 
 
 
 
 
 
530
  if export_format == "EDL":
531
- final_output = generate_cmx_edl("Junior_Editor_Cut", edl_segments, final_source_name, fps, offset_sec)
532
  ext = "edl"
533
  else:
534
- final_output = generate_xml("Junior_Editor_Cut", edl_segments, final_source_name, fps, offset_sec)
535
  ext = "xml"
536
 
537
  st.subheader("Ready for Import")
 
 
538
  with st.expander("Show XML/EDL Code", expanded=False):
539
  st.code(final_output, language="xml" if ext == "xml" else "text")
540
 
541
- st.download_button(f"Download .{ext.upper()}", data=final_output, file_name=f"junior_editor_cut.{ext}")
542
-
543
-
544
 
545
 
 
179
  lines.append('\t\t\t</format>')
180
  lines.append('\t\t\t<track>')
181
 
182
+ file_defined = False
183
  timeline_head_frames = 0
184
  for i, seg in enumerate(segments, 1):
185
  src_start_val = float(seg.get('src_start', seg.get('start', 0.0)))
 
196
  clip_note = (raw_note[:75] + '..') if len(raw_note) > 75 else raw_note
197
 
198
  lines.append(f'\t\t\t\t<clipitem id="clipitem-v-{i}">')
199
+ lines.append(f'\t\t\t\t\t<name>{source_name}</name>')
200
+ lines.append(f'\t\t\t\t\t<duration>8640000</duration>')
201
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
202
  lines.append(f'\t\t\t\t\t<start>{tl_start}</start>')
203
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
 
206
  lines.append(f'\t\t\t\t\t<masterclipid>{master_id}</masterclipid>')
207
 
208
  # --- ROBUST FILE DEFINITION ---
209
+ if not file_defined:
210
+ lines.append(f'\t\t\t\t\t<file id="{master_id}">')
211
+ lines.append(f'\t\t\t\t\t\t<name>{source_name}</name>')
212
+ lines.append(f'\t\t\t\t\t\t<pathurl>{path_url}</pathurl>')
213
+ lines.append(f'\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
214
+ lines.append(f'\t\t\t\t\t\t<duration>8640000</duration>')
215
+ lines.append(f'\t\t\t\t\t\t<timecode>')
216
+ lines.append(f'\t\t\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
217
+ lines.append(f'\t\t\t\t\t\t\t<string>{start_tc_string}</string>')
218
+ lines.append(f'\t\t\t\t\t\t\t<frame>{start_offset_frames}</frame>')
219
+ lines.append(f'\t\t\t\t\t\t\t<displayformat>NDF</displayformat>')
220
+ lines.append(f'\t\t\t\t\t\t</timecode>')
221
+ lines.append('\t\t\t\t\t\t<media>')
222
+ lines.append('\t\t\t\t\t\t\t<video><samplecharacteristics><width>1920</width><height>1080</height></samplecharacteristics></video>')
223
+ lines.append('\t\t\t\t\t\t\t<audio><samplecharacteristics><depth>16</depth><samplerate>48000</samplerate></samplecharacteristics><channelcount>2</channelcount></audio>')
224
+ lines.append('\t\t\t\t\t\t</media>')
225
+ lines.append('\t\t\t\t\t</file>')
226
+ file_defined = True
227
+ else:
228
+ lines.append(f'\t\t\t\t\t<file id="{master_id}"/>')
229
+
230
+ lines.append('\t\t\t\t\t<marker>')
231
+ lines.append(f'\t\t\t\t\t\t<name>{clip_note}</name>')
232
+ lines.append(f'\t\t\t\t\t\t<in>{src_in_frames}</in>')
233
+ lines.append(f'\t\t\t\t\t\t<out>{src_in_frames}</out>')
234
+ lines.append('\t\t\t\t\t</marker>')
235
+
236
  lines.append('\t\t\t\t</clipitem>')
237
 
238
  gap_frames = seconds_to_frames(float(seg.get('gap', 0.0)), fps)
 
257
  tl_end = tl_start + duration_frames
258
 
259
  lines.append(f'\t\t\t\t<clipitem id="clipitem-a-{i}">')
260
+ lines.append(f'\t\t\t\t\t<name>{source_name}</name>')
261
  lines.append(f'\t\t\t\t\t<masterclipid>{master_id}</masterclipid>')
262
+ lines.append(f'\t\t\t\t\t<duration>8640000</duration>')
263
  lines.append(f'\t\t\t\t\t<rate><timebase>{timebase}</timebase></rate>')
264
  lines.append(f'\t\t\t\t\t<start>{tl_start}</start>')
265
  lines.append(f'\t\t\t\t\t<end>{tl_end}</end>')
266
  lines.append(f'\t\t\t\t\t<in>{src_in_frames}</in>')
267
  lines.append(f'\t\t\t\t\t<out>{src_out_frames}</out>')
268
+ lines.append(f'\t\t\t\t\t<file id="{master_id}"/>')
269
  lines.append('\t\t\t\t\t<sourcetrack><mediatype>audio</mediatype><trackindex>1</trackindex></sourcetrack>')
270
  lines.append('\t\t\t\t</clipitem>')
271
  timeline_head_frames = tl_end + seconds_to_frames(float(seg.get('gap', 0.0)), fps)
 
326
  "gemini-2.5-pro"
327
  ]
328
 
329
+ # Try the v1beta endpoint first as it natively supports systemInstruction and responseMimeType in REST
330
+ endpoints_to_try = ["v1beta", "v1"]
331
  last_error = ""
332
 
333
  for model_name in models_to_try:
 
342
  result_json = res.json()
343
  raw_text = result_json['candidates'][0]['content']['parts'][0]['text']
344
  cleaned_text = clean_json_response(raw_text)
345
+ return json.loads(cleaned_text), model_name, api_version
346
 
347
  # Handle High Demand (503) or Rate Limits (429)
348
  elif res.status_code in [503, 429]:
349
  last_error = f"Model {model_name} busy ({res.status_code}) on {api_version}."
350
  st.warning(f"Debug: {last_error} Skipping to next model...")
351
+ break # Break inner loop: No point trying another endpoint if rate limited. Move to next model.
352
 
353
  # Handle endpoints that don't exist (404) or API rejections (400)
354
  else:
 
358
  error_details = res.text
359
  last_error = f"Model {model_name} rejected request ({res.status_code}) on {api_version}: {error_details}"
360
  st.warning(f"Debug: {last_error} Trying fallback endpoint/model...")
361
+ continue # Try v1, or the next model
362
 
363
  except json.JSONDecodeError:
364
  last_error = f"Model {model_name} returned invalid JSON on {api_version}."
 
375
 
376
  # If the loop finishes without returning, all models failed
377
  st.error(f"All Gemini models failed or are currently experiencing high demand. Last error: {last_error}")
378
+ return None, None, None
379
 
380
  # --- Streamlit UI ---
381
  st.set_page_config(page_title="Junior Editor", layout="wide")
 
540
  # Parse the offset from sidebar input
541
  offset_sec = timecode_to_seconds(source_start_tc, fps)
542
 
543
+ edl_segments, used_model, used_endpoint = call_gemini_for_edl(st.session_state.transcript, brief, ACTIVE_GEMINI_KEY)
544
+
545
  if edl_segments:
546
+ # Create a safe filename without special characters
547
+ safe_filename = "".join([c for c in final_source_name if c.isalnum() or c in (' ', '_', '-')]).strip()
548
+ safe_filename = safe_filename.replace(' ', '_')
549
+ if not safe_filename:
550
+ safe_filename = "junior_editor_cut"
551
+
552
  if export_format == "EDL":
553
+ final_output = generate_cmx_edl(final_source_name, edl_segments, final_source_name, fps, offset_sec)
554
  ext = "edl"
555
  else:
556
+ final_output = generate_xml(final_source_name, edl_segments, final_source_name, fps, offset_sec)
557
  ext = "xml"
558
 
559
  st.subheader("Ready for Import")
560
+ st.success(f"✅ Edit generated successfully using **{used_model}** (via {used_endpoint}).")
561
+
562
  with st.expander("Show XML/EDL Code", expanded=False):
563
  st.code(final_output, language="xml" if ext == "xml" else "text")
564
 
565
+ st.download_button(f"Download .{ext.upper()}", data=final_output, file_name=f"{safe_filename}.{ext}")
 
 
566
 
567