CB commited on
Commit
4ed7ca7
·
verified ·
1 Parent(s): eb05733

Update streamlit_app.py

Browse files
Files changed (1) hide show
  1. streamlit_app.py +83 -47
streamlit_app.py CHANGED
@@ -276,7 +276,6 @@ if st.session_state["videos"]:
276
  st.sidebar.caption(f"File size: {file_size_mb:.1f} MB")
277
  if file_size_mb > 50 and not st.session_state.get("fast_mode", False):
278
  st.sidebar.warning("Large file detected — consider enabling Fast mode or compression.", icon="⚠️")
279
- # do not forcibly change user's fast_mode here; just recommend
280
  except Exception:
281
  pass
282
 
@@ -291,14 +290,12 @@ if generate_now and not st.session_state.get("busy"):
291
  else:
292
  try:
293
  st.session_state["busy"] = True
294
- # ensure genai is configured now
295
  try:
296
  if HAS_GENAI and genai is not None:
297
  genai.configure(api_key=key_to_use)
298
  except Exception:
299
  pass
300
 
301
- # recreate/clear agent if key or model changed
302
  model_id = (st.session_state.get("model_input") or "gemini-2.5-flash-lite").strip()
303
  if st.session_state.get("last_model") != model_id:
304
  st.session_state["last_model"] = ""
@@ -352,15 +349,12 @@ if generate_now and not st.session_state.get("busy"):
352
  model_used = model_id
353
  max_tokens = 1024
354
 
355
- # cost/tokens estimate (very rough)
356
  est_tokens = max_tokens
357
  est_cost_caption = f"Est. max tokens: {est_tokens}"
358
 
359
- # Generate via Agent if available
360
  agent = maybe_create_agent(model_used)
361
  if agent:
362
  with st.spinner("Generating description via Agent..."):
363
- # guard processed for agent: must be non-none
364
  if not processed:
365
  raise RuntimeError("Processed file missing for agent generation")
366
  response = agent.run(prompt_text, videos=[processed], safety_settings=safety_settings)
@@ -374,7 +368,8 @@ if generate_now and not st.session_state.get("busy"):
374
  raise RuntimeError("Uploaded file missing name/id")
375
  system_msg = {"role": "system", "content": prompt_text}
376
  user_msg = {"role": "user", "content": "Please summarize the attached video."}
377
- # call responses.generate, handling both signature variants and return shapes
 
378
  try:
379
  response = genai.responses.generate(
380
  model=model_used,
@@ -391,63 +386,104 @@ if generate_now and not st.session_state.get("busy"):
391
  max_output_tokens=max_tokens,
392
  )
393
 
394
- # Normalize outputs to a list of items with .content or dict form
395
  outputs = []
396
  if response is None:
397
  outputs = []
398
  else:
399
- outputs = getattr(response, "output", None) or (response.get("output") if isinstance(response, dict) else None) or []
400
- # Newer API may use 'candidates' or 'items' -- check safely
401
- if not outputs:
402
- # check common alternative keys
403
- if isinstance(response, dict):
404
- if "candidates" in response and isinstance(response["candidates"], list):
405
- outputs = response["candidates"]
406
- elif "items" in response and isinstance(response["items"], list):
407
- outputs = response["items"]
408
- elif "output" in response and isinstance(response["output"], list):
409
- outputs = response["output"]
410
  else:
411
- # attempt attribute access fallbacks
412
- outputs = getattr(response, "candidates", None) or getattr(response, "items", None) or getattr(response, "output", None) or []
413
- # ensure outputs is a list
414
- if outputs is None:
415
- outputs = []
 
 
 
 
 
 
 
 
 
 
 
 
 
416
 
417
  text_pieces = []
 
418
  for item in outputs:
419
- # item may be dict or object
420
- contents = getattr(item, "content", None) or (item.get("content") if isinstance(item, dict) else None)
421
- # some shapes put text directly on item
422
- if contents is None:
423
- # fallback to checking item text or string
424
- txt_direct = getattr(item, "text", None) or (item.get("text") if isinstance(item, dict) else None)
425
- if txt_direct:
426
- text_pieces.append(txt_direct)
 
 
 
 
 
427
  continue
428
- # contents might be list or single dict/object
 
429
  if isinstance(contents, (list, tuple)):
430
- content_iter = contents
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
431
  else:
432
- content_iter = [contents]
433
- for c in content_iter:
434
- ctype = getattr(c, "type", None) or (c.get("type") if isinstance(c, dict) else None)
435
- if ctype in ("output_text", "text") or ctype is None:
436
- txt = getattr(c, "text", None) or (c.get("text") if isinstance(c, dict) else None)
437
- if txt:
438
- text_pieces.append(txt)
439
-
440
- # final fallback: top-level text fields
441
  if not text_pieces:
442
- top_text = getattr(response, "text", None) or (response.get("text") if isinstance(response, dict) else None)
 
 
 
 
443
  if top_text:
444
- text_pieces.append(top_text)
445
 
446
- # dedupe while preserving order
447
  seen = set()
448
  filtered = []
449
  for t in text_pieces:
450
- if t not in seen:
 
 
451
  filtered.append(t)
452
  seen.add(t)
453
  out = "\n\n".join(filtered)
 
276
  st.sidebar.caption(f"File size: {file_size_mb:.1f} MB")
277
  if file_size_mb > 50 and not st.session_state.get("fast_mode", False):
278
  st.sidebar.warning("Large file detected — consider enabling Fast mode or compression.", icon="⚠️")
 
279
  except Exception:
280
  pass
281
 
 
290
  else:
291
  try:
292
  st.session_state["busy"] = True
 
293
  try:
294
  if HAS_GENAI and genai is not None:
295
  genai.configure(api_key=key_to_use)
296
  except Exception:
297
  pass
298
 
 
299
  model_id = (st.session_state.get("model_input") or "gemini-2.5-flash-lite").strip()
300
  if st.session_state.get("last_model") != model_id:
301
  st.session_state["last_model"] = ""
 
349
  model_used = model_id
350
  max_tokens = 1024
351
 
 
352
  est_tokens = max_tokens
353
  est_cost_caption = f"Est. max tokens: {est_tokens}"
354
 
 
355
  agent = maybe_create_agent(model_used)
356
  if agent:
357
  with st.spinner("Generating description via Agent..."):
 
358
  if not processed:
359
  raise RuntimeError("Processed file missing for agent generation")
360
  response = agent.run(prompt_text, videos=[processed], safety_settings=safety_settings)
 
368
  raise RuntimeError("Uploaded file missing name/id")
369
  system_msg = {"role": "system", "content": prompt_text}
370
  user_msg = {"role": "user", "content": "Please summarize the attached video."}
371
+
372
+ # Try the modern and legacy signatures; fail clearly if both fail
373
  try:
374
  response = genai.responses.generate(
375
  model=model_used,
 
386
  max_output_tokens=max_tokens,
387
  )
388
 
389
+ # Normalize response into iterable items safely
390
  outputs = []
391
  if response is None:
392
  outputs = []
393
  else:
394
+ # response might be object or dict; try known attributes/keys
395
+ if isinstance(response, dict):
396
+ # common dict keys
397
+ if isinstance(response.get("output"), list):
398
+ outputs = response.get("output") or []
399
+ elif isinstance(response.get("candidates"), list):
400
+ outputs = response.get("candidates") or []
401
+ elif isinstance(response.get("items"), list):
402
+ outputs = response.get("items") or []
403
+ elif isinstance(response.get("responses"), list):
404
+ outputs = response.get("responses") or []
405
  else:
406
+ # fallback: try to find list-valued entries
407
+ for v in response.values():
408
+ if isinstance(v, list):
409
+ outputs = v
410
+ break
411
+ else:
412
+ # try attribute access
413
+ attr_candidates = []
414
+ for attr in ("output", "candidates", "items", "responses"):
415
+ val = getattr(response, attr, None)
416
+ if isinstance(val, list):
417
+ attr_candidates = val
418
+ break
419
+ outputs = attr_candidates or []
420
+
421
+ # Ensure we have a list
422
+ if not isinstance(outputs, list):
423
+ outputs = list(outputs) if outputs else []
424
 
425
  text_pieces = []
426
+ # Iterate safely through outputs (may be dicts or objects)
427
  for item in outputs:
428
+ if item is None:
429
+ continue
430
+ # attempt to extract a 'content' bag
431
+ contents = None
432
+ if isinstance(item, dict):
433
+ contents = item.get("content") or item.get("text") or item.get("message") or item.get("output")
434
+ else:
435
+ contents = getattr(item, "content", None) or getattr(item, "text", None) or getattr(item, "message", None) or getattr(item, "output", None)
436
+
437
+ # If contents is a single string, take it
438
+ if isinstance(contents, str):
439
+ if contents.strip():
440
+ text_pieces.append(contents.strip())
441
  continue
442
+
443
+ # If contents is list-like, iterate
444
  if isinstance(contents, (list, tuple)):
445
+ for c in contents:
446
+ if c is None:
447
+ continue
448
+ if isinstance(c, str):
449
+ if c.strip():
450
+ text_pieces.append(c.strip())
451
+ continue
452
+ c_text = None
453
+ if isinstance(c, dict):
454
+ c_text = c.get("text") or c.get("content") or None
455
+ else:
456
+ c_text = getattr(c, "text", None) or getattr(c, "content", None)
457
+ if c_text:
458
+ text_pieces.append(str(c_text).strip())
459
+ continue
460
+
461
+ # If the item itself contains direct text fields
462
+ direct_txt = None
463
+ if isinstance(item, dict):
464
+ direct_txt = item.get("text") or item.get("output_text") or item.get("message")
465
  else:
466
+ direct_txt = getattr(item, "text", None) or getattr(item, "output_text", None) or getattr(item, "message", None)
467
+ if direct_txt:
468
+ text_pieces.append(str(direct_txt).strip())
469
+
470
+ # final fallback: top-level text on response
 
 
 
 
471
  if not text_pieces:
472
+ top_text = None
473
+ if isinstance(response, dict):
474
+ top_text = response.get("text") or response.get("message") or None
475
+ else:
476
+ top_text = getattr(response, "text", None) or getattr(response, "message", None)
477
  if top_text:
478
+ text_pieces.append(str(top_text).strip())
479
 
480
+ # dedupe preserving order
481
  seen = set()
482
  filtered = []
483
  for t in text_pieces:
484
+ if not isinstance(t, str):
485
+ continue
486
+ if t and t not in seen:
487
  filtered.append(t)
488
  seen.add(t)
489
  out = "\n\n".join(filtered)