Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
"""
|
2 |
-
Gradio Space: GPT
|
3 |
Generate · Edit (paint mask!) · Variations
|
4 |
==========================================
|
5 |
-
Adds an **in
|
6 |
draw the mask directly instead of uploading one.
|
7 |
|
8 |
### How mask painting works
|
@@ -41,8 +41,9 @@ def _client(key: str) -> openai.OpenAI:
|
|
41 |
return openai.OpenAI(api_key=api_key)
|
42 |
|
43 |
|
44 |
-
def _img_list(resp, *, fmt: str
|
45 |
-
|
|
|
46 |
return [
|
47 |
f"data:{mime};base64,{d.b64_json}" if hasattr(d, "b64_json") else d.url
|
48 |
for d in resp.data
|
@@ -58,19 +59,27 @@ def _common_kwargs(
|
|
58 |
compression: int,
|
59 |
transparent_bg: bool,
|
60 |
):
|
61 |
-
|
|
|
62 |
model=MODEL,
|
63 |
n=n,
|
64 |
size=size,
|
65 |
quality=quality,
|
66 |
output_format=out_fmt,
|
67 |
-
transparent_background=transparent_bg,
|
68 |
-
response_format="url" if out_fmt == "png" and not transparent_bg else "b64_json",
|
69 |
)
|
|
|
|
|
70 |
if prompt is not None:
|
71 |
kwargs["prompt"] = prompt
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
if out_fmt in {"jpeg", "webp"}:
|
73 |
-
kwargs["
|
|
|
74 |
return kwargs
|
75 |
|
76 |
|
@@ -91,7 +100,7 @@ def generate(
|
|
91 |
resp = client.images.generate(**_common_kwargs(prompt, n, size, quality, out_fmt, compression, transparent_bg))
|
92 |
except Exception as e:
|
93 |
raise gr.Error(f"OpenAI error: {e}")
|
94 |
-
return _img_list(resp, fmt=out_fmt
|
95 |
|
96 |
|
97 |
# ---------- Edit / Inpaint ---------- #
|
@@ -147,7 +156,7 @@ def edit_image(
|
|
147 |
mask_numpy = _extract_mask_array(mask_value)
|
148 |
|
149 |
if mask_numpy is not None:
|
150 |
-
# Convert painted area (any non
|
151 |
if mask_numpy.shape[-1] == 4: # RGBA (has alpha channel)
|
152 |
alpha = mask_numpy[:, :, 3]
|
153 |
else: # RGB or grayscale
|
@@ -164,7 +173,7 @@ def edit_image(
|
|
164 |
)
|
165 |
except Exception as e:
|
166 |
raise gr.Error(f"OpenAI error: {e}")
|
167 |
-
return _img_list(resp, fmt=out_fmt
|
168 |
|
169 |
|
170 |
# ---------- Variations ---------- #
|
@@ -190,17 +199,17 @@ def variation_image(
|
|
190 |
)
|
191 |
except Exception as e:
|
192 |
raise gr.Error(f"OpenAI error: {e}")
|
193 |
-
return _img_list(resp, fmt=out_fmt
|
194 |
|
195 |
|
196 |
# ---------- UI ---------- #
|
197 |
|
198 |
def build_ui():
|
199 |
-
with gr.Blocks(title="GPT
|
200 |
-
gr.Markdown("""# GPT
|
201 |
|
202 |
with gr.Accordion("🔐 API key", open=False):
|
203 |
-
api = gr.Textbox(label="OpenAI API key", type="password", placeholder="sk
|
204 |
|
205 |
# Common controls
|
206 |
n_slider = gr.Slider(1, 10, value=1, step=1, label="Number of images (n)")
|
@@ -208,7 +217,7 @@ def build_ui():
|
|
208 |
quality = gr.Dropdown(QUALITY_CHOICES, value="auto", label="Quality")
|
209 |
out_fmt = gr.Radio(FORMAT_CHOICES, value="png", label="Format")
|
210 |
compression = gr.Slider(0, 100, value=75, step=1, label="Compression (JPEG/WebP)")
|
211 |
-
transparent = gr.Checkbox(False, label="Transparent background (PNG only)")
|
212 |
|
213 |
def _toggle_compression(fmt):
|
214 |
return gr.update(visible=fmt in {"jpeg", "webp"})
|
@@ -242,19 +251,4 @@ def build_ui():
|
|
242 |
|
243 |
# ----- Variations Tab ----- #
|
244 |
with gr.TabItem("Variations"):
|
245 |
-
img_var =
|
246 |
-
btn_var = gr.Button("Variations 🔄")
|
247 |
-
gallery_var = gr.Gallery(columns=2, height="auto")
|
248 |
-
btn_var.click(
|
249 |
-
variation_image,
|
250 |
-
inputs=[api, img_var, n_slider, size, quality, out_fmt, compression, transparent],
|
251 |
-
outputs=gallery_var,
|
252 |
-
)
|
253 |
-
|
254 |
-
return demo
|
255 |
-
|
256 |
-
|
257 |
-
demo = build_ui()
|
258 |
-
|
259 |
-
if __name__ == "__main__":
|
260 |
-
demo.launch()
|
|
|
1 |
"""
|
2 |
+
Gradio Space: GPT-Image-1 – BYOT playground
|
3 |
Generate · Edit (paint mask!) · Variations
|
4 |
==========================================
|
5 |
+
Adds an **in-browser paint tool** for the edit / inpaint workflow so users can
|
6 |
draw the mask directly instead of uploading one.
|
7 |
|
8 |
### How mask painting works
|
|
|
41 |
return openai.OpenAI(api_key=api_key)
|
42 |
|
43 |
|
44 |
+
def _img_list(resp, *, fmt: str) -> List[str]:
|
45 |
+
"""Return list of data URLs or direct URLs depending on API response."""
|
46 |
+
mime = f"image/{fmt}"
|
47 |
return [
|
48 |
f"data:{mime};base64,{d.b64_json}" if hasattr(d, "b64_json") else d.url
|
49 |
for d in resp.data
|
|
|
59 |
compression: int,
|
60 |
transparent_bg: bool,
|
61 |
):
|
62 |
+
"""Prepare keyword arguments for Images API based on latest OpenAI spec."""
|
63 |
+
kwargs: Dict[str, Any] = dict(
|
64 |
model=MODEL,
|
65 |
n=n,
|
66 |
size=size,
|
67 |
quality=quality,
|
68 |
output_format=out_fmt,
|
|
|
|
|
69 |
)
|
70 |
+
|
71 |
+
# Prompt is optional for variations
|
72 |
if prompt is not None:
|
73 |
kwargs["prompt"] = prompt
|
74 |
+
|
75 |
+
# Transparency via background parameter (png & webp only)
|
76 |
+
if transparent_bg:
|
77 |
+
kwargs["background"] = "transparent"
|
78 |
+
|
79 |
+
# Compression for lossy formats
|
80 |
if out_fmt in {"jpeg", "webp"}:
|
81 |
+
kwargs["output_compression"] = f"{compression}%"
|
82 |
+
|
83 |
return kwargs
|
84 |
|
85 |
|
|
|
100 |
resp = client.images.generate(**_common_kwargs(prompt, n, size, quality, out_fmt, compression, transparent_bg))
|
101 |
except Exception as e:
|
102 |
raise gr.Error(f"OpenAI error: {e}")
|
103 |
+
return _img_list(resp, fmt=out_fmt)
|
104 |
|
105 |
|
106 |
# ---------- Edit / Inpaint ---------- #
|
|
|
156 |
mask_numpy = _extract_mask_array(mask_value)
|
157 |
|
158 |
if mask_numpy is not None:
|
159 |
+
# Convert painted area (any non-zero pixel) to white, else black; 1‑channel.
|
160 |
if mask_numpy.shape[-1] == 4: # RGBA (has alpha channel)
|
161 |
alpha = mask_numpy[:, :, 3]
|
162 |
else: # RGB or grayscale
|
|
|
173 |
)
|
174 |
except Exception as e:
|
175 |
raise gr.Error(f"OpenAI error: {e}")
|
176 |
+
return _img_list(resp, fmt=out_fmt)
|
177 |
|
178 |
|
179 |
# ---------- Variations ---------- #
|
|
|
199 |
)
|
200 |
except Exception as e:
|
201 |
raise gr.Error(f"OpenAI error: {e}")
|
202 |
+
return _img_list(resp, fmt=out_fmt)
|
203 |
|
204 |
|
205 |
# ---------- UI ---------- #
|
206 |
|
207 |
def build_ui():
|
208 |
+
with gr.Blocks(title="GPT-Image-1 (BYOT)") as demo:
|
209 |
+
gr.Markdown("""# GPT-Image-1 Playground 🖼️🔑\nGenerate • Edit (paint mask) • Variations""")
|
210 |
|
211 |
with gr.Accordion("🔐 API key", open=False):
|
212 |
+
api = gr.Textbox(label="OpenAI API key", type="password", placeholder="sk-…")
|
213 |
|
214 |
# Common controls
|
215 |
n_slider = gr.Slider(1, 10, value=1, step=1, label="Number of images (n)")
|
|
|
217 |
quality = gr.Dropdown(QUALITY_CHOICES, value="auto", label="Quality")
|
218 |
out_fmt = gr.Radio(FORMAT_CHOICES, value="png", label="Format")
|
219 |
compression = gr.Slider(0, 100, value=75, step=1, label="Compression (JPEG/WebP)")
|
220 |
+
transparent = gr.Checkbox(False, label="Transparent background (PNG/WebP only)")
|
221 |
|
222 |
def _toggle_compression(fmt):
|
223 |
return gr.update(visible=fmt in {"jpeg", "webp"})
|
|
|
251 |
|
252 |
# ----- Variations Tab ----- #
|
253 |
with gr.TabItem("Variations"):
|
254 |
+
img_var =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|