Update app.py
Browse files
app.py
CHANGED
|
@@ -52,8 +52,7 @@ steel_blue_theme = SteelBlueTheme()
|
|
| 52 |
|
| 53 |
# ── Device / dtype ─────────────────────────────────────────────────────────────
|
| 54 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 55 |
-
dtype
|
| 56 |
-
|
| 57 |
print("CUDA available:", torch.cuda.is_available())
|
| 58 |
print("Using device:", device)
|
| 59 |
|
|
@@ -75,8 +74,8 @@ pipe = QwenImageEditPlusPipeline.from_pretrained(
|
|
| 75 |
# ── OOM FIX: Enable VAE tiling and slicing to bound VRAM usage ─────────────────
|
| 76 |
pipe.vae.enable_tiling(tile_sample_min_width=256, tile_sample_min_height=256)
|
| 77 |
pipe.vae.enable_slicing()
|
| 78 |
-
# ───────────────────────────────────────────────────────────────────────────────
|
| 79 |
|
|
|
|
| 80 |
try:
|
| 81 |
pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
|
| 82 |
print("Flash Attention 3 Processor set successfully.")
|
|
@@ -85,127 +84,130 @@ except Exception as e:
|
|
| 85 |
|
| 86 |
# ── LoRA catalog ──────────────────────────────────────────────────────────
|
| 87 |
LORA_REPO = "wiikoo/Qwen-lora-nsfw"
|
|
|
|
| 88 |
LORA_CONFIGS = {
|
| 89 |
-
"CockQwen_v3":
|
| 90 |
-
"Eva_Qwen_V3":
|
| 91 |
-
"Facial_Cumshots_V1":
|
| 92 |
-
"HearmemanAI_V3_Breasts":
|
| 93 |
-
"HearmemanAI_V4_Breasts":
|
| 94 |
-
"InniePussy":
|
| 95 |
-
"JTT2_5":
|
| 96 |
-
"LumiNude01a":
|
| 97 |
-
"MEXX_QWEN_TG300":
|
| 98 |
-
"Meta4":
|
| 99 |
-
"MysticXXX":
|
| 100 |
-
"Nsfw_Body_V10":
|
| 101 |
-
"Nsfw_Body_V14":
|
| 102 |
-
"OilySkin_V2":
|
| 103 |
-
"PillowHump_2509":
|
| 104 |
-
"PutItHere_V2":
|
| 105 |
-
"PutItHere_V01":
|
| 106 |
-
"Qwen4Play_v2":
|
| 107 |
-
"QwenHentai_v3":
|
| 108 |
-
"Qwen_Helm":
|
| 109 |
-
"Qwen_NSFW_Beta1":
|
| 110 |
-
"Qwen_NSFW_Beta2":
|
| 111 |
-
"Qwen_NSFW_Beta4":
|
| 112 |
-
"Qwen_NSFW_Beta5":
|
| 113 |
-
"Qwen_Real_Nud3s":
|
| 114 |
-
"Qwen_Real_PS":
|
| 115 |
-
"QwenSnofs_v1":
|
| 116 |
-
"QwenSnofs_v1_1":
|
| 117 |
-
"
|
| 118 |
-
"
|
| 119 |
-
"
|
| 120 |
-
"
|
| 121 |
-
"
|
| 122 |
-
"
|
| 123 |
-
"
|
| 124 |
-
"
|
| 125 |
-
"
|
| 126 |
-
"
|
| 127 |
-
"
|
| 128 |
-
"
|
| 129 |
-
"
|
| 130 |
-
"
|
| 131 |
-
"
|
| 132 |
-
"
|
| 133 |
-
"
|
| 134 |
-
"
|
| 135 |
-
"
|
| 136 |
-
"
|
| 137 |
-
"
|
| 138 |
-
"
|
| 139 |
-
"
|
| 140 |
-
"
|
| 141 |
-
"
|
| 142 |
-
"
|
| 143 |
-
"
|
| 144 |
-
"
|
| 145 |
-
"
|
| 146 |
-
"
|
| 147 |
-
"
|
| 148 |
-
"
|
| 149 |
-
"
|
| 150 |
-
"
|
| 151 |
-
"
|
| 152 |
-
"
|
| 153 |
-
"
|
| 154 |
-
"
|
|
|
|
| 155 |
}
|
| 156 |
|
| 157 |
LORA_TRIGGER_WORDS = {
|
| 158 |
-
"Qwen4Play_v2":
|
| 159 |
-
"qwen_MCNL":
|
| 160 |
-
"remove_clothing":
|
| 161 |
-
"Qwen_Real_Nud3s":
|
| 162 |
-
"HearmemanAI_V4_Breasts":
|
| 163 |
-
"HearmemanAI_V3_Breasts":
|
| 164 |
-
"Ultimate_Breast_Nipples":
|
| 165 |
-
"ass_up_QWEN":
|
| 166 |
-
"PillowHump_2509":
|
| 167 |
-
"InniePussy":
|
| 168 |
-
"p0ssy_lora_v1":
|
| 169 |
-
"CockQwen_v3":
|
| 170 |
-
"p3nis":
|
| 171 |
-
"qwen_PENISLORA":
|
| 172 |
-
"Facial_Cumshots_V1":
|
| 173 |
-
"bfs_v2_head":
|
| 174 |
-
"bfs_v2_face":
|
| 175 |
-
"bfs_v2_focus_face":
|
| 176 |
-
"goblin_anal_v1":
|
| 177 |
-
"d33p7hroa7":
|
| 178 |
-
"QwenHentai_v3":
|
| 179 |
-
"Eva_Qwen_V3":
|
| 180 |
-
"JTT2_5":
|
| 181 |
-
"MEXX_QWEN_TG300":
|
| 182 |
-
"OilySkin_V2":
|
| 183 |
-
"barbell_nipples_QWEN":
|
| 184 |
-
"Qwen_Helm":
|
| 185 |
-
"MysticXXX":
|
| 186 |
-
"Qwen_NSFW_Beta1":
|
| 187 |
-
"Qwen_NSFW_Beta2":
|
| 188 |
-
"Qwen_NSFW_Beta4":
|
| 189 |
-
"Qwen_NSFW_Beta5":
|
| 190 |
-
"QwenSnofs_v1":
|
| 191 |
-
"QwenSnofs_v1_1":
|
| 192 |
-
"
|
| 193 |
-
"
|
| 194 |
-
"
|
| 195 |
-
"
|
| 196 |
-
"
|
| 197 |
-
"
|
| 198 |
-
"
|
| 199 |
-
"
|
| 200 |
-
"
|
| 201 |
-
"
|
| 202 |
-
"
|
| 203 |
-
"
|
| 204 |
-
"
|
| 205 |
-
"
|
| 206 |
-
"
|
| 207 |
-
"
|
| 208 |
-
"
|
|
|
|
| 209 |
}
|
| 210 |
|
| 211 |
# Tracks which adapter names have been successfully loaded into the pipeline.
|
|
@@ -246,11 +248,24 @@ def load_and_apply_stack(extra_adapters: list[str], extra_weights: list[float]):
|
|
| 246 |
if name not in LOADED_ADAPTERS:
|
| 247 |
try:
|
| 248 |
print(f"--- Loading adapter: {name} ---")
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
LOADED_ADAPTERS.add(name)
|
| 255 |
except Exception as e:
|
| 256 |
# If it already exists from a previous call in this Space session,
|
|
@@ -269,7 +284,6 @@ def load_and_apply_stack(extra_adapters: list[str], extra_weights: list[float]):
|
|
| 269 |
pipe.set_adapters(loaded, adapter_weights=weights_out)
|
| 270 |
else:
|
| 271 |
pipe.disable_lora()
|
| 272 |
-
|
| 273 |
return loaded, weights_out
|
| 274 |
|
| 275 |
|
|
@@ -316,7 +330,7 @@ def infer(
|
|
| 316 |
|
| 317 |
# ── Validate aspect ratio ────────────────────────────────────────────────
|
| 318 |
# Extreme ratios (>4:1) produce degenerate latent shapes that crash the
|
| 319 |
-
# transformer or produce garbage.
|
| 320 |
image = input_image.convert("RGB")
|
| 321 |
w, h = image.size
|
| 322 |
ratio = max(w, h) / max(min(w, h), 1)
|
|
@@ -375,6 +389,7 @@ def infer(
|
|
| 375 |
torch.cuda.empty_cache()
|
| 376 |
# ─────────────────────────────────────────────────────────────────────
|
| 377 |
|
|
|
|
| 378 |
# ── UI ─────────────────────────────────────────────────────────────────────────
|
| 379 |
css = """
|
| 380 |
#col-container { margin: 0 auto; max-width: 980px; }
|
|
@@ -404,6 +419,7 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
|
| 404 |
"**Fast local LoRA-powered image editing** powered by `Qwen-Image-Edit-2509` + `Qwen-Image-Edit-Rapid-AIO-V4` + 50+ community LoRAs.<br>"
|
| 405 |
"Upload an image, describe the edit, optionally stack LoRAs, and hit **Edit Image**."
|
| 406 |
)
|
|
|
|
| 407 |
with gr.Accordion("💡 Quick Tips", open=False):
|
| 408 |
gr.Markdown(
|
| 409 |
"- **LoRAs auto-add trigger words** to your prompt when selected.<br>"
|
|
@@ -442,6 +458,7 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
|
| 442 |
with gr.Row():
|
| 443 |
gr.Markdown("**Stack up to 6 LoRAs.** Select a LoRA to auto-fill trigger words in the prompt.")
|
| 444 |
clear_btn = gr.Button("🧹 Clear All", size="sm", variant="secondary", scale=0)
|
|
|
|
| 445 |
lora_stack = []
|
| 446 |
for i in range(6):
|
| 447 |
with gr.Row():
|
|
@@ -503,7 +520,6 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
|
| 503 |
inputs=[output_image],
|
| 504 |
outputs=[input_image],
|
| 505 |
)
|
| 506 |
-
|
| 507 |
clear_output_btn.click(
|
| 508 |
fn=lambda: gr.update(value=None),
|
| 509 |
inputs=None,
|
|
@@ -513,4 +529,4 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
|
|
| 513 |
if __name__ == "__main__":
|
| 514 |
demo.queue(max_size=30).launch(
|
| 515 |
mcp_server=True, ssr_mode=False, show_error=True
|
| 516 |
-
)
|
|
|
|
| 52 |
|
| 53 |
# ── Device / dtype ─────────────────────────────────────────────────────────────
|
| 54 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 55 |
+
dtype = torch.bfloat16
|
|
|
|
| 56 |
print("CUDA available:", torch.cuda.is_available())
|
| 57 |
print("Using device:", device)
|
| 58 |
|
|
|
|
| 74 |
# ── OOM FIX: Enable VAE tiling and slicing to bound VRAM usage ─────────────────
|
| 75 |
pipe.vae.enable_tiling(tile_sample_min_width=256, tile_sample_min_height=256)
|
| 76 |
pipe.vae.enable_slicing()
|
|
|
|
| 77 |
|
| 78 |
+
# ───────────────────────────────────────────────────────────────────────────────
|
| 79 |
try:
|
| 80 |
pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
|
| 81 |
print("Flash Attention 3 Processor set successfully.")
|
|
|
|
| 84 |
|
| 85 |
# ── LoRA catalog ──────────────────────────────────────────────────────────
|
| 86 |
LORA_REPO = "wiikoo/Qwen-lora-nsfw"
|
| 87 |
+
|
| 88 |
LORA_CONFIGS = {
|
| 89 |
+
"CockQwen_v3": "loras/CockQwen-v3.safetensors",
|
| 90 |
+
"Eva_Qwen_V3": "loras/Eva_Qwen_V3.safetensors",
|
| 91 |
+
"Facial_Cumshots_V1": "loras/Facial_Cumshots_For_Qwen_Image_V1.safetensors",
|
| 92 |
+
"HearmemanAI_V3_Breasts": "loras/HearmemanAI_V3_Rank64_BreastsLoRA_Epoch60.safetensors",
|
| 93 |
+
"HearmemanAI_V4_Breasts": "loras/HearmemanAI_V4_Rank128_BreastsLoRA_Epoch80.safetensors",
|
| 94 |
+
"InniePussy": "loras/InniePussy.safetensors",
|
| 95 |
+
"JTT2_5": "loras/[QWEN] JTT2_5.safetensors",
|
| 96 |
+
"LumiNude01a": "loras/LumiNude01a_CE_QWEN_AIT3k.safetensors",
|
| 97 |
+
"MEXX_QWEN_TG300": "loras/MEXX_QWEN_TG300_23.safetensors",
|
| 98 |
+
"Meta4": "loras/Meta4.safetensors",
|
| 99 |
+
"MysticXXX": "loras/Qwen-MysticXXX-v1.safetensors",
|
| 100 |
+
"Nsfw_Body_V10": "loras/Qwen_Nsfw_Body_V10-4K.safetensors",
|
| 101 |
+
"Nsfw_Body_V14": "loras/Qwen_Nsfw_Body_V14-10K.safetensors",
|
| 102 |
+
"OilySkin_V2": "loras/Oily Skin QWEN V2-GMR.safetensors",
|
| 103 |
+
"PillowHump_2509": "loras/PillowHump_2509.safetensors",
|
| 104 |
+
"PutItHere_V2": "loras/Put it here_Qwen edit_V2.0.safetensors",
|
| 105 |
+
"PutItHere_V01": "loras/put it here_QwenEdit_V0.1.safetensors",
|
| 106 |
+
"Qwen4Play_v2": "loras/Qwen4Play_v2.safetensors",
|
| 107 |
+
"QwenHentai_v3": "loras/QwenImageHentaiPIV_v3.1.safetensors",
|
| 108 |
+
"Qwen_Helm": "loras/Qwen-Image-Helm_v0.1.safetensors",
|
| 109 |
+
"Qwen_NSFW_Beta1": "loras/Qwen-NSFW.safetensors",
|
| 110 |
+
"Qwen_NSFW_Beta2": "loras/Qwen-NSFW-Beta2.safetensors",
|
| 111 |
+
"Qwen_NSFW_Beta4": "loras/Qwen-NSFW-Beta4.safetensors",
|
| 112 |
+
"Qwen_NSFW_Beta5": "loras/Qwen-NSFW-Beta5.safetensors",
|
| 113 |
+
"Qwen_Real_Nud3s": "loras/Qwen_Real_Nud3s.safetensors",
|
| 114 |
+
"Qwen_Real_PS": "loras/Qwen-Real PS_v1_83K.safetensors",
|
| 115 |
+
"QwenSnofs_v1": "loras/qwen_snofs.safetensors",
|
| 116 |
+
"QwenSnofs_v1_1": "loras/QwenSnofs1_1.safetensors",
|
| 117 |
+
"QwenSnofs_1.3": ("Cassanovason69/Qwensnofs", "Qwen_Snofs_1_3.safetensors"), # ← from other repo
|
| 118 |
+
"Real_Breast_Nipples": "loras/Real Breast Nipples-QWEN-[rbn]-GMR.safetensors",
|
| 119 |
+
"SendDudes": "loras/[QWEN] SendDudes.safetensors",
|
| 120 |
+
"SendNudesLite": "loras/SendNudesLite (Qwen).safetensors",
|
| 121 |
+
"SendNudesPro_Beta": "loras/[QWEN] Send Nudes Pro - Beta v1.safetensors",
|
| 122 |
+
"Ultimate_Breast_Nipples": "loras/Ultimate Realistic Breast NIPPLES-QWEN-[rab]-GMR.safetensors",
|
| 123 |
+
"ass_up_QWEN": "loras/ass_up_QWEN.safetensors",
|
| 124 |
+
"barbell_nipples_QWEN": "loras/QWEN_jtn_barbell.safetensors",
|
| 125 |
+
"bfs_v2_face": "loras-sfw/face_swap_5500_qwen_image_edit_2509_v1.safetensors",
|
| 126 |
+
"bfs_v2_focus_face": "loras-sfw/bfs_v2_000005000.safetensors",
|
| 127 |
+
"bfs_v2_head": "loras-sfw/bfs_v2_head_000007000.safetensors",
|
| 128 |
+
"big_nipples_QWEN": "loras/big_nipples_QWEN.safetensors",
|
| 129 |
+
"bumpynipples": "loras/bumpynipples1.safetensors",
|
| 130 |
+
"cmslt_cum_on_her": "loras/cmslt_2509_2.safetensors",
|
| 131 |
+
"consistence_edit_v1": "loras-2/consistence_edit_v1.safetensors",
|
| 132 |
+
"consistence_edit_v2": "loras2/consistence_edit_v2.safetensors",
|
| 133 |
+
"d33p7hroa7": "loras/d33p7hroa7_qwen.safetensors",
|
| 134 |
+
"d1ck_p3n1s_V1_1": "loras/qwen-image_d!ck_P3N1S_LoRA_V1.1.safetensors",
|
| 135 |
+
"goblin_anal_v1": "loras/goblin_anal_v1_qwen.safetensors",
|
| 136 |
+
"horseshoe_nipple_rings": "loras/horseshoe_nipple_rings_QWEN.safetensors",
|
| 137 |
+
"jib_nudity_fixer": "loras/jib_qwen_fix_000002750.safetensors",
|
| 138 |
+
"jillin": "loras/jillin1.safetensors",
|
| 139 |
+
"male_nude": "loras/lora_nudenan_v1.safetensors",
|
| 140 |
+
"milk_juggs": "loras/milk_juggs_QWEN.safetensors",
|
| 141 |
+
"n00d_b": "loras/n00d-b-qwen.safetensors",
|
| 142 |
+
"nsfw_adv_v1": "loras/qwen-image_nsfw_adv_v1.0.safetensors",
|
| 143 |
+
"p0ssy_lora_v1": "loras/p0ssy_lora_v1.safetensors",
|
| 144 |
+
"p3nis": "loras/p3nis.safetensors",
|
| 145 |
+
"qwen_MCNL": "loras/qwen_MCNL_v1.0.safetensors",
|
| 146 |
+
"qwen_PENISLORA": "loras/qwen-PENISLORA.safetensors",
|
| 147 |
+
"qwen_hand_grab": "loras/qwen_hand_grab_6000s.safetensors",
|
| 148 |
+
"qwen_uncensor": "loras/qwen_uncensor_000014928.safetensors",
|
| 149 |
+
"reclining_nude": "loras/reclining_nude_v1_000003500.safetensors",
|
| 150 |
+
"remove_clothing": "loras/qwen_image_edit_remove-clothing_v1.0.safetensors",
|
| 151 |
+
"royal_treatment_V3": "loras/royal+treatment+V3.safetensors",
|
| 152 |
+
"sabi_character": "loras-2/sabi_character_v1.safetensors",
|
| 153 |
+
"snapchat_selfie": "loras/qwen_image_snapchat.safetensors",
|
| 154 |
+
"uka_qwen": "loras/uka_1_qwen.safetensors",
|
| 155 |
+
"ultimate_realistic_breast": "loras/ultimate realistic breast.safetensors",
|
| 156 |
}
|
| 157 |
|
| 158 |
LORA_TRIGGER_WORDS = {
|
| 159 |
+
"Qwen4Play_v2": "d0gg13, c0wg1rl, r3v3rs3_c0wg1rl, m15510n4ry, bl0wj0b, penis",
|
| 160 |
+
"qwen_MCNL": "nsfw, cum_on_face, blowjob, cowgirlout, creamp1e, penis, l1ck, missionary, nipples, reversecowgirlpov, vagina",
|
| 161 |
+
"remove_clothing": "remove her clothing",
|
| 162 |
+
"Qwen_Real_Nud3s": "nud3",
|
| 163 |
+
"HearmemanAI_V4_Breasts": "large breasts, hard nipples, erect nipples",
|
| 164 |
+
"HearmemanAI_V3_Breasts": "large breasts, hard nipples, erect nipples",
|
| 165 |
+
"Ultimate_Breast_Nipples": "rab",
|
| 166 |
+
"ass_up_QWEN": "ass up showing pussy and anus",
|
| 167 |
+
"PillowHump_2509": "Pillow, Humping",
|
| 168 |
+
"InniePussy": "Innie pussy, Clean shaven, Vertical slit",
|
| 169 |
+
"p0ssy_lora_v1": "Nude",
|
| 170 |
+
"CockQwen_v3": "Erect Penis",
|
| 171 |
+
"p3nis": "holding a p3nis",
|
| 172 |
+
"qwen_PENISLORA": "PENISLORA",
|
| 173 |
+
"Facial_Cumshots_V1": "cum",
|
| 174 |
+
"bfs_v2_head": "head swap, transfer head from image 1 to image 2",
|
| 175 |
+
"bfs_v2_face": "keep the face consistent, preserve facial identity",
|
| 176 |
+
"bfs_v2_focus_face": "head swap from Image 1 to Image 2",
|
| 177 |
+
"goblin_anal_v1": "anal penetration, spread ass",
|
| 178 |
+
"d33p7hroa7": "deepthroat, penis deep in mouth",
|
| 179 |
+
"QwenHentai_v3": "nsfw, anime style, explicit",
|
| 180 |
+
"Eva_Qwen_V3": "Eva_gothic, in a kneeling position",
|
| 181 |
+
"JTT2_5": "massive breasts, large breasts, medium breasts, small breasts",
|
| 182 |
+
"MEXX_QWEN_TG300": "nsfw, female body",
|
| 183 |
+
"OilySkin_V2": "oilski",
|
| 184 |
+
"barbell_nipples_QWEN": "barbell nipple piercings",
|
| 185 |
+
"Qwen_Helm": "nsfw, anime style",
|
| 186 |
+
"MysticXXX": "nsfw",
|
| 187 |
+
"Qwen_NSFW_Beta1": "nsfw",
|
| 188 |
+
"Qwen_NSFW_Beta2": "nsfw",
|
| 189 |
+
"Qwen_NSFW_Beta4": "nsfw",
|
| 190 |
+
"Qwen_NSFW_Beta5": "nsfw",
|
| 191 |
+
"QwenSnofs_v1": "sex, missionary, cum, cowgirl, reverse cowgirl, selfie, snapchat selfie, prone position, spooning position, undressing",
|
| 192 |
+
"QwenSnofs_v1_1": "nsfw, nude, sex, blowjob, cum, selfie",
|
| 193 |
+
"QwenSnofs_1.3": "nsfw, nude, sex, blowjob, cum, selfie", # same style as previous versions
|
| 194 |
+
"Nsfw_Body_V10": "Hourglass figure, Hairless pussy, Hairly pussy",
|
| 195 |
+
"Nsfw_Body_V14": "SSS Waistline, Hairless pussy, Hairly pussy",
|
| 196 |
+
"SendNudesLite": "nude",
|
| 197 |
+
"SendNudesPro_Beta": "flat chest, small breasts, medium breasts, large breasts, massive breasts, big nipples",
|
| 198 |
+
"SendDudes": "Penis",
|
| 199 |
+
"cmslt_cum_on_her": "Put cum on her",
|
| 200 |
+
"horseshoe_nipple_rings": "horseshoe-ring nipple piercings, circular-barbell nipple piercings",
|
| 201 |
+
"jib_nudity_fixer": "nude, nipples, vagina",
|
| 202 |
+
"jillin": "masturbating",
|
| 203 |
+
"male_nude": "nudeman",
|
| 204 |
+
"n00d_b": "nude, art photography",
|
| 205 |
+
"nsfw_adv_v1": "nsfw",
|
| 206 |
+
"d1ck_p3n1s_V1_1": "P3N1S, penis",
|
| 207 |
+
"qwen_uncensor": "nsfw, cum_on_face, blowjob, cowgirlout, creamp1e, penis, l1ck, missionary, nipples, reversecowgirlpov, vagina",
|
| 208 |
+
"royal_treatment_V3": "lick ass, blowjob",
|
| 209 |
+
"snapchat_selfie": "selfie, snapchat",
|
| 210 |
+
"ultimate_realistic_breast": "urb, realistic breast",
|
| 211 |
}
|
| 212 |
|
| 213 |
# Tracks which adapter names have been successfully loaded into the pipeline.
|
|
|
|
| 248 |
if name not in LOADED_ADAPTERS:
|
| 249 |
try:
|
| 250 |
print(f"--- Loading adapter: {name} ---")
|
| 251 |
+
cfg = LORA_CONFIGS[name]
|
| 252 |
+
|
| 253 |
+
if isinstance(cfg, tuple):
|
| 254 |
+
# LoRA from a different Hugging Face repo
|
| 255 |
+
repo_id, weight_name = cfg
|
| 256 |
+
pipe.load_lora_weights(
|
| 257 |
+
repo_id,
|
| 258 |
+
weight_name=weight_name,
|
| 259 |
+
adapter_name=name,
|
| 260 |
+
)
|
| 261 |
+
else:
|
| 262 |
+
# Normal LoRA from the main LORA_REPO
|
| 263 |
+
pipe.load_lora_weights(
|
| 264 |
+
LORA_REPO,
|
| 265 |
+
weight_name=cfg,
|
| 266 |
+
adapter_name=name,
|
| 267 |
+
)
|
| 268 |
+
|
| 269 |
LOADED_ADAPTERS.add(name)
|
| 270 |
except Exception as e:
|
| 271 |
# If it already exists from a previous call in this Space session,
|
|
|
|
| 284 |
pipe.set_adapters(loaded, adapter_weights=weights_out)
|
| 285 |
else:
|
| 286 |
pipe.disable_lora()
|
|
|
|
| 287 |
return loaded, weights_out
|
| 288 |
|
| 289 |
|
|
|
|
| 330 |
|
| 331 |
# ── Validate aspect ratio ────────────────────────────────────────────────
|
| 332 |
# Extreme ratios (>4:1) produce degenerate latent shapes that crash the
|
| 333 |
+
# transformer or produce garbage. Reject early with a clear message.
|
| 334 |
image = input_image.convert("RGB")
|
| 335 |
w, h = image.size
|
| 336 |
ratio = max(w, h) / max(min(w, h), 1)
|
|
|
|
| 389 |
torch.cuda.empty_cache()
|
| 390 |
# ─────────────────────────────────────────────────────────────────────
|
| 391 |
|
| 392 |
+
|
| 393 |
# ── UI ─────────────────────────────────────────────────────────────────────────
|
| 394 |
css = """
|
| 395 |
#col-container { margin: 0 auto; max-width: 980px; }
|
|
|
|
| 419 |
"**Fast local LoRA-powered image editing** powered by `Qwen-Image-Edit-2509` + `Qwen-Image-Edit-Rapid-AIO-V4` + 50+ community LoRAs.<br>"
|
| 420 |
"Upload an image, describe the edit, optionally stack LoRAs, and hit **Edit Image**."
|
| 421 |
)
|
| 422 |
+
|
| 423 |
with gr.Accordion("💡 Quick Tips", open=False):
|
| 424 |
gr.Markdown(
|
| 425 |
"- **LoRAs auto-add trigger words** to your prompt when selected.<br>"
|
|
|
|
| 458 |
with gr.Row():
|
| 459 |
gr.Markdown("**Stack up to 6 LoRAs.** Select a LoRA to auto-fill trigger words in the prompt.")
|
| 460 |
clear_btn = gr.Button("🧹 Clear All", size="sm", variant="secondary", scale=0)
|
| 461 |
+
|
| 462 |
lora_stack = []
|
| 463 |
for i in range(6):
|
| 464 |
with gr.Row():
|
|
|
|
| 520 |
inputs=[output_image],
|
| 521 |
outputs=[input_image],
|
| 522 |
)
|
|
|
|
| 523 |
clear_output_btn.click(
|
| 524 |
fn=lambda: gr.update(value=None),
|
| 525 |
inputs=None,
|
|
|
|
| 529 |
if __name__ == "__main__":
|
| 530 |
demo.queue(max_size=30).launch(
|
| 531 |
mcp_server=True, ssr_mode=False, show_error=True
|
| 532 |
+
)
|