A1111 / app.py
Leteint's picture
Update app.py
5dbac4e verified
import spaces
import json
import os
import torch
import gradio as gr
from diffusers import AutoPipelineForText2Image
from PIL import PngImagePlugin
# -----------------------
# Config modèles
# -----------------------
BASE_MODEL_ID = "stabilityai/stable-diffusion-xl-base-1.0"
# LoRA "wrong" (améliore qualité + adhérence prompt)
LORA_WRONG_REPO = "minimaxir/sdxl-wrong-lora" # [web:183]
LORA_WRONG_ADAPTER = "wrong_prompt"
# LoRA visages / détails
LORA_FACE_REPO = "akash-guptag/Detailers_By_Stable_Yogi"
LORA_FACE_ADAPTER = "face_detail"
LORA_SEXY_REPO = "ntc-ai/SDXL-LoRA-slider.sexy"
LORA_SEXY_ADAPTER ="sexy"
LORA_DETAILLED_REPO = "ntc-ai/SDXL-LoRA-slider.extremely-detailed"
LORA_DETAILLED_ADAPTER = "extremely detailed"
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32
# -----------------------
# Chargement pipeline
# -----------------------
print("Chargement SDXL...")
pipe = AutoPipelineForText2Image.from_pretrained(
BASE_MODEL_ID,
torch_dtype=DTYPE,
variant="fp16" if DTYPE == torch.float16 else None,
safety_checker=None, # on désactive officiellement
requires_safety_checker=False,
)
pipe.to(DEVICE)
# Monkey-patch du safety checker (NSFW fully bypass)
def dummy_safety_checker(images, **kwargs):
# renvoie toujours "tout va bien"
return images, [False] * len(images)
pipe.safety_checker = dummy_safety_checker
pipe.set_progress_bar_config(disable=True)
print("Chargement LoRA WRONG (prompt/qualité)...")
pipe.load_lora_weights(LORA_WRONG_REPO, adapter_name=LORA_WRONG_ADAPTER)
print("Chargement LoRA face/detail (Stable Yogi)...")
pipe.load_lora_weights(LORA_FACE_REPO, adapter_name=LORA_FACE_ADAPTER)
pipe.load_lora_weights(LORA_SEXY_REPO, adapter_name=LORA_SEXY_ADAPTER)
pipe.load_lora_weights(LORA_DETAILLED_REPO, adapter_name=LORA_DETAILLED_ADAPTER)
os.makedirs("outputs", exist_ok=True)
# -----------------------
# Fonction de génération
# -----------------------
@spaces.GPU()
def generate(
prompt: str,
negative: str,
seed_in,
steps: float,
guidance: float,
width: float,
height: float,
face_weight: float,
script_name: str,
):
# Seed robuste (Gradio envoie parfois int, parfois str)
try:
if isinstance(seed_in, str):
seed_in = seed_in.strip()
seed = int(float(seed_in)) if seed_in != "" else -1
elif seed_in is None:
seed = -1
else:
seed = int(seed_in)
except Exception:
seed = -1
if seed >= 0:
generator = torch.Generator(device=DEVICE).manual_seed(seed)
else:
generator = torch.Generator(device=DEVICE)
# Prompt principal (on enrobe pour aider SDXL)
final_prompt = (
"masterpiece, best quality, extremely detailed, dynamic pose,cinematic "
+ (prompt or "1girl, caucasian, medium breasts, dressed like a princess,medium breasts, detailed face, realistic skin")
+ ", sharp focus"
)
# Negative : "wrong" est la clé pour sdxl-wrong-lora
if negative and negative.strip():
final_negative = "wrong, " + negative.strip()
else:
final_negative = "wrong, blurry, low quality, deformed, bad anatomy, extra limbs"
# On combine les deux LoRA : WRONG à 1.0, face en slider
adapters = [LORA_WRONG_ADAPTER, LORA_FACE_ADAPTER, LORA_SEXY_ADAPTER, LORA_DETAILLED_ADAPTER]
weights = [1.0, float(face_weight), 1.5, 2.0]
pipe.set_adapters(adapters, adapter_weights=weights)
try:
result = pipe(
prompt=final_prompt,
negative_prompt=final_negative,
num_inference_steps=int(steps),
guidance_scale=float(guidance),
width=int(width),
height=int(height),
generator=generator,
)
except Exception as e:
return None, f"Erreur pendant la génération : {repr(e)}", ""
image = result.images[0]
metadata = {
"base_model": BASE_MODEL_ID,
"prompt_raw": prompt,
"prompt_final": final_prompt,
"negative_raw": negative,
"negative_final": final_negative,
"seed": seed,
"steps": int(steps),
"guidance": float(guidance),
"width": int(width),
"height": int(height),
"lora_wrong_repo": LORA_WRONG_REPO,
"lora_wrong_adapter": LORA_WRONG_ADAPTER,
"lora_wrong_weight": 1.0,
"lora_face_repo": LORA_FACE_REPO,
"lora_face_adapter": LORA_FACE_ADAPTER,
"lora_face_weight": float(face_weight),
}
base_name = script_name.strip().replace(" ", "_") if script_name else "sdxl_wrong_lora"
img_path = os.path.join("outputs", f"{base_name}.png")
json_path = os.path.join("outputs", f"{base_name}.json")
pnginfo = PngImagePlugin.PngInfo()
pnginfo.add_text("generation_params", json.dumps(metadata, ensure_ascii=False))
image.save(img_path, pnginfo=pnginfo)
with open(json_path, "w", encoding="utf-8") as f:
json.dump(metadata, f, ensure_ascii=False, indent=2)
script_txt = json.dumps(metadata, ensure_ascii=False, indent=2)
return image, script_txt, json_path
# -----------------------
# UI Gradio
# -----------------------
with gr.Blocks(title="SDXL + WRONG LoRA + Face Detail") as demo:
gr.Markdown(
"## SDXL 1.0 + LoRA **WRONG** (meilleure compréhension) + LoRA détail visage \n"
"- Utilise le LoRA `sdxl-wrong-lora` pour améliorer qualité et adhérence au prompt.[web:183][web:194]\n"
"- Utilise `Detailers_By_Stable_Yogi` pour les visages/détails.[web:60][web:63]\n"
"- NSFW débloqué (safety checker bypassé)."
)
with gr.Row():
with gr.Column():
prompt = gr.Textbox(
label="Prompt",
placeholder="1girl nude, red dress, on the beach at sunset, cinematic lighting, smiling at viewer",
value=None,
lines=4,
)
negative = gr.Textbox(
label="Negative prompt (\"wrong\" sera ajouté automatiquement)",
placeholder="blurry, deformed, ugly, extra limbs, bad anatomy",
value=None,
lines=3,
)
seed = gr.Number(
label="Seed (-1 = random)",
value=-1,
)
steps = gr.Slider(
minimum=20,
maximum=60,
value=40,
step=1,
label="Steps (plus haut = meilleure adhérence)",
)
guidance = gr.Slider(
minimum=5.0,
maximum=15.0,
value=9.0,
step=0.5,
label="CFG / Guidance scale",
)
width = gr.Slider(
minimum=512,
maximum=1536,
value=1024,
step=64,
label="Width (SDXL natif 1024)",
)
height = gr.Slider(
minimum=512,
maximum=1536,
value=1024,
step=64,
label="Height (SDXL natif 1024)",
)
face_weight = gr.Slider(
minimum=0.0,
maximum=1.2,
value=0.7,
step=0.05,
label="Force LoRA face/detail (Stable Yogi)",
)
script_name = gr.Textbox(
label="Nom base pour l'image / script",
value="sdxl_wrong_example",
)
run_btn = gr.Button("🚀 Générer", variant="primary")
with gr.Column():
out_img = gr.Image(
label="Image générée (SDXL + WRONG + Face)",
)
out_script = gr.Textbox(
label="Metadata / Script JSON",
lines=20,
)
out_file = gr.File(
label="Fichier JSON des paramètres (téléchargeable)",
)
run_btn.click(
fn=generate,
inputs=[
prompt,
negative,
seed,
steps,
guidance,
width,
height,
face_weight,
script_name,
],
outputs=[out_img, out_script, out_file],
)
if __name__ == "__main__":
demo.launch()