| import spaces |
| import json |
| import os |
| import torch |
| import gradio as gr |
|
|
| from diffusers import AutoPipelineForText2Image |
| from PIL import PngImagePlugin |
|
|
| |
| |
| |
| BASE_MODEL_ID = "stabilityai/stable-diffusion-xl-base-1.0" |
|
|
| |
| LORA_WRONG_REPO = "minimaxir/sdxl-wrong-lora" |
| LORA_WRONG_ADAPTER = "wrong_prompt" |
|
|
| |
| 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 |
|
|
| |
| |
| |
| print("Chargement SDXL...") |
| pipe = AutoPipelineForText2Image.from_pretrained( |
| BASE_MODEL_ID, |
| torch_dtype=DTYPE, |
| variant="fp16" if DTYPE == torch.float16 else None, |
| safety_checker=None, |
| requires_safety_checker=False, |
| ) |
| pipe.to(DEVICE) |
|
|
| |
| def dummy_safety_checker(images, **kwargs): |
| |
| 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) |
|
|
|
|
| |
| |
| |
| @spaces.GPU() |
| def generate( |
| prompt: str, |
| negative: str, |
| seed_in, |
| steps: float, |
| guidance: float, |
| width: float, |
| height: float, |
| face_weight: float, |
| script_name: 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) |
|
|
| |
| 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" |
| ) |
|
|
| |
| if negative and negative.strip(): |
| final_negative = "wrong, " + negative.strip() |
| else: |
| final_negative = "wrong, blurry, low quality, deformed, bad anatomy, extra limbs" |
|
|
| |
| 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 |
|
|
|
|
| |
| |
| |
| 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() |
|
|