File size: 10,305 Bytes
4b3102d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
import os
import gradio as gr
import torch
import gdown
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
from PIL import Image


# --- Download from Google Drive ---
def download_from_gdrive(file_id, dest_path):
    if not os.path.exists(dest_path):
        print(f"πŸ“₯ Downloading {dest_path}...")
        gdown.download(f"https://drive.google.com/uc?id={file_id}", dest_path, quiet=False)
        print(f"βœ… Downloaded {dest_path} from Google Drive")
    else:
        print(f"βœ… {dest_path} already exists")


# Download base model and LoRA
print("πŸš€ Starting BitKun LoRA Generator...")
ckpt_id = "1OdP2SDB6MyR6JDK6_ekyqFHz91rkT2ZK"  # Your base model ID
download_from_gdrive(ckpt_id, "AnyLoRA_noVae_fp16-pruned.ckpt")

# βš™οΈ Configuration
project_name = "bitkun"
epoch_number = 10
lora_path = f"{project_name}-{epoch_number:02d}.safetensors"
base_model_path = "AnyLoRA_noVae_fp16-pruned.ckpt"
output_folder = "generated_images"
os.makedirs(output_folder, exist_ok=True)

# Auto-detect device and set appropriate dtype
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.float16 if device == "cuda" else torch.float32

print(f"πŸ”§ Using device: {device} with dtype: {dtype}")

# πŸš€ Load Base Model with optimizations
print("πŸ“¦ Loading base model...")
try:
    pipe = StableDiffusionPipeline.from_single_file(
        base_model_path,
        torch_dtype=dtype,
        safety_checker=None,
        requires_safety_checker=False,
        use_safetensors=True
    ).to(device)

    # ⏩ Use faster scheduler
    pipe.scheduler = DPMSolverMultistepScheduler.from_config(
        pipe.scheduler.config,
        use_karras_sigmas=True,
        algorithm_type="dpmsolver++"
    )

    # Enable memory efficient attention if available
    if hasattr(pipe, "enable_attention_slicing"):
        pipe.enable_attention_slicing()

    # Enable memory efficient attention
    if hasattr(pipe, "enable_xformers_memory_efficient_attention"):
        try:
            pipe.enable_xformers_memory_efficient_attention()
            print("βœ… XFormers memory efficient attention enabled")
        except:
            print("⚠️ XFormers not available, using standard attention")

    print("βœ… Base model loaded successfully!")

except Exception as e:
    print(f"❌ Error loading base model: {e}")
    raise e

# πŸ”„ Load LoRA
lora_loaded = False
try:
    if os.path.exists(lora_path):
        pipe.load_lora_weights(lora_path, adapter_name="default")
        pipe.set_adapters(["default"], adapter_weights=[0.8])
        lora_loaded = True
        print("βœ… LoRA loaded and pipeline ready!")
    else:
        print(f"⚠️ LoRA file not found: {lora_path}")
        print("Pipeline will run with base model only.")
except Exception as e:
    print(f"⚠️ Could not load LoRA weights: {e}")
    print("Pipeline will run with base model only.")


# 🎨 Optimized Generation Function
def generate_bitkun(prompt, negative_prompt, num_images, steps, guidance_scale, width, height):
    if not prompt.strip():
        return [], "⚠️ Please enter a prompt!"

    # Add bitkun to prompt if not present
    if "bitkun" not in prompt.lower():
        prompt = f"bitkun, {prompt}"

    seed = 42
    images = []

    for i in range(num_images):
        try:
            print(f"🎨 Generating image {i + 1}/{num_images}...")
            generator = torch.Generator(device=device).manual_seed(seed + i)

            # Use autocast only for CUDA
            if device == "cuda":
                with torch.autocast("cuda"):
                    result = pipe(
                        prompt=prompt,
                        negative_prompt=negative_prompt,
                        num_inference_steps=steps,
                        guidance_scale=guidance_scale,
                        width=width,
                        height=height,
                        generator=generator
                    )
            else:
                result = pipe(
                    prompt=prompt,
                    negative_prompt=negative_prompt,
                    num_inference_steps=steps,
                    guidance_scale=guidance_scale,
                    width=width,
                    height=height,
                    generator=generator
                )

            image = result.images[0]

            # Save image
            filename = f"{project_name}_custom_{i + 1}.png"
            filepath = os.path.join(output_folder, filename)
            image.save(filepath)
            images.append(image)

        except Exception as e:
            error_msg = f"❌ Error generating image {i + 1}: {str(e)}"
            print(error_msg)
            continue

    if not images:
        final_status = "❌ Failed to generate any images. Please try again with different settings."
    else:
        lora_status = "with LoRA" if lora_loaded else "without LoRA"
        final_status = f"πŸŽ‰ Successfully generated {len(images)}/{num_images} image(s) {lora_status}!"

    return images, final_status


# 🌐 Gradio UI with Speed Presets
with gr.Blocks(title="BitKun LoRA Generator", theme=gr.themes.Soft()) as demo:
    gr.Markdown("""
    # 🐢 BitKun LoRA Generator 🎨 (FAST VERSION)
    ### θ‡ͺη”±γͺγƒ—γƒ­γƒ³γƒ—γƒˆε―ΎεΏœ / Custom Prompt Support
    """)

    # Show LoRA status
    lora_status_text = "βœ… LoRA loaded successfully!" if lora_loaded else "⚠️ Running with base model only (LoRA not found)"
    gr.Markdown(f"**Status:** {lora_status_text}")

    with gr.Row():
        with gr.Column(scale=1):
            gr.Markdown("### 🎯 Generation Settings")

            custom_prompt = gr.Textbox(
                label="πŸ“ γƒ—γƒ­γƒ³γƒ—γƒˆ / Prompt",
                placeholder="δΎ‹: happy, smiling, cartoon style, colorful background",
                lines=3,
                info="'bitkun' will be automatically added if not included"
            )

            negative_prompt = gr.Textbox(
                label="🚫 γƒγ‚¬γƒ†γ‚£γƒ–γƒ—γƒ­γƒ³γƒ—γƒˆ / Negative Prompt",
                value="realistic, human skin, photo, blurry, distorted, extra limbs, bad anatomy",
                lines=2
            )

            # Speed Presets
            gr.Markdown("### ⚑ Speed Presets")
            with gr.Row():
                speed_preset = gr.Radio(
                    choices=[
                        ("πŸš€ Ultra Fast (10 steps, 256x256)", "ultra_fast"),
                        ("⚑ Fast (15 steps, 384x384)", "fast"),
                        ("🎯 Balanced (20 steps, 512x512)", "balanced"),
                        ("🎨 Quality (25 steps, 512x512)", "quality"),
                        ("πŸ”§ Custom", "custom")
                    ],
                    value="fast",
                    label="Choose Speed vs Quality"
                )

            with gr.Row():
                num_images = gr.Slider(
                    label="πŸ–ΌοΈ Number of Images",
                    minimum=1,
                    maximum=3,
                    value=1,
                    step=1,
                    info="More images = longer processing time"
                )

            # Advanced settings (hidden by default)
            with gr.Accordion("πŸ”§ Advanced Settings", open=False):
                steps = gr.Slider(
                    label="πŸ”„ Inference Steps",
                    minimum=5,
                    maximum=50,
                    value=15,
                    step=1,
                    info="More steps = higher quality but slower"
                )

                guidance_scale = gr.Slider(
                    label="🎚️ Guidance Scale",
                    minimum=1.0,
                    maximum=15.0,
                    value=7.5,
                    step=0.5,
                    info="Higher = more prompt adherence"
                )

                with gr.Row():
                    width = gr.Slider(
                        label="πŸ“ Width",
                        minimum=256,
                        maximum=768,
                        value=384,
                        step=64
                    )

                    height = gr.Slider(
                        label="πŸ“ Height",
                        minimum=256,
                        maximum=768,
                        value=384,
                        step=64
                    )

            generate_btn = gr.Button(
                "🎨 η”»εƒγ‚’η”Ÿζˆ / Generate Images",
                variant="primary",
                size="lg"
            )

        with gr.Column(scale=1):
            gr.Markdown("### πŸ–ΌοΈ Generated Images")

            gallery = gr.Gallery(
                label="η”Ÿζˆη”»εƒ / Generated Images",
                columns=2,
                rows=2,
                height=400,
                show_label=False
            )

            status_text = gr.Textbox(
                label="πŸ“Š Generation Status",
                interactive=False,
                lines=2
            )


    # Speed preset change handler
    def update_settings(preset):
        if preset == "ultra_fast":
            return 10, 7.0, 256, 256
        elif preset == "fast":
            return 15, 7.5, 384, 384
        elif preset == "balanced":
            return 20, 7.5, 512, 512
        elif preset == "quality":
            return 25, 8.0, 512, 512
        else:  # custom
            return 15, 7.5, 384, 384


    speed_preset.change(
        fn=update_settings,
        inputs=[speed_preset],
        outputs=[steps, guidance_scale, width, height]
    )

    # Example prompts section
    gr.Markdown("""
    ### πŸ“ Quick Examples / クむック例:

    **⚑ For fastest results, try these short prompts:**
    - `happy, smiling`
    - `sad, crying`  
    - `angry, red face`
    - `surprised, shocked`
    - `sleepy, tired`
    - `superhero, cape`
    """)

    # Button click event
    generate_btn.click(
        fn=generate_bitkun,
        inputs=[custom_prompt, negative_prompt, num_images, steps, guidance_scale, width, height],
        outputs=[gallery, status_text],
        show_progress=True
    )

# Launch the app
if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        show_error=True
    )