Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -18,69 +18,66 @@ MAX_SEED = np.iinfo(np.int32).max
|
|
18 |
|
19 |
pipe = FluxKontextPipeline.from_pretrained("black-forest-labs/FLUX.1-Kontext-dev", torch_dtype=torch.bfloat16).to("cuda")
|
20 |
|
21 |
-
# Load LoRA data
|
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 |
-
"likes": 60
|
82 |
-
}
|
83 |
-
]
|
84 |
# Global variables for LoRA management
|
85 |
current_lora = None
|
86 |
lora_cache = {}
|
@@ -136,11 +133,14 @@ def update_selection(selected_state: gr.SelectData, flux_loras):
|
|
136 |
if selected_state.index >= len(flux_loras):
|
137 |
return "### No LoRA selected", gr.update(), None
|
138 |
|
139 |
-
|
140 |
-
|
|
|
|
|
141 |
|
142 |
-
|
143 |
-
|
|
|
144 |
|
145 |
return updated_text, gr.update(placeholder=new_placeholder), selected_state.index
|
146 |
|
@@ -188,17 +188,20 @@ def get_huggingface_lora(link):
|
|
188 |
def load_custom_lora(link):
|
189 |
"""Load custom LoRA from user input"""
|
190 |
if not link:
|
191 |
-
return gr.update(visible=False), "", gr.update(visible=False), None, gr.Gallery(selected_index=None), "###
|
192 |
|
193 |
try:
|
194 |
repo_name, weights_file, trigger_word = get_huggingface_lora(link)
|
195 |
|
196 |
card = f'''
|
197 |
-
<div
|
198 |
-
<
|
199 |
-
|
200 |
-
<
|
201 |
-
|
|
|
|
|
|
|
202 |
</div>
|
203 |
</div>
|
204 |
'''
|
@@ -209,10 +212,10 @@ def load_custom_lora(link):
|
|
209 |
"trigger_word": trigger_word
|
210 |
}
|
211 |
|
212 |
-
return gr.update(visible=True), card, gr.update(visible=True), custom_lora_data, gr.Gallery(selected_index=None), f"Custom: {repo_name}", None
|
213 |
|
214 |
except Exception as e:
|
215 |
-
return gr.update(visible=True), f"Error: {str(e)}", gr.update(visible=False), None, gr.update(), "###
|
216 |
|
217 |
def remove_custom_lora():
|
218 |
"""Remove custom LoRA"""
|
@@ -224,16 +227,26 @@ def classify_gallery(flux_loras):
|
|
224 |
sorted_gallery = sorted(flux_loras, key=lambda x: x.get("likes", 0), reverse=True)
|
225 |
gallery_items = []
|
226 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
227 |
for item in sorted_gallery:
|
228 |
if "image" in item and "title" in item:
|
229 |
image_url = item["image"]
|
230 |
title = item["title"]
|
231 |
|
232 |
-
# If image is a local file path
|
233 |
-
if isinstance(image_url, str) and (image_url.startswith("/home/") or image_url.startswith("samples/") or not image_url.startswith("http")):
|
234 |
-
|
235 |
-
|
236 |
-
image_url = f"https://via.placeholder.com/512x512/E0E7FF/818CF8?text={title.replace(' ', '+')}"
|
237 |
|
238 |
gallery_items.append((image_url, title))
|
239 |
|
@@ -246,7 +259,7 @@ def classify_gallery(flux_loras):
|
|
246 |
print(f"Error in classify_gallery: {e}")
|
247 |
return [], []
|
248 |
|
249 |
-
def infer_with_lora_wrapper(input_image, prompt, selected_index, custom_lora, seed=42, randomize_seed=False, guidance_scale=2.5, lora_scale=1.
|
250 |
"""Wrapper function to handle state serialization"""
|
251 |
return infer_with_lora(input_image, prompt, selected_index, custom_lora, seed, randomize_seed, guidance_scale, lora_scale, flux_loras, progress)
|
252 |
|
@@ -257,7 +270,7 @@ def infer_with_lora(input_image, prompt, selected_index, custom_lora, seed=42, r
|
|
257 |
|
258 |
# Check if input image is provided
|
259 |
if input_image is None:
|
260 |
-
gr.Warning("Please upload
|
261 |
return None, seed, gr.update(visible=False)
|
262 |
|
263 |
if randomize_seed:
|
@@ -290,7 +303,7 @@ def infer_with_lora(input_image, prompt, selected_index, custom_lora, seed=42, r
|
|
290 |
current_lora = lora_to_use
|
291 |
else:
|
292 |
print(f"Failed to load LoRA from {repo_id}")
|
293 |
-
gr.Warning(f"Failed to load
|
294 |
return None, seed, gr.update(visible=False)
|
295 |
|
296 |
except Exception as e:
|
@@ -305,17 +318,33 @@ def infer_with_lora(input_image, prompt, selected_index, custom_lora, seed=42, r
|
|
305 |
input_image = input_image.convert("RGB")
|
306 |
except Exception as e:
|
307 |
print(f"Error processing image: {e}")
|
308 |
-
gr.Warning("Error processing the uploaded image. Please try a different
|
309 |
return None, seed, gr.update(visible=False)
|
310 |
|
311 |
# Check if LoRA is selected
|
312 |
if lora_to_use is None:
|
313 |
-
gr.Warning("Please select
|
314 |
return None, seed, gr.update(visible=False)
|
315 |
|
316 |
# Add trigger word to prompt
|
317 |
trigger_word = lora_to_use.get("trigger_word", "")
|
318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
prompt = f"create a How2Draw sketch of the person of the photo {prompt}, maintain the facial identity of the person and general features"
|
320 |
elif trigger_word == ", video game screenshot in the style of THSMS":
|
321 |
prompt = f"create a video game screenshot in the style of THSMS with the person from the photo, {prompt}. maintain the facial identity of the person and general features"
|
@@ -571,10 +600,10 @@ with gr.Blocks(css=css) as demo:
|
|
571 |
with gr.Row(elem_id="main_app"):
|
572 |
with gr.Column(scale=4, elem_id="box_column"):
|
573 |
with gr.Group(elem_id="gallery_box"):
|
574 |
-
input_image = gr.Image(label="Upload
|
575 |
|
576 |
gallery = gr.Gallery(
|
577 |
-
label="
|
578 |
allow_preview=False,
|
579 |
columns=3,
|
580 |
elem_id="gallery",
|
@@ -583,55 +612,57 @@ with gr.Blocks(css=css) as demo:
|
|
583 |
)
|
584 |
|
585 |
custom_model = gr.Textbox(
|
586 |
-
label="Or
|
587 |
placeholder="e.g., username/lora-name",
|
588 |
visible=True
|
589 |
)
|
590 |
custom_model_card = gr.HTML(visible=False)
|
591 |
-
custom_model_button = gr.Button("Remove custom LoRA", visible=False)
|
592 |
|
593 |
with gr.Column(scale=5):
|
594 |
with gr.Row():
|
595 |
prompt = gr.Textbox(
|
596 |
-
label="
|
597 |
show_label=False,
|
598 |
lines=1,
|
599 |
max_lines=1,
|
600 |
-
placeholder="
|
601 |
elem_id="prompt"
|
602 |
)
|
603 |
run_button = gr.Button("Generate ✨", elem_id="run_button")
|
604 |
|
605 |
-
result = gr.Image(label="
|
606 |
reuse_button = gr.Button("🔄 Reuse this image", visible=False)
|
607 |
|
608 |
-
with gr.Accordion("Advanced Settings", open=False):
|
609 |
lora_scale = gr.Slider(
|
610 |
-
label="
|
611 |
minimum=0,
|
612 |
maximum=2,
|
613 |
step=0.1,
|
614 |
-
value=1.
|
615 |
-
info="
|
616 |
)
|
617 |
seed = gr.Slider(
|
618 |
-
label="Seed",
|
619 |
minimum=0,
|
620 |
maximum=MAX_SEED,
|
621 |
step=1,
|
622 |
value=0,
|
|
|
623 |
)
|
624 |
-
randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
|
625 |
guidance_scale = gr.Slider(
|
626 |
-
label="Guidance
|
627 |
minimum=1,
|
628 |
maximum=10,
|
629 |
step=0.1,
|
630 |
value=2.5,
|
|
|
631 |
)
|
632 |
|
633 |
prompt_title = gr.Markdown(
|
634 |
-
value="###
|
635 |
visible=True,
|
636 |
elem_id="selected_lora",
|
637 |
)
|
|
|
18 |
|
19 |
pipe = FluxKontextPipeline.from_pretrained("black-forest-labs/FLUX.1-Kontext-dev", torch_dtype=torch.bfloat16).to("cuda")
|
20 |
|
21 |
+
# Load LoRA data
|
22 |
+
flux_loras_raw = [
|
23 |
+
{
|
24 |
+
"image": "examples/1.png",
|
25 |
+
"title": "Studio Ghibli",
|
26 |
+
"repo": "openfree/flux-chatgpt-ghibli-lora",
|
27 |
+
"trigger_word": "ghibli",
|
28 |
+
"weights": "pytorch_lora_weights.safetensors",
|
29 |
+
"likes": 0
|
30 |
+
},
|
31 |
+
{
|
32 |
+
"image": "examples/2.png",
|
33 |
+
"title": "Winslow Homer",
|
34 |
+
"repo": "openfree/winslow-homer",
|
35 |
+
"trigger_word": "homer",
|
36 |
+
"weights": "pytorch_lora_weights.safetensors",
|
37 |
+
"likes": 0
|
38 |
+
},
|
39 |
+
{
|
40 |
+
"image": "examples/3.png",
|
41 |
+
"title": "Van Gogh",
|
42 |
+
"repo": "openfree/van-gogh",
|
43 |
+
"trigger_word": "gogh",
|
44 |
+
"weights": "pytorch_lora_weights.safetensors",
|
45 |
+
"likes": 0
|
46 |
+
},
|
47 |
+
{
|
48 |
+
"image": "examples/4.png",
|
49 |
+
"title": "Paul Cézanne",
|
50 |
+
"repo": "openfree/paul-cezanne",
|
51 |
+
"trigger_word": "Cezanne",
|
52 |
+
"weights": "pytorch_lora_weights.safetensors",
|
53 |
+
"likes": 0
|
54 |
+
},
|
55 |
+
{
|
56 |
+
"image": "examples/5.png",
|
57 |
+
"title": "Renoir",
|
58 |
+
"repo": "openfree/pierre-auguste-renoir",
|
59 |
+
"trigger_word": "Renoir",
|
60 |
+
"weights": "pytorch_lora_weights.safetensors",
|
61 |
+
"likes": 0
|
62 |
+
},
|
63 |
+
{
|
64 |
+
"image": "examples/6.png",
|
65 |
+
"title": "Claude Monet",
|
66 |
+
"repo": "openfree/claude-monet",
|
67 |
+
"trigger_word": "claude monet",
|
68 |
+
"weights": "pytorch_lora_weights.safetensors",
|
69 |
+
"likes": 0
|
70 |
+
},
|
71 |
+
{
|
72 |
+
"image": "examples/7.png",
|
73 |
+
"title": "Fantasy Art",
|
74 |
+
"repo": "openfree/myt-flux-fantasy",
|
75 |
+
"trigger_word": "fantasy",
|
76 |
+
"weights": "pytorch_lora_weights.safetensors",
|
77 |
+
"likes": 0
|
78 |
+
}
|
79 |
+
]
|
80 |
+
print(f"Loaded {len(flux_loras_raw)} LoRAs")
|
|
|
|
|
|
|
81 |
# Global variables for LoRA management
|
82 |
current_lora = None
|
83 |
lora_cache = {}
|
|
|
133 |
if selected_state.index >= len(flux_loras):
|
134 |
return "### No LoRA selected", gr.update(), None
|
135 |
|
136 |
+
lora = flux_loras[selected_state.index]
|
137 |
+
lora_title = lora["title"]
|
138 |
+
lora_repo = lora["repo"]
|
139 |
+
trigger_word = lora["trigger_word"]
|
140 |
|
141 |
+
# Create a more informative selected text
|
142 |
+
updated_text = f"### 🎨 Selected Style: {lora_title}"
|
143 |
+
new_placeholder = f"Describe additional details, e.g., 'wearing a red hat' or 'smiling'"
|
144 |
|
145 |
return updated_text, gr.update(placeholder=new_placeholder), selected_state.index
|
146 |
|
|
|
188 |
def load_custom_lora(link):
|
189 |
"""Load custom LoRA from user input"""
|
190 |
if not link:
|
191 |
+
return gr.update(visible=False), "", gr.update(visible=False), None, gr.Gallery(selected_index=None), "### 🎨 Select an art style from the gallery", None
|
192 |
|
193 |
try:
|
194 |
repo_name, weights_file, trigger_word = get_huggingface_lora(link)
|
195 |
|
196 |
card = f'''
|
197 |
+
<div class="custom_lora_card">
|
198 |
+
<div style="display: flex; align-items: center; margin-bottom: 12px;">
|
199 |
+
<span style="font-size: 18px; margin-right: 8px;">✅</span>
|
200 |
+
<strong style="font-size: 16px;">Custom LoRA Loaded!</strong>
|
201 |
+
</div>
|
202 |
+
<div style="background: rgba(255, 255, 255, 0.8); padding: 12px; border-radius: 8px;">
|
203 |
+
<h4 style="margin: 0 0 8px 0; color: #333;">{repo_name}</h4>
|
204 |
+
<small style="color: #666;">{"Trigger: <code style='background: #f0f0f0; padding: 2px 6px; border-radius: 4px;'><b>"+trigger_word+"</b></code>" if trigger_word else "No trigger word found"}</small>
|
205 |
</div>
|
206 |
</div>
|
207 |
'''
|
|
|
212 |
"trigger_word": trigger_word
|
213 |
}
|
214 |
|
215 |
+
return gr.update(visible=True), card, gr.update(visible=True), custom_lora_data, gr.Gallery(selected_index=None), f"🎨 Custom Style: {repo_name}", None
|
216 |
|
217 |
except Exception as e:
|
218 |
+
return gr.update(visible=True), f"Error: {str(e)}", gr.update(visible=False), None, gr.update(), "### 🎨 Select an art style from the gallery", None
|
219 |
|
220 |
def remove_custom_lora():
|
221 |
"""Remove custom LoRA"""
|
|
|
227 |
sorted_gallery = sorted(flux_loras, key=lambda x: x.get("likes", 0), reverse=True)
|
228 |
gallery_items = []
|
229 |
|
230 |
+
# Color mapping for each style
|
231 |
+
style_colors = {
|
232 |
+
"Studio Ghibli": "81C784/FFFFFF", # Green
|
233 |
+
"Winslow Homer": "64B5F6/FFFFFF", # Blue
|
234 |
+
"Van Gogh": "FFD54F/333333", # Yellow
|
235 |
+
"Paul Cézanne": "FF8A65/FFFFFF", # Orange
|
236 |
+
"Renoir": "F06292/FFFFFF", # Pink
|
237 |
+
"Claude Monet": "9575CD/FFFFFF", # Purple
|
238 |
+
"Fantasy Art": "4FC3F7/FFFFFF" # Light Blue
|
239 |
+
}
|
240 |
+
|
241 |
for item in sorted_gallery:
|
242 |
if "image" in item and "title" in item:
|
243 |
image_url = item["image"]
|
244 |
title = item["title"]
|
245 |
|
246 |
+
# If image is a local file path, use a styled placeholder
|
247 |
+
if isinstance(image_url, str) and (image_url.startswith("examples/") or image_url.startswith("/home/") or image_url.startswith("samples/") or not image_url.startswith("http")):
|
248 |
+
color = style_colors.get(title, "E0E7FF/818CF8")
|
249 |
+
image_url = f"https://via.placeholder.com/512x512/{color}?text={title.replace(' ', '+')}"
|
|
|
250 |
|
251 |
gallery_items.append((image_url, title))
|
252 |
|
|
|
259 |
print(f"Error in classify_gallery: {e}")
|
260 |
return [], []
|
261 |
|
262 |
+
def infer_with_lora_wrapper(input_image, prompt, selected_index, custom_lora, seed=42, randomize_seed=False, guidance_scale=2.5, lora_scale=1.0, flux_loras=None, progress=gr.Progress(track_tqdm=True)):
|
263 |
"""Wrapper function to handle state serialization"""
|
264 |
return infer_with_lora(input_image, prompt, selected_index, custom_lora, seed, randomize_seed, guidance_scale, lora_scale, flux_loras, progress)
|
265 |
|
|
|
270 |
|
271 |
# Check if input image is provided
|
272 |
if input_image is None:
|
273 |
+
gr.Warning("Please upload your portrait photo first! 📸")
|
274 |
return None, seed, gr.update(visible=False)
|
275 |
|
276 |
if randomize_seed:
|
|
|
303 |
current_lora = lora_to_use
|
304 |
else:
|
305 |
print(f"Failed to load LoRA from {repo_id}")
|
306 |
+
gr.Warning(f"Failed to load {lora_to_use.get('title', 'style')}. Please try a different art style.")
|
307 |
return None, seed, gr.update(visible=False)
|
308 |
|
309 |
except Exception as e:
|
|
|
318 |
input_image = input_image.convert("RGB")
|
319 |
except Exception as e:
|
320 |
print(f"Error processing image: {e}")
|
321 |
+
gr.Warning("Error processing the uploaded image. Please try a different photo. 📸")
|
322 |
return None, seed, gr.update(visible=False)
|
323 |
|
324 |
# Check if LoRA is selected
|
325 |
if lora_to_use is None:
|
326 |
+
gr.Warning("Please select an art style from the gallery first! 🎨")
|
327 |
return None, seed, gr.update(visible=False)
|
328 |
|
329 |
# Add trigger word to prompt
|
330 |
trigger_word = lora_to_use.get("trigger_word", "")
|
331 |
+
|
332 |
+
# Special handling for different art styles
|
333 |
+
if trigger_word == "ghibli":
|
334 |
+
prompt = f"Create a Studio Ghibli anime style portrait of the person in the photo, {prompt}. Maintain the facial identity while transforming into whimsical anime art style."
|
335 |
+
elif trigger_word == "homer":
|
336 |
+
prompt = f"Paint the person in Winslow Homer's American realist style, {prompt}. Keep facial features while applying watercolor and marine art techniques."
|
337 |
+
elif trigger_word == "gogh":
|
338 |
+
prompt = f"Transform the portrait into Van Gogh's post-impressionist style with swirling brushstrokes, {prompt}. Maintain facial identity with expressive colors."
|
339 |
+
elif trigger_word == "Cezanne":
|
340 |
+
prompt = f"Render the person in Paul Cézanne's geometric post-impressionist style, {prompt}. Keep facial structure while applying structured brushwork."
|
341 |
+
elif trigger_word == "Renoir":
|
342 |
+
prompt = f"Paint the portrait in Pierre-Auguste Renoir's impressionist style with soft light, {prompt}. Maintain identity with luminous skin tones."
|
343 |
+
elif trigger_word == "claude monet":
|
344 |
+
prompt = f"Create an impressionist portrait in Claude Monet's style with visible brushstrokes, {prompt}. Keep facial features while using light and color."
|
345 |
+
elif trigger_word == "fantasy":
|
346 |
+
prompt = f"Transform into an epic fantasy character portrait, {prompt}. Maintain facial identity while adding magical and fantastical elements."
|
347 |
+
elif trigger_word == ", How2Draw":
|
348 |
prompt = f"create a How2Draw sketch of the person of the photo {prompt}, maintain the facial identity of the person and general features"
|
349 |
elif trigger_word == ", video game screenshot in the style of THSMS":
|
350 |
prompt = f"create a video game screenshot in the style of THSMS with the person from the photo, {prompt}. maintain the facial identity of the person and general features"
|
|
|
600 |
with gr.Row(elem_id="main_app"):
|
601 |
with gr.Column(scale=4, elem_id="box_column"):
|
602 |
with gr.Group(elem_id="gallery_box"):
|
603 |
+
input_image = gr.Image(label="Upload your portrait photo 📸", type="pil", height=300)
|
604 |
|
605 |
gallery = gr.Gallery(
|
606 |
+
label="Choose Your Art Style",
|
607 |
allow_preview=False,
|
608 |
columns=3,
|
609 |
elem_id="gallery",
|
|
|
612 |
)
|
613 |
|
614 |
custom_model = gr.Textbox(
|
615 |
+
label="🔗 Or use a custom LoRA from HuggingFace",
|
616 |
placeholder="e.g., username/lora-name",
|
617 |
visible=True
|
618 |
)
|
619 |
custom_model_card = gr.HTML(visible=False)
|
620 |
+
custom_model_button = gr.Button("❌ Remove custom LoRA", visible=False)
|
621 |
|
622 |
with gr.Column(scale=5):
|
623 |
with gr.Row():
|
624 |
prompt = gr.Textbox(
|
625 |
+
label="Additional Details (optional)",
|
626 |
show_label=False,
|
627 |
lines=1,
|
628 |
max_lines=1,
|
629 |
+
placeholder="Describe additional details, e.g., 'wearing a red hat' or 'smiling'",
|
630 |
elem_id="prompt"
|
631 |
)
|
632 |
run_button = gr.Button("Generate ✨", elem_id="run_button")
|
633 |
|
634 |
+
result = gr.Image(label="Your Artistic Portrait", interactive=False)
|
635 |
reuse_button = gr.Button("🔄 Reuse this image", visible=False)
|
636 |
|
637 |
+
with gr.Accordion("⚙️ Advanced Settings", open=False):
|
638 |
lora_scale = gr.Slider(
|
639 |
+
label="Style Strength",
|
640 |
minimum=0,
|
641 |
maximum=2,
|
642 |
step=0.1,
|
643 |
+
value=1.0,
|
644 |
+
info="How strongly to apply the art style (1.0 = balanced)"
|
645 |
)
|
646 |
seed = gr.Slider(
|
647 |
+
label="Random Seed",
|
648 |
minimum=0,
|
649 |
maximum=MAX_SEED,
|
650 |
step=1,
|
651 |
value=0,
|
652 |
+
info="Set to 0 for random results"
|
653 |
)
|
654 |
+
randomize_seed = gr.Checkbox(label="🎲 Randomize seed for each generation", value=True)
|
655 |
guidance_scale = gr.Slider(
|
656 |
+
label="Image Guidance",
|
657 |
minimum=1,
|
658 |
maximum=10,
|
659 |
step=0.1,
|
660 |
value=2.5,
|
661 |
+
info="How closely to follow the input image (lower = more creative)"
|
662 |
)
|
663 |
|
664 |
prompt_title = gr.Markdown(
|
665 |
+
value="### 🎨 Select an art style from the gallery",
|
666 |
visible=True,
|
667 |
elem_id="selected_lora",
|
668 |
)
|