File size: 4,335 Bytes
01c0c12
92e5cf2
ce188b1
92e5cf2
 
 
01c0c12
ae92154
92e5cf2
 
 
01c0c12
92e5cf2
 
 
 
 
 
 
 
 
 
01c0c12
92e5cf2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
01c0c12
 
 
92e5cf2
 
01c0c12
 
 
 
 
92e5cf2
 
 
 
 
 
 
 
 
 
 
01c0c12
92e5cf2
 
01c0c12
 
 
 
 
92e5cf2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
01c0c12
92e5cf2
 
01c0c12
 
 
92e5cf2
87680ff
01c0c12
 
 
 
 
 
 
 
ce188b1
01c0c12
ce188b1
01c0c12
ce188b1
 
87680ff
01c0c12
b761b10
92e5cf2
01c0c12
92e5cf2
 
01c0c12
92e5cf2
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# app.py
import sys
import os
import tempfile
from pathlib import Path
import streamlit as st
from PIL import Image

# Force app root and pipeline to be importable (for HF docker)
sys.path.append(str(Path(__file__).parent.resolve()))
sys.path.append(str(Path(__file__).parent.resolve() / "pipeline"))

# === CUDA DIAGNOSTICS (LOGS) ===
try:
    import torch
    print("=== CUDA Info ===")
    print("CUDA available:", torch.cuda.is_available())
    print("CUDA device count:", torch.cuda.device_count())
    print("torch version:", torch.__version__)
    print("=================")
except Exception as e:
    print(f"[WARN] Could not print CUDA info: {e}")

# === Import the two-stage pipeline ===
try:
    from pipeline.two_stage_pipeline import process_two_stage
except ImportError as e:
    st.error(f"Pipeline not found or misconfigured: {e}")
    st.stop()

st.set_page_config(
    page_title="BackgroundFX Pro",
    layout="wide",
    page_icon="🎬"
)

st.title("🎬 BackgroundFX Pro β€” AI Video Background Replacer")
st.write(
    "Upload a video and a background image (optional). The system will remove the original background "
    "using **SAM2** & **MatAnyone**, and composite the subject over your new background image."
)

def progress_callback(msg, prog):
    """Streamlit-friendly progress reporting (persistent)."""
    if "progress_bar" not in st.session_state:
        st.session_state.progress_bar = st.progress(0)
        st.session_state.progress_text = st.empty()
    st.session_state.progress_bar.progress(min(max(prog,0.0),1.0))
    st.session_state.progress_text.text(msg)

# --- Uploaders ---
video_file = st.file_uploader(
    "1️⃣ Upload video file (mp4, mov, avi, mkv)", 
    type=["mp4", "mov", "avi", "mkv"]
)
bg_file = st.file_uploader(
    "2️⃣ Upload new background (jpg/png, optional)", 
    type=["jpg", "jpeg", "png"]
)

video_path, bg_path = None, None

if video_file:
    # Save video to temp file
    with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as vf:
        vf.write(video_file.read())
        video_path = vf.name
    st.video(video_path)

if bg_file:
    # Save background to temp file
    with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as bf:
        bf.write(bg_file.read())
        bg_path = bf.name
    background_img = Image.open(bg_path).convert("RGB")
    st.image(background_img, caption="Background Image")
elif video_file:
    # Fallback: green background sized to video or 1280x720
    try:
        import cv2
        cap = cv2.VideoCapture(video_path)
        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) or 1280
        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) or 720
        cap.release()
    except Exception:
        width, height = 1280, 720
    background_img = Image.new("RGB", (width, height), (0,255,0))
    st.info("No background image uploaded. Using default green background.")

# --- Processing ---
if video_path and background_img:
    if st.button("πŸš€ Run Background Replacement"):
        st.session_state.progress_bar = st.progress(0)
        st.session_state.progress_text = st.empty()
        with st.spinner("Processing video... (May take several minutes for long videos)"):
            try:
                out_path = process_two_stage(
                    video_path,
                    background_img,
                    progress=progress_callback
                )
                st.success("βœ… Done! Here is your composited video:")
                st.video(str(out_path))
                with open(out_path, "rb") as f:
                    st.download_button(
                        label="πŸ’Ύ Download Result",
                        data=f,
                        file_name="backgroundfx_result.mp4",
                        mime="video/mp4"
                    )
            except Exception as e:
                st.error(f"❌ Processing failed: {e}")

        # Clean up temp files (best effort)
        try:
            if video_path and os.path.exists(video_path):
                os.unlink(video_path)
        except Exception: pass
        try:
            if bg_path and os.path.exists(bg_path):
                os.unlink(bg_path)
        except Exception: pass

# HF Spaces tip
st.caption("Built for Hugging Face T4 Spaces β€’ CUDA & GPU acceleration required β€’ v2025.10")