CB commited on
Commit
534bb58
·
verified ·
1 Parent(s): 5947544

Update streamlit_app.py

Browse files
Files changed (1) hide show
  1. streamlit_app.py +96 -33
streamlit_app.py CHANGED
@@ -4,6 +4,7 @@ import time
4
  import string
5
  import hashlib
6
  import traceback
 
7
  from glob import glob
8
  from pathlib import Path
9
  from difflib import SequenceMatcher
@@ -18,13 +19,18 @@ from dotenv import load_dotenv
18
 
19
  load_dotenv()
20
 
21
- # phi agent removed to avoid fragile imports in varied environments
22
  HAS_PHI = False
23
 
24
  # google generative ai SDK (may be absent or partial in some runtimes)
25
  try:
26
  import google.generativeai as genai # type: ignore
27
- from google.generativeai import upload_file, get_file # type: ignore
 
 
 
 
 
28
  HAS_GENAI = True
29
  except Exception:
30
  genai = None
@@ -117,7 +123,6 @@ def maybe_configure_genai(key):
117
  if not key or not HAS_GENAI:
118
  return False
119
  try:
120
- # defensive configuration (some envs require configure)
121
  genai.configure(api_key=key)
122
  return True
123
  except Exception:
@@ -137,7 +142,7 @@ def clear_all_video_state():
137
  except Exception:
138
  pass
139
 
140
- # URL expand + extraction helpers (integrated into Load Video)
141
  def expand_url(short_url, timeout=10):
142
  try:
143
  r = requests.get(short_url, allow_redirects=True, timeout=timeout, headers={"User-Agent":"Mozilla/5.0"})
@@ -148,50 +153,41 @@ def expand_url(short_url, timeout=10):
148
 
149
  def extract_video_from_html(html, base_url=None):
150
  soup = BeautifulSoup(html, "html.parser")
151
- # 1) Open Graph video
152
  og = soup.find("meta", property="og:video")
153
  if og and og.get("content"):
154
  return og.get("content")
155
- # 2) Look for video tags
156
  vtag = soup.find("video")
157
  if vtag:
158
  src = vtag.get("src")
159
  if src:
160
  return src
161
- # source children
162
  source = vtag.find("source")
163
  if source and source.get("src"):
164
  return source.get("src")
165
- # 3) JSON-LD or structured data with video
166
  for script in soup.find_all("script", type="application/ld+json"):
167
  try:
168
  import json
169
  data = json.loads(script.string or "{}")
170
- # common pattern
171
  if isinstance(data, dict):
172
  video = data.get("video") or data.get("videoObject") or data.get("mainEntity")
173
  if isinstance(video, dict):
174
  for k in ("contentUrl", "url"):
175
  if video.get(k):
176
  return video.get(k)
177
- # top-level contentUrl
178
  if data.get("contentUrl"):
179
  return data.get("contentUrl")
180
  except Exception:
181
  continue
182
- # 4) look for meta property site-specific fallbacks
183
  for meta_name in ("twitter:player:stream", "twitter:player"):
184
  m = soup.find("meta", attrs={"name": meta_name})
185
  if m and m.get("content"):
186
  return m.get("content")
187
- # fallback: search for direct links to common video hosts (youtube, vimeo) in anchor tags
188
  for a in soup.find_all("a", href=True):
189
  href = a["href"]
190
  if any(domain in href for domain in ("youtube.com", "youtu.be", "vimeo.com")):
191
  return href
192
  return None
193
 
194
- # When SDK has upload_file/get_file, use them; else raise when needed
195
  def upload_video_sdk(filepath: str):
196
  key = get_effective_api_key()
197
  if not key:
@@ -244,6 +240,86 @@ def remove_prompt_echo(prompt: str, text: str, check_len: int = 600, ratio_thres
244
  return b_full[len(ph):].lstrip(" \n:-")
245
  return text
246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  # UI layout
248
  current_url = st.session_state.get("url", "")
249
  if current_url != st.session_state.get("last_url_value"):
@@ -287,7 +363,6 @@ if st.sidebar.button("Load Video", use_container_width=True):
287
  try:
288
  vpw = st.session_state.get("video-password", "")
289
  url_val = st.session_state.get("url", "").strip()
290
- # If URL present, try to expand and extract video from HTML first
291
  final_url = url_val
292
  html_text = None
293
  if url_val:
@@ -296,9 +371,7 @@ if st.sidebar.button("Load Video", use_container_width=True):
296
  final_url = expanded
297
  html_text = html_or_err
298
  else:
299
- # expansion failed but html_or_err contains error message; ignore
300
  html_text = None
301
- # If we have HTML, try to find direct video link
302
  extracted = None
303
  if html_text:
304
  extracted = extract_video_from_html(html_text, base_url=final_url)
@@ -410,7 +483,7 @@ if generate_now and not st.session_state.get("busy"):
410
  try:
411
  if not HAS_GENAI or genai is None:
412
  raise RuntimeError("Responses API not available; install google.generativeai SDK.")
413
- # ensure configured
414
  try:
415
  genai.configure(api_key=key_to_use)
416
  except Exception:
@@ -441,16 +514,12 @@ if generate_now and not st.session_state.get("busy"):
441
  diagnostics["responses.generate_error"] = str(e)
442
  response = None
443
 
444
- # Attempt #2: GenerativeModel variants (0.8.x+)
445
  if response is None:
446
  try:
447
  if hasattr(genai, "GenerativeModel"):
448
  diagnostics["attempts"].append("GenerativeModel")
449
- gm = genai.GenerativeModel(model=model_used)
450
- if hasattr(gm, "generate_content"):
451
- response = gm.generate_content([system_msg, user_msg], files=[{"name": fname}], max_output_tokens=max_tokens)
452
- elif hasattr(gm, "generate"):
453
- response = gm.generate([system_msg, user_msg], files=[{"name": fname}], max_output_tokens=max_tokens)
454
  except Exception as e:
455
  diagnostics["GenerativeModel_error"] = str(e)
456
  response = None
@@ -468,22 +537,16 @@ if generate_now and not st.session_state.get("busy"):
468
  diagnostics["top_level_error"] = str(e)
469
  response = None
470
 
471
- # Final defensive tries for known objects
472
  if response is None:
473
  try:
474
- if hasattr(genai, "GenerativeModel"):
475
- diagnostics["attempts"].append("GenerativeModel_last")
476
- gm = genai.GenerativeModel(model=model_used)
477
- try:
478
- response = gm.generate_content([system_msg, user_msg], files=[{"name": fname}], max_output_tokens=max_tokens)
479
- except Exception:
480
- response = gm.generate([system_msg, user_msg], files=[{"name": fname}], max_output_tokens=max_tokens)
481
  except Exception as e:
482
- diagnostics["GenerativeModel_last_error"] = str(e)
483
  response = None
484
 
485
  if response is None:
486
- # Instead of raising the runtime error seen previously, attach diagnostics to last_error and return gracefully
487
  diag_text = f"No supported generate method found on google.generativeai in this runtime. Diagnostics: {diagnostics}"
488
  st.session_state["last_error"] = diag_text
489
  st.error("Responses API not supported in this runtime. See Last Error for details.")
 
4
  import string
5
  import hashlib
6
  import traceback
7
+ import inspect
8
  from glob import glob
9
  from pathlib import Path
10
  from difflib import SequenceMatcher
 
19
 
20
  load_dotenv()
21
 
22
+ # Remove phi agent code (fragile imports); keep simple flag
23
  HAS_PHI = False
24
 
25
  # google generative ai SDK (may be absent or partial in some runtimes)
26
  try:
27
  import google.generativeai as genai # type: ignore
28
+ # upload_file/get_file exist in some versions
29
+ try:
30
+ from google.generativeai import upload_file, get_file # type: ignore
31
+ except Exception:
32
+ upload_file = None
33
+ get_file = None
34
  HAS_GENAI = True
35
  except Exception:
36
  genai = None
 
123
  if not key or not HAS_GENAI:
124
  return False
125
  try:
 
126
  genai.configure(api_key=key)
127
  return True
128
  except Exception:
 
142
  except Exception:
143
  pass
144
 
145
+ # URL expand + extraction helpers
146
  def expand_url(short_url, timeout=10):
147
  try:
148
  r = requests.get(short_url, allow_redirects=True, timeout=timeout, headers={"User-Agent":"Mozilla/5.0"})
 
153
 
154
  def extract_video_from_html(html, base_url=None):
155
  soup = BeautifulSoup(html, "html.parser")
 
156
  og = soup.find("meta", property="og:video")
157
  if og and og.get("content"):
158
  return og.get("content")
 
159
  vtag = soup.find("video")
160
  if vtag:
161
  src = vtag.get("src")
162
  if src:
163
  return src
 
164
  source = vtag.find("source")
165
  if source and source.get("src"):
166
  return source.get("src")
 
167
  for script in soup.find_all("script", type="application/ld+json"):
168
  try:
169
  import json
170
  data = json.loads(script.string or "{}")
 
171
  if isinstance(data, dict):
172
  video = data.get("video") or data.get("videoObject") or data.get("mainEntity")
173
  if isinstance(video, dict):
174
  for k in ("contentUrl", "url"):
175
  if video.get(k):
176
  return video.get(k)
 
177
  if data.get("contentUrl"):
178
  return data.get("contentUrl")
179
  except Exception:
180
  continue
 
181
  for meta_name in ("twitter:player:stream", "twitter:player"):
182
  m = soup.find("meta", attrs={"name": meta_name})
183
  if m and m.get("content"):
184
  return m.get("content")
 
185
  for a in soup.find_all("a", href=True):
186
  href = a["href"]
187
  if any(domain in href for domain in ("youtube.com", "youtu.be", "vimeo.com")):
188
  return href
189
  return None
190
 
 
191
  def upload_video_sdk(filepath: str):
192
  key = get_effective_api_key()
193
  if not key:
 
240
  return b_full[len(ph):].lstrip(" \n:-")
241
  return text
242
 
243
+ # Helper: try to call GenerativeModel with compatible signature
244
+ def generative_model_call_flexible(model_name, messages, files=None, max_output_tokens=1024):
245
+ """
246
+ Try different call patterns for genai.GenerativeModel depending on its constructor/signature.
247
+ Returns the response object or raises if none work.
248
+ """
249
+ if not HAS_GENAI or genai is None:
250
+ raise RuntimeError("genai not available")
251
+
252
+ # Inspect GenerativeModel if present
253
+ GM = getattr(genai, "GenerativeModel", None)
254
+ if GM is None:
255
+ raise RuntimeError("GenerativeModel not available")
256
+
257
+ # Inspect constructor signature
258
+ try:
259
+ sig = inspect.signature(GM)
260
+ params = sig.parameters
261
+ # prefer 'model' if available
262
+ if "model" in params:
263
+ gm = GM(model=model_name)
264
+ elif "model_name" in params:
265
+ gm = GM(model_name=model_name)
266
+ else:
267
+ # fallback to no-arg constructor
268
+ gm = GM()
269
+ # attempt to set attribute if accepted
270
+ try:
271
+ if hasattr(gm, "model"):
272
+ setattr(gm, "model", model_name)
273
+ except Exception:
274
+ pass
275
+ except Exception:
276
+ # if signature inspection fails, try common constructors defensively
277
+ try:
278
+ gm = GM(model=model_name)
279
+ except TypeError:
280
+ try:
281
+ gm = GM(model_name=model_name)
282
+ except TypeError:
283
+ gm = GM()
284
+
285
+ # Now try available methods
286
+ if hasattr(gm, "generate_content"):
287
+ return gm.generate_content(messages, files=files, max_output_tokens=max_output_tokens)
288
+ if hasattr(gm, "generate"):
289
+ # some versions use generate(messages,...)
290
+ try:
291
+ return gm.generate(messages, files=files, max_output_tokens=max_output_tokens)
292
+ except TypeError:
293
+ # try positional
294
+ return gm.generate(messages, max_output_tokens=max_output_tokens)
295
+ raise RuntimeError("No usable generate method on GenerativeModel instance")
296
+
297
+ # Fallback HTTP call using the REST Responses endpoint if the SDK is present but broken.
298
+ # This requires an API key and uses the public Responses API endpoint.
299
+ def responses_http_call(api_key, model, messages, file_name=None, max_output_tokens=1024, safety_settings=None):
300
+ """
301
+ Minimal fallback: POST to the Responses API /v1/responses.
302
+ This constructs a small payload; note: some runtimes may block direct HTTP to Google or expect different endpoints.
303
+ """
304
+ # Basic endpoint; adjust if your environment needs a different base URL
305
+ url = "https://generativeai.googleapis.com/v1beta2/models/{model}:generateMessage".format(model=model)
306
+ headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
307
+ payload = {
308
+ "messages": [{"role": m.get("role", "user"), "content": [{"type": "text", "text": m.get("content", "")}]} for m in messages],
309
+ "maxOutputTokens": max_output_tokens,
310
+ }
311
+ if safety_settings:
312
+ payload["safetySettings"] = safety_settings
313
+ if file_name:
314
+ # Attach file ref format used by some SDKs
315
+ payload["files"] = [{"name": file_name}]
316
+ try:
317
+ r = requests.post(url, json=payload, headers=headers, timeout=60)
318
+ r.raise_for_status()
319
+ return r.json()
320
+ except Exception as e:
321
+ raise RuntimeError(f"HTTP responses fallback failed: {e}")
322
+
323
  # UI layout
324
  current_url = st.session_state.get("url", "")
325
  if current_url != st.session_state.get("last_url_value"):
 
363
  try:
364
  vpw = st.session_state.get("video-password", "")
365
  url_val = st.session_state.get("url", "").strip()
 
366
  final_url = url_val
367
  html_text = None
368
  if url_val:
 
371
  final_url = expanded
372
  html_text = html_or_err
373
  else:
 
374
  html_text = None
 
375
  extracted = None
376
  if html_text:
377
  extracted = extract_video_from_html(html_text, base_url=final_url)
 
483
  try:
484
  if not HAS_GENAI or genai is None:
485
  raise RuntimeError("Responses API not available; install google.generativeai SDK.")
486
+ # ensure configured (best-effort)
487
  try:
488
  genai.configure(api_key=key_to_use)
489
  except Exception:
 
514
  diagnostics["responses.generate_error"] = str(e)
515
  response = None
516
 
517
+ # Attempt #2: GenerativeModel variants (0.8.x+), using flexible caller
518
  if response is None:
519
  try:
520
  if hasattr(genai, "GenerativeModel"):
521
  diagnostics["attempts"].append("GenerativeModel")
522
+ response = generative_model_call_flexible(model_used, [system_msg, user_msg], files=[{"name": fname}], max_output_tokens=max_tokens)
 
 
 
 
523
  except Exception as e:
524
  diagnostics["GenerativeModel_error"] = str(e)
525
  response = None
 
537
  diagnostics["top_level_error"] = str(e)
538
  response = None
539
 
540
+ # Attempt #4: fallback HTTP Responses call
541
  if response is None:
542
  try:
543
+ diagnostics["attempts"].append("http_fallback")
544
+ response = responses_http_call(key_to_use, model_used, [system_msg, user_msg], file_name=fname, max_output_tokens=max_tokens, safety_settings=safety_settings)
 
 
 
 
 
545
  except Exception as e:
546
+ diagnostics["http_fallback_error"] = str(e)
547
  response = None
548
 
549
  if response is None:
 
550
  diag_text = f"No supported generate method found on google.generativeai in this runtime. Diagnostics: {diagnostics}"
551
  st.session_state["last_error"] = diag_text
552
  st.error("Responses API not supported in this runtime. See Last Error for details.")