wanghaofan commited on
Commit
5bc1cd2
Β·
verified Β·
1 Parent(s): 85bb0f3

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +5 -5
  2. app.py +203 -0
  3. loras.json +50 -0
  4. requirements.txt +17 -0
README.md CHANGED
@@ -1,13 +1,13 @@
1
  ---
2
  title: FLUX Kontext LoRA Gallery
3
- emoji: πŸ“š
4
  colorFrom: purple
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 5.38.0
8
  app_file: app.py
9
  pinned: false
10
- short_description: Image editing with Kontext LoRAs
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
  title: FLUX Kontext LoRA Gallery
3
+ emoji: πŸ˜„
4
  colorFrom: purple
5
+ colorTo: red
6
  sdk: gradio
7
+ sdk_version: 4.42.0
8
  app_file: app.py
9
  pinned: false
10
+ license: other
11
  ---
12
 
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import json
4
+ import logging
5
+ import torch
6
+ from PIL import Image
7
+ import spaces
8
+ from diffusers import FluxKontextPipeline
9
+
10
+ from huggingface_hub import HfFileSystem, ModelCard
11
+ import copy
12
+ import random
13
+ import time
14
+
15
+ import subprocess
16
+ subprocess.run("rm -rf /data-nvme/zerogpu-offload/*", env={}, shell=True)
17
+
18
+ from huggingface_hub import login
19
+ hf_token = os.environ.get("HF_TOKEN_GATED")
20
+ login(token=hf_token)
21
+
22
+ # Load LoRAs from JSON file
23
+ with open('loras.json', 'r') as f:
24
+ loras = json.load(f)
25
+
26
+ # Initialize the base model
27
+ dtype = torch.bfloat16
28
+ device = "cuda" if torch.cuda.is_available() else "cpu"
29
+ base_model = "black-forest-labs/FLUX.1-Kontext-dev"
30
+
31
+ pipe = FluxKontextPipeline.from_pretrained(base_model, torch_dtype=dtype).to(device)
32
+
33
+ MAX_SEED = 2**32-1
34
+
35
+ class calculateDuration:
36
+ def __init__(self, activity_name=""):
37
+ self.activity_name = activity_name
38
+
39
+ def __enter__(self):
40
+ self.start_time = time.time()
41
+ return self
42
+
43
+ def __exit__(self, exc_type, exc_value, traceback):
44
+ self.end_time = time.time()
45
+ self.elapsed_time = self.end_time - self.start_time
46
+ if self.activity_name:
47
+ print(f"Elapsed time for {self.activity_name}: {self.elapsed_time:.6f} seconds")
48
+ else:
49
+ print(f"Elapsed time: {self.elapsed_time:.6f} seconds")
50
+
51
+ def update_selection(evt: gr.SelectData, default_scale, lora_scale):
52
+ selected_lora = loras[evt.index]
53
+ new_placeholder = f"Type a prompt for {selected_lora['title']}"
54
+ prompt = selected_lora["prompt"]
55
+ lora_repo = selected_lora["repo"]
56
+ updated_text = f"### Selected: [{lora_repo}](https://huggingface.co/{lora_repo}) ✨"
57
+ if default_scale:
58
+ lora_scale = selected_lora["lora_scale"]
59
+ return (
60
+ prompt,
61
+ updated_text,
62
+ evt.index,
63
+ lora_scale,
64
+ )
65
+
66
+ @spaces.GPU
67
+ def generate_image(input_image, prompt_mash, steps, seed, cfg_scale, lora_scale, progress):
68
+ pipe.to("cuda")
69
+ generator = torch.Generator(device="cuda").manual_seed(seed)
70
+ with calculateDuration("Generating image"):
71
+ # Generate image
72
+ for img in pipe(
73
+ image=input_image,
74
+ prompt=prompt_mash,
75
+ num_inference_steps=steps,
76
+ guidance_scale=cfg_scale,
77
+ generator=generator,
78
+ joint_attention_kwargs={"scale": lora_scale},
79
+ output_type="pil",
80
+ ):
81
+ yield img
82
+
83
+ @spaces.GPU
84
+ def run_lora(input_image, prompt, cfg_scale, steps, selected_index, randomize_seed, seed, lora_scale, progress=gr.Progress(track_tqdm=True)):
85
+ if selected_index is None:
86
+ raise gr.Error("You must select a LoRA before proceeding.")
87
+ selected_lora = loras[selected_index]
88
+ lora_path = selected_lora["repo"]
89
+ trigger_word = selected_lora["trigger_word"]
90
+ if(trigger_word):
91
+ if "trigger_position" in selected_lora:
92
+ if selected_lora["trigger_position"] == "prepend" and trigger_word != prompt:
93
+ prompt_mash = f"{trigger_word} {prompt}"
94
+ else:
95
+ if trigger_word != prompt:
96
+ prompt_mash = f"{prompt} {trigger_word}"
97
+ else:
98
+ prompt_mash = prompt
99
+ else:
100
+ prompt_mash = f"{trigger_word} {prompt}"
101
+ else:
102
+ prompt_mash = prompt
103
+
104
+ with calculateDuration("Unloading LoRA"):
105
+ pipe.unload_lora_weights()
106
+
107
+ # Load LoRA weights
108
+ with calculateDuration(f"Loading LoRA weights for {selected_lora['title']}"):
109
+ if "weights" in selected_lora:
110
+ pipe.load_lora_weights(lora_path, weight_name=selected_lora["weights"])
111
+ else:
112
+ pipe.load_lora_weights(lora_path)
113
+
114
+ # Set random seed for reproducibility
115
+ with calculateDuration("Randomizing seed"):
116
+ if randomize_seed:
117
+ seed = random.randint(0, MAX_SEED)
118
+
119
+ image_generator = generate_image(input_image, prompt_mash, steps, seed, cfg_scale, lora_scale, progress)
120
+
121
+ # Consume the generator to get the final image
122
+ final_image = None
123
+ step_counter = 0
124
+ for image in image_generator:
125
+ step_counter+=1
126
+ final_image = image
127
+ progress_bar = f'<div class="progress-container"><div class="progress-bar" style="--current: {step_counter}; --total: {steps};"></div></div>'
128
+ yield image, seed, gr.update(value=progress_bar, visible=True)
129
+
130
+ yield final_image, seed, gr.update(value=progress_bar, visible=False)
131
+
132
+ css = '''
133
+ #gen_btn{height: 100%}
134
+ #title{text-align: center}
135
+ #title h1{font-size: 3em; display:inline-flex; align-items:center}
136
+ #title img{width: 100px; margin-right: 0.5em}
137
+ #gallery .grid-wrap{height: 10vh}
138
+ #lora_list{background: var(--block-background-fill);padding: 0 1em .3em; font-size: 90%}
139
+ .card_internal{display: flex;height: 100px;margin-top: .5em}
140
+ .card_internal img{margin-right: 1em}
141
+ .styler{--form-gap-width: 0px !important}
142
+ #progress{height:30px}
143
+ #progress .generating{display:none}
144
+ .progress-container {width: 100%;height: 30px;background-color: #f0f0f0;border-radius: 15px;overflow: hidden;margin-bottom: 20px}
145
+ .progress-bar {height: 100%;background-color: #4f46e5;width: calc(var(--current) / var(--total) * 100%);transition: width 0.5s ease-in-out}
146
+ '''
147
+ with gr.Blocks(theme=gr.themes.Soft(), css=css) as app:
148
+ title = gr.HTML(
149
+ """<h1><img src="https://huggingface.co/Shakker-Labs/FLUX.1-dev-LoRA-collections/resolve/main/logo.png" alt="LoRA"> FLUX Kontext LoRA Gallery from Shakker AI</h1>""",
150
+ elem_id="title",
151
+ )
152
+ selected_index = gr.State(None)
153
+ with gr.Row():
154
+ with gr.Column(scale=3):
155
+ prompt = gr.Textbox(label="Prompt", lines=1, placeholder="Type a prompt after selecting a LoRA")
156
+ with gr.Column(scale=1, elem_id="gen_column"):
157
+ generate_button = gr.Button("Generate", variant="primary", elem_id="gen_btn")
158
+ with gr.Row():
159
+ with gr.Column():
160
+ selected_info = gr.Markdown("")
161
+ gallery = gr.Gallery(
162
+ [(item["image"], item["title"]) for item in loras],
163
+ label="LoRA Gallery",
164
+ allow_preview=False,
165
+ columns=3,
166
+ elem_id="gallery"
167
+ )
168
+ with gr.Row():
169
+ with gr.Column():
170
+ image_in = gr.Image(label="Upload the image for editing", type="pil")
171
+
172
+ with gr.Column():
173
+ progress_bar = gr.Markdown(elem_id="progress",visible=False)
174
+ result = gr.Image(label="Generated Image")
175
+
176
+ with gr.Row():
177
+ with gr.Accordion("Advanced Settings", open=False):
178
+ with gr.Column():
179
+ with gr.Row():
180
+ cfg_scale = gr.Slider(label="CFG Scale", minimum=1, maximum=20, step=0.5, value=2.5)
181
+ steps = gr.Slider(label="Steps", minimum=1, maximum=50, step=1, value=28)
182
+
183
+ with gr.Row():
184
+ randomize_seed = gr.Checkbox(True, label="Randomize seed")
185
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0, randomize=True)
186
+
187
+ default_scale = gr.Checkbox(True, label="Use default LoRA scale")
188
+ lora_scale = gr.Slider(label="LoRA Scale", minimum=0, maximum=3, step=0.01, value=1.0)
189
+
190
+ gallery.select(
191
+ update_selection,
192
+ inputs=[default_scale, lora_scale],
193
+ outputs=[prompt, selected_info, selected_index, lora_scale]
194
+ )
195
+ gr.on(
196
+ triggers=[generate_button.click, prompt.submit],
197
+ fn=run_lora,
198
+ inputs=[image_in, prompt, cfg_scale, steps, selected_index, randomize_seed, seed, lora_scale],
199
+ outputs=[result, seed, progress_bar]
200
+ )
201
+
202
+ app.queue()
203
+ app.launch()
loras.json ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "image": "https://huggingface.co/Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Sketch-Style/resolve/main/images/example1.png",
4
+ "title": "FLUX.1-Kontext-dev-LoRA-Sketch-Style",
5
+ "repo": "Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Sketch-Style",
6
+ "trigger_word": "convert this image into sketches",
7
+ "prompt": "convert this image into sketches",
8
+ "lora_scale": 1.0
9
+ },
10
+ {
11
+ "image": "https://huggingface.co/Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Flat-Cartoon-Style/resolve/main/images/example1.png",
12
+ "title": "FLUX.1-Kontext-dev-LoRA-Flat-Cartoon-Style",
13
+ "repo": "Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Flat-Cartoon-Style",
14
+ "trigger_word": "Convert to a flat cartoon style while keeping the subject unchanged",
15
+ "prompt": "Convert to a flat cartoon style while keeping the subject unchanged",
16
+ "lora_scale": 1.0
17
+ },
18
+ {
19
+ "image": "https://huggingface.co/Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Illustration-Style/resolve/main/images/example3.png",
20
+ "title": "FLUX.1-Kontext-dev-LoRA-Illustration-Style",
21
+ "repo": "Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Illustration-Style",
22
+ "trigger_word": "change to illustration style",
23
+ "prompt": "change to illustration style",
24
+ "lora_scale": 1.0
25
+ },
26
+ {
27
+ "image": "https://huggingface.co/Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Pixel-Style/resolve/main/images/example1.png",
28
+ "title": "FLUX.1-Kontext-dev-LoRA-Pixel-Style",
29
+ "repo": "Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Pixel-Style",
30
+ "trigger_word": "Convert to a pixel art style",
31
+ "prompt": "Convert to a pixel art style",
32
+ "lora_scale": 1.0
33
+ },
34
+ {
35
+ "image": "https://huggingface.co/Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Felt-Style/resolve/main/images/example1.png",
36
+ "title": "FLUX.1-Kontext-dev-LoRA-Felt-Style",
37
+ "repo": "Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Felt-Style",
38
+ "trigger_word": "Turned into a plush felt toy",
39
+ "prompt": "Turned into a plush felt toy",
40
+ "lora_scale": 1.0
41
+ },
42
+ {
43
+ "image": "https://huggingface.co/Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Bioluminescence-Style/resolve/main/images/example1.png",
44
+ "title": "FLUX.1-Kontext-dev-LoRA-Bioluminescence-Style",
45
+ "repo": "Shakker-Labs/FLUX.1-Kontext-dev-LoRA-Bioluminescence-Style",
46
+ "trigger_word": "bioluminescence efficiency",
47
+ "prompt": "The edges of the character's body emit a dazzling light effect.",
48
+ "lora_scale": 1.0
49
+ }
50
+ ]
requirements.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ git+https://github.com/huggingface/diffusers.git
2
+ torch
3
+ torchvision
4
+ transformers
5
+ einops
6
+ spaces
7
+ accelerate
8
+ omegaconf
9
+ huggingface-hub
10
+ opencv-python
11
+ sentencepiece
12
+ peft
13
+ scipy
14
+ scikit-image
15
+ numpy
16
+ gradio==4.32.0
17
+ pydantic==2.9.0