File size: 5,059 Bytes
fe3ca1d
 
 
c3ce72d
f1d52bb
fe3ca1d
e29313f
 
fe3ca1d
0dec9f5
e92ac40
 
 
 
f1d52bb
 
e92ac40
f1d52bb
e92ac40
fe3ca1d
 
0dec9f5
e92ac40
 
 
fba219b
e92ac40
 
 
 
fba219b
e92ac40
 
fe3ca1d
e29313f
 
 
fe3ca1d
e92ac40
 
e29313f
 
 
e92ac40
 
fe3ca1d
 
 
 
e29313f
c3ce72d
e92ac40
e29313f
fe3ca1d
 
 
 
 
e92ac40
 
e29313f
 
 
 
 
 
 
 
fe3ca1d
 
eebddbb
e92ac40
 
d85795c
fe3ca1d
 
d85795c
eebddbb
 
 
 
fe3ca1d
eebddbb
fe3ca1d
eebddbb
 
fe3ca1d
 
eebddbb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b268ca
 
eebddbb
 
 
 
e29313f
7af42b0
 
eebddbb
 
 
3b268ca
e92ac40
e29313f
 
 
 
 
fe3ca1d
 
 
e92ac40
e29313f
fe3ca1d
 
 
d85795c
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
import gradio as gr
import numpy as np
import random
import spaces
import os
import torch
import re
from PIL import Image

from diffusers import DiffusionPipeline, AutoencoderTiny
from huggingface_hub import login
from live_preview_helpers import flux_pipe_call_that_returns_an_iterable_of_images

# Authenticate for gated repo access
hf_token = os.environ.get("HF_TOKEN")
if hf_token:
    login(token=hf_token)

dtype = torch.bfloat16
device = "cuda" if torch.cuda.is_available() else "cpu"

# ✅ DO NOT CHANGE: Working pipeline using taef1
taef1 = AutoencoderTiny.from_pretrained("madebyollin/taef1", torch_dtype=dtype).to(device)

pipe = DiffusionPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    torch_dtype=dtype,
    token=hf_token,
    vae=taef1
).to(device)

pipe.flux_pipe_call_that_returns_an_iterable_of_images = flux_pipe_call_that_returns_an_iterable_of_images.__get__(pipe)
pipe.load_lora_weights("ZennyKenny/flux_lora_natalie-diffusion")

# Ensure image_preview dir exists
os.makedirs("image_preview", exist_ok=True)

MAX_SEED = np.iinfo(np.int32).max
MAX_IMAGE_SIZE = 2048

def sanitize_filename(name):
    return re.sub(r"[^a-zA-Z0-9_-]", "_", name)[:80]

@spaces.GPU(duration=75)
def infer(prompt, seed=42, randomize_seed=False, width=1024, height=1024, guidance_scale=3.5, num_inference_steps=28, progress=gr.Progress(track_tqdm=True)):
    if randomize_seed:
        seed = random.randint(0, MAX_SEED)
    generator = torch.Generator().manual_seed(seed)

    full_prompt = f"XTON {prompt}"

    for img in pipe.flux_pipe_call_that_returns_an_iterable_of_images(
        prompt=full_prompt,
        guidance_scale=guidance_scale,
        num_inference_steps=num_inference_steps,
        width=width,
        height=height,
        generator=generator,
        output_type="pil",
    ):
        # Save image to /image_preview
        safe_name = sanitize_filename(prompt)
        img_path = f"image_preview/{safe_name}_{seed}.jpg"
        img.convert("RGB").save(img_path, "JPEG", quality=60)

        # Return image and updated list of previews
        previews = [f"image_preview/{f}" for f in sorted(os.listdir("image_preview")) if f.endswith(".jpg")]
        return img, seed, previews

examples = [
    "a man walking in the forest",
    "a viking ship sailing down a river",
    "a woman resting by an open fire",
    "a sword fight in a medieval village"
]

with gr.Blocks() as natalie_diffusion:
    with gr.Row():
        with gr.Column(scale=1, elem_id="left-column"):
            gr.Markdown("""
# ХТОНЬ: Natalie LoRA Image Generator

Generate images in the surreal style of artist [Natalie Kav](https://www.behance.net/nataliKav), adapted using a custom LoRA on the FLUX.1 [dev] model.

> This space is designed for prototyping concept art for a forthcoming game called **ХТОНЬ**. All outputs are generated locally in the browser using GPU acceleration.
""")

            with gr.Row():
                prompt = gr.Text(
                    label="Prompt",
                    show_label=False,
                    max_lines=1,
                    placeholder="Enter your prompt...",
                    container=False,
                )
                run_button = gr.Button("🎨 Generate", scale=0)

            with gr.Accordion("Advanced Settings", open=False):
                seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
                randomize_seed = gr.Checkbox(label="Randomize seed", value=True)

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

                with gr.Row():
                    guidance_scale = gr.Slider(label="Guidance Scale", minimum=1, maximum=15, step=0.1, value=3.5)
                    num_inference_steps = gr.Slider(label="Number of inference steps", minimum=1, maximum=50, step=1, value=28)

            result_example = gr.Image(visible=False)

            gr.Examples(
                examples=examples,
                fn=infer,
                inputs=[prompt],
                outputs=[result_example, seed, gr.Gallery(visible=False)],
                cache_examples=True,
                cache_mode="lazy"
            )

        with gr.Column(scale=1, elem_id="right-column"):
            result = gr.Image(label="", show_label=False, elem_id="generated-image")

    gr_state = gr.State([])  # internal list of previews
    with gr.Column():
        gr.Markdown("<h3 style='text-align:center;'>Generated Images Preview</h3>")
        gallery = gr.Gallery(label="", columns=4, height="auto", object_fit="cover")

    gr.on(
        triggers=[run_button.click, prompt.submit],
        fn=infer,
        inputs=[prompt, seed, randomize_seed, width, height, guidance_scale, num_inference_steps],
        outputs=[result, seed, gallery],
    )

if __name__ == "__main__":
    natalie_diffusion.launch(css="style.css")