Spaces:
Running on Zero
Running on Zero
qwenimageedit
#10
by huangsongqing0 - opened
- app_local.py +110 -129
- presets.py +7 -134
app_local.py
CHANGED
|
@@ -15,8 +15,8 @@ import math
|
|
| 15 |
import json # Added json import
|
| 16 |
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
|
| 17 |
import logging
|
| 18 |
-
import copy
|
| 19 |
from copy import deepcopy
|
|
|
|
| 20 |
#############################
|
| 21 |
os.environ.setdefault('GRADIO_ANALYTICS_ENABLED', 'False')
|
| 22 |
os.environ.setdefault('HF_HUB_DISABLE_TELEMETRY', '1')
|
|
@@ -47,21 +47,17 @@ rewriter_model = AutoModelForCausalLM.from_pretrained(
|
|
| 47 |
quantization_config=bnb_config,
|
| 48 |
)
|
| 49 |
|
| 50 |
-
# Store original presets for reference
|
| 51 |
-
ORIGINAL_PRESETS = deepcopy(PRESETS)
|
| 52 |
-
|
| 53 |
def get_fresh_presets():
|
| 54 |
-
|
|
|
|
| 55 |
|
| 56 |
-
|
|
|
|
| 57 |
|
| 58 |
-
def reset_presets():
|
| 59 |
-
return get_fresh_presets()
|
| 60 |
-
|
| 61 |
# Preload enhancement model at startup
|
| 62 |
-
|
| 63 |
rewriter_tokenizer = AutoTokenizer.from_pretrained(REWRITER_MODEL)
|
| 64 |
-
|
| 65 |
|
| 66 |
SYSTEM_PROMPT_EDIT = '''
|
| 67 |
# Edit Instruction Rewriter
|
|
@@ -117,7 +113,7 @@ def extract_json_response(model_output: str) -> str:
|
|
| 117 |
end_idx = model_output.rfind('}')
|
| 118 |
# Fix the condition - check if brackets were found
|
| 119 |
if start_idx == -1 or end_idx == -1 or start_idx >= end_idx:
|
| 120 |
-
|
| 121 |
return None
|
| 122 |
# Expand to the full object including outer braces
|
| 123 |
end_idx += 1 # Include the closing brace
|
|
@@ -157,8 +153,8 @@ def extract_json_response(model_output: str) -> str:
|
|
| 157 |
if str_values:
|
| 158 |
return str_values[0].strip()
|
| 159 |
except Exception as e:
|
| 160 |
-
|
| 161 |
-
|
| 162 |
return None
|
| 163 |
|
| 164 |
def polish_prompt(original_prompt: str) -> str:
|
|
@@ -177,10 +173,10 @@ def polish_prompt(original_prompt: str) -> str:
|
|
| 177 |
with torch.no_grad():
|
| 178 |
generated_ids = rewriter_model.generate(
|
| 179 |
**model_inputs,
|
| 180 |
-
max_new_tokens=
|
| 181 |
do_sample=True,
|
| 182 |
-
temperature=0.
|
| 183 |
-
top_p=0.
|
| 184 |
repetition_penalty=1.1,
|
| 185 |
no_repeat_ngram_size=3,
|
| 186 |
pad_token_id=rewriter_tokenizer.eos_token_id
|
|
@@ -190,8 +186,8 @@ def polish_prompt(original_prompt: str) -> str:
|
|
| 190 |
generated_ids[0][model_inputs.input_ids.shape[1]:],
|
| 191 |
skip_special_tokens=True
|
| 192 |
).strip()
|
| 193 |
-
|
| 194 |
-
|
| 195 |
# Try to extract JSON content
|
| 196 |
rewritten_prompt = extract_json_response(enhanced)
|
| 197 |
if rewritten_prompt:
|
|
@@ -249,7 +245,7 @@ pipe = QwenImageEditPipeline.from_pretrained(
|
|
| 249 |
pipe.load_lora_weights(
|
| 250 |
"lightx2v/Qwen-Image-Lightning",
|
| 251 |
# weight_name="Qwen-Image-Lightning-8steps-V1.1.safetensors"
|
| 252 |
-
weight_name="Qwen-Image-
|
| 253 |
)
|
| 254 |
pipe.fuse_lora()
|
| 255 |
|
|
@@ -260,7 +256,7 @@ pipe.fuse_lora()
|
|
| 260 |
try:
|
| 261 |
pipe.enable_vae_slicing()
|
| 262 |
except Exception as e:
|
| 263 |
-
|
| 264 |
|
| 265 |
|
| 266 |
def toggle_output_count(preset_type):
|
|
@@ -301,30 +297,39 @@ def update_prompt_preview(preset_type, base_prompt):
|
|
| 301 |
return preview_text
|
| 302 |
else:
|
| 303 |
return "Select a preset above to see how your base prompt will be modified for batch generation."
|
| 304 |
-
|
| 305 |
-
def update_preset_prompt_textbox(preset_type,
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 316 |
def update_prompt_preview_with_presets(preset_type, base_prompt, custom_presets):
|
|
|
|
| 317 |
if preset_type and preset_type in custom_presets:
|
| 318 |
preset = custom_presets[preset_type]
|
| 319 |
non_empty_prompts = [p for p in preset["prompts"] if p.strip()]
|
| 320 |
if not non_empty_prompts:
|
| 321 |
return "No prompts defined. Please enter at least one prompt in the editor."
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
|
|
|
|
|
|
|
|
|
| 328 |
|
| 329 |
@spaces.GPU()
|
| 330 |
def infer(
|
|
@@ -333,7 +338,7 @@ def infer(
|
|
| 333 |
seed=42,
|
| 334 |
randomize_seed=False,
|
| 335 |
true_guidance_scale=4.0,
|
| 336 |
-
num_inference_steps=
|
| 337 |
rewrite_prompt=True,
|
| 338 |
num_images_per_prompt=1,
|
| 339 |
preset_type=None,
|
|
@@ -341,8 +346,6 @@ def infer(
|
|
| 341 |
):
|
| 342 |
"""Image editing endpoint with optimized prompt handling - now uses fresh presets"""
|
| 343 |
# Resize image to max 1024px on longest side
|
| 344 |
-
session_presets = preset_state.value
|
| 345 |
-
|
| 346 |
def resize_image(pil_image, max_size=1024):
|
| 347 |
"""Resize image to maximum dimension of 1024px while maintaining aspect ratio"""
|
| 348 |
try:
|
|
@@ -358,10 +361,10 @@ def infer(
|
|
| 358 |
new_height = int(height * scale)
|
| 359 |
# Resize image
|
| 360 |
resized_image = pil_image.resize((new_width, new_height), Image.LANCZOS)
|
| 361 |
-
|
| 362 |
return resized_image
|
| 363 |
except Exception as e:
|
| 364 |
-
|
| 365 |
return pil_image # Return original if resize fails
|
| 366 |
|
| 367 |
# Add noise function for batch variation
|
|
@@ -379,11 +382,11 @@ def infer(
|
|
| 379 |
noisy_array = (noisy_array * 255).astype(np.uint8)
|
| 380 |
return Image.fromarray(noisy_array)
|
| 381 |
except Exception as e:
|
| 382 |
-
|
| 383 |
return pil_image # Return original if noise addition fails
|
| 384 |
|
| 385 |
# Get fresh presets for this session
|
| 386 |
-
|
| 387 |
|
| 388 |
# Resize input image first
|
| 389 |
image = resize_image(image, max_size=1024)
|
|
@@ -399,19 +402,19 @@ def infer(
|
|
| 399 |
batch_prompts = [f"{original_prompt}, {preset_prompt}" for preset_prompt in non_empty_preset_prompts]
|
| 400 |
num_images_per_prompt = len(non_empty_preset_prompts) # Use actual count of non-empty prompts
|
| 401 |
prompt_info = (
|
| 402 |
-
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #2196F3;>"
|
| 403 |
f"<h4 style='margin-top: 0;'>🎨 Preset: {preset_type}</h4>"
|
| 404 |
f"<p>{preset['description']}</p>"
|
| 405 |
f"<p><strong>Base Prompt:</strong> {original_prompt}</p>"
|
| 406 |
f"<p>Generating {len(non_empty_preset_prompts)} image{'s' if len(non_empty_preset_prompts) > 1 else ''}</p>"
|
| 407 |
f"</div>"
|
| 408 |
)
|
| 409 |
-
|
| 410 |
else:
|
| 411 |
# Fallback to manual if no valid prompts
|
| 412 |
batch_prompts = [prompt]
|
| 413 |
prompt_info = (
|
| 414 |
-
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #FF9800;>"
|
| 415 |
f"<h4 style='margin-top: 0;'>⚠️ Invalid Preset</h4>"
|
| 416 |
f"<p>No valid prompts found. Using manual prompt.</p>"
|
| 417 |
f"<p><strong>Prompt:</strong> {original_prompt}</p>"
|
|
@@ -420,13 +423,12 @@ def infer(
|
|
| 420 |
else:
|
| 421 |
batch_prompts = [prompt] # Single prompt in list
|
| 422 |
# Handle regular prompt rewriting
|
| 423 |
-
|
| 424 |
if rewrite_prompt:
|
| 425 |
try:
|
| 426 |
enhanced_instruction = polish_prompt(original_prompt)
|
| 427 |
if enhanced_instruction and enhanced_instruction != original_prompt:
|
| 428 |
prompt_info = (
|
| 429 |
-
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #4CAF50;>"
|
| 430 |
f"<h4 style='margin-top: 0;'>🚀 Prompt Enhancement</h4>"
|
| 431 |
f"<p><strong>Original:</strong> {original_prompt}</p>"
|
| 432 |
f"<p><strong style='color:#2E7D32;'>Enhanced:</strong> {enhanced_instruction}</p>"
|
|
@@ -435,23 +437,23 @@ def infer(
|
|
| 435 |
batch_prompts = [enhanced_instruction]
|
| 436 |
else:
|
| 437 |
prompt_info = (
|
| 438 |
-
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #FF9800;>"
|
| 439 |
f"<h4 style='margin-top: 0;'>📝 Prompt Enhancement</h4>"
|
| 440 |
f"<p>No enhancement applied or enhancement failed</p>"
|
| 441 |
f"</div>"
|
| 442 |
)
|
| 443 |
except Exception as e:
|
| 444 |
-
|
| 445 |
gr.Warning(f"Prompt enhancement failed: {str(e)}")
|
| 446 |
prompt_info = (
|
| 447 |
-
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #FF5252;>"
|
| 448 |
f"<h4 style='margin-top: 0;'>⚠️ Enhancement Not Applied</h4>"
|
| 449 |
f"<p>Using original prompt. Error: {str(e)[:100]}</p>"
|
| 450 |
f"</div>"
|
| 451 |
)
|
| 452 |
else:
|
| 453 |
prompt_info = (
|
| 454 |
-
f"<div style='margin:10px; padding:10px; border-radius:8px;>"
|
| 455 |
f"<h4 style='margin-top: 0;'>📝 Original Prompt</h4>"
|
| 456 |
f"<p>{original_prompt}</p>"
|
| 457 |
f"</div>"
|
|
@@ -481,10 +483,10 @@ def infer(
|
|
| 481 |
num_inference_steps=num_inference_steps,
|
| 482 |
generator=generator,
|
| 483 |
true_cfg_scale=varied_guidance,
|
| 484 |
-
num_images_per_prompt=
|
| 485 |
).images
|
| 486 |
edited_images.extend(result)
|
| 487 |
-
|
| 488 |
# Clear cache after generation
|
| 489 |
# if device == "cuda":
|
| 490 |
# torch.cuda.empty_cache()
|
|
@@ -497,17 +499,23 @@ def infer(
|
|
| 497 |
gc.collect()
|
| 498 |
gr.Error(f"Image generation failed: {str(e)}")
|
| 499 |
return [], base_seed, (
|
| 500 |
-
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #dd2c00;>"
|
| 501 |
f"<h4 style='margin-top: 0;'>⚠️ Processing Error</h4>"
|
| 502 |
f"<p>{str(e)[:200]}</p>"
|
| 503 |
f"</div>"
|
| 504 |
)
|
| 505 |
|
| 506 |
-
with gr.Blocks(title="
|
| 507 |
preset_prompts_state = gr.State(value=[])
|
| 508 |
# preset_prompts_state = gr.State(value=["", "", "", ""])
|
| 509 |
-
|
| 510 |
-
gr.Markdown("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 511 |
|
| 512 |
with gr.Row(equal_height=True):
|
| 513 |
# Input Column
|
|
@@ -516,15 +524,8 @@ with gr.Blocks(title="'Qwen Image Edit' Model Playground & Showcase [4-Step Ligh
|
|
| 516 |
label="Source Image",
|
| 517 |
type="pil",
|
| 518 |
height=300
|
| 519 |
-
)
|
| 520 |
-
|
| 521 |
-
result = gr.Gallery(
|
| 522 |
-
label="Edited Images",
|
| 523 |
-
columns=2,
|
| 524 |
-
container=True
|
| 525 |
-
)
|
| 526 |
-
with gr.Row():
|
| 527 |
-
with gr.Column(scale=1):
|
| 528 |
prompt = gr.Textbox(
|
| 529 |
label="Edit Instructions / Base Prompt",
|
| 530 |
placeholder="e.g. Replace the background with a beach sunset... When a preset is selected, use as the base prompt, e.g. the lamborghini",
|
|
@@ -547,11 +548,13 @@ with gr.Blocks(title="'Qwen Image Edit' Model Playground & Showcase [4-Step Ligh
|
|
| 547 |
preset_prompt_2 = gr.Textbox(label="Prompt 2", lines=1, value="")
|
| 548 |
preset_prompt_3 = gr.Textbox(label="Prompt 3", lines=1, value="")
|
| 549 |
preset_prompt_4 = gr.Textbox(label="Prompt 4", lines=1, value="")
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
| 554 |
-
|
|
|
|
|
|
|
| 555 |
|
| 556 |
# Add prompt preview component
|
| 557 |
prompt_preview = gr.Textbox(
|
|
@@ -562,14 +565,6 @@ with gr.Blocks(title="'Qwen Image Edit' Model Playground & Showcase [4-Step Ligh
|
|
| 562 |
value="Enter a base prompt and select a preset above to see how your prompt will be modified for batch generation.",
|
| 563 |
placeholder="Prompt preview will appear here..."
|
| 564 |
)
|
| 565 |
-
|
| 566 |
-
rewrite_toggle = gr.Checkbox(
|
| 567 |
-
label="Additional Prompt Enhancement",
|
| 568 |
-
info="Setting this to true will pass the basic prompt(s) generated via the static preset template to a secondary LLM tasked with improving the overall cohesiveness and details of the final generation prompt.",
|
| 569 |
-
value=True,
|
| 570 |
-
interactive=True
|
| 571 |
-
)
|
| 572 |
-
|
| 573 |
run_button = gr.Button(
|
| 574 |
"Generate Edit(s)",
|
| 575 |
variant="primary"
|
|
@@ -593,14 +588,14 @@ with gr.Blocks(title="'Qwen Image Edit' Model Playground & Showcase [4-Step Ligh
|
|
| 593 |
minimum=1.0,
|
| 594 |
maximum=10.0,
|
| 595 |
step=0.1,
|
| 596 |
-
value=1.
|
| 597 |
)
|
| 598 |
num_inference_steps = gr.Slider(
|
| 599 |
label="Inference Steps",
|
| 600 |
-
minimum=
|
| 601 |
maximum=16,
|
| 602 |
step=1,
|
| 603 |
-
value=
|
| 604 |
)
|
| 605 |
|
| 606 |
num_images_per_prompt = gr.Slider(
|
|
@@ -612,33 +607,45 @@ with gr.Blocks(title="'Qwen Image Edit' Model Playground & Showcase [4-Step Ligh
|
|
| 612 |
interactive=True
|
| 613 |
)
|
| 614 |
|
|
|
|
| 615 |
with gr.Column(scale=2):
|
| 616 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 617 |
value="<div style='padding:15px; margin-top:15px'>"
|
| 618 |
-
"
|
| 619 |
)
|
| 620 |
-
|
| 621 |
-
|
| 622 |
def show_preset_editor(preset_type):
|
| 623 |
-
if preset_type and preset_type in
|
| 624 |
-
preset =
|
| 625 |
-
prompts = preset["prompts"]
|
| 626 |
-
|
|
|
|
|
|
|
|
|
|
| 627 |
return gr.Group(visible=False), "", "", "", ""
|
| 628 |
-
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
|
|
|
|
|
|
| 633 |
return gr.Slider(interactive=True)
|
| 634 |
|
| 635 |
# Update the preset_dropdown.change handlers to use ORIGINAL_PRESETS
|
| 636 |
preset_dropdown.change(
|
| 637 |
-
fn=
|
| 638 |
-
inputs=
|
| 639 |
-
outputs=[preset_editor, preset_prompt_1, preset_prompt_2, preset_prompt_3, preset_prompt_4]
|
| 640 |
)
|
| 641 |
-
|
| 642 |
|
| 643 |
preset_dropdown.change(
|
| 644 |
fn=update_prompt_preview,
|
|
@@ -646,28 +653,6 @@ with gr.Blocks(title="'Qwen Image Edit' Model Playground & Showcase [4-Step Ligh
|
|
| 646 |
outputs=prompt_preview
|
| 647 |
)
|
| 648 |
|
| 649 |
-
preset_prompt_1.change(
|
| 650 |
-
fn=update_preset_prompt_textbox,
|
| 651 |
-
inputs=[preset_dropdown, preset_prompt_1, preset_prompt_2, preset_prompt_3, preset_prompt_4],
|
| 652 |
-
outputs=prompt_preview
|
| 653 |
-
)
|
| 654 |
-
|
| 655 |
-
preset_prompt_2.change(
|
| 656 |
-
fn=update_preset_prompt_textbox,
|
| 657 |
-
inputs=[preset_dropdown, preset_prompt_1, preset_prompt_2, preset_prompt_3, preset_prompt_4],
|
| 658 |
-
outputs=prompt_preview
|
| 659 |
-
)
|
| 660 |
-
preset_prompt_3.change(
|
| 661 |
-
fn=update_preset_prompt_textbox,
|
| 662 |
-
inputs=[preset_dropdown, preset_prompt_1, preset_prompt_2, preset_prompt_3, preset_prompt_4],
|
| 663 |
-
outputs=prompt_preview
|
| 664 |
-
)
|
| 665 |
-
preset_prompt_4.change(
|
| 666 |
-
fn=update_preset_prompt_textbox,
|
| 667 |
-
inputs=[preset_dropdown, preset_prompt_1, preset_prompt_2, preset_prompt_3, preset_prompt_4],
|
| 668 |
-
outputs=prompt_preview
|
| 669 |
-
)
|
| 670 |
-
|
| 671 |
preset_prompt_1.change(
|
| 672 |
fn=update_preset_count,
|
| 673 |
inputs=[preset_dropdown, preset_prompt_1, preset_prompt_2, preset_prompt_3, preset_prompt_4],
|
|
@@ -720,14 +705,10 @@ with gr.Blocks(title="'Qwen Image Edit' Model Playground & Showcase [4-Step Ligh
|
|
| 720 |
inputs=inputs,
|
| 721 |
outputs=outputs
|
| 722 |
)
|
| 723 |
-
# .then(
|
| 724 |
-
# fn=reset_presets, outputs=preset_state
|
| 725 |
-
# )
|
| 726 |
prompt.submit(
|
| 727 |
fn=infer,
|
| 728 |
inputs=inputs,
|
| 729 |
outputs=outputs
|
| 730 |
)
|
| 731 |
-
reset_button.click(fn=reset_presets, outputs=preset_state)
|
| 732 |
|
| 733 |
demo.queue(max_size=5).launch()
|
|
|
|
| 15 |
import json # Added json import
|
| 16 |
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
|
| 17 |
import logging
|
|
|
|
| 18 |
from copy import deepcopy
|
| 19 |
+
|
| 20 |
#############################
|
| 21 |
os.environ.setdefault('GRADIO_ANALYTICS_ENABLED', 'False')
|
| 22 |
os.environ.setdefault('HF_HUB_DISABLE_TELEMETRY', '1')
|
|
|
|
| 47 |
quantization_config=bnb_config,
|
| 48 |
)
|
| 49 |
|
|
|
|
|
|
|
|
|
|
| 50 |
def get_fresh_presets():
|
| 51 |
+
"""Return a fresh copy of presets to avoid persistence across users"""
|
| 52 |
+
return deepcopy(PRESETS)
|
| 53 |
|
| 54 |
+
# Store original presets for reference
|
| 55 |
+
ORIGINAL_PRESETS = deepcopy(PRESETS)
|
| 56 |
|
|
|
|
|
|
|
|
|
|
| 57 |
# Preload enhancement model at startup
|
| 58 |
+
print("🔄 Loading prompt enhancement model...")
|
| 59 |
rewriter_tokenizer = AutoTokenizer.from_pretrained(REWRITER_MODEL)
|
| 60 |
+
print("✅ Enhancement model loaded and ready!")
|
| 61 |
|
| 62 |
SYSTEM_PROMPT_EDIT = '''
|
| 63 |
# Edit Instruction Rewriter
|
|
|
|
| 113 |
end_idx = model_output.rfind('}')
|
| 114 |
# Fix the condition - check if brackets were found
|
| 115 |
if start_idx == -1 or end_idx == -1 or start_idx >= end_idx:
|
| 116 |
+
print(f"No valid JSON structure found in output. Start: {start_idx}, End: {end_idx}")
|
| 117 |
return None
|
| 118 |
# Expand to the full object including outer braces
|
| 119 |
end_idx += 1 # Include the closing brace
|
|
|
|
| 153 |
if str_values:
|
| 154 |
return str_values[0].strip()
|
| 155 |
except Exception as e:
|
| 156 |
+
print(f"JSON parse error: {str(e)}")
|
| 157 |
+
print(f"Model output was: {model_output}")
|
| 158 |
return None
|
| 159 |
|
| 160 |
def polish_prompt(original_prompt: str) -> str:
|
|
|
|
| 173 |
with torch.no_grad():
|
| 174 |
generated_ids = rewriter_model.generate(
|
| 175 |
**model_inputs,
|
| 176 |
+
max_new_tokens=256,
|
| 177 |
do_sample=True,
|
| 178 |
+
temperature=0.7,
|
| 179 |
+
top_p=0.8,
|
| 180 |
repetition_penalty=1.1,
|
| 181 |
no_repeat_ngram_size=3,
|
| 182 |
pad_token_id=rewriter_tokenizer.eos_token_id
|
|
|
|
| 186 |
generated_ids[0][model_inputs.input_ids.shape[1]:],
|
| 187 |
skip_special_tokens=True
|
| 188 |
).strip()
|
| 189 |
+
print(f"Original Prompt: {original_prompt}")
|
| 190 |
+
print(f"Model raw output: {enhanced}") # Debug logging
|
| 191 |
# Try to extract JSON content
|
| 192 |
rewritten_prompt = extract_json_response(enhanced)
|
| 193 |
if rewritten_prompt:
|
|
|
|
| 245 |
pipe.load_lora_weights(
|
| 246 |
"lightx2v/Qwen-Image-Lightning",
|
| 247 |
# weight_name="Qwen-Image-Lightning-8steps-V1.1.safetensors"
|
| 248 |
+
weight_name="Qwen-Image-Lightning-4steps-V1.0.safetensors"
|
| 249 |
)
|
| 250 |
pipe.fuse_lora()
|
| 251 |
|
|
|
|
| 256 |
try:
|
| 257 |
pipe.enable_vae_slicing()
|
| 258 |
except Exception as e:
|
| 259 |
+
print(f"VAE Slicing Failed: {e}")
|
| 260 |
|
| 261 |
|
| 262 |
def toggle_output_count(preset_type):
|
|
|
|
| 297 |
return preview_text
|
| 298 |
else:
|
| 299 |
return "Select a preset above to see how your base prompt will be modified for batch generation."
|
| 300 |
+
|
| 301 |
+
def update_preset_prompt_textbox(preset_type, prompt_1, prompt_2, prompt_3, prompt_4):
|
| 302 |
+
"""Update preset prompts based on user input - now works with session copy"""
|
| 303 |
+
if preset_type and preset_type in ORIGINAL_PRESETS:
|
| 304 |
+
# Update each prompt in the preset copy (this won't persist globally)
|
| 305 |
+
new_prompts = [prompt_1, prompt_2, prompt_3, prompt_4]
|
| 306 |
+
# Create a working copy for preview purposes
|
| 307 |
+
working_presets = get_fresh_presets()
|
| 308 |
+
for i, new_prompt in enumerate(new_prompts):
|
| 309 |
+
if i < len(working_presets[preset_type]["prompts"]):
|
| 310 |
+
working_presets[preset_type]["prompts"][i] = new_prompt.strip()
|
| 311 |
+
else:
|
| 312 |
+
working_presets[preset_type]["prompts"].append(new_prompt.strip())
|
| 313 |
+
# Return updated preset info for preview
|
| 314 |
+
return update_prompt_preview_with_presets(preset_type, "your subject", working_presets)
|
| 315 |
+
return "Select a preset first to edit its prompts."
|
| 316 |
+
|
| 317 |
def update_prompt_preview_with_presets(preset_type, base_prompt, custom_presets):
|
| 318 |
+
"""Update the prompt preview display with custom presets"""
|
| 319 |
if preset_type and preset_type in custom_presets:
|
| 320 |
preset = custom_presets[preset_type]
|
| 321 |
non_empty_prompts = [p for p in preset["prompts"] if p.strip()]
|
| 322 |
if not non_empty_prompts:
|
| 323 |
return "No prompts defined. Please enter at least one prompt in the editor."
|
| 324 |
+
preview_text = f"**Preset: {preset_type}**\n\n"
|
| 325 |
+
preview_text += f"*{preset['description']}*\n\n"
|
| 326 |
+
preview_text += f"**Generating {len(non_empty_prompts)} image{'s' if len(non_empty_prompts) > 1 else ''}:**\n"
|
| 327 |
+
for i, preset_prompt in enumerate(non_empty_prompts, 1):
|
| 328 |
+
full_prompt = f"{base_prompt}, {preset_prompt}"
|
| 329 |
+
preview_text += f"{i}. {full_prompt}\n"
|
| 330 |
+
return preview_text
|
| 331 |
+
else:
|
| 332 |
+
return "Select a preset above to see how your base prompt will be modified for batch generation."
|
| 333 |
|
| 334 |
@spaces.GPU()
|
| 335 |
def infer(
|
|
|
|
| 338 |
seed=42,
|
| 339 |
randomize_seed=False,
|
| 340 |
true_guidance_scale=4.0,
|
| 341 |
+
num_inference_steps=4,
|
| 342 |
rewrite_prompt=True,
|
| 343 |
num_images_per_prompt=1,
|
| 344 |
preset_type=None,
|
|
|
|
| 346 |
):
|
| 347 |
"""Image editing endpoint with optimized prompt handling - now uses fresh presets"""
|
| 348 |
# Resize image to max 1024px on longest side
|
|
|
|
|
|
|
| 349 |
def resize_image(pil_image, max_size=1024):
|
| 350 |
"""Resize image to maximum dimension of 1024px while maintaining aspect ratio"""
|
| 351 |
try:
|
|
|
|
| 361 |
new_height = int(height * scale)
|
| 362 |
# Resize image
|
| 363 |
resized_image = pil_image.resize((new_width, new_height), Image.LANCZOS)
|
| 364 |
+
print(f"📝 Image resized from {width}x{height} to {new_width}x{new_height}")
|
| 365 |
return resized_image
|
| 366 |
except Exception as e:
|
| 367 |
+
print(f"⚠️ Image resize failed: {e}")
|
| 368 |
return pil_image # Return original if resize fails
|
| 369 |
|
| 370 |
# Add noise function for batch variation
|
|
|
|
| 382 |
noisy_array = (noisy_array * 255).astype(np.uint8)
|
| 383 |
return Image.fromarray(noisy_array)
|
| 384 |
except Exception as e:
|
| 385 |
+
print(f"Warning: Could not add noise to image: {e}")
|
| 386 |
return pil_image # Return original if noise addition fails
|
| 387 |
|
| 388 |
# Get fresh presets for this session
|
| 389 |
+
session_presets = get_fresh_presets()
|
| 390 |
|
| 391 |
# Resize input image first
|
| 392 |
image = resize_image(image, max_size=1024)
|
|
|
|
| 402 |
batch_prompts = [f"{original_prompt}, {preset_prompt}" for preset_prompt in non_empty_preset_prompts]
|
| 403 |
num_images_per_prompt = len(non_empty_preset_prompts) # Use actual count of non-empty prompts
|
| 404 |
prompt_info = (
|
| 405 |
+
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #2196F3; background: #f0f8ff'>"
|
| 406 |
f"<h4 style='margin-top: 0;'>🎨 Preset: {preset_type}</h4>"
|
| 407 |
f"<p>{preset['description']}</p>"
|
| 408 |
f"<p><strong>Base Prompt:</strong> {original_prompt}</p>"
|
| 409 |
f"<p>Generating {len(non_empty_preset_prompts)} image{'s' if len(non_empty_preset_prompts) > 1 else ''}</p>"
|
| 410 |
f"</div>"
|
| 411 |
)
|
| 412 |
+
print(f"Using preset: {preset_type} with {len(batch_prompts)} variations")
|
| 413 |
else:
|
| 414 |
# Fallback to manual if no valid prompts
|
| 415 |
batch_prompts = [prompt]
|
| 416 |
prompt_info = (
|
| 417 |
+
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #FF9800; background: #fff8f0'>"
|
| 418 |
f"<h4 style='margin-top: 0;'>⚠️ Invalid Preset</h4>"
|
| 419 |
f"<p>No valid prompts found. Using manual prompt.</p>"
|
| 420 |
f"<p><strong>Prompt:</strong> {original_prompt}</p>"
|
|
|
|
| 423 |
else:
|
| 424 |
batch_prompts = [prompt] # Single prompt in list
|
| 425 |
# Handle regular prompt rewriting
|
|
|
|
| 426 |
if rewrite_prompt:
|
| 427 |
try:
|
| 428 |
enhanced_instruction = polish_prompt(original_prompt)
|
| 429 |
if enhanced_instruction and enhanced_instruction != original_prompt:
|
| 430 |
prompt_info = (
|
| 431 |
+
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #4CAF50; background: #f5f9fe'>"
|
| 432 |
f"<h4 style='margin-top: 0;'>🚀 Prompt Enhancement</h4>"
|
| 433 |
f"<p><strong>Original:</strong> {original_prompt}</p>"
|
| 434 |
f"<p><strong style='color:#2E7D32;'>Enhanced:</strong> {enhanced_instruction}</p>"
|
|
|
|
| 437 |
batch_prompts = [enhanced_instruction]
|
| 438 |
else:
|
| 439 |
prompt_info = (
|
| 440 |
+
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #FF9800; background: #fff8f0'>"
|
| 441 |
f"<h4 style='margin-top: 0;'>📝 Prompt Enhancement</h4>"
|
| 442 |
f"<p>No enhancement applied or enhancement failed</p>"
|
| 443 |
f"</div>"
|
| 444 |
)
|
| 445 |
except Exception as e:
|
| 446 |
+
print(f"Prompt enhancement error: {str(e)}") # Debug logging
|
| 447 |
gr.Warning(f"Prompt enhancement failed: {str(e)}")
|
| 448 |
prompt_info = (
|
| 449 |
+
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #FF5252; background: #fef5f5'>"
|
| 450 |
f"<h4 style='margin-top: 0;'>⚠️ Enhancement Not Applied</h4>"
|
| 451 |
f"<p>Using original prompt. Error: {str(e)[:100]}</p>"
|
| 452 |
f"</div>"
|
| 453 |
)
|
| 454 |
else:
|
| 455 |
prompt_info = (
|
| 456 |
+
f"<div style='margin:10px; padding:10px; border-radius:8px; background: #f8f9fa'>"
|
| 457 |
f"<h4 style='margin-top: 0;'>📝 Original Prompt</h4>"
|
| 458 |
f"<p>{original_prompt}</p>"
|
| 459 |
f"</div>"
|
|
|
|
| 483 |
num_inference_steps=num_inference_steps,
|
| 484 |
generator=generator,
|
| 485 |
true_cfg_scale=varied_guidance,
|
| 486 |
+
num_images_per_prompt=1
|
| 487 |
).images
|
| 488 |
edited_images.extend(result)
|
| 489 |
+
print(f"Generated image {i+1}/{len(batch_prompts)} with prompt: {current_prompt[:75]}...")
|
| 490 |
# Clear cache after generation
|
| 491 |
# if device == "cuda":
|
| 492 |
# torch.cuda.empty_cache()
|
|
|
|
| 499 |
gc.collect()
|
| 500 |
gr.Error(f"Image generation failed: {str(e)}")
|
| 501 |
return [], base_seed, (
|
| 502 |
+
f"<div style='margin:10px; padding:15px; border-radius:8px; border-left:4px solid #dd2c00; background: #fef5f5'>"
|
| 503 |
f"<h4 style='margin-top: 0;'>⚠️ Processing Error</h4>"
|
| 504 |
f"<p>{str(e)[:200]}</p>"
|
| 505 |
f"</div>"
|
| 506 |
)
|
| 507 |
|
| 508 |
+
with gr.Blocks(title="Qwen Image Edit - Fast Lightning Mode w/ Batch") as demo:
|
| 509 |
preset_prompts_state = gr.State(value=[])
|
| 510 |
# preset_prompts_state = gr.State(value=["", "", "", ""])
|
| 511 |
+
|
| 512 |
+
gr.Markdown("""
|
| 513 |
+
<div style="text-align: center; background: linear-gradient(to right, #3a7bd5, #00d2ff); color: white; padding: 20px; border-radius: 8px;">
|
| 514 |
+
<h1 style="margin-bottom: 5px;">⚡️ Qwen-Image-Edit Lightning</h1>
|
| 515 |
+
<p>✨ 4-step inferencing with lightx2v's LoRA.</p>
|
| 516 |
+
<p>📝 Local Prompt Enhancement, Batched Multi-image Generation, 🎨 Preset Batches</p>
|
| 517 |
+
</div>
|
| 518 |
+
""")
|
| 519 |
|
| 520 |
with gr.Row(equal_height=True):
|
| 521 |
# Input Column
|
|
|
|
| 524 |
label="Source Image",
|
| 525 |
type="pil",
|
| 526 |
height=300
|
| 527 |
+
)
|
| 528 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
prompt = gr.Textbox(
|
| 530 |
label="Edit Instructions / Base Prompt",
|
| 531 |
placeholder="e.g. Replace the background with a beach sunset... When a preset is selected, use as the base prompt, e.g. the lamborghini",
|
|
|
|
| 548 |
preset_prompt_2 = gr.Textbox(label="Prompt 2", lines=1, value="")
|
| 549 |
preset_prompt_3 = gr.Textbox(label="Prompt 3", lines=1, value="")
|
| 550 |
preset_prompt_4 = gr.Textbox(label="Prompt 4", lines=1, value="")
|
| 551 |
+
update_preset_button = gr.Button("Update Preset", variant="secondary")
|
| 552 |
+
|
| 553 |
+
rewrite_toggle = gr.Checkbox(
|
| 554 |
+
label="Enable Prompt Enhancement",
|
| 555 |
+
value=True,
|
| 556 |
+
interactive=True
|
| 557 |
+
)
|
| 558 |
|
| 559 |
# Add prompt preview component
|
| 560 |
prompt_preview = gr.Textbox(
|
|
|
|
| 565 |
value="Enter a base prompt and select a preset above to see how your prompt will be modified for batch generation.",
|
| 566 |
placeholder="Prompt preview will appear here..."
|
| 567 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 568 |
run_button = gr.Button(
|
| 569 |
"Generate Edit(s)",
|
| 570 |
variant="primary"
|
|
|
|
| 588 |
minimum=1.0,
|
| 589 |
maximum=10.0,
|
| 590 |
step=0.1,
|
| 591 |
+
value=1.0
|
| 592 |
)
|
| 593 |
num_inference_steps = gr.Slider(
|
| 594 |
label="Inference Steps",
|
| 595 |
+
minimum=2,
|
| 596 |
maximum=16,
|
| 597 |
step=1,
|
| 598 |
+
value=4
|
| 599 |
)
|
| 600 |
|
| 601 |
num_images_per_prompt = gr.Slider(
|
|
|
|
| 607 |
interactive=True
|
| 608 |
)
|
| 609 |
|
| 610 |
+
# Output Column
|
| 611 |
with gr.Column(scale=2):
|
| 612 |
+
result = gr.Gallery(
|
| 613 |
+
label="Edited Images",
|
| 614 |
+
columns=lambda x: min(x, 2),
|
| 615 |
+
height=500,
|
| 616 |
+
object_fit="cover",
|
| 617 |
+
preview=True
|
| 618 |
+
)
|
| 619 |
+
prompt_info = gr.HTML(
|
| 620 |
value="<div style='padding:15px; margin-top:15px'>"
|
| 621 |
+
"Prompt details will appear after generation. Ability to edit Preset Prompts on the fly will be implemented shortly.</div>"
|
| 622 |
)
|
| 623 |
+
|
| 624 |
+
# Fix the show_preset_editor function to use ORIGINAL_PRESETS:
|
| 625 |
def show_preset_editor(preset_type):
|
| 626 |
+
if preset_type and preset_type in ORIGINAL_PRESETS: # Changed from PRESETS to ORIGINAL_PRESETS
|
| 627 |
+
preset = ORIGINAL_PRESETS[preset_type]
|
| 628 |
+
prompts = preset["prompts"]
|
| 629 |
+
# Pad prompts to 4 items if needed
|
| 630 |
+
while len(prompts) < 4:
|
| 631 |
+
prompts.append("")
|
| 632 |
+
return gr.Group(visible=True), prompts[0], prompts[1], prompts[2], prompts[3]
|
| 633 |
return gr.Group(visible=False), "", "", "", ""
|
| 634 |
+
|
| 635 |
+
# Fix the update_preset_count function to use ORIGINAL_PRESETS:
|
| 636 |
+
def update_preset_count(preset_type, prompt_1, prompt_2, prompt_3, prompt_4):
|
| 637 |
+
"""Update the output count slider based on non-empty preset prompts"""
|
| 638 |
+
if preset_type and preset_type in ORIGINAL_PRESETS: # Changed from PRESETS to ORIGINAL_PRESETS
|
| 639 |
+
non_empty_count = len([p for p in [prompt_1, prompt_2, prompt_3, prompt_4] if p.strip()])
|
| 640 |
+
return gr.Slider(value=max(1, min(4, non_empty_count)), interactive=False)
|
| 641 |
return gr.Slider(interactive=True)
|
| 642 |
|
| 643 |
# Update the preset_dropdown.change handlers to use ORIGINAL_PRESETS
|
| 644 |
preset_dropdown.change(
|
| 645 |
+
fn=toggle_output_count,
|
| 646 |
+
inputs=preset_dropdown,
|
| 647 |
+
outputs=[preset_editor, num_images_per_prompt, preset_prompt_1, preset_prompt_2, preset_prompt_3, preset_prompt_4]
|
| 648 |
)
|
|
|
|
| 649 |
|
| 650 |
preset_dropdown.change(
|
| 651 |
fn=update_prompt_preview,
|
|
|
|
| 653 |
outputs=prompt_preview
|
| 654 |
)
|
| 655 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 656 |
preset_prompt_1.change(
|
| 657 |
fn=update_preset_count,
|
| 658 |
inputs=[preset_dropdown, preset_prompt_1, preset_prompt_2, preset_prompt_3, preset_prompt_4],
|
|
|
|
| 705 |
inputs=inputs,
|
| 706 |
outputs=outputs
|
| 707 |
)
|
|
|
|
|
|
|
|
|
|
| 708 |
prompt.submit(
|
| 709 |
fn=infer,
|
| 710 |
inputs=inputs,
|
| 711 |
outputs=outputs
|
| 712 |
)
|
|
|
|
| 713 |
|
| 714 |
demo.queue(max_size=5).launch()
|
presets.py
CHANGED
|
@@ -30,9 +30,9 @@ PRESETS = {
|
|
| 30 |
"prompts": [
|
| 31 |
"frontal view of the subject, facing camera directly",
|
| 32 |
"side view of subject, profile view from the side",
|
| 33 |
-
"
|
| 34 |
],
|
| 35 |
-
"description": "Generate
|
| 36 |
},
|
| 37 |
"Style Variations": {
|
| 38 |
"count": 3,
|
|
@@ -61,143 +61,16 @@ PRESETS = {
|
|
| 61 |
],
|
| 62 |
"description": "Show the subject in different hairstyles"
|
| 63 |
},
|
| 64 |
-
"
|
| 65 |
-
"count":
|
| 66 |
"prompts": [
|
| 67 |
-
"in
|
| 68 |
-
"in
|
| 69 |
-
"in a crisp autumn forest, leaves turning orange",
|
| 70 |
-
"in a misty spring garden, blooming flowers"
|
| 71 |
],
|
| 72 |
-
"description": "
|
| 73 |
-
},
|
| 74 |
-
|
| 75 |
-
"Emotional Mood": {
|
| 76 |
-
"count": 4,
|
| 77 |
-
"prompts": [
|
| 78 |
-
"with a joyful grin, eyes sparkling",
|
| 79 |
-
"with a thoughtful expression, slightly furrowed brow",
|
| 80 |
-
"with a dramatic, intense stare",
|
| 81 |
-
"with a gentle, serene smile"
|
| 82 |
-
],
|
| 83 |
-
"description": "Show the subject’s emotions in four different moods"
|
| 84 |
-
},
|
| 85 |
-
|
| 86 |
-
"Historical Eras": {
|
| 87 |
-
"count": 4,
|
| 88 |
-
"prompts": [
|
| 89 |
-
"in Victorian England, ornate lace and corset",
|
| 90 |
-
"in the 1980s, neon lights and big hair",
|
| 91 |
-
"in a medieval castle, knight armor",
|
| 92 |
-
"in a futuristic cyber‑punk city, holographic backdrop"
|
| 93 |
-
],
|
| 94 |
-
"description": "Place the subject in four iconic time periods"
|
| 95 |
-
},
|
| 96 |
-
|
| 97 |
-
"Camera Lens Effects": {
|
| 98 |
-
"count": 4,
|
| 99 |
-
"prompts": [
|
| 100 |
-
"captured with a wide‑angle lens, exaggerated perspective",
|
| 101 |
-
"shot with a telephoto lens, shallow depth of field",
|
| 102 |
-
"taken with a fisheye lens, circular distortion",
|
| 103 |
-
"rendered with a macro lens, extreme close‑up detail"
|
| 104 |
-
],
|
| 105 |
-
"description": "Play with different lens styles for the same subject"
|
| 106 |
-
},
|
| 107 |
-
|
| 108 |
-
"Fantasy Elements": {
|
| 109 |
-
"count": 3,
|
| 110 |
-
"prompts": [
|
| 111 |
-
"surrounded by a swirling vortex of light",
|
| 112 |
-
"hovering above a floating island in the clouds",
|
| 113 |
-
"paired with a companion dragon, breathing fire",
|
| 114 |
-
],
|
| 115 |
-
"description": "Add a fantastical twist to each rendition"
|
| 116 |
-
},
|
| 117 |
-
|
| 118 |
-
"Texture Variations": {
|
| 119 |
-
"count": 3,
|
| 120 |
-
"prompts": [
|
| 121 |
-
"covered in soft velvet, plush texture",
|
| 122 |
-
"painted with glossy enamel, shiny finish",
|
| 123 |
-
"wrapped in intricate lace patterns",
|
| 124 |
-
],
|
| 125 |
-
"description": "Show the subject in three distinct surface textures"
|
| 126 |
-
},
|
| 127 |
-
|
| 128 |
-
"Color Palette Swaps": {
|
| 129 |
-
"count": 3,
|
| 130 |
-
"prompts": [
|
| 131 |
-
"in pastel colors, soft hues",
|
| 132 |
-
"with neon saturation, high‑contrast glow",
|
| 133 |
-
"in monochrome black & white, dramatic contrast"
|
| 134 |
-
],
|
| 135 |
-
"description": "Recolor the subject with three distinct palettes"
|
| 136 |
-
},
|
| 137 |
-
"Runway Catwalk": {
|
| 138 |
-
"count": 4,
|
| 139 |
-
"prompts": [
|
| 140 |
-
"strutting down a glossy runway, spotlight on the model",
|
| 141 |
-
"walking confidently with a high‑fashion backdrop",
|
| 142 |
-
"posing with a dramatic, angular pose on the catwalk",
|
| 143 |
-
"showcasing an avant‑garde ensemble, dramatic lighting"
|
| 144 |
-
],
|
| 145 |
-
"description": "Capture the model on a high‑end runway"
|
| 146 |
-
},
|
| 147 |
-
|
| 148 |
-
"Vogue Editorial": {
|
| 149 |
-
"count": 3,
|
| 150 |
-
"prompts": [
|
| 151 |
-
"editorial shot with a moody, artistic background",
|
| 152 |
-
"intimate close‑up, dramatic lighting and subtle shadows",
|
| 153 |
-
"wide‑angle full‑body shot, striking composition"
|
| 154 |
-
],
|
| 155 |
-
"description": "Create a magazine‑quality editorial spread"
|
| 156 |
-
},
|
| 157 |
-
"Evening Gown Glam": {
|
| 158 |
-
"count": 3,
|
| 159 |
-
"prompts": [
|
| 160 |
-
"floor‑length ballroom gown, shimmering crystal embellishments",
|
| 161 |
-
"gold‑en, reflective lighting, chandelier backdrop",
|
| 162 |
-
"soft, ethereal glow, elegant pose"
|
| 163 |
-
],
|
| 164 |
-
"description": "Render an elegant evening dress in glamorous lighting"
|
| 165 |
-
},
|
| 166 |
-
|
| 167 |
-
"Chic Streetwear": {
|
| 168 |
-
"count": 4,
|
| 169 |
-
"prompts": [
|
| 170 |
-
"urban street backdrop, high‑contrast graffiti walls",
|
| 171 |
-
"modern athleisure look, bold colors and textures",
|
| 172 |
-
"casual, relaxed pose with a casual jacket and sneakers",
|
| 173 |
-
"dynamic movement shot, capturing fluidity"
|
| 174 |
-
],
|
| 175 |
-
"description": "Showcase the model in trendy street‑style attire"
|
| 176 |
-
},
|
| 177 |
-
"Swimwear Showcase": {
|
| 178 |
-
"count": 4,
|
| 179 |
-
"prompts": [
|
| 180 |
-
"wearing a vibrant neon bikini, sunny beach background",
|
| 181 |
-
"in a sleek one‑piece with high‑waisted cut, poolside setting",
|
| 182 |
-
"sporty swim trunks and matching tank top, surfing wave backdrop",
|
| 183 |
-
"coastal vibe with a chic cover‑up over a solid‑color swimsuit"
|
| 184 |
-
],
|
| 185 |
-
"description": "Highlight the model in four distinct swimwear styles, from bold bikinis to elegant one‑pieces and sporty swimwear"
|
| 186 |
-
},
|
| 187 |
-
"Polaroid and Film": {
|
| 188 |
-
"count": 4,
|
| 189 |
-
"prompts": [
|
| 190 |
-
"captured in a vintage Polaroid frame, sepia‑tone filter, soft vignette",
|
| 191 |
-
"black‑and‑white film shot with a slight grain, high‑contrast lighting",
|
| 192 |
-
"soft focus, pastel color palette with a subtle yellow tint, nostalgic feel",
|
| 193 |
-
"classic instant camera style, square format, warm lighting, subtle bokeh"
|
| 194 |
-
],
|
| 195 |
-
"description": "Generate a nostalgic Polaroid/film aesthetic across four different looks"
|
| 196 |
}
|
| 197 |
}
|
| 198 |
|
| 199 |
-
|
| 200 |
-
|
| 201 |
def get_preset_choices():
|
| 202 |
"""
|
| 203 |
Return list of preset choices for Gradio dropdown.
|
|
|
|
| 30 |
"prompts": [
|
| 31 |
"frontal view of the subject, facing camera directly",
|
| 32 |
"side view of subject, profile view from the side",
|
| 33 |
+
"back side view of subject, showing the rear/back view"
|
| 34 |
],
|
| 35 |
+
"description": "Generate 4 different views of the subject"
|
| 36 |
},
|
| 37 |
"Style Variations": {
|
| 38 |
"count": 3,
|
|
|
|
| 61 |
],
|
| 62 |
"description": "Show the subject in different hairstyles"
|
| 63 |
},
|
| 64 |
+
"Color Comparison": {
|
| 65 |
+
"count": 2,
|
| 66 |
"prompts": [
|
| 67 |
+
"painted in matte black paint and red accents",
|
| 68 |
+
"covered in gold glitter over white fabric"
|
|
|
|
|
|
|
| 69 |
],
|
| 70 |
+
"description": "Simple two-tone color comparison"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
}
|
| 72 |
}
|
| 73 |
|
|
|
|
|
|
|
| 74 |
def get_preset_choices():
|
| 75 |
"""
|
| 76 |
Return list of preset choices for Gradio dropdown.
|