MogensR commited on
Commit
3d9c3c0
Β·
1 Parent(s): 9f57b9b

Update ui/ui_components.py

Browse files
Files changed (1) hide show
  1. ui/ui_components.py +89 -42
ui/ui_components.py CHANGED
@@ -1,9 +1,11 @@
1
  #!/usr/bin/env python3
2
  """
3
  UI Components for BackgroundFX Pro
4
- - Layout only (no heavy logic here)
5
- - Delegates callbacks to ui/callbacks.py
6
- - Adds previews for uploaded video (first frame) and custom background image
 
 
7
  """
8
 
9
  from __future__ import annotations
@@ -17,8 +19,8 @@
17
  cb_clear,
18
  cb_generate_bg,
19
  cb_use_gen_bg,
20
- cb_video_changed, # should return a preview image (or None)
21
- cb_custom_bg_preview, # should return a preview image (or None)
22
  )
23
 
24
  CSS = """
@@ -34,7 +36,7 @@
34
  .preview-img { border-radius: var(--radius); border: 1px solid rgba(0,0,0,.08); }
35
  """
36
 
37
- # NOTE: Keep these keys in sync with utils/cv_processing.PROFESSIONAL_BACKGROUNDS
38
  _BG_CHOICES = [
39
  "minimalist",
40
  "office_modern",
@@ -44,6 +46,7 @@
44
  "tech_dark",
45
  ]
46
 
 
47
  def create_interface() -> gr.Blocks:
48
  with gr.Blocks(
49
  title="🎬 BackgroundFX Pro",
@@ -52,21 +55,28 @@ def create_interface() -> gr.Blocks:
52
  theme=gr.themes.Soft()
53
  ) as demo:
54
 
55
- # ---------- HERO ----------
 
 
56
  with gr.Row(elem_id="hero"):
57
  gr.Markdown(
58
- "## 🎬 BackgroundFX Pro\n"
59
- "Polished matting & background replacement for video. Runs on Hugging Face Spaces.\n"
60
- "Tip: **Load models** before processing for best results."
 
61
  )
62
 
63
- # ---------- QUICK START ----------
 
 
64
  with gr.Tab("🏁 Quick Start"):
 
65
  with gr.Row():
66
- # Left column: inputs & controls
67
  with gr.Column(scale=1):
68
  video = gr.Video(label="Upload Video", interactive=True)
69
- # Small live preview (first frame)
 
70
  video_preview = gr.Image(
71
  label="Video Preview (first frame)",
72
  interactive=False,
@@ -77,93 +87,133 @@ def create_interface() -> gr.Blocks:
77
  label="Background Style",
78
  choices=_BG_CHOICES,
79
  value="minimalist",
80
- info="Matches built-in PROFESSIONAL_BACKGROUNDS keys."
81
  )
 
82
  custom_bg = gr.File(
83
- label="Custom Background (Optional)",
84
  file_types=["image"],
85
  interactive=True
86
  )
87
- # Custom background preview
88
  custom_bg_preview_img = gr.Image(
89
  label="Custom Background Preview",
90
  interactive=False,
91
  elem_classes=["preview-img"]
92
  )
93
 
 
94
  with gr.Accordion("Advanced", open=False):
95
- use_two_stage = gr.Checkbox(label="Use Two-Stage Pipeline", value=False)
 
 
 
 
96
  chroma_preset = gr.Dropdown(
97
  label="Chroma Preset",
98
- choices=["standard"],
99
  value="standard"
100
  )
 
 
 
 
 
 
 
 
101
  preview_mask = gr.Checkbox(
102
- label="Preview Mask (no audio remix)",
103
  value=False
104
  )
 
105
  preview_greenscreen = gr.Checkbox(
106
- label="Preview Greenscreen (no audio remix)",
107
  value=False
108
  )
109
 
110
  with gr.Row():
111
- btn_load = gr.Button("πŸ”„ Load Models", variant="secondary")
112
- btn_run = gr.Button("🎬 Process Video", variant="primary")
113
- btn_cancel = gr.Button("⏹️ Cancel", variant="secondary")
114
 
115
- # Right column: outputs & status
116
  with gr.Column(scale=1):
117
  out_video = gr.Video(label="Processed Output", interactive=False)
118
  statusbox = gr.Textbox(label="Status", lines=8, elem_id="statusbox")
 
119
  with gr.Row():
120
  btn_refresh = gr.Button("πŸ” Refresh Status", variant="secondary")
121
- btn_clear = gr.Button("🧹 Clear", variant="secondary")
122
 
123
- # ---------- AI BACKGROUND ----------
 
 
124
  with gr.Tab("🧠 AI Background (Lightweight)"):
 
125
  with gr.Row():
126
  with gr.Column(scale=1):
127
  prompt = gr.Textbox(
128
  label="Describe vibe",
129
  value="modern office",
130
- info="Examples: 'modern office', 'soft sunset studio', 'cool tech dark', 'forest ambience'"
131
  )
 
132
  with gr.Row():
133
- gen_width = gr.Slider(640, 1920, value=1280, step=10, label="Width")
134
- gen_height = gr.Slider(360, 1080, value=720, step=10, label="Height")
 
135
  with gr.Row():
136
- bokeh = gr.Slider(0, 30, value=8, step=1, label="Bokeh Blur")
137
- vignette = gr.Slider(0.0, 0.6, value=0.15, step=0.01, label="Vignette")
138
- contrast = gr.Slider(0.8, 1.4, value=1.05, step=0.01, label="Contrast")
139
 
140
  btn_gen_bg = gr.Button("✨ Generate Background", variant="primary")
141
 
142
  with gr.Column(scale=1):
143
- gen_preview = gr.Image(label="Generated Background", interactive=False, elem_classes=["preview-img"])
 
 
 
 
144
  gen_path = gr.Textbox(label="Saved Path", interactive=False)
145
- use_gen_as_custom = gr.Button("πŸ“Œ Use As Custom Background", variant="secondary")
146
 
147
- # ---------- STATUS ----------
 
 
148
  with gr.Tab("πŸ“ˆ Status & Settings"):
149
  with gr.Row():
150
  with gr.Column(scale=1, elem_classes=["card"]):
151
  model_status = gr.JSON(label="Model Status")
152
  with gr.Column(scale=1, elem_classes=["card"]):
153
  cache_status = gr.JSON(label="Cache / System Status")
 
154
  gr.Markdown(
155
  "<div class='footer-note'>If models fail to load, fallbacks keep the UI responsive. "
156
- "Check logs for details.</div>"
157
  )
158
 
159
- # ---------- CALLBACK WIRING ----------
160
- # Core actions
 
161
  btn_load.click(cb_load_models, outputs=statusbox)
 
162
  btn_run.click(
163
  cb_process_video,
164
- inputs=[video, bg_style, custom_bg, use_two_stage, chroma_preset, preview_mask, preview_greenscreen],
 
 
 
 
 
 
 
 
 
165
  outputs=[out_video, statusbox],
166
  )
 
167
  btn_cancel.click(cb_cancel, outputs=statusbox)
168
  btn_refresh.click(cb_status, outputs=[model_status, cache_status])
169
  btn_clear.click(cb_clear, outputs=[out_video, statusbox, gen_preview, gen_path])
@@ -177,9 +227,6 @@ def create_interface() -> gr.Blocks:
177
  use_gen_as_custom.click(cb_use_gen_bg, inputs=[gen_path], outputs=[custom_bg])
178
 
179
  # Live previews
180
- # Expectation:
181
- # - cb_video_changed(video_path) -> PIL.Image | numpy array | None
182
- # - cb_custom_bg_preview(file_obj) -> PIL.Image | numpy array | None
183
  video.change(cb_video_changed, inputs=[video], outputs=[video_preview])
184
  custom_bg.change(cb_custom_bg_preview, inputs=[custom_bg], outputs=[custom_bg_preview_img])
185
 
 
1
  #!/usr/bin/env python3
2
  """
3
  UI Components for BackgroundFX Pro
4
+ ----------------------------------
5
+ * Pure layout: no heavy logic
6
+ * All callbacks live in ui/callbacks.py
7
+ * Adds live previews for the first frame of the uploaded video
8
+ and for the custom background image
9
  """
10
 
11
  from __future__ import annotations
 
19
  cb_clear,
20
  cb_generate_bg,
21
  cb_use_gen_bg,
22
+ cb_video_changed,
23
+ cb_custom_bg_preview,
24
  )
25
 
26
  CSS = """
 
36
  .preview-img { border-radius: var(--radius); border: 1px solid rgba(0,0,0,.08); }
37
  """
38
 
39
+ # Keep in sync with utils/cv_processing.PROFESSIONAL_BACKGROUNDS
40
  _BG_CHOICES = [
41
  "minimalist",
42
  "office_modern",
 
46
  "tech_dark",
47
  ]
48
 
49
+
50
  def create_interface() -> gr.Blocks:
51
  with gr.Blocks(
52
  title="🎬 BackgroundFX Pro",
 
55
  theme=gr.themes.Soft()
56
  ) as demo:
57
 
58
+ # ------------------------------------------------------------------
59
+ # HERO
60
+ # ------------------------------------------------------------------
61
  with gr.Row(elem_id="hero"):
62
  gr.Markdown(
63
+ "## 🎬 BackgroundFX Pro (CSP-Safe)\n"
64
+ "Replace your video background with cinema-quality AI matting. "
65
+ "Built for Hugging Face Spaces CSP.\n\n"
66
+ "_Tip: press **Load Models** once after the Space spins up._"
67
  )
68
 
69
+ # ------------------------------------------------------------------
70
+ # TAB – Quick Start
71
+ # ------------------------------------------------------------------
72
  with gr.Tab("🏁 Quick Start"):
73
+
74
  with gr.Row():
75
+ # ── Left column ────────────────────────────────────────────
76
  with gr.Column(scale=1):
77
  video = gr.Video(label="Upload Video", interactive=True)
78
+
79
+ # First-frame live preview
80
  video_preview = gr.Image(
81
  label="Video Preview (first frame)",
82
  interactive=False,
 
87
  label="Background Style",
88
  choices=_BG_CHOICES,
89
  value="minimalist",
90
+ info="Matches keys in PROFESSIONAL_BACKGROUNDS"
91
  )
92
+
93
  custom_bg = gr.File(
94
+ label="Custom Background (optional)",
95
  file_types=["image"],
96
  interactive=True
97
  )
98
+
99
  custom_bg_preview_img = gr.Image(
100
  label="Custom Background Preview",
101
  interactive=False,
102
  elem_classes=["preview-img"]
103
  )
104
 
105
+ # ── Advanced options accordion ───────────────────────
106
  with gr.Accordion("Advanced", open=False):
107
+ use_two_stage = gr.Checkbox(
108
+ label="Use Two-Stage Pipeline",
109
+ value=False
110
+ )
111
+
112
  chroma_preset = gr.Dropdown(
113
  label="Chroma Preset",
114
+ choices=["standard"], # can add 'studio', 'outdoor' later
115
  value="standard"
116
  )
117
+
118
+ key_color_mode = gr.Dropdown(
119
+ label="Key-Colour Mode",
120
+ choices=["auto", "green", "blue", "cyan", "magenta"],
121
+ value="auto",
122
+ info="Auto picks a colour far from your clothes; override if needed."
123
+ )
124
+
125
  preview_mask = gr.Checkbox(
126
+ label="Preview Mask only (mute audio)",
127
  value=False
128
  )
129
+
130
  preview_greenscreen = gr.Checkbox(
131
+ label="Preview Green-screen only (mute audio)",
132
  value=False
133
  )
134
 
135
  with gr.Row():
136
+ btn_load = gr.Button("πŸ”„ Load Models", variant="secondary")
137
+ btn_run = gr.Button("🎬 Process Video", variant="primary")
138
+ btn_cancel = gr.Button("⏹️ Cancel", variant="secondary")
139
 
140
+ # ── Right column ──────────────────────────────────────────
141
  with gr.Column(scale=1):
142
  out_video = gr.Video(label="Processed Output", interactive=False)
143
  statusbox = gr.Textbox(label="Status", lines=8, elem_id="statusbox")
144
+
145
  with gr.Row():
146
  btn_refresh = gr.Button("πŸ” Refresh Status", variant="secondary")
147
+ btn_clear = gr.Button("🧹 Clear", variant="secondary")
148
 
149
+ # ------------------------------------------------------------------
150
+ # TAB – AI background (optional lightweight generator)
151
+ # ------------------------------------------------------------------
152
  with gr.Tab("🧠 AI Background (Lightweight)"):
153
+
154
  with gr.Row():
155
  with gr.Column(scale=1):
156
  prompt = gr.Textbox(
157
  label="Describe vibe",
158
  value="modern office",
159
+ info="e.g. 'soft sunset studio', 'cool tech dark', 'forest ambience'"
160
  )
161
+
162
  with gr.Row():
163
+ gen_width = gr.Slider(640, 1920, 1280, step=10, label="Width")
164
+ gen_height = gr.Slider(360, 1080, 720, step=10, label="Height")
165
+
166
  with gr.Row():
167
+ bokeh = gr.Slider(0, 30, 8, step=1, label="Bokeh Blur")
168
+ vignette = gr.Slider(0, 0.6, 0.15, step=0.01, label="Vignette")
169
+ contrast = gr.Slider(0.8, 1.4, 1.05, step=0.01, label="Contrast")
170
 
171
  btn_gen_bg = gr.Button("✨ Generate Background", variant="primary")
172
 
173
  with gr.Column(scale=1):
174
+ gen_preview = gr.Image(
175
+ label="Generated Background",
176
+ interactive=False,
177
+ elem_classes=["preview-img"]
178
+ )
179
  gen_path = gr.Textbox(label="Saved Path", interactive=False)
180
+ use_gen_as_custom = gr.Button("πŸ“Œ Use as Custom Background", variant="secondary")
181
 
182
+ # ------------------------------------------------------------------
183
+ # TAB – Status & settings
184
+ # ------------------------------------------------------------------
185
  with gr.Tab("πŸ“ˆ Status & Settings"):
186
  with gr.Row():
187
  with gr.Column(scale=1, elem_classes=["card"]):
188
  model_status = gr.JSON(label="Model Status")
189
  with gr.Column(scale=1, elem_classes=["card"]):
190
  cache_status = gr.JSON(label="Cache / System Status")
191
+
192
  gr.Markdown(
193
  "<div class='footer-note'>If models fail to load, fallbacks keep the UI responsive. "
194
+ "Check the runtime log for details.</div>"
195
  )
196
 
197
+ # ------------------------------------------------------------------
198
+ # Callback wiring
199
+ # ------------------------------------------------------------------
200
  btn_load.click(cb_load_models, outputs=statusbox)
201
+
202
  btn_run.click(
203
  cb_process_video,
204
+ inputs=[
205
+ video,
206
+ bg_style,
207
+ custom_bg,
208
+ use_two_stage,
209
+ chroma_preset,
210
+ key_color_mode, # NEW
211
+ preview_mask,
212
+ preview_greenscreen,
213
+ ],
214
  outputs=[out_video, statusbox],
215
  )
216
+
217
  btn_cancel.click(cb_cancel, outputs=statusbox)
218
  btn_refresh.click(cb_status, outputs=[model_status, cache_status])
219
  btn_clear.click(cb_clear, outputs=[out_video, statusbox, gen_preview, gen_path])
 
227
  use_gen_as_custom.click(cb_use_gen_bg, inputs=[gen_path], outputs=[custom_bg])
228
 
229
  # Live previews
 
 
 
230
  video.change(cb_video_changed, inputs=[video], outputs=[video_preview])
231
  custom_bg.change(cb_custom_bg_preview, inputs=[custom_bg], outputs=[custom_bg_preview_img])
232