Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -159,6 +159,9 @@ def convert_to_jpeg_bytes(img_bytes: bytes, base_h: int = 480) -> bytes:
|
|
| 159 |
except UnidentifiedImageError:
|
| 160 |
print(f"Warning: convert_to_jpeg_bytes received unidentifiable image data.")
|
| 161 |
return b"" # Return empty bytes if data is not an identifiable image
|
|
|
|
|
|
|
|
|
|
| 162 |
|
| 163 |
try:
|
| 164 |
if getattr(img, "is_animated", False): # Handles animated GIFs by taking first frame
|
|
@@ -524,7 +527,7 @@ def _convert_video_for_preview_if_needed(path: str) -> str:
|
|
| 524 |
_temp_preview_files_to_delete.remove(out_path)
|
| 525 |
try: os.remove(out_path)
|
| 526 |
except Exception: pass
|
| 527 |
-
return path
|
| 528 |
|
| 529 |
# --- Preview Generation Logic ---
|
| 530 |
def _get_playable_preview_path_from_raw(src_url: str, raw_bytes: bytes, is_image_hint: bool, is_video_hint: bool) -> str:
|
|
@@ -536,50 +539,62 @@ def _get_playable_preview_path_from_raw(src_url: str, raw_bytes: bytes, is_image
|
|
| 536 |
print(f"Error: No raw bytes provided for preview generation of {src_url}.")
|
| 537 |
return ""
|
| 538 |
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
playable_path = _convert_video_for_preview_if_needed(temp_raw_video_path)
|
| 543 |
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
except Exception: pass
|
| 550 |
-
return playable_path
|
| 551 |
-
elif is_image_hint: # Use the passed hint
|
| 552 |
-
jpeg_bytes = convert_to_jpeg_bytes(raw_bytes, base_h=1024)
|
| 553 |
-
if not jpeg_bytes: # Handle if convert_to_jpeg_bytes failed
|
| 554 |
-
print(f"Warning: Could not convert image bytes for {src_url} to JPEG.")
|
| 555 |
-
return ""
|
| 556 |
-
return _temp_file(jpeg_bytes, suffix=".jpg")
|
| 557 |
-
else:
|
| 558 |
-
# Fallback if hints are unclear, try image first, then video
|
| 559 |
try:
|
| 560 |
# Attempt to open as image
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
img_bytes_io.seek(0) # Reset stream position after verify
|
| 565 |
-
jpeg_bytes = convert_to_jpeg_bytes(img_bytes_io.read(), base_h=1024)
|
| 566 |
-
if jpeg_bytes: # If conversion yielded bytes, create temp file
|
| 567 |
-
return _temp_file(jpeg_bytes, suffix=".jpg")
|
| 568 |
-
else: # If convert_to_jpeg_bytes failed even after verify
|
| 569 |
-
raise UnidentifiedImageError("Could not convert verified image to JPEG.") # Re-raise to fall to video path
|
| 570 |
except UnidentifiedImageError:
|
| 571 |
-
#
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
playable_path = _convert_video_for_preview_if_needed(temp_raw_video_path)
|
| 576 |
-
return playable_path
|
| 577 |
-
except Exception as e: # Catch other potential PIL/IO errors during image check
|
| 578 |
print(f"Warning: Generic error during image check for {src_url}: {e}. Falling back to video preview attempt.")
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 583 |
|
| 584 |
|
| 585 |
def _fetch_with_retries_bytes(src: str, timeout: int = 15, max_retries: int = 3) -> bytes:
|
|
@@ -822,44 +837,56 @@ def create_demo():
|
|
| 822 |
if not raw_bytes:
|
| 823 |
return "error", "Failed to download media bytes.", "", []
|
| 824 |
|
| 825 |
-
#
|
| 826 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 827 |
try:
|
|
|
|
| 828 |
Image.open(BytesIO(raw_bytes)).verify()
|
| 829 |
-
|
| 830 |
-
except
|
| 831 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 832 |
|
| 833 |
# --- Video Processing Path ---
|
| 834 |
-
if
|
| 835 |
temp_media_file_for_analysis = _temp_file(raw_bytes, suffix=ext_from_src(url) or ".mp4")
|
| 836 |
if not temp_media_file_for_analysis: # Handle if _temp_file failed
|
| 837 |
return "error", "Failed to create temporary video file for analysis.", "", []
|
| 838 |
-
generated_main_preview_path = _get_playable_preview_path_from_raw(url, raw_bytes, is_img_worker, is_vid_worker)
|
| 839 |
-
|
| 840 |
progress(0.25, desc="Running full‑video analysis")
|
| 841 |
result_text, generated_screenshot_paths = analyze_video_cohesive(client, temp_media_file_for_analysis, prompt, progress=progress)
|
| 842 |
|
| 843 |
# --- Image Processing Path ---
|
| 844 |
-
elif
|
| 845 |
-
generated_main_preview_path = _get_playable_preview_path_from_raw(url, raw_bytes, is_img_worker, is_vid_worker)
|
| 846 |
-
|
| 847 |
progress(0.20, desc="Running image analysis")
|
| 848 |
result_text = analyze_image_structured(client, raw_bytes, prompt, progress=progress)
|
| 849 |
# No screenshots for images
|
| 850 |
|
| 851 |
-
# ---
|
| 852 |
else:
|
| 853 |
-
#
|
| 854 |
-
|
|
|
|
| 855 |
temp_media_file_for_analysis = _temp_file(raw_bytes, suffix=ext_from_src(url) or ".mp4")
|
| 856 |
-
if not temp_media_file_for_analysis:
|
| 857 |
-
return "error", "Failed to create temporary video file for analysis
|
| 858 |
-
|
| 859 |
-
generated_main_preview_path = _get_playable_preview_path_from_raw(url, raw_bytes, False, True)
|
| 860 |
-
progress(0.25, desc="Running video analysis (fallback for unknown type)")
|
| 861 |
result_text, generated_screenshot_paths = analyze_video_cohesive(client, temp_media_file_for_analysis, prompt, progress=progress)
|
| 862 |
|
|
|
|
| 863 |
status = "done" if not (isinstance(result_text, str) and result_text.lower().startswith("error")) else "error"
|
| 864 |
|
| 865 |
return status, result_text, generated_main_preview_path, generated_screenshot_paths
|
|
|
|
| 159 |
except UnidentifiedImageError:
|
| 160 |
print(f"Warning: convert_to_jpeg_bytes received unidentifiable image data.")
|
| 161 |
return b"" # Return empty bytes if data is not an identifiable image
|
| 162 |
+
except Exception as e:
|
| 163 |
+
print(f"Warning: Error opening image for JPEG conversion: {e}")
|
| 164 |
+
return b""
|
| 165 |
|
| 166 |
try:
|
| 167 |
if getattr(img, "is_animated", False): # Handles animated GIFs by taking first frame
|
|
|
|
| 527 |
_temp_preview_files_to_delete.remove(out_path)
|
| 528 |
try: os.remove(out_path)
|
| 529 |
except Exception: pass
|
| 530 |
+
return path
|
| 531 |
|
| 532 |
# --- Preview Generation Logic ---
|
| 533 |
def _get_playable_preview_path_from_raw(src_url: str, raw_bytes: bytes, is_image_hint: bool, is_video_hint: bool) -> str:
|
|
|
|
| 539 |
print(f"Error: No raw bytes provided for preview generation of {src_url}.")
|
| 540 |
return ""
|
| 541 |
|
| 542 |
+
# Determine media type (prioritizing hints, then byte analysis)
|
| 543 |
+
is_actually_image = False
|
| 544 |
+
is_actually_video = False
|
|
|
|
| 545 |
|
| 546 |
+
if is_image_hint:
|
| 547 |
+
is_actually_image = True
|
| 548 |
+
elif is_video_hint:
|
| 549 |
+
is_actually_video = True
|
| 550 |
+
else: # If hints are not definitive, try to determine from bytes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 551 |
try:
|
| 552 |
# Attempt to open as image
|
| 553 |
+
# We don't need to load the whole image, just verify format.
|
| 554 |
+
Image.open(BytesIO(raw_bytes)).verify()
|
| 555 |
+
is_actually_image = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 556 |
except UnidentifiedImageError:
|
| 557 |
+
# Not an identifiable image by PIL, assume video
|
| 558 |
+
is_actually_video = True
|
| 559 |
+
except Exception as e:
|
| 560 |
+
# Other PIL errors, assume video as a fallback for preview
|
|
|
|
|
|
|
|
|
|
| 561 |
print(f"Warning: Generic error during image check for {src_url}: {e}. Falling back to video preview attempt.")
|
| 562 |
+
is_actually_video = True
|
| 563 |
+
|
| 564 |
+
# --- Attempt Image Preview ---
|
| 565 |
+
if is_actually_image:
|
| 566 |
+
jpeg_bytes = convert_to_jpeg_bytes(raw_bytes, base_h=1024)
|
| 567 |
+
if jpeg_bytes:
|
| 568 |
+
return _temp_file(jpeg_bytes, suffix=".jpg")
|
| 569 |
+
else:
|
| 570 |
+
# If image conversion fails, even if it seemed like an image, fall back to video
|
| 571 |
+
print(f"Warning: Could not convert image bytes for {src_url} to JPEG. Attempting video fallback.")
|
| 572 |
+
is_actually_image = False # Clear image flag
|
| 573 |
+
is_actually_video = True # Set video flag for next block
|
| 574 |
+
|
| 575 |
+
# --- Attempt Video Preview ---
|
| 576 |
+
if is_actually_video:
|
| 577 |
+
# Create a temporary file for the raw video bytes first
|
| 578 |
+
temp_raw_video_path = _temp_file(raw_bytes, suffix=ext_from_src(src_url) or ".mp4")
|
| 579 |
+
if not temp_raw_video_path:
|
| 580 |
+
print(f"Error: Failed to create temporary raw video file for {src_url}.")
|
| 581 |
+
return ""
|
| 582 |
+
|
| 583 |
+
playable_path = _convert_video_for_preview_if_needed(temp_raw_video_path)
|
| 584 |
+
|
| 585 |
+
# If _convert_video_for_preview_if_needed created a new file,
|
| 586 |
+
# the original temp_raw_video_path is no longer needed. Remove it from tracking
|
| 587 |
+
# and delete it if it's no longer the returned playable_path.
|
| 588 |
+
if playable_path != temp_raw_video_path and os.path.exists(temp_raw_video_path):
|
| 589 |
+
if temp_raw_video_path in _temp_preview_files_to_delete:
|
| 590 |
+
_temp_preview_files_to_delete.remove(temp_raw_video_path)
|
| 591 |
+
try: os.remove(temp_raw_video_path)
|
| 592 |
+
except Exception as e: print(f"Error during cleanup of intermediate raw video temp file {temp_raw_video_path}: {e}")
|
| 593 |
+
|
| 594 |
+
return playable_path
|
| 595 |
+
|
| 596 |
+
print(f"Error: No playable preview path generated for {src_url}.")
|
| 597 |
+
return ""
|
| 598 |
|
| 599 |
|
| 600 |
def _fetch_with_retries_bytes(src: str, timeout: int = 15, max_retries: int = 3) -> bytes:
|
|
|
|
| 837 |
if not raw_bytes:
|
| 838 |
return "error", "Failed to download media bytes.", "", []
|
| 839 |
|
| 840 |
+
# Determine type more definitively using raw bytes
|
| 841 |
+
# This step is now more robustly handled inside _get_playable_preview_path_from_raw itself for preview,
|
| 842 |
+
# but we need it here for deciding analysis path (image model vs. video model)
|
| 843 |
+
is_actually_image_for_analysis = is_img_worker
|
| 844 |
+
is_actually_video_for_analysis = is_vid_worker
|
| 845 |
+
|
| 846 |
+
if not is_actually_image_for_analysis and not is_actually_video_for_analysis:
|
| 847 |
try:
|
| 848 |
+
# Attempt to open as image
|
| 849 |
Image.open(BytesIO(raw_bytes)).verify()
|
| 850 |
+
is_actually_image_for_analysis = True
|
| 851 |
+
except UnidentifiedImageError:
|
| 852 |
+
is_actually_video_for_analysis = True # Not an image, assume video
|
| 853 |
+
except Exception as e:
|
| 854 |
+
print(f"Warning: Could not definitively determine media type for {url} based on bytes: {e}. Attempting video analysis.")
|
| 855 |
+
is_actually_video_for_analysis = True # Generic error, fallback to video
|
| 856 |
+
|
| 857 |
+
# Get playable preview path (this internally handles image/video decision and conversion for preview)
|
| 858 |
+
generated_main_preview_path = _get_playable_preview_path_from_raw(url, raw_bytes, is_actually_image_for_analysis, is_actually_video_for_analysis)
|
| 859 |
+
if not generated_main_preview_path:
|
| 860 |
+
print(f"Error: Could not generate main preview for analysis: {url}") # Log this specific failure point
|
| 861 |
+
return "error", "Could not generate a playable preview for display.", "", []
|
| 862 |
+
|
| 863 |
|
| 864 |
# --- Video Processing Path ---
|
| 865 |
+
if is_actually_video_for_analysis:
|
| 866 |
temp_media_file_for_analysis = _temp_file(raw_bytes, suffix=ext_from_src(url) or ".mp4")
|
| 867 |
if not temp_media_file_for_analysis: # Handle if _temp_file failed
|
| 868 |
return "error", "Failed to create temporary video file for analysis.", "", []
|
|
|
|
|
|
|
| 869 |
progress(0.25, desc="Running full‑video analysis")
|
| 870 |
result_text, generated_screenshot_paths = analyze_video_cohesive(client, temp_media_file_for_analysis, prompt, progress=progress)
|
| 871 |
|
| 872 |
# --- Image Processing Path ---
|
| 873 |
+
elif is_actually_image_for_analysis:
|
|
|
|
|
|
|
| 874 |
progress(0.20, desc="Running image analysis")
|
| 875 |
result_text = analyze_image_structured(client, raw_bytes, prompt, progress=progress)
|
| 876 |
# No screenshots for images
|
| 877 |
|
| 878 |
+
# --- Fallback if still no clear analysis path (should be rare with refined logic) ---
|
| 879 |
else:
|
| 880 |
+
# This block should ideally not be reached if previous type determination is robust.
|
| 881 |
+
# As a final fallback, treat as video for analysis.
|
| 882 |
+
print(f"Warning: No definitive analysis type determined for {url} after all checks. Attempting video analysis fallback.")
|
| 883 |
temp_media_file_for_analysis = _temp_file(raw_bytes, suffix=ext_from_src(url) or ".mp4")
|
| 884 |
+
if not temp_media_file_for_analysis:
|
| 885 |
+
return "error", "Failed to create temporary video file for final analysis fallback.", "", []
|
| 886 |
+
progress(0.25, desc="Running video analysis (final fallback for unknown type)")
|
|
|
|
|
|
|
| 887 |
result_text, generated_screenshot_paths = analyze_video_cohesive(client, temp_media_file_for_analysis, prompt, progress=progress)
|
| 888 |
|
| 889 |
+
|
| 890 |
status = "done" if not (isinstance(result_text, str) and result_text.lower().startswith("error")) else "error"
|
| 891 |
|
| 892 |
return status, result_text, generated_main_preview_path, generated_screenshot_paths
|