rairo Claude Opus 4.8 commited on
Commit
5c4d18d
·
1 Parent(s): 0393d8a

Constrain Gemini tutorial timestamps to real video duration

Browse files

Pre-probe the video length and tell Gemini all timestamps must fall
within 0..duration, so it stops inventing segments past the end of the
video (which produced phantom articles with no clip). Also logs the
probed duration/codec before extraction.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files changed (1) hide show
  1. main.py +24 -1
main.py CHANGED
@@ -1242,6 +1242,29 @@ def tutorial_ingest():
1242
  logger.info("[tutorial] STEP 1/5: received '%s' (%.2f MB, mime=%s)",
1243
  video_title, len(video_bytes) / 1024 / 1024, mime_type)
1244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1245
  # Upload to Gemini Files API and wait for processing
1246
  logger.info("[tutorial] STEP 2/5: uploading to Gemini Files API + waiting for ACTIVE...")
1247
  gemini_file = _upload_video_to_gemini(video_bytes, mime_type, display_name=video_title)
@@ -1257,7 +1280,7 @@ def tutorial_ingest():
1257
  t_extract = time.time()
1258
  resp = _gemini_client.models.generate_content(
1259
  model=GEMINI_MODEL,
1260
- contents=[gemini_file, TUTORIAL_VIDEO_PROMPT],
1261
  config=genai_types.GenerateContentConfig(
1262
  response_mime_type="application/json",
1263
  http_options=genai_types.HttpOptions(timeout=GEMINI_VIDEO_TIMEOUT_MS),
 
1242
  logger.info("[tutorial] STEP 1/5: received '%s' (%.2f MB, mime=%s)",
1243
  video_title, len(video_bytes) / 1024 / 1024, mime_type)
1244
 
1245
+ # Probe the real duration up front so we can constrain Gemini's timestamps to it —
1246
+ # otherwise the model sometimes invents segments past the end of the video.
1247
+ vid_dur_hint = 0.0
1248
+ try:
1249
+ with tempfile.NamedTemporaryFile(suffix=ext, delete=False) as _pt:
1250
+ _pt.write(video_bytes)
1251
+ _probe_path = _pt.name
1252
+ vid_dur_hint = _video_duration(_probe_path)
1253
+ logger.info("[tutorial] probed duration %.1fs, codec %s",
1254
+ vid_dur_hint, _video_codec(_probe_path))
1255
+ os.remove(_probe_path)
1256
+ except Exception as e:
1257
+ logger.warning("[tutorial] pre-probe failed: %s", e)
1258
+
1259
+ extraction_prompt = TUTORIAL_VIDEO_PROMPT
1260
+ if vid_dur_hint and vid_dur_hint > 0:
1261
+ extraction_prompt += (
1262
+ f"\n\nIMPORTANT: This video is exactly {int(vid_dur_hint)} seconds long. "
1263
+ f"Every timestamp_start and timestamp_end MUST be between 0 and {int(vid_dur_hint)}. "
1264
+ f"Do not output any timestamp greater than {int(vid_dur_hint)}, and only describe "
1265
+ f"steps that actually occur within the video's length."
1266
+ )
1267
+
1268
  # Upload to Gemini Files API and wait for processing
1269
  logger.info("[tutorial] STEP 2/5: uploading to Gemini Files API + waiting for ACTIVE...")
1270
  gemini_file = _upload_video_to_gemini(video_bytes, mime_type, display_name=video_title)
 
1280
  t_extract = time.time()
1281
  resp = _gemini_client.models.generate_content(
1282
  model=GEMINI_MODEL,
1283
+ contents=[gemini_file, extraction_prompt],
1284
  config=genai_types.GenerateContentConfig(
1285
  response_mime_type="application/json",
1286
  http_options=genai_types.HttpOptions(timeout=GEMINI_VIDEO_TIMEOUT_MS),