Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -450,12 +450,11 @@ def create_demo():
|
|
| 450 |
delay = float(ra) if ra is not None else delay
|
| 451 |
except Exception:
|
| 452 |
pass
|
| 453 |
-
# for other 4xx/5xx raise to outer except to allow retry logic
|
| 454 |
r.raise_for_status()
|
| 455 |
else:
|
| 456 |
with open(src, "rb") as fh:
|
| 457 |
return fh.read()
|
| 458 |
-
except requests.exceptions.RequestException
|
| 459 |
if attempt >= max_retries:
|
| 460 |
raise
|
| 461 |
time.sleep(delay)
|
|
@@ -489,20 +488,17 @@ def create_demo():
|
|
| 489 |
# returns (preview_image_path, preview_video_path, status_msg)
|
| 490 |
if not url:
|
| 491 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), gr.update(value="")
|
| 492 |
-
# If remote, check head to avoid unnecessary download when it's clearly video
|
| 493 |
try:
|
| 494 |
if is_remote(url):
|
| 495 |
head = safe_head(url)
|
| 496 |
if head:
|
| 497 |
ctype = (head.headers.get("content-type") or "").lower()
|
| 498 |
if ctype.startswith("video/") or any(url.lower().endswith(ext) for ext in VIDEO_EXTS):
|
| 499 |
-
# save remote to temp to avoid Gradio re-download later
|
| 500 |
local = _save_preview_local(url)
|
| 501 |
if local:
|
| 502 |
return gr.update(value=None, visible=False), gr.update(value=local, visible=True), gr.update(value=f"Remote video detected (content-type={ctype}). Showing preview if browser-playable.")
|
| 503 |
else:
|
| 504 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), gr.update(value=f"Remote video detected but preview download failed (content-type={ctype}).")
|
| 505 |
-
# Try image fetch and load
|
| 506 |
local = _save_preview_local(url)
|
| 507 |
if not local:
|
| 508 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), gr.update(value="Preview load failed: could not fetch resource.")
|
|
@@ -510,10 +506,8 @@ def create_demo():
|
|
| 510 |
img = Image.open(local)
|
| 511 |
if getattr(img, "is_animated", False):
|
| 512 |
img.seek(0)
|
| 513 |
-
# return local path for gr.Image (type=filepath)
|
| 514 |
return gr.update(value=local, visible=True), gr.update(value=None, visible=False), gr.update(value="Image preview loaded.")
|
| 515 |
except UnidentifiedImageError:
|
| 516 |
-
# Not an image — maybe a video; return video preview if available
|
| 517 |
if any(local.lower().endswith(ext) for ext in VIDEO_EXTS) or True:
|
| 518 |
return gr.update(value=None, visible=False), gr.update(value=local, visible=True), gr.update(value="Non-image file — showing as video preview if playable.")
|
| 519 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), gr.update(value="Preview load failed: file is not a valid image.")
|
|
@@ -528,7 +522,6 @@ def create_demo():
|
|
| 528 |
clear_btn.click(fn=clear_all, inputs=[], outputs=[url_input, preview_image, preview_video, status_state, progress_md, output_md, preview_path_state])
|
| 529 |
|
| 530 |
def _convert_video_for_preview(path: str) -> str:
|
| 531 |
-
# fix: check FFMPEG_BIN path, not 'path'
|
| 532 |
if not FFMPEG_BIN or not os.path.exists(FFMPEG_BIN):
|
| 533 |
return path
|
| 534 |
out_fd, out_path = tempfile.mkstemp(suffix=".mp4")
|
|
@@ -546,7 +539,7 @@ def create_demo():
|
|
| 546 |
except Exception: pass
|
| 547 |
return path
|
| 548 |
|
| 549 |
-
# Worker now returns (status_state, output_md,
|
| 550 |
def worker(url: str, prompt: str, key: str, progress=gr.Progress()):
|
| 551 |
try:
|
| 552 |
if not url:
|
|
@@ -563,14 +556,12 @@ def create_demo():
|
|
| 563 |
tmp = save_bytes_to_temp(raw, suffix=ext_from_src(url) or ".mp4")
|
| 564 |
progress(0.18, desc="Saved video to temp; converting for preview if needed...")
|
| 565 |
preview_tmp = _convert_video_for_preview(tmp)
|
| 566 |
-
# ensure preview_local is a local path to avoid Gradio re-download
|
| 567 |
preview_local = preview_tmp if os.path.exists(preview_tmp) else tmp
|
| 568 |
progress(0.25, desc="Starting video analysis...")
|
| 569 |
res = analyze_video_cohesive(client, tmp, prompt or "", progress=progress)
|
| 570 |
progress(0.98, desc="Finalizing result...")
|
| 571 |
try:
|
| 572 |
if preview_tmp != tmp and os.path.exists(preview_tmp):
|
| 573 |
-
# leave preview_tmp for frontend; worker will clean tmp
|
| 574 |
pass
|
| 575 |
finally:
|
| 576 |
try: os.remove(tmp)
|
|
@@ -580,7 +571,6 @@ def create_demo():
|
|
| 580 |
elif is_img:
|
| 581 |
progress(0.08, desc="Fetching image bytes...")
|
| 582 |
raw = fetch_bytes(url, progress=progress)
|
| 583 |
-
# save preview locally so Gradio won't re-download later
|
| 584 |
try:
|
| 585 |
preview_fd, preview_path = tempfile.mkstemp(suffix=".jpg")
|
| 586 |
os.close(preview_fd)
|
|
@@ -606,7 +596,6 @@ def create_demo():
|
|
| 606 |
progress(0.2, desc="Image detected — analyzing...")
|
| 607 |
res = analyze_image_structured(client, raw, prompt or "", progress=progress)
|
| 608 |
status = "done" if not (isinstance(res, str) and res.lower().startswith("error")) else "error"
|
| 609 |
-
# save preview as image
|
| 610 |
try:
|
| 611 |
preview_fd, preview_path = tempfile.mkstemp(suffix=".jpg")
|
| 612 |
os.close(preview_fd)
|
|
@@ -634,8 +623,18 @@ def create_demo():
|
|
| 634 |
except Exception as e:
|
| 635 |
return ("error", f"Unexpected worker error: {e}", "")
|
| 636 |
|
| 637 |
-
#
|
| 638 |
-
submit_btn.click(fn=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 639 |
|
| 640 |
# update submit button label from status
|
| 641 |
def btn_label_from_state(s):
|
|
@@ -652,13 +651,11 @@ def create_demo():
|
|
| 652 |
def apply_preview(path: str):
|
| 653 |
if not path:
|
| 654 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), ""
|
| 655 |
-
# choose whether it's image or video by extension/content
|
| 656 |
try:
|
| 657 |
if any(path.lower().endswith(ext) for ext in IMAGE_EXTS):
|
| 658 |
return gr.update(value=path, visible=True), gr.update(value=None, visible=False), "Preview updated."
|
| 659 |
if any(path.lower().endswith(ext) for ext in VIDEO_EXTS):
|
| 660 |
return gr.update(value=None, visible=False), gr.update(value=path, visible=True), "Preview updated."
|
| 661 |
-
# try load as image
|
| 662 |
try:
|
| 663 |
Image.open(path)
|
| 664 |
return gr.update(value=path, visible=True), gr.update(value=None, visible=False), "Preview updated."
|
|
@@ -669,8 +666,9 @@ def create_demo():
|
|
| 669 |
|
| 670 |
preview_path_state.change(fn=apply_preview, inputs=[preview_path_state], outputs=[preview_image, preview_video, preview_status])
|
| 671 |
|
|
|
|
|
|
|
| 672 |
return demo
|
| 673 |
|
| 674 |
-
|
| 675 |
if __name__ == "__main__":
|
| 676 |
create_demo().launch(share=False, server_name="0.0.0.0", server_port=7860, max_threads=8)
|
|
|
|
| 450 |
delay = float(ra) if ra is not None else delay
|
| 451 |
except Exception:
|
| 452 |
pass
|
|
|
|
| 453 |
r.raise_for_status()
|
| 454 |
else:
|
| 455 |
with open(src, "rb") as fh:
|
| 456 |
return fh.read()
|
| 457 |
+
except requests.exceptions.RequestException:
|
| 458 |
if attempt >= max_retries:
|
| 459 |
raise
|
| 460 |
time.sleep(delay)
|
|
|
|
| 488 |
# returns (preview_image_path, preview_video_path, status_msg)
|
| 489 |
if not url:
|
| 490 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), gr.update(value="")
|
|
|
|
| 491 |
try:
|
| 492 |
if is_remote(url):
|
| 493 |
head = safe_head(url)
|
| 494 |
if head:
|
| 495 |
ctype = (head.headers.get("content-type") or "").lower()
|
| 496 |
if ctype.startswith("video/") or any(url.lower().endswith(ext) for ext in VIDEO_EXTS):
|
|
|
|
| 497 |
local = _save_preview_local(url)
|
| 498 |
if local:
|
| 499 |
return gr.update(value=None, visible=False), gr.update(value=local, visible=True), gr.update(value=f"Remote video detected (content-type={ctype}). Showing preview if browser-playable.")
|
| 500 |
else:
|
| 501 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), gr.update(value=f"Remote video detected but preview download failed (content-type={ctype}).")
|
|
|
|
| 502 |
local = _save_preview_local(url)
|
| 503 |
if not local:
|
| 504 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), gr.update(value="Preview load failed: could not fetch resource.")
|
|
|
|
| 506 |
img = Image.open(local)
|
| 507 |
if getattr(img, "is_animated", False):
|
| 508 |
img.seek(0)
|
|
|
|
| 509 |
return gr.update(value=local, visible=True), gr.update(value=None, visible=False), gr.update(value="Image preview loaded.")
|
| 510 |
except UnidentifiedImageError:
|
|
|
|
| 511 |
if any(local.lower().endswith(ext) for ext in VIDEO_EXTS) or True:
|
| 512 |
return gr.update(value=None, visible=False), gr.update(value=local, visible=True), gr.update(value="Non-image file — showing as video preview if playable.")
|
| 513 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), gr.update(value="Preview load failed: file is not a valid image.")
|
|
|
|
| 522 |
clear_btn.click(fn=clear_all, inputs=[], outputs=[url_input, preview_image, preview_video, status_state, progress_md, output_md, preview_path_state])
|
| 523 |
|
| 524 |
def _convert_video_for_preview(path: str) -> str:
|
|
|
|
| 525 |
if not FFMPEG_BIN or not os.path.exists(FFMPEG_BIN):
|
| 526 |
return path
|
| 527 |
out_fd, out_path = tempfile.mkstemp(suffix=".mp4")
|
|
|
|
| 539 |
except Exception: pass
|
| 540 |
return path
|
| 541 |
|
| 542 |
+
# Worker now returns (status_state, output_md, preview_path_state)
|
| 543 |
def worker(url: str, prompt: str, key: str, progress=gr.Progress()):
|
| 544 |
try:
|
| 545 |
if not url:
|
|
|
|
| 556 |
tmp = save_bytes_to_temp(raw, suffix=ext_from_src(url) or ".mp4")
|
| 557 |
progress(0.18, desc="Saved video to temp; converting for preview if needed...")
|
| 558 |
preview_tmp = _convert_video_for_preview(tmp)
|
|
|
|
| 559 |
preview_local = preview_tmp if os.path.exists(preview_tmp) else tmp
|
| 560 |
progress(0.25, desc="Starting video analysis...")
|
| 561 |
res = analyze_video_cohesive(client, tmp, prompt or "", progress=progress)
|
| 562 |
progress(0.98, desc="Finalizing result...")
|
| 563 |
try:
|
| 564 |
if preview_tmp != tmp and os.path.exists(preview_tmp):
|
|
|
|
| 565 |
pass
|
| 566 |
finally:
|
| 567 |
try: os.remove(tmp)
|
|
|
|
| 571 |
elif is_img:
|
| 572 |
progress(0.08, desc="Fetching image bytes...")
|
| 573 |
raw = fetch_bytes(url, progress=progress)
|
|
|
|
| 574 |
try:
|
| 575 |
preview_fd, preview_path = tempfile.mkstemp(suffix=".jpg")
|
| 576 |
os.close(preview_fd)
|
|
|
|
| 596 |
progress(0.2, desc="Image detected — analyzing...")
|
| 597 |
res = analyze_image_structured(client, raw, prompt or "", progress=progress)
|
| 598 |
status = "done" if not (isinstance(res, str) and res.lower().startswith("error")) else "error"
|
|
|
|
| 599 |
try:
|
| 600 |
preview_fd, preview_path = tempfile.mkstemp(suffix=".jpg")
|
| 601 |
os.close(preview_fd)
|
|
|
|
| 623 |
except Exception as e:
|
| 624 |
return ("error", f"Unexpected worker error: {e}", "")
|
| 625 |
|
| 626 |
+
# immediate UI flip to "busy" so user sees work started
|
| 627 |
+
submit_btn.click(fn=lambda: "busy", inputs=[], outputs=[status_state])
|
| 628 |
+
|
| 629 |
+
# actual heavy work runs in the queue and shows progress (attach to progress_md)
|
| 630 |
+
submit_btn.click(
|
| 631 |
+
fn=worker,
|
| 632 |
+
inputs=[url_input, custom_prompt, api_key],
|
| 633 |
+
outputs=[status_state, output_md, preview_path_state],
|
| 634 |
+
queue=True,
|
| 635 |
+
show_progress="full",
|
| 636 |
+
show_progress_on=progress_md,
|
| 637 |
+
)
|
| 638 |
|
| 639 |
# update submit button label from status
|
| 640 |
def btn_label_from_state(s):
|
|
|
|
| 651 |
def apply_preview(path: str):
|
| 652 |
if not path:
|
| 653 |
return gr.update(value=None, visible=False), gr.update(value=None, visible=False), ""
|
|
|
|
| 654 |
try:
|
| 655 |
if any(path.lower().endswith(ext) for ext in IMAGE_EXTS):
|
| 656 |
return gr.update(value=path, visible=True), gr.update(value=None, visible=False), "Preview updated."
|
| 657 |
if any(path.lower().endswith(ext) for ext in VIDEO_EXTS):
|
| 658 |
return gr.update(value=None, visible=False), gr.update(value=path, visible=True), "Preview updated."
|
|
|
|
| 659 |
try:
|
| 660 |
Image.open(path)
|
| 661 |
return gr.update(value=path, visible=True), gr.update(value=None, visible=False), "Preview updated."
|
|
|
|
| 666 |
|
| 667 |
preview_path_state.change(fn=apply_preview, inputs=[preview_path_state], outputs=[preview_image, preview_video, preview_status])
|
| 668 |
|
| 669 |
+
# ensure global queue behavior
|
| 670 |
+
demo.queue()
|
| 671 |
return demo
|
| 672 |
|
|
|
|
| 673 |
if __name__ == "__main__":
|
| 674 |
create_demo().launch(share=False, server_name="0.0.0.0", server_port=7860, max_threads=8)
|