Spaces:
Sleeping
Sleeping
CB commited on
Update streamlit_app.py
Browse files- streamlit_app.py +14 -32
streamlit_app.py
CHANGED
|
@@ -198,9 +198,9 @@ API_KEY_INPUT = settings.text_input("Google API Key (one-time)", value="", type=
|
|
| 198 |
# Default model changed to text-bison@001 (broadly available). Replace if you have another.
|
| 199 |
model_input = settings.text_input("Model (short name)", "text-bison@001")
|
| 200 |
model_id = model_input.strip() or "text-bison@001"
|
| 201 |
-
# model_arg used with SDK;
|
| 202 |
-
model_arg = model_id
|
| 203 |
-
model_for_url_default = model_arg
|
| 204 |
|
| 205 |
default_prompt = (
|
| 206 |
"You are an Indoor Human Behavior Analyzer. Watch the video and produce a detailed, evidence‑based behavioral report focused on human actions, "
|
|
@@ -282,19 +282,16 @@ def get_runtime_api_key():
|
|
| 282 |
# ---- Simplified SDK-first + HTTP-fallback layer ----
|
| 283 |
def _normalize_model_for_http(model: str) -> str:
|
| 284 |
"""
|
| 285 |
-
Return a model
|
| 286 |
-
|
| 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 "
|
| 294 |
m = model.strip()
|
|
|
|
| 295 |
if m.startswith("models/"):
|
| 296 |
-
return m
|
| 297 |
-
return
|
| 298 |
|
| 299 |
def _messages_to_prompt(messages):
|
| 300 |
if not messages:
|
|
@@ -309,11 +306,10 @@ def _messages_to_prompt(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,7 +322,6 @@ def _http_generate(api_key: str, model: str, prompt: str, max_tokens: int):
|
|
| 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
|
|
@@ -346,7 +341,6 @@ def responses_generate(model, messages, files, max_output_tokens, api_key):
|
|
| 346 |
sdk_kwargs["files"] = files
|
| 347 |
return responses_obj.generate(**sdk_kwargs)
|
| 348 |
except Exception:
|
| 349 |
-
# fall through to HTTP fallback
|
| 350 |
pass
|
| 351 |
# HTTP fallback
|
| 352 |
prompt = _messages_to_prompt(messages)
|
|
@@ -367,15 +361,11 @@ def call_responses_once(model_used, system_msg, user_msg, fname, max_tokens):
|
|
| 367 |
def extract_text_from_response(response):
|
| 368 |
if response is None:
|
| 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"]:
|
|
@@ -389,12 +379,10 @@ def extract_text_from_response(response):
|
|
| 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:
|
| 399 |
outputs = getattr(response, "output", None) or getattr(response, "candidates", None)
|
| 400 |
if outputs:
|
|
@@ -414,7 +402,6 @@ def extract_text_from_response(response):
|
|
| 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.")
|
|
@@ -485,7 +472,6 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
|
|
| 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."}
|
| 490 |
user_msg = {"role": "user", "content": prompt_text}
|
| 491 |
|
|
@@ -494,7 +480,6 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
|
|
| 494 |
|
| 495 |
out = extract_text_from_response(response)
|
| 496 |
|
| 497 |
-
# Try to read token info if present
|
| 498 |
meta = getattr(response, "metrics", None) or (response.get("metrics") if isinstance(response, dict) else None) or {}
|
| 499 |
output_tokens = 0
|
| 500 |
try:
|
|
@@ -505,7 +490,6 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
|
|
| 505 |
except Exception:
|
| 506 |
output_tokens = 0
|
| 507 |
|
| 508 |
-
# Retry strategies if no output
|
| 509 |
if (not out or output_tokens == 0) and model_used:
|
| 510 |
retry_prompt = "Summarize the video content briefly and vividly (2-4 paragraphs)."
|
| 511 |
try:
|
|
@@ -530,7 +514,6 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
|
|
| 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:
|
|
@@ -540,8 +523,6 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
|
|
| 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,7 +571,8 @@ with st.sidebar.expander("Manage uploads", expanded=False):
|
|
| 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[""] =
|
|
|
|
| 594 |
try:
|
| 595 |
fname = file_name_or_id(st.session_state.get("uploaded_file"))
|
| 596 |
if fname and delete_file and HAS_GENAI:
|
|
|
|
| 198 |
# Default model changed to text-bison@001 (broadly available). Replace if you have another.
|
| 199 |
model_input = settings.text_input("Model (short name)", "text-bison@001")
|
| 200 |
model_id = model_input.strip() or "text-bison@001"
|
| 201 |
+
# model_arg used with SDK; keep as short name like "text-bison@001"
|
| 202 |
+
model_arg = model_id
|
| 203 |
+
model_for_url_default = model_arg
|
| 204 |
|
| 205 |
default_prompt = (
|
| 206 |
"You are an Indoor Human Behavior Analyzer. Watch the video and produce a detailed, evidence‑based behavioral report focused on human actions, "
|
|
|
|
| 282 |
# ---- Simplified SDK-first + HTTP-fallback layer ----
|
| 283 |
def _normalize_model_for_http(model: str) -> str:
|
| 284 |
"""
|
| 285 |
+
Return a short model name appropriate for the HTTP path,
|
| 286 |
+
e.g. "text-bison@001" (no "models/" prefix).
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
"""
|
| 288 |
if not model:
|
| 289 |
+
return "text-bison@001"
|
| 290 |
m = model.strip()
|
| 291 |
+
# If user mistakenly provided "models/..." strip the prefix for HTTP path
|
| 292 |
if m.startswith("models/"):
|
| 293 |
+
return m.split("/", 1)[1]
|
| 294 |
+
return m
|
| 295 |
|
| 296 |
def _messages_to_prompt(messages):
|
| 297 |
if not messages:
|
|
|
|
| 306 |
def _http_generate(api_key: str, model: str, prompt: str, max_tokens: int):
|
| 307 |
host = "https://generativelanguage.googleapis.com"
|
| 308 |
norm = _normalize_model_for_http(model)
|
|
|
|
| 309 |
candidates = [
|
| 310 |
+
f"{host}/v1/models/{norm}:generate",
|
| 311 |
+
f"{host}/v1beta3/models/{norm}:generate",
|
| 312 |
+
f"{host}/v1beta2/models/{norm}:generate",
|
| 313 |
]
|
| 314 |
payload = {"prompt": {"text": prompt}, "maxOutputTokens": int(max_tokens or 512)}
|
| 315 |
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
|
|
|
|
| 322 |
return r.json()
|
| 323 |
except Exception:
|
| 324 |
return {"text": r.text}
|
|
|
|
| 325 |
last_exc = RuntimeError(f"HTTP {r.status_code}: {r.text}")
|
| 326 |
except Exception as e:
|
| 327 |
last_exc = e
|
|
|
|
| 341 |
sdk_kwargs["files"] = files
|
| 342 |
return responses_obj.generate(**sdk_kwargs)
|
| 343 |
except Exception:
|
|
|
|
| 344 |
pass
|
| 345 |
# HTTP fallback
|
| 346 |
prompt = _messages_to_prompt(messages)
|
|
|
|
| 361 |
def extract_text_from_response(response):
|
| 362 |
if response is None:
|
| 363 |
return None
|
|
|
|
| 364 |
if isinstance(response, dict):
|
|
|
|
|
|
|
| 365 |
if "candidates" in response and isinstance(response["candidates"], list) and response["candidates"]:
|
| 366 |
cand = response["candidates"][0]
|
| 367 |
if isinstance(cand, dict):
|
| 368 |
return cand.get("content") or cand.get("text") or response.get("text")
|
|
|
|
| 369 |
if "output" in response and isinstance(response["output"], list):
|
| 370 |
pieces = []
|
| 371 |
for item in response["output"]:
|
|
|
|
| 379 |
return response["text"]
|
| 380 |
if "outputText" in response and isinstance(response["outputText"], str):
|
| 381 |
return response["outputText"]
|
|
|
|
| 382 |
for k in ("result", "generated_text", "description"):
|
| 383 |
if k in response and isinstance(response[k], str):
|
| 384 |
return response[k]
|
| 385 |
return None
|
|
|
|
| 386 |
try:
|
| 387 |
outputs = getattr(response, "output", None) or getattr(response, "candidates", None)
|
| 388 |
if outputs:
|
|
|
|
| 402 |
|
| 403 |
# ---- end compatibility layer ----
|
| 404 |
|
|
|
|
| 405 |
if (st.session_state.get("busy") is False) and ('generate_now' in locals() and generate_now):
|
| 406 |
if not st.session_state.get("videos"):
|
| 407 |
st.error("No video loaded. Use 'Load Video' in the sidebar.")
|
|
|
|
| 472 |
model_used = model_arg or "text-bison@001"
|
| 473 |
max_tokens = int(st.session_state.get("max_output_tokens", 1024))
|
| 474 |
|
|
|
|
| 475 |
system_msg = {"role": "system", "content": "You are a helpful assistant that summarizes videos concisely in vivid detail."}
|
| 476 |
user_msg = {"role": "user", "content": prompt_text}
|
| 477 |
|
|
|
|
| 480 |
|
| 481 |
out = extract_text_from_response(response)
|
| 482 |
|
|
|
|
| 483 |
meta = getattr(response, "metrics", None) or (response.get("metrics") if isinstance(response, dict) else None) or {}
|
| 484 |
output_tokens = 0
|
| 485 |
try:
|
|
|
|
| 490 |
except Exception:
|
| 491 |
output_tokens = 0
|
| 492 |
|
|
|
|
| 493 |
if (not out or output_tokens == 0) and model_used:
|
| 494 |
retry_prompt = "Summarize the video content briefly and vividly (2-4 paragraphs)."
|
| 495 |
try:
|
|
|
|
| 514 |
st.subheader("Analysis Result")
|
| 515 |
st.markdown(out or "_(no text returned)_")
|
| 516 |
|
|
|
|
| 517 |
try:
|
| 518 |
if reupload_needed:
|
| 519 |
try:
|
|
|
|
| 523 |
p.unlink(missing_ok=True)
|
| 524 |
except Exception:
|
| 525 |
pass
|
|
|
|
|
|
|
| 526 |
except Exception:
|
| 527 |
pass
|
| 528 |
|
|
|
|
| 571 |
st.session_state["uploaded_file"] = None
|
| 572 |
st.session_state["processed_file"] = None
|
| 573 |
st.session_state["last_loaded_path"] = ""
|
| 574 |
+
st.session_state["analysis_out"] = ""
|
| 575 |
+
st.session_state["file_hash"] = None
|
| 576 |
try:
|
| 577 |
fname = file_name_or_id(st.session_state.get("uploaded_file"))
|
| 578 |
if fname and delete_file and HAS_GENAI:
|