Spaces:
Build error
Build error
CB commited on
Update streamlit_app.py
Browse files- streamlit_app.py +47 -46
streamlit_app.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
# streamlit_app.py
|
| 2 |
import os
|
| 3 |
import time
|
| 4 |
import hashlib
|
|
@@ -216,7 +215,7 @@ st.sidebar.text_input("Video URL", key="url", placeholder="https://")
|
|
| 216 |
settings = st.sidebar.expander("Settings", expanded=False)
|
| 217 |
|
| 218 |
env_key = os.getenv("GOOGLE_API_KEY", "")
|
| 219 |
-
API_KEY_INPUT = settings.text_input("Google API Key (one-time)", value="", type="password"
|
| 220 |
model_input = settings.text_input("Gemini Model (short name)", "gemini-2.0-flash-lite")
|
| 221 |
model_id = model_input.strip() or "gemini-2.0-flash-lite"
|
| 222 |
model_arg = model_id if not model_id.startswith("models/") else model_id.split("/", 1)[1]
|
|
@@ -236,7 +235,7 @@ settings.checkbox("Enable compression for large files (>50MB)", value=True, key=
|
|
| 236 |
settings.number_input("Max output tokens", key="max_output_tokens", value=1024, min_value=128, max_value=8192, step=128)
|
| 237 |
|
| 238 |
if not API_KEY_INPUT and not env_key:
|
| 239 |
-
settings.info("No Google API key provided; upload/generation disabled.
|
| 240 |
|
| 241 |
if st.sidebar.button("Load Video", use_container_width=True):
|
| 242 |
try:
|
|
@@ -298,33 +297,38 @@ def get_runtime_api_key():
|
|
| 298 |
return key
|
| 299 |
return os.getenv("GOOGLE_API_KEY", "").strip() or None
|
| 300 |
|
| 301 |
-
#
|
| 302 |
def responses_generate(model, messages, files, max_output_tokens, api_key):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 303 |
genai.configure(api_key=api_key)
|
| 304 |
-
# preferred SDK
|
| 305 |
if hasattr(genai, "responses") and getattr(genai, "responses") is not None:
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
except Exception:
|
| 309 |
-
# let higher level handle retries/errors
|
| 310 |
-
raise
|
| 311 |
-
# older/newer SDKs might expose different helpers; attempt generic client POST
|
| 312 |
-
# fallback: directly call the REST endpoint via genai.client/_client if available
|
| 313 |
client_attr = getattr(genai, "client", None) or getattr(genai, "_client", None) or getattr(genai, "transport", None)
|
| 314 |
if client_attr:
|
| 315 |
-
|
| 316 |
-
|
| 317 |
payload = {"model": model, "messages": messages, "max_output_tokens": max_output_tokens}
|
| 318 |
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
if post:
|
| 322 |
-
# endpoint path used by Google Generative API
|
| 323 |
-
url = "/v1/responses"
|
| 324 |
-
resp = post(url, json=payload, headers=headers)
|
| 325 |
return resp
|
| 326 |
-
|
| 327 |
-
|
| 328 |
raise RuntimeError("genai.responses not available and HTTP fallback failed")
|
| 329 |
|
| 330 |
if (st.session_state.get("busy") is False) and ('generate_now' in locals() and generate_now):
|
|
@@ -334,8 +338,6 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
|
|
| 334 |
runtime_key = get_runtime_api_key()
|
| 335 |
if not runtime_key:
|
| 336 |
st.error("Google API key not set. Provide in Settings or set GOOGLE_API_KEY in environment.")
|
| 337 |
-
elif not HAS_GENAI:
|
| 338 |
-
st.error("google.generativeai SDK not available. Install the SDK to enable uploads/generation.")
|
| 339 |
else:
|
| 340 |
try:
|
| 341 |
st.session_state["busy"] = True
|
|
@@ -369,14 +371,21 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
|
|
| 369 |
except Exception:
|
| 370 |
upload_path = local_path
|
| 371 |
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
else:
|
| 381 |
uploaded = st.session_state.get("uploaded_file")
|
| 382 |
processed = st.session_state.get("processed_file")
|
|
@@ -395,7 +404,8 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
|
|
| 395 |
def call_responses_once(model_used, system_msg, user_msg, fname, max_tokens):
|
| 396 |
for attempt in range(2):
|
| 397 |
try:
|
| 398 |
-
|
|
|
|
| 399 |
return resp
|
| 400 |
except Exception:
|
| 401 |
if attempt == 0:
|
|
@@ -404,26 +414,17 @@ if (st.session_state.get("busy") is False) and ('generate_now' in locals() and g
|
|
| 404 |
raise
|
| 405 |
|
| 406 |
fname = file_name_or_id(processed) or file_name_or_id(uploaded)
|
| 407 |
-
if not fname:
|
| 408 |
-
try:
|
| 409 |
-
uri = getattr(processed, "uri", None) or (processed.get("uri") if isinstance(processed, dict) else None)
|
| 410 |
-
if uri:
|
| 411 |
-
tail = str(uri).rstrip("/").split("/")[-1]
|
| 412 |
-
fname = tail if tail.startswith("files/") else f"files/{tail}"
|
| 413 |
-
except Exception:
|
| 414 |
-
pass
|
| 415 |
-
if not fname:
|
| 416 |
-
raise RuntimeError("Uploaded file missing name/id/uri; cannot reference for Responses API.")
|
| 417 |
-
|
| 418 |
response = call_responses_once(model_used, system_msg, user_msg, fname, max_tokens)
|
| 419 |
|
| 420 |
def extract_text_from_response(response):
|
| 421 |
outputs = getattr(response, "output", None) or (response.get("output") if isinstance(response, dict) else None) or []
|
| 422 |
-
if
|
| 423 |
-
outputs =
|
| 424 |
text_pieces = []
|
| 425 |
for item in outputs or []:
|
| 426 |
contents = getattr(item, "content", None) or (item.get("content") if isinstance(item, dict) else None) or []
|
|
|
|
|
|
|
| 427 |
for c in contents:
|
| 428 |
ctype = getattr(c, "type", None) or (c.get("type") if isinstance(c, dict) else None)
|
| 429 |
if ctype in ("output_text", "text") or ctype is None:
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
import time
|
| 3 |
import hashlib
|
|
|
|
| 215 |
settings = st.sidebar.expander("Settings", expanded=False)
|
| 216 |
|
| 217 |
env_key = os.getenv("GOOGLE_API_KEY", "")
|
| 218 |
+
API_KEY_INPUT = settings.text_input("Google API Key (one-time)", value="", type="password")
|
| 219 |
model_input = settings.text_input("Gemini Model (short name)", "gemini-2.0-flash-lite")
|
| 220 |
model_id = model_input.strip() or "gemini-2.0-flash-lite"
|
| 221 |
model_arg = model_id if not model_id.startswith("models/") else model_id.split("/", 1)[1]
|
|
|
|
| 235 |
settings.number_input("Max output tokens", key="max_output_tokens", value=1024, min_value=128, max_value=8192, step=128)
|
| 236 |
|
| 237 |
if not API_KEY_INPUT and not env_key:
|
| 238 |
+
settings.info("No Google API key provided; upload/generation disabled.", icon="ℹ️")
|
| 239 |
|
| 240 |
if st.sidebar.button("Load Video", use_container_width=True):
|
| 241 |
try:
|
|
|
|
| 297 |
return key
|
| 298 |
return os.getenv("GOOGLE_API_KEY", "").strip() or None
|
| 299 |
|
| 300 |
+
# Robust responses caller: SDK preferred, then attempt HTTP fallback via requests
|
| 301 |
def responses_generate(model, messages, files, max_output_tokens, api_key):
|
| 302 |
+
if not api_key:
|
| 303 |
+
raise RuntimeError("No API key for responses_generate")
|
| 304 |
+
if not HAS_GENAI:
|
| 305 |
+
# try HTTP directly using requests
|
| 306 |
+
import requests
|
| 307 |
+
url = "https://gen-ai.googleapis.com/v1/responses"
|
| 308 |
+
payload = {"model": model, "messages": messages, "max_output_tokens": max_output_tokens}
|
| 309 |
+
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
|
| 310 |
+
try:
|
| 311 |
+
r = requests.post(url, json=payload, headers=headers, timeout=60)
|
| 312 |
+
r.raise_for_status()
|
| 313 |
+
return r.json()
|
| 314 |
+
except Exception as e:
|
| 315 |
+
raise RuntimeError(f"HTTP fallback to Responses API failed: {e}")
|
| 316 |
genai.configure(api_key=api_key)
|
| 317 |
+
# preferred SDK call
|
| 318 |
if hasattr(genai, "responses") and getattr(genai, "responses") is not None:
|
| 319 |
+
return genai.responses.generate(model=model, messages=messages, files=files, max_output_tokens=max_output_tokens)
|
| 320 |
+
# try client-level post if exposed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
client_attr = getattr(genai, "client", None) or getattr(genai, "_client", None) or getattr(genai, "transport", None)
|
| 322 |
if client_attr:
|
| 323 |
+
post = getattr(client_attr, "post", None) or getattr(client_attr, "request", None)
|
| 324 |
+
if post:
|
| 325 |
payload = {"model": model, "messages": messages, "max_output_tokens": max_output_tokens}
|
| 326 |
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
|
| 327 |
+
try:
|
| 328 |
+
resp = post("/v1/responses", json=payload, headers=headers)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 329 |
return resp
|
| 330 |
+
except Exception:
|
| 331 |
+
pass
|
| 332 |
raise RuntimeError("genai.responses not available and HTTP fallback failed")
|
| 333 |
|
| 334 |
if (st.session_state.get("busy") is False) and ('generate_now' in locals() and generate_now):
|
|
|
|
| 338 |
runtime_key = get_runtime_api_key()
|
| 339 |
if not runtime_key:
|
| 340 |
st.error("Google API key not set. Provide in Settings or set GOOGLE_API_KEY in environment.")
|
|
|
|
|
|
|
| 341 |
else:
|
| 342 |
try:
|
| 343 |
st.session_state["busy"] = True
|
|
|
|
| 371 |
except Exception:
|
| 372 |
upload_path = local_path
|
| 373 |
|
| 374 |
+
if HAS_GENAI and upload_file is not None:
|
| 375 |
+
genai.configure(api_key=runtime_key)
|
| 376 |
+
with st.spinner("Uploading video..."):
|
| 377 |
+
uploaded = upload_video_sdk(upload_path)
|
| 378 |
+
processed = wait_for_processed(uploaded, timeout=600)
|
| 379 |
+
st.session_state["uploaded_file"] = uploaded
|
| 380 |
+
st.session_state["processed_file"] = processed
|
| 381 |
+
st.session_state["last_loaded_path"] = current_path
|
| 382 |
+
st.session_state["file_hash"] = current_hash
|
| 383 |
+
else:
|
| 384 |
+
# no SDK upload support: continue without upload and try HTTP responses with no file reference
|
| 385 |
+
uploaded = None
|
| 386 |
+
processed = None
|
| 387 |
+
st.session_state["uploaded_file"] = None
|
| 388 |
+
st.session_state["processed_file"] = None
|
| 389 |
else:
|
| 390 |
uploaded = st.session_state.get("uploaded_file")
|
| 391 |
processed = st.session_state.get("processed_file")
|
|
|
|
| 404 |
def call_responses_once(model_used, system_msg, user_msg, fname, max_tokens):
|
| 405 |
for attempt in range(2):
|
| 406 |
try:
|
| 407 |
+
files = [{"name": fname}] if fname else None
|
| 408 |
+
resp = responses_generate(model_used, [system_msg, user_msg], files, max_tokens, api_key=runtime_key)
|
| 409 |
return resp
|
| 410 |
except Exception:
|
| 411 |
if attempt == 0:
|
|
|
|
| 414 |
raise
|
| 415 |
|
| 416 |
fname = file_name_or_id(processed) or file_name_or_id(uploaded)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
response = call_responses_once(model_used, system_msg, user_msg, fname, max_tokens)
|
| 418 |
|
| 419 |
def extract_text_from_response(response):
|
| 420 |
outputs = getattr(response, "output", None) or (response.get("output") if isinstance(response, dict) else None) or []
|
| 421 |
+
if isinstance(outputs, dict):
|
| 422 |
+
outputs = outputs.get("contents") or outputs.get("items") or []
|
| 423 |
text_pieces = []
|
| 424 |
for item in outputs or []:
|
| 425 |
contents = getattr(item, "content", None) or (item.get("content") if isinstance(item, dict) else None) or []
|
| 426 |
+
if isinstance(contents, dict):
|
| 427 |
+
contents = [contents]
|
| 428 |
for c in contents:
|
| 429 |
ctype = getattr(c, "type", None) or (c.get("type") if isinstance(c, dict) else None)
|
| 430 |
if ctype in ("output_text", "text") or ctype is None:
|