CB commited on
Commit
e61ff31
·
verified ·
1 Parent(s): ae82b95

Update streamlit_app.py

Browse files
Files changed (1) hide show
  1. streamlit_app.py +75 -19
streamlit_app.py CHANGED
@@ -52,6 +52,7 @@ st.session_state.setdefault("api_key", os.getenv("GOOGLE_API_KEY", ""))
52
  st.session_state.setdefault("last_model", "")
53
  st.session_state.setdefault("upload_progress", {"uploaded": 0, "total": 0})
54
  st.session_state.setdefault("last_url_value", "")
 
55
 
56
  def sanitize_filename(path_str: str):
57
  name = Path(path_str).name
@@ -77,7 +78,9 @@ def convert_video_to_mp4(video_path: str) -> str:
77
 
78
  def compress_video(input_path: str, target_path: str, crf: int = 28, preset: str = "fast"):
79
  try:
80
- ffmpeg.input(input_path).output(target_path, vcodec="libx264", crf=crf, preset=preset).run(overwrite_output=True, quiet=True)
 
 
81
  return target_path
82
  except Exception:
83
  return input_path
@@ -170,6 +173,16 @@ default_prompt = (
170
  analysis_prompt = settings_exp.text_area("Enter analysis", value=default_prompt, height=140)
171
  settings_exp.text_input("Video Password (if needed)", key="video-password", placeholder="password", type="password")
172
 
 
 
 
 
 
 
 
 
 
 
173
  key_source = "session" if st.session_state.get("api_key") else ".env" if os.getenv("GOOGLE_API_KEY") else "none"
174
  settings_exp.caption(f"Using API key from: **{key_source}**")
175
 
@@ -192,7 +205,15 @@ def upload_video_sdk(filepath: str):
192
  genai.configure(api_key=key)
193
  return upload_file(filepath)
194
 
195
- def wait_for_processed(file_obj, timeout=180):
 
 
 
 
 
 
 
 
196
  if not HAS_GENAI or get_file is None:
197
  return file_obj
198
  start = time.time()
@@ -200,13 +221,24 @@ def wait_for_processed(file_obj, timeout=180):
200
  if not name:
201
  return file_obj
202
  backoff = 1.0
 
203
  while True:
204
- obj = get_file(name)
 
 
 
 
 
 
 
 
 
205
  state = getattr(obj, "state", None)
206
  if not state or getattr(state, "name", None) != "PROCESSING":
207
  return obj
 
208
  if time.time() - start > timeout:
209
- raise TimeoutError("File processing timed out")
210
  time.sleep(backoff)
211
  backoff = min(backoff * 2, 8.0)
212
 
@@ -230,17 +262,29 @@ def remove_prompt_echo(prompt: str, text: str, check_len: int = 600, ratio_thres
230
  return text
231
 
232
  def compress_video_if_large(local_path: str, threshold_mb: int = 50):
 
 
 
 
 
233
  try:
234
  file_size_mb = os.path.getsize(local_path) / (1024 * 1024)
235
- except Exception:
236
- return local_path
 
 
237
  if file_size_mb <= threshold_mb:
238
- return local_path
 
239
  compressed_path = str(Path(local_path).with_name(Path(local_path).stem + "_compressed.mp4"))
240
  try:
241
- return compress_video(local_path, compressed_path, crf=28, preset="fast")
242
- except Exception:
243
- return local_path
 
 
 
 
244
 
245
  def generate_via_responses_api(prompt_text: str, processed, model_used: str, max_tokens: int = 1024):
246
  key = get_effective_api_key()
@@ -446,15 +490,27 @@ if generate_now and not st.session_state.get("busy"):
446
  if not HAS_GENAI:
447
  raise RuntimeError("google.generativeai SDK not available; install it.")
448
  local_path = current_path
449
- upload_path = compress_video_if_large(local_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
 
451
- with st.spinner("Uploading video..."):
452
- uploaded = upload_video_sdk(upload_path)
453
- processed = wait_for_processed(uploaded, timeout=180)
454
- st.session_state["uploaded_file"] = uploaded
455
- st.session_state["processed_file"] = processed
456
- st.session_state["last_loaded_path"] = current_path
457
- st.session_state["file_hash"] = current_hash
458
 
459
  prompt_text = (analysis_prompt.strip() or default_prompt).strip()
460
  out = ""
@@ -523,7 +579,7 @@ if generate_now and not st.session_state.get("busy"):
523
 
524
  except Exception as e:
525
  tb = traceback.format_exc()
526
- st.session_state["last_error"] = f"{e}\n\nDebug: {locals().get('debug_info', debug_info)}\n\nTraceback:\n{tb}"
527
  st.error("An error occurred while generating the story. You can try Generate again; the uploaded video will be reused.")
528
  finally:
529
  st.session_state["busy"] = False
 
52
  st.session_state.setdefault("last_model", "")
53
  st.session_state.setdefault("upload_progress", {"uploaded": 0, "total": 0})
54
  st.session_state.setdefault("last_url_value", "")
55
+ st.session_state.setdefault("processing_timeout", 600) # default 10 minutes
56
 
57
  def sanitize_filename(path_str: str):
58
  name = Path(path_str).name
 
78
 
79
  def compress_video(input_path: str, target_path: str, crf: int = 28, preset: str = "fast"):
80
  try:
81
+ ffmpeg.input(input_path).output(
82
+ target_path, vcodec="libx264", crf=crf, preset=preset
83
+ ).run(overwrite_output=True, quiet=True)
84
  return target_path
85
  except Exception:
86
  return input_path
 
173
  analysis_prompt = settings_exp.text_area("Enter analysis", value=default_prompt, height=140)
174
  settings_exp.text_input("Video Password (if needed)", key="video-password", placeholder="password", type="password")
175
 
176
+ # Expose processing timeout
177
+ settings_exp.number_input(
178
+ "Processing timeout (s)",
179
+ min_value=60,
180
+ max_value=3600,
181
+ value=st.session_state.get("processing_timeout", 600),
182
+ step=30,
183
+ key="processing_timeout",
184
+ )
185
+
186
  key_source = "session" if st.session_state.get("api_key") else ".env" if os.getenv("GOOGLE_API_KEY") else "none"
187
  settings_exp.caption(f"Using API key from: **{key_source}**")
188
 
 
205
  genai.configure(api_key=key)
206
  return upload_file(filepath)
207
 
208
+ def wait_for_processed(file_obj, timeout: int = None):
209
+ """
210
+ Poll get_file until file is no longer in PROCESSING state.
211
+ Uses st.session_state['processing_timeout'] if timeout is None.
212
+ Retries on transient get_file errors with exponential backoff.
213
+ Raises TimeoutError on timeout.
214
+ """
215
+ if timeout is None:
216
+ timeout = st.session_state.get("processing_timeout", 600)
217
  if not HAS_GENAI or get_file is None:
218
  return file_obj
219
  start = time.time()
 
221
  if not name:
222
  return file_obj
223
  backoff = 1.0
224
+ last_exc = None
225
  while True:
226
+ try:
227
+ obj = get_file(name)
228
+ except Exception as e:
229
+ last_exc = e
230
+ if time.time() - start > timeout:
231
+ raise TimeoutError(f"Failed to fetch file status before timeout: {e}")
232
+ time.sleep(backoff)
233
+ backoff = min(backoff * 2, 8.0)
234
+ continue
235
+
236
  state = getattr(obj, "state", None)
237
  if not state or getattr(state, "name", None) != "PROCESSING":
238
  return obj
239
+
240
  if time.time() - start > timeout:
241
+ raise TimeoutError(f"File processing timed out after {int(time.time() - start)}s")
242
  time.sleep(backoff)
243
  backoff = min(backoff * 2, 8.0)
244
 
 
262
  return text
263
 
264
  def compress_video_if_large(local_path: str, threshold_mb: int = 50):
265
+ """
266
+ Returns (path_to_upload, compressed_flag).
267
+ If compression fails or isn't needed returns (local_path, False).
268
+ Logs errors to st.session_state['last_error'].
269
+ """
270
  try:
271
  file_size_mb = os.path.getsize(local_path) / (1024 * 1024)
272
+ except Exception as e:
273
+ st.session_state["last_error"] = f"Failed to stat file before compression: {e}"
274
+ return local_path, False
275
+
276
  if file_size_mb <= threshold_mb:
277
+ return local_path, False
278
+
279
  compressed_path = str(Path(local_path).with_name(Path(local_path).stem + "_compressed.mp4"))
280
  try:
281
+ result = compress_video(local_path, compressed_path, crf=28, preset="fast")
282
+ if result and os.path.exists(result):
283
+ return result, True
284
+ return local_path, False
285
+ except Exception as e:
286
+ st.session_state["last_error"] = f"Video compression failed: {e}\n{traceback.format_exc()}"
287
+ return local_path, False
288
 
289
  def generate_via_responses_api(prompt_text: str, processed, model_used: str, max_tokens: int = 1024):
290
  key = get_effective_api_key()
 
490
  if not HAS_GENAI:
491
  raise RuntimeError("google.generativeai SDK not available; install it.")
492
  local_path = current_path
493
+ upload_path, compressed = compress_video_if_large(local_path)
494
+
495
+ with st.spinner(f"Uploading video{' (compressed)' if compressed else ''}..."):
496
+ try:
497
+ uploaded = upload_video_sdk(upload_path)
498
+ except Exception as e:
499
+ st.session_state["last_error"] = f"Upload failed: {e}\n\nTraceback:\n{traceback.format_exc()}"
500
+ st.error("Upload failed. See Last Error for details.")
501
+ raise
502
+
503
+ try:
504
+ processed = wait_for_processed(uploaded, timeout=st.session_state.get("processing_timeout", 600))
505
+ except Exception as e:
506
+ st.session_state["last_error"] = f"Processing failed/wait timeout: {e}\n\nTraceback:\n{traceback.format_exc()}"
507
+ st.error("Video processing failed or timed out. See Last Error.")
508
+ raise
509
 
510
+ st.session_state["uploaded_file"] = uploaded
511
+ st.session_state["processed_file"] = processed
512
+ st.session_state["last_loaded_path"] = current_path
513
+ st.session_state["file_hash"] = current_hash
 
 
 
514
 
515
  prompt_text = (analysis_prompt.strip() or default_prompt).strip()
516
  out = ""
 
579
 
580
  except Exception as e:
581
  tb = traceback.format_exc()
582
+ st.session_state["last_error"] = f"{e}\n\nDebug: {locals().get('debug_info', {})}\n\nTraceback:\n{tb}"
583
  st.error("An error occurred while generating the story. You can try Generate again; the uploaded video will be reused.")
584
  finally:
585
  st.session_state["busy"] = False