File size: 5,080 Bytes
069396c
 
6cd8c22
 
 
 
 
 
0dfe3cb
 
 
 
 
b7cde37
 
 
0dfe3cb
b7cde37
0dfe3cb
 
 
 
 
 
 
 
 
 
b7cde37
 
0dfe3cb
 
 
 
 
 
6cd8c22
 
 
 
 
 
 
0dfe3cb
 
 
 
 
 
 
6cd8c22
0dfe3cb
 
 
 
 
 
 
 
 
 
 
 
 
 
069396c
0dfe3cb
069396c
 
 
0dfe3cb
 
069396c
564f386
069396c
 
0dfe3cb
069396c
0dfe3cb
 
 
 
 
6cd8c22
0dfe3cb
069396c
0dfe3cb
 
 
 
 
069396c
0dfe3cb
 
 
 
6cd8c22
 
0dfe3cb
6cd8c22
069396c
 
0dfe3cb
 
 
 
 
 
 
 
 
 
 
6cd8c22
 
 
 
 
 
0dfe3cb
 
 
 
 
 
 
069396c
 
0dfe3cb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import gradio as gr
import torch
from diffusers import (
    StableDiffusionXLPipeline,
    EulerDiscreteScheduler,
    AutoencoderKL,
    DPMSolverSinglestepScheduler,
)

# --- Configuration ---
# The base model your LoRA was trained on.
base_model_id = "stabilityai/stable-diffusion-xl-base-1.0"

# --- The file is local, so we just need its name ---
# The safetensors file is in the same directory as this script.
lora_file_path = "emilyh.safetensors"

# --- Load the Pipeline ---
# Use a recommended VAE for SDXL
vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16)
pipe = StableDiffusionXLPipeline.from_pretrained(
    base_model_id,
    vae=vae,
    torch_dtype=torch.float16,
    variant="fp16",
    use_safetensors=True
)

# --- Load the local LoRA file ---
# No download needed. We just load the local file directly.
pipe.load_lora_weights(lora_file_path)

# Move the pipeline to the GPU
pipe.to("cuda")

# --- Default Settings from your Recommendations ---
default_positive_prompt = "masterpiece, best quality, ultra-detailed, realistic skin, intricate details, highres"
default_negative_prompt = "low quality, worst quality, blurry, (deformed:1.3), extra fingers, cartoon, 3d, anime, bad anatomy"
default_sampler = "DPM++ 2M Karras"
default_cfg = 6.0
default_steps = 30
trigger_word = "emilyh"
lora_tag_main = "<lora:emilyh:0.9>"


# --- Define the Inference Function ---
def generate_image(prompt, negative_prompt, sampler, steps, cfg, width, height, seed):
    """
    Function to generate an image based on user inputs.
    """
    # Combine the user prompt with the trigger word and LoRA tag
    full_prompt = f"{lora_tag_main}, {trigger_word}, {prompt}"

    # Set the scheduler (sampler)
    if sampler == "DPM++ 2M Karras":
        pipe.scheduler = EulerDiscreteScheduler.from_config(pipe.scheduler.config, use_karras_sigmas=True)
    elif sampler == "DPM++ SDE Karras":
        pipe.scheduler = DPMSolverSinglestepScheduler.from_config(pipe.scheduler.config, use_karras_sigmas=True, algorithm_type="sde-dpmsolver++")
    else: # Default to DPM++ 2M Karras
        pipe.scheduler = EulerDiscreteScheduler.from_config(pipe.scheduler.config, use_karras_sigmas=True)

    # Set seed for reproducibility
    generator = torch.Generator("cuda").manual_seed(seed) if seed != -1 else None

    # Generate the image
    image = pipe(
        prompt=full_prompt,
        negative_prompt=negative_prompt,
        width=width,
        height=height,
        guidance_scale=cfg,
        num_inference_steps=steps,
        generator=generator,
        cross_attention_kwargs={"scale": 0.9} 
    ).images[0]

    return image

# --- Create the Gradio Interface ---
with gr.Blocks(css="style.css") as demo:
    gr.Markdown("# `emilyh` LoRA Image Generator")
    gr.Markdown(
        "A Gradio interface for the `emilyh` LoRA. "
        "Based on the recommendations provided."
    )

    with gr.Row():
        with gr.Column():
            prompt = gr.Textbox(label="Positive Prompt", value=default_positive_prompt, lines=3)
            negative_prompt = gr.Textbox(label="Negative Prompt", value=default_negative_prompt, lines=3)
            
            with gr.Row():
                sampler = gr.Radio(
                    label="Sampler",
                    choices=["DPM++ 2M Karras", "DPM++ SDE Karras"],
                    value=default_sampler,
                )
                steps = gr.Slider(label="Steps", minimum=15, maximum=50, value=default_steps, step=1)
            
            cfg = gr.Slider(label="CFG Scale", minimum=1.0, maximum=10.0, value=default_cfg, step=0.5)

            with gr.Row():
                width = gr.Slider(label="Width", minimum=512, maximum=1024, value=1024, step=64)
                height = gr.Slider(label="Height", minimum=512, maximum=1024, value=1024, step=64)

            seed = gr.Slider(label="Seed", minimum=-1, maximum=999999999, step=1, value=-1, info="Use -1 for a random seed.")
            
            generate_button = gr.Button("Generate Image", variant="primary")

        with gr.Column():
            output_image = gr.Image(label="Generated Image", type="pil")
            gr.Markdown(
                """
                ### 🔧 Usage Guide
                * The trigger word `emilyh` and the LoRA tag `<lora:emilyh:0.9>` are automatically added to your prompt.
                * For best results, generate images in batches and choose the most consistent ones.
                * The LoRA captures the subject's appearance well across various poses and outfits.
                * A weight of 0.9 provides a good balance of likeness and flexibility. Using a weight closer to 1.0 can increase consistency but may cause stiffness.
                * This interface does not include ADetailer, which is recommended for final face refinement.
                """
            )

    generate_button.click(
        fn=generate_image,
        inputs=[prompt, negative_prompt, sampler, steps, cfg, width, height, seed],
        outputs=output_image
    )

demo.launch()