Spaces:
Runtime error
Runtime error
Add animation feature and remove FreeU from standard pipeline
Browse files- Add KSampler animation with intermediate frame preview every 5 steps
- Fix VAE latent scaling (0.18215) for proper preview image quality
- Remove FreeU from standard pipeline (kept in artistic only)
- Increase ZeroGPU duration from 120 to 150 seconds
- Update seed range to 2^32-1 for JSON compatibility
- Update UI descriptions for animation, color quantization, and upscale
- Set artistic pipeline defaults to Japanese temple example
- Add "Change Settings Manually" section descriptions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
app.py
CHANGED
|
@@ -1,5 +1,8 @@
|
|
| 1 |
import os
|
| 2 |
import sys
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
# Force unbuffered output for real-time logging
|
| 5 |
sys.stdout.reconfigure(line_buffering=True)
|
|
@@ -570,7 +573,7 @@ def compile_models_with_aoti():
|
|
| 570 |
return False
|
| 571 |
|
| 572 |
|
| 573 |
-
@spaces.GPU(duration=
|
| 574 |
def generate_qr_code_unified(
|
| 575 |
prompt: str,
|
| 576 |
negative_prompt: str = "ugly, tiling, poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, extra limbs, body out of frame, blurry, bad anatomy, blurred, watermark, grainy, signature, cut off, draft, closed eyes, text, logo",
|
|
@@ -605,6 +608,7 @@ def generate_qr_code_unified(
|
|
| 605 |
apply_gradient_filter: bool = False,
|
| 606 |
gradient_strength: float = 0.3,
|
| 607 |
variation_steps: int = 5,
|
|
|
|
| 608 |
progress=gr.Progress(),
|
| 609 |
):
|
| 610 |
# Only manipulate the text if it's a URL input type
|
|
@@ -616,7 +620,7 @@ def generate_qr_code_unified(
|
|
| 616 |
qr_text = qr_text.replace("http://", "")
|
| 617 |
|
| 618 |
# Use custom seed or random
|
| 619 |
-
actual_seed = seed if use_custom_seed else random.randint(1, 2**
|
| 620 |
|
| 621 |
with torch.inference_mode():
|
| 622 |
if pipeline == "standard":
|
|
@@ -643,6 +647,7 @@ def generate_qr_code_unified(
|
|
| 643 |
apply_gradient_filter=apply_gradient_filter,
|
| 644 |
gradient_strength=gradient_strength,
|
| 645 |
variation_steps=variation_steps,
|
|
|
|
| 646 |
gr_progress=progress,
|
| 647 |
)
|
| 648 |
else: # artistic
|
|
@@ -676,10 +681,124 @@ def generate_qr_code_unified(
|
|
| 676 |
apply_gradient_filter=apply_gradient_filter,
|
| 677 |
gradient_strength=gradient_strength,
|
| 678 |
variation_steps=variation_steps,
|
|
|
|
| 679 |
gr_progress=progress,
|
| 680 |
)
|
| 681 |
|
| 682 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 683 |
def apply_color_quantization(
|
| 684 |
image: Image.Image,
|
| 685 |
colors: list[str],
|
|
@@ -882,7 +1001,7 @@ def generate_standard_qr(
|
|
| 882 |
use_custom_seed: bool = False,
|
| 883 |
seed: int = 0,
|
| 884 |
enable_upscale: bool = False,
|
| 885 |
-
|
| 886 |
controlnet_strength_standard_first: float = 0.45,
|
| 887 |
controlnet_strength_standard_final: float = 1.0,
|
| 888 |
enable_color_quantization: bool = False,
|
|
@@ -898,7 +1017,7 @@ def generate_standard_qr(
|
|
| 898 |
):
|
| 899 |
"""Wrapper function for standard QR generation"""
|
| 900 |
# Get actual seed used (custom or random)
|
| 901 |
-
actual_seed = seed if use_custom_seed else random.randint(1, 2**
|
| 902 |
|
| 903 |
# Create settings JSON once
|
| 904 |
settings_dict = {
|
|
@@ -915,7 +1034,7 @@ def generate_standard_qr(
|
|
| 915 |
"seed": actual_seed,
|
| 916 |
"use_custom_seed": True,
|
| 917 |
"enable_upscale": enable_upscale,
|
| 918 |
-
"
|
| 919 |
"controlnet_strength_standard_first": controlnet_strength_standard_first,
|
| 920 |
"controlnet_strength_standard_final": controlnet_strength_standard_final,
|
| 921 |
"enable_color_quantization": enable_color_quantization,
|
|
@@ -945,6 +1064,7 @@ def generate_standard_qr(
|
|
| 945 |
seed,
|
| 946 |
pipeline="standard",
|
| 947 |
enable_upscale=enable_upscale,
|
|
|
|
| 948 |
controlnet_strength_standard_first=controlnet_strength_standard_first,
|
| 949 |
controlnet_strength_standard_final=controlnet_strength_standard_final,
|
| 950 |
enable_color_quantization=enable_color_quantization,
|
|
@@ -991,6 +1111,7 @@ def generate_artistic_qr(
|
|
| 991 |
use_custom_seed: bool = False,
|
| 992 |
seed: int = 0,
|
| 993 |
enable_upscale: bool = True,
|
|
|
|
| 994 |
enable_freeu: bool = True,
|
| 995 |
freeu_b1: float = 1.4,
|
| 996 |
freeu_b2: float = 1.3,
|
|
@@ -1014,7 +1135,7 @@ def generate_artistic_qr(
|
|
| 1014 |
):
|
| 1015 |
"""Wrapper function for artistic QR generation with FreeU and SAG parameters"""
|
| 1016 |
# Get actual seed used (custom or random)
|
| 1017 |
-
actual_seed = seed if use_custom_seed else random.randint(1, 2**
|
| 1018 |
|
| 1019 |
# Create settings JSON once
|
| 1020 |
settings_dict = {
|
|
@@ -1031,6 +1152,7 @@ def generate_artistic_qr(
|
|
| 1031 |
"seed": actual_seed,
|
| 1032 |
"use_custom_seed": True,
|
| 1033 |
"enable_upscale": enable_upscale,
|
|
|
|
| 1034 |
"enable_freeu": enable_freeu,
|
| 1035 |
"freeu_b1": freeu_b1,
|
| 1036 |
"freeu_b2": freeu_b2,
|
|
@@ -1086,6 +1208,7 @@ def generate_artistic_qr(
|
|
| 1086 |
apply_gradient_filter=apply_gradient_filter,
|
| 1087 |
gradient_strength=gradient_strength,
|
| 1088 |
variation_steps=variation_steps,
|
|
|
|
| 1089 |
progress=progress,
|
| 1090 |
)
|
| 1091 |
|
|
@@ -1192,7 +1315,7 @@ def load_settings_from_json_standard(json_string: str):
|
|
| 1192 |
use_custom_seed = params.get("use_custom_seed", True)
|
| 1193 |
seed = params.get("seed", 718313)
|
| 1194 |
enable_upscale = params.get("enable_upscale", False)
|
| 1195 |
-
|
| 1196 |
controlnet_strength_standard_first = params.get(
|
| 1197 |
"controlnet_strength_standard_first", 0.45
|
| 1198 |
)
|
|
@@ -1223,7 +1346,7 @@ def load_settings_from_json_standard(json_string: str):
|
|
| 1223 |
use_custom_seed,
|
| 1224 |
seed,
|
| 1225 |
enable_upscale,
|
| 1226 |
-
|
| 1227 |
controlnet_strength_standard_first,
|
| 1228 |
controlnet_strength_standard_final,
|
| 1229 |
enable_color_quantization,
|
|
@@ -1604,8 +1727,14 @@ def _pipeline_standard(
|
|
| 1604 |
apply_gradient_filter: bool = False,
|
| 1605 |
gradient_strength: float = 0.3,
|
| 1606 |
variation_steps: int = 5,
|
|
|
|
| 1607 |
gr_progress=None,
|
| 1608 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1609 |
emptylatentimage_5 = emptylatentimage.generate(
|
| 1610 |
width=image_size, height=image_size, batch_size=1
|
| 1611 |
)
|
|
@@ -1711,18 +1840,52 @@ def _pipeline_standard(
|
|
| 1711 |
vae=get_value_at_index(checkpointloadersimple_4, 2),
|
| 1712 |
)
|
| 1713 |
|
| 1714 |
-
|
| 1715 |
-
|
| 1716 |
-
|
| 1717 |
-
|
| 1718 |
-
|
| 1719 |
-
|
| 1720 |
-
|
| 1721 |
-
|
| 1722 |
-
|
| 1723 |
-
|
| 1724 |
-
|
| 1725 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1726 |
|
| 1727 |
# Yield progress update after first sampling completes
|
| 1728 |
msg = "First pass sampling complete... decoding image"
|
|
@@ -1764,18 +1927,52 @@ def _pipeline_standard(
|
|
| 1764 |
vae=get_value_at_index(checkpointloadersimple_4, 2),
|
| 1765 |
)
|
| 1766 |
|
| 1767 |
-
|
| 1768 |
-
|
| 1769 |
-
|
| 1770 |
-
|
| 1771 |
-
|
| 1772 |
-
|
| 1773 |
-
|
| 1774 |
-
|
| 1775 |
-
|
| 1776 |
-
|
| 1777 |
-
|
| 1778 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1779 |
|
| 1780 |
# Yield progress update after second sampling completes
|
| 1781 |
msg = "Second pass sampling complete... decoding final image"
|
|
@@ -1903,8 +2100,14 @@ def _pipeline_artistic(
|
|
| 1903 |
apply_gradient_filter: bool = False,
|
| 1904 |
gradient_strength: float = 0.3,
|
| 1905 |
variation_steps: int = 5,
|
|
|
|
| 1906 |
gr_progress=None,
|
| 1907 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1908 |
# Generate QR code
|
| 1909 |
qr_protocol = "None" if input_type == "Plain Text" else "Https"
|
| 1910 |
|
|
@@ -2060,18 +2263,52 @@ def _pipeline_artistic(
|
|
| 2060 |
# First sampling pass
|
| 2061 |
log_progress("First pass - artistic sampling...", gr_progress, 0.2)
|
| 2062 |
|
| 2063 |
-
|
| 2064 |
-
|
| 2065 |
-
|
| 2066 |
-
|
| 2067 |
-
|
| 2068 |
-
|
| 2069 |
-
|
| 2070 |
-
|
| 2071 |
-
|
| 2072 |
-
|
| 2073 |
-
|
| 2074 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2075 |
|
| 2076 |
# Yield progress update after first sampling completes
|
| 2077 |
msg = f"First pass sampling complete... decoding image (step {current_step}/{total_steps})"
|
|
@@ -2121,18 +2358,52 @@ def _pipeline_artistic(
|
|
| 2121 |
# Final sampling pass
|
| 2122 |
log_progress("Second pass (refinement)...", gr_progress, 0.6)
|
| 2123 |
|
| 2124 |
-
|
| 2125 |
-
|
| 2126 |
-
|
| 2127 |
-
|
| 2128 |
-
|
| 2129 |
-
|
| 2130 |
-
|
| 2131 |
-
|
| 2132 |
-
|
| 2133 |
-
|
| 2134 |
-
|
| 2135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2136 |
|
| 2137 |
# Yield progress update after second sampling completes
|
| 2138 |
msg = f"Second pass sampling complete... decoding final image (step {current_step}/{total_steps})"
|
|
@@ -2244,6 +2515,9 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2244 |
- Include style keywords like 'photorealistic', 'detailed', '8k'
|
| 2245 |
- Choose **URL** mode for web links or **Plain Text** mode for VCARD, WiFi credentials, calendar events, etc.
|
| 2246 |
- Try the examples below for inspiration
|
|
|
|
|
|
|
|
|
|
| 2247 |
- **Copy/paste settings**: After generation, copy the JSON settings string that appears below the image and paste it into "Import Settings from JSON" to reproduce exact results or share with others
|
| 2248 |
|
| 2249 |
### Two Modes:
|
|
@@ -2274,13 +2548,13 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2274 |
artistic_prompt_input = gr.Textbox(
|
| 2275 |
label="Prompt",
|
| 2276 |
placeholder="Describe the image you want to generate (check examples below for inspiration)",
|
| 2277 |
-
value="
|
| 2278 |
lines=3,
|
| 2279 |
)
|
| 2280 |
artistic_text_input = gr.Textbox(
|
| 2281 |
label="QR Code Content",
|
| 2282 |
placeholder="Enter URL or plain text",
|
| 2283 |
-
value="
|
| 2284 |
lines=3,
|
| 2285 |
)
|
| 2286 |
|
|
@@ -2310,6 +2584,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2310 |
|
| 2311 |
# Change Settings Manually - separate accordion
|
| 2312 |
with gr.Accordion("Change Settings Manually", open=False):
|
|
|
|
| 2313 |
# Negative Prompt
|
| 2314 |
negative_prompt_artistic = gr.Textbox(
|
| 2315 |
label="Negative Prompt",
|
|
@@ -2324,9 +2599,9 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2324 |
minimum=512,
|
| 2325 |
maximum=1024,
|
| 2326 |
step=64,
|
| 2327 |
-
value=
|
| 2328 |
label="Image Size",
|
| 2329 |
-
info="Base size of the generated image. Final output will be 2x this size (e.g.,
|
| 2330 |
)
|
| 2331 |
|
| 2332 |
# Add border size slider for artistic QR
|
|
@@ -2347,7 +2622,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2347 |
"Quartile (25%)",
|
| 2348 |
"High (30%)",
|
| 2349 |
],
|
| 2350 |
-
value="
|
| 2351 |
label="Error Correction Level",
|
| 2352 |
info="Higher error correction makes the QR code more scannable when damaged or obscured, but increases its size and complexity. High (30%) is recommended for artistic QR codes.",
|
| 2353 |
)
|
|
@@ -2357,16 +2632,16 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2357 |
minimum=4,
|
| 2358 |
maximum=16,
|
| 2359 |
step=1,
|
| 2360 |
-
value=
|
| 2361 |
label="QR Module Size",
|
| 2362 |
-
info="Pixel width of the smallest QR code unit. Larger values improve readability but require a larger image size.
|
| 2363 |
)
|
| 2364 |
|
| 2365 |
# Add module drawer dropdown with style examples for artistic QR
|
| 2366 |
artistic_module_drawer = gr.Dropdown(
|
| 2367 |
choices=[
|
| 2368 |
"Square",
|
| 2369 |
-
"Gapped
|
| 2370 |
"Circle",
|
| 2371 |
"Rounded",
|
| 2372 |
"Vertical bars",
|
|
@@ -2441,8 +2716,16 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2441 |
info="Enable upscaling with RealESRGAN for higher quality output (enabled by default for artistic pipeline)",
|
| 2442 |
)
|
| 2443 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2444 |
# Color Quantization Section
|
| 2445 |
gr.Markdown("### Color Quantization (Optional)")
|
|
|
|
| 2446 |
artistic_enable_color_quantization = gr.Checkbox(
|
| 2447 |
label="Enable Color Quantization",
|
| 2448 |
value=False,
|
|
@@ -2556,7 +2839,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2556 |
)
|
| 2557 |
artistic_seed = gr.Slider(
|
| 2558 |
minimum=0,
|
| 2559 |
-
maximum=
|
| 2560 |
step=1,
|
| 2561 |
value=718313,
|
| 2562 |
label="Seed",
|
|
@@ -2694,6 +2977,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2694 |
artistic_use_custom_seed,
|
| 2695 |
artistic_seed,
|
| 2696 |
artistic_enable_upscale,
|
|
|
|
| 2697 |
enable_freeu_artistic,
|
| 2698 |
freeu_b1,
|
| 2699 |
freeu_b2,
|
|
@@ -2739,6 +3023,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 2739 |
artistic_use_custom_seed,
|
| 2740 |
artistic_seed,
|
| 2741 |
artistic_enable_upscale,
|
|
|
|
| 2742 |
enable_freeu_artistic,
|
| 2743 |
freeu_b1,
|
| 2744 |
freeu_b2,
|
|
@@ -3193,13 +3478,13 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 3193 |
prompt_input = gr.Textbox(
|
| 3194 |
label="Prompt",
|
| 3195 |
placeholder="Describe the image you want to generate (check examples below for inspiration)",
|
| 3196 |
-
value="
|
| 3197 |
lines=3,
|
| 3198 |
)
|
| 3199 |
text_input = gr.Textbox(
|
| 3200 |
label="QR Code Content",
|
| 3201 |
placeholder="Enter URL or plain text",
|
| 3202 |
-
value="
|
| 3203 |
lines=3,
|
| 3204 |
)
|
| 3205 |
|
|
@@ -3229,6 +3514,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 3229 |
|
| 3230 |
# Change Settings Manually - separate accordion
|
| 3231 |
with gr.Accordion("Change Settings Manually", open=False):
|
|
|
|
| 3232 |
# Negative Prompt
|
| 3233 |
negative_prompt_standard = gr.Textbox(
|
| 3234 |
label="Negative Prompt",
|
|
@@ -3285,7 +3571,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 3285 |
module_drawer = gr.Dropdown(
|
| 3286 |
choices=[
|
| 3287 |
"Square",
|
| 3288 |
-
"Gapped
|
| 3289 |
"Circle",
|
| 3290 |
"Rounded",
|
| 3291 |
"Vertical bars",
|
|
@@ -3360,15 +3646,16 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 3360 |
info="Enable upscaling with RealESRGAN for higher quality output (disabled by default for standard pipeline)",
|
| 3361 |
)
|
| 3362 |
|
| 3363 |
-
#
|
| 3364 |
-
|
| 3365 |
-
label="Enable
|
| 3366 |
-
value=
|
| 3367 |
-
info="
|
| 3368 |
)
|
| 3369 |
|
| 3370 |
# Color Quantization Section
|
| 3371 |
gr.Markdown("### Color Quantization (Optional)")
|
|
|
|
| 3372 |
enable_color_quantization = gr.Checkbox(
|
| 3373 |
label="Enable Color Quantization",
|
| 3374 |
value=False,
|
|
@@ -3478,7 +3765,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 3478 |
)
|
| 3479 |
seed = gr.Slider(
|
| 3480 |
minimum=0,
|
| 3481 |
-
maximum=
|
| 3482 |
step=1,
|
| 3483 |
value=718313,
|
| 3484 |
label="Seed",
|
|
@@ -3550,7 +3837,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 3550 |
use_custom_seed,
|
| 3551 |
seed,
|
| 3552 |
enable_upscale,
|
| 3553 |
-
|
| 3554 |
controlnet_strength_standard_first,
|
| 3555 |
controlnet_strength_standard_final,
|
| 3556 |
enable_color_quantization,
|
|
@@ -3569,6 +3856,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 3569 |
settings_output_standard,
|
| 3570 |
settings_accordion_standard,
|
| 3571 |
],
|
|
|
|
| 3572 |
)
|
| 3573 |
|
| 3574 |
# Load Settings button event handler
|
|
@@ -3588,7 +3876,7 @@ if __name__ == "__main__" and not os.environ.get("QR_TESTING_MODE"):
|
|
| 3588 |
use_custom_seed,
|
| 3589 |
seed,
|
| 3590 |
enable_upscale,
|
| 3591 |
-
|
| 3592 |
controlnet_strength_standard_first,
|
| 3593 |
controlnet_strength_standard_final,
|
| 3594 |
enable_color_quantization,
|
|
|
|
| 1 |
import os
|
| 2 |
import sys
|
| 3 |
+
import time
|
| 4 |
+
import threading
|
| 5 |
+
import queue
|
| 6 |
|
| 7 |
# Force unbuffered output for real-time logging
|
| 8 |
sys.stdout.reconfigure(line_buffering=True)
|
|
|
|
| 573 |
return False
|
| 574 |
|
| 575 |
|
| 576 |
+
@spaces.GPU(duration=150) # Allows time for animation frames during generation
|
| 577 |
def generate_qr_code_unified(
|
| 578 |
prompt: str,
|
| 579 |
negative_prompt: str = "ugly, tiling, poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, extra limbs, body out of frame, blurry, bad anatomy, blurred, watermark, grainy, signature, cut off, draft, closed eyes, text, logo",
|
|
|
|
| 608 |
apply_gradient_filter: bool = False,
|
| 609 |
gradient_strength: float = 0.3,
|
| 610 |
variation_steps: int = 5,
|
| 611 |
+
enable_animation: bool = True,
|
| 612 |
progress=gr.Progress(),
|
| 613 |
):
|
| 614 |
# Only manipulate the text if it's a URL input type
|
|
|
|
| 620 |
qr_text = qr_text.replace("http://", "")
|
| 621 |
|
| 622 |
# Use custom seed or random
|
| 623 |
+
actual_seed = seed if use_custom_seed else random.randint(1, 2**32 - 1)
|
| 624 |
|
| 625 |
with torch.inference_mode():
|
| 626 |
if pipeline == "standard":
|
|
|
|
| 647 |
apply_gradient_filter=apply_gradient_filter,
|
| 648 |
gradient_strength=gradient_strength,
|
| 649 |
variation_steps=variation_steps,
|
| 650 |
+
enable_animation=enable_animation,
|
| 651 |
gr_progress=progress,
|
| 652 |
)
|
| 653 |
else: # artistic
|
|
|
|
| 681 |
apply_gradient_filter=apply_gradient_filter,
|
| 682 |
gradient_strength=gradient_strength,
|
| 683 |
variation_steps=variation_steps,
|
| 684 |
+
enable_animation=enable_animation,
|
| 685 |
gr_progress=progress,
|
| 686 |
)
|
| 687 |
|
| 688 |
|
| 689 |
+
class AnimationHandler:
|
| 690 |
+
"""Handler for managing KSampler animation callbacks"""
|
| 691 |
+
def __init__(self, preview_size=512):
|
| 692 |
+
self.intermediate_images = []
|
| 693 |
+
self.image_queue = queue.Queue()
|
| 694 |
+
self.enabled = False
|
| 695 |
+
self.preview_size = preview_size # Consistent preview size for all intermediate images
|
| 696 |
+
|
| 697 |
+
def create_callback(self, vae, interval=5):
|
| 698 |
+
"""Create a callback that stores intermediate decoded images"""
|
| 699 |
+
last_step = [0]
|
| 700 |
+
|
| 701 |
+
def callback(step, x0, x, total_steps):
|
| 702 |
+
if not self.enabled:
|
| 703 |
+
return
|
| 704 |
+
|
| 705 |
+
# Only decode every 'interval' steps, but skip the very last step to avoid contaminating main pipeline
|
| 706 |
+
if (step - last_step[0]) >= interval and step < total_steps:
|
| 707 |
+
last_step[0] = step
|
| 708 |
+
try:
|
| 709 |
+
# Use torch.no_grad() instead of inference_mode to avoid tensor contamination
|
| 710 |
+
# Key insight: inference_mode tensors cannot be used in backward pass
|
| 711 |
+
# Source: https://pytorch.org/docs/stable/generated/torch.autograd.grad_mode.inference_mode.html
|
| 712 |
+
import torch
|
| 713 |
+
with torch.no_grad():
|
| 714 |
+
# Create a detached clone and ensure contiguous memory layout
|
| 715 |
+
# .contiguous() ensures proper memory layout for VAE decoder
|
| 716 |
+
x0_copy = x0.detach().clone().contiguous()
|
| 717 |
+
|
| 718 |
+
# CRITICAL: Scale the latent for VAE decoding
|
| 719 |
+
# SD1.5 uses scale_factor = 0.18215, so we divide by it
|
| 720 |
+
# This converts from model sampling space to VAE decoding space
|
| 721 |
+
x0_scaled = x0_copy / 0.18215
|
| 722 |
+
|
| 723 |
+
# Decode - create full latent dict like KSampler output
|
| 724 |
+
latent_dict = {"samples": x0_scaled}
|
| 725 |
+
decoded = vaedecode.decode(samples=latent_dict, vae=vae)
|
| 726 |
+
image_tensor = get_value_at_index(decoded, 0)
|
| 727 |
+
|
| 728 |
+
# Convert EXACTLY like final images (lines 1915-1918) - no transpose, no mode
|
| 729 |
+
image_np = (image_tensor.detach().cpu().numpy() * 255).astype(np.uint8)
|
| 730 |
+
image_np = image_np[0]
|
| 731 |
+
pil_image = Image.fromarray(image_np)
|
| 732 |
+
|
| 733 |
+
# Resize to consistent preview size to avoid size inconsistencies in UI
|
| 734 |
+
if pil_image.size[0] > self.preview_size or pil_image.size[1] > self.preview_size:
|
| 735 |
+
pil_image.thumbnail((self.preview_size, self.preview_size), Image.LANCZOS)
|
| 736 |
+
|
| 737 |
+
# Store with message (step is already the correct value at interval points)
|
| 738 |
+
msg = f"Sampling progress: step {step}/{total_steps}"
|
| 739 |
+
self.intermediate_images.append((pil_image, msg))
|
| 740 |
+
self.image_queue.put((pil_image, msg))
|
| 741 |
+
except Exception as e:
|
| 742 |
+
print(f"Animation decode error: {e}")
|
| 743 |
+
|
| 744 |
+
return callback
|
| 745 |
+
|
| 746 |
+
def get_and_clear_images(self):
|
| 747 |
+
"""Get all intermediate images and clear the buffer"""
|
| 748 |
+
images = self.intermediate_images.copy()
|
| 749 |
+
self.intermediate_images.clear()
|
| 750 |
+
return images
|
| 751 |
+
|
| 752 |
+
|
| 753 |
+
def ksampler_with_animation(model, seed, steps, cfg, sampler_name, scheduler,
|
| 754 |
+
positive, negative, latent_image, denoise=1.0,
|
| 755 |
+
animation_handler=None, vae=None):
|
| 756 |
+
"""
|
| 757 |
+
Custom KSampler that supports animation callbacks.
|
| 758 |
+
Based on ComfyUI's common_ksampler but with animation support.
|
| 759 |
+
"""
|
| 760 |
+
import comfy.sample
|
| 761 |
+
import comfy.utils
|
| 762 |
+
|
| 763 |
+
# Prepare noise
|
| 764 |
+
latent = latent_image
|
| 765 |
+
latent_image_data = latent["samples"]
|
| 766 |
+
latent_image_data = comfy.sample.fix_empty_latent_channels(model, latent_image_data)
|
| 767 |
+
|
| 768 |
+
batch_inds = latent["batch_index"] if "batch_index" in latent else None
|
| 769 |
+
noise = comfy.sample.prepare_noise(latent_image_data, seed, batch_inds)
|
| 770 |
+
|
| 771 |
+
noise_mask = None
|
| 772 |
+
if "noise_mask" in latent:
|
| 773 |
+
noise_mask = latent["noise_mask"]
|
| 774 |
+
|
| 775 |
+
# Create animation callback once before sampling (not on every step!)
|
| 776 |
+
callback_fn = None
|
| 777 |
+
if animation_handler and animation_handler.enabled and vae:
|
| 778 |
+
callback_fn = animation_handler.create_callback(vae)
|
| 779 |
+
|
| 780 |
+
def animation_callback(step, x0, x, total_steps):
|
| 781 |
+
# Call animation callback if enabled
|
| 782 |
+
if callback_fn:
|
| 783 |
+
callback_fn(step, x0, x, total_steps)
|
| 784 |
+
|
| 785 |
+
disable_pbar = not comfy.utils.PROGRESS_BAR_ENABLED
|
| 786 |
+
|
| 787 |
+
# Sample
|
| 788 |
+
samples = comfy.sample.sample(
|
| 789 |
+
model, noise, steps, cfg, sampler_name, scheduler,
|
| 790 |
+
positive, negative, latent_image_data,
|
| 791 |
+
denoise=denoise, disable_noise=False, start_step=None,
|
| 792 |
+
last_step=None, force_full_denoise=False,
|
| 793 |
+
noise_mask=noise_mask, callback=animation_callback,
|
| 794 |
+
disable_pbar=disable_pbar, seed=seed
|
| 795 |
+
)
|
| 796 |
+
|
| 797 |
+
out = latent.copy()
|
| 798 |
+
out["samples"] = samples
|
| 799 |
+
return (out,)
|
| 800 |
+
|
| 801 |
+
|
| 802 |
def apply_color_quantization(
|
| 803 |
image: Image.Image,
|
| 804 |
colors: list[str],
|
|
|
|
| 1001 |
use_custom_seed: bool = False,
|
| 1002 |
seed: int = 0,
|
| 1003 |
enable_upscale: bool = False,
|
| 1004 |
+
enable_animation: bool = True,
|
| 1005 |
controlnet_strength_standard_first: float = 0.45,
|
| 1006 |
controlnet_strength_standard_final: float = 1.0,
|
| 1007 |
enable_color_quantization: bool = False,
|
|
|
|
| 1017 |
):
|
| 1018 |
"""Wrapper function for standard QR generation"""
|
| 1019 |
# Get actual seed used (custom or random)
|
| 1020 |
+
actual_seed = seed if use_custom_seed else random.randint(1, 2**32 - 1)
|
| 1021 |
|
| 1022 |
# Create settings JSON once
|
| 1023 |
settings_dict = {
|
|
|
|
| 1034 |
"seed": actual_seed,
|
| 1035 |
"use_custom_seed": True,
|
| 1036 |
"enable_upscale": enable_upscale,
|
| 1037 |
+
"enable_animation": enable_animation,
|
| 1038 |
"controlnet_strength_standard_first": controlnet_strength_standard_first,
|
| 1039 |
"controlnet_strength_standard_final": controlnet_strength_standard_final,
|
| 1040 |
"enable_color_quantization": enable_color_quantization,
|
|
|
|
| 1064 |
seed,
|
| 1065 |
pipeline="standard",
|
| 1066 |
enable_upscale=enable_upscale,
|
| 1067 |
+
enable_animation=enable_animation,
|
| 1068 |
controlnet_strength_standard_first=controlnet_strength_standard_first,
|
| 1069 |
controlnet_strength_standard_final=controlnet_strength_standard_final,
|
| 1070 |
enable_color_quantization=enable_color_quantization,
|
|
|
|
| 1111 |
use_custom_seed: bool = False,
|
| 1112 |
seed: int = 0,
|
| 1113 |
enable_upscale: bool = True,
|
| 1114 |
+
enable_animation: bool = True,
|
| 1115 |
enable_freeu: bool = True,
|
| 1116 |
freeu_b1: float = 1.4,
|
| 1117 |
freeu_b2: float = 1.3,
|
|
|
|
| 1135 |
):
|
| 1136 |
"""Wrapper function for artistic QR generation with FreeU and SAG parameters"""
|
| 1137 |
# Get actual seed used (custom or random)
|
| 1138 |
+
actual_seed = seed if use_custom_seed else random.randint(1, 2**32 - 1)
|
| 1139 |
|
| 1140 |
# Create settings JSON once
|
| 1141 |
settings_dict = {
|
|
|
|
| 1152 |
"seed": actual_seed,
|
| 1153 |
"use_custom_seed": True,
|
| 1154 |
"enable_upscale": enable_upscale,
|
| 1155 |
+
"enable_animation": enable_animation,
|
| 1156 |
"enable_freeu": enable_freeu,
|
| 1157 |
"freeu_b1": freeu_b1,
|
| 1158 |
"freeu_b2": freeu_b2,
|
|
|
|
| 1208 |
apply_gradient_filter=apply_gradient_filter,
|
| 1209 |
gradient_strength=gradient_strength,
|
| 1210 |
variation_steps=variation_steps,
|
| 1211 |
+
enable_animation=enable_animation,
|
| 1212 |
progress=progress,
|
| 1213 |
)
|
| 1214 |
|
|
|
|
| 1315 |
use_custom_seed = params.get("use_custom_seed", True)
|
| 1316 |
seed = params.get("seed", 718313)
|
| 1317 |
enable_upscale = params.get("enable_upscale", False)
|
| 1318 |
+
enable_animation = params.get("enable_animation", True)
|
| 1319 |
controlnet_strength_standard_first = params.get(
|
| 1320 |
"controlnet_strength_standard_first", 0.45
|
| 1321 |
)
|
|
|
|
| 1346 |
use_custom_seed,
|
| 1347 |
seed,
|
| 1348 |
enable_upscale,
|
| 1349 |
+
enable_animation,
|
| 1350 |
controlnet_strength_standard_first,
|
| 1351 |
controlnet_strength_standard_final,
|
| 1352 |
enable_color_quantization,
|
|
|
|
| 1727 |
apply_gradient_filter: bool = False,
|
| 1728 |
gradient_strength: float = 0.3,
|
| 1729 |
variation_steps: int = 5,
|
| 1730 |
+
enable_animation: bool = True,
|
| 1731 |
gr_progress=None,
|
| 1732 |
):
|
| 1733 |
+
# Initialize animation handler if enabled
|
| 1734 |
+
animation_handler = AnimationHandler(preview_size=image_size) if enable_animation else None
|
| 1735 |
+
if animation_handler:
|
| 1736 |
+
animation_handler.enabled = True
|
| 1737 |
+
|
| 1738 |
emptylatentimage_5 = emptylatentimage.generate(
|
| 1739 |
width=image_size, height=image_size, batch_size=1
|
| 1740 |
)
|
|
|
|
| 1840 |
vae=get_value_at_index(checkpointloadersimple_4, 2),
|
| 1841 |
)
|
| 1842 |
|
| 1843 |
+
# Use animation-enabled sampler if requested
|
| 1844 |
+
if animation_handler and enable_animation:
|
| 1845 |
+
# Run ksampler in thread to allow real-time image yielding
|
| 1846 |
+
result_container = [None]
|
| 1847 |
+
def run_ksampler():
|
| 1848 |
+
result_container[0] = ksampler_with_animation(
|
| 1849 |
+
model=get_value_at_index(checkpointloadersimple_4, 0),
|
| 1850 |
+
seed=seed,
|
| 1851 |
+
steps=20,
|
| 1852 |
+
cfg=7,
|
| 1853 |
+
sampler_name="dpmpp_2m",
|
| 1854 |
+
scheduler="karras",
|
| 1855 |
+
positive=get_value_at_index(controlnetapplyadvanced_13, 0),
|
| 1856 |
+
negative=get_value_at_index(controlnetapplyadvanced_13, 1),
|
| 1857 |
+
latent_image=get_value_at_index(emptylatentimage_5, 0),
|
| 1858 |
+
denoise=1,
|
| 1859 |
+
animation_handler=animation_handler,
|
| 1860 |
+
vae=get_value_at_index(checkpointloadersimple_4, 2),
|
| 1861 |
+
)
|
| 1862 |
+
|
| 1863 |
+
ksampler_thread = threading.Thread(target=run_ksampler)
|
| 1864 |
+
ksampler_thread.start()
|
| 1865 |
+
|
| 1866 |
+
# Yield intermediate images as they're captured
|
| 1867 |
+
while ksampler_thread.is_alive() or not animation_handler.image_queue.empty():
|
| 1868 |
+
try:
|
| 1869 |
+
img, msg = animation_handler.image_queue.get(timeout=0.1)
|
| 1870 |
+
yield img, msg
|
| 1871 |
+
except queue.Empty:
|
| 1872 |
+
pass
|
| 1873 |
+
|
| 1874 |
+
ksampler_thread.join()
|
| 1875 |
+
ksampler_3 = result_container[0]
|
| 1876 |
+
else:
|
| 1877 |
+
ksampler_3 = ksampler.sample(
|
| 1878 |
+
seed=seed,
|
| 1879 |
+
steps=20,
|
| 1880 |
+
cfg=7,
|
| 1881 |
+
sampler_name="dpmpp_2m",
|
| 1882 |
+
scheduler="karras",
|
| 1883 |
+
denoise=1,
|
| 1884 |
+
model=get_value_at_index(checkpointloadersimple_4, 0),
|
| 1885 |
+
positive=get_value_at_index(controlnetapplyadvanced_13, 0),
|
| 1886 |
+
negative=get_value_at_index(controlnetapplyadvanced_13, 1),
|
| 1887 |
+
latent_image=get_value_at_index(emptylatentimage_5, 0),
|
| 1888 |
+
)
|
| 1889 |
|
| 1890 |
# Yield progress update after first sampling completes
|
| 1891 |
msg = "First pass sampling complete... decoding image"
|
|
|
|
| 1927 |
vae=get_value_at_index(checkpointloadersimple_4, 2),
|
| 1928 |
)
|
| 1929 |
|
| 1930 |
+
# Use animation-enabled sampler if requested
|
| 1931 |
+
if animation_handler and enable_animation:
|
| 1932 |
+
# Run ksampler in thread to allow real-time image yielding
|
| 1933 |
+
result_container = [None]
|
| 1934 |
+
def run_ksampler():
|
| 1935 |
+
result_container[0] = ksampler_with_animation(
|
| 1936 |
+
model=get_value_at_index(checkpointloadersimple_4, 0),
|
| 1937 |
+
seed=seed + 1,
|
| 1938 |
+
steps=20,
|
| 1939 |
+
cfg=7,
|
| 1940 |
+
sampler_name="dpmpp_2m",
|
| 1941 |
+
scheduler="karras",
|
| 1942 |
+
positive=get_value_at_index(controlnetapplyadvanced_20, 0),
|
| 1943 |
+
negative=get_value_at_index(controlnetapplyadvanced_20, 1),
|
| 1944 |
+
latent_image=get_value_at_index(emptylatentimage_17, 0),
|
| 1945 |
+
denoise=1,
|
| 1946 |
+
animation_handler=animation_handler,
|
| 1947 |
+
vae=get_value_at_index(checkpointloadersimple_4, 2),
|
| 1948 |
+
)
|
| 1949 |
+
|
| 1950 |
+
ksampler_thread = threading.Thread(target=run_ksampler)
|
| 1951 |
+
ksampler_thread.start()
|
| 1952 |
+
|
| 1953 |
+
# Yield intermediate images as they're captured
|
| 1954 |
+
while ksampler_thread.is_alive() or not animation_handler.image_queue.empty():
|
| 1955 |
+
try:
|
| 1956 |
+
img, msg = animation_handler.image_queue.get(timeout=0.1)
|
| 1957 |
+
yield img, msg
|
| 1958 |
+
except queue.Empty:
|
| 1959 |
+
pass
|
| 1960 |
+
|
| 1961 |
+
ksampler_thread.join()
|
| 1962 |
+
ksampler_18 = result_container[0]
|
| 1963 |
+
else:
|
| 1964 |
+
ksampler_18 = ksampler.sample(
|
| 1965 |
+
seed=seed + 1,
|
| 1966 |
+
steps=20,
|
| 1967 |
+
cfg=7,
|
| 1968 |
+
sampler_name="dpmpp_2m",
|
| 1969 |
+
scheduler="karras",
|
| 1970 |
+
denoise=1,
|
| 1971 |
+
model=get_value_at_index(checkpointloadersimple_4, 0),
|
| 1972 |
+
positive=get_value_at_index(controlnetapplyadvanced_20, 0),
|
| 1973 |
+
negative=get_value_at_index(controlnetapplyadvanced_20, 1),
|
| 1974 |
+
latent_image=get_value_at_index(emptylatentimage_17, 0),
|
| 1975 |
+
)
|
| 1976 |
|
| 1977 |
# Yield progress update after second sampling completes
|
| 1978 |
msg = "Second pass sampling complete... decoding final image"
|
|
|
|
| 2100 |
apply_gradient_filter: bool = False,
|
| 2101 |
gradient_strength: float = 0.3,
|
| 2102 |
variation_steps: int = 5,
|
| 2103 |
+
enable_animation: bool = True,
|
| 2104 |
gr_progress=None,
|
| 2105 |
):
|
| 2106 |
+
# Initialize animation handler if enabled
|
| 2107 |
+
animation_handler = AnimationHandler(preview_size=image_size) if enable_animation else None
|
| 2108 |
+
if animation_handler:
|
| 2109 |
+
animation_handler.enabled = True
|
| 2110 |
+
|
| 2111 |
# Generate QR code
|
| 2112 |
qr_protocol = "None" if input_type == "Plain Text" else "Https"
|
| 2113 |
|
|
|
|
| 2263 |
# First sampling pass
|
| 2264 |
log_progress("First pass - artistic sampling...", gr_progress, 0.2)
|
| 2265 |
|
| 2266 |
+
# Use animation-enabled sampler if requested
|
| 2267 |
+
if animation_handler and enable_animation:
|
| 2268 |
+
# Run ksampler in thread to allow real-time image yielding
|
| 2269 |
+
result_container = [None]
|
| 2270 |
+
def run_ksampler():
|
| 2271 |
+
result_container[0] = ksampler_with_animation(
|
| 2272 |
+
model=enhanced_model, # Using FreeU + SAG enhanced model
|
| 2273 |
+
seed=seed,
|
| 2274 |
+
steps=30,
|
| 2275 |
+
cfg=7,
|
| 2276 |
+
sampler_name="dpmpp_3m_sde",
|
| 2277 |
+
scheduler="karras",
|
| 2278 |
+
positive=get_value_at_index(controlnet_apply, 0),
|
| 2279 |
+
negative=get_value_at_index(controlnet_apply, 1),
|
| 2280 |
+
latent_image=get_value_at_index(latent_image, 0),
|
| 2281 |
+
denoise=1,
|
| 2282 |
+
animation_handler=animation_handler,
|
| 2283 |
+
vae=get_value_at_index(checkpointloadersimple_artistic, 2),
|
| 2284 |
+
)
|
| 2285 |
+
|
| 2286 |
+
ksampler_thread = threading.Thread(target=run_ksampler)
|
| 2287 |
+
ksampler_thread.start()
|
| 2288 |
+
|
| 2289 |
+
# Yield intermediate images as they're captured
|
| 2290 |
+
while ksampler_thread.is_alive() or not animation_handler.image_queue.empty():
|
| 2291 |
+
try:
|
| 2292 |
+
img, msg = animation_handler.image_queue.get(timeout=0.1)
|
| 2293 |
+
yield (img, msg)
|
| 2294 |
+
except queue.Empty:
|
| 2295 |
+
pass
|
| 2296 |
+
|
| 2297 |
+
ksampler_thread.join()
|
| 2298 |
+
samples = result_container[0]
|
| 2299 |
+
else:
|
| 2300 |
+
samples = ksampler.sample(
|
| 2301 |
+
seed=seed,
|
| 2302 |
+
steps=30,
|
| 2303 |
+
cfg=7,
|
| 2304 |
+
sampler_name="dpmpp_3m_sde",
|
| 2305 |
+
scheduler="karras",
|
| 2306 |
+
denoise=1,
|
| 2307 |
+
model=enhanced_model, # Using FreeU + SAG enhanced model
|
| 2308 |
+
positive=get_value_at_index(controlnet_apply, 0),
|
| 2309 |
+
negative=get_value_at_index(controlnet_apply, 1),
|
| 2310 |
+
latent_image=get_value_at_index(latent_image, 0),
|
| 2311 |
+
)
|
| 2312 |
|
| 2313 |
# Yield progress update after first sampling completes
|
| 2314 |
msg = f"First pass sampling complete... decoding image (step {current_step}/{total_steps})"
|
|
|
|
| 2358 |
# Final sampling pass
|
| 2359 |
log_progress("Second pass (refinement)...", gr_progress, 0.6)
|
| 2360 |
|
| 2361 |
+
# Use animation-enabled sampler if requested
|
| 2362 |
+
if animation_handler and enable_animation:
|
| 2363 |
+
# Run ksampler in thread to allow real-time image yielding
|
| 2364 |
+
result_container = [None]
|
| 2365 |
+
def run_ksampler():
|
| 2366 |
+
result_container[0] = ksampler_with_animation(
|
| 2367 |
+
model=enhanced_model, # Using FreeU + SAG enhanced model
|
| 2368 |
+
seed=seed + 1,
|
| 2369 |
+
steps=30,
|
| 2370 |
+
cfg=7,
|
| 2371 |
+
sampler_name="dpmpp_3m_sde",
|
| 2372 |
+
scheduler="karras",
|
| 2373 |
+
positive=get_value_at_index(controlnet_apply_final, 0),
|
| 2374 |
+
negative=get_value_at_index(controlnet_apply_final, 1),
|
| 2375 |
+
latent_image=get_value_at_index(upscaled_latent, 0),
|
| 2376 |
+
denoise=0.8,
|
| 2377 |
+
animation_handler=animation_handler,
|
| 2378 |
+
vae=get_value_at_index(checkpointloadersimple_artistic, 2),
|
| 2379 |
+
)
|
| 2380 |
+
|
| 2381 |
+
ksampler_thread = threading.Thread(target=run_ksampler)
|
| 2382 |
+
ksampler_thread.start()
|
| 2383 |
+
|
| 2384 |
+
# Yield intermediate images as they're captured
|
| 2385 |
+
while ksampler_thread.is_alive() or not animation_handler.image_queue.empty():
|
| 2386 |
+
try:
|
| 2387 |
+
img, msg = animation_handler.image_queue.get(timeout=0.1)
|
| 2388 |
+
yield (img, msg)
|
| 2389 |
+
except queue.Empty:
|
| 2390 |
+
pass
|
| 2391 |
+
|
| 2392 |
+
ksampler_thread.join()
|
| 2393 |
+
final_samples = result_container[0]
|
| 2394 |
+
else:
|
| 2395 |
+
final_samples = ksampler.sample(
|
| 2396 |
+
seed=seed + 1,
|
| 2397 |
+
steps=30,
|
| 2398 |
+
cfg=7,
|
| 2399 |
+
sampler_name="dpmpp_3m_sde",
|
| 2400 |
+
scheduler="karras",
|
| 2401 |
+
denoise=0.8,
|
| 2402 |
+
model=enhanced_model, # Using FreeU + SAG enhanced model
|
| 2403 |
+
positive=get_value_at_index(controlnet_apply_final, 0),
|
| 2404 |
+
negative=get_value_at_index(controlnet_apply_final, 1),
|
| 2405 |
+
latent_image=get_value_at_index(upscaled_latent, 0),
|
| 2406 |
+
)
|
| 2407 |
|
| 2408 |
# Yield progress update after second sampling completes
|
| 2409 |
msg = f"Second pass sampling complete... decoding final image (step {current_step}/{total_steps})"
|
|
|
|
| 2515 |
- Include style keywords like 'photorealistic', 'detailed', '8k'
|
| 2516 |
- Choose **URL** mode for web links or **Plain Text** mode for VCARD, WiFi credentials, calendar events, etc.
|
| 2517 |
- Try the examples below for inspiration
|
| 2518 |
+
- **Animation** (enabled by default): Shows intermediate generation steps every 5 steps. Disable for faster generation. (Available in "Change Settings Manually")
|
| 2519 |
+
- **Color Quantization** (disabled by default): Optional feature to specify a custom color scheme (2-4 colors) for your QR code. Perfect for matching brand colors or creating themed designs with gradient variations. (Available in "Change Settings Manually")
|
| 2520 |
+
- **Upscale Image**: Enhances output quality with RealESRGAN (enabled by default in Artistic, disabled in Standard). (Available in "Change Settings Manually")
|
| 2521 |
- **Copy/paste settings**: After generation, copy the JSON settings string that appears below the image and paste it into "Import Settings from JSON" to reproduce exact results or share with others
|
| 2522 |
|
| 2523 |
### Two Modes:
|
|
|
|
| 2548 |
artistic_prompt_input = gr.Textbox(
|
| 2549 |
label="Prompt",
|
| 2550 |
placeholder="Describe the image you want to generate (check examples below for inspiration)",
|
| 2551 |
+
value="some clothes spread on ropes, Japanese girl sits inside in the middle of the image, few sakura flowers, realistic, great details, out in the open air sunny day realistic, great details, absence of people, Detailed and Intricate, CGI, Photoshoot, rim light, 8k, 16k, ultra detail",
|
| 2552 |
lines=3,
|
| 2553 |
)
|
| 2554 |
artistic_text_input = gr.Textbox(
|
| 2555 |
label="QR Code Content",
|
| 2556 |
placeholder="Enter URL or plain text",
|
| 2557 |
+
value="https://www.google.com",
|
| 2558 |
lines=3,
|
| 2559 |
)
|
| 2560 |
|
|
|
|
| 2584 |
|
| 2585 |
# Change Settings Manually - separate accordion
|
| 2586 |
with gr.Accordion("Change Settings Manually", open=False):
|
| 2587 |
+
gr.Markdown("**Advanced controls including:** Animation toggle, Color Quantization, FreeU/SAG parameters, ControlNet strength, QR settings, and more.")
|
| 2588 |
# Negative Prompt
|
| 2589 |
negative_prompt_artistic = gr.Textbox(
|
| 2590 |
label="Negative Prompt",
|
|
|
|
| 2599 |
minimum=512,
|
| 2600 |
maximum=1024,
|
| 2601 |
step=64,
|
| 2602 |
+
value=640,
|
| 2603 |
label="Image Size",
|
| 2604 |
+
info="Base size of the generated image. Final output will be 2x this size (e.g., 640 → 1280) due to the two-step enhancement process. Higher values use more VRAM and take longer to process.",
|
| 2605 |
)
|
| 2606 |
|
| 2607 |
# Add border size slider for artistic QR
|
|
|
|
| 2622 |
"Quartile (25%)",
|
| 2623 |
"High (30%)",
|
| 2624 |
],
|
| 2625 |
+
value="Medium (15%)",
|
| 2626 |
label="Error Correction Level",
|
| 2627 |
info="Higher error correction makes the QR code more scannable when damaged or obscured, but increases its size and complexity. High (30%) is recommended for artistic QR codes.",
|
| 2628 |
)
|
|
|
|
| 2632 |
minimum=4,
|
| 2633 |
maximum=16,
|
| 2634 |
step=1,
|
| 2635 |
+
value=14,
|
| 2636 |
label="QR Module Size",
|
| 2637 |
+
info="Pixel width of the smallest QR code unit. Larger values improve readability but require a larger image size. 14 is a good starting point.",
|
| 2638 |
)
|
| 2639 |
|
| 2640 |
# Add module drawer dropdown with style examples for artistic QR
|
| 2641 |
artistic_module_drawer = gr.Dropdown(
|
| 2642 |
choices=[
|
| 2643 |
"Square",
|
| 2644 |
+
"Gapped square",
|
| 2645 |
"Circle",
|
| 2646 |
"Rounded",
|
| 2647 |
"Vertical bars",
|
|
|
|
| 2716 |
info="Enable upscaling with RealESRGAN for higher quality output (enabled by default for artistic pipeline)",
|
| 2717 |
)
|
| 2718 |
|
| 2719 |
+
# Animation toggle
|
| 2720 |
+
artistic_enable_animation = gr.Checkbox(
|
| 2721 |
+
label="Enable Animation (Show KSampler Progress)",
|
| 2722 |
+
value=True,
|
| 2723 |
+
info="Shows intermediate images every 5 steps during generation. Disable for faster generation.",
|
| 2724 |
+
)
|
| 2725 |
+
|
| 2726 |
# Color Quantization Section
|
| 2727 |
gr.Markdown("### Color Quantization (Optional)")
|
| 2728 |
+
gr.Markdown("Use this option to specify a custom color scheme for your QR code. Perfect for matching brand colors or creating themed designs.")
|
| 2729 |
artistic_enable_color_quantization = gr.Checkbox(
|
| 2730 |
label="Enable Color Quantization",
|
| 2731 |
value=False,
|
|
|
|
| 2839 |
)
|
| 2840 |
artistic_seed = gr.Slider(
|
| 2841 |
minimum=0,
|
| 2842 |
+
maximum=2**32 - 1,
|
| 2843 |
step=1,
|
| 2844 |
value=718313,
|
| 2845 |
label="Seed",
|
|
|
|
| 2977 |
artistic_use_custom_seed,
|
| 2978 |
artistic_seed,
|
| 2979 |
artistic_enable_upscale,
|
| 2980 |
+
artistic_enable_animation,
|
| 2981 |
enable_freeu_artistic,
|
| 2982 |
freeu_b1,
|
| 2983 |
freeu_b2,
|
|
|
|
| 3023 |
artistic_use_custom_seed,
|
| 3024 |
artistic_seed,
|
| 3025 |
artistic_enable_upscale,
|
| 3026 |
+
artistic_enable_animation,
|
| 3027 |
enable_freeu_artistic,
|
| 3028 |
freeu_b1,
|
| 3029 |
freeu_b2,
|
|
|
|
| 3478 |
prompt_input = gr.Textbox(
|
| 3479 |
label="Prompt",
|
| 3480 |
placeholder="Describe the image you want to generate (check examples below for inspiration)",
|
| 3481 |
+
value="some clothes spread on ropes, realistic, great details, out in the open air sunny day realistic, great details,absence of people, Detailed and Intricate, CGI, Photoshoot,rim light, 8k, 16k, ultra detail",
|
| 3482 |
lines=3,
|
| 3483 |
)
|
| 3484 |
text_input = gr.Textbox(
|
| 3485 |
label="QR Code Content",
|
| 3486 |
placeholder="Enter URL or plain text",
|
| 3487 |
+
value="https://www.google.com",
|
| 3488 |
lines=3,
|
| 3489 |
)
|
| 3490 |
|
|
|
|
| 3514 |
|
| 3515 |
# Change Settings Manually - separate accordion
|
| 3516 |
with gr.Accordion("Change Settings Manually", open=False):
|
| 3517 |
+
gr.Markdown("**Advanced controls including:** Animation toggle, Color Quantization, ControlNet strength, QR settings, and more.")
|
| 3518 |
# Negative Prompt
|
| 3519 |
negative_prompt_standard = gr.Textbox(
|
| 3520 |
label="Negative Prompt",
|
|
|
|
| 3571 |
module_drawer = gr.Dropdown(
|
| 3572 |
choices=[
|
| 3573 |
"Square",
|
| 3574 |
+
"Gapped square",
|
| 3575 |
"Circle",
|
| 3576 |
"Rounded",
|
| 3577 |
"Vertical bars",
|
|
|
|
| 3646 |
info="Enable upscaling with RealESRGAN for higher quality output (disabled by default for standard pipeline)",
|
| 3647 |
)
|
| 3648 |
|
| 3649 |
+
# Animation toggle
|
| 3650 |
+
enable_animation = gr.Checkbox(
|
| 3651 |
+
label="Enable Animation (Show KSampler Progress)",
|
| 3652 |
+
value=True,
|
| 3653 |
+
info="Shows intermediate images every 5 steps during generation. Disable for faster generation.",
|
| 3654 |
)
|
| 3655 |
|
| 3656 |
# Color Quantization Section
|
| 3657 |
gr.Markdown("### Color Quantization (Optional)")
|
| 3658 |
+
gr.Markdown("Use this option to specify a custom color scheme for your QR code. Perfect for matching brand colors or creating themed designs.")
|
| 3659 |
enable_color_quantization = gr.Checkbox(
|
| 3660 |
label="Enable Color Quantization",
|
| 3661 |
value=False,
|
|
|
|
| 3765 |
)
|
| 3766 |
seed = gr.Slider(
|
| 3767 |
minimum=0,
|
| 3768 |
+
maximum=2**32 - 1,
|
| 3769 |
step=1,
|
| 3770 |
value=718313,
|
| 3771 |
label="Seed",
|
|
|
|
| 3837 |
use_custom_seed,
|
| 3838 |
seed,
|
| 3839 |
enable_upscale,
|
| 3840 |
+
enable_animation,
|
| 3841 |
controlnet_strength_standard_first,
|
| 3842 |
controlnet_strength_standard_final,
|
| 3843 |
enable_color_quantization,
|
|
|
|
| 3856 |
settings_output_standard,
|
| 3857 |
settings_accordion_standard,
|
| 3858 |
],
|
| 3859 |
+
show_progress="full",
|
| 3860 |
)
|
| 3861 |
|
| 3862 |
# Load Settings button event handler
|
|
|
|
| 3876 |
use_custom_seed,
|
| 3877 |
seed,
|
| 3878 |
enable_upscale,
|
| 3879 |
+
enable_animation,
|
| 3880 |
controlnet_strength_standard_first,
|
| 3881 |
controlnet_strength_standard_final,
|
| 3882 |
enable_color_quantization,
|