MogensR commited on
Commit
9a8f4a0
·
verified ·
1 Parent(s): 27430ce

Update ui.py

Browse files
Files changed (1) hide show
  1. ui.py +64 -17
ui.py CHANGED
@@ -3,7 +3,7 @@
3
  Modern UI for Video Background Replacer (PRO)
4
  - Clean, responsive Streamlit layout
5
  - Shows live stage progress and all errors during processing
6
- - NO automatic reruns (no st.rerun) to avoid killing long-running jobs
7
  """
8
  import streamlit as st
9
  import os
@@ -14,7 +14,7 @@
14
  import time
15
 
16
  logger = logging.getLogger("Advanced Video Background Replacer")
17
- UI_BUILD = "ui-2025-10-04-10-30Z" # visible in sidebar so you know this file is active
18
 
19
  def tail_file(path: str, lines: int = 400) -> str:
20
  if not os.path.exists(path):
@@ -36,7 +36,6 @@ def read_file_bytes(path: str) -> bytes:
36
  return b""
37
 
38
  def _render_background_settings():
39
- # Available stock images (may not exist in Space)
40
  stock_images = {
41
  "Sunset Beach": "stock_images/sunset_beach.jpg",
42
  "Urban Office": "stock_images/urban_office.jpg",
@@ -94,7 +93,6 @@ def _render_background_settings():
94
  prompt = st.text_input("Describe the background to generate (AI):", key="ai_bg_prompt")
95
  ai_ready = False
96
  if st.button("Generate Background", key="gen_bg_btn") and prompt:
97
- # TODO: Plug in real AI image generator
98
  background = Image.new("RGB", (512, 320), (64, 32, 96))
99
  st.session_state.generated_bg = background
100
  st.success("AI-generated background (stub). Replace with your generator!")
@@ -115,7 +113,6 @@ def render_ui(process_video_func):
115
  st.caption(f"UI build: {UI_BUILD}")
116
  st.markdown("**Log file:** `/tmp/app.log`")
117
 
118
- # GPU indicator (best-effort)
119
  if st.session_state.get('gpu_available', False):
120
  try:
121
  import torch
@@ -126,7 +123,6 @@ def render_ui(process_video_func):
126
  else:
127
  st.error("GPU: Not Available")
128
 
129
- # Log tail controls (NO auto refresh, only manual button)
130
  st.number_input("Tail last N lines", min_value=50, max_value=5000, step=50, key="log_tail_lines")
131
  log_bytes = read_file_bytes("/tmp/app.log")
132
  st.download_button(
@@ -160,7 +156,7 @@ def render_ui(process_video_func):
160
  try:
161
  uploaded_video.seek(0)
162
  video_bytes = uploaded_video.read()
163
- st.session_state.video_bytes_cache = video_bytes # persist across reruns
164
  with video_preview_placeholder.container():
165
  st.video(video_bytes)
166
  except Exception as e:
@@ -173,23 +169,73 @@ def render_ui(process_video_func):
173
  with col2:
174
  background, bg_type = _render_background_settings()
175
  st.header("3. Process Video")
176
- status_box = st.empty() # progress area
177
-
 
 
 
 
 
 
178
  can_process = (
179
  st.session_state.get('video_bytes_cache') is not None
180
  and not st.session_state.get('processing', False)
181
  and (background is not None)
182
  )
183
 
 
 
 
184
  def progress_callback(msg):
185
- status_box.info(msg)
186
  logger.info(f"[STAGE] {msg}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
  if st.button("Process Video", disabled=not can_process, use_container_width=True):
189
  try:
190
  logger.info("Process Video button clicked")
 
 
 
 
 
 
191
 
192
- # Rebuild a file-like object from cached bytes so we don't depend on the upload widget object
193
  import io
194
  class _MemFile:
195
  def __init__(self, name, data):
@@ -209,15 +255,16 @@ def seek(self, pos):
209
 
210
  st.session_state.processing = False
211
  if success:
212
- status_box.success("✅ Video processing complete!")
 
213
  st.success("Video processing complete!")
214
  else:
215
- status_box.error(" Video processing failed. Check logs for details.")
216
  st.error("Video processing failed. Check logs for details.")
217
  except Exception as e:
218
  st.session_state.processing = False
219
  logger.error(f"[UI] Process video error: {e}", exc_info=True)
220
- status_box.error(f"Processing error: {str(e)}. Check logs for details.")
221
  st.error(f"Processing error: {str(e)}. Check logs for details.")
222
 
223
  # --- Results Display ---
@@ -239,11 +286,11 @@ def seek(self, pos):
239
 
240
  # --- Error Display ---
241
  if st.session_state.get('last_error'):
242
- with st.expander("⚠️ Last Error", expanded=True):
243
  st.error(st.session_state.last_error)
244
  if st.button("Clear Error"):
245
  st.session_state.last_error = None
246
- # No st.rerun() — the next interaction will refresh naturally
247
  except Exception as e:
248
  logger.error(f"[UI] Render UI error: {e}", exc_info=True)
249
- st.error(f"UI rendering error: {str(e)}. Check logs for details.")
 
3
  Modern UI for Video Background Replacer (PRO)
4
  - Clean, responsive Streamlit layout
5
  - Shows live stage progress and all errors during processing
6
+ - Progress bars and visual feedback to keep session alive
7
  """
8
  import streamlit as st
9
  import os
 
14
  import time
15
 
16
  logger = logging.getLogger("Advanced Video Background Replacer")
17
+ UI_BUILD = "ui-2025-10-04-16-00Z"
18
 
19
  def tail_file(path: str, lines: int = 400) -> str:
20
  if not os.path.exists(path):
 
36
  return b""
37
 
38
  def _render_background_settings():
 
39
  stock_images = {
40
  "Sunset Beach": "stock_images/sunset_beach.jpg",
41
  "Urban Office": "stock_images/urban_office.jpg",
 
93
  prompt = st.text_input("Describe the background to generate (AI):", key="ai_bg_prompt")
94
  ai_ready = False
95
  if st.button("Generate Background", key="gen_bg_btn") and prompt:
 
96
  background = Image.new("RGB", (512, 320), (64, 32, 96))
97
  st.session_state.generated_bg = background
98
  st.success("AI-generated background (stub). Replace with your generator!")
 
113
  st.caption(f"UI build: {UI_BUILD}")
114
  st.markdown("**Log file:** `/tmp/app.log`")
115
 
 
116
  if st.session_state.get('gpu_available', False):
117
  try:
118
  import torch
 
123
  else:
124
  st.error("GPU: Not Available")
125
 
 
126
  st.number_input("Tail last N lines", min_value=50, max_value=5000, step=50, key="log_tail_lines")
127
  log_bytes = read_file_bytes("/tmp/app.log")
128
  st.download_button(
 
156
  try:
157
  uploaded_video.seek(0)
158
  video_bytes = uploaded_video.read()
159
+ st.session_state.video_bytes_cache = video_bytes
160
  with video_preview_placeholder.container():
161
  st.video(video_bytes)
162
  except Exception as e:
 
169
  with col2:
170
  background, bg_type = _render_background_settings()
171
  st.header("3. Process Video")
172
+
173
+ # Progress tracking UI elements
174
+ progress_container = st.container()
175
+ with progress_container:
176
+ progress_bar = st.progress(0)
177
+ status_text = st.empty()
178
+ stage_status = st.empty()
179
+
180
  can_process = (
181
  st.session_state.get('video_bytes_cache') is not None
182
  and not st.session_state.get('processing', False)
183
  and (background is not None)
184
  )
185
 
186
+ # Enhanced progress callback with visual updates
187
+ progress_state = {"step": 0, "total_steps": 12}
188
+
189
  def progress_callback(msg):
190
+ status_text.info(f"**Status:** {msg}")
191
  logger.info(f"[STAGE] {msg}")
192
+
193
+ # Update progress based on message content
194
+ if "Stage 1 initiated" in msg:
195
+ progress_state["step"] = 1
196
+ stage_status.markdown("**Current Stage:** Stage 1 - Transparent Video Creation")
197
+ elif "GPU engaged" in msg or "SAM2" in msg:
198
+ progress_state["step"] = 2
199
+ elif "SAM2 processing frame" in msg:
200
+ progress_state["step"] = 3
201
+ elif "SAM2 complete" in msg or "clearing GPU" in msg:
202
+ progress_state["step"] = 4
203
+ elif "MatAnyone starting" in msg:
204
+ progress_state["step"] = 5
205
+ stage_status.markdown("**Current Stage:** Stage 1 - MatAnyone Processing")
206
+ elif "MatAnyone processing" in msg:
207
+ progress_state["step"] = 6
208
+ elif "MatAnyone complete" in msg:
209
+ progress_state["step"] = 7
210
+ elif "Smoothing" in msg:
211
+ progress_state["step"] = 8
212
+ elif "transparent video" in msg and "Creating" in msg:
213
+ progress_state["step"] = 9
214
+ elif "Stage 1 complete" in msg:
215
+ progress_state["step"] = 10
216
+ elif "Stage 2 begun" in msg:
217
+ progress_state["step"] = 10
218
+ stage_status.markdown("**Current Stage:** Stage 2 - Background Compositing")
219
+ elif "Compositing frames" in msg:
220
+ progress_state["step"] = 11
221
+ elif "Stage 2 complete" in msg:
222
+ progress_state["step"] = 12
223
+ stage_status.markdown("**Current Stage:** Complete!")
224
+
225
+ # Update progress bar
226
+ progress_pct = min(100, int((progress_state["step"] / progress_state["total_steps"]) * 100))
227
+ progress_bar.progress(progress_pct)
228
 
229
  if st.button("Process Video", disabled=not can_process, use_container_width=True):
230
  try:
231
  logger.info("Process Video button clicked")
232
+
233
+ # Reset progress
234
+ progress_state["step"] = 0
235
+ progress_bar.progress(0)
236
+ status_text.empty()
237
+ stage_status.empty()
238
 
 
239
  import io
240
  class _MemFile:
241
  def __init__(self, name, data):
 
255
 
256
  st.session_state.processing = False
257
  if success:
258
+ progress_bar.progress(100)
259
+ status_text.success("**Status:** Processing complete!")
260
  st.success("Video processing complete!")
261
  else:
262
+ status_text.error("**Status:** Processing failed. Check logs for details.")
263
  st.error("Video processing failed. Check logs for details.")
264
  except Exception as e:
265
  st.session_state.processing = False
266
  logger.error(f"[UI] Process video error: {e}", exc_info=True)
267
+ status_text.error(f"**Status:** Error - {str(e)}")
268
  st.error(f"Processing error: {str(e)}. Check logs for details.")
269
 
270
  # --- Results Display ---
 
286
 
287
  # --- Error Display ---
288
  if st.session_state.get('last_error'):
289
+ with st.expander("Last Error", expanded=True):
290
  st.error(st.session_state.last_error)
291
  if st.button("Clear Error"):
292
  st.session_state.last_error = None
293
+
294
  except Exception as e:
295
  logger.error(f"[UI] Render UI error: {e}", exc_info=True)
296
+ st.error(f"UI rendering error: {str(e)}. Check logs for details.")