multimodalart HF Staff commited on
Commit
47a2c66
·
verified ·
1 Parent(s): c211492

Unify UI to single interface with optional image input; add generate defaults so examples work

Browse files
Files changed (1) hide show
  1. app.py +99 -126
app.py CHANGED
@@ -1,7 +1,8 @@
1
  """Mage-Flow: Efficient Native-Resolution Foundation Model for Image Generation and Editing.
2
 
3
- Gradio Space demo supporting text-to-image generation and instruction-based image editing
4
- using Microsoft's Mage-Flow model (Turbo variants for fast inference).
 
5
  """
6
  import os
7
 
@@ -25,27 +26,53 @@ pipe_edit = MageFlowPipeline.from_pretrained(EDIT_MODEL, device="cuda")
25
  @spaces.GPU(duration=60)
26
  def generate(
27
  prompt: str,
28
- negative_prompt: str,
29
- steps: int,
30
- cfg: float,
31
- height: int,
32
- width: int,
33
- seed: int,
 
 
34
  progress=gr.Progress(track_tqdm=True),
35
  ):
36
- """Generate an image from a text prompt using Mage-Flow-Turbo.
 
 
 
 
37
 
38
  Args:
39
- prompt: Text description of the image to generate.
40
- negative_prompt: What to avoid in the generation.
 
41
  steps: Number of denoising steps (Turbo uses 4).
42
  cfg: Classifier-free guidance scale (Turbo uses 1.0).
43
- height: Output image height (multiple of 16).
44
- width: Output image width (multiple of 16).
 
45
  seed: Random seed for reproducibility.
46
  """
47
  if not (prompt or "").strip():
48
  raise gr.Error("Prompt is empty.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  img = pipe_t2i.generate(
50
  [prompt],
51
  neg_prompts=[negative_prompt or " "],
@@ -58,152 +85,98 @@ def generate(
58
  return img
59
 
60
 
61
- @spaces.GPU(duration=60)
62
- def edit(
63
- prompt: str,
64
- negative_prompt: str,
65
- ref_img,
66
- steps: int,
67
- cfg: float,
68
- max_size: int,
69
- seed: int,
70
- progress=gr.Progress(track_tqdm=True),
71
- ):
72
- """Edit a reference image using an instruction prompt with Mage-Flow-Edit-Turbo.
73
-
74
- Args:
75
- prompt: Edit instruction describing how to modify the image.
76
- negative_prompt: What to avoid in the edited result.
77
- ref_img: Reference image to edit.
78
- steps: Number of denoising steps (Turbo uses 4).
79
- cfg: Classifier-free guidance scale.
80
- max_size: Longest side of output (0 = keep source resolution).
81
- seed: Random seed for reproducibility.
82
- """
83
- if not (prompt or "").strip():
84
- raise gr.Error("Edit instruction is empty.")
85
- if ref_img is None:
86
- raise gr.Error("Upload a reference image to edit.")
87
- if isinstance(ref_img, str):
88
- ref_img = Image.open(ref_img)
89
- refs = [ref_img.convert("RGB")]
90
- out = pipe_edit.edit(
91
- [prompt],
92
- [refs],
93
- neg_prompts=[negative_prompt or " "],
94
- seeds=[int(seed)],
95
- steps=int(steps),
96
- cfg=float(cfg),
97
- max_size=int(max_size) if max_size else None,
98
- )[0]
99
- return out
100
-
101
-
102
  ASSETS_DIR = os.path.join(os.path.dirname(__file__), "mage_flow", "assets")
103
 
104
  CSS = """
105
- #col-container { max-width: 1100px; margin: 0 auto; }
106
  .dark .gradio-container { color: var(--body-text-color); }
107
  """
108
 
109
  with gr.Blocks(css=CSS) as demo:
110
- gr.Markdown(
111
- "# Mage-Flow\n"
112
- "Efficient Native-Resolution Foundation Model for Image Generation and Editing.\n\n"
113
- "Model: [microsoft/Mage-Flow-Turbo](https://huggingface.co/microsoft/Mage-Flow-Turbo) | "
114
- "[Paper](https://huggingface.co/papers/2607.19064) | "
115
- "[GitHub](https://github.com/microsoft/Mage)"
116
- )
 
 
 
117
 
118
- with gr.Tab("Text → Image"):
119
  with gr.Row():
120
  with gr.Column(scale=1):
121
- t_prompt = gr.Textbox(
122
- label="Prompt",
123
- lines=3,
124
- value="A close-up portrait of an elderly African man with deep wrinkles, "
125
- "wearing a traditional hat, soft natural lighting, ultra realistic.",
126
- )
127
- t_neg = gr.Textbox(label="Negative prompt", value=" ", lines=1)
128
- with gr.Row():
129
- t_steps = gr.Slider(1, 50, value=4, step=1, label="Steps")
130
- t_cfg = gr.Slider(1.0, 10.0, value=1.0, step=0.5, label="CFG")
131
  with gr.Row():
132
- t_h = gr.Slider(256, 1536, value=1024, step=16, label="Height")
133
- t_w = gr.Slider(256, 1536, value=1024, step=16, label="Width")
134
- t_seed = gr.Number(value=42, precision=0, label="Seed")
135
- t_btn = gr.Button("Generate", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  with gr.Column(scale=1):
137
- t_out = gr.Image(type="pil", label="Output", height=560)
138
 
 
139
  gr.Examples(
140
  examples=[
141
  ["A close-up portrait of an elderly African man with deep wrinkles, wearing a traditional hat, soft natural lighting, ultra realistic."],
142
  ["A serene mountain landscape at sunset, with snow-capped peaks reflecting golden light, photorealistic."],
143
  ["A cute robot playing a guitar in a neon-lit cyberpunk city, digital art style."],
144
  ],
145
- inputs=[t_prompt],
146
- outputs=t_out,
147
  fn=generate,
148
  cache_examples=True,
149
  cache_mode="lazy",
150
  )
151
 
152
- t_btn.click(
153
- lambda: None, None, t_out
154
- ).then(
155
- generate,
156
- [t_prompt, t_neg, t_steps, t_cfg, t_h, t_w, t_seed],
157
- t_out,
158
- api_name="generate",
159
- )
160
-
161
- with gr.Tab("Image Edit"):
162
- with gr.Row():
163
- with gr.Column(scale=1):
164
- e_prompt = gr.Textbox(
165
- label="Edit instruction",
166
- lines=2,
167
- value="change the background to a city street",
168
- )
169
- e_neg = gr.Textbox(label="Negative prompt", value=" ", lines=1)
170
- e_ref = gr.Image(
171
- type="pil", label="Reference image", height=280,
172
- value=os.path.join(ASSETS_DIR, "dog.jpg"),
173
- )
174
- with gr.Row():
175
- e_steps = gr.Slider(1, 50, value=4, step=1, label="Steps")
176
- e_cfg = gr.Slider(1.0, 10.0, value=1.0, step=0.5, label="CFG")
177
- e_max = gr.Slider(
178
- 0, 1536, value=1024, step=16,
179
- label="Max output side (0 = keep source size)",
180
- )
181
- e_seed = gr.Number(value=42, precision=0, label="Seed")
182
- e_btn = gr.Button("Edit", variant="primary")
183
- with gr.Column(scale=1):
184
- e_out = gr.Image(type="pil", label="Output", height=560)
185
-
186
  gr.Examples(
187
  examples=[
188
  ["change the background to a city street", os.path.join(ASSETS_DIR, "dog.jpg")],
189
  ["make it look like a painting", os.path.join(ASSETS_DIR, "cuisine.jpg")],
190
  ["add a hat to the person", os.path.join(ASSETS_DIR, "portrait.jpg")],
191
  ],
192
- inputs=[e_prompt, e_ref],
193
- outputs=e_out,
194
- fn=edit,
195
  cache_examples=True,
196
  cache_mode="lazy",
197
  )
198
 
199
- e_btn.click(
200
- lambda: None, None, e_out
201
- ).then(
202
- edit,
203
- [e_prompt, e_neg, e_ref, e_steps, e_cfg, e_max, e_seed],
204
- e_out,
205
- api_name="edit",
206
- )
207
 
208
  if __name__ == "__main__":
209
- demo.launch(theme=gr.themes.Citrus(), mcp_server=True, show_error=True)
 
1
  """Mage-Flow: Efficient Native-Resolution Foundation Model for Image Generation and Editing.
2
 
3
+ Gradio Space demo with a single unified interface: enter a prompt and optionally
4
+ upload an image. If an image is provided, the request is routed to the
5
+ Mage-Flow-Edit-Turbo model; otherwise it is routed to the Mage-Flow-Turbo model.
6
  """
7
  import os
8
 
 
26
  @spaces.GPU(duration=60)
27
  def generate(
28
  prompt: str,
29
+ image=None,
30
+ negative_prompt: str = " ",
31
+ steps: int = 4,
32
+ cfg: float = 1.0,
33
+ height: int = 1024,
34
+ width: int = 1024,
35
+ max_size: int = 1024,
36
+ seed: int = 42,
37
  progress=gr.Progress(track_tqdm=True),
38
  ):
39
+ """Generate or edit an image with Mage-Flow.
40
+
41
+ If ``image`` is provided, the reference image is edited with
42
+ Mage-Flow-Edit-Turbo. Otherwise a new image is generated from the text
43
+ prompt with Mage-Flow-Turbo.
44
 
45
  Args:
46
+ prompt: Text description (generation) or edit instruction (editing).
47
+ image: Optional reference image. When given, routes to the edit model.
48
+ negative_prompt: What to avoid in the result.
49
  steps: Number of denoising steps (Turbo uses 4).
50
  cfg: Classifier-free guidance scale (Turbo uses 1.0).
51
+ height: Output image height for text-to-image (multiple of 16).
52
+ width: Output image width for text-to-image (multiple of 16).
53
+ max_size: Longest side of edited output (0 = keep source resolution).
54
  seed: Random seed for reproducibility.
55
  """
56
  if not (prompt or "").strip():
57
  raise gr.Error("Prompt is empty.")
58
+
59
+ if image is not None:
60
+ # Route to the edit model when an image is provided.
61
+ if isinstance(image, str):
62
+ image = Image.open(image)
63
+ refs = [image.convert("RGB")]
64
+ out = pipe_edit.edit(
65
+ [prompt],
66
+ [refs],
67
+ neg_prompts=[negative_prompt or " "],
68
+ seeds=[int(seed)],
69
+ steps=int(steps),
70
+ cfg=float(cfg),
71
+ max_size=int(max_size) if max_size else None,
72
+ )[0]
73
+ return out
74
+
75
+ # No image: route to the text-to-image model.
76
  img = pipe_t2i.generate(
77
  [prompt],
78
  neg_prompts=[negative_prompt or " "],
 
85
  return img
86
 
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  ASSETS_DIR = os.path.join(os.path.dirname(__file__), "mage_flow", "assets")
89
 
90
  CSS = """
91
+ #col-container { margin: 0 auto; max-width: 1100px; }
92
  .dark .gradio-container { color: var(--body-text-color); }
93
  """
94
 
95
  with gr.Blocks(css=CSS) as demo:
96
+ with gr.Column(elem_id="col-container"):
97
+ gr.Markdown(
98
+ "# Mage-Flow\n"
99
+ "Efficient Native-Resolution Foundation Model for Image Generation and Editing. "
100
+ "Enter a prompt to generate an image, or upload an image to edit it.\n\n"
101
+ "Models: [Mage-Flow-Turbo](https://huggingface.co/microsoft/Mage-Flow-Turbo) & "
102
+ "[Mage-Flow-Edit-Turbo](https://huggingface.co/microsoft/Mage-Flow-Edit-Turbo) | "
103
+ "[Paper](https://huggingface.co/papers/2607.19064) | "
104
+ "[GitHub](https://github.com/microsoft/Mage)"
105
+ )
106
 
 
107
  with gr.Row():
108
  with gr.Column(scale=1):
 
 
 
 
 
 
 
 
 
 
109
  with gr.Row():
110
+ prompt = gr.Textbox(
111
+ label="Prompt",
112
+ show_label=False,
113
+ max_lines=3,
114
+ placeholder="Describe an image to generate, or an edit instruction for an uploaded image",
115
+ container=False,
116
+ scale=4,
117
+ )
118
+ run_btn = gr.Button("Run", variant="primary", scale=1)
119
+
120
+ with gr.Accordion("Input image (optional — enables editing)", open=True):
121
+ image = gr.Image(
122
+ type="pil",
123
+ label="Input image",
124
+ show_label=False,
125
+ height=300,
126
+ )
127
+
128
+ with gr.Accordion("Advanced Settings", open=False):
129
+ negative_prompt = gr.Textbox(label="Negative prompt", value=" ", lines=1)
130
+ with gr.Row():
131
+ steps = gr.Slider(1, 50, value=4, step=1, label="Steps")
132
+ cfg = gr.Slider(1.0, 10.0, value=1.0, step=0.5, label="CFG")
133
+ with gr.Row():
134
+ height = gr.Slider(256, 1536, value=1024, step=16, label="Height (text→image)")
135
+ width = gr.Slider(256, 1536, value=1024, step=16, label="Width (text→image)")
136
+ max_size = gr.Slider(
137
+ 0, 1536, value=1024, step=16,
138
+ label="Max output side for editing (0 = keep source size)",
139
+ )
140
+ seed = gr.Number(value=42, precision=0, label="Seed")
141
+
142
  with gr.Column(scale=1):
143
+ result = gr.Image(type="pil", label="Output", height=560)
144
 
145
+ gr.Markdown("### Text → Image examples")
146
  gr.Examples(
147
  examples=[
148
  ["A close-up portrait of an elderly African man with deep wrinkles, wearing a traditional hat, soft natural lighting, ultra realistic."],
149
  ["A serene mountain landscape at sunset, with snow-capped peaks reflecting golden light, photorealistic."],
150
  ["A cute robot playing a guitar in a neon-lit cyberpunk city, digital art style."],
151
  ],
152
+ inputs=[prompt],
153
+ outputs=result,
154
  fn=generate,
155
  cache_examples=True,
156
  cache_mode="lazy",
157
  )
158
 
159
+ gr.Markdown("### Image editing examples")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  gr.Examples(
161
  examples=[
162
  ["change the background to a city street", os.path.join(ASSETS_DIR, "dog.jpg")],
163
  ["make it look like a painting", os.path.join(ASSETS_DIR, "cuisine.jpg")],
164
  ["add a hat to the person", os.path.join(ASSETS_DIR, "portrait.jpg")],
165
  ],
166
+ inputs=[prompt, image],
167
+ outputs=result,
168
+ fn=generate,
169
  cache_examples=True,
170
  cache_mode="lazy",
171
  )
172
 
173
+ inputs = [prompt, image, negative_prompt, steps, cfg, height, width, max_size, seed]
174
+ run_btn.click(lambda: None, None, result).then(
175
+ generate, inputs, result, api_name="generate",
176
+ )
177
+ prompt.submit(lambda: None, None, result).then(
178
+ generate, inputs, result, api_name=False,
179
+ )
 
180
 
181
  if __name__ == "__main__":
182
+ demo.launch(theme=gr.themes.Citrus(), mcp_server=True, show_error=True)