Oysiyl commited on
Commit
e173e7b
·
1 Parent(s): 1318560

improvements to QR code generation, shareable JSON

Browse files
Files changed (1) hide show
  1. app.py +434 -49
app.py CHANGED
@@ -22,7 +22,6 @@ hf_hub_download(repo_id="comfyanonymous/ControlNet-v1-1_fp16_safetensors", filen
22
  hf_hub_download(repo_id="Lykon/dreamshaper-7", filename="vae/diffusion_pytorch_model.fp16.safetensors", local_dir="models")
23
  hf_hub_download(repo_id="stabilityai/sd-vae-ft-mse-original", filename="vae-ft-mse-840000-ema-pruned.safetensors", local_dir="models/vae")
24
  hf_hub_download(repo_id="lllyasviel/Annotators", filename="RealESRGAN_x4plus.pth", local_dir="models/upscale_models")
25
- hf_hub_download(repo_id="lykon/RealESRGAN_x4plus", filename="RealESRGAN_x4plus.pth", local_dir="models/upscale_models")
26
 
27
  def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any:
28
  """Returns the value at the given index of a sequence or mapping.
@@ -195,13 +194,249 @@ def generate_qr_code_unified(prompt: str, text_input: str, input_type: str = "UR
195
  else: # artistic
196
  yield from _pipeline_artistic(prompt, qr_text, input_type, image_size, border_size, error_correction, module_size, module_drawer, actual_seed, enable_upscale, freeu_b1, freeu_b2, freeu_s1, freeu_s2, enable_sag, sag_scale, sag_blur_sigma, controlnet_strength_first, controlnet_strength_final)
197
 
198
- def generate_standard_qr(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0, enable_upscale: bool = False):
199
  """Wrapper function for standard QR generation"""
200
- yield from generate_qr_code_unified(prompt, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, pipeline="standard", enable_upscale=enable_upscale)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
- def generate_artistic_qr(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0, enable_upscale: bool = True, freeu_b1: float = 1.4, freeu_b2: float = 1.3, freeu_s1: float = 0.0, freeu_s2: float = 1.3, enable_sag: bool = True, sag_scale: float = 0.5, sag_blur_sigma: float = 1.5, controlnet_strength_first: float = 0.45, controlnet_strength_final: float = 0.7):
203
  """Wrapper function for artistic QR generation with FreeU and SAG parameters"""
204
- yield from generate_qr_code_unified(prompt, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, pipeline="artistic", enable_upscale=enable_upscale, freeu_b1=freeu_b1, freeu_b2=freeu_b2, freeu_s1=freeu_s1, freeu_s2=freeu_s2, enable_sag=enable_sag, sag_scale=sag_scale, sag_blur_sigma=sag_blur_sigma, controlnet_strength_first=controlnet_strength_first, controlnet_strength_final=controlnet_strength_final)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
 
206
  def add_noise_to_border_only(image_tensor, seed: int, border_size: int, image_size: int, module_size: int = 12):
207
  """
@@ -331,7 +566,7 @@ def _pipeline_standard(prompt: str, qr_text: str, input_type: str, image_size: i
331
  except RuntimeError as e:
332
  error_msg = (
333
  f"Error generating QR code: {str(e)}\n"
334
- "Try with a shorter text, increase the image size, or decrease the border size, module size, and error correction level under Advanced Settings."
335
  )
336
  yield None, error_msg
337
  return
@@ -453,16 +688,16 @@ def _pipeline_standard(prompt: str, qr_text: str, input_type: str, image_size: i
453
  image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
454
  image_np = image_np[0]
455
  pil_image = Image.fromarray(image_np)
456
- yield pil_image, f"No errors, all good! Final QR art generated and upscaled. (step 4/4) | Seed: {seed}"
457
  else:
458
  # No upscaling
459
  image_tensor = get_value_at_index(vaedecode_21, 0)
460
  image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
461
  image_np = image_np[0]
462
  pil_image = Image.fromarray(image_np)
463
- yield pil_image, f"No errors, all good! Final QR art generated. | Seed: {seed}"
464
 
465
- def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: int, border_size: int, error_correction: str, module_size: int, module_drawer: str, seed: int, enable_upscale: bool = True, freeu_b1: float = 1.4, freeu_b2: float = 1.3, freeu_s1: float = 0.0, freeu_s2: float = 1.3, enable_sag: bool = True, sag_scale: float = 0.5, sag_blur_sigma: float = 1.5, controlnet_strength_first: float = 0.45, controlnet_strength_final: float = 0.7):
466
  # Generate QR code
467
  qr_protocol = "None" if input_type == "Plain Text" else "Https"
468
 
@@ -481,7 +716,7 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
481
  except RuntimeError as e:
482
  error_msg = (
483
  f"Error generating QR code: {str(e)}\n"
484
- "Try with a shorter text, increase the image size, or decrease the border size, module size, and error correction level under Advanced Settings."
485
  )
486
  yield None, error_msg
487
  return
@@ -620,7 +855,11 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
620
  first_pass_np = (first_pass_tensor.cpu().numpy() * 255).astype(np.uint8)
621
  first_pass_np = first_pass_np[0]
622
  first_pass_pil = Image.fromarray(first_pass_np)
623
- step_msg = "First enhancement pass complete (step 3/5)... final refinement pass" if border_size > 0 else "First enhancement pass complete (step 2/4)... final refinement pass"
 
 
 
 
624
  yield first_pass_pil, step_msg
625
 
626
  # Final ControlNet pass (second pass - refinement)
@@ -683,7 +922,7 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
683
  image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
684
  image_np = image_np[0]
685
  final_image = Image.fromarray(image_np)
686
- step_msg = f"No errors, all good! Final artistic QR code generated and upscaled. (step 5/5) | Seed: {seed}" if border_size > 0 else f"No errors, all good! Final artistic QR code generated and upscaled. (step 4/4) | Seed: {seed}"
687
  yield final_image, step_msg
688
  else:
689
  # No upscaling
@@ -691,7 +930,7 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
691
  image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
692
  image_np = image_np[0]
693
  final_image = Image.fromarray(image_np)
694
- step_msg = f"No errors, all good! Final artistic QR code generated. (step 4/4) | Seed: {seed}" if border_size > 0 else f"No errors, all good! Final artistic QR code generated. (step 3/3) | Seed: {seed}"
695
  yield final_image, step_msg
696
 
697
 
@@ -710,10 +949,11 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
710
  - Include style keywords like 'photorealistic', 'detailed', '8k'
711
  - Choose **URL** mode for web links or **Plain Text** mode for VCARD, WiFi credentials, calendar events, etc.
712
  - Try the examples below for inspiration
 
713
 
714
  ### Two Modes:
715
- - **Standard QR**: Stable, accurate QR code generation (faster, more scannable)
716
- - **Artistic QR**: More artistic and creative results with upscaling (slower, more creative)
717
 
718
  ### Note:
719
  Feel free to share your suggestions or feedback on how to improve the app! Thanks!
@@ -747,7 +987,26 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
747
  lines=3
748
  )
749
 
750
- with gr.Accordion("Advanced Settings", open=False):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
751
  # Add image size slider
752
  image_size = gr.Slider(
753
  minimum=512,
@@ -828,6 +1087,13 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
828
  info="Enable upscaling with RealESRGAN for higher quality output (disabled by default for standard pipeline)"
829
  )
830
 
 
 
 
 
 
 
 
831
  # Add seed controls
832
  use_custom_seed = gr.Checkbox(
833
  label="Use Custom Seed",
@@ -840,6 +1106,7 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
840
  step=1,
841
  value=718313,
842
  label="Seed",
 
843
  info="Seed value for reproducibility. Same seed with same settings will produce the same result."
844
  )
845
 
@@ -854,12 +1121,55 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
854
  interactive=False,
855
  lines=3,
856
  )
 
 
 
 
 
 
 
 
857
 
858
  # When clicking the button, it will trigger the main function
859
  generate_btn.click(
860
  fn=generate_standard_qr,
861
- inputs=[prompt_input, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, enable_upscale],
862
- outputs=[output_image, error_message]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
863
  )
864
 
865
  # Add examples
@@ -1009,7 +1319,26 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
1009
  lines=3
1010
  )
1011
 
1012
- with gr.Accordion("Advanced Settings", open=False):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1013
  # Add image size slider for artistic QR
1014
  artistic_image_size = gr.Slider(
1015
  minimum=512,
@@ -1102,11 +1431,17 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
1102
  step=1,
1103
  value=718313,
1104
  label="Seed",
 
1105
  info="Seed value for reproducibility. Same seed with same settings will produce the same result."
1106
  )
1107
 
1108
  # FreeU Parameters
1109
  gr.Markdown("### FreeU Quality Enhancement")
 
 
 
 
 
1110
  freeu_b1 = gr.Slider(
1111
  minimum=1.0,
1112
  maximum=1.6,
@@ -1159,9 +1494,9 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
1159
  minimum=0.0,
1160
  maximum=5.0,
1161
  step=0.1,
1162
- value=1.5,
1163
  label="SAG Blur Sigma",
1164
- info="Blur amount for artistic blending. Higher values create softer, more artistic effects. Range: 0.0-5.0, Default: 1.5"
1165
  )
1166
 
1167
  # The generate button for artistic QR
@@ -1175,74 +1510,124 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
1175
  interactive=False,
1176
  lines=3,
1177
  )
 
 
 
 
 
 
 
 
1178
 
1179
  # When clicking the button, it will trigger the artistic function
1180
  artistic_generate_btn.click(
1181
  fn=generate_artistic_qr,
1182
- inputs=[artistic_prompt_input, artistic_text_input, artistic_input_type, artistic_image_size, artistic_border_size, artistic_error_correction, artistic_module_size, artistic_module_drawer, artistic_use_custom_seed, artistic_seed, artistic_enable_upscale, freeu_b1, freeu_b2, freeu_s1, freeu_s2, enable_sag, sag_scale, sag_blur_sigma],
1183
- outputs=[artistic_output_image, artistic_error_message]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1184
  )
1185
 
1186
  # Add examples for artistic QR
1187
  artistic_examples = [
1188
  [
1189
- "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",
1190
  "https://www.google.com",
1191
  "URL",
1192
- 512,
1193
- 4,
1194
- "Medium (15%)",
1195
- 12,
1196
  "Square"
1197
  ],
1198
  [
1199
  "some cards on poker tale, realistic, great details, realistic, great details,absence of people, Detailed and Intricate, CGI, Photoshoot,rim light, 8k, 16k, ultra detail",
1200
  "https://store.steampowered.com",
1201
  "URL",
1202
- 512,
1203
- 4,
1204
- "Medium (15%)",
1205
- 12,
1206
  "Square"
1207
  ],
1208
  [
1209
  "a beautiful sunset over mountains, photorealistic, detailed landscape, golden hour, dramatic lighting, 8k, ultra detailed",
1210
  "https://github.com",
1211
  "URL",
1212
- 512,
1213
- 4,
1214
- "Medium (15%)",
1215
- 12,
1216
  "Square"
1217
  ],
1218
  [
1219
  "underwater scene with coral reef and tropical fish, photorealistic, detailed, crystal clear water, sunlight rays, 8k, ultra detailed",
1220
  "https://twitter.com",
1221
  "URL",
1222
- 512,
1223
- 4,
1224
- "Medium (15%)",
1225
- 12,
1226
  "Square"
1227
  ],
1228
  [
1229
  "futuristic cityscape with flying cars and neon lights, cyberpunk style, detailed architecture, night scene, 8k, ultra detailed",
1230
  "https://linkedin.com",
1231
  "URL",
1232
- 512,
1233
- 4,
1234
- "Medium (15%)",
1235
- 12,
1236
  "Square"
1237
  ],
1238
  [
1239
  "vintage camera on wooden table, photorealistic, detailed textures, soft lighting, bokeh background, 8k, ultra detailed",
1240
  "https://instagram.com",
1241
  "URL",
1242
- 512,
1243
- 4,
1244
- "Medium (15%)",
1245
- 12,
1246
  "Square"
1247
  ],
1248
  [
@@ -1301,7 +1686,7 @@ if __name__ == "__main__" and not os.environ.get('QR_TESTING_MODE'):
1301
  ],
1302
  outputs=[artistic_output_image, artistic_error_message],
1303
  fn=generate_artistic_qr,
1304
- cache_examples=False
1305
  )
1306
 
1307
  app.launch(share=False, mcp_server=True)
 
22
  hf_hub_download(repo_id="Lykon/dreamshaper-7", filename="vae/diffusion_pytorch_model.fp16.safetensors", local_dir="models")
23
  hf_hub_download(repo_id="stabilityai/sd-vae-ft-mse-original", filename="vae-ft-mse-840000-ema-pruned.safetensors", local_dir="models/vae")
24
  hf_hub_download(repo_id="lllyasviel/Annotators", filename="RealESRGAN_x4plus.pth", local_dir="models/upscale_models")
 
25
 
26
  def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any:
27
  """Returns the value at the given index of a sequence or mapping.
 
194
  else: # artistic
195
  yield from _pipeline_artistic(prompt, qr_text, input_type, image_size, border_size, error_correction, module_size, module_drawer, actual_seed, enable_upscale, freeu_b1, freeu_b2, freeu_s1, freeu_s2, enable_sag, sag_scale, sag_blur_sigma, controlnet_strength_first, controlnet_strength_final)
196
 
197
+ def generate_standard_qr(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0, enable_upscale: bool = False, enable_freeu: bool = False):
198
  """Wrapper function for standard QR generation"""
199
+ # Get actual seed used (custom or random)
200
+ actual_seed = seed if use_custom_seed else random.randint(1, 2**64)
201
+
202
+ # Create settings JSON once
203
+ settings_dict = {
204
+ "pipeline": "standard",
205
+ "prompt": prompt,
206
+ "text_input": text_input,
207
+ "input_type": input_type,
208
+ "image_size": image_size,
209
+ "border_size": border_size,
210
+ "error_correction": error_correction,
211
+ "module_size": module_size,
212
+ "module_drawer": module_drawer,
213
+ "seed": actual_seed,
214
+ "use_custom_seed": True,
215
+ "enable_upscale": enable_upscale,
216
+ "enable_freeu": enable_freeu
217
+ }
218
+ settings_json = generate_settings_json(settings_dict)
219
+
220
+ # Generate QR and yield progressive results
221
+ generator = generate_qr_code_unified(prompt, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, pipeline="standard", enable_upscale=enable_upscale)
222
+
223
+ final_image = None
224
+ final_status = None
225
+
226
+ for image, status in generator:
227
+ final_image = image
228
+ final_status = status
229
+ # Show progressive updates but don't show accordion yet
230
+ yield (image, status, gr.update(), gr.update())
231
+
232
+ # After all steps complete, show the accordion with JSON
233
+ if final_image is not None:
234
+ yield (
235
+ final_image,
236
+ final_status,
237
+ gr.update(value=settings_json), # Update textbox content
238
+ gr.update(visible=True) # Make accordion visible only at the end
239
+ )
240
 
241
+ def generate_artistic_qr(prompt: str, text_input: str, input_type: str = "URL", image_size: int = 512, border_size: int = 4, error_correction: str = "Medium (15%)", module_size: int = 12, module_drawer: str = "Square", use_custom_seed: bool = False, seed: int = 0, enable_upscale: bool = True, enable_freeu: bool = True, freeu_b1: float = 1.4, freeu_b2: float = 1.3, freeu_s1: float = 0.0, freeu_s2: float = 1.3, enable_sag: bool = True, sag_scale: float = 0.5, sag_blur_sigma: float = 0.5, controlnet_strength_first: float = 0.45, controlnet_strength_final: float = 0.7):
242
  """Wrapper function for artistic QR generation with FreeU and SAG parameters"""
243
+ # Get actual seed used (custom or random)
244
+ actual_seed = seed if use_custom_seed else random.randint(1, 2**64)
245
+
246
+ # Create settings JSON once
247
+ settings_dict = {
248
+ "pipeline": "artistic",
249
+ "prompt": prompt,
250
+ "text_input": text_input,
251
+ "input_type": input_type,
252
+ "image_size": image_size,
253
+ "border_size": border_size,
254
+ "error_correction": error_correction,
255
+ "module_size": module_size,
256
+ "module_drawer": module_drawer,
257
+ "seed": actual_seed,
258
+ "use_custom_seed": True,
259
+ "enable_upscale": enable_upscale,
260
+ "enable_freeu": enable_freeu,
261
+ "freeu_b1": freeu_b1,
262
+ "freeu_b2": freeu_b2,
263
+ "freeu_s1": freeu_s1,
264
+ "freeu_s2": freeu_s2,
265
+ "enable_sag": enable_sag,
266
+ "sag_scale": sag_scale,
267
+ "sag_blur_sigma": sag_blur_sigma
268
+ }
269
+ settings_json = generate_settings_json(settings_dict)
270
+
271
+ # Generate QR and yield progressive results
272
+ generator = generate_qr_code_unified(prompt, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, pipeline="artistic", enable_upscale=enable_upscale, freeu_b1=freeu_b1, freeu_b2=freeu_b2, freeu_s1=freeu_s1, freeu_s2=freeu_s2, enable_sag=enable_sag, sag_scale=sag_scale, sag_blur_sigma=sag_blur_sigma, controlnet_strength_first=controlnet_strength_first, controlnet_strength_final=controlnet_strength_final)
273
+
274
+ final_image = None
275
+ final_status = None
276
+
277
+ for image, status in generator:
278
+ final_image = image
279
+ final_status = status
280
+ # Show progressive updates but don't show accordion yet
281
+ yield (image, status, gr.update(), gr.update())
282
+
283
+ # After all steps complete, show the accordion with JSON
284
+ if final_image is not None:
285
+ yield (
286
+ final_image,
287
+ final_status,
288
+ gr.update(value=settings_json), # Update textbox content
289
+ gr.update(visible=True) # Make accordion visible only at the end
290
+ )
291
+
292
+ # Helper functions for shareable settings JSON
293
+ import json
294
+
295
+ def generate_settings_json(params_dict: dict) -> str:
296
+ """Generate a formatted JSON string from parameters dictionary"""
297
+ try:
298
+ return json.dumps(params_dict, indent=2, ensure_ascii=False)
299
+ except Exception as e:
300
+ return json.dumps({"error": f"Failed to generate JSON: {str(e)}"}, indent=2)
301
+
302
+ def parse_settings_json(json_string: str) -> dict:
303
+ """Parse JSON string and return parameters dictionary with validation"""
304
+ try:
305
+ if not json_string or not json_string.strip():
306
+ return {}
307
+
308
+ params = json.loads(json_string)
309
+ if not isinstance(params, dict):
310
+ return {}
311
+
312
+ return params
313
+ except json.JSONDecodeError as e:
314
+ return {"error": f"Invalid JSON: {str(e)}"}
315
+ except Exception as e:
316
+ return {"error": f"Failed to parse JSON: {str(e)}"}
317
+
318
+ def load_settings_from_json_standard(json_string: str):
319
+ """Load settings from JSON for Standard pipeline"""
320
+ try:
321
+ params = json.loads(json_string)
322
+
323
+ # Validate pipeline type
324
+ pipeline = params.get("pipeline", "standard") # Default to standard for backward compatibility
325
+ if pipeline != "standard":
326
+ error_msg = f"❌ Error: You're trying to load {pipeline.upper()} pipeline settings into the STANDARD pipeline. Please use the correct tab."
327
+ # Return empty updates for all fields + error message + make status visible
328
+ return (
329
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
330
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
331
+ gr.update(), gr.update(),
332
+ gr.update(value=error_msg, visible=True)
333
+ )
334
+
335
+ # Extract parameters with defaults
336
+ prompt = params.get("prompt", "")
337
+ text_input = params.get("text_input", "")
338
+ input_type = params.get("input_type", "URL")
339
+ image_size = params.get("image_size", 512)
340
+ border_size = params.get("border_size", 4)
341
+ error_correction = params.get("error_correction", "Medium (15%)")
342
+ module_size = params.get("module_size", 12)
343
+ module_drawer = params.get("module_drawer", "Square")
344
+ use_custom_seed = params.get("use_custom_seed", True)
345
+ seed = params.get("seed", 718313)
346
+ enable_upscale = params.get("enable_upscale", False)
347
+ enable_freeu = params.get("enable_freeu", False)
348
+
349
+ success_msg = "✅ Settings loaded successfully!"
350
+ return (
351
+ prompt, text_input, input_type, image_size, border_size,
352
+ error_correction, module_size, module_drawer, use_custom_seed,
353
+ seed, enable_upscale, enable_freeu,
354
+ gr.update(value=success_msg, visible=True)
355
+ )
356
+
357
+ except json.JSONDecodeError as e:
358
+ error_msg = f"❌ Invalid JSON format: {str(e)}"
359
+ return (
360
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
361
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
362
+ gr.update(), gr.update(),
363
+ gr.update(value=error_msg, visible=True)
364
+ )
365
+ except Exception as e:
366
+ error_msg = f"❌ Error loading settings: {str(e)}"
367
+ return (
368
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
369
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
370
+ gr.update(), gr.update(),
371
+ gr.update(value=error_msg, visible=True)
372
+ )
373
+
374
+ def load_settings_from_json_artistic(json_string: str):
375
+ """Load settings from JSON for Artistic pipeline"""
376
+ try:
377
+ params = json.loads(json_string)
378
+
379
+ # Validate pipeline type
380
+ pipeline = params.get("pipeline", "artistic") # Default to artistic for backward compatibility
381
+ if pipeline != "artistic":
382
+ error_msg = f"❌ Error: You're trying to load {pipeline.upper()} pipeline settings into the ARTISTIC pipeline. Please use the correct tab."
383
+ # Return empty updates for all fields + error message + make status visible
384
+ return (
385
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
386
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
387
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
388
+ gr.update(), gr.update(), gr.update(), gr.update(),
389
+ gr.update(value=error_msg, visible=True)
390
+ )
391
+
392
+ # Extract parameters with defaults
393
+ prompt = params.get("prompt", "")
394
+ text_input = params.get("text_input", "")
395
+ input_type = params.get("input_type", "URL")
396
+ image_size = params.get("image_size", 704)
397
+ border_size = params.get("border_size", 6)
398
+ error_correction = params.get("error_correction", "High (30%)")
399
+ module_size = params.get("module_size", 16)
400
+ module_drawer = params.get("module_drawer", "Square")
401
+ use_custom_seed = params.get("use_custom_seed", True)
402
+ seed = params.get("seed", 718313)
403
+ enable_upscale = params.get("enable_upscale", True)
404
+ enable_freeu = params.get("enable_freeu", True)
405
+ freeu_b1 = params.get("freeu_b1", 1.4)
406
+ freeu_b2 = params.get("freeu_b2", 1.3)
407
+ freeu_s1 = params.get("freeu_s1", 0.0)
408
+ freeu_s2 = params.get("freeu_s2", 1.3)
409
+ enable_sag = params.get("enable_sag", True)
410
+ sag_scale = params.get("sag_scale", 0.5)
411
+ sag_blur_sigma = params.get("sag_blur_sigma", 0.5)
412
+
413
+ success_msg = "✅ Settings loaded successfully!"
414
+ return (
415
+ prompt, text_input, input_type, image_size, border_size,
416
+ error_correction, module_size, module_drawer, use_custom_seed,
417
+ seed, enable_upscale, enable_freeu, freeu_b1, freeu_b2, freeu_s1,
418
+ freeu_s2, enable_sag, sag_scale, sag_blur_sigma,
419
+ gr.update(value=success_msg, visible=True)
420
+ )
421
+
422
+ except json.JSONDecodeError as e:
423
+ error_msg = f"❌ Invalid JSON format: {str(e)}"
424
+ return (
425
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
426
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
427
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
428
+ gr.update(), gr.update(), gr.update(), gr.update(),
429
+ gr.update(value=error_msg, visible=True)
430
+ )
431
+ except Exception as e:
432
+ error_msg = f"❌ Error loading settings: {str(e)}"
433
+ return (
434
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
435
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
436
+ gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
437
+ gr.update(), gr.update(), gr.update(), gr.update(),
438
+ gr.update(value=error_msg, visible=True)
439
+ )
440
 
441
  def add_noise_to_border_only(image_tensor, seed: int, border_size: int, image_size: int, module_size: int = 12):
442
  """
 
566
  except RuntimeError as e:
567
  error_msg = (
568
  f"Error generating QR code: {str(e)}\n"
569
+ "Try with a shorter text, increase the image size, or decrease the border size, module size, and error correction level under Change Settings Manually."
570
  )
571
  yield None, error_msg
572
  return
 
688
  image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
689
  image_np = image_np[0]
690
  pil_image = Image.fromarray(image_np)
691
+ yield pil_image, "No errors, all good! Final QR art generated and upscaled. (step 4/4)"
692
  else:
693
  # No upscaling
694
  image_tensor = get_value_at_index(vaedecode_21, 0)
695
  image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
696
  image_np = image_np[0]
697
  pil_image = Image.fromarray(image_np)
698
+ yield pil_image, "No errors, all good! Final QR art generated."
699
 
700
+ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: int, border_size: int, error_correction: str, module_size: int, module_drawer: str, seed: int, enable_upscale: bool = True, freeu_b1: float = 1.4, freeu_b2: float = 1.3, freeu_s1: float = 0.0, freeu_s2: float = 1.3, enable_sag: bool = True, sag_scale: float = 0.5, sag_blur_sigma: float = 0.5, controlnet_strength_first: float = 0.45, controlnet_strength_final: float = 0.7):
701
  # Generate QR code
702
  qr_protocol = "None" if input_type == "Plain Text" else "Https"
703
 
 
716
  except RuntimeError as e:
717
  error_msg = (
718
  f"Error generating QR code: {str(e)}\n"
719
+ "Try with a shorter text, increase the image size, or decrease the border size, module size, and error correction level under Change Settings Manually."
720
  )
721
  yield None, error_msg
722
  return
 
855
  first_pass_np = (first_pass_tensor.cpu().numpy() * 255).astype(np.uint8)
856
  first_pass_np = first_pass_np[0]
857
  first_pass_pil = Image.fromarray(first_pass_np)
858
+ # Calculate step based on border and upscale
859
+ if enable_upscale:
860
+ step_msg = "First enhancement pass complete (step 3/5)... final refinement pass" if border_size > 0 else "First enhancement pass complete (step 2/4)... final refinement pass"
861
+ else:
862
+ step_msg = "First enhancement pass complete (step 3/4)... final refinement pass" if border_size > 0 else "First enhancement pass complete (step 2/3)... final refinement pass"
863
  yield first_pass_pil, step_msg
864
 
865
  # Final ControlNet pass (second pass - refinement)
 
922
  image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
923
  image_np = image_np[0]
924
  final_image = Image.fromarray(image_np)
925
+ step_msg = "No errors, all good! Final artistic QR code generated and upscaled. (step 5/5)" if border_size > 0 else "No errors, all good! Final artistic QR code generated and upscaled. (step 4/4)"
926
  yield final_image, step_msg
927
  else:
928
  # No upscaling
 
930
  image_np = (image_tensor.cpu().numpy() * 255).astype(np.uint8)
931
  image_np = image_np[0]
932
  final_image = Image.fromarray(image_np)
933
+ step_msg = "No errors, all good! Final artistic QR code generated. (step 4/4)" if border_size > 0 else "No errors, all good! Final artistic QR code generated. (step 3/3)"
934
  yield final_image, step_msg
935
 
936
 
 
949
  - Include style keywords like 'photorealistic', 'detailed', '8k'
950
  - Choose **URL** mode for web links or **Plain Text** mode for VCARD, WiFi credentials, calendar events, etc.
951
  - Try the examples below for inspiration
952
+ - **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
953
 
954
  ### Two Modes:
955
+ - **Standard QR**: Stable, accurate QR code generation (faster, more scannable, less creative)
956
+ - **Artistic QR**: More artistic and creative results with upscaling (slower, more creative, less scannable)
957
 
958
  ### Note:
959
  Feel free to share your suggestions or feedback on how to improve the app! Thanks!
 
987
  lines=3
988
  )
989
 
990
+ # Import Settings section - separate accordion
991
+ with gr.Accordion("Import Settings from JSON", open=False):
992
+ gr.Markdown("Paste a settings JSON string (copied from a previous generation) to load all parameters at once.")
993
+ import_json_input_standard = gr.Textbox(
994
+ label="Paste Settings JSON",
995
+ placeholder='{"pipeline": "standard", "prompt": "...", "seed": 718313, ...}',
996
+ lines=3
997
+ )
998
+ import_status_standard = gr.Textbox(
999
+ label="Import Status",
1000
+ interactive=False,
1001
+ visible=False,
1002
+ lines=2
1003
+ )
1004
+ with gr.Row():
1005
+ load_settings_btn_standard = gr.Button("Load Settings", variant="primary")
1006
+ clear_json_btn_standard = gr.Button("Clear", variant="secondary")
1007
+
1008
+ # Change Settings Manually - separate accordion
1009
+ with gr.Accordion("Change Settings Manually", open=False):
1010
  # Add image size slider
1011
  image_size = gr.Slider(
1012
  minimum=512,
 
1087
  info="Enable upscaling with RealESRGAN for higher quality output (disabled by default for standard pipeline)"
1088
  )
1089
 
1090
+ # Add FreeU checkbox
1091
+ enable_freeu_standard = gr.Checkbox(
1092
+ label="Enable FreeU",
1093
+ value=False,
1094
+ info="Enable FreeU quality enhancement (disabled by default for standard pipeline)"
1095
+ )
1096
+
1097
  # Add seed controls
1098
  use_custom_seed = gr.Checkbox(
1099
  label="Use Custom Seed",
 
1106
  step=1,
1107
  value=718313,
1108
  label="Seed",
1109
+ visible=True, # Initially visible since use_custom_seed=True
1110
  info="Seed value for reproducibility. Same seed with same settings will produce the same result."
1111
  )
1112
 
 
1121
  interactive=False,
1122
  lines=3,
1123
  )
1124
+ # Wrap settings output in accordion (initially hidden)
1125
+ with gr.Accordion("Shareable Settings (JSON)", open=True, visible=False) as settings_accordion_standard:
1126
+ settings_output_standard = gr.Textbox(
1127
+ label="Copy this JSON to share your exact settings",
1128
+ interactive=True,
1129
+ lines=5,
1130
+ show_copy_button=True
1131
+ )
1132
 
1133
  # When clicking the button, it will trigger the main function
1134
  generate_btn.click(
1135
  fn=generate_standard_qr,
1136
+ inputs=[prompt_input, text_input, input_type, image_size, border_size, error_correction, module_size, module_drawer, use_custom_seed, seed, enable_upscale, enable_freeu_standard],
1137
+ outputs=[output_image, error_message, settings_output_standard, settings_accordion_standard]
1138
+ )
1139
+
1140
+ # Load Settings button event handler
1141
+ load_settings_btn_standard.click(
1142
+ fn=load_settings_from_json_standard,
1143
+ inputs=[import_json_input_standard],
1144
+ outputs=[
1145
+ prompt_input,
1146
+ text_input,
1147
+ input_type,
1148
+ image_size,
1149
+ border_size,
1150
+ error_correction,
1151
+ module_size,
1152
+ module_drawer,
1153
+ use_custom_seed,
1154
+ seed,
1155
+ enable_upscale,
1156
+ enable_freeu_standard,
1157
+ import_status_standard
1158
+ ]
1159
+ )
1160
+
1161
+ # Clear button event handler
1162
+ clear_json_btn_standard.click(
1163
+ fn=lambda: ("", gr.update(visible=False)),
1164
+ inputs=[],
1165
+ outputs=[import_json_input_standard, import_status_standard]
1166
+ )
1167
+
1168
+ # Seed slider visibility toggle
1169
+ use_custom_seed.change(
1170
+ fn=lambda x: gr.update(visible=x),
1171
+ inputs=[use_custom_seed],
1172
+ outputs=[seed]
1173
  )
1174
 
1175
  # Add examples
 
1319
  lines=3
1320
  )
1321
 
1322
+ # Import Settings section - separate accordion
1323
+ with gr.Accordion("Import Settings from JSON", open=False):
1324
+ gr.Markdown("Paste a settings JSON string (copied from a previous generation) to load all parameters at once.")
1325
+ import_json_input_artistic = gr.Textbox(
1326
+ label="Paste Settings JSON",
1327
+ placeholder='{"pipeline": "artistic", "prompt": "...", "seed": 718313, ...}',
1328
+ lines=3
1329
+ )
1330
+ import_status_artistic = gr.Textbox(
1331
+ label="Import Status",
1332
+ interactive=False,
1333
+ visible=False,
1334
+ lines=2
1335
+ )
1336
+ with gr.Row():
1337
+ load_settings_btn_artistic = gr.Button("Load Settings", variant="primary")
1338
+ clear_json_btn_artistic = gr.Button("Clear", variant="secondary")
1339
+
1340
+ # Change Settings Manually - separate accordion
1341
+ with gr.Accordion("Change Settings Manually", open=False):
1342
  # Add image size slider for artistic QR
1343
  artistic_image_size = gr.Slider(
1344
  minimum=512,
 
1431
  step=1,
1432
  value=718313,
1433
  label="Seed",
1434
+ visible=True, # Initially visible since artistic_use_custom_seed=True
1435
  info="Seed value for reproducibility. Same seed with same settings will produce the same result."
1436
  )
1437
 
1438
  # FreeU Parameters
1439
  gr.Markdown("### FreeU Quality Enhancement")
1440
+ enable_freeu_artistic = gr.Checkbox(
1441
+ label="Enable FreeU",
1442
+ value=True,
1443
+ info="Enable FreeU quality enhancement (enabled by default for artistic pipeline)"
1444
+ )
1445
  freeu_b1 = gr.Slider(
1446
  minimum=1.0,
1447
  maximum=1.6,
 
1494
  minimum=0.0,
1495
  maximum=5.0,
1496
  step=0.1,
1497
+ value=0.5,
1498
  label="SAG Blur Sigma",
1499
+ info="Blur amount for artistic blending. Higher values create softer, more artistic effects. Range: 0.0-5.0, Default: 0.5"
1500
  )
1501
 
1502
  # The generate button for artistic QR
 
1510
  interactive=False,
1511
  lines=3,
1512
  )
1513
+ # Wrap settings output in accordion (initially hidden)
1514
+ with gr.Accordion("Shareable Settings (JSON)", open=True, visible=False) as settings_accordion_artistic:
1515
+ settings_output_artistic = gr.Textbox(
1516
+ label="Copy this JSON to share your exact settings",
1517
+ interactive=True,
1518
+ lines=5,
1519
+ show_copy_button=True
1520
+ )
1521
 
1522
  # When clicking the button, it will trigger the artistic function
1523
  artistic_generate_btn.click(
1524
  fn=generate_artistic_qr,
1525
+ inputs=[artistic_prompt_input, artistic_text_input, artistic_input_type, artistic_image_size, artistic_border_size, artistic_error_correction, artistic_module_size, artistic_module_drawer, artistic_use_custom_seed, artistic_seed, artistic_enable_upscale, enable_freeu_artistic, freeu_b1, freeu_b2, freeu_s1, freeu_s2, enable_sag, sag_scale, sag_blur_sigma],
1526
+ outputs=[artistic_output_image, artistic_error_message, settings_output_artistic, settings_accordion_artistic]
1527
+ )
1528
+
1529
+ # Load Settings button event handler
1530
+ load_settings_btn_artistic.click(
1531
+ fn=load_settings_from_json_artistic,
1532
+ inputs=[import_json_input_artistic],
1533
+ outputs=[
1534
+ artistic_prompt_input,
1535
+ artistic_text_input,
1536
+ artistic_input_type,
1537
+ artistic_image_size,
1538
+ artistic_border_size,
1539
+ artistic_error_correction,
1540
+ artistic_module_size,
1541
+ artistic_module_drawer,
1542
+ artistic_use_custom_seed,
1543
+ artistic_seed,
1544
+ artistic_enable_upscale,
1545
+ enable_freeu_artistic,
1546
+ freeu_b1,
1547
+ freeu_b2,
1548
+ freeu_s1,
1549
+ freeu_s2,
1550
+ enable_sag,
1551
+ sag_scale,
1552
+ sag_blur_sigma,
1553
+ import_status_artistic
1554
+ ]
1555
+ )
1556
+
1557
+ # Clear button event handler for artistic tab
1558
+ clear_json_btn_artistic.click(
1559
+ fn=lambda: ("", gr.update(visible=False)),
1560
+ inputs=[],
1561
+ outputs=[import_json_input_artistic, import_status_artistic]
1562
+ )
1563
+
1564
+ # Seed slider visibility toggle for artistic tab
1565
+ artistic_use_custom_seed.change(
1566
+ fn=lambda x: gr.update(visible=x),
1567
+ inputs=[artistic_use_custom_seed],
1568
+ outputs=[artistic_seed]
1569
  )
1570
 
1571
  # Add examples for artistic QR
1572
  artistic_examples = [
1573
  [
1574
+ "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",
1575
  "https://www.google.com",
1576
  "URL",
1577
+ 640, # Image size
1578
+ 6, # Border
1579
+ "Medium (15%)", # Error correction
1580
+ 14, # Module size
1581
  "Square"
1582
  ],
1583
  [
1584
  "some cards on poker tale, realistic, great details, realistic, great details,absence of people, Detailed and Intricate, CGI, Photoshoot,rim light, 8k, 16k, ultra detail",
1585
  "https://store.steampowered.com",
1586
  "URL",
1587
+ 768, # Image size
1588
+ 6, # Border
1589
+ "High (30%)", # Error correction
1590
+ 16, # Module size
1591
  "Square"
1592
  ],
1593
  [
1594
  "a beautiful sunset over mountains, photorealistic, detailed landscape, golden hour, dramatic lighting, 8k, ultra detailed",
1595
  "https://github.com",
1596
  "URL",
1597
+ 704, # Image size (default)
1598
+ 6, # Border
1599
+ "High (30%)", # Error correction
1600
+ 16, # Module size
1601
  "Square"
1602
  ],
1603
  [
1604
  "underwater scene with coral reef and tropical fish, photorealistic, detailed, crystal clear water, sunlight rays, 8k, ultra detailed",
1605
  "https://twitter.com",
1606
  "URL",
1607
+ 704, # Image size (default)
1608
+ 6, # Border
1609
+ "High (30%)", # Error correction
1610
+ 16, # Module size
1611
  "Square"
1612
  ],
1613
  [
1614
  "futuristic cityscape with flying cars and neon lights, cyberpunk style, detailed architecture, night scene, 8k, ultra detailed",
1615
  "https://linkedin.com",
1616
  "URL",
1617
+ 704, # Image size (default)
1618
+ 6, # Border
1619
+ "High (30%)", # Error correction
1620
+ 16, # Module size
1621
  "Square"
1622
  ],
1623
  [
1624
  "vintage camera on wooden table, photorealistic, detailed textures, soft lighting, bokeh background, 8k, ultra detailed",
1625
  "https://instagram.com",
1626
  "URL",
1627
+ 704, # Image size (default)
1628
+ 6, # Border
1629
+ "High (30%)", # Error correction
1630
+ 16, # Module size
1631
  "Square"
1632
  ],
1633
  [
 
1686
  ],
1687
  outputs=[artistic_output_image, artistic_error_message],
1688
  fn=generate_artistic_qr,
1689
+ cache_examples=True
1690
  )
1691
 
1692
  app.launch(share=False, mcp_server=True)