yukee1992 commited on
Commit
5237974
Β·
verified Β·
1 Parent(s): 05fe702

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +204 -21
app.py CHANGED
@@ -234,11 +234,44 @@ def save_image_to_persistent_storage(image, prompt, subfolder=""):
234
  print(f"❌ Failed to save to persistent storage: {e}")
235
  return None
236
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  def generate_test_image(prompt, model_choice, style_choice):
238
  """Generate a single image for testing and save to persistent storage"""
239
  try:
240
  if not prompt.strip():
241
- return None, "❌ Please enter a prompt"
242
 
243
  print(f"🎨 Generating test image with prompt: {prompt}")
244
 
@@ -276,12 +309,12 @@ def generate_test_image(prompt, model_choice, style_choice):
276
 
277
  πŸ’‘ You can also use the download button below the image!"""
278
 
279
- return image, status_msg
280
 
281
  except Exception as e:
282
  error_msg = f"❌ Generation failed: {str(e)}"
283
  print(error_msg)
284
- return None, error_msg
285
 
286
  # JOB MANAGEMENT FUNCTIONS
287
  def create_job(story_request: StorybookRequest) -> str:
@@ -393,21 +426,77 @@ async def list_test_images():
393
  "created": os.path.getctime(full_path) if os.path.exists(full_path) else 0
394
  })
395
 
 
 
396
  return {
397
  "status": "success",
398
  "image_count": len(images_list),
399
  "image_directory": PERSISTENT_IMAGE_DIR,
 
400
  "images": sorted(images_list, key=lambda x: x["created"], reverse=True)
401
  }
402
  except Exception as e:
403
  return {"status": "error", "message": str(e)}
404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
405
  # GRADIO INTERFACE
406
  def create_test_interface():
407
  with gr.Blocks(title="High-Quality Image Generator", theme="soft") as demo:
408
  gr.Markdown("# 🎨 High-Quality Image Generator")
409
  gr.Markdown("**Generate studio-quality images that auto-save to your Files tab!**")
410
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  with gr.Row():
412
  with gr.Column(scale=1):
413
  model_dropdown = gr.Dropdown(
@@ -441,13 +530,19 @@ def create_test_interface():
441
  with gr.Column(scale=2):
442
  image_output = gr.Image(
443
  label="Generated Image",
444
- height=500,
445
  show_download_button=True,
446
  show_share_button=True
447
  )
 
 
 
 
 
 
448
  status_output = gr.Textbox(
449
  label="Status & File Location",
450
- lines=5,
451
  show_copy_button=True
452
  )
453
 
@@ -466,43 +561,129 @@ def create_test_interface():
466
  outputs=prompt_input
467
  )
468
 
469
- # Image browser section
470
- with gr.Accordion("πŸ“ Browse Generated Images", open=False):
471
  gr.Markdown(f"### Images saved in `{PERSISTENT_IMAGE_DIR}/`")
472
- refresh_btn = gr.Button("πŸ”„ Refresh File List")
473
- file_list = gr.File(
 
 
 
 
474
  label="Generated Images",
475
- file_count="multiple",
476
- type="filepath",
477
- height=300
 
478
  )
479
 
 
 
 
 
480
  def refresh_file_list():
481
  """Refresh the list of generated images"""
482
  try:
483
  image_files = []
 
 
484
  for root, dirs, files in os.walk(PERSISTENT_IMAGE_DIR):
485
  for file in files:
486
  if file.endswith(('.png', '.jpg', '.jpeg')):
487
  full_path = os.path.join(root, file)
488
- image_files.append(full_path)
489
- return image_files
 
 
 
490
  except Exception as e:
491
  print(f"Error refreshing file list: {e}")
492
- return []
493
 
494
- refresh_btn.click(fn=refresh_file_list, outputs=file_list)
495
- # Auto-refresh on load
496
- demo.load(fn=refresh_file_list, outputs=file_list)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
497
 
 
498
  generate_btn.click(
499
  fn=generate_test_image,
500
  inputs=[prompt_input, model_dropdown, style_dropdown],
501
- outputs=[image_output, status_output]
502
  ).then(
503
  fn=refresh_file_list,
504
- outputs=file_list
505
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
506
 
507
  return demo
508
 
@@ -528,7 +709,8 @@ async def files_info():
528
  return {
529
  "persistent_directory": PERSISTENT_IMAGE_DIR,
530
  "exists": os.path.exists(PERSISTENT_IMAGE_DIR),
531
- "file_structure": file_structure
 
532
  }
533
  except Exception as e:
534
  return {"error": str(e)}
@@ -541,4 +723,5 @@ if __name__ == "__main__":
541
  print("πŸš€ Starting High-Quality Storybook Generator...")
542
  print(f"πŸ“ Persistent image directory: {PERSISTENT_IMAGE_DIR}")
543
  print("βœ… Images will auto-save to your Files tab")
 
544
  gradio_app.launch(server_name="0.0.0.0", server_port=7860)
 
234
  print(f"❌ Failed to save to persistent storage: {e}")
235
  return None
236
 
237
+ def delete_image_file(filepath):
238
+ """Delete an image file from persistent storage"""
239
+ try:
240
+ if os.path.exists(filepath):
241
+ os.remove(filepath)
242
+ print(f"πŸ—‘οΈ Deleted image: {filepath}")
243
+ return True, f"βœ… Successfully deleted: {os.path.basename(filepath)}"
244
+ else:
245
+ return False, f"❌ File not found: {filepath}"
246
+ except Exception as e:
247
+ return False, f"❌ Error deleting file: {str(e)}"
248
+
249
+ def get_storage_info():
250
+ """Get information about storage usage"""
251
+ try:
252
+ total_size = 0
253
+ file_count = 0
254
+
255
+ for root, dirs, files in os.walk(PERSISTENT_IMAGE_DIR):
256
+ for file in files:
257
+ filepath = os.path.join(root, file)
258
+ if os.path.exists(filepath):
259
+ total_size += os.path.getsize(filepath)
260
+ file_count += 1
261
+
262
+ return {
263
+ "total_files": file_count,
264
+ "total_size_mb": round(total_size / (1024 * 1024), 2),
265
+ "directory": PERSISTENT_IMAGE_DIR
266
+ }
267
+ except Exception as e:
268
+ return {"error": str(e)}
269
+
270
  def generate_test_image(prompt, model_choice, style_choice):
271
  """Generate a single image for testing and save to persistent storage"""
272
  try:
273
  if not prompt.strip():
274
+ return None, "❌ Please enter a prompt", None
275
 
276
  print(f"🎨 Generating test image with prompt: {prompt}")
277
 
 
309
 
310
  πŸ’‘ You can also use the download button below the image!"""
311
 
312
+ return image, status_msg, saved_path
313
 
314
  except Exception as e:
315
  error_msg = f"❌ Generation failed: {str(e)}"
316
  print(error_msg)
317
+ return None, error_msg, None
318
 
319
  # JOB MANAGEMENT FUNCTIONS
320
  def create_job(story_request: StorybookRequest) -> str:
 
426
  "created": os.path.getctime(full_path) if os.path.exists(full_path) else 0
427
  })
428
 
429
+ storage_info = get_storage_info()
430
+
431
  return {
432
  "status": "success",
433
  "image_count": len(images_list),
434
  "image_directory": PERSISTENT_IMAGE_DIR,
435
+ "storage_info": storage_info,
436
  "images": sorted(images_list, key=lambda x: x["created"], reverse=True)
437
  }
438
  except Exception as e:
439
  return {"status": "error", "message": str(e)}
440
 
441
+ @app.delete("/api/delete-image/{image_path:path}")
442
+ async def delete_image(image_path: str):
443
+ """API endpoint to delete an image"""
444
+ try:
445
+ # Security check: ensure the path is within our image directory
446
+ full_path = os.path.join(PERSISTENT_IMAGE_DIR, image_path)
447
+ if not full_path.startswith(os.path.abspath(PERSISTENT_IMAGE_DIR)):
448
+ return {"status": "error", "message": "Invalid path"}
449
+
450
+ success, message = delete_image_file(full_path)
451
+ return {"status": "success" if success else "error", "message": message}
452
+ except Exception as e:
453
+ return {"status": "error", "message": str(e)}
454
+
455
+ @app.delete("/api/clear-all-images")
456
+ async def clear_all_images():
457
+ """API endpoint to delete all generated images"""
458
+ try:
459
+ deleted_count = 0
460
+ error_count = 0
461
+
462
+ for root, dirs, files in os.walk(PERSISTENT_IMAGE_DIR):
463
+ for file in files:
464
+ if file.endswith(('.png', '.jpg', '.jpeg')):
465
+ filepath = os.path.join(root, file)
466
+ success, _ = delete_image_file(filepath)
467
+ if success:
468
+ deleted_count += 1
469
+ else:
470
+ error_count += 1
471
+
472
+ return {
473
+ "status": "success",
474
+ "message": f"Deleted {deleted_count} images, {error_count} errors",
475
+ "deleted_count": deleted_count,
476
+ "error_count": error_count
477
+ }
478
+ except Exception as e:
479
+ return {"status": "error", "message": str(e)}
480
+
481
  # GRADIO INTERFACE
482
  def create_test_interface():
483
  with gr.Blocks(title="High-Quality Image Generator", theme="soft") as demo:
484
  gr.Markdown("# 🎨 High-Quality Image Generator")
485
  gr.Markdown("**Generate studio-quality images that auto-save to your Files tab!**")
486
 
487
+ # Storage info display
488
+ storage_info = gr.Textbox(
489
+ label="πŸ“Š Storage Information",
490
+ interactive=False,
491
+ lines=2
492
+ )
493
+
494
+ def update_storage_info():
495
+ info = get_storage_info()
496
+ if "error" not in info:
497
+ return f"πŸ“ Storage: {info['total_files']} images, {info['total_size_mb']} MB used"
498
+ return "πŸ“ Storage: Unable to calculate"
499
+
500
  with gr.Row():
501
  with gr.Column(scale=1):
502
  model_dropdown = gr.Dropdown(
 
530
  with gr.Column(scale=2):
531
  image_output = gr.Image(
532
  label="Generated Image",
533
+ height=400,
534
  show_download_button=True,
535
  show_share_button=True
536
  )
537
+
538
+ # Delete button for current image
539
+ current_file_path = gr.State() # Hidden state to store file path
540
+ delete_btn = gr.Button("πŸ—‘οΈ Delete This Image", variant="stop", size="sm")
541
+ delete_status = gr.Textbox(label="Delete Status", interactive=False, lines=2)
542
+
543
  status_output = gr.Textbox(
544
  label="Status & File Location",
545
+ lines=4,
546
  show_copy_button=True
547
  )
548
 
 
561
  outputs=prompt_input
562
  )
563
 
564
+ # Image browser section with delete functionality
565
+ with gr.Accordion("πŸ“ Manage Generated Images", open=False):
566
  gr.Markdown(f"### Images saved in `{PERSISTENT_IMAGE_DIR}/`")
567
+
568
+ with gr.Row():
569
+ refresh_btn = gr.Button("πŸ”„ Refresh List")
570
+ clear_all_btn = gr.Button("πŸ—‘οΈ Clear All Images", variant="stop")
571
+
572
+ file_list = gr.Gallery(
573
  label="Generated Images",
574
+ show_label=True,
575
+ elem_id="gallery",
576
+ columns=3,
577
+ height="auto"
578
  )
579
 
580
+ selected_file_info = gr.Textbox(label="Selected Image Info", interactive=False)
581
+ delete_selected_btn = gr.Button("πŸ—‘οΈ Delete Selected Image", variant="stop")
582
+ delete_selected_status = gr.Textbox(label="Delete Status", interactive=False)
583
+
584
  def refresh_file_list():
585
  """Refresh the list of generated images"""
586
  try:
587
  image_files = []
588
+ image_info = []
589
+
590
  for root, dirs, files in os.walk(PERSISTENT_IMAGE_DIR):
591
  for file in files:
592
  if file.endswith(('.png', '.jpg', '.jpeg')):
593
  full_path = os.path.join(root, file)
594
+ if os.path.exists(full_path):
595
+ image_files.append(full_path)
596
+ image_info.append(f"πŸ“„ {file}\nπŸ“ {os.path.relpath(root, PERSISTENT_IMAGE_DIR)}")
597
+
598
+ return image_files, update_storage_info()
599
  except Exception as e:
600
  print(f"Error refreshing file list: {e}")
601
+ return [], "❌ Error loading images"
602
 
603
+ def get_file_info(evt: gr.SelectData):
604
+ """Get info about selected file"""
605
+ if evt.value:
606
+ filepath = evt.value
607
+ filename = os.path.basename(filepath)
608
+ size_kb = os.path.getsize(filepath) / 1024 if os.path.exists(filepath) else 0
609
+ return f"Selected: {filename}\nSize: {size_kb:.1f} KB\nPath: {filepath}"
610
+ return "No image selected"
611
+
612
+ def delete_selected_file(selected_files):
613
+ """Delete the selected file"""
614
+ if not selected_files:
615
+ return "❌ No image selected", None, update_storage_info()
616
+
617
+ filepath = selected_files[0] if isinstance(selected_files, list) else selected_files
618
+ success, message = delete_image_file(filepath)
619
+
620
+ # Refresh the file list
621
+ new_files, storage_info = refresh_file_list()
622
+ return message, new_files, storage_info
623
+
624
+ def clear_all_images_func():
625
+ """Clear all images"""
626
+ try:
627
+ deleted_count = 0
628
+ for root, dirs, files in os.walk(PERSISTENT_IMAGE_DIR):
629
+ for file in files:
630
+ if file.endswith(('.png', '.jpg', '.jpeg')):
631
+ filepath = os.path.join(root, file)
632
+ success, _ = delete_image_file(filepath)
633
+ if success:
634
+ deleted_count += 1
635
+
636
+ new_files, storage_info = refresh_file_list()
637
+ return f"βœ… Deleted {deleted_count} images", new_files, storage_info
638
+ except Exception as e:
639
+ return f"❌ Error: {str(e)}", None, update_storage_info()
640
+
641
+ # Connect events
642
+ refresh_btn.click(fn=refresh_file_list, outputs=[file_list, storage_info])
643
+ clear_all_btn.click(fn=clear_all_images_func, outputs=[delete_selected_status, file_list, storage_info])
644
+ file_list.select(fn=get_file_info, outputs=selected_file_info)
645
+ delete_selected_btn.click(
646
+ fn=delete_selected_file,
647
+ inputs=file_list,
648
+ outputs=[delete_selected_status, file_list, storage_info]
649
+ )
650
+
651
+ # Delete current image functionality
652
+ def delete_current_image(filepath):
653
+ """Delete the currently displayed image"""
654
+ if not filepath:
655
+ return "❌ No image to delete", None, None, update_storage_info()
656
+
657
+ success, message = delete_image_file(filepath)
658
+ new_files, storage_info = refresh_file_list()
659
+
660
+ if success:
661
+ return message, None, "βœ… Image deleted successfully!", storage_info
662
+ else:
663
+ return message, None, "❌ Delete failed", storage_info
664
 
665
+ # Connect main generate button
666
  generate_btn.click(
667
  fn=generate_test_image,
668
  inputs=[prompt_input, model_dropdown, style_dropdown],
669
+ outputs=[image_output, status_output, current_file_path]
670
  ).then(
671
  fn=refresh_file_list,
672
+ outputs=[file_list, storage_info]
673
  )
674
+
675
+ # Connect delete button
676
+ delete_btn.click(
677
+ fn=delete_current_image,
678
+ inputs=current_file_path,
679
+ outputs=[delete_status, image_output, status_output, storage_info]
680
+ ).then(
681
+ fn=refresh_file_list,
682
+ outputs=[file_list, storage_info]
683
+ )
684
+
685
+ # Initialize on load
686
+ demo.load(fn=refresh_file_list, outputs=[file_list, storage_info])
687
 
688
  return demo
689
 
 
709
  return {
710
  "persistent_directory": PERSISTENT_IMAGE_DIR,
711
  "exists": os.path.exists(PERSISTENT_IMAGE_DIR),
712
+ "file_structure": file_structure,
713
+ "storage_info": get_storage_info()
714
  }
715
  except Exception as e:
716
  return {"error": str(e)}
 
723
  print("πŸš€ Starting High-Quality Storybook Generator...")
724
  print(f"πŸ“ Persistent image directory: {PERSISTENT_IMAGE_DIR}")
725
  print("βœ… Images will auto-save to your Files tab")
726
+ print("πŸ—‘οΈ Delete functionality enabled for storage management")
727
  gradio_app.launch(server_name="0.0.0.0", server_port=7860)