File size: 4,424 Bytes
da4c8ed
 
6194646
f7e0c92
e4b37f8
0e797f9
92d864d
da4c8ed
551486d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e4b37f8
7a8ae95
551486d
 
e4b37f8
 
551486d
 
 
 
 
 
 
 
 
 
 
 
da4c8ed
0e797f9
551486d
0e797f9
 
 
551486d
da4c8ed
551486d
da4c8ed
551486d
0e797f9
 
6194646
0e797f9
551486d
 
 
 
 
f9206e7
551486d
 
 
 
 
 
 
835d2fc
551486d
 
 
 
 
835d2fc
551486d
 
 
 
 
 
835d2fc
551486d
 
 
 
 
e4b37f8
f9206e7
551486d
 
 
 
e4b37f8
6194646
551486d
 
 
0e797f9
551486d
5abccf3
835d2fc
e4b37f8
551486d
 
 
835d2fc
551486d
92d864d
030736b
551486d
 
835d2fc
551486d
0e797f9
551486d
 
 
0e797f9
bdebad1
689a708
551486d
835d2fc
689a708
030736b
da4c8ed
0e797f9
551486d
 
f9206e7
e4b37f8
551486d
f9206e7
551486d
 
f9206e7
92d864d
 
242e2d2
0e797f9
457f72c
551486d
 
457f72c
551486d
0e797f9
835d2fc
 
da4c8ed
 
82e78bb
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
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
import gradio as gr
import torch
import random
import time
from transformers import AutoTokenizer, AutoModelForCausalLM
from diffusers import DiffusionPipeline, LCMScheduler
from PIL import Image, ImageFilter

# ===============================
# TEXT MODEL (PROMPT ENHANCER)
# ===============================
TEXT_MODEL_ID = "HuggingFaceTB/SmolLM-135M-Instruct"

tokenizer = AutoTokenizer.from_pretrained(TEXT_MODEL_ID)
text_model = AutoModelForCausalLM.from_pretrained(TEXT_MODEL_ID)

def enhance_prompt(user_prompt: str) -> str:
    instruction = (
        "Please enhance this prompt so it is suitable for an image generator "
        "that requires clear instructions. Analyse the prompt, and output as "
        "much visual detail as possible about it.\n\n"
        f"Prompt to enhance: {user_prompt}\n\n"
        "Enhanced prompt:"
    )

    inputs = tokenizer(instruction, return_tensors="pt")
    outputs = text_model.generate(
        **inputs,
        max_new_tokens=500,
        temperature=0.6,
        do_sample=True,
    )

    decoded = tokenizer.decode(outputs[0], skip_special_tokens=True)

    if "Enhanced prompt:" in decoded:
        decoded = decoded.split("Enhanced prompt:")[-1]

    return decoded.strip()

# ===============================
# IMAGE MODEL (CPU)
# ===============================
IMG_MODEL = "runwayml/stable-diffusion-v1-5"
LCM_LORA = "latent-consistency/lcm-lora-sdv1-5"

pipe = DiffusionPipeline.from_pretrained(
    IMG_MODEL,
    torch_dtype=torch.float32,
    safety_checker=None
)

pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
pipe.load_lora_weights(LCM_LORA)
pipe.to("cpu")

pipe.enable_attention_slicing()
pipe.enable_vae_slicing()
pipe.set_progress_bar_config(disable=True)

# ===============================
# TIME ESTIMATION
# ===============================
def estimate_time(steps, res):
    res = int(res)
    steps = int(steps)
    base = {512: 12, 768: 25, 1024: 45}[res]
    total = steps * base + 5
    return f"⏱️ Estimated: ~{total//60}m {total%60}s"

# ===============================
# GENERATION FUNCTION
# ===============================
def generate(prompt, negative, resolution, steps):
    size = int(resolution)

    # Placeholder while thinking
    yield (
        [Image.new("RGB", (size, size), "white")],
        "🧠 Enhancing prompt..."
    )

    enhanced = enhance_prompt(prompt)

    yield (
        [Image.new("RGB", (size, size), "white")],
        "🎨 Generating image..."
    )

    seed = random.randint(0, 1_000_000_000)
    generator = torch.Generator("cpu").manual_seed(seed)

    pipe.scheduler.set_timesteps(int(steps))

    start = time.time()
    image = pipe(
        prompt=enhanced,
        negative_prompt=negative,
        num_inference_steps=int(steps),
        guidance_scale=1.2,
        width=size,
        height=size,
        generator=generator
    ).images[0]
    elapsed = int(time.time() - start)

    # Blur reveal
    for i in range(10):
        blur = image.filter(ImageFilter.GaussianBlur(radius=(10 - i)))
        yield (
            [blur],
            f"👀 Revealing... ({i+1}/10)"
        )
        time.sleep(1)

    yield (
        [image],
        f"✅ Done in {elapsed}s | Seed {seed}"
    )

# ===============================
# UI
# ===============================
with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown("# 👾 Creeper AI Image - CPU")
    gr.Markdown(
        "1️⃣ The higher the resolution & steps, the longer the image takes.\n\n"
        "2️⃣ The more detailed the prompt and negative prompt, the better the result."
    )

    with gr.Row():
        with gr.Column():
            prompt = gr.Textbox(label="Prompt")
            negative = gr.Textbox(label="Negative Prompt")

            resolution = gr.Radio([512, 768, 1024], value=512, label="Resolution")
            steps = gr.Slider(6, 8, value=6, step=1, label="Steps")

            eta = gr.Markdown("⏱️ Estimated: ~1m")
            generate_btn = gr.Button("Generate")

            status = gr.Markdown("🟢 Ready")

        with gr.Column():
            gallery = gr.Gallery(columns=1)

    resolution.change(estimate_time, [steps, resolution], eta)
    steps.change(estimate_time, [steps, resolution], eta)

    generate_btn.click(
        generate,
        inputs=[prompt, negative, resolution, steps],
        outputs=[gallery, status]
    )

demo.launch(share=False)