prithivMLmods commited on
Commit
c8a929f
·
verified ·
1 Parent(s): 67a7c5f

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -379
app.py DELETED
@@ -1,379 +0,0 @@
1
- import os
2
- import gc
3
- import gradio as gr
4
- from gradio import Server
5
- from fastapi.responses import HTMLResponse
6
- import numpy as np
7
- import spaces
8
- import torch
9
- import random
10
- import base64
11
- import json
12
- from io import BytesIO
13
- from PIL import Image
14
-
15
- MAX_SEED = np.iinfo(np.int32).max
16
- LANCZOS = getattr(Image, "Resampling", Image).LANCZOS
17
-
18
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
19
-
20
- print("CUDA_VISIBLE_DEVICES=", os.environ.get("CUDA_VISIBLE_DEVICES"))
21
- print("torch.__version__ =", torch.__version__)
22
- print("torch.version.cuda =", torch.version.cuda)
23
- print("cuda available:", torch.cuda.is_available())
24
- print("cuda device count:", torch.cuda.device_count())
25
- if torch.cuda.is_available():
26
- print("current device:", torch.cuda.current_device())
27
- print("device name:", torch.cuda.get_device_name(torch.cuda.current_device()))
28
-
29
- print("Using device:", device)
30
-
31
- from diffusers import FlowMatchEulerDiscreteScheduler
32
- from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
33
- from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
34
- from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
35
-
36
- dtype = torch.bfloat16
37
-
38
- pipe = QwenImageEditPlusPipeline.from_pretrained(
39
- "Qwen/Qwen-Image-Edit-2511",
40
- transformer=QwenImageTransformer2DModel.from_pretrained(
41
- "prithivMLmods/Qwen-Image-Edit-Rapid-AIO-V19",
42
- torch_dtype=dtype,
43
- device_map="cuda",
44
- ),
45
- torch_dtype=dtype,
46
- ).to(device)
47
-
48
- try:
49
- pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
50
- print("Flash Attention 3 Processor set successfully.")
51
- except Exception as e:
52
- print(f"Warning: Could not set FA3 processor: {e}")
53
-
54
- ADAPTER_SPECS = {
55
- "Multiple-Angles": {
56
- "repo": "dx8152/Qwen-Edit-2509-Multiple-angles",
57
- "weights": "镜头转换.safetensors",
58
- "adapter_name": "multiple-angles",
59
- },
60
- "Photo-to-Anime": {
61
- "repo": "autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime",
62
- "weights": "Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
63
- "adapter_name": "photo-to-anime",
64
- },
65
- "Anime-V2": {
66
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Anime",
67
- "weights": "Qwen-Image-Edit-2511-Anime-2000.safetensors",
68
- "adapter_name": "anime-v2",
69
- },
70
- "Light-Migration": {
71
- "repo": "dx8152/Qwen-Edit-2509-Light-Migration",
72
- "weights": "参考色调.safetensors",
73
- "adapter_name": "light-migration",
74
- },
75
- "Upscaler": {
76
- "repo": "starsfriday/Qwen-Image-Edit-2511-Upscale2K",
77
- "weights": "qwen_image_edit_2511_upscale.safetensors",
78
- "adapter_name": "upscale-2k",
79
- },
80
- "Style-Transfer": {
81
- "repo": "zooeyy/Style-Transfer",
82
- "weights": "Style Transfer-Alpha-V0.1.safetensors",
83
- "adapter_name": "style-transfer",
84
- },
85
- "Manga-Tone": {
86
- "repo": "nappa114514/Qwen-Image-Edit-2509-Manga-Tone",
87
- "weights": "tone001.safetensors",
88
- "adapter_name": "manga-tone",
89
- },
90
- "Anything2Real": {
91
- "repo": "lrzjason/Anything2Real_2601",
92
- "weights": "anything2real_2601.safetensors",
93
- "adapter_name": "anything2real",
94
- },
95
- "Fal-Multiple-Angles": {
96
- "repo": "fal/Qwen-Image-Edit-2511-Multiple-Angles-LoRA",
97
- "weights": "qwen-image-edit-2511-multiple-angles-lora.safetensors",
98
- "adapter_name": "fal-multiple-angles",
99
- },
100
- "Polaroid-Photo": {
101
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Polaroid-Photo",
102
- "weights": "Qwen-Image-Edit-2511-Polaroid-Photo.safetensors",
103
- "adapter_name": "polaroid-photo",
104
- },
105
- "Unblur-Anything": {
106
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Unblur-Upscale",
107
- "weights": "Qwen-Image-Edit-Unblur-Upscale_15.safetensors",
108
- "adapter_name": "unblur-anything",
109
- },
110
- "Midnight-Noir-Eyes-Spotlight": {
111
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Midnight-Noir-Eyes-Spotlight",
112
- "weights": "Qwen-Image-Edit-2511-Midnight-Noir-Eyes-Spotlight.safetensors",
113
- "adapter_name": "midnight-noir-eyes-spotlight",
114
- },
115
- "Hyper-Realistic-Portrait": {
116
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Hyper-Realistic-Portrait",
117
- "weights": "HRP_20.safetensors",
118
- "adapter_name": "hyper-realistic-portrait",
119
- },
120
- "Ultra-Realistic-Portrait": {
121
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Ultra-Realistic-Portrait",
122
- "weights": "URP_20.safetensors",
123
- "adapter_name": "ultra-realistic-portrait",
124
- },
125
- "Pixar-Inspired-3D": {
126
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Pixar-Inspired-3D",
127
- "weights": "PI3_20.safetensors",
128
- "adapter_name": "pi3",
129
- },
130
- "Noir-Comic-Book": {
131
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Noir-Comic-Book-Panel",
132
- "weights": "Noir-Comic-Book-Panel_20.safetensors",
133
- "adapter_name": "ncb",
134
- },
135
- "Any-light": {
136
- "repo": "lilylilith/QIE-2511-MP-AnyLight",
137
- "weights": "QIE-2511-AnyLight_.safetensors",
138
- "adapter_name": "any-light",
139
- },
140
- "Studio-DeLight": {
141
- "repo": "prithivMLmods/QIE-2511-Studio-DeLight",
142
- "weights": "QIE-2511-Studio-DeLight-5000.safetensors",
143
- "adapter_name": "studio-delight",
144
- },
145
- "Cinematic-FlatLog": {
146
- "repo": "prithivMLmods/QIE-2511-Cinematic-FlatLog-Control",
147
- "weights": "QIE-2511-Cinematic-FlatLog-Control-3200.safetensors",
148
- "adapter_name": "flat-log",
149
- },
150
- }
151
-
152
- LOADED_ADAPTERS: set = set()
153
- ADAPTER_NAMES = list(ADAPTER_SPECS.keys())
154
-
155
- EXAMPLES_CONFIG = [
156
- {"images": ["examples/B.jpg"], "prompt": "Transform into anime.", "lora": "Photo-to-Anime"},
157
- {"images": ["examples/HRP.jpg"], "prompt": "Transform into a hyper-realistic face portrait.", "lora": "Hyper-Realistic-Portrait"},
158
- {"images": ["examples/A.jpeg"], "prompt": "Rotate the camera 45 degrees to the right.", "lora": "Multiple-Angles"},
159
- {"images": ["examples/U.jpg"], "prompt": "Upscale this picture to 4K resolution.", "lora": "Upscaler"},
160
- {"images": ["examples/L1.jpg", "examples/L2.jpg"], "prompt": "Apply the lighting from image 2 to image 1.", "lora": "Any-light"},
161
- {"images": ["examples/PP1.jpg"], "prompt": "cinematic polaroid with soft grain subtle vignette gentle lighting white frame handwritten photographed preserving realistic texture and details.", "lora": "Polaroid-Photo"},
162
- {"images": ["examples/Z1.jpg"], "prompt": "Front-right quarter view.", "lora": "Fal-Multiple-Angles"},
163
- {"images": ["examples/URP.jpg"], "prompt": "Transform into a cinematic flat log.", "lora": "Cinematic-FlatLog"},
164
- {"images": ["examples/SL.jpg"], "prompt": "Neutral uniform lighting. Preserve identity and composition.", "lora": "Studio-DeLight"},
165
- {"images": ["examples/PI.jpg"], "prompt": "Transform it into Pixar-inspired 3D.", "lora": "Pixar-Inspired-3D"},
166
- {"images": ["examples/MT.jpg"], "prompt": "Paint with manga tone.", "lora": "Manga-Tone"},
167
- {"images": ["examples/NCB.jpg"], "prompt": "Transform into a noir comic book style.", "lora": "Noir-Comic-Book"},
168
- {"images": ["examples/URP.jpg"], "prompt": "Ultra-realistic portrait.", "lora": "Ultra-Realistic-Portrait"},
169
- {"images": ["examples/MN.jpg"], "prompt": "Transform into Midnight Noir Eyes Spotlight.", "lora": "Midnight-Noir-Eyes-Spotlight"},
170
- {"images": ["examples/ST1.jpg", "examples/ST2.jpg"], "prompt": "Convert Image 1 to the style of Image 2.", "lora": "Style-Transfer"},
171
- {"images": ["examples/R1.jpg"], "prompt": "Change the picture to realistic photograph.", "lora": "Anything2Real"},
172
- {"images": ["examples/UA.jpeg"], "prompt": "Unblur and upscale.", "lora": "Unblur-Anything"},
173
- {"images": ["examples/L1.jpg", "examples/L2.jpg"], "prompt": "Refer to the color tone, remove the original lighting from Image 1, and relight Image 1 based on the lighting and color tone of Image 2.", "lora": "Light-Migration"},
174
- {"images": ["examples/P1.jpg"], "prompt": "Transform into anime (while preserving the background and remaining elements maintaining realism and original details.)", "lora": "Anime-V2"},
175
- ]
176
-
177
-
178
- def make_thumb_b64(path, max_dim=220):
179
- if not os.path.exists(path):
180
- return ""
181
- try:
182
- img = Image.open(path).convert("RGB")
183
- img.thumbnail((max_dim, max_dim), LANCZOS)
184
- buf = BytesIO()
185
- img.save(buf, format="JPEG", quality=65)
186
- return f"data:image/jpeg;base64,{base64.b64encode(buf.getvalue()).decode()}"
187
- except Exception as e:
188
- print(f"Thumbnail error for {path}: {e}")
189
- return ""
190
-
191
-
192
- def encode_full_image(path):
193
- if not os.path.exists(path):
194
- return ""
195
- try:
196
- with open(path, "rb") as f:
197
- data = f.read()
198
- ext = path.rsplit(".", 1)[-1].lower()
199
- mime = {"jpg": "image/jpeg", "jpeg": "image/jpeg", "png": "image/png", "webp": "image/webp"}.get(ext, "image/jpeg")
200
- return f"data:{mime};base64,{base64.b64encode(data).decode()}"
201
- except Exception as e:
202
- print(f"Encode error for {path}: {e}")
203
- return ""
204
-
205
-
206
- def build_client_config():
207
- """Static config consumed by the frontend: LoRA list + example cards."""
208
- examples = []
209
- for i, ex in enumerate(EXAMPLES_CONFIG):
210
- examples.append({
211
- "idx": i,
212
- "thumbs": [make_thumb_b64(p) for p in ex["images"]],
213
- "n_images": len(ex["images"]),
214
- "lora": ex["lora"],
215
- "prompt": ex["prompt"],
216
- })
217
- return {
218
- "loras": ADAPTER_NAMES,
219
- "default_lora": "Photo-to-Anime",
220
- "examples": examples,
221
- }
222
-
223
-
224
- print("Building client config (example thumbnails)…")
225
- CLIENT_CONFIG = build_client_config()
226
- print(f"Built config with {len(EXAMPLES_CONFIG)} examples and {len(ADAPTER_NAMES)} LoRAs.")
227
-
228
-
229
- def b64_to_pil_list(b64_json_str):
230
- if not b64_json_str or b64_json_str.strip() in ("", "[]"):
231
- return []
232
- try:
233
- b64_list = json.loads(b64_json_str)
234
- except Exception:
235
- return []
236
- pil_images = []
237
- for b64_str in b64_list:
238
- if not b64_str or not isinstance(b64_str, str):
239
- continue
240
- try:
241
- if b64_str.startswith("data:image"):
242
- _, data = b64_str.split(",", 1)
243
- else:
244
- data = b64_str
245
- image_data = base64.b64decode(data)
246
- pil_images.append(Image.open(BytesIO(image_data)).convert("RGB"))
247
- except Exception as e:
248
- print(f"Error decoding image: {e}")
249
- return pil_images
250
-
251
-
252
- def pil_to_b64_png(image: Image.Image) -> str:
253
- buf = BytesIO()
254
- image.save(buf, format="PNG")
255
- return f"data:image/png;base64,{base64.b64encode(buf.getvalue()).decode()}"
256
-
257
-
258
- def update_dimensions_on_upload(image):
259
- if image is None:
260
- return 1024, 1024
261
- w, h = image.size
262
- if w > h:
263
- nw = 1024
264
- nh = int(nw * h / w)
265
- else:
266
- nh = 1024
267
- nw = int(nh * w / h)
268
- return (nw // 8) * 8, (nh // 8) * 8
269
-
270
-
271
- # ── Gradio Server (Server mode): FastAPI + Gradio queue/API engine ────────────
272
- app = Server(title="Qwen-Image-Edit-2511-LoRAs-Fast")
273
-
274
-
275
- @app.mcp.tool(name="edit_image")
276
- @app.api(name="edit_image")
277
- @spaces.GPU(size="xlarge")
278
- def infer(
279
- images_b64_json: str,
280
- prompt: str,
281
- lora_adapter: str,
282
- seed: int,
283
- randomize_seed: bool,
284
- guidance_scale: float,
285
- steps: int,
286
- ) -> dict:
287
- """Edit one or more images with Qwen-Image-Edit-2511 + a lazily-loaded LoRA.
288
-
289
- Returns {"image": <base64 PNG data URL>, "seed": <seed used>}.
290
- """
291
- gc.collect()
292
- torch.cuda.empty_cache()
293
-
294
- pil_images = b64_to_pil_list(images_b64_json)
295
- if not pil_images:
296
- raise gr.Error("Please upload at least one image to edit.")
297
- if not prompt or prompt.strip() == "":
298
- raise gr.Error("Please enter an edit prompt.")
299
-
300
- spec = ADAPTER_SPECS.get(lora_adapter)
301
- if not spec:
302
- raise gr.Error(f"Configuration not found for: {lora_adapter}")
303
-
304
- adapter_name = spec["adapter_name"]
305
- if adapter_name not in LOADED_ADAPTERS:
306
- print(f"--- Downloading and Loading Adapter: {lora_adapter} ---")
307
- try:
308
- pipe.load_lora_weights(spec["repo"], weight_name=spec["weights"], adapter_name=adapter_name)
309
- LOADED_ADAPTERS.add(adapter_name)
310
- except Exception as e:
311
- raise gr.Error(f"Failed to load adapter {lora_adapter}: {e}")
312
- else:
313
- print(f"--- Adapter {lora_adapter} already loaded. ---")
314
-
315
- pipe.set_adapters([adapter_name], adapter_weights=[1.0])
316
-
317
- if randomize_seed:
318
- seed = random.randint(0, MAX_SEED)
319
-
320
- generator = torch.Generator(device=device).manual_seed(seed)
321
- negative_prompt = (
322
- "worst quality, low quality, bad anatomy, bad hands, text, error, missing fingers, "
323
- "extra digit, fewer digits, cropped, jpeg artifacts, signature, watermark, username, blurry"
324
- )
325
- width, height = update_dimensions_on_upload(pil_images[0])
326
-
327
- try:
328
- result_image = pipe(
329
- image=pil_images,
330
- prompt=prompt,
331
- negative_prompt=negative_prompt,
332
- height=height,
333
- width=width,
334
- num_inference_steps=steps,
335
- generator=generator,
336
- true_cfg_scale=guidance_scale,
337
- ).images[0]
338
- return {"image": pil_to_b64_png(result_image), "seed": seed}
339
- except Exception as e:
340
- raise e
341
- finally:
342
- gc.collect()
343
- torch.cuda.empty_cache()
344
-
345
-
346
- @app.api(name="load_example", queue=False)
347
- def load_example(idx: float) -> dict:
348
- """Return base64-encoded example images + prompt + LoRA for a given example index."""
349
- try:
350
- i = int(idx)
351
- except (ValueError, TypeError):
352
- i = -1
353
- if i < 0 or i >= len(EXAMPLES_CONFIG):
354
- return {"images": [], "prompt": "", "lora": "", "names": [], "status": "error"}
355
- ex = EXAMPLES_CONFIG[i]
356
- b64_list, names = [], []
357
- for path in ex["images"]:
358
- b64 = encode_full_image(path)
359
- if b64:
360
- b64_list.append(b64)
361
- names.append(os.path.basename(path))
362
- return {"images": b64_list, "prompt": ex["prompt"], "lora": ex["lora"], "names": names, "status": "ok"}
363
-
364
-
365
- @app.get("/api/config")
366
- def client_config():
367
- """Plain FastAPI route: LoRA choices + example card data for the frontend."""
368
- return CLIENT_CONFIG
369
-
370
-
371
- @app.get("/", response_class=HTMLResponse)
372
- async def homepage():
373
- html_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "index.html")
374
- with open(html_path, "r", encoding="utf-8") as f:
375
- return f.read()
376
-
377
-
378
- if __name__ == "__main__":
379
- app.launch(show_error=True, mcp_server=True)