AI / app.py
hitoshifreak's picture
Update app.py
a0a57dd verified
import os
import gc
import gradio as gr
import numpy as np
import spaces
import torch
import random
from PIL import Image
from typing import Iterable
from gradio.themes import Soft
from gradio.themes.utils import colors, fonts, sizes
colors.orange_red = colors.Color(
name="orange_red",
c50="#FFF0E5",
c100="#FFE0CC",
c200="#FFC299",
c300="#FFA366",
c400="#FF8533",
c500="#FF4500",
c600="#E63E00",
c700="#CC3700",
c800="#B33000",
c900="#992900",
c950="#802200",
)
class OrangeRedTheme(Soft):
def __init__(
self,
*,
primary_hue: colors.Color | str = colors.gray,
secondary_hue: colors.Color | str = colors.orange_red,
neutral_hue: colors.Color | str = colors.slate,
text_size: sizes.Size | str = sizes.text_lg,
font: fonts.Font | str | Iterable[fonts.Font | str] = (
fonts.GoogleFont("Outfit"), "Arial", "sans-serif",
),
font_mono: fonts.Font | str | Iterable[fonts.Font | str] = (
fonts.GoogleFont("IBM Plex Mono"), "ui-monospace", "monospace",
),
):
super().__init__(
primary_hue=primary_hue,
secondary_hue=secondary_hue,
neutral_hue=neutral_hue,
text_size=text_size,
font=font,
font_mono=font_mono,
)
orange_red_theme = OrangeRedTheme()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
from diffusers import FlowMatchEulerDiscreteScheduler
from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
dtype = torch.bfloat16
pipe = QwenImageEditPlusPipeline.from_pretrained(
"Qwen/Qwen-Image-Edit-2511",
transformer=QwenImageTransformer2DModel.from_pretrained(
"prithivMLmods/Qwen-Image-Edit-Rapid-AIO-V19",
torch_dtype=dtype,
device_map="cuda"
),
torch_dtype=dtype
).to(device)
try:
pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
except Exception as e:
print(f"Warning: Could not set FA3 processor: {e}")
MAX_SEED = np.iinfo(np.int32).max
ADAPTER_SPECS = {
"Multiple-Angles": {
"repo": "dx8152/Qwen-Edit-2509-Multiple-angles",
"weights": "镜头转换.safetensors",
"adapter_name": "multiple-angles"
},
"Photo-to-Anime": {
"repo": "autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime",
"weights": "Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
"adapter_name": "photo-to-anime"
},
"Anime-V2": {
"repo": "prithivMLmods/Qwen-Image-Edit-2511-Anime",
"weights": "Qwen-Image-Edit-2511-Anime-2000.safetensors",
"adapter_name": "anime-v2"
},
"Light-Migration": {
"repo": "dx8152/Qwen-Edit-2509-Light-Migration",
"weights": "参考色调.safetensors",
"adapter_name": "light-migration"
},
"Upscaler": {
"repo": "starsfriday/Qwen-Image-Edit-2511-Upscale2K",
"weights": "qwen_image_edit_2511_upscale.safetensors",
"adapter_name": "upscale-2k"
},
"Style-Transfer": {
"repo": "zooeyy/Style-Transfer",
"weights": "Style Transfer-Alpha-V0.1.safetensors",
"adapter_name": "style-transfer"
},
"Manga-Tone": {
"repo": "nappa114514/Qwen-Image-Edit-2509-Manga-Tone",
"weights": "tone001.safetensors",
"adapter_name": "manga-tone"
},
"Anything2Real": {
"repo": "lrzjason/Anything2Real_2601",
"weights": "anything2real_2601.safetensors",
"adapter_name": "anything2real"
},
}
LOADED_ADAPTERS = set()
def update_dimensions_on_upload(image):
if image is None:
return 1024, 1024
original_width, original_height = image.size
if original_width > original_height:
new_width = 1024
new_height = int(new_width * (original_height / original_width))
else:
new_height = 1024
new_width = int(new_height * (original_width / original_height))
new_width = (new_width // 8) * 8
new_height = (new_height // 8) * 8
return new_width, new_height
@spaces.GPU
def infer(
images,
prompt,
seed,
randomize_seed,
guidance_scale,
steps,
progress=gr.Progress(track_tqdm=True)
):
gc.collect()
torch.cuda.empty_cache()
if not images:
raise gr.Error("Please upload an image.")
pil_images = []
for item in images:
try:
if isinstance(item, tuple) or isinstance(item, list):
path_or_img = item[0]
else:
path_or_img = item
if isinstance(path_or_img, str):
pil_images.append(Image.open(path_or_img).convert("RGB"))
elif isinstance(path_or_img, Image.Image):
pil_images.append(path_or_img.convert("RGB"))
else:
pil_images.append(Image.open(path_or_img.name).convert("RGB"))
except Exception:
continue
if not pil_images:
raise gr.Error("Could not process uploaded image.")
# LOCKED STYLE
spec = ADAPTER_SPECS["Anything2Real"]
adapter_name = spec["adapter_name"]
if adapter_name not in LOADED_ADAPTERS:
pipe.load_lora_weights(
spec["repo"],
weight_name=spec["weights"],
adapter_name=adapter_name
)
LOADED_ADAPTERS.add(adapter_name)
pipe.set_adapters([adapter_name], adapter_weights=[1.0])
if randomize_seed:
seed = random.randint(0, MAX_SEED)
generator = torch.Generator(device=device).manual_seed(seed)
width, height = update_dimensions_on_upload(pil_images[0])
result_image = pipe(
image=pil_images,
prompt=prompt,
negative_prompt="worst quality, blurry, watermark",
height=height,
width=width,
num_inference_steps=steps,
generator=generator,
true_cfg_scale=guidance_scale,
).images[0]
gc.collect()
torch.cuda.empty_cache()
return result_image, seed
css = """
#col-container {
margin: 0 auto;
max-width: 850px;
}
#main-title h1 {
font-size: 2.4em !important;
text-align: center;
}
"""
with gr.Blocks(theme=orange_red_theme, css=css) as demo:
with gr.Column(elem_id="col-container"):
gr.Markdown("# **Image Nsfw Editor**", elem_id="main-title")
gr.Markdown("Upload an image and transform it into NSFW.")
input_image = gr.Gallery(
label="Upload Image",
type="filepath",
columns=1,
rows=1,
height=350,
allow_preview=True
)
prompt = gr.Textbox(
label="Prompt",
placeholder="Describe the realistic transformation..."
)
run_button = gr.Button("Generate", variant="primary")
output_image = gr.Image(
label="Output",
interactive=False,
format="png",
height=500
)
# hidden backend essentials
seed = gr.State(0)
randomize_seed = gr.State(True)
guidance_scale = gr.State(1.0)
steps = gr.State(4)
run_button.click(
fn=infer,
inputs=[
input_image,
prompt,
seed,
randomize_seed,
guidance_scale,
steps
],
outputs=[output_image, seed]
)
if __name__ == "__main__":
demo.queue(max_size=30).launch(
mcp_server=True,
ssr_mode=False,
show_error=True
)