3v324v23 commited on
Commit
b0cc56a
·
1 Parent(s): 4fa7797
Files changed (3) hide show
  1. app.py +206 -0
  2. pyproject.toml +18 -0
  3. requirements.txt +10 -0
app.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ from typing import cast
4
+ import torch
5
+ from PIL import Image
6
+ from diffusers import DiffusionPipeline
7
+ import gradio as gr
8
+ from gradio.components.image_editor import EditorValue
9
+ import spaces
10
+
11
+ DEVICE = "cuda"
12
+
13
+ MAIN_MODEL_REPO_ID = os.getenv("MAIN_MODEL_REPO_ID", None)
14
+ SUB_MODEL_REPO_ID = os.getenv("SUB_MODEL_REPO_ID", None)
15
+ SUB_MODEL_SUBFOLDER = os.getenv("SUB_MODEL_SUBFOLDER", None)
16
+
17
+ if MAIN_MODEL_REPO_ID is None:
18
+ raise ValueError("MAIN_MODEL_REPO_ID is not set")
19
+ if SUB_MODEL_REPO_ID is None:
20
+ raise ValueError("SUB_MODEL_REPO_ID is not set")
21
+ if SUB_MODEL_SUBFOLDER is None:
22
+ raise ValueError("SUB_MODEL_SUBFOLDER is not set")
23
+
24
+ pipeline = DiffusionPipeline.from_pretrained(
25
+ MAIN_MODEL_REPO_ID,
26
+ torch_dtype=torch.bfloat16,
27
+ custom_pipeline=SUB_MODEL_REPO_ID,
28
+ ).to(DEVICE)
29
+
30
+
31
+ def crop_divisible_by_16(image: Image.Image) -> Image.Image:
32
+ w, h = image.size
33
+ w = w - w % 16
34
+ h = h - h % 16
35
+ return image.crop((0, 0, w, h))
36
+
37
+
38
+ @spaces.GPU(duration=150)
39
+ def predict(
40
+ image_and_mask: EditorValue | None,
41
+ seed: int = 0,
42
+ num_inference_steps: int = 28,
43
+ max_dimension: int = 1024,
44
+ condition_scale: float = 1.0,
45
+ progress: gr.Progress = gr.Progress(track_tqdm=True), # noqa: ARG001, B008
46
+ ) -> Image.Image | None:
47
+ if not image_and_mask:
48
+ gr.Info("Please upload an image and draw a mask")
49
+ return None
50
+ image_np = image_and_mask["background"]
51
+ image_np = cast(np.ndarray, image_np)
52
+
53
+ # If the image is empty, return None
54
+ if np.sum(image_np) == 0:
55
+ gr.Info("Please upload an image")
56
+ return None
57
+
58
+ alpha_channel = image_and_mask["layers"][0]
59
+ alpha_channel = cast(np.ndarray, alpha_channel)
60
+ mask_np = np.where(alpha_channel[:, :, 3] == 0, 0, 255).astype(np.uint8)
61
+
62
+ # if mask_np is empty, return None
63
+ if np.sum(mask_np) == 0:
64
+ gr.Info("Please mark the areas you want to remove")
65
+ return None
66
+
67
+ pipeline.load(
68
+ SUB_MODEL_REPO_ID,
69
+ subfolder=SUB_MODEL_SUBFOLDER,
70
+ )
71
+
72
+ image = Image.fromarray(image_np)
73
+ # Resize to max dimension
74
+ image.thumbnail((max_dimension, max_dimension))
75
+ # Ensure dimensions are multiple of 16 (for VAE)
76
+ image = crop_divisible_by_16(image)
77
+
78
+ mask = Image.fromarray(mask_np)
79
+ mask.thumbnail((max_dimension, max_dimension))
80
+ mask = crop_divisible_by_16(mask)
81
+
82
+ # Image masked is the image with the mask applied (black background)
83
+ image_masked = Image.new("RGBA", image.size, (0, 0, 0, 0))
84
+ image_masked.paste(image, (0, 0), mask)
85
+
86
+ prompt = "[VIRTUAL STAGING]. An empty room."
87
+
88
+ generator = torch.Generator(device="cpu").manual_seed(seed)
89
+
90
+ final_image = pipeline(
91
+ condition_image=image_masked,
92
+ condition_scale=condition_scale,
93
+ prompt=prompt,
94
+ num_inference_steps=num_inference_steps,
95
+ generator=generator,
96
+ max_sequence_length=512,
97
+ ).images[0]
98
+
99
+ return final_image
100
+
101
+
102
+ intro_markdown = r"""
103
+ # Inpainting Demo
104
+ """
105
+
106
+ css = r"""
107
+ #col-left {
108
+ margin: 0 auto;
109
+ max-width: 650px;
110
+ }
111
+ #col-right {
112
+ margin: 0 auto;
113
+ max-width: 650px;
114
+ }
115
+ #col-showcase {
116
+ margin: 0 auto;
117
+ max-width: 1100px;
118
+ }
119
+ """
120
+
121
+
122
+ with gr.Blocks(css=css) as demo:
123
+ gr.Markdown(intro_markdown)
124
+
125
+ with gr.Row() as content:
126
+ with gr.Column(elem_id="col-left"):
127
+ gr.HTML(
128
+ """
129
+ <div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
130
+ <div>
131
+ Step 1. Upload a room image ⬇️
132
+ </div>
133
+ </div>
134
+ """,
135
+ max_height=50,
136
+ )
137
+ image_and_mask = gr.ImageMask(
138
+ label="Image and Mask",
139
+ layers=False,
140
+ show_fullscreen_button=False,
141
+ sources=["upload"],
142
+ show_download_button=False,
143
+ interactive=True,
144
+ brush=gr.Brush(default_size=75, colors=["#000000"], color_mode="fixed"),
145
+ transforms=[],
146
+ )
147
+ with gr.Column(elem_id="col-right"):
148
+ gr.HTML(
149
+ """
150
+ <div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
151
+ <div>
152
+ Step 2. Press Run to launch
153
+ </div>
154
+ </div>
155
+ """,
156
+ max_height=50,
157
+ )
158
+ result = gr.Image(label="result")
159
+ run_button = gr.Button("Run")
160
+
161
+ with gr.Accordion("Advanced Settings", open=False):
162
+ seed = gr.Slider(
163
+ label="Seed",
164
+ minimum=0,
165
+ maximum=100_000,
166
+ step=1,
167
+ value=0,
168
+ )
169
+ condition_scale = gr.Slider(
170
+ label="Condition Scale",
171
+ minimum=-10.0,
172
+ maximum=10.0,
173
+ step=0.10,
174
+ value=1.0,
175
+ )
176
+ with gr.Column():
177
+ max_dimension = gr.Slider(
178
+ label="Max Dimension",
179
+ minimum=512,
180
+ maximum=2048,
181
+ step=128,
182
+ value=1024,
183
+ )
184
+
185
+ num_inference_steps = gr.Slider(
186
+ label="Number of inference steps",
187
+ minimum=1,
188
+ maximum=50,
189
+ step=1,
190
+ value=28,
191
+ )
192
+
193
+ run_button.click(
194
+ fn=predict,
195
+ inputs=[
196
+ image_and_mask,
197
+ seed,
198
+ num_inference_steps,
199
+ max_dimension,
200
+ condition_scale,
201
+ ],
202
+ outputs=[result],
203
+ )
204
+
205
+
206
+ demo.launch()
pyproject.toml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "VirtualStaging"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "accelerate>=1.2.1",
9
+ "diffusers==0.31.0",
10
+ "gradio>=5.12.0",
11
+ "gradio-imageslider>=0.0.20",
12
+ "peft>=0.14.0",
13
+ "pillow>=11.1.0",
14
+ "safetensors>=0.5.2",
15
+ "sentencepiece>=0.2.0",
16
+ "spaces>=0.32.0",
17
+ "transformers>=4.48.0",
18
+ ]
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ diffusers==0.31.0
2
+ transformers
3
+ accelerate
4
+ safetensors
5
+ sentencepiece
6
+ peft
7
+ gradio
8
+ spaces
9
+ pillow
10
+ gradio_imageslider