prithivMLmods commited on
Commit
68a17c4
·
verified ·
1 Parent(s): 591939f

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -394
app.py DELETED
@@ -1,394 +0,0 @@
1
- import spaces
2
- import gradio as gr
3
- import torch
4
- from PIL import Image
5
- from diffusers import DiffusionPipeline, QwenImageEditPipeline, FlowMatchEulerDiscreteScheduler
6
- import random
7
- import uuid
8
- import numpy as np
9
- import time
10
- import zipfile
11
- import os
12
- import requests
13
- from urllib.parse import urlparse
14
- import tempfile
15
- import shutil
16
- import math
17
-
18
- # --- App Description ---
19
- DESCRIPTION = """## Qwen Image Hpc/."""
20
-
21
- # --- Helper Functions for Both Tabs ---
22
- MAX_SEED = np.iinfo(np.int32).max
23
-
24
- def save_image(img):
25
- """Saves a PIL image to a temporary file with a unique name."""
26
- unique_name = str(uuid.uuid4()) + ".png"
27
- img.save(unique_name)
28
- return unique_name
29
-
30
- def randomize_seed_fn(seed: int, randomize_seed: bool) -> int:
31
- """Returns a random seed if randomize_seed is True, otherwise returns the original seed."""
32
- if randomize_seed:
33
- seed = random.randint(0, MAX_SEED)
34
- return seed
35
-
36
- # --- Model Loading ---
37
- dtype = torch.bfloat16
38
- device = "cuda" if torch.cuda.is_available() else "cpu"
39
-
40
- # --- Qwen-Image-Gen Model ---
41
- pipe_qwen_gen = DiffusionPipeline.from_pretrained(
42
- "Qwen/Qwen-Image",
43
- torch_dtype=dtype
44
- ).to(device)
45
-
46
- # --- Qwen-Image-Edit Model with Lightning LoRA ---
47
- scheduler_config = {
48
- "base_image_seq_len": 256,
49
- "base_shift": math.log(3),
50
- "invert_sigmas": False,
51
- "max_image_seq_len": 8192,
52
- "max_shift": math.log(3),
53
- "num_train_timesteps": 1000,
54
- "shift": 1.0,
55
- "shift_terminal": None,
56
- "stochastic_sampling": False,
57
- "time_shift_type": "exponential",
58
- "use_beta_sigmas": False,
59
- "use_dynamic_shifting": True,
60
- "use_exponential_sigmas": False,
61
- "use_karras_sigmas": False,
62
- }
63
- scheduler = FlowMatchEulerDiscreteScheduler.from_config(scheduler_config)
64
-
65
- pipe_qwen_edit = QwenImageEditPipeline.from_pretrained(
66
- "Qwen/Qwen-Image-Edit",
67
- scheduler=scheduler,
68
- torch_dtype=dtype
69
- ).to(device)
70
-
71
- try:
72
- pipe_qwen_edit.load_lora_weights(
73
- "lightx2v/Qwen-Image-Lightning",
74
- weight_name="Qwen-Image-Lightning-8steps-V1.1.safetensors"
75
- )
76
- pipe_qwen_edit.fuse_lora()
77
- print("Successfully loaded Lightning LoRA weights for Qwen-Image-Edit")
78
- except Exception as e:
79
- print(f"Warning: Could not load Lightning LoRA weights for Qwen-Image-Edit: {e}")
80
- print("Continuing with the base Qwen-Image-Edit model...")
81
-
82
-
83
- # --- Qwen-Image-Gen Functions ---
84
- aspect_ratios = {
85
- "1:1": (1328, 1328),
86
- "16:9": (1664, 928),
87
- "9:16": (928, 1664),
88
- "4:3": (1472, 1140),
89
- "3:4": (1140, 1472)
90
- }
91
-
92
- def load_lora_opt(pipe, lora_input):
93
- """Loads a LoRA from a local path, Hugging Face repo, or URL."""
94
- lora_input = lora_input.strip()
95
- if not lora_input:
96
- return
97
-
98
- if "/" in lora_input and not lora_input.startswith("http"):
99
- pipe.load_lora_weights(lora_input, adapter_name="default")
100
- return
101
-
102
- if lora_input.startswith("http"):
103
- url = lora_input
104
- if "huggingface.co" in url and "/blob/" not in url and "/resolve/" not in url:
105
- repo_id = urlparse(url).path.strip("/")
106
- pipe.load_lora_weights(repo_id, adapter_name="default")
107
- return
108
-
109
- if "/blob/" in url:
110
- url = url.replace("/blob/", "/resolve/")
111
-
112
- tmp_dir = tempfile.mkdtemp()
113
- local_path = os.path.join(tmp_dir, os.path.basename(urlparse(url).path))
114
-
115
- try:
116
- print(f"Downloading LoRA from {url}...")
117
- resp = requests.get(url, stream=True)
118
- resp.raise_for_status()
119
- with open(local_path, "wb") as f:
120
- for chunk in resp.iter_content(chunk_size=8192):
121
- f.write(chunk)
122
- print(f"Saved LoRA to {local_path}")
123
- pipe.load_lora_weights(local_path, adapter_name="default")
124
- finally:
125
- shutil.rmtree(tmp_dir, ignore_errors=True)
126
-
127
- @spaces.GPU(duration=120)
128
- def generate_qwen(
129
- prompt: str,
130
- negative_prompt: str = "",
131
- seed: int = 0,
132
- width: int = 1024,
133
- height: int = 1024,
134
- guidance_scale: float = 4.0,
135
- randomize_seed: bool = False,
136
- num_inference_steps: int = 50,
137
- num_images: int = 1,
138
- zip_images: bool = False,
139
- lora_input: str = "",
140
- lora_scale: float = 1.0,
141
- progress=gr.Progress(track_tqdm=True),
142
- ):
143
- """Main generation function for Qwen-Image-Gen."""
144
- seed = randomize_seed_fn(seed, randomize_seed)
145
- generator = torch.Generator(device).manual_seed(seed)
146
-
147
- start_time = time.time()
148
-
149
- current_adapters = pipe_qwen_gen.get_list_adapters()
150
- for adapter in current_adapters:
151
- pipe_qwen_gen.delete_adapters(adapter)
152
- pipe_qwen_gen.disable_lora()
153
-
154
- if lora_input and lora_input.strip() != "":
155
- load_lora_opt(pipe_qwen_gen, lora_input)
156
- pipe_qwen_gen.set_adapters(["default"], adapter_weights=[lora_scale])
157
-
158
- images = pipe_qwen_gen(
159
- prompt=prompt,
160
- negative_prompt=negative_prompt if negative_prompt else " ",
161
- height=height,
162
- width=width,
163
- guidance_scale=guidance_scale,
164
- num_inference_steps=num_inference_steps,
165
- num_images_per_prompt=num_images,
166
- generator=generator,
167
- ).images
168
-
169
- end_time = time.time()
170
- duration = end_time - start_time
171
-
172
- image_paths = [save_image(img) for img in images]
173
- zip_path = None
174
- if zip_images and len(image_paths) > 0:
175
- zip_name = str(uuid.uuid4()) + ".zip"
176
- with zipfile.ZipFile(zip_name, 'w') as zipf:
177
- for i, img_path in enumerate(image_paths):
178
- zipf.write(img_path, arcname=f"Img_{i}.png")
179
- zip_path = zip_name
180
-
181
- current_adapters = pipe_qwen_gen.get_list_adapters()
182
- for adapter in current_adapters:
183
- pipe_qwen_gen.delete_adapters(adapter)
184
- pipe_qwen_gen.disable_lora()
185
-
186
- return image_paths, seed, f"{duration:.2f}", zip_path
187
-
188
- @spaces.GPU(duration=120)
189
- def generate(
190
- prompt: str,
191
- negative_prompt: str,
192
- use_negative_prompt: bool,
193
- seed: int,
194
- width: int,
195
- height: int,
196
- guidance_scale: float,
197
- randomize_seed: bool,
198
- num_inference_steps: int,
199
- num_images: int,
200
- zip_images: bool,
201
- lora_input: str,
202
- lora_scale: float,
203
- progress=gr.Progress(track_tqdm=True),
204
- ):
205
- """UI wrapper for the Qwen-Image-Gen generation function."""
206
- final_negative_prompt = negative_prompt if use_negative_prompt else ""
207
- return generate_qwen(
208
- prompt=prompt,
209
- negative_prompt=final_negative_prompt,
210
- seed=seed,
211
- width=width,
212
- height=height,
213
- guidance_scale=guidance_scale,
214
- randomize_seed=randomize_seed,
215
- num_inference_steps=num_inference_steps,
216
- num_images=num_images,
217
- zip_images=zip_images,
218
- lora_input=lora_input,
219
- lora_scale=lora_scale,
220
- progress=progress,
221
- )
222
-
223
- # --- Qwen-Image-Edit Functions ---
224
- @spaces.GPU(duration=60)
225
- def infer_edit(
226
- image,
227
- prompt,
228
- seed=42,
229
- randomize_seed=False,
230
- true_guidance_scale=1.0,
231
- num_inference_steps=8,
232
- progress=gr.Progress(track_tqdm=True),
233
- ):
234
- """Main inference function for Qwen-Image-Edit."""
235
- if image is None:
236
- raise gr.Error("Please upload an image to edit.")
237
-
238
- negative_prompt = " "
239
- seed = randomize_seed_fn(seed, randomize_seed)
240
- generator = torch.Generator(device=device).manual_seed(seed)
241
-
242
- print(f"Original prompt: '{prompt}'")
243
- print(f"Negative Prompt: '{negative_prompt}'")
244
- print(f"Seed: {seed}, Steps: {num_inference_steps}, Guidance: {true_guidance_scale}")
245
-
246
- try:
247
- images = pipe_qwen_edit(
248
- image,
249
- prompt=prompt,
250
- negative_prompt=negative_prompt,
251
- num_inference_steps=num_inference_steps,
252
- generator=generator,
253
- true_cfg_scale=true_guidance_scale,
254
- num_images_per_prompt=1
255
- ).images
256
- return images[0], seed
257
- except Exception as e:
258
- print(f"Error during inference: {e}")
259
- raise gr.Error(f"An error occurred during image editing: {e}")
260
-
261
- # --- Gradio UI ---
262
- css = '''
263
- .gradio-container {
264
- max-width: 800px !important;
265
- margin: 0 auto !important;
266
- }
267
- h1 {
268
- text-align: center;
269
- }
270
- footer {
271
- visibility: hidden;
272
- }
273
- '''
274
-
275
- with gr.Blocks(css=css, theme="bethecloud/storj_theme", delete_cache=(240, 240)) as demo:
276
- gr.Markdown(DESCRIPTION)
277
-
278
- with gr.Tabs():
279
- with gr.TabItem("Qwen-Image-Gen"):
280
- with gr.Column():
281
- with gr.Row():
282
- prompt_gen = gr.Text(
283
- label="Prompt",
284
- show_label=False,
285
- max_lines=1,
286
- placeholder="✦︎ Enter your prompt for generation",
287
- container=False,
288
- )
289
- run_button_gen = gr.Button("Generate", scale=0, variant="primary")
290
- result_gen = gr.Gallery(label="Result", columns=2, show_label=False, preview=True, height="auto")
291
-
292
- with gr.Row():
293
- aspect_ratio_gen = gr.Dropdown(
294
- label="Aspect Ratio",
295
- choices=list(aspect_ratios.keys()),
296
- value="1:1",
297
- )
298
- lora_gen = gr.Textbox(label="Optional LoRA", placeholder="Enter Hugging Face repo ID or URL...")
299
-
300
- with gr.Accordion("Additional Options", open=False):
301
- use_negative_prompt_gen = gr.Checkbox(label="Use negative prompt", value=True)
302
- negative_prompt_gen = gr.Text(
303
- label="Negative prompt",
304
- max_lines=1,
305
- placeholder="Enter a negative prompt",
306
- value="text, watermark, copyright, blurry, low resolution",
307
- )
308
- seed_gen = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
309
- randomize_seed_gen = gr.Checkbox(label="Randomize seed", value=True)
310
- with gr.Row():
311
- width_gen = gr.Slider(label="Width", minimum=512, maximum=2048, step=64, value=1328)
312
- height_gen = gr.Slider(label="Height", minimum=512, maximum=2048, step=64, value=1328)
313
- guidance_scale_gen = gr.Slider(label="Guidance Scale", minimum=0.0, maximum=20.0, step=0.1, value=4.0)
314
- num_inference_steps_gen = gr.Slider("Number of inference steps", 1, 100, 50, step=1)
315
- num_images_gen = gr.Slider("Number of images", 1, 5, 1, step=1)
316
- zip_images_gen = gr.Checkbox(label="Zip generated images", value=False)
317
- with gr.Row():
318
- lora_scale_gen = gr.Slider(label="LoRA Scale", minimum=0, maximum=2, step=0.01, value=1)
319
-
320
- gr.Markdown("### Output Information")
321
- seed_display_gen = gr.Textbox(label="Seed used", interactive=False)
322
- generation_time_gen = gr.Textbox(label="Generation time (seconds)", interactive=False)
323
- zip_file_gen = gr.File(label="Download ZIP")
324
-
325
- # --- Gen Tab Logic ---
326
- def set_dimensions(ar):
327
- w, h = aspect_ratios[ar]
328
- return gr.update(value=w), gr.update(value=h)
329
-
330
- aspect_ratio_gen.change(fn=set_dimensions, inputs=aspect_ratio_gen, outputs=[width_gen, height_gen])
331
- use_negative_prompt_gen.change(fn=lambda x: gr.update(visible=x), inputs=use_negative_prompt_gen, outputs=negative_prompt_gen)
332
-
333
- gen_inputs = [
334
- prompt_gen, negative_prompt_gen, use_negative_prompt_gen, seed_gen, width_gen, height_gen,
335
- guidance_scale_gen, randomize_seed_gen, num_inference_steps_gen, num_images_gen,
336
- zip_images_gen, lora_gen, lora_scale_gen
337
- ]
338
- gen_outputs = [result_gen, seed_display_gen, generation_time_gen, zip_file_gen]
339
-
340
- gr.on(triggers=[prompt_gen.submit, run_button_gen.click], fn=generate, inputs=gen_inputs, outputs=gen_outputs)
341
-
342
- gen_examples = [
343
- "A decadent slice of layered chocolate cake on a ceramic plate with a drizzle of chocolate syrup and powdered sugar dusted on top.",
344
- "A young girl wearing school uniform stands in a classroom, writing on a chalkboard. The text 'Introducing Qwen-Image' appears in neat white chalk.",
345
- "一幅精致细腻的工笔画,画面中心是一株蓬勃生长的红色牡丹,花朵繁茂。",
346
- "Realistic still life photography style: A single, fresh apple, resting on a clean, soft-textured surface.",
347
- ]
348
- gr.Examples(examples=gen_examples, inputs=prompt_gen, outputs=gen_outputs, fn=generate, cache_examples=False)
349
-
350
- with gr.TabItem("Qwen-Image-Edit"):
351
- with gr.Column():
352
- with gr.Row():
353
- input_image_edit = gr.Image(label="Input Image", type="pil", height=400)
354
- result_edit = gr.Image(label="Result", type="pil", height=400)
355
-
356
- with gr.Row():
357
- prompt_edit = gr.Text(
358
- label="Edit Instruction",
359
- show_label=False,
360
- placeholder="Describe the edit you want to make",
361
- container=False,
362
- )
363
- run_button_edit = gr.Button("Edit", variant="primary")
364
-
365
- with gr.Accordion("Advanced Settings", open=False):
366
- seed_edit = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=42)
367
- randomize_seed_edit = gr.Checkbox(label="Randomize seed", value=True)
368
- with gr.Row():
369
- true_guidance_scale_edit = gr.Slider(
370
- label="True guidance scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0
371
- )
372
- num_inference_steps_edit = gr.Slider(
373
- label="Inference steps (Lightning LoRA)", minimum=4, maximum=28, step=1, value=8
374
- )
375
-
376
- # --- Edit Tab Logic ---
377
- edit_inputs = [
378
- input_image_edit, prompt_edit, seed_edit, randomize_seed_edit,
379
- true_guidance_scale_edit, num_inference_steps_edit
380
- ]
381
- edit_outputs = [result_edit, seed_edit]
382
-
383
- gr.on(triggers=[prompt_edit.submit, run_button_edit.click], fn=infer_edit, inputs=edit_inputs, outputs=edit_outputs)
384
-
385
- edit_examples = [
386
- ["image-edit/cat.png", "make the cat wear sunglasses"],
387
- ["image-edit/girl.png", "change her hair to blonde"],
388
- ]
389
-
390
- gr.Examples(examples=edit_examples, inputs=[input_image_edit, prompt_edit], outputs=edit_outputs, fn=infer_edit, cache_examples=True)
391
-
392
-
393
- if __name__ == "__main__":
394
- demo.queue(max_size=50).launch(share=False, debug=True)