CB commited on
Commit
b1d8f7e
·
verified ·
1 Parent(s): 8085632

Update streamlit_app.py

Browse files
Files changed (1) hide show
  1. streamlit_app.py +52 -23
streamlit_app.py CHANGED
@@ -281,11 +281,20 @@ def get_runtime_api_key():
281
 
282
  # ---- Simplified SDK-first + HTTP-fallback layer ----
283
  def _normalize_model_for_http(model: str) -> str:
 
 
 
 
 
 
 
 
284
  if not model:
285
- return "text-bison@001"
286
- # if user provided "models/..." strip prefix
287
- m = model.split("/", 1)[-1] if model.startswith("models/") else model
288
- return m
 
289
 
290
  def _messages_to_prompt(messages):
291
  if not messages:
@@ -300,10 +309,11 @@ def _messages_to_prompt(messages):
300
  def _http_generate(api_key: str, model: str, prompt: str, max_tokens: int):
301
  host = "https://generativelanguage.googleapis.com"
302
  norm = _normalize_model_for_http(model)
 
303
  candidates = [
304
- f"{host}/v1/models/{norm}:generate",
305
- f"{host}/v1beta3/models/{norm}:generate",
306
- f"{host}/v1beta2/models/{norm}:generate",
307
  ]
308
  payload = {"prompt": {"text": prompt}, "maxOutputTokens": int(max_tokens or 512)}
309
  headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
@@ -316,6 +326,7 @@ def _http_generate(api_key: str, model: str, prompt: str, max_tokens: int):
316
  return r.json()
317
  except Exception:
318
  return {"text": r.text}
 
319
  last_exc = RuntimeError(f"HTTP {r.status_code}: {r.text}")
320
  except Exception as e:
321
  last_exc = e
@@ -358,10 +369,13 @@ def extract_text_from_response(response):
358
  return None
359
  # dict-like (HTTP)
360
  if isinstance(response, dict):
361
- # try common shapes
 
362
  if "candidates" in response and isinstance(response["candidates"], list) and response["candidates"]:
363
  cand = response["candidates"][0]
364
- return cand.get("content") or cand.get("text") or response.get("text")
 
 
365
  if "output" in response and isinstance(response["output"], list):
366
  pieces = []
367
  for item in response["output"]:
@@ -373,7 +387,12 @@ def extract_text_from_response(response):
373
  return "\n\n".join(pieces)
374
  if "text" in response and isinstance(response["text"], str):
375
  return response["text"]
376
- # fallback: join any candidate-like entries
 
 
 
 
 
377
  return None
378
  # object-like (SDK)
379
  try:
@@ -386,7 +405,7 @@ def extract_text_from_response(response):
386
  pieces.append(txt)
387
  if pieces:
388
  return "\n\n".join(pieces)
389
- txt = getattr(response, "text", None)
390
  if txt:
391
  return txt
392
  except Exception:
@@ -395,6 +414,7 @@ def extract_text_from_response(response):
395
 
396
  # ---- end compatibility layer ----
397
 
 
398
  if (st.session_state.get("busy") is False) and ('generate_now' in locals() and generate_now):
399
  if not st.session_state.get("videos"):
400
  st.error("No video loaded. Use 'Load Video' in the sidebar.")
@@ -418,22 +438,26 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
418
 
419
  upload_path = current_path
420
  uploaded = st.session_state.get("uploaded_file")
 
421
  if reupload_needed:
422
  local_path = current_path
423
- fast_mode = st.session_state.get("fast_mode", False)
424
  try:
425
  file_size_mb = os.path.getsize(local_path) / (1024 * 1024)
426
  except Exception:
427
  file_size_mb = 0
428
 
429
- use_compression = st.session_state.get("use_compression", True)
430
  if use_compression and not fast_mode and file_size_mb > 50:
431
  compressed_path = str(Path(local_path).with_name(Path(local_path).stem + "_compressed.mp4"))
432
  try:
433
  preset = "veryfast" if fast_mode else "fast"
434
  upload_path = compress_video(local_path, compressed_path, crf=28, preset=preset)
 
 
435
  except Exception:
436
  upload_path = local_path
 
437
 
438
  if HAS_GENAI and upload_file is not None:
439
  genai.configure(api_key=runtime_key)
@@ -453,13 +477,13 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
453
  uploaded = st.session_state.get("uploaded_file")
454
  processed = st.session_state.get("processed_file")
455
 
456
- prompt_text = (analysis_prompt or default_prompt).strip()
457
  if st.session_state.get("fast_mode"):
458
  model_used = model_arg or "text-bison@001"
459
- max_tokens = min(st.session_state.get("max_output_tokens", 512), 1024)
460
  else:
461
- model_used = model_arg
462
- max_tokens = st.session_state.get("max_output_tokens", 1024)
463
 
464
  # Ensure model_used is a short name (SDK accepts it; HTTP will normalize)
465
  system_msg = {"role": "system", "content": "You are a helpful assistant that summarizes videos concisely in vivid detail."}
@@ -506,12 +530,18 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
506
  st.subheader("Analysis Result")
507
  st.markdown(out or "_(no text returned)_")
508
 
 
509
  try:
510
  if reupload_needed:
511
- if upload_path and Path(upload_path).exists() and Path(upload_path) != Path(current_path):
512
- Path(upload_path).unlink(missing_ok=True)
513
- Path(current_path).unlink(missing_ok=True)
514
- st.session_state["videos"] = ""
 
 
 
 
 
515
  except Exception:
516
  pass
517
 
@@ -560,8 +590,7 @@ with st.sidebar.expander("Manage uploads", expanded=False):
560
  st.session_state["uploaded_file"] = None
561
  st.session_state["processed_file"] = None
562
  st.session_state["last_loaded_path"] = ""
563
- st.session_state["analysis_out"] = ""
564
- st.session_state["file_hash"] = None
565
  try:
566
  fname = file_name_or_id(st.session_state.get("uploaded_file"))
567
  if fname and delete_file and HAS_GENAI:
 
281
 
282
  # ---- Simplified SDK-first + HTTP-fallback layer ----
283
  def _normalize_model_for_http(model: str) -> str:
284
+ """
285
+ Return a model identifier appropriate for the HTTP path.
286
+ Accept inputs like:
287
+ - "text-bison@001" -> "models/text-bison@001"
288
+ - "models/text-bison@001" -> "models/text-bison@001"
289
+ - "models/foo" -> "models/foo"
290
+ - "foo" -> "models/foo"
291
+ """
292
  if not model:
293
+ return "models/text-bison@001"
294
+ m = model.strip()
295
+ if m.startswith("models/"):
296
+ return m
297
+ return f"models/{m}"
298
 
299
  def _messages_to_prompt(messages):
300
  if not messages:
 
309
  def _http_generate(api_key: str, model: str, prompt: str, max_tokens: int):
310
  host = "https://generativelanguage.googleapis.com"
311
  norm = _normalize_model_for_http(model)
312
+ # Try several API paths. norm already contains "models/..."
313
  candidates = [
314
+ f"{host}/v1/{norm}:generate",
315
+ f"{host}/v1beta3/{norm}:generate",
316
+ f"{host}/v1beta2/{norm}:generate",
317
  ]
318
  payload = {"prompt": {"text": prompt}, "maxOutputTokens": int(max_tokens or 512)}
319
  headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
 
326
  return r.json()
327
  except Exception:
328
  return {"text": r.text}
329
+ # Explicit 404 handling: try next candidate
330
  last_exc = RuntimeError(f"HTTP {r.status_code}: {r.text}")
331
  except Exception as e:
332
  last_exc = e
 
369
  return None
370
  # dict-like (HTTP)
371
  if isinstance(response, dict):
372
+ # Try common shapes
373
+ # 1) "candidates": [ { "content": "...", "text": "..." } ]
374
  if "candidates" in response and isinstance(response["candidates"], list) and response["candidates"]:
375
  cand = response["candidates"][0]
376
+ if isinstance(cand, dict):
377
+ return cand.get("content") or cand.get("text") or response.get("text")
378
+ # 2) "output": [ { "content": "..."} ] or "output_text"
379
  if "output" in response and isinstance(response["output"], list):
380
  pieces = []
381
  for item in response["output"]:
 
387
  return "\n\n".join(pieces)
388
  if "text" in response and isinstance(response["text"], str):
389
  return response["text"]
390
+ if "outputText" in response and isinstance(response["outputText"], str):
391
+ return response["outputText"]
392
+ # fallback: try joining string fields
393
+ for k in ("result", "generated_text", "description"):
394
+ if k in response and isinstance(response[k], str):
395
+ return response[k]
396
  return None
397
  # object-like (SDK)
398
  try:
 
405
  pieces.append(txt)
406
  if pieces:
407
  return "\n\n".join(pieces)
408
+ txt = getattr(response, "text", None) or getattr(response, "output_text", None)
409
  if txt:
410
  return txt
411
  except Exception:
 
414
 
415
  # ---- end compatibility layer ----
416
 
417
+ # The main generation block (patched, robust)
418
  if (st.session_state.get("busy") is False) and ('generate_now' in locals() and generate_now):
419
  if not st.session_state.get("videos"):
420
  st.error("No video loaded. Use 'Load Video' in the sidebar.")
 
438
 
439
  upload_path = current_path
440
  uploaded = st.session_state.get("uploaded_file")
441
+ compressed_path = None
442
  if reupload_needed:
443
  local_path = current_path
444
+ fast_mode = bool(st.session_state.get("fast_mode", False))
445
  try:
446
  file_size_mb = os.path.getsize(local_path) / (1024 * 1024)
447
  except Exception:
448
  file_size_mb = 0
449
 
450
+ use_compression = bool(st.session_state.get("use_compression", True))
451
  if use_compression and not fast_mode and file_size_mb > 50:
452
  compressed_path = str(Path(local_path).with_name(Path(local_path).stem + "_compressed.mp4"))
453
  try:
454
  preset = "veryfast" if fast_mode else "fast"
455
  upload_path = compress_video(local_path, compressed_path, crf=28, preset=preset)
456
+ if Path(upload_path) == Path(local_path):
457
+ compressed_path = None
458
  except Exception:
459
  upload_path = local_path
460
+ compressed_path = None
461
 
462
  if HAS_GENAI and upload_file is not None:
463
  genai.configure(api_key=runtime_key)
 
477
  uploaded = st.session_state.get("uploaded_file")
478
  processed = st.session_state.get("processed_file")
479
 
480
+ prompt_text = (analysis_prompt or default_prompt or "").strip()
481
  if st.session_state.get("fast_mode"):
482
  model_used = model_arg or "text-bison@001"
483
+ max_tokens = min(int(st.session_state.get("max_output_tokens", 512)), 1024)
484
  else:
485
+ model_used = model_arg or "text-bison@001"
486
+ max_tokens = int(st.session_state.get("max_output_tokens", 1024))
487
 
488
  # Ensure model_used is a short name (SDK accepts it; HTTP will normalize)
489
  system_msg = {"role": "system", "content": "You are a helpful assistant that summarizes videos concisely in vivid detail."}
 
530
  st.subheader("Analysis Result")
531
  st.markdown(out or "_(no text returned)_")
532
 
533
+ # Clean up compressed temporary file only (don't remove original unless it was a true temp)
534
  try:
535
  if reupload_needed:
536
+ try:
537
+ if compressed_path:
538
+ p = Path(compressed_path)
539
+ if p.exists():
540
+ p.unlink(missing_ok=True)
541
+ except Exception:
542
+ pass
543
+ # don't delete original unless it's intended to be removed (conservative)
544
+ # If you want original removed, enable a setting and handle carefully.
545
  except Exception:
546
  pass
547
 
 
590
  st.session_state["uploaded_file"] = None
591
  st.session_state["processed_file"] = None
592
  st.session_state["last_loaded_path"] = ""
593
+ st.session_state[""] = None
 
594
  try:
595
  fname = file_name_or_id(st.session_state.get("uploaded_file"))
596
  if fname and delete_file and HAS_GENAI: