MogensR commited on
Commit
d2a013f
·
verified ·
1 Parent(s): e74531f

Update streamlit_app.py

Browse files
Files changed (1) hide show
  1. streamlit_app.py +186 -197
streamlit_app.py CHANGED
@@ -30,12 +30,45 @@ def custom_excepthook(type, value, tb):
30
 
31
  # --- Streamlit Page Config ---
32
  st.set_page_config(
33
- page_title="🎬 Advanced Video Background Replacer",
34
  page_icon="🎥",
35
  layout="wide",
36
  initial_sidebar_state="expanded"
37
  )
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  # --- Custom CSS ---
40
  st.markdown("""
41
  <style>
@@ -59,21 +92,6 @@ def custom_excepthook(type, value, tb):
59
  .stAlert {
60
  border-radius: 10px;
61
  }
62
- .stTabs [data-baseweb="tab-list"] {
63
- gap: 10px;
64
- }
65
- .stTabs [data-baseweb="tab"] {
66
- height: 50px;
67
- white-space: pre;
68
- background-color: #f0f2f6;
69
- border-radius: 4px 4px 0 0;
70
- padding: 10px 20px;
71
- margin-right: 5px;
72
- }
73
- .stTabs [aria-selected="true"] {
74
- background-color: #4CAF50;
75
- color: white;
76
- }
77
  .video-container {
78
  border: 2px dashed #4CAF50;
79
  border-radius: 10px;
@@ -86,35 +104,26 @@ def custom_excepthook(type, value, tb):
86
  # --- Session State Initialization ---
87
  def initialize_session_state():
88
  """Initialize all session state variables"""
89
- defaults = {
90
- 'uploaded_video': None,
91
- 'video_bytes_cache': None,
92
- 'bg_image': None,
93
- 'bg_image_cache': None,
94
- 'bg_image_name': None,
95
- 'bg_color': "#00FF00",
96
- 'cached_color': None,
97
- 'color_display_cache': None,
98
- 'processed_video_bytes': None, # Store bytes instead of path
99
- 'processing': False,
100
- 'progress': 0,
101
- 'progress_text': "Ready",
102
- 'last_video_id': None,
103
- 'last_bg_image_id': None,
104
- 'process_complete': False
105
- }
106
- for key, value in defaults.items():
107
- if key not in st.session_state:
108
- st.session_state[key] = value
109
 
110
  # --- Video Processing ---
111
  def process_video(input_file, background, bg_type="image"):
112
- """
113
- Process video with the selected background using SAM2 and MatAnyone pipeline.
114
- Returns the video bytes.
115
- """
116
  logger.info("=" * 60)
117
- logger.info("🎬 STARTING VIDEO PROCESSING")
118
  logger.info("=" * 60)
119
 
120
  try:
@@ -124,77 +133,78 @@ def process_video(input_file, background, bg_type="image"):
124
  temp_dir = temp_base / f"session_{int(time.time())}"
125
  temp_dir.mkdir(exist_ok=True)
126
 
127
- logger.info(f"📁 Created temp directory: {temp_dir}")
128
 
129
- # Save the uploaded video to a temporary file
130
  input_path = str(temp_dir / "input.mp4")
131
- logger.info(f"💾 Writing video to {input_path}")
132
 
 
133
  with open(input_path, "wb") as f:
134
- written = f.write(input_file.getvalue())
135
- logger.info(f"Wrote {written/1e6:.2f}MB")
136
 
137
- if not os.path.exists(input_path):
138
- raise FileNotFoundError(f"Input video not saved: {input_path}")
139
 
140
- logger.info(f"Video file exists: {os.path.getsize(input_path)} bytes")
141
 
142
  # Prepare background
143
  bg_path = None
144
  if bg_type == "image" and background is not None:
145
- logger.info("🖼️ Processing background IMAGE")
146
  bg_cv = cv2.cvtColor(np.array(background), cv2.COLOR_RGB2BGR)
147
  bg_path = str(temp_dir / "background.jpg")
148
  cv2.imwrite(bg_path, bg_cv)
149
- logger.info(f"Background image written to {bg_path}")
150
 
151
- elif bg_type == "color" and hasattr(st.session_state, 'bg_color'):
152
- logger.info(f"🎨 Processing background COLOR: {st.session_state.bg_color}")
153
  color_hex = st.session_state.bg_color.lstrip('#')
154
  color_rgb = tuple(int(color_hex[i:i+2], 16) for i in (0, 2, 4))
155
  bg_path = str(temp_dir / "background.jpg")
156
  cv2.imwrite(bg_path, np.ones((100, 100, 3), dtype=np.uint8) * color_rgb[::-1])
157
- logger.info(f"Background color image written to {bg_path}")
158
 
159
- # Set up progress placeholders
160
  progress_placeholder = st.empty()
161
  status_placeholder = st.empty()
162
 
163
  def progress_callback(progress, message):
164
  progress = max(0, min(1, float(progress)))
165
- logger.info(f"📊 Progress: {progress*100:.1f}% - {message}")
166
  progress_placeholder.progress(progress)
167
  status_placeholder.text(f"Status: {message}")
168
 
169
- # Log GPU state
170
  if torch.cuda.is_available():
171
- logger.info(f"🎮 CUDA Available: True, Device: {torch.cuda.get_device_name(0)}")
172
- logger.info(f"💾 GPU Mem Before: {torch.cuda.memory_allocated()/1e9:.2f}GB")
 
 
173
  else:
174
- logger.info("⚠️ CUDA Available: False (using CPU)")
175
 
176
  # Process the video
177
  output_path = str(temp_dir / "output.mp4")
178
  click_points = [[0.5, 0.5]]
179
 
180
- logger.info("🔧 Importing TwoStageProcessor...")
181
  from pipeline.integrated_pipeline import TwoStageProcessor
182
 
183
- # Cache processor
184
  @st.cache_resource
185
  def load_processor(temp_dir_str):
186
- logger.info(f"🏗️ Loading processor with temp_dir: {temp_dir_str}")
187
  return TwoStageProcessor(temp_dir=temp_dir_str)
188
 
189
  processor = load_processor(str(temp_dir))
190
- logger.info("Processor loaded")
191
 
192
  try:
193
- logger.info("🎬 Calling TwoStageProcessor.process_video...")
194
- logger.info(f" - Input: {input_path}")
195
- logger.info(f" - Background: {bg_path}")
196
- logger.info(f" - Output: {output_path}")
197
- logger.info(f" - Click points: {click_points}")
198
 
199
  success = processor.process_video(
200
  input_video=input_path,
@@ -205,52 +215,51 @@ def load_processor(temp_dir_str):
205
  progress_callback=progress_callback
206
  )
207
 
208
- logger.info(f"📊 Processing returned: {success}")
209
 
210
  except Exception as e:
211
- logger.error(f"Pipeline processing failed: {traceback.format_exc()}", exc_info=True)
212
  raise
213
 
214
  if torch.cuda.is_available():
215
- logger.info(f"💾 GPU Mem After: {torch.cuda.memory_allocated()/1e9:.2f}GB")
 
216
  torch.cuda.empty_cache()
217
- logger.info("🧹 GPU cache cleared")
218
 
219
  if not success:
220
- raise RuntimeError("Video processing returned False")
221
 
222
- # Check if output file exists
223
  if not os.path.exists(output_path):
224
- logger.error(f"Output file does not exist: {output_path}")
225
  raise FileNotFoundError(f"Output video not created: {output_path}")
226
 
227
  output_size = os.path.getsize(output_path)
228
- logger.info(f"Output file exists: {output_size} bytes ({output_size/1e6:.2f}MB)")
229
 
230
- # Read the output video into memory
231
- logger.info("📖 Reading output video into memory...")
232
  with open(output_path, 'rb') as f:
233
  video_bytes = f.read()
234
 
235
- logger.info(f"Read {len(video_bytes)/1e6:.2f}MB into memory")
236
 
237
- # Clean up temp directory
238
  try:
239
- logger.info(f"🧹 Cleaning up temp directory: {temp_dir}")
240
  shutil.rmtree(temp_dir)
241
- logger.info("Temp directory cleaned")
242
  except Exception as e:
243
- logger.warning(f"⚠️ Could not clean temp directory: {e}")
244
 
245
  logger.info("=" * 60)
246
- logger.info("VIDEO PROCESSING COMPLETED SUCCESSFULLY")
247
  logger.info("=" * 60)
248
 
249
  return video_bytes
250
 
251
  except Exception as e:
252
  logger.error("=" * 60)
253
- logger.error(f"ERROR IN VIDEO PROCESSING: {str(e)}")
254
  logger.error(traceback.format_exc())
255
  logger.error("=" * 60)
256
  st.error(f"An error occurred during processing: {str(e)}")
@@ -258,13 +267,21 @@ def load_processor(temp_dir_str):
258
 
259
  # --- Main Application ---
260
  def main():
261
- st.title("🎬 Advanced Video Background Replacer")
262
  st.markdown("---")
263
 
264
  # Initialize session state
265
  initialize_session_state()
266
 
267
- logger.info(f"🔄 App rerun - Processing: {st.session_state.processing}, Complete: {st.session_state.process_complete}")
 
 
 
 
 
 
 
 
268
 
269
  # Main layout
270
  col1, col2 = st.columns([1, 1], gap="large")
@@ -273,36 +290,32 @@ def main():
273
  st.header("1. Upload Video")
274
 
275
  uploaded = st.file_uploader(
276
- "📹 Upload Video",
277
  type=["mp4", "mov", "avi"],
278
  key="video_uploader"
279
  )
280
 
281
- # Check if video actually changed using id()
282
- current_video_id = id(uploaded)
283
- if current_video_id != st.session_state.last_video_id:
284
- logger.info(f"📹 New video uploaded: {uploaded.name if uploaded else 'None'}")
285
- st.session_state.uploaded_video = uploaded
286
- st.session_state.last_video_id = current_video_id
287
- st.session_state.video_bytes_cache = None
288
- st.session_state.processed_video_bytes = None # Clear processed video
289
- st.session_state.process_complete = False
290
 
291
- # Video preview section
292
  st.markdown("### Video Preview")
293
- video_preview_container = st.container()
294
-
295
- with video_preview_container:
296
- if st.session_state.uploaded_video is not None:
297
- if st.session_state.video_bytes_cache is None:
298
- logger.info("📖 Caching video bytes...")
299
- st.session_state.video_bytes_cache = st.session_state.uploaded_video.getvalue()
300
- st.session_state.uploaded_video.seek(0)
301
- logger.info(f"✅ Cached {len(st.session_state.video_bytes_cache)/1e6:.2f}MB")
302
-
303
- st.video(st.session_state.video_bytes_cache)
304
- else:
305
- st.info("No video uploaded yet")
306
 
307
  with col2:
308
  st.header("2. Background Settings")
@@ -311,134 +324,110 @@ def main():
311
  "Select Background Type:",
312
  ["Image", "Color", "Blur"],
313
  horizontal=True,
314
- index=0,
315
  key="bg_type_radio"
316
  )
317
 
318
  if bg_type == "Image":
319
  bg_image = st.file_uploader(
320
- "🖼️ Upload Background Image",
321
  type=["jpg", "png", "jpeg"],
322
  key="bg_image_uploader"
323
  )
324
 
325
- # Check if image actually changed using id()
326
- current_bg_id = id(bg_image)
327
- if current_bg_id != st.session_state.last_bg_image_id:
328
- logger.info(f"🖼️ New background image: {bg_image.name if bg_image else 'None'}")
329
- st.session_state.last_bg_image_id = current_bg_id
330
- if bg_image is not None:
331
  st.session_state.bg_image_cache = Image.open(bg_image)
332
- st.session_state.bg_image_name = bg_image.name
333
- logger.info(f"✅ Background image cached: {bg_image.name}")
334
- else:
335
- st.session_state.bg_image_cache = None
336
-
337
- # Background preview
338
- bg_preview_container = st.container()
339
- with bg_preview_container:
340
- if st.session_state.bg_image_cache is not None:
341
- st.image(
342
- st.session_state.bg_image_cache,
343
- caption="Selected Background",
344
- use_container_width=True
345
- )
346
- else:
347
- st.info("No background image uploaded yet")
348
 
349
  elif bg_type == "Color":
350
  selected_color = st.color_picker(
351
- "🎨 Choose Background Color",
352
  st.session_state.bg_color,
353
  key="color_picker"
354
  )
355
 
356
- # Update only if color actually changed
357
- if selected_color != st.session_state.cached_color:
358
- logger.info(f"🎨 Color changed to: {selected_color}")
359
  st.session_state.bg_color = selected_color
360
- st.session_state.cached_color = selected_color
361
 
362
  color_rgb = tuple(int(selected_color.lstrip('#')[i:i+2], 16) for i in (0, 2, 4))
363
  color_display = np.zeros((100, 100, 3), dtype=np.uint8)
364
  color_display[:, :] = color_rgb[::-1]
365
  st.session_state.color_display_cache = color_display
366
 
367
- # Color preview
368
- color_preview_container = st.container()
369
- with color_preview_container:
370
- if st.session_state.color_display_cache is not None:
371
- st.image(st.session_state.color_display_cache, caption="Selected Color", width=200)
372
 
373
  st.header("3. Process & Download")
374
 
375
- with st.form("process_form"):
376
- submitted = st.form_submit_button(
377
- "🚀 Process Video",
378
- disabled=not st.session_state.uploaded_video or st.session_state.processing
379
- )
 
 
 
 
 
380
 
381
- if submitted and not st.session_state.processing:
382
- logger.info("🚀 PROCESS BUTTON CLICKED")
383
- st.session_state.processing = True
384
- st.session_state.process_complete = False
385
- st.session_state.processed_video_bytes = None
386
-
387
- with st.spinner("Processing video (this may take a few minutes)..."):
388
- try:
389
- background = None
390
- if bg_type == "Image" and st.session_state.bg_image_cache is not None:
391
- background = st.session_state.bg_image_cache
392
- logger.info("📦 Using background IMAGE")
393
- elif bg_type == "Color" and 'bg_color' in st.session_state:
394
- background = st.session_state.bg_color
395
- logger.info(f"📦 Using background COLOR: {background}")
396
-
397
- video_bytes = process_video(
398
- st.session_state.uploaded_video,
399
- background,
400
- bg_type=bg_type.lower()
401
- )
 
 
 
402
 
403
- if video_bytes and len(video_bytes) > 0:
404
- st.session_state.processed_video_bytes = video_bytes
405
- st.session_state.process_complete = True
406
- logger.info(f" Processing complete! Video size: {len(video_bytes)/1e6:.2f}MB")
407
- st.success("✅ Video processing complete!")
408
- else:
409
- logger.error("Processing returned empty or None")
410
- st.error("❌ Failed to process video. Please check the logs for details.")
411
-
412
- except Exception as e:
413
- logger.error(f"❌ Exception during processing: {str(e)}")
414
- logger.error(traceback.format_exc())
415
- st.error(f"❌ An error occurred: {str(e)}")
416
- finally:
417
- st.session_state.processing = False
418
- logger.info(f"🏁 Processing finished. Success: {st.session_state.process_complete}")
419
 
420
- # Show processed video if available (OUTSIDE the form)
421
  if st.session_state.processed_video_bytes is not None and len(st.session_state.processed_video_bytes) > 0:
422
  st.markdown("---")
423
- st.markdown("### Processed Video")
424
 
425
  try:
426
- logger.info(f"📺 Displaying processed video: {len(st.session_state.processed_video_bytes)/1e6:.2f}MB")
427
  st.video(st.session_state.processed_video_bytes)
428
 
429
  st.download_button(
430
- label="💾 Download Processed Video",
431
  data=st.session_state.processed_video_bytes,
432
  file_name="processed_video.mp4",
433
  mime="video/mp4",
434
- use_container_width=True,
435
- key="download_button"
436
  )
437
- logger.info("✅ Video displayed successfully")
438
 
439
  except Exception as e:
440
- logger.error(f"Error displaying video: {str(e)}")
441
- logger.error(traceback.format_exc())
442
  st.error(f"Error displaying video: {str(e)}")
443
 
444
  if __name__ == "__main__":
 
30
 
31
  # --- Streamlit Page Config ---
32
  st.set_page_config(
33
+ page_title="Advanced Video Background Replacer",
34
  page_icon="🎥",
35
  layout="wide",
36
  initial_sidebar_state="expanded"
37
  )
38
 
39
+ # --- GPU Diagnostic ---
40
+ def check_gpu():
41
+ """Check GPU availability and log details"""
42
+ logger.info("=" * 60)
43
+ logger.info("GPU DIAGNOSTIC")
44
+ logger.info("=" * 60)
45
+
46
+ cuda_available = torch.cuda.is_available()
47
+ logger.info(f"torch.cuda.is_available(): {cuda_available}")
48
+
49
+ if cuda_available:
50
+ logger.info(f"CUDA Version: {torch.version.cuda}")
51
+ logger.info(f"Device Count: {torch.cuda.device_count()}")
52
+ logger.info(f"Current Device: {torch.cuda.current_device()}")
53
+ logger.info(f"Device Name: {torch.cuda.get_device_name(0)}")
54
+ logger.info(f"Device Capability: {torch.cuda.get_device_capability(0)}")
55
+
56
+ # Test GPU tensor
57
+ try:
58
+ test_tensor = torch.randn(100, 100).cuda()
59
+ logger.info(f"GPU Test Tensor Created Successfully on: {test_tensor.device}")
60
+ del test_tensor
61
+ torch.cuda.empty_cache()
62
+ except Exception as e:
63
+ logger.error(f"GPU Test Failed: {e}")
64
+ else:
65
+ logger.warning("CUDA NOT AVAILABLE")
66
+ logger.info(f"PyTorch Version: {torch.__version__}")
67
+ logger.info(f"CUDA Built Version: {torch.version.cuda}")
68
+
69
+ logger.info("=" * 60)
70
+ return cuda_available
71
+
72
  # --- Custom CSS ---
73
  st.markdown("""
74
  <style>
 
92
  .stAlert {
93
  border-radius: 10px;
94
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  .video-container {
96
  border: 2px dashed #4CAF50;
97
  border-radius: 10px;
 
104
  # --- Session State Initialization ---
105
  def initialize_session_state():
106
  """Initialize all session state variables"""
107
+ if 'initialized' not in st.session_state:
108
+ st.session_state.initialized = True
109
+ st.session_state.uploaded_video = None
110
+ st.session_state.video_bytes_cache = None
111
+ st.session_state.bg_image_cache = None
112
+ st.session_state.bg_color = "#00FF00"
113
+ st.session_state.color_display_cache = None
114
+ st.session_state.processed_video_bytes = None
115
+ st.session_state.processing = False
116
+ st.session_state.process_complete = False
117
+
118
+ # Run GPU check on first init
119
+ gpu_available = check_gpu()
120
+ st.session_state.gpu_available = gpu_available
 
 
 
 
 
 
121
 
122
  # --- Video Processing ---
123
  def process_video(input_file, background, bg_type="image"):
124
+ """Process video with the selected background using SAM2 and MatAnyone pipeline."""
 
 
 
125
  logger.info("=" * 60)
126
+ logger.info("STARTING VIDEO PROCESSING")
127
  logger.info("=" * 60)
128
 
129
  try:
 
133
  temp_dir = temp_base / f"session_{int(time.time())}"
134
  temp_dir.mkdir(exist_ok=True)
135
 
136
+ logger.info(f"Temp directory: {temp_dir}")
137
 
138
+ # Save the uploaded video
139
  input_path = str(temp_dir / "input.mp4")
140
+ logger.info(f"Writing video to {input_path}")
141
 
142
+ input_file.seek(0) # Ensure we're at the start
143
  with open(input_path, "wb") as f:
144
+ written = f.write(input_file.read())
145
+ logger.info(f"Wrote {written/1e6:.2f}MB")
146
 
147
+ if not os.path.exists(input_path) or os.path.getsize(input_path) == 0:
148
+ raise FileNotFoundError(f"Input video not saved properly: {input_path}")
149
 
150
+ logger.info(f"Video file verified: {os.path.getsize(input_path)} bytes")
151
 
152
  # Prepare background
153
  bg_path = None
154
  if bg_type == "image" and background is not None:
155
+ logger.info("Processing background IMAGE")
156
  bg_cv = cv2.cvtColor(np.array(background), cv2.COLOR_RGB2BGR)
157
  bg_path = str(temp_dir / "background.jpg")
158
  cv2.imwrite(bg_path, bg_cv)
159
+ logger.info(f"Background image written: {bg_path}")
160
 
161
+ elif bg_type == "color":
162
+ logger.info(f"Processing background COLOR: {st.session_state.bg_color}")
163
  color_hex = st.session_state.bg_color.lstrip('#')
164
  color_rgb = tuple(int(color_hex[i:i+2], 16) for i in (0, 2, 4))
165
  bg_path = str(temp_dir / "background.jpg")
166
  cv2.imwrite(bg_path, np.ones((100, 100, 3), dtype=np.uint8) * color_rgb[::-1])
167
+ logger.info(f"Background color image written: {bg_path}")
168
 
169
+ # Progress tracking
170
  progress_placeholder = st.empty()
171
  status_placeholder = st.empty()
172
 
173
  def progress_callback(progress, message):
174
  progress = max(0, min(1, float(progress)))
175
+ logger.info(f"Progress: {progress*100:.1f}% - {message}")
176
  progress_placeholder.progress(progress)
177
  status_placeholder.text(f"Status: {message}")
178
 
179
+ # GPU check
180
  if torch.cuda.is_available():
181
+ device = torch.cuda.get_device_name(0)
182
+ mem_before = torch.cuda.memory_allocated()/1e9
183
+ logger.info(f"CUDA Device: {device}")
184
+ logger.info(f"GPU Memory Before: {mem_before:.2f}GB")
185
  else:
186
+ logger.warning("CUDA NOT AVAILABLE - Processing on CPU")
187
 
188
  # Process the video
189
  output_path = str(temp_dir / "output.mp4")
190
  click_points = [[0.5, 0.5]]
191
 
192
+ logger.info("Importing TwoStageProcessor...")
193
  from pipeline.integrated_pipeline import TwoStageProcessor
194
 
 
195
  @st.cache_resource
196
  def load_processor(temp_dir_str):
197
+ logger.info(f"Loading processor with temp_dir: {temp_dir_str}")
198
  return TwoStageProcessor(temp_dir=temp_dir_str)
199
 
200
  processor = load_processor(str(temp_dir))
201
+ logger.info("Processor loaded")
202
 
203
  try:
204
+ logger.info("Calling process_video...")
205
+ logger.info(f" Input: {input_path}")
206
+ logger.info(f" Background: {bg_path}")
207
+ logger.info(f" Output: {output_path}")
 
208
 
209
  success = processor.process_video(
210
  input_video=input_path,
 
215
  progress_callback=progress_callback
216
  )
217
 
218
+ logger.info(f"Processing returned: {success}")
219
 
220
  except Exception as e:
221
+ logger.error(f"Pipeline processing failed: {traceback.format_exc()}")
222
  raise
223
 
224
  if torch.cuda.is_available():
225
+ mem_after = torch.cuda.memory_allocated()/1e9
226
+ logger.info(f"GPU Memory After: {mem_after:.2f}GB")
227
  torch.cuda.empty_cache()
 
228
 
229
  if not success:
230
+ raise RuntimeError("Video processing returned False")
231
 
232
+ # Verify output
233
  if not os.path.exists(output_path):
234
+ logger.error(f"Output file does not exist: {output_path}")
235
  raise FileNotFoundError(f"Output video not created: {output_path}")
236
 
237
  output_size = os.path.getsize(output_path)
238
+ logger.info(f"Output file exists: {output_size} bytes ({output_size/1e6:.2f}MB)")
239
 
240
+ # Read output into memory
241
+ logger.info("Reading output video into memory...")
242
  with open(output_path, 'rb') as f:
243
  video_bytes = f.read()
244
 
245
+ logger.info(f"Read {len(video_bytes)/1e6:.2f}MB into memory")
246
 
247
+ # Cleanup
248
  try:
 
249
  shutil.rmtree(temp_dir)
250
+ logger.info("Temp directory cleaned")
251
  except Exception as e:
252
+ logger.warning(f"Could not clean temp directory: {e}")
253
 
254
  logger.info("=" * 60)
255
+ logger.info("VIDEO PROCESSING COMPLETED")
256
  logger.info("=" * 60)
257
 
258
  return video_bytes
259
 
260
  except Exception as e:
261
  logger.error("=" * 60)
262
+ logger.error(f"ERROR IN VIDEO PROCESSING: {str(e)}")
263
  logger.error(traceback.format_exc())
264
  logger.error("=" * 60)
265
  st.error(f"An error occurred during processing: {str(e)}")
 
267
 
268
  # --- Main Application ---
269
  def main():
270
+ st.title("Advanced Video Background Replacer")
271
  st.markdown("---")
272
 
273
  # Initialize session state
274
  initialize_session_state()
275
 
276
+ # GPU Status in sidebar
277
+ with st.sidebar:
278
+ st.subheader("System Status")
279
+ if st.session_state.gpu_available:
280
+ st.success(f"GPU: {torch.cuda.get_device_name(0)}")
281
+ else:
282
+ st.error("GPU: Not Available (using CPU)")
283
+
284
+ logger.info(f"Rerun - Processing: {st.session_state.processing}, Complete: {st.session_state.process_complete}")
285
 
286
  # Main layout
287
  col1, col2 = st.columns([1, 1], gap="large")
 
290
  st.header("1. Upload Video")
291
 
292
  uploaded = st.file_uploader(
293
+ "Upload Video",
294
  type=["mp4", "mov", "avi"],
295
  key="video_uploader"
296
  )
297
 
298
+ # Store uploaded video
299
+ if uploaded is not None:
300
+ if st.session_state.uploaded_video is None or uploaded.name != getattr(st.session_state.uploaded_video, 'name', ''):
301
+ logger.info(f"New video: {uploaded.name} ({uploaded.size} bytes)")
302
+ st.session_state.uploaded_video = uploaded
303
+ st.session_state.video_bytes_cache = None
304
+ st.session_state.processed_video_bytes = None
305
+ st.session_state.process_complete = False
 
306
 
307
+ # Video preview
308
  st.markdown("### Video Preview")
309
+ if st.session_state.uploaded_video is not None:
310
+ if st.session_state.video_bytes_cache is None:
311
+ logger.info("Caching video bytes...")
312
+ st.session_state.uploaded_video.seek(0)
313
+ st.session_state.video_bytes_cache = st.session_state.uploaded_video.read()
314
+ logger.info(f"Cached {len(st.session_state.video_bytes_cache)/1e6:.2f}MB")
315
+
316
+ st.video(st.session_state.video_bytes_cache)
317
+ else:
318
+ st.info("No video uploaded yet")
 
 
 
319
 
320
  with col2:
321
  st.header("2. Background Settings")
 
324
  "Select Background Type:",
325
  ["Image", "Color", "Blur"],
326
  horizontal=True,
 
327
  key="bg_type_radio"
328
  )
329
 
330
  if bg_type == "Image":
331
  bg_image = st.file_uploader(
332
+ "Upload Background Image",
333
  type=["jpg", "png", "jpeg"],
334
  key="bg_image_uploader"
335
  )
336
 
337
+ if bg_image is not None:
338
+ if st.session_state.bg_image_cache is None or bg_image.name != getattr(st.session_state.bg_image_cache, 'name', ''):
339
+ logger.info(f"New background: {bg_image.name}")
 
 
 
340
  st.session_state.bg_image_cache = Image.open(bg_image)
341
+ st.session_state.bg_image_cache.name = bg_image.name
342
+
343
+ st.image(st.session_state.bg_image_cache, caption="Selected Background", use_container_width=True)
344
+ else:
345
+ st.info("No background image uploaded yet")
 
 
 
 
 
 
 
 
 
 
 
346
 
347
  elif bg_type == "Color":
348
  selected_color = st.color_picker(
349
+ "Choose Background Color",
350
  st.session_state.bg_color,
351
  key="color_picker"
352
  )
353
 
354
+ if selected_color != st.session_state.bg_color:
355
+ logger.info(f"Color changed to: {selected_color}")
 
356
  st.session_state.bg_color = selected_color
 
357
 
358
  color_rgb = tuple(int(selected_color.lstrip('#')[i:i+2], 16) for i in (0, 2, 4))
359
  color_display = np.zeros((100, 100, 3), dtype=np.uint8)
360
  color_display[:, :] = color_rgb[::-1]
361
  st.session_state.color_display_cache = color_display
362
 
363
+ if st.session_state.color_display_cache is not None:
364
+ st.image(st.session_state.color_display_cache, caption="Selected Color", width=200)
 
 
 
365
 
366
  st.header("3. Process & Download")
367
 
368
+ # Simple button instead of form
369
+ if st.button(
370
+ "Process Video",
371
+ disabled=st.session_state.uploaded_video is None or st.session_state.processing,
372
+ use_container_width=True
373
+ ):
374
+ logger.info("PROCESS BUTTON CLICKED")
375
+ st.session_state.processing = True
376
+ st.session_state.process_complete = False
377
+ st.session_state.processed_video_bytes = None
378
 
379
+ with st.spinner("Processing video..."):
380
+ try:
381
+ background = None
382
+ if bg_type == "Image" and st.session_state.bg_image_cache is not None:
383
+ background = st.session_state.bg_image_cache
384
+ logger.info("Using background IMAGE")
385
+ elif bg_type == "Color":
386
+ background = st.session_state.bg_color
387
+ logger.info(f"Using background COLOR: {background}")
388
+
389
+ video_bytes = process_video(
390
+ st.session_state.uploaded_video,
391
+ background,
392
+ bg_type=bg_type.lower()
393
+ )
394
+
395
+ if video_bytes and len(video_bytes) > 0:
396
+ st.session_state.processed_video_bytes = video_bytes
397
+ st.session_state.process_complete = True
398
+ logger.info(f"Processing complete! {len(video_bytes)/1e6:.2f}MB")
399
+ st.success("Video processing complete!")
400
+ else:
401
+ logger.error("Processing returned empty or None")
402
+ st.error("Failed to process video")
403
 
404
+ except Exception as e:
405
+ logger.error(f"Exception: {str(e)}")
406
+ logger.error(traceback.format_exc())
407
+ st.error(f"An error occurred: {str(e)}")
408
+ finally:
409
+ st.session_state.processing = False
410
+ logger.info(f"Processing finished. Success: {st.session_state.process_complete}")
 
 
 
 
 
 
 
 
 
411
 
412
+ # Show processed video
413
  if st.session_state.processed_video_bytes is not None and len(st.session_state.processed_video_bytes) > 0:
414
  st.markdown("---")
415
+ st.markdown("### Processed Video")
416
 
417
  try:
418
+ logger.info(f"Displaying video: {len(st.session_state.processed_video_bytes)/1e6:.2f}MB")
419
  st.video(st.session_state.processed_video_bytes)
420
 
421
  st.download_button(
422
+ label="Download Processed Video",
423
  data=st.session_state.processed_video_bytes,
424
  file_name="processed_video.mp4",
425
  mime="video/mp4",
426
+ use_container_width=True
 
427
  )
 
428
 
429
  except Exception as e:
430
+ logger.error(f"Error displaying video: {str(e)}")
 
431
  st.error(f"Error displaying video: {str(e)}")
432
 
433
  if __name__ == "__main__":