multimodalart HF Staff commited on
Commit
8ef9ed4
Β·
verified Β·
1 Parent(s): 9436060

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +182 -120
app.py CHANGED
@@ -6,8 +6,9 @@ A web interface for the Z-Image-i2L model that converts images to LoRA models.
6
  Setup Instructions:
7
  1. Install dependencies:
8
  pip install -r requirements.txt
 
9
 
10
- 2. Run this demo (DiffSynth-Studio will be auto-installed):
11
  python app.py
12
 
13
  Note: This requires a GPU with sufficient VRAM (recommended 24GB+)
@@ -22,29 +23,110 @@ import sys
22
  import subprocess
23
  import tempfile
24
  from pathlib import Path
 
25
 
26
  # Default negative prompts
27
  NEGATIVE_PROMPT_CN = "ζ³›ι»„οΌŒε‘η»ΏοΌŒζ¨‘η³ŠοΌŒδ½Žεˆ†θΎ¨ηŽ‡οΌŒδ½Žθ΄¨ι‡ε›ΎεƒοΌŒζ‰­ζ›²ηš„θ‚’δ½“οΌŒθ―‘εΌ‚ηš„ε€–θ§‚οΌŒδΈ‘ι™‹οΌŒAIζ„ŸοΌŒε™ͺη‚ΉοΌŒη½‘ζ Όζ„ŸοΌŒJPEGεŽ‹ηΌ©ζ‘ηΊΉοΌŒεΌ‚εΈΈηš„θ‚’δ½“οΌŒζ°΄ε°οΌŒδΉ±η οΌŒζ„δΉ‰δΈζ˜Žηš„ε­—η¬¦"
28
  NEGATIVE_PROMPT_EN = "Yellowed, green-tinted, blurry, low-resolution, low-quality image, distorted limbs, eerie appearance, ugly, AI-looking, noise, grid-like artifacts, JPEG compression artifacts, abnormal limbs, watermark, garbled text, meaningless characters"
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  def install_diffsynth_studio():
32
  """Clone and install DiffSynth-Studio if not already installed."""
33
- # Check if already installed
34
  try:
35
  from diffsynth.pipelines.z_image import ZImagePipeline
36
  return True, "βœ… DiffSynth-Studio is already installed."
37
  except ImportError:
38
  pass
39
 
40
- # Define paths
41
  repo_dir = Path(__file__).parent / "DiffSynth-Studio"
42
 
43
  try:
44
- # Clone the repository if it doesn't exist
45
  if not repo_dir.exists():
46
  print("πŸ“₯ Cloning DiffSynth-Studio repository...")
47
- result = subprocess.run(
48
  ["git", "clone", "https://github.com/modelscope/DiffSynth-Studio.git", str(repo_dir)],
49
  capture_output=True,
50
  text=True,
@@ -53,15 +135,14 @@ def install_diffsynth_studio():
53
  print("βœ… Repository cloned successfully.")
54
  else:
55
  print("πŸ“ DiffSynth-Studio directory already exists, pulling latest...")
56
- result = subprocess.run(
57
  ["git", "-C", str(repo_dir), "pull"],
58
  capture_output=True,
59
  text=True
60
  )
61
 
62
- # Install in editable mode
63
  print("πŸ“¦ Installing DiffSynth-Studio...")
64
- result = subprocess.run(
65
  [sys.executable, "-m", "pip", "install", "-e", str(repo_dir)],
66
  capture_output=True,
67
  text=True,
@@ -69,7 +150,6 @@ def install_diffsynth_studio():
69
  )
70
  print("βœ… DiffSynth-Studio installed successfully.")
71
 
72
- # Add to path and try importing again
73
  sys.path.insert(0, str(repo_dir))
74
 
75
  from diffsynth.pipelines.z_image import ZImagePipeline
@@ -86,22 +166,28 @@ def install_diffsynth_studio():
86
 
87
 
88
  # =============================================================================
89
- # Pipeline Initialization (runs at module load time)
90
  # =============================================================================
91
 
92
- print("=" * 50)
93
  print(" Z-Image-i2L Gradio Demo - Initializing")
94
- print("=" * 50)
95
  print()
96
 
97
- # Ensure DiffSynth-Studio is installed
98
- print("πŸ” Checking DiffSynth-Studio installation...")
99
  success, message = install_diffsynth_studio()
100
  print(message)
101
 
102
  if not success:
103
  raise RuntimeError("Failed to install DiffSynth-Studio. Cannot continue.")
104
 
 
 
 
 
 
 
105
  # Import required modules
106
  from diffsynth.pipelines.z_image import (
107
  ZImagePipeline, ModelConfig,
@@ -109,8 +195,9 @@ from diffsynth.pipelines.z_image import (
109
  )
110
  from safetensors.torch import save_file, load_file
111
 
112
- # Configure VRAM settings
113
- print("βš™οΈ Configuring VRAM settings...")
 
114
  vram_config = {
115
  "offload_dtype": torch.bfloat16,
116
  "offload_device": "cuda",
@@ -122,27 +209,75 @@ vram_config = {
122
  "computation_device": "cuda",
123
  }
124
 
125
- # Load the pipeline
126
- print("πŸš€ Loading Z-Image pipeline...")
127
- print(" This may take a few minutes on first run (downloading models)...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  pipe = ZImagePipeline.from_pretrained(
130
  torch_dtype=torch.bfloat16,
131
  device="cuda",
132
- model_configs=[
133
- ModelConfig(model_id="Tongyi-MAI/Z-Image", origin_file_pattern="transformer/*.safetensors", **vram_config),
134
- ModelConfig(model_id="Tongyi-MAI/Z-Image-Turbo", origin_file_pattern="text_encoder/*.safetensors"),
135
- ModelConfig(model_id="Tongyi-MAI/Z-Image-Turbo", origin_file_pattern="vae/diffusion_pytorch_model.safetensors"),
136
- ModelConfig(model_id="DiffSynth-Studio/General-Image-Encoders", origin_file_pattern="SigLIP2-G384/model.safetensors"),
137
- ModelConfig(model_id="DiffSynth-Studio/General-Image-Encoders", origin_file_pattern="DINOv3-7B/model.safetensors"),
138
- ModelConfig(model_id="DiffSynth-Studio/Z-Image-i2L", origin_file_pattern="model.safetensors"),
139
- ],
140
- tokenizer_config=ModelConfig(model_id="Tongyi-MAI/Z-Image-Turbo", origin_file_pattern="tokenizer/"),
141
  )
142
 
 
143
  print("βœ… Pipeline loaded successfully!")
 
144
  print()
145
 
 
146
  # =============================================================================
147
  # Gradio Functions
148
  # =============================================================================
@@ -156,13 +291,11 @@ def image_to_lora(images, progress=gr.Progress()):
156
  try:
157
  progress(0.1, desc="Processing images...")
158
 
159
- # Convert uploaded images to PIL
160
  pil_images = []
161
  for img in images:
162
  if isinstance(img, str):
163
  pil_images.append(Image.open(img).convert("RGB"))
164
  elif isinstance(img, tuple):
165
- # Gradio gallery returns tuples (filepath, caption)
166
  pil_images.append(Image.open(img[0]).convert("RGB"))
167
  else:
168
  pil_images.append(Image.fromarray(img).convert("RGB"))
@@ -176,14 +309,13 @@ def image_to_lora(images, progress=gr.Progress()):
176
 
177
  progress(0.9, desc="Saving LoRA file...")
178
 
179
- # Save to temporary file
180
  temp_dir = tempfile.mkdtemp()
181
  lora_path = os.path.join(temp_dir, "generated_lora.safetensors")
182
  save_file(lora, lora_path)
183
 
184
  progress(1.0, desc="Done!")
185
 
186
- return lora_path, f"βœ… LoRA generated successfully from {len(pil_images)} images!"
187
 
188
  except Exception as e:
189
  return None, f"❌ Error generating LoRA: {str(e)}"
@@ -235,10 +367,7 @@ def create_demo():
235
  with gr.Blocks(
236
  title="Z-Image-i2L Demo",
237
  theme=gr.themes.Soft(),
238
- css="""
239
- .gradio-container { max-width: 1200px !important; }
240
- .status-box { padding: 10px; border-radius: 5px; margin: 10px 0; }
241
- """
242
  ) as demo:
243
  gr.Markdown("""
244
  # 🎨 Z-Image-i2L: Image to LoRA Demo
@@ -251,12 +380,9 @@ def create_demo():
251
  3. **Generate Images**: Use the LoRA to create new images with your style
252
 
253
  > πŸ’‘ **Tip**: For best results, use 4-6 images with a consistent artistic style.
254
-
255
- βœ… **Pipeline is pre-loaded and ready to use!**
256
  """)
257
 
258
  with gr.Tabs():
259
- # Tab 1: Image to LoRA
260
  with gr.TabItem("πŸ“Έ Step 1: Image to LoRA"):
261
  with gr.Row():
262
  with gr.Column(scale=1):
@@ -269,10 +395,10 @@ def create_demo():
269
  )
270
 
271
  gr.Markdown("""
272
- **Guidelines for input images:**
273
  - Upload 1-6 images with a consistent style
274
  - Higher quality images produce better results
275
- - Mix of subjects (people, objects, scenes) helps generalization
276
  """)
277
 
278
  generate_lora_btn = gr.Button("🎯 Generate LoRA", variant="primary")
@@ -284,12 +410,11 @@ def create_demo():
284
  interactive=False
285
  )
286
  lora_status = gr.Textbox(
287
- label="LoRA Generation Status",
288
  interactive=False,
289
  lines=2
290
  )
291
 
292
- # Tab 2: Generate Images
293
  with gr.TabItem("πŸ–ΌοΈ Step 2: Generate Images"):
294
  with gr.Row():
295
  with gr.Column(scale=1):
@@ -316,59 +441,22 @@ def create_demo():
316
  use_en_neg = gr.Button("Use English", size="sm")
317
 
318
  with gr.Accordion("Advanced Settings", open=False):
319
- seed = gr.Number(
320
- label="Seed",
321
- value=0,
322
- precision=0
323
- )
324
- cfg_scale = gr.Slider(
325
- label="CFG Scale",
326
- minimum=1,
327
- maximum=10,
328
- value=4,
329
- step=0.5
330
- )
331
- sigma_shift = gr.Slider(
332
- label="Sigma Shift",
333
- minimum=1,
334
- maximum=15,
335
- value=8,
336
- step=1
337
- )
338
- num_steps = gr.Slider(
339
- label="Number of Steps",
340
- minimum=20,
341
- maximum=100,
342
- value=50,
343
- step=5
344
- )
345
 
346
  generate_btn = gr.Button("✨ Generate Image", variant="primary")
347
 
348
  with gr.Column(scale=1):
349
- output_image = gr.Image(
350
- label="Generated Image",
351
- type="pil",
352
- height=512
353
- )
354
- gen_status = gr.Textbox(
355
- label="Generation Status",
356
- interactive=False,
357
- lines=2
358
- )
359
 
360
  gr.Markdown("""
361
  ---
362
- ### πŸ“š Resources
363
- - [Z-Image-i2L Model](https://modelscope.cn/models/DiffSynth-Studio/Z-Image-i2L)
364
- - [DiffSynth-Studio GitHub](https://github.com/modelscope/DiffSynth-Studio)
365
- - [Online Demo](https://modelscope.cn/studios/DiffSynth-Studio/Z-Image-i2L)
366
-
367
- ### βš™οΈ Recommended Settings
368
- - **CFG Scale**: 4
369
- - **Sigma Shift**: 8
370
- - **Steps**: 50
371
- - Use negative prompts for better quality
372
  """)
373
 
374
  # Event handlers
@@ -378,47 +466,21 @@ def create_demo():
378
  outputs=[lora_output, lora_status]
379
  )
380
 
381
- # Auto-update lora_input when lora is generated
382
- lora_output.change(
383
- fn=lambda x: x,
384
- inputs=[lora_output],
385
- outputs=[lora_input]
386
- )
387
 
388
  generate_btn.click(
389
  fn=generate_image,
390
- inputs=[
391
- lora_input,
392
- prompt,
393
- negative_prompt,
394
- seed,
395
- cfg_scale,
396
- sigma_shift,
397
- num_steps
398
- ],
399
  outputs=[output_image, gen_status]
400
  )
401
 
402
- # Negative prompt presets
403
- use_cn_neg.click(
404
- fn=lambda: NEGATIVE_PROMPT_CN,
405
- outputs=[negative_prompt]
406
- )
407
- use_en_neg.click(
408
- fn=lambda: NEGATIVE_PROMPT_EN,
409
- outputs=[negative_prompt]
410
- )
411
 
412
  return demo
413
 
414
 
415
  if __name__ == "__main__":
416
  print("Starting Gradio server...")
417
- print()
418
-
419
  demo = create_demo()
420
- demo.launch(
421
- server_name="0.0.0.0",
422
- server_port=7860,
423
- share=False
424
- )
 
6
  Setup Instructions:
7
  1. Install dependencies:
8
  pip install -r requirements.txt
9
+ pip install huggingface_hub
10
 
11
+ 2. Run this demo (models will be auto-downloaded):
12
  python app.py
13
 
14
  Note: This requires a GPU with sufficient VRAM (recommended 24GB+)
 
23
  import subprocess
24
  import tempfile
25
  from pathlib import Path
26
+ import glob
27
 
28
  # Default negative prompts
29
  NEGATIVE_PROMPT_CN = "ζ³›ι»„οΌŒε‘η»ΏοΌŒζ¨‘η³ŠοΌŒδ½Žεˆ†θΎ¨ηŽ‡οΌŒδ½Žθ΄¨ι‡ε›ΎεƒοΌŒζ‰­ζ›²ηš„θ‚’δ½“οΌŒθ―‘εΌ‚ηš„ε€–θ§‚οΌŒδΈ‘ι™‹οΌŒAIζ„ŸοΌŒε™ͺη‚ΉοΌŒη½‘ζ Όζ„ŸοΌŒJPEGεŽ‹ηΌ©ζ‘ηΊΉοΌŒεΌ‚εΈΈηš„θ‚’δ½“οΌŒζ°΄ε°οΌŒδΉ±η οΌŒζ„δΉ‰δΈζ˜Žηš„ε­—η¬¦"
30
  NEGATIVE_PROMPT_EN = "Yellowed, green-tinted, blurry, low-resolution, low-quality image, distorted limbs, eerie appearance, ugly, AI-looking, noise, grid-like artifacts, JPEG compression artifacts, abnormal limbs, watermark, garbled text, meaningless characters"
31
 
32
+ # Model paths - can be overridden via environment variables
33
+ MODELS_DIR = Path(os.environ.get("ZIMAGE_MODELS_DIR", "./models"))
34
+
35
+
36
+ # =============================================================================
37
+ # Model Download Functions
38
+ # =============================================================================
39
+
40
+ def download_hf_models(output_dir: Path) -> dict:
41
+ """
42
+ Download required models from Hugging Face using huggingface_hub.
43
+
44
+ Downloads:
45
+ - DiffSynth-Studio/General-Image-Encoders
46
+ - Tongyi-MAI/Z-Image-Turbo
47
+ - Tongyi-MAI/Z-Image
48
+
49
+ Returns dict with paths to downloaded models.
50
+ """
51
+ from huggingface_hub import snapshot_download
52
+
53
+ output_dir.mkdir(parents=True, exist_ok=True)
54
+
55
+ models = [
56
+ {
57
+ "repo_id": "DiffSynth-Studio/General-Image-Encoders",
58
+ "description": "General Image Encoders (SigLIP2-G384, DINOv3-7B)",
59
+ "allow_patterns": None,
60
+ },
61
+ {
62
+ "repo_id": "Tongyi-MAI/Z-Image-Turbo",
63
+ "description": "Z-Image Turbo (text encoder, VAE, tokenizer)",
64
+ "allow_patterns": [
65
+ "text_encoder/*.safetensors",
66
+ "vae/*.safetensors",
67
+ "tokenizer/*",
68
+ ],
69
+ },
70
+ {
71
+ "repo_id": "Tongyi-MAI/Z-Image",
72
+ "description": "Z-Image base model (transformer)",
73
+ "allow_patterns": ["transformer/*.safetensors"],
74
+ },
75
+ ]
76
+
77
+ downloaded_paths = {}
78
+
79
+ for model in models:
80
+ repo_id = model["repo_id"]
81
+ local_dir = output_dir / repo_id
82
+
83
+ # Check if already downloaded
84
+ if local_dir.exists() and any(local_dir.rglob("*.safetensors")):
85
+ print(f" βœ“ {repo_id} (already downloaded)")
86
+ downloaded_paths[repo_id] = local_dir
87
+ continue
88
+
89
+ print(f" πŸ“₯ Downloading {repo_id}...")
90
+ print(f" {model['description']}")
91
+
92
+ try:
93
+ result_path = snapshot_download(
94
+ repo_id=repo_id,
95
+ local_dir=str(local_dir),
96
+ allow_patterns=model["allow_patterns"],
97
+ local_dir_use_symlinks=False,
98
+ resume_download=True,
99
+ )
100
+ downloaded_paths[repo_id] = Path(result_path)
101
+ print(f" βœ“ {repo_id}")
102
+ except Exception as e:
103
+ print(f" ❌ Error downloading {repo_id}: {e}")
104
+ raise
105
+
106
+ return downloaded_paths
107
+
108
+
109
+ def get_model_files(base_path: Path, pattern: str) -> list:
110
+ """Get list of files matching a glob pattern."""
111
+ full_pattern = str(base_path / pattern)
112
+ files = sorted(glob.glob(full_pattern))
113
+ return files
114
+
115
 
116
  def install_diffsynth_studio():
117
  """Clone and install DiffSynth-Studio if not already installed."""
 
118
  try:
119
  from diffsynth.pipelines.z_image import ZImagePipeline
120
  return True, "βœ… DiffSynth-Studio is already installed."
121
  except ImportError:
122
  pass
123
 
 
124
  repo_dir = Path(__file__).parent / "DiffSynth-Studio"
125
 
126
  try:
 
127
  if not repo_dir.exists():
128
  print("πŸ“₯ Cloning DiffSynth-Studio repository...")
129
+ subprocess.run(
130
  ["git", "clone", "https://github.com/modelscope/DiffSynth-Studio.git", str(repo_dir)],
131
  capture_output=True,
132
  text=True,
 
135
  print("βœ… Repository cloned successfully.")
136
  else:
137
  print("πŸ“ DiffSynth-Studio directory already exists, pulling latest...")
138
+ subprocess.run(
139
  ["git", "-C", str(repo_dir), "pull"],
140
  capture_output=True,
141
  text=True
142
  )
143
 
 
144
  print("πŸ“¦ Installing DiffSynth-Studio...")
145
+ subprocess.run(
146
  [sys.executable, "-m", "pip", "install", "-e", str(repo_dir)],
147
  capture_output=True,
148
  text=True,
 
150
  )
151
  print("βœ… DiffSynth-Studio installed successfully.")
152
 
 
153
  sys.path.insert(0, str(repo_dir))
154
 
155
  from diffsynth.pipelines.z_image import ZImagePipeline
 
166
 
167
 
168
  # =============================================================================
169
+ # Pipeline Initialization
170
  # =============================================================================
171
 
172
+ print("=" * 60)
173
  print(" Z-Image-i2L Gradio Demo - Initializing")
174
+ print("=" * 60)
175
  print()
176
 
177
+ # Step 1: Install DiffSynth-Studio
178
+ print("πŸ” Step 1: Checking DiffSynth-Studio installation...")
179
  success, message = install_diffsynth_studio()
180
  print(message)
181
 
182
  if not success:
183
  raise RuntimeError("Failed to install DiffSynth-Studio. Cannot continue.")
184
 
185
+ # Step 2: Download HuggingFace models
186
+ print()
187
+ print("πŸ” Step 2: Downloading models from HuggingFace...")
188
+ print(f" Models directory: {MODELS_DIR.absolute()}")
189
+ downloaded_paths = download_hf_models(MODELS_DIR)
190
+
191
  # Import required modules
192
  from diffsynth.pipelines.z_image import (
193
  ZImagePipeline, ModelConfig,
 
195
  )
196
  from safetensors.torch import save_file, load_file
197
 
198
+ # Step 3: Configure VRAM settings
199
+ print()
200
+ print("βš™οΈ Step 3: Configuring VRAM settings...")
201
  vram_config = {
202
  "offload_dtype": torch.bfloat16,
203
  "offload_device": "cuda",
 
209
  "computation_device": "cuda",
210
  }
211
 
212
+ # Step 4: Resolve local model paths
213
+ print()
214
+ print("πŸ“‚ Step 4: Resolving model paths...")
215
+
216
+ # Z-Image transformer
217
+ zimage_path = MODELS_DIR / "Tongyi-MAI" / "Z-Image"
218
+ zimage_transformer_files = get_model_files(zimage_path, "transformer/*.safetensors")
219
+
220
+ # Z-Image-Turbo
221
+ zimage_turbo_path = MODELS_DIR / "Tongyi-MAI" / "Z-Image-Turbo"
222
+ text_encoder_files = get_model_files(zimage_turbo_path, "text_encoder/*.safetensors")
223
+ vae_file = get_model_files(zimage_turbo_path, "vae/diffusion_pytorch_model.safetensors")
224
+ tokenizer_path = zimage_turbo_path / "tokenizer"
225
+
226
+ # General Image Encoders
227
+ encoders_path = MODELS_DIR / "DiffSynth-Studio" / "General-Image-Encoders"
228
+ siglip_file = get_model_files(encoders_path, "SigLIP2-G384/model.safetensors")
229
+ dino_file = get_model_files(encoders_path, "DINOv3-7B/model.safetensors")
230
+
231
+ print(f" Z-Image transformer: {len(zimage_transformer_files)} file(s)")
232
+ print(f" Text encoder: {len(text_encoder_files)} file(s)")
233
+ print(f" VAE: {len(vae_file)} file(s)")
234
+ print(f" Tokenizer: {tokenizer_path}")
235
+ print(f" SigLIP2: {len(siglip_file)} file(s)")
236
+ print(f" DINOv3: {len(dino_file)} file(s)")
237
+ print(f" Z-Image-i2L: ModelScope (auto-download)")
238
+
239
+ # Validate files
240
+ missing = []
241
+ if not zimage_transformer_files: missing.append("Z-Image transformer")
242
+ if not text_encoder_files: missing.append("Text encoder")
243
+ if not vae_file: missing.append("VAE")
244
+ if not tokenizer_path.exists(): missing.append("Tokenizer")
245
+ if not siglip_file: missing.append("SigLIP2")
246
+ if not dino_file: missing.append("DINOv3")
247
+
248
+ if missing:
249
+ raise FileNotFoundError(f"Missing model files: {', '.join(missing)}")
250
+
251
+ # Step 5: Load pipeline
252
+ print()
253
+ print("πŸš€ Step 5: Loading Z-Image pipeline...")
254
+ print(" HuggingFace models: loaded from local paths")
255
+ print(" Z-Image-i2L: loading from ModelScope...")
256
+
257
+ model_configs = [
258
+ # HuggingFace models - use path= for local files
259
+ ModelConfig(path=zimage_transformer_files, **vram_config),
260
+ ModelConfig(path=text_encoder_files),
261
+ ModelConfig(path=vae_file),
262
+ ModelConfig(path=siglip_file),
263
+ ModelConfig(path=dino_file),
264
+ # ModelScope only - use model_id= for remote download
265
+ ModelConfig(model_id="DiffSynth-Studio/Z-Image-i2L", origin_file_pattern="model.safetensors"),
266
+ ]
267
 
268
  pipe = ZImagePipeline.from_pretrained(
269
  torch_dtype=torch.bfloat16,
270
  device="cuda",
271
+ model_configs=model_configs,
272
+ tokenizer_config=ModelConfig(path=str(tokenizer_path)),
 
 
 
 
 
 
 
273
  )
274
 
275
+ print()
276
  print("βœ… Pipeline loaded successfully!")
277
+ print("=" * 60)
278
  print()
279
 
280
+
281
  # =============================================================================
282
  # Gradio Functions
283
  # =============================================================================
 
291
  try:
292
  progress(0.1, desc="Processing images...")
293
 
 
294
  pil_images = []
295
  for img in images:
296
  if isinstance(img, str):
297
  pil_images.append(Image.open(img).convert("RGB"))
298
  elif isinstance(img, tuple):
 
299
  pil_images.append(Image.open(img[0]).convert("RGB"))
300
  else:
301
  pil_images.append(Image.fromarray(img).convert("RGB"))
 
309
 
310
  progress(0.9, desc="Saving LoRA file...")
311
 
 
312
  temp_dir = tempfile.mkdtemp()
313
  lora_path = os.path.join(temp_dir, "generated_lora.safetensors")
314
  save_file(lora, lora_path)
315
 
316
  progress(1.0, desc="Done!")
317
 
318
+ return lora_path, f"βœ… LoRA generated successfully from {len(pil_images)} image(s)!"
319
 
320
  except Exception as e:
321
  return None, f"❌ Error generating LoRA: {str(e)}"
 
367
  with gr.Blocks(
368
  title="Z-Image-i2L Demo",
369
  theme=gr.themes.Soft(),
370
+ css=".gradio-container { max-width: 1200px !important; }"
 
 
 
371
  ) as demo:
372
  gr.Markdown("""
373
  # 🎨 Z-Image-i2L: Image to LoRA Demo
 
380
  3. **Generate Images**: Use the LoRA to create new images with your style
381
 
382
  > πŸ’‘ **Tip**: For best results, use 4-6 images with a consistent artistic style.
 
 
383
  """)
384
 
385
  with gr.Tabs():
 
386
  with gr.TabItem("πŸ“Έ Step 1: Image to LoRA"):
387
  with gr.Row():
388
  with gr.Column(scale=1):
 
395
  )
396
 
397
  gr.Markdown("""
398
+ **Guidelines:**
399
  - Upload 1-6 images with a consistent style
400
  - Higher quality images produce better results
401
+ - Mix of subjects helps generalization
402
  """)
403
 
404
  generate_lora_btn = gr.Button("🎯 Generate LoRA", variant="primary")
 
410
  interactive=False
411
  )
412
  lora_status = gr.Textbox(
413
+ label="Status",
414
  interactive=False,
415
  lines=2
416
  )
417
 
 
418
  with gr.TabItem("πŸ–ΌοΈ Step 2: Generate Images"):
419
  with gr.Row():
420
  with gr.Column(scale=1):
 
441
  use_en_neg = gr.Button("Use English", size="sm")
442
 
443
  with gr.Accordion("Advanced Settings", open=False):
444
+ seed = gr.Number(label="Seed", value=0, precision=0)
445
+ cfg_scale = gr.Slider(label="CFG Scale", minimum=1, maximum=10, value=4, step=0.5)
446
+ sigma_shift = gr.Slider(label="Sigma Shift", minimum=1, maximum=15, value=8, step=1)
447
+ num_steps = gr.Slider(label="Steps", minimum=20, maximum=100, value=50, step=5)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
 
449
  generate_btn = gr.Button("✨ Generate Image", variant="primary")
450
 
451
  with gr.Column(scale=1):
452
+ output_image = gr.Image(label="Generated Image", type="pil", height=512)
453
+ gen_status = gr.Textbox(label="Status", interactive=False, lines=2)
 
 
 
 
 
 
 
 
454
 
455
  gr.Markdown("""
456
  ---
457
+ **Resources:** [Z-Image-i2L](https://modelscope.cn/models/DiffSynth-Studio/Z-Image-i2L) |
458
+ [DiffSynth-Studio](https://github.com/modelscope/DiffSynth-Studio) |
459
+ **Settings:** CFG=4, Sigma Shift=8, Steps=50
 
 
 
 
 
 
 
460
  """)
461
 
462
  # Event handlers
 
466
  outputs=[lora_output, lora_status]
467
  )
468
 
469
+ lora_output.change(fn=lambda x: x, inputs=[lora_output], outputs=[lora_input])
 
 
 
 
 
470
 
471
  generate_btn.click(
472
  fn=generate_image,
473
+ inputs=[lora_input, prompt, negative_prompt, seed, cfg_scale, sigma_shift, num_steps],
 
 
 
 
 
 
 
 
474
  outputs=[output_image, gen_status]
475
  )
476
 
477
+ use_cn_neg.click(fn=lambda: NEGATIVE_PROMPT_CN, outputs=[negative_prompt])
478
+ use_en_neg.click(fn=lambda: NEGATIVE_PROMPT_EN, outputs=[negative_prompt])
 
 
 
 
 
 
 
479
 
480
  return demo
481
 
482
 
483
  if __name__ == "__main__":
484
  print("Starting Gradio server...")
 
 
485
  demo = create_demo()
486
+ demo.launch(server_name="0.0.0.0", server_port=7860, share=False)