akhaliq HF Staff commited on
Commit
a000256
·
verified ·
1 Parent(s): edcd91a

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. app.py +432 -0
  2. requirements.txt +21 -0
app.py ADDED
@@ -0,0 +1,432 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ GLM-Image to Image Editing App
3
+ A Gradio 6 application for image-to-image editing using the GLM-Image model.
4
+
5
+ This app allows users to upload an image and provide a prompt to transform
6
+ the image using the GLM-Image diffusion model.
7
+ """
8
+
9
+ import gradio as gr
10
+ import torch
11
+ from diffusers.pipelines.glm_image import GlmImagePipeline
12
+ from PIL import Image
13
+ import os
14
+ from datetime import datetime
15
+
16
+ # Initialize the model (lazy loading for better startup performance)
17
+ pipe = None
18
+
19
+ def load_model():
20
+ """Load the GLM-Image model with proper configuration."""
21
+ global pipe
22
+ if pipe is None:
23
+ pipe = GlmImagePipeline.from_pretrained(
24
+ "zai-org/GLM-Image",
25
+ torch_dtype=torch.bfloat16,
26
+ device_map="cuda"
27
+ )
28
+ return pipe
29
+
30
+ def validate_dimensions(height: int, width: int) -> tuple:
31
+ """
32
+ Validate and adjust dimensions to be multiples of 32.
33
+ GLM-Image requires height and width to be multiples of 32.
34
+ """
35
+ # Adjust to nearest multiples of 32
36
+ adjusted_height = (height // 32 + (1 if height % 32 != 0 else 0)) * 32
37
+ adjusted_width = (width // 32 + (1 if width % 32 != 0 else 0)) * 32
38
+ return adjusted_height, adjusted_width
39
+
40
+ def get_image_dimensions(image: Image.Image) -> tuple:
41
+ """Get the dimensions of an uploaded PIL image."""
42
+ return image.size[1], image.size[0] # height, width
43
+
44
+ def process_image(
45
+ image: Image.Image,
46
+ prompt: str,
47
+ height: int,
48
+ width: int,
49
+ num_inference_steps: int,
50
+ guidance_scale: float,
51
+ seed: int,
52
+ progress: gr.Progress
53
+ ) -> tuple:
54
+ """
55
+ Process the image through the GLM-Image pipeline.
56
+
57
+ Args:
58
+ image: Input PIL Image
59
+ prompt: Text prompt describing the desired transformation
60
+ height: Output height (must be multiple of 32)
61
+ width: Output width (must be multiple of 32)
62
+ num_inference_steps: Number of diffusion steps
63
+ guidance_scale: Guidance scale for diffusion
64
+ seed: Random seed for reproducibility
65
+ progress: Gradio progress tracker
66
+
67
+ Returns:
68
+ Tuple of (output_image, status_message)
69
+ """
70
+ try:
71
+ # Validate inputs
72
+ if image is None:
73
+ raise ValueError("Please upload an image first.")
74
+
75
+ if not prompt or not prompt.strip():
76
+ raise ValueError("Please enter a prompt describing the image transformation.")
77
+
78
+ # Adjust dimensions to be multiples of 32
79
+ adjusted_height, adjusted_width = validate_dimensions(height, width)
80
+
81
+ if adjusted_height != height or adjusted_width != width:
82
+ height, width = adjusted_height, adjusted_width
83
+
84
+ # Load model if not already loaded
85
+ progress(0.1, desc="Loading model...")
86
+ model = load_model()
87
+
88
+ # Prepare image
89
+ progress(0.2, desc="Processing image...")
90
+ input_image = image.convert("RGB")
91
+
92
+ # Create generator with seed
93
+ generator = torch.Generator(device="cuda").manual_seed(seed)
94
+
95
+ # Run the pipeline
96
+ progress(0.3, desc="Generating image...")
97
+ result = model(
98
+ prompt=prompt,
99
+ image=[input_image],
100
+ height=height,
101
+ width=width,
102
+ num_inference_steps=num_inference_steps,
103
+ guidance_scale=guidance_scale,
104
+ generator=generator
105
+ )
106
+
107
+ output_image = result.images[0]
108
+
109
+ progress(1.0, desc="Complete!")
110
+
111
+ status = f"✅ Successfully generated! ({height}x{width}, {num_inference_steps} steps)"
112
+ return output_image, status
113
+
114
+ except Exception as e:
115
+ error_msg = f"❌ Error: {str(e)}"
116
+ return None, error_msg
117
+
118
+ def update_dimensions_from_image(image: Image.Image) -> tuple:
119
+ """Update height and width based on uploaded image dimensions."""
120
+ if image is None:
121
+ return 1024, 1024
122
+ h, w = get_image_dimensions(image)
123
+ # Adjust to nearest multiples of 32
124
+ adjusted_h = (h // 32 + (1 if h % 32 != 0 else 0)) * 32
125
+ adjusted_w = (w // 32 + (1 if w % 32 != 0 else 0)) * 32
126
+ return adjusted_h, adjusted_w
127
+
128
+ def generate_random_seed() -> int:
129
+ """Generate a random seed for the diffusion process."""
130
+ import random
131
+ return random.randint(0, 2**32 - 1)
132
+
133
+ # Custom theme with modern design
134
+ custom_theme = gr.themes.Soft(
135
+ primary_hue="indigo",
136
+ secondary_hue="blue",
137
+ neutral_hue="slate",
138
+ font=gr.themes.GoogleFont("Inter"),
139
+ text_size="lg",
140
+ spacing_size="md",
141
+ radius_size="md"
142
+ ).set(
143
+ button_primary_background_fill="*primary_600",
144
+ button_primary_background_fill_hover="*primary_700",
145
+ button_secondary_background_fill="*secondary_200",
146
+ button_secondary_background_fill_hover="*secondary_300",
147
+ block_title_text_weight="600",
148
+ block_title_text_color="*primary_600",
149
+ input_background_fill="*neutral_100",
150
+ input_border_color="*neutral_300",
151
+ input_focus_border_color="*primary_400",
152
+ )
153
+
154
+ # Build the Gradio 6 application
155
+ with gr.Blocks(theme=custom_theme, fill_height=True) as demo:
156
+
157
+ # Header with branding
158
+ gr.Markdown(
159
+ """
160
+ # 🎨 GLM-Image Editor
161
+ Transform your images with AI-powered editing. Upload an image and describe how you want to modify it.
162
+
163
+ <div align="center">
164
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder">Built with anycoder</a>
165
+ </div>
166
+ """,
167
+ elem_classes=["header-markdown"]
168
+ )
169
+
170
+ # Main content in a row
171
+ with gr.Row(equal_height=True):
172
+ # Left column - Input controls
173
+ with gr.Column(scale=1, min_width=350):
174
+ gr.Markdown("### 📤 Input")
175
+
176
+ # Image upload
177
+ input_image = gr.Image(
178
+ label="Upload Image",
179
+ type="pil",
180
+ sources=["upload", "clipboard"],
181
+ elem_id="input-image",
182
+ height=300
183
+ )
184
+
185
+ # Prompt input
186
+ prompt = gr.Textbox(
187
+ label="Prompt",
188
+ placeholder="Describe how you want to transform the image...\n\nExample: Replace the background with an underground station featuring an automatic escalator.",
189
+ lines=4,
190
+ max_lines=6,
191
+ info="Be specific about what you want to change"
192
+ )
193
+
194
+ # Advanced settings accordion
195
+ with gr.Accordion("⚙️ Advanced Settings", open=False):
196
+ with gr.Row():
197
+ height = gr.Number(
198
+ label="Height",
199
+ value=1024,
200
+ minimum=64,
201
+ maximum=2048,
202
+ step=32,
203
+ info="Will be adjusted to multiple of 32"
204
+ )
205
+ width = gr.Number(
206
+ label="Width",
207
+ value=1024,
208
+ minimum=64,
209
+ maximum=2048,
210
+ step=32,
211
+ info="Will be adjusted to multiple of 32"
212
+ )
213
+
214
+ with gr.Row():
215
+ num_inference_steps = gr.Slider(
216
+ label="Inference Steps",
217
+ minimum=10,
218
+ maximum=100,
219
+ value=50,
220
+ step=5,
221
+ info="More steps = higher quality but slower"
222
+ )
223
+ guidance_scale = gr.Slider(
224
+ label="Guidance Scale",
225
+ minimum=0.5,
226
+ maximum=3.0,
227
+ value=1.5,
228
+ step=0.1,
229
+ info="How closely to follow the prompt"
230
+ )
231
+
232
+ with gr.Row():
233
+ seed = gr.Number(
234
+ label="Seed",
235
+ value=42,
236
+ minimum=0,
237
+ maximum=2**32 - 1,
238
+ step=1,
239
+ info="Random seed for reproducibility"
240
+ )
241
+ random_seed_btn = gr.Button(
242
+ "🎲 Random",
243
+ size="sm",
244
+ variant="secondary"
245
+ )
246
+
247
+ # Action buttons
248
+ with gr.Row():
249
+ generate_btn = gr.Button(
250
+ "✨ Generate Image",
251
+ variant="primary",
252
+ size="lg",
253
+ full_width=True
254
+ )
255
+
256
+ # Clear button
257
+ clear_btn = gr.Button(
258
+ "🗑️ Clear All",
259
+ variant="stop",
260
+ size="sm"
261
+ )
262
+
263
+ # Right column - Output
264
+ with gr.Column(scale=1, min_width=350):
265
+ gr.Markdown("### 📥 Output")
266
+
267
+ # Output image display
268
+ output_image = gr.Image(
269
+ label="Generated Image",
270
+ type="pil",
271
+ elem_id="output-image",
272
+ height=400,
273
+ interactive=False
274
+ )
275
+
276
+ # Status message
277
+ status = gr.Textbox(
278
+ label="Status",
279
+ value="Ready to generate!",
280
+ interactive=False,
281
+ show_label=True
282
+ )
283
+
284
+ # Download button
285
+ download_btn = gr.DownloadButton(
286
+ "💾 Download Image",
287
+ value=None,
288
+ variant="secondary",
289
+ interactive=False
290
+ )
291
+
292
+ # Tips section
293
+ with gr.Accordion("💡 Tips for Better Results", open=False):
294
+ gr.Markdown(
295
+ """
296
+ - **Be specific**: Include details about colors, style, and composition
297
+ - **Background changes**: Start with "Replace the background with..." or "Change the background to..."
298
+ - **Style transfer**: Mention artistic styles like "in the style of" or specific artists
299
+ - **Lighting**: Include lighting conditions like "soft natural lighting" or "dramatic shadows"
300
+
301
+ **Common prompt patterns:**
302
+ - `"Replace the background with [description]"`
303
+ - `"Transform this into [style]"`
304
+ - `"Add [elements] to the scene"`
305
+ - `"Change the [specific part] to [description]"`
306
+ """
307
+ )
308
+
309
+ # Example prompts section
310
+ with gr.Accordion("📝 Example Prompts", open=False):
311
+ gr.Markdown(
312
+ """
313
+ Try these prompts to get started:
314
+
315
+ | Transformation | Prompt |
316
+ |---------------|--------|
317
+ | Background Change | "Replace the background with a futuristic city skyline at sunset" |
318
+ | Style Transfer | "Transform this into an oil painting in the style of Van Gogh" |
319
+ | Scene Change | "Change the environment to an underwater coral reef with colorful fish" |
320
+ | Object Addition | "Add a red sports car parked in the foreground" |
321
+ | Weather Effect | "Make it look like it's raining with wet reflections on the ground" |
322
+ """
323
+ )
324
+
325
+ # Event handlers
326
+
327
+ # Update dimensions when image is uploaded
328
+ input_image.change(
329
+ fn=update_dimensions_from_image,
330
+ inputs=input_image,
331
+ outputs=[height, width],
332
+ api_visibility="private"
333
+ )
334
+
335
+ # Random seed generation
336
+ random_seed_btn.click(
337
+ fn=generate_random_seed,
338
+ outputs=seed,
339
+ api_visibility="private"
340
+ )
341
+
342
+ # Generate button handler
343
+ generate_btn.click(
344
+ fn=process_image,
345
+ inputs=[
346
+ input_image,
347
+ prompt,
348
+ height,
349
+ width,
350
+ num_inference_steps,
351
+ guidance_scale,
352
+ seed
353
+ ],
354
+ outputs=[output_image, status],
355
+ progress=gr.Progress()
356
+ )
357
+
358
+ # Update download button when output is generated
359
+ def enable_download(img):
360
+ if img is not None:
361
+ return gr.DownloadButton(value=img, interactive=True)
362
+ return gr.DownloadButton(interactive=False)
363
+
364
+ output_image.change(
365
+ fn=enable_download,
366
+ inputs=output_image,
367
+ outputs=download_btn,
368
+ api_visibility="private"
369
+ )
370
+
371
+ # Clear button handler
372
+ def clear_all():
373
+ return {
374
+ input_image: None,
375
+ prompt: "",
376
+ output_image: None,
377
+ status: "Ready to generate!",
378
+ download_btn: gr.DownloadButton(interactive=False)
379
+ }
380
+
381
+ clear_btn.click(
382
+ fn=clear_all,
383
+ outputs={
384
+ input_image: input_image,
385
+ prompt: prompt,
386
+ output_image: output_image,
387
+ status: status,
388
+ download_btn: download_btn
389
+ },
390
+ api_visibility="private"
391
+ )
392
+
393
+ # Gradio 6 - ALL app parameters go in launch()!
394
+ demo.launch(
395
+ theme=custom_theme,
396
+ css="""
397
+ .header-markdown {
398
+ text-align: center;
399
+ padding: 1rem;
400
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
401
+ border-radius: 0.5rem;
402
+ margin-bottom: 1rem;
403
+ }
404
+ .header-markdown h1 {
405
+ color: white !important;
406
+ margin: 0;
407
+ }
408
+ .header-markdown p {
409
+ color: rgba(255,255,255,0.9) !important;
410
+ margin: 0.5rem 0 0 0;
411
+ }
412
+ .header-markdown a {
413
+ color: #ffd700 !important;
414
+ text-decoration: underline;
415
+ }
416
+ #input-image, #output-image {
417
+ border: 2px dashed var(--neutral-300);
418
+ border-radius: var(--radius-lg);
419
+ }
420
+ #input-image:hover, #output-image:hover {
421
+ border-color: var(--primary-400);
422
+ }
423
+ """,
424
+ footer_links=[
425
+ {"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"},
426
+ {"label": "GLM-Image Model", "url": "https://huggingface.co/zai-org/GLM-Image"},
427
+ {"label": "Diffusers Library", "url": "https://github.com/huggingface/diffusers"}
428
+ ],
429
+ server_name="0.0.0.0",
430
+ server_port=7860,
431
+ debug=False
432
+ )
requirements.txt ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Pillow
2
+ torch
3
+ torchvision
4
+ torchaudio
5
+ gradio>=6.0
6
+ git+https://github.com/huggingface/diffusers
7
+ git+https://github.com/huggingface/transformers
8
+ sentencepiece
9
+ accelerate
10
+ tokenizers
11
+ datasets
12
+ numpy
13
+ requests
14
+ safetensors
15
+ huggingface-hub
16
+ fsspec
17
+ packaging
18
+ filelock
19
+ regex
20
+ tqdm
21
+ pyyaml