Spaces:
Sleeping
Sleeping
Commit ·
2b422b2
1
Parent(s): ad4a177
gradio workflow (#89)
Browse files- Convert app to gr.Workflow calling Z-Image-Turbo via HF Inference API (639e5b2674a6fe682cefac3e005abd5dcdb70404)
- Pin gradio 6.20.0 and scope OAuth to inference-api only (3953d49ac5e885a01cf75ed42b1d1b0f8927b74e)
- Use Spaces mode: workflow calls mrfakename/Z-Image-Turbo Space (2546607bb3b8fc5b737fa6495b34f3213c157adb)
- Single Space: workflow + @spaces.GPU fn bound via gr.Workflow (8859027f9fdd1583b29818a31734bf0b62cb6291)
- Drop inference-api OAuth scope (1fadc382061acddf691dab33e1171adaf8b51bb7)
- README.md +73 -2
- app.py +56 -229
- requirements.txt +3 -2
- workflow.json +154 -0
README.md
CHANGED
|
@@ -4,9 +4,80 @@ emoji: 🖼️
|
|
| 4 |
colorFrom: yellow
|
| 5 |
colorTo: yellow
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version: 6.
|
| 8 |
app_file: app.py
|
| 9 |
pinned: true
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
colorFrom: yellow
|
| 5 |
colorTo: yellow
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 6.20.0
|
| 8 |
app_file: app.py
|
| 9 |
pinned: true
|
| 10 |
+
hf_oauth: true
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# Z-Image-Turbo (Gradio Workflow — single Space, ZeroGPU)
|
| 14 |
+
|
| 15 |
+
A visual, node-based image-generation app built with `gr.Workflow`. The
|
| 16 |
+
workflow frontend and the ZeroGPU-powered generation function live in the
|
| 17 |
+
**same Space**: the canvas calls a bound `@spaces.GPU` Python function via a
|
| 18 |
+
`fn` operator node, so there is no cross-Space round-trip.
|
| 19 |
+
|
| 20 |
+
## How it works
|
| 21 |
+
|
| 22 |
+
The workflow is defined in [`workflow.json`](./workflow.json):
|
| 23 |
+
|
| 24 |
+
| Node | Role | Type |
|
| 25 |
+
|---|---|---|
|
| 26 |
+
| Prompt · Height · Width · Inference Steps · Seed · Randomize Seed | references (inputs) | text / number / boolean |
|
| 27 |
+
| `generate_image` | operator — `kind: "fn"`, bound to `@spaces.GPU generate_image` in `app.py` | calls the local zero-GPU pipeline |
|
| 28 |
+
| Output Image · Seed Used | subjects (outputs) | image / number |
|
| 29 |
+
|
| 30 |
+
`app.py` loads the `Tongyi-MAI/Z-Image-Turbo` pipeline at startup and binds it:
|
| 31 |
+
|
| 32 |
+
```python
|
| 33 |
+
@spaces.GPU
|
| 34 |
+
def generate_image(prompt, height, width, num_inference_steps, seed, randomize_seed):
|
| 35 |
+
...
|
| 36 |
+
return image, seed_used
|
| 37 |
+
|
| 38 |
+
gr.Workflow(graph="workflow.json", bind={"generate_image": generate_image}).launch()
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
When the canvas hits **Run**, the executor's `fn` branch routes the call to
|
| 42 |
+
the local `generate_image`, and `@spaces.GPU` allocates a ZeroGPU worker for
|
| 43 |
+
that invocation.
|
| 44 |
+
|
| 45 |
+
Edit the topology on the canvas (drag nodes, change the prompt, rewire) and
|
| 46 |
+
hit **Run**. Changes are saved back to `workflow.json`.
|
| 47 |
+
|
| 48 |
+
## Running locally
|
| 49 |
+
|
| 50 |
+
```bash
|
| 51 |
+
pip install -r requirements.txt
|
| 52 |
+
python app.py
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
GPU access through `@spaces.GPU` only works on Hugging Face Spaces — locally
|
| 56 |
+
the decorated call will raise. Otherwise the workflow frontend, node wiring
|
| 57 |
+
and grading still work.
|
| 58 |
+
|
| 59 |
+
Open the **write-access link** printed at launch to edit the workflow; plain
|
| 60 |
+
local/share URLs open it read-only.
|
| 61 |
+
|
| 62 |
+
## Deploying
|
| 63 |
+
|
| 64 |
+
```bash
|
| 65 |
+
gradio deploy
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
`hf_oauth: true` is set so that, on a Space, each visitor signs in with their
|
| 69 |
+
own HF account and ZeroGPU allocations run under their own token. The Space
|
| 70 |
+
owner can edit and save the workflow; visitors get a read-only view and can
|
| 71 |
+
run the pipeline.
|
| 72 |
+
|
| 73 |
+
## API access
|
| 74 |
+
|
| 75 |
+
Every Workflow app is a Gradio app, so it exposes a REST endpoint per output
|
| 76 |
+
(subject) node — e.g. `/output_image` and `/seed_used`:
|
| 77 |
+
|
| 78 |
+
```python
|
| 79 |
+
from gradio_client import Client
|
| 80 |
+
|
| 81 |
+
client = Client("your-username/your-space")
|
| 82 |
+
client.view_api() # list endpoints and their parameters
|
| 83 |
+
```
|
app.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
| 1 |
-
import
|
|
|
|
|
|
|
| 2 |
import spaces
|
|
|
|
| 3 |
import gradio as gr
|
| 4 |
from diffusers import DiffusionPipeline
|
| 5 |
|
| 6 |
-
# Load the pipeline once at startup
|
|
|
|
| 7 |
print("Loading Z-Image-Turbo pipeline...")
|
| 8 |
pipe = DiffusionPipeline.from_pretrained(
|
| 9 |
"Tongyi-MAI/Z-Image-Turbo",
|
|
@@ -11,19 +15,50 @@ pipe = DiffusionPipeline.from_pretrained(
|
|
| 11 |
low_cpu_mem_usage=False,
|
| 12 |
)
|
| 13 |
pipe.to("cuda")
|
|
|
|
| 14 |
|
| 15 |
-
# ======== AoTI compilation + FA3 ========
|
| 16 |
-
# pipe.transformer.layers._repeated_blocks = ["ZImageTransformerBlock"]
|
| 17 |
-
# spaces.aoti_blocks_load(pipe.transformer.layers, "zerogpu-aoti/Z-Image", variant="fa3")
|
| 18 |
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
@spaces.GPU
|
| 22 |
-
def generate_image(
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
if randomize_seed:
|
| 25 |
seed = torch.randint(0, 2**32 - 1, (1,)).item()
|
| 26 |
-
|
| 27 |
generator = torch.Generator("cuda").manual_seed(int(seed))
|
| 28 |
image = pipe(
|
| 29 |
prompt=prompt,
|
|
@@ -33,228 +68,20 @@ def generate_image(prompt, height, width, num_inference_steps, seed, randomize_s
|
|
| 33 |
guidance_scale=0.0,
|
| 34 |
generator=generator,
|
| 35 |
).images[0]
|
| 36 |
-
|
| 37 |
-
return image, seed
|
| 38 |
|
| 39 |
-
|
| 40 |
-
examples = [
|
| 41 |
-
["Young Chinese woman in red Hanfu, intricate embroidery. Impeccable makeup, red floral forehead pattern. Elaborate high bun, golden phoenix headdress, red flowers, beads. Holds round folding fan with lady, trees, bird. Neon lightning-bolt lamp, bright yellow glow, above extended left palm. Soft-lit outdoor night background, silhouetted tiered pagoda, blurred colorful distant lights."],
|
| 42 |
-
["A majestic dragon soaring through clouds at sunset, scales shimmering with iridescent colors, detailed fantasy art style"],
|
| 43 |
-
["Cozy coffee shop interior, warm lighting, rain on windows, plants on shelves, vintage aesthetic, photorealistic"],
|
| 44 |
-
["Astronaut riding a horse on Mars, cinematic lighting, sci-fi concept art, highly detailed"],
|
| 45 |
-
["Portrait of a wise old wizard with a long white beard, holding a glowing crystal staff, magical forest background"],
|
| 46 |
-
]
|
| 47 |
|
| 48 |
-
# Custom theme with modern aesthetics (Gradio 6)
|
| 49 |
-
custom_theme = gr.themes.Soft(
|
| 50 |
-
primary_hue="yellow",
|
| 51 |
-
secondary_hue="amber",
|
| 52 |
-
neutral_hue="slate",
|
| 53 |
-
font=gr.themes.GoogleFont("Inter"),
|
| 54 |
-
text_size="lg",
|
| 55 |
-
spacing_size="md",
|
| 56 |
-
radius_size="lg"
|
| 57 |
-
).set(
|
| 58 |
-
button_primary_background_fill="*primary_500",
|
| 59 |
-
button_primary_background_fill_hover="*primary_600",
|
| 60 |
-
block_title_text_weight="600",
|
| 61 |
-
)
|
| 62 |
|
| 63 |
-
#
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
with gr.Row(equal_height=False):
|
| 75 |
-
# Left column - Input controls
|
| 76 |
-
with gr.Column(scale=1, min_width=320):
|
| 77 |
-
prompt = gr.Textbox(
|
| 78 |
-
label="✨ Your Prompt",
|
| 79 |
-
placeholder="Describe the image you want to create...",
|
| 80 |
-
lines=5,
|
| 81 |
-
max_lines=10,
|
| 82 |
-
autofocus=True,
|
| 83 |
-
)
|
| 84 |
-
|
| 85 |
-
with gr.Accordion("⚙️ Advanced Settings", open=False):
|
| 86 |
-
with gr.Row():
|
| 87 |
-
height = gr.Slider(
|
| 88 |
-
minimum=512,
|
| 89 |
-
maximum=2048,
|
| 90 |
-
value=1024,
|
| 91 |
-
step=64,
|
| 92 |
-
label="Height",
|
| 93 |
-
info="Image height in pixels"
|
| 94 |
-
)
|
| 95 |
-
width = gr.Slider(
|
| 96 |
-
minimum=512,
|
| 97 |
-
maximum=2048,
|
| 98 |
-
value=1024,
|
| 99 |
-
step=64,
|
| 100 |
-
label="Width",
|
| 101 |
-
info="Image width in pixels"
|
| 102 |
-
)
|
| 103 |
-
|
| 104 |
-
num_inference_steps = gr.Slider(
|
| 105 |
-
minimum=1,
|
| 106 |
-
maximum=20,
|
| 107 |
-
value=9,
|
| 108 |
-
step=1,
|
| 109 |
-
label="Inference Steps",
|
| 110 |
-
info="9 steps = 8 DiT forwards (recommended)"
|
| 111 |
-
)
|
| 112 |
-
|
| 113 |
-
with gr.Row():
|
| 114 |
-
randomize_seed = gr.Checkbox(
|
| 115 |
-
label="🎲 Random Seed",
|
| 116 |
-
value=True,
|
| 117 |
-
)
|
| 118 |
-
seed = gr.Number(
|
| 119 |
-
label="Seed",
|
| 120 |
-
value=42,
|
| 121 |
-
precision=0,
|
| 122 |
-
visible=False,
|
| 123 |
-
)
|
| 124 |
-
|
| 125 |
-
def toggle_seed(randomize):
|
| 126 |
-
return gr.Number(visible=not randomize)
|
| 127 |
-
|
| 128 |
-
randomize_seed.change(
|
| 129 |
-
toggle_seed,
|
| 130 |
-
inputs=[randomize_seed],
|
| 131 |
-
outputs=[seed]
|
| 132 |
-
)
|
| 133 |
-
|
| 134 |
-
generate_btn = gr.Button(
|
| 135 |
-
"🚀 Generate Image",
|
| 136 |
-
variant="primary",
|
| 137 |
-
size="lg",
|
| 138 |
-
scale=1
|
| 139 |
-
)
|
| 140 |
-
|
| 141 |
-
# Example prompts
|
| 142 |
-
gr.Examples(
|
| 143 |
-
examples=examples,
|
| 144 |
-
inputs=[prompt],
|
| 145 |
-
label="💡 Try these prompts",
|
| 146 |
-
examples_per_page=5,
|
| 147 |
-
)
|
| 148 |
-
|
| 149 |
-
# Right column - Output
|
| 150 |
-
with gr.Column(scale=1, min_width=320):
|
| 151 |
-
output_image = gr.Image(
|
| 152 |
-
label="Generated Image",
|
| 153 |
-
type="pil",
|
| 154 |
-
format="png",
|
| 155 |
-
show_label=False,
|
| 156 |
-
height=600,
|
| 157 |
-
buttons=["download", "share"],
|
| 158 |
-
)
|
| 159 |
-
|
| 160 |
-
used_seed = gr.Number(
|
| 161 |
-
label="🎲 Seed Used",
|
| 162 |
-
interactive=False,
|
| 163 |
-
container=True,
|
| 164 |
-
)
|
| 165 |
-
|
| 166 |
-
# Footer credits
|
| 167 |
-
gr.Markdown(
|
| 168 |
-
"""
|
| 169 |
-
---
|
| 170 |
-
<div style="text-align: center; opacity: 0.7; font-size: 0.9em; margin-top: 1rem;">
|
| 171 |
-
<strong>Model:</strong> <a href="https://huggingface.co/Tongyi-MAI/Z-Image-Turbo" target="_blank">Tongyi-MAI/Z-Image-Turbo</a> (Apache 2.0 License) •
|
| 172 |
-
<strong>Demo by:</strong> <a href="https://x.com/realmrfakename" target="_blank">@mrfakename</a> •
|
| 173 |
-
<strong>Redesign by:</strong> AnyCoder •
|
| 174 |
-
<strong>Optimizations:</strong> <a href="https://huggingface.co/multimodalart" target="_blank">@multimodalart</a> (FA3 + AoTI)
|
| 175 |
-
</div>
|
| 176 |
-
""",
|
| 177 |
-
elem_classes="footer-text"
|
| 178 |
-
)
|
| 179 |
-
|
| 180 |
-
# Connect the generate button
|
| 181 |
-
generate_btn.click(
|
| 182 |
-
fn=generate_image,
|
| 183 |
-
inputs=[prompt, height, width, num_inference_steps, seed, randomize_seed],
|
| 184 |
-
outputs=[output_image, used_seed],
|
| 185 |
-
)
|
| 186 |
-
|
| 187 |
-
# Also allow generating by pressing Enter in the prompt box
|
| 188 |
-
prompt.submit(
|
| 189 |
-
fn=generate_image,
|
| 190 |
-
inputs=[prompt, height, width, num_inference_steps, seed, randomize_seed],
|
| 191 |
-
outputs=[output_image, used_seed],
|
| 192 |
-
)
|
| 193 |
|
| 194 |
if __name__ == "__main__":
|
| 195 |
-
demo.launch(
|
| 196 |
-
theme=custom_theme,
|
| 197 |
-
css="""
|
| 198 |
-
.header-text h1 {
|
| 199 |
-
font-size: 2.5rem !important;
|
| 200 |
-
font-weight: 700 !important;
|
| 201 |
-
margin-bottom: 0.5rem !important;
|
| 202 |
-
background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
|
| 203 |
-
-webkit-background-clip: text;
|
| 204 |
-
-webkit-text-fill-color: transparent;
|
| 205 |
-
background-clip: text;
|
| 206 |
-
}
|
| 207 |
-
|
| 208 |
-
.header-text p {
|
| 209 |
-
font-size: 1.1rem !important;
|
| 210 |
-
color: #64748b !important;
|
| 211 |
-
margin-top: 0 !important;
|
| 212 |
-
}
|
| 213 |
-
|
| 214 |
-
.footer-text {
|
| 215 |
-
padding: 1rem 0;
|
| 216 |
-
}
|
| 217 |
-
|
| 218 |
-
.footer-text a {
|
| 219 |
-
color: #f59e0b !important;
|
| 220 |
-
text-decoration: none !important;
|
| 221 |
-
font-weight: 500;
|
| 222 |
-
}
|
| 223 |
-
|
| 224 |
-
.footer-text a:hover {
|
| 225 |
-
text-decoration: underline !important;
|
| 226 |
-
}
|
| 227 |
-
|
| 228 |
-
/* Mobile optimizations */
|
| 229 |
-
@media (max-width: 768px) {
|
| 230 |
-
.header-text h1 {
|
| 231 |
-
font-size: 1.8rem !important;
|
| 232 |
-
}
|
| 233 |
-
|
| 234 |
-
.header-text p {
|
| 235 |
-
font-size: 1rem !important;
|
| 236 |
-
}
|
| 237 |
-
}
|
| 238 |
-
|
| 239 |
-
/* Smooth transitions */
|
| 240 |
-
button, .gr-button {
|
| 241 |
-
transition: all 0.2s ease !important;
|
| 242 |
-
}
|
| 243 |
-
|
| 244 |
-
button:hover, .gr-button:hover {
|
| 245 |
-
transform: translateY(-1px);
|
| 246 |
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
|
| 247 |
-
}
|
| 248 |
-
|
| 249 |
-
/* Better spacing */
|
| 250 |
-
.gradio-container {
|
| 251 |
-
max-width: 1400px !important;
|
| 252 |
-
margin: 0 auto !important;
|
| 253 |
-
}
|
| 254 |
-
""",
|
| 255 |
-
footer_links=[
|
| 256 |
-
"api",
|
| 257 |
-
"gradio"
|
| 258 |
-
],
|
| 259 |
-
mcp_server=True
|
| 260 |
-
)
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import tempfile
|
| 3 |
+
|
| 4 |
import spaces
|
| 5 |
+
import torch
|
| 6 |
import gradio as gr
|
| 7 |
from diffusers import DiffusionPipeline
|
| 8 |
|
| 9 |
+
# Load the pipeline once at startup. The Space is a ZeroGPU space, so the
|
| 10 |
+
# model weights stay resident and `@spaces.GPU` allocates a worker per call.
|
| 11 |
print("Loading Z-Image-Turbo pipeline...")
|
| 12 |
pipe = DiffusionPipeline.from_pretrained(
|
| 13 |
"Tongyi-MAI/Z-Image-Turbo",
|
|
|
|
| 15 |
low_cpu_mem_usage=False,
|
| 16 |
)
|
| 17 |
pipe.to("cuda")
|
| 18 |
+
print("Pipeline loaded!")
|
| 19 |
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
+
def _save_image(image) -> dict:
|
| 22 |
+
"""Mirror of `gradio.workflow._save_tmp`: serialize a PIL.Image as a JSON
|
| 23 |
+
pointer the canvas can render. `Workflow.launch()` already adds the
|
| 24 |
+
tempdir to `allowed_paths`, so the /gradio_api/file=… URL resolves."""
|
| 25 |
+
path = os.path.join(
|
| 26 |
+
tempfile.gettempdir(), f"zimage_{os.urandom(8).hex()}.png"
|
| 27 |
+
)
|
| 28 |
+
image.save(path)
|
| 29 |
+
return {
|
| 30 |
+
"path": path,
|
| 31 |
+
"url": f"/gradio_api/file={path}",
|
| 32 |
+
"orig_name": "zimage.png",
|
| 33 |
+
"mime_type": "image/png",
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
|
| 37 |
@spaces.GPU
|
| 38 |
+
def generate_image(
|
| 39 |
+
prompt: str,
|
| 40 |
+
height: int,
|
| 41 |
+
width: int,
|
| 42 |
+
num_inference_steps: int,
|
| 43 |
+
seed: int,
|
| 44 |
+
randomize_seed: bool,
|
| 45 |
+
):
|
| 46 |
+
"""Generate an image from a prompt using Z-Image-Turbo on ZeroGPU.
|
| 47 |
+
|
| 48 |
+
Bound to the workflow canvas as a `fn` operator node — the workflow
|
| 49 |
+
calls this Python function directly server-side, so the entire pipeline
|
| 50 |
+
(frontend + ZeroGPU) lives in a single Space.
|
| 51 |
+
|
| 52 |
+
Returns (image_dict, seed_used). The image is serialized to a /gradio_api
|
| 53 |
+
file URL so JSON serialization across the fn bridge succeeds; the executor's
|
| 54 |
+
`fromGradioOutput` turns the dict back into an image port value.
|
| 55 |
+
"""
|
| 56 |
+
if not prompt or not prompt.strip():
|
| 57 |
+
raise gr.Error("Please enter a prompt.")
|
| 58 |
+
|
| 59 |
if randomize_seed:
|
| 60 |
seed = torch.randint(0, 2**32 - 1, (1,)).item()
|
| 61 |
+
|
| 62 |
generator = torch.Generator("cuda").manual_seed(int(seed))
|
| 63 |
image = pipe(
|
| 64 |
prompt=prompt,
|
|
|
|
| 68 |
guidance_scale=0.0,
|
| 69 |
generator=generator,
|
| 70 |
).images[0]
|
|
|
|
|
|
|
| 71 |
|
| 72 |
+
return _save_image(image), int(seed)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
+
# The workflow (workflow.json) wires this function as a `fn` operator:
|
| 76 |
+
# Prompt, Height, Width, Inference Steps, Seed, Randomize Seed ─▶
|
| 77 |
+
# generate_image (fn operator, kind="fn") ─▶ Output Image, Seed Used
|
| 78 |
+
#
|
| 79 |
+
# On a Space with `hf_oauth: true`, visiting the canvas runs this function
|
| 80 |
+
# under a ZeroGPU worker using each visitor's own HF token.
|
| 81 |
+
demo = gr.Workflow(
|
| 82 |
+
graph="workflow.json",
|
| 83 |
+
bind={"generate_image": generate_image},
|
| 84 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
|
| 86 |
if __name__ == "__main__":
|
| 87 |
+
demo.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
-
gradio
|
| 2 |
git+https://github.com/huggingface/diffusers
|
| 3 |
transformers
|
| 4 |
kernels
|
| 5 |
-
|
|
|
|
|
|
| 1 |
+
gradio>=6.20.0
|
| 2 |
git+https://github.com/huggingface/diffusers
|
| 3 |
transformers
|
| 4 |
kernels
|
| 5 |
+
spaces
|
| 6 |
+
gradio[mcp]
|
workflow.json
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema_version": "2",
|
| 3 |
+
"name": "Z-Image-Turbo",
|
| 4 |
+
"description": "Ultra-fast AI image generation with Z-Image-Turbo on ZeroGPU, driven by a gr.Workflow fn-bound @spaces.GPU function. Single Space: the workflow frontend and the GPU worker share one process.",
|
| 5 |
+
"runtime": { "default": "client" },
|
| 6 |
+
"view": { "default": "canvas" },
|
| 7 |
+
"references": [
|
| 8 |
+
{
|
| 9 |
+
"id": "ref_prompt",
|
| 10 |
+
"label": "Prompt",
|
| 11 |
+
"role": "reference",
|
| 12 |
+
"asset_type": "text",
|
| 13 |
+
"inputs": [{ "id": "in", "label": "Prompt", "type": "text" }],
|
| 14 |
+
"outputs": [{ "id": "out", "label": "Prompt", "type": "text" }],
|
| 15 |
+
"x": 60,
|
| 16 |
+
"y": 160,
|
| 17 |
+
"width": 240,
|
| 18 |
+
"height": 120,
|
| 19 |
+
"data": {
|
| 20 |
+
"out": "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
|
| 21 |
+
}
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"id": "ref_height",
|
| 25 |
+
"label": "Height",
|
| 26 |
+
"role": "reference",
|
| 27 |
+
"asset_type": "number",
|
| 28 |
+
"inputs": [{ "id": "in", "label": "Height", "type": "number" }],
|
| 29 |
+
"outputs": [{ "id": "out", "label": "Height", "type": "number" }],
|
| 30 |
+
"x": 60,
|
| 31 |
+
"y": 300,
|
| 32 |
+
"width": 200,
|
| 33 |
+
"height": 90,
|
| 34 |
+
"data": { "out": 1024 }
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"id": "ref_width",
|
| 38 |
+
"label": "Width",
|
| 39 |
+
"role": "reference",
|
| 40 |
+
"asset_type": "number",
|
| 41 |
+
"inputs": [{ "id": "in", "label": "Width", "type": "number" }],
|
| 42 |
+
"outputs": [{ "id": "out", "label": "Width", "type": "number" }],
|
| 43 |
+
"x": 60,
|
| 44 |
+
"y": 410,
|
| 45 |
+
"width": 200,
|
| 46 |
+
"height": 90,
|
| 47 |
+
"data": { "out": 1024 }
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
"id": "ref_steps",
|
| 51 |
+
"label": "Inference Steps",
|
| 52 |
+
"role": "reference",
|
| 53 |
+
"asset_type": "number",
|
| 54 |
+
"inputs": [{ "id": "in", "label": "Steps", "type": "number" }],
|
| 55 |
+
"outputs": [{ "id": "out", "label": "Steps", "type": "number" }],
|
| 56 |
+
"x": 60,
|
| 57 |
+
"y": 520,
|
| 58 |
+
"width": 200,
|
| 59 |
+
"height": 90,
|
| 60 |
+
"data": { "out": 9 }
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"id": "ref_seed",
|
| 64 |
+
"label": "Seed",
|
| 65 |
+
"role": "reference",
|
| 66 |
+
"asset_type": "number",
|
| 67 |
+
"inputs": [{ "id": "in", "label": "Seed", "type": "number" }],
|
| 68 |
+
"outputs": [{ "id": "out", "label": "Seed", "type": "number" }],
|
| 69 |
+
"x": 60,
|
| 70 |
+
"y": 630,
|
| 71 |
+
"width": 200,
|
| 72 |
+
"height": 90,
|
| 73 |
+
"data": { "out": 42 }
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"id": "ref_randomize",
|
| 77 |
+
"label": "Randomize Seed",
|
| 78 |
+
"role": "reference",
|
| 79 |
+
"asset_type": "boolean",
|
| 80 |
+
"inputs": [{ "id": "in", "label": "Randomize", "type": "boolean" }],
|
| 81 |
+
"outputs": [{ "id": "out", "label": "Randomize", "type": "boolean" }],
|
| 82 |
+
"x": 60,
|
| 83 |
+
"y": 740,
|
| 84 |
+
"width": 200,
|
| 85 |
+
"height": 90,
|
| 86 |
+
"data": { "out": true }
|
| 87 |
+
}
|
| 88 |
+
],
|
| 89 |
+
"operators": [
|
| 90 |
+
{
|
| 91 |
+
"id": "op_generate",
|
| 92 |
+
"label": "generate_image",
|
| 93 |
+
"role": "operator",
|
| 94 |
+
"kind": "fn",
|
| 95 |
+
"source": "fn",
|
| 96 |
+
"fn": "generate_image",
|
| 97 |
+
"inputs": [
|
| 98 |
+
{ "id": "in_0", "label": "prompt", "type": "text", "required": true },
|
| 99 |
+
{ "id": "in_1", "label": "height", "type": "number" },
|
| 100 |
+
{ "id": "in_2", "label": "width", "type": "number" },
|
| 101 |
+
{ "id": "in_3", "label": "num_inference_steps", "type": "number" },
|
| 102 |
+
{ "id": "in_4", "label": "seed", "type": "number" },
|
| 103 |
+
{ "id": "in_5", "label": "randomize_seed", "type": "boolean" }
|
| 104 |
+
],
|
| 105 |
+
"outputs": [
|
| 106 |
+
{ "id": "out_0", "label": "image", "type": "image", "output_index": 0 },
|
| 107 |
+
{ "id": "out_1", "label": "seed_used", "type": "number", "output_index": 1 }
|
| 108 |
+
],
|
| 109 |
+
"x": 420,
|
| 110 |
+
"y": 320,
|
| 111 |
+
"width": 280,
|
| 112 |
+
"height": 220,
|
| 113 |
+
"data": {}
|
| 114 |
+
}
|
| 115 |
+
],
|
| 116 |
+
"subjects": [
|
| 117 |
+
{
|
| 118 |
+
"id": "sub_image",
|
| 119 |
+
"label": "Output Image",
|
| 120 |
+
"role": "subject",
|
| 121 |
+
"asset_type": "image",
|
| 122 |
+
"inputs": [{ "id": "in", "label": "Image", "type": "image" }],
|
| 123 |
+
"outputs": [{ "id": "out", "label": "Image", "type": "image" }],
|
| 124 |
+
"x": 820,
|
| 125 |
+
"y": 280,
|
| 126 |
+
"width": 240,
|
| 127 |
+
"height": 130,
|
| 128 |
+
"data": {}
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"id": "sub_seed",
|
| 132 |
+
"label": "Seed Used",
|
| 133 |
+
"role": "subject",
|
| 134 |
+
"asset_type": "number",
|
| 135 |
+
"inputs": [{ "id": "in", "label": "Seed", "type": "number" }],
|
| 136 |
+
"outputs": [{ "id": "out", "label": "Seed", "type": "number" }],
|
| 137 |
+
"x": 820,
|
| 138 |
+
"y": 460,
|
| 139 |
+
"width": 240,
|
| 140 |
+
"height": 100,
|
| 141 |
+
"data": {}
|
| 142 |
+
}
|
| 143 |
+
],
|
| 144 |
+
"edges": [
|
| 145 |
+
{ "id": "e_prompt", "from_node_id": "ref_prompt", "from_port_id": "out", "to_node_id": "op_generate", "to_port_id": "in_0", "type": "text" },
|
| 146 |
+
{ "id": "e_height", "from_node_id": "ref_height", "from_port_id": "out", "to_node_id": "op_generate", "to_port_id": "in_1", "type": "number" },
|
| 147 |
+
{ "id": "e_width", "from_node_id": "ref_width", "from_port_id": "out", "to_node_id": "op_generate", "to_port_id": "in_2", "type": "number" },
|
| 148 |
+
{ "id": "e_steps", "from_node_id": "ref_steps", "from_port_id": "out", "to_node_id": "op_generate", "to_port_id": "in_3", "type": "number" },
|
| 149 |
+
{ "id": "e_seed", "from_node_id": "ref_seed", "from_port_id": "out", "to_node_id": "op_generate", "to_port_id": "in_4", "type": "number" },
|
| 150 |
+
{ "id": "e_randomize", "from_node_id": "ref_randomize", "from_port_id": "out", "to_node_id": "op_generate", "to_port_id": "in_5", "type": "boolean" },
|
| 151 |
+
{ "id": "e_image_out", "from_node_id": "op_generate", "from_port_id": "out_0", "to_node_id": "sub_image", "to_port_id": "in", "type": "image" },
|
| 152 |
+
{ "id": "e_seed_out", "from_node_id": "op_generate", "from_port_id": "out_1", "to_node_id": "sub_seed", "to_port_id": "in", "type": "number" }
|
| 153 |
+
]
|
| 154 |
+
}
|