minotrey commited on
Commit
e9dd3c0
ยท
1 Parent(s): ad395bd

Implement custom Gradio State-based login system

Browse files

- Remove Gradio's built-in HTTP auth
- Add login/logout pages with session management
- Implement handle_login() and handle_logout() functions
- Use gr.State for session persistence
- Login page visible by default, main page hidden
- Logout button in main page header

Note: Page refresh will log out user (State limitation)

Files changed (1) hide show
  1. app.py +678 -615
app.py CHANGED
@@ -473,153 +473,203 @@ def create_app():
473
 
474
  with gr.Blocks(title="PixelFree v3.0.0", theme=gr.themes.Soft(), css=custom_css) as demo:
475
 
476
- # ๋ฉ”์ธ ํ—ค๋”
477
- gr.Markdown("# ๐ŸŽจ PixelFree Studio")
478
-
479
- # ์ž…๋ ฅ ์„น์…˜
480
- gr.Markdown("## ๐Ÿ“ธ ์ž…๋ ฅ ์ด๋ฏธ์ง€")
481
-
482
- input_state = gr.State(None)
483
- bg_removed_state = gr.State(None)
484
- selected_bg_state = gr.State(None)
485
- selected_face_state = gr.State(None)
486
- last_output_state = gr.State(None)
487
-
488
- input_image = gr.Image(label="์ž…๋ ฅ ์ด๋ฏธ์ง€", type="pil", height=540)
489
-
490
- # ๊ฒฐ๊ณผ ์„น์…˜
491
- gr.Markdown("## โœจ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€")
492
- output_image = gr.Image(label="์ฒ˜๋ฆฌ๋œ ์ด๋ฏธ์ง€", type="pil", height=500, interactive=False)
493
- download_btn = gr.DownloadButton(
494
- "๐Ÿ“ฅ ์‚ฌ์ง„ ๋‹ค์šด๋กœ๋“œ",
495
- value=None,
496
- interactive=False
497
- )
498
-
499
- # ๋น„๋””์˜ค ์ƒ์„ฑ ์„น์…˜
500
- gr.Markdown("## ๐ŸŽฌ AI ๋น„๋””์˜ค ์ƒ์„ฑ")
501
- with gr.Row():
502
- video_output = gr.Video(
503
- label="์ƒ์„ฑ๋œ ์˜์ƒ",
504
- height=360,
505
- interactive=False,
506
- autoplay=True,
507
  )
508
- with gr.Column():
509
- gr.Markdown("์ตœ๊ทผ ์ด๋ฏธ์ง€ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์งง์€ ํด๋ฆฝ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.")
510
- generate_video_btn = gr.Button(
511
- "๐ŸŽฌ ์˜์ƒ ์ƒ์„ฑํ•˜๊ธฐ",
512
- variant="primary",
513
- size="lg",
514
- interactive=False,
515
- )
516
-
517
- # ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ ์„น์…˜
518
- gr.Markdown("## ๐ŸŽฏ AI ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ")
519
- remove_bg_btn = gr.Button("๐Ÿš€ ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ ์‹คํ–‰", variant="primary", size="lg", interactive=False)
520
-
521
- # AI ์ƒ์„ฑ ๊ธฐ๋Šฅ ์„น์…˜
522
- gr.Markdown("## ๐ŸŽจ AI ์ƒ์„ฑ ๊ธฐ๋Šฅ")
523
- with gr.Row():
524
- with gr.Column():
525
- gr.Markdown("### ๐Ÿž๏ธ ๋ฐฐ๊ฒฝ ์ƒ์„ฑ")
526
- with gr.Tabs():
527
- with gr.Tab("๐Ÿ  ์‹ค๋‚ด"):
528
- indoor_gallery = gr.Gallery(
529
- value=bg_images["indoor"],
530
- columns=4,
531
- show_label=False, interactive=False,
532
- allow_preview=False,
533
- object_fit="contain"
534
- )
535
- with gr.Tab("๐ŸŒณ ์•„์›ƒ๋„์–ด"):
536
- outdoor_gallery = gr.Gallery(
537
- value=bg_images["outdoor"],
538
- columns=4,
539
- rows=4, show_label=False, interactive=False,
540
- allow_preview=False,
541
- object_fit="contain"
542
- )
543
- hq_checkbox = gr.Checkbox(label="โœจ ๊ณ ํ’ˆ์งˆ ๋ชจ๋“œ", value=False)
544
- generate_bg_btn = gr.Button("๐ŸŽจ ๋ฐฐ๊ฒฝ ์ƒ์„ฑํ•˜๊ธฐ", variant="secondary", interactive=False, size="lg")
545
- with gr.Column():
546
- gr.Markdown("### ๐Ÿ‘ค ์–ผ๊ตด ๊ต์ฒด")
547
- with gr.Tabs():
548
- with gr.Tab("๐Ÿ‘จ ๋‚จ์„ฑ"):
549
- man_gallery = gr.Gallery(
550
- value=face_images["man_pil"],
551
- columns=4,
552
- rows=2, show_label=False, interactive=False,
553
- allow_preview=False,
554
- object_fit="contain"
555
- )
556
- with gr.Tab("๐Ÿ‘ฉ ์—ฌ์„ฑ"):
557
- woman_gallery = gr.Gallery(
558
- value=face_images["woman_pil"],
559
- columns=4,
560
- rows=2, show_label=False, interactive=False,
561
- allow_preview=False,
562
- object_fit="contain"
563
- )
564
- swap_face_btn = gr.Button("๐Ÿ”„ ์–ผ๊ตด ๊ต์ฒด ์ ์šฉ", variant="secondary", interactive=False, size="lg")
565
- # Collapsible history section with image grid
566
- with gr.Accordion("๐Ÿ“œ ์ž‘์—… ํžˆ์Šคํ† ๋ฆฌ", open=False):
567
- # History gallery with preview enabled
568
- history_gallery = gr.Gallery(
569
- value=[img for img, _ in get_history_items(20)],
570
- label=None,
571
- show_label=False,
572
- columns=5,
573
- rows=4,
574
- height=500,
575
- object_fit="contain",
576
- allow_preview=True,
577
- elem_id="history-gallery",
578
- interactive=False
579
  )
580
-
581
- def make_download_update(image: Optional[Image.Image], prefix: str = "pixelfree_output"):
582
- if image is None:
583
- return gr.update(value=None, interactive=False)
584
- filename = f"{prefix}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
585
- temp_path = f"/tmp/{filename}"
586
- image.save(temp_path, "PNG")
587
- return gr.update(value=temp_path, interactive=True)
588
-
589
- def history_update():
590
- """Update history gallery with original images."""
591
- items = get_history_items(20)
592
- images = [img for img, _ in items]
593
- return gr.update(value=images)
594
-
595
- def disable_all_buttons():
596
- disabled = gr.update(interactive=False)
597
- return disabled, disabled, disabled, disabled
598
-
599
- def compute_button_states(
600
- input_img: Optional[Image.Image],
601
- last_output: Optional[Image.Image],
602
- bg_removed: Optional[Image.Image],
603
- selected_bg: Optional[Image.Image],
604
- selected_face: Optional[Image.Image],
605
- ):
606
- remove_ready = gr.update(interactive=input_img is not None)
607
- video_ready = gr.update(interactive=input_img is not None)
608
- bg_ready = gr.update(interactive=(bg_removed is not None and selected_bg is not None))
609
- swap_ready = gr.update(
610
- interactive=(selected_face is not None and ((last_output is not None) or (input_img is not None)))
611
  )
612
- return remove_ready, video_ready, bg_ready, swap_ready
613
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
 
615
- def on_upload(new_image: Optional[Image.Image]):
616
- if new_image is None:
617
- gr.Warning("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
618
- remove_ready, video_ready, bg_ready, swap_ready = disable_all_buttons()
619
- return (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
620
  None,
621
  None,
622
  None,
 
 
 
 
 
623
  None,
624
  None,
625
  gr.update(value=None),
@@ -632,156 +682,151 @@ def create_app():
632
  history_update(),
633
  )
634
 
635
- gr.Info("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.")
636
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
637
- new_image,
638
- None,
639
- None,
640
- None,
641
- None,
642
- )
643
- return (
644
- new_image,
645
- None,
646
- None,
647
- None,
648
- None,
649
- gr.update(value=None),
650
- make_download_update(None),
651
- gr.update(value=None),
652
- remove_ready,
653
- video_ready,
654
- bg_ready,
655
- swap_ready,
656
- history_update(),
657
- )
658
-
659
- def handle_remove_background(
660
- input_img: Optional[Image.Image],
661
- current_bg_removed: Optional[Image.Image],
662
- selected_bg: Optional[Image.Image],
663
- current_output: Optional[Image.Image],
664
- selected_face: Optional[Image.Image],
665
- ):
666
- if input_img is None:
667
- gr.Warning("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ๋จผ์ € ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
668
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
669
- input_img,
670
- current_output,
671
- current_bg_removed,
672
- selected_bg,
673
- selected_face,
674
- )
675
  yield (
676
  current_bg_removed,
677
  current_output,
678
  gr.update(),
679
  make_download_update(current_output),
680
- bg_ready,
681
- swap_ready,
682
- remove_ready,
683
- video_ready,
684
  history_update(),
685
  )
686
- return
687
-
688
- remove_disabled, video_disabled, bg_disabled, swap_disabled = disable_all_buttons()
689
- yield (
690
- current_bg_removed,
691
- current_output,
692
- gr.update(),
693
- make_download_update(current_output),
694
- bg_disabled,
695
- swap_disabled,
696
- remove_disabled,
697
- video_disabled,
698
- history_update(),
699
- )
700
 
701
- removed, message = processor.remove_background(input_img)
702
- if removed is None:
703
- gr.Warning(message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
704
  remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
705
  input_img,
706
- current_output,
707
- current_bg_removed,
708
  selected_bg,
709
  selected_face,
710
  )
711
  yield (
712
- current_bg_removed,
713
- current_output,
714
- gr.update(value=current_output),
715
- make_download_update(current_output),
716
  bg_ready,
717
  swap_ready,
718
  remove_ready,
719
  video_ready,
720
  history_update(),
721
  )
722
- return
723
-
724
- gr.Info(message)
725
- add_to_history(removed, "bg_remove")
726
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
727
- input_img,
728
- removed,
729
- removed,
730
- selected_bg,
731
- selected_face,
732
- )
733
- yield (
734
- removed,
735
- removed,
736
- gr.update(value=removed),
737
- make_download_update(removed, "background_removed"),
738
- bg_ready,
739
- swap_ready,
740
- remove_ready,
741
- video_ready,
742
- history_update(),
743
- )
744
 
745
- def on_generate_video(
746
- last_output: Optional[Image.Image],
747
- input_img: Optional[Image.Image],
748
- current_bg_removed: Optional[Image.Image],
749
- selected_bg: Optional[Image.Image],
750
- selected_face: Optional[Image.Image],
751
- ):
752
- base_image = last_output or input_img
753
- if base_image is None:
754
- gr.Warning("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ๋จผ์ € ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
755
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
756
- input_img,
757
- last_output,
758
- current_bg_removed,
759
- selected_bg,
760
- selected_face,
761
- )
 
 
 
 
 
 
 
 
 
 
 
762
  yield (
763
- gr.update(value=None),
764
  history_update(),
765
- remove_ready,
766
- video_ready,
767
- bg_ready,
768
- swap_ready,
769
  )
770
- return
771
-
772
- remove_disabled, video_disabled, bg_disabled, swap_disabled = disable_all_buttons()
773
- yield (
774
- gr.update(),
775
- history_update(),
776
- remove_disabled,
777
- video_disabled,
778
- bg_disabled,
779
- swap_disabled,
780
- )
781
 
782
- video_path, message = processor.generate_video(base_image)
783
- if video_path is None:
784
- gr.Warning(message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785
  remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
786
  input_img,
787
  last_output,
@@ -790,419 +835,438 @@ def create_app():
790
  selected_face,
791
  )
792
  yield (
793
- gr.update(value=None),
794
  history_update(),
795
  remove_ready,
796
  video_ready,
797
  bg_ready,
798
  swap_ready,
799
  )
800
- return
801
-
802
- gr.Info(message)
803
- add_to_history(base_image, "video")
804
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
805
- input_img,
806
- last_output,
807
- current_bg_removed,
808
- selected_bg,
809
- selected_face,
810
- )
811
- yield (
812
- gr.update(value=video_path),
813
- history_update(),
814
- remove_ready,
815
- video_ready,
816
- bg_ready,
817
- swap_ready,
818
- )
819
 
820
- def load_background_image(category: str, index: int) -> Optional[Image.Image]:
821
- key = f"{category}_pil"
822
- paths = bg_images.get(key, [])
823
- if 0 <= index < len(paths):
824
- path = paths[index]
825
- return load_full_image(path)
826
- return None
827
-
828
- def on_select_background(
829
- evt: gr.SelectData,
830
- category: str,
831
- bg_removed: Optional[Image.Image],
832
- ):
833
- index = getattr(evt, "index", None)
834
- if index is None:
835
- gr.Warning("์„ ํƒ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
836
- return None, gr.update(interactive=False)
837
- image = load_background_image(category, index)
838
- if image is None:
839
- gr.Warning("์„ ํƒํ•œ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.")
840
- return None, gr.update(interactive=False)
841
- gr.Info("๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.")
842
- ready = gr.update(interactive=bg_removed is not None)
843
- return image, ready
844
-
845
- def on_generate_background(
846
- last_output: Optional[Image.Image],
847
- selected_bg: Optional[Image.Image],
848
- hq_mode: bool,
849
- input_img: Optional[Image.Image],
850
- current_bg_removed: Optional[Image.Image],
851
- selected_face: Optional[Image.Image],
852
- ):
853
- if last_output is None:
854
- gr.Warning("๋จผ์ € ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ๋ฅผ ์‹คํ–‰ํ•ด์ฃผ์„ธ์š”.")
855
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
856
- input_img,
857
- last_output,
858
- current_bg_removed,
859
- selected_bg,
860
- selected_face,
861
- )
862
- yield (
863
- last_output,
864
- gr.update(value=last_output),
865
- make_download_update(last_output),
866
- history_update(),
867
- remove_ready,
868
- video_ready,
869
- bg_ready,
870
- swap_ready,
871
- )
872
- return
873
 
874
- if selected_bg is None:
875
- gr.Warning("์‚ฌ์šฉํ•  ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”.")
876
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
877
- input_img,
878
- last_output,
879
- current_bg_removed,
880
- selected_bg,
881
- selected_face,
882
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
883
  yield (
884
  last_output,
885
  gr.update(value=last_output),
886
  make_download_update(last_output),
887
  history_update(),
888
- remove_ready,
889
- video_ready,
890
- bg_ready,
891
- swap_ready,
892
  )
893
- return
894
-
895
- remove_disabled, video_disabled, bg_disabled, swap_disabled = disable_all_buttons()
896
- yield (
897
- last_output,
898
- gr.update(value=last_output),
899
- make_download_update(last_output),
900
- history_update(),
901
- remove_disabled,
902
- video_disabled,
903
- bg_disabled,
904
- swap_disabled,
905
- )
906
 
907
- generated, message = processor.generate_background(last_output, selected_bg, hq_mode)
908
- if generated is None:
909
- gr.Warning(message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
910
  remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
911
  input_img,
912
- last_output,
913
  current_bg_removed,
914
  selected_bg,
915
  selected_face,
916
  )
917
  yield (
918
- last_output,
919
- gr.update(value=last_output),
920
- make_download_update(last_output),
921
  history_update(),
922
  remove_ready,
923
  video_ready,
924
  bg_ready,
925
  swap_ready,
926
  )
927
- return
928
-
929
- gr.Info(message)
930
- add_to_history(generated, "bg_gen")
931
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
932
- input_img,
933
- generated,
934
- current_bg_removed,
935
- selected_bg,
936
- selected_face,
937
- )
938
- yield (
939
- generated,
940
- gr.update(value=generated),
941
- make_download_update(generated, "background_generated"),
942
- history_update(),
943
- remove_ready,
944
- video_ready,
945
- bg_ready,
946
- swap_ready,
947
- )
948
 
949
- def load_face_image(category: str, index: int) -> Optional[Image.Image]:
950
- key = f"{category}_paths"
951
- paths = face_images.get(key, [])
952
- if 0 <= index < len(paths):
953
- path = paths[index]
954
- return load_full_image(path)
955
- return None
956
 
957
- def on_select_face(
958
- evt: gr.SelectData,
959
- category: str,
960
- last_output: Optional[Image.Image],
961
- input_img: Optional[Image.Image],
962
- ):
963
- base_image = last_output or input_img
964
- index = getattr(evt, "index", None)
965
- if index is None:
966
- gr.Warning("์„ ํƒ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
967
- return None, gr.update(interactive=False)
968
- image = load_face_image(category, index)
969
- if image is None:
970
- gr.Warning("์„ ํƒํ•œ ์–ผ๊ตด ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.")
971
- return None, gr.update(interactive=False)
972
- gr.Info("์–ผ๊ตด ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.")
973
- ready = gr.update(interactive=base_image is not None)
974
- return image, ready
975
-
976
- def on_swap_face(
977
- last_output: Optional[Image.Image],
978
- input_img: Optional[Image.Image],
979
- selected_face: Optional[Image.Image],
980
- current_bg_removed: Optional[Image.Image],
981
- selected_bg: Optional[Image.Image],
982
- ):
983
- base_image = last_output or input_img
984
- if base_image is None:
985
- gr.Warning("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ๋จผ์ € ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
986
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
987
- input_img,
988
- last_output,
989
- current_bg_removed,
990
- selected_bg,
991
- selected_face,
992
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
993
  yield (
994
  last_output,
995
- gr.update(),
996
  make_download_update(last_output),
997
  history_update(),
998
- remove_ready,
999
- video_ready,
1000
- bg_ready,
1001
- swap_ready,
1002
  )
1003
- return
1004
 
1005
- if selected_face is None:
1006
- gr.Warning("์‚ฌ์šฉํ•  ์–ผ๊ตด ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1007
  remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
1008
  input_img,
1009
- last_output,
1010
  current_bg_removed,
1011
  selected_bg,
1012
  selected_face,
1013
  )
1014
  yield (
1015
- last_output,
1016
- gr.update(value=base_image),
1017
- make_download_update(last_output),
1018
  history_update(),
1019
  remove_ready,
1020
  video_ready,
1021
  bg_ready,
1022
  swap_ready,
1023
  )
1024
- return
1025
-
1026
- remove_disabled, video_disabled, bg_disabled, swap_disabled = disable_all_buttons()
1027
- yield (
1028
- last_output,
1029
- gr.update(value=base_image),
1030
- make_download_update(last_output),
1031
- history_update(),
1032
- remove_disabled,
1033
- video_disabled,
1034
- bg_disabled,
1035
- swap_disabled,
 
 
 
 
 
 
 
1036
  )
1037
 
1038
- swapped, message = processor.swap_face(base_image, selected_face)
1039
- if swapped is None:
1040
- gr.Warning(message)
1041
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
1042
- input_img,
1043
- last_output,
1044
- current_bg_removed,
1045
- selected_bg,
1046
- selected_face,
1047
- )
1048
- yield (
1049
- last_output,
1050
- gr.update(value=base_image),
1051
- make_download_update(last_output),
1052
- history_update(),
1053
- remove_ready,
1054
- video_ready,
1055
- bg_ready,
1056
- swap_ready,
1057
- )
1058
- return
1059
-
1060
- gr.Info(message)
1061
- add_to_history(swapped, "face_swap")
1062
- remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
1063
- input_img,
1064
- swapped,
1065
- current_bg_removed,
1066
- selected_bg,
1067
- selected_face,
1068
  )
1069
- yield (
1070
- swapped,
1071
- gr.update(value=swapped),
1072
- make_download_update(swapped, "face_swap"),
1073
- history_update(),
1074
- remove_ready,
1075
- video_ready,
1076
- bg_ready,
1077
- swap_ready,
 
 
 
 
 
 
 
 
 
1078
  )
1079
 
1080
- input_image.change(
1081
- on_upload,
1082
- inputs=[input_image],
1083
- outputs=[
1084
- input_state,
1085
- bg_removed_state,
1086
- selected_bg_state,
1087
- selected_face_state,
1088
- last_output_state,
1089
- output_image,
1090
- download_btn,
1091
- video_output,
1092
- remove_bg_btn,
1093
- generate_video_btn,
1094
- generate_bg_btn,
1095
- swap_face_btn,
1096
- history_gallery,
1097
- ],
1098
- )
1099
 
1100
- remove_bg_btn.click(
1101
- handle_remove_background,
1102
- inputs=[
1103
- input_state,
1104
- bg_removed_state,
1105
- selected_bg_state,
1106
- last_output_state,
1107
- selected_face_state,
1108
- ],
1109
- outputs=[
1110
- bg_removed_state,
1111
- last_output_state,
1112
- output_image,
1113
- download_btn,
1114
- generate_bg_btn,
1115
- swap_face_btn,
1116
- remove_bg_btn,
1117
- generate_video_btn,
1118
- history_gallery,
1119
- ],
1120
- )
1121
 
1122
- generate_video_btn.click(
1123
- on_generate_video,
1124
- inputs=[
1125
- last_output_state,
1126
- input_state,
1127
- bg_removed_state,
1128
- selected_bg_state,
1129
- selected_face_state,
1130
- ],
1131
- outputs=[
1132
- video_output,
1133
- history_gallery,
1134
- remove_bg_btn,
1135
- generate_video_btn,
1136
- generate_bg_btn,
1137
- swap_face_btn,
1138
- ],
1139
- )
 
 
 
1140
 
1141
- indoor_gallery.select(
1142
- on_select_background,
1143
- inputs=[gr.State("indoor"), bg_removed_state],
1144
- outputs=[selected_bg_state, generate_bg_btn],
1145
- )
1146
 
1147
- outdoor_gallery.select(
1148
- on_select_background,
1149
- inputs=[gr.State("outdoor"), bg_removed_state],
1150
- outputs=[selected_bg_state, generate_bg_btn],
1151
- )
1152
 
1153
- generate_bg_btn.click(
1154
- on_generate_background,
1155
- inputs=[
1156
- last_output_state,
1157
- selected_bg_state,
1158
- hq_checkbox,
1159
- input_state,
1160
- bg_removed_state,
1161
- selected_face_state,
1162
- ],
1163
- outputs=[
1164
- last_output_state,
1165
- output_image,
1166
- download_btn,
1167
- history_gallery,
1168
- remove_bg_btn,
1169
- generate_video_btn,
1170
- generate_bg_btn,
1171
- swap_face_btn,
1172
- ],
1173
- )
1174
 
1175
- man_gallery.select(
1176
- on_select_face,
1177
- inputs=[gr.State("man"), last_output_state, input_state],
1178
- outputs=[selected_face_state, swap_face_btn],
1179
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1180
 
1181
- woman_gallery.select(
1182
- on_select_face,
1183
- inputs=[gr.State("woman"), last_output_state, input_state],
1184
- outputs=[selected_face_state, swap_face_btn],
 
1185
  )
1186
 
1187
- swap_face_btn.click(
1188
- on_swap_face,
1189
- inputs=[
1190
- last_output_state,
1191
- input_state,
1192
- selected_face_state,
1193
- bg_removed_state,
1194
- selected_bg_state,
1195
- ],
1196
- outputs=[
1197
- last_output_state,
1198
- output_image,
1199
- download_btn,
1200
- history_gallery,
1201
- remove_bg_btn,
1202
- generate_video_btn,
1203
- generate_bg_btn,
1204
- swap_face_btn,
1205
- ],
1206
  )
1207
 
1208
 
@@ -1213,6 +1277,5 @@ if __name__ == "__main__":
1213
  app.launch(
1214
  share=True,
1215
  show_error=True,
1216
- auth=auth_fn,
1217
  ssr_mode=False
1218
  )
 
473
 
474
  with gr.Blocks(title="PixelFree v3.0.0", theme=gr.themes.Soft(), css=custom_css) as demo:
475
 
476
+ # ์„ธ์…˜ ์ƒํƒœ ๊ด€๋ฆฌ
477
+ session_user = gr.State(None)
478
+
479
+ # ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€
480
+ with gr.Column(visible=True, elem_id="login-page") as login_page:
481
+ gr.Markdown("# ๐Ÿ” PixelFree ๋กœ๊ทธ์ธ")
482
+ gr.Markdown("ํ—ˆ๊ฐ€๋œ ์‚ฌ์šฉ์ž๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.")
483
+ username_input = gr.Textbox(
484
+ label="์‚ฌ์šฉ์ž๋ช…",
485
+ placeholder="username์„ ์ž…๋ ฅํ•˜์„ธ์š”",
486
+ max_lines=1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  )
488
+ password_input = gr.Textbox(
489
+ label="๋น„๋ฐ€๋ฒˆํ˜ธ",
490
+ placeholder="password๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”",
491
+ type="password",
492
+ max_lines=1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  )
494
+ login_btn = gr.Button("๐Ÿ”“ ๋กœ๊ทธ์ธ", variant="primary", size="lg")
495
+ login_msg = gr.Markdown("")
496
+
497
+ # ๋ฉ”์ธ ํŽ˜์ด์ง€ (์ดˆ๊ธฐ์—๋Š” ์ˆจ๊น€)
498
+ with gr.Column(visible=False, elem_id="main-page") as main_page:
499
+
500
+ # ๋ฉ”์ธ ํ—ค๋”
501
+ with gr.Row():
502
+ gr.Markdown("# ๐ŸŽจ PixelFree Studio")
503
+ logout_btn = gr.Button("๐Ÿšช ๋กœ๊ทธ์•„์›ƒ", variant="secondary", size="sm")
504
+
505
+ # ์ž…๋ ฅ ์„น์…˜
506
+ gr.Markdown("## ๐Ÿ“ธ ์ž…๋ ฅ ์ด๋ฏธ์ง€")
507
+
508
+ input_state = gr.State(None)
509
+ bg_removed_state = gr.State(None)
510
+ selected_bg_state = gr.State(None)
511
+ selected_face_state = gr.State(None)
512
+ last_output_state = gr.State(None)
513
+
514
+ input_image = gr.Image(label="์ž…๋ ฅ ์ด๋ฏธ์ง€", type="pil", height=540)
515
+
516
+ # ๊ฒฐ๊ณผ ์„น์…˜
517
+ gr.Markdown("## โœจ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€")
518
+ output_image = gr.Image(label="์ฒ˜๋ฆฌ๋œ ์ด๋ฏธ์ง€", type="pil", height=500, interactive=False)
519
+ download_btn = gr.DownloadButton(
520
+ "๐Ÿ“ฅ ์‚ฌ์ง„ ๋‹ค์šด๋กœ๋“œ",
521
+ value=None,
522
+ interactive=False
 
 
523
  )
 
524
 
525
+ # ๋น„๋””์˜ค ์ƒ์„ฑ ์„น์…˜
526
+ gr.Markdown("## ๐ŸŽฌ AI ๋น„๋””์˜ค ์ƒ์„ฑ")
527
+ with gr.Row():
528
+ video_output = gr.Video(
529
+ label="์ƒ์„ฑ๋œ ์˜์ƒ",
530
+ height=360,
531
+ interactive=False,
532
+ autoplay=True,
533
+ )
534
+ with gr.Column():
535
+ gr.Markdown("์ตœ๊ทผ ์ด๋ฏธ์ง€ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์งง์€ ํด๋ฆฝ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.")
536
+ generate_video_btn = gr.Button(
537
+ "๐ŸŽฌ ์˜์ƒ ์ƒ์„ฑํ•˜๊ธฐ",
538
+ variant="primary",
539
+ size="lg",
540
+ interactive=False,
541
+ )
542
+
543
+ # ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ ์„น์…˜
544
+ gr.Markdown("## ๐ŸŽฏ AI ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ")
545
+ remove_bg_btn = gr.Button("๐Ÿš€ ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ ์‹คํ–‰", variant="primary", size="lg", interactive=False)
546
+
547
+ # AI ์ƒ์„ฑ ๊ธฐ๋Šฅ ์„น์…˜
548
+ gr.Markdown("## ๐ŸŽจ AI ์ƒ์„ฑ ๊ธฐ๋Šฅ")
549
+ with gr.Row():
550
+ with gr.Column():
551
+ gr.Markdown("### ๐Ÿž๏ธ ๋ฐฐ๊ฒฝ ์ƒ์„ฑ")
552
+ with gr.Tabs():
553
+ with gr.Tab("๐Ÿ  ์‹ค๋‚ด"):
554
+ indoor_gallery = gr.Gallery(
555
+ value=bg_images["indoor"],
556
+ columns=4,
557
+ show_label=False, interactive=False,
558
+ allow_preview=False,
559
+ object_fit="contain"
560
+ )
561
+ with gr.Tab("๐ŸŒณ ์•„์›ƒ๋„์–ด"):
562
+ outdoor_gallery = gr.Gallery(
563
+ value=bg_images["outdoor"],
564
+ columns=4,
565
+ rows=4, show_label=False, interactive=False,
566
+ allow_preview=False,
567
+ object_fit="contain"
568
+ )
569
+ hq_checkbox = gr.Checkbox(label="โœจ ๊ณ ํ’ˆ์งˆ ๋ชจ๋“œ", value=False)
570
+ generate_bg_btn = gr.Button("๐ŸŽจ ๋ฐฐ๊ฒฝ ์ƒ์„ฑํ•˜๊ธฐ", variant="secondary", interactive=False, size="lg")
571
+ with gr.Column():
572
+ gr.Markdown("### ๐Ÿ‘ค ์–ผ๊ตด ๊ต์ฒด")
573
+ with gr.Tabs():
574
+ with gr.Tab("๐Ÿ‘จ ๋‚จ์„ฑ"):
575
+ man_gallery = gr.Gallery(
576
+ value=face_images["man_pil"],
577
+ columns=4,
578
+ rows=2, show_label=False, interactive=False,
579
+ allow_preview=False,
580
+ object_fit="contain"
581
+ )
582
+ with gr.Tab("๐Ÿ‘ฉ ์—ฌ์„ฑ"):
583
+ woman_gallery = gr.Gallery(
584
+ value=face_images["woman_pil"],
585
+ columns=4,
586
+ rows=2, show_label=False, interactive=False,
587
+ allow_preview=False,
588
+ object_fit="contain"
589
+ )
590
+ swap_face_btn = gr.Button("๐Ÿ”„ ์–ผ๊ตด ๊ต์ฒด ์ ์šฉ", variant="secondary", interactive=False, size="lg")
591
+ # Collapsible history section with image grid
592
+ with gr.Accordion("๐Ÿ“œ ์ž‘์—… ํžˆ์Šคํ† ๋ฆฌ", open=False):
593
+ # History gallery with preview enabled
594
+ history_gallery = gr.Gallery(
595
+ value=[img for img, _ in get_history_items(20)],
596
+ label=None,
597
+ show_label=False,
598
+ columns=5,
599
+ rows=4,
600
+ height=500,
601
+ object_fit="contain",
602
+ allow_preview=True,
603
+ elem_id="history-gallery",
604
+ interactive=False
605
+ )
606
 
607
+ def make_download_update(image: Optional[Image.Image], prefix: str = "pixelfree_output"):
608
+ if image is None:
609
+ return gr.update(value=None, interactive=False)
610
+ filename = f"{prefix}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
611
+ temp_path = f"/tmp/{filename}"
612
+ image.save(temp_path, "PNG")
613
+ return gr.update(value=temp_path, interactive=True)
614
+
615
+ def history_update():
616
+ """Update history gallery with original images."""
617
+ items = get_history_items(20)
618
+ images = [img for img, _ in items]
619
+ return gr.update(value=images)
620
+
621
+ def disable_all_buttons():
622
+ disabled = gr.update(interactive=False)
623
+ return disabled, disabled, disabled, disabled
624
+
625
+ def compute_button_states(
626
+ input_img: Optional[Image.Image],
627
+ last_output: Optional[Image.Image],
628
+ bg_removed: Optional[Image.Image],
629
+ selected_bg: Optional[Image.Image],
630
+ selected_face: Optional[Image.Image],
631
+ ):
632
+ remove_ready = gr.update(interactive=input_img is not None)
633
+ video_ready = gr.update(interactive=input_img is not None)
634
+ bg_ready = gr.update(interactive=(bg_removed is not None and selected_bg is not None))
635
+ swap_ready = gr.update(
636
+ interactive=(selected_face is not None and ((last_output is not None) or (input_img is not None)))
637
+ )
638
+ return remove_ready, video_ready, bg_ready, swap_ready
639
+
640
+
641
+ def on_upload(new_image: Optional[Image.Image]):
642
+ if new_image is None:
643
+ gr.Warning("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
644
+ remove_ready, video_ready, bg_ready, swap_ready = disable_all_buttons()
645
+ return (
646
+ None,
647
+ None,
648
+ None,
649
+ None,
650
+ None,
651
+ gr.update(value=None),
652
+ make_download_update(None),
653
+ gr.update(value=None),
654
+ remove_ready,
655
+ video_ready,
656
+ bg_ready,
657
+ swap_ready,
658
+ history_update(),
659
+ )
660
+
661
+ gr.Info("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.")
662
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
663
+ new_image,
664
+ None,
665
  None,
666
  None,
667
  None,
668
+ )
669
+ return (
670
+ new_image,
671
+ None,
672
+ None,
673
  None,
674
  None,
675
  gr.update(value=None),
 
682
  history_update(),
683
  )
684
 
685
+ def handle_remove_background(
686
+ input_img: Optional[Image.Image],
687
+ current_bg_removed: Optional[Image.Image],
688
+ selected_bg: Optional[Image.Image],
689
+ current_output: Optional[Image.Image],
690
+ selected_face: Optional[Image.Image],
691
+ ):
692
+ if input_img is None:
693
+ gr.Warning("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ๋จผ์ € ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
694
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
695
+ input_img,
696
+ current_output,
697
+ current_bg_removed,
698
+ selected_bg,
699
+ selected_face,
700
+ )
701
+ yield (
702
+ current_bg_removed,
703
+ current_output,
704
+ gr.update(),
705
+ make_download_update(current_output),
706
+ bg_ready,
707
+ swap_ready,
708
+ remove_ready,
709
+ video_ready,
710
+ history_update(),
711
+ )
712
+ return
713
+
714
+ remove_disabled, video_disabled, bg_disabled, swap_disabled = disable_all_buttons()
 
 
 
 
 
 
 
 
 
 
715
  yield (
716
  current_bg_removed,
717
  current_output,
718
  gr.update(),
719
  make_download_update(current_output),
720
+ bg_disabled,
721
+ swap_disabled,
722
+ remove_disabled,
723
+ video_disabled,
724
  history_update(),
725
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
726
 
727
+ removed, message = processor.remove_background(input_img)
728
+ if removed is None:
729
+ gr.Warning(message)
730
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
731
+ input_img,
732
+ current_output,
733
+ current_bg_removed,
734
+ selected_bg,
735
+ selected_face,
736
+ )
737
+ yield (
738
+ current_bg_removed,
739
+ current_output,
740
+ gr.update(value=current_output),
741
+ make_download_update(current_output),
742
+ bg_ready,
743
+ swap_ready,
744
+ remove_ready,
745
+ video_ready,
746
+ history_update(),
747
+ )
748
+ return
749
+
750
+ gr.Info(message)
751
+ add_to_history(removed, "bg_remove")
752
  remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
753
  input_img,
754
+ removed,
755
+ removed,
756
  selected_bg,
757
  selected_face,
758
  )
759
  yield (
760
+ removed,
761
+ removed,
762
+ gr.update(value=removed),
763
+ make_download_update(removed, "background_removed"),
764
  bg_ready,
765
  swap_ready,
766
  remove_ready,
767
  video_ready,
768
  history_update(),
769
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
770
 
771
+ def on_generate_video(
772
+ last_output: Optional[Image.Image],
773
+ input_img: Optional[Image.Image],
774
+ current_bg_removed: Optional[Image.Image],
775
+ selected_bg: Optional[Image.Image],
776
+ selected_face: Optional[Image.Image],
777
+ ):
778
+ base_image = last_output or input_img
779
+ if base_image is None:
780
+ gr.Warning("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ๋จผ์ € ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
781
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
782
+ input_img,
783
+ last_output,
784
+ current_bg_removed,
785
+ selected_bg,
786
+ selected_face,
787
+ )
788
+ yield (
789
+ gr.update(value=None),
790
+ history_update(),
791
+ remove_ready,
792
+ video_ready,
793
+ bg_ready,
794
+ swap_ready,
795
+ )
796
+ return
797
+
798
+ remove_disabled, video_disabled, bg_disabled, swap_disabled = disable_all_buttons()
799
  yield (
800
+ gr.update(),
801
  history_update(),
802
+ remove_disabled,
803
+ video_disabled,
804
+ bg_disabled,
805
+ swap_disabled,
806
  )
 
 
 
 
 
 
 
 
 
 
 
807
 
808
+ video_path, message = processor.generate_video(base_image)
809
+ if video_path is None:
810
+ gr.Warning(message)
811
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
812
+ input_img,
813
+ last_output,
814
+ current_bg_removed,
815
+ selected_bg,
816
+ selected_face,
817
+ )
818
+ yield (
819
+ gr.update(value=None),
820
+ history_update(),
821
+ remove_ready,
822
+ video_ready,
823
+ bg_ready,
824
+ swap_ready,
825
+ )
826
+ return
827
+
828
+ gr.Info(message)
829
+ add_to_history(base_image, "video")
830
  remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
831
  input_img,
832
  last_output,
 
835
  selected_face,
836
  )
837
  yield (
838
+ gr.update(value=video_path),
839
  history_update(),
840
  remove_ready,
841
  video_ready,
842
  bg_ready,
843
  swap_ready,
844
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
845
 
846
+ def load_background_image(category: str, index: int) -> Optional[Image.Image]:
847
+ key = f"{category}_pil"
848
+ paths = bg_images.get(key, [])
849
+ if 0 <= index < len(paths):
850
+ path = paths[index]
851
+ return load_full_image(path)
852
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
853
 
854
+ def on_select_background(
855
+ evt: gr.SelectData,
856
+ category: str,
857
+ bg_removed: Optional[Image.Image],
858
+ ):
859
+ index = getattr(evt, "index", None)
860
+ if index is None:
861
+ gr.Warning("์„ ํƒ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
862
+ return None, gr.update(interactive=False)
863
+ image = load_background_image(category, index)
864
+ if image is None:
865
+ gr.Warning("์„ ํƒํ•œ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.")
866
+ return None, gr.update(interactive=False)
867
+ gr.Info("๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.")
868
+ ready = gr.update(interactive=bg_removed is not None)
869
+ return image, ready
870
+
871
+ def on_generate_background(
872
+ last_output: Optional[Image.Image],
873
+ selected_bg: Optional[Image.Image],
874
+ hq_mode: bool,
875
+ input_img: Optional[Image.Image],
876
+ current_bg_removed: Optional[Image.Image],
877
+ selected_face: Optional[Image.Image],
878
+ ):
879
+ if last_output is None:
880
+ gr.Warning("๋จผ์ € ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ๋ฅผ ์‹คํ–‰ํ•ด์ฃผ์„ธ์š”.")
881
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
882
+ input_img,
883
+ last_output,
884
+ current_bg_removed,
885
+ selected_bg,
886
+ selected_face,
887
+ )
888
+ yield (
889
+ last_output,
890
+ gr.update(value=last_output),
891
+ make_download_update(last_output),
892
+ history_update(),
893
+ remove_ready,
894
+ video_ready,
895
+ bg_ready,
896
+ swap_ready,
897
+ )
898
+ return
899
+
900
+ if selected_bg is None:
901
+ gr.Warning("์‚ฌ์šฉํ•  ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”.")
902
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
903
+ input_img,
904
+ last_output,
905
+ current_bg_removed,
906
+ selected_bg,
907
+ selected_face,
908
+ )
909
+ yield (
910
+ last_output,
911
+ gr.update(value=last_output),
912
+ make_download_update(last_output),
913
+ history_update(),
914
+ remove_ready,
915
+ video_ready,
916
+ bg_ready,
917
+ swap_ready,
918
+ )
919
+ return
920
+
921
+ remove_disabled, video_disabled, bg_disabled, swap_disabled = disable_all_buttons()
922
  yield (
923
  last_output,
924
  gr.update(value=last_output),
925
  make_download_update(last_output),
926
  history_update(),
927
+ remove_disabled,
928
+ video_disabled,
929
+ bg_disabled,
930
+ swap_disabled,
931
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
932
 
933
+ generated, message = processor.generate_background(last_output, selected_bg, hq_mode)
934
+ if generated is None:
935
+ gr.Warning(message)
936
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
937
+ input_img,
938
+ last_output,
939
+ current_bg_removed,
940
+ selected_bg,
941
+ selected_face,
942
+ )
943
+ yield (
944
+ last_output,
945
+ gr.update(value=last_output),
946
+ make_download_update(last_output),
947
+ history_update(),
948
+ remove_ready,
949
+ video_ready,
950
+ bg_ready,
951
+ swap_ready,
952
+ )
953
+ return
954
+
955
+ gr.Info(message)
956
+ add_to_history(generated, "bg_gen")
957
  remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
958
  input_img,
959
+ generated,
960
  current_bg_removed,
961
  selected_bg,
962
  selected_face,
963
  )
964
  yield (
965
+ generated,
966
+ gr.update(value=generated),
967
+ make_download_update(generated, "background_generated"),
968
  history_update(),
969
  remove_ready,
970
  video_ready,
971
  bg_ready,
972
  swap_ready,
973
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
974
 
975
+ def load_face_image(category: str, index: int) -> Optional[Image.Image]:
976
+ key = f"{category}_paths"
977
+ paths = face_images.get(key, [])
978
+ if 0 <= index < len(paths):
979
+ path = paths[index]
980
+ return load_full_image(path)
981
+ return None
982
 
983
+ def on_select_face(
984
+ evt: gr.SelectData,
985
+ category: str,
986
+ last_output: Optional[Image.Image],
987
+ input_img: Optional[Image.Image],
988
+ ):
989
+ base_image = last_output or input_img
990
+ index = getattr(evt, "index", None)
991
+ if index is None:
992
+ gr.Warning("์„ ํƒ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
993
+ return None, gr.update(interactive=False)
994
+ image = load_face_image(category, index)
995
+ if image is None:
996
+ gr.Warning("์„ ํƒํ•œ ์–ผ๊ตด ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.")
997
+ return None, gr.update(interactive=False)
998
+ gr.Info("์–ผ๊ตด ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.")
999
+ ready = gr.update(interactive=base_image is not None)
1000
+ return image, ready
1001
+
1002
+ def on_swap_face(
1003
+ last_output: Optional[Image.Image],
1004
+ input_img: Optional[Image.Image],
1005
+ selected_face: Optional[Image.Image],
1006
+ current_bg_removed: Optional[Image.Image],
1007
+ selected_bg: Optional[Image.Image],
1008
+ ):
1009
+ base_image = last_output or input_img
1010
+ if base_image is None:
1011
+ gr.Warning("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ๋จผ์ € ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
1012
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
1013
+ input_img,
1014
+ last_output,
1015
+ current_bg_removed,
1016
+ selected_bg,
1017
+ selected_face,
1018
+ )
1019
+ yield (
1020
+ last_output,
1021
+ gr.update(),
1022
+ make_download_update(last_output),
1023
+ history_update(),
1024
+ remove_ready,
1025
+ video_ready,
1026
+ bg_ready,
1027
+ swap_ready,
1028
+ )
1029
+ return
1030
+
1031
+ if selected_face is None:
1032
+ gr.Warning("์‚ฌ์šฉํ•  ์–ผ๊ตด ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”.")
1033
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
1034
+ input_img,
1035
+ last_output,
1036
+ current_bg_removed,
1037
+ selected_bg,
1038
+ selected_face,
1039
+ )
1040
+ yield (
1041
+ last_output,
1042
+ gr.update(value=base_image),
1043
+ make_download_update(last_output),
1044
+ history_update(),
1045
+ remove_ready,
1046
+ video_ready,
1047
+ bg_ready,
1048
+ swap_ready,
1049
+ )
1050
+ return
1051
+
1052
+ remove_disabled, video_disabled, bg_disabled, swap_disabled = disable_all_buttons()
1053
  yield (
1054
  last_output,
1055
+ gr.update(value=base_image),
1056
  make_download_update(last_output),
1057
  history_update(),
1058
+ remove_disabled,
1059
+ video_disabled,
1060
+ bg_disabled,
1061
+ swap_disabled,
1062
  )
 
1063
 
1064
+ swapped, message = processor.swap_face(base_image, selected_face)
1065
+ if swapped is None:
1066
+ gr.Warning(message)
1067
+ remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
1068
+ input_img,
1069
+ last_output,
1070
+ current_bg_removed,
1071
+ selected_bg,
1072
+ selected_face,
1073
+ )
1074
+ yield (
1075
+ last_output,
1076
+ gr.update(value=base_image),
1077
+ make_download_update(last_output),
1078
+ history_update(),
1079
+ remove_ready,
1080
+ video_ready,
1081
+ bg_ready,
1082
+ swap_ready,
1083
+ )
1084
+ return
1085
+
1086
+ gr.Info(message)
1087
+ add_to_history(swapped, "face_swap")
1088
  remove_ready, video_ready, bg_ready, swap_ready = compute_button_states(
1089
  input_img,
1090
+ swapped,
1091
  current_bg_removed,
1092
  selected_bg,
1093
  selected_face,
1094
  )
1095
  yield (
1096
+ swapped,
1097
+ gr.update(value=swapped),
1098
+ make_download_update(swapped, "face_swap"),
1099
  history_update(),
1100
  remove_ready,
1101
  video_ready,
1102
  bg_ready,
1103
  swap_ready,
1104
  )
1105
+
1106
+ input_image.change(
1107
+ on_upload,
1108
+ inputs=[input_image],
1109
+ outputs=[
1110
+ input_state,
1111
+ bg_removed_state,
1112
+ selected_bg_state,
1113
+ selected_face_state,
1114
+ last_output_state,
1115
+ output_image,
1116
+ download_btn,
1117
+ video_output,
1118
+ remove_bg_btn,
1119
+ generate_video_btn,
1120
+ generate_bg_btn,
1121
+ swap_face_btn,
1122
+ history_gallery,
1123
+ ],
1124
  )
1125
 
1126
+ remove_bg_btn.click(
1127
+ handle_remove_background,
1128
+ inputs=[
1129
+ input_state,
1130
+ bg_removed_state,
1131
+ selected_bg_state,
1132
+ last_output_state,
1133
+ selected_face_state,
1134
+ ],
1135
+ outputs=[
1136
+ bg_removed_state,
1137
+ last_output_state,
1138
+ output_image,
1139
+ download_btn,
1140
+ generate_bg_btn,
1141
+ swap_face_btn,
1142
+ remove_bg_btn,
1143
+ generate_video_btn,
1144
+ history_gallery,
1145
+ ],
 
 
 
 
 
 
 
 
 
 
1146
  )
1147
+
1148
+ generate_video_btn.click(
1149
+ on_generate_video,
1150
+ inputs=[
1151
+ last_output_state,
1152
+ input_state,
1153
+ bg_removed_state,
1154
+ selected_bg_state,
1155
+ selected_face_state,
1156
+ ],
1157
+ outputs=[
1158
+ video_output,
1159
+ history_gallery,
1160
+ remove_bg_btn,
1161
+ generate_video_btn,
1162
+ generate_bg_btn,
1163
+ swap_face_btn,
1164
+ ],
1165
  )
1166
 
1167
+ indoor_gallery.select(
1168
+ on_select_background,
1169
+ inputs=[gr.State("indoor"), bg_removed_state],
1170
+ outputs=[selected_bg_state, generate_bg_btn],
1171
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1172
 
1173
+ outdoor_gallery.select(
1174
+ on_select_background,
1175
+ inputs=[gr.State("outdoor"), bg_removed_state],
1176
+ outputs=[selected_bg_state, generate_bg_btn],
1177
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1178
 
1179
+ generate_bg_btn.click(
1180
+ on_generate_background,
1181
+ inputs=[
1182
+ last_output_state,
1183
+ selected_bg_state,
1184
+ hq_checkbox,
1185
+ input_state,
1186
+ bg_removed_state,
1187
+ selected_face_state,
1188
+ ],
1189
+ outputs=[
1190
+ last_output_state,
1191
+ output_image,
1192
+ download_btn,
1193
+ history_gallery,
1194
+ remove_bg_btn,
1195
+ generate_video_btn,
1196
+ generate_bg_btn,
1197
+ swap_face_btn,
1198
+ ],
1199
+ )
1200
 
1201
+ man_gallery.select(
1202
+ on_select_face,
1203
+ inputs=[gr.State("man"), last_output_state, input_state],
1204
+ outputs=[selected_face_state, swap_face_btn],
1205
+ )
1206
 
1207
+ woman_gallery.select(
1208
+ on_select_face,
1209
+ inputs=[gr.State("woman"), last_output_state, input_state],
1210
+ outputs=[selected_face_state, swap_face_btn],
1211
+ )
1212
 
1213
+ swap_face_btn.click(
1214
+ on_swap_face,
1215
+ inputs=[
1216
+ last_output_state,
1217
+ input_state,
1218
+ selected_face_state,
1219
+ bg_removed_state,
1220
+ selected_bg_state,
1221
+ ],
1222
+ outputs=[
1223
+ last_output_state,
1224
+ output_image,
1225
+ download_btn,
1226
+ history_gallery,
1227
+ remove_bg_btn,
1228
+ generate_video_btn,
1229
+ generate_bg_btn,
1230
+ swap_face_btn,
1231
+ ],
1232
+ )
 
1233
 
1234
+ # ๋กœ๊ทธ์ธ/๋กœ๊ทธ์•„์›ƒ ํ•ธ๋“ค๋Ÿฌ
1235
+ def handle_login(username, password):
1236
+ """๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ"""
1237
+ if username in ALLOWED_USERS and username == password:
1238
+ return (
1239
+ gr.update(visible=False), # ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์ˆจ๊น€
1240
+ gr.update(visible=True), # ๋ฉ”์ธ ํŽ˜์ด์ง€ ํ‘œ์‹œ
1241
+ username, # ์„ธ์…˜์— ์‚ฌ์šฉ์ž ์ €์žฅ
1242
+ gr.update(value="โœ… ๋กœ๊ทธ์ธ ์„ฑ๊ณต!")
1243
+ )
1244
+ return (
1245
+ gr.update(visible=True), # ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์œ ์ง€
1246
+ gr.update(visible=False), # ๋ฉ”์ธ ํŽ˜์ด์ง€ ์ˆจ๊น€
1247
+ None, # ์„ธ์…˜ ์ดˆ๊ธฐํ™”
1248
+ gr.update(value="โŒ ๋กœ๊ทธ์ธ ์‹คํŒจ: ์‚ฌ์šฉ์ž๋ช… ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
1249
+ )
1250
+
1251
+ def handle_logout():
1252
+ """๋กœ๊ทธ์•„์›ƒ ์ฒ˜๋ฆฌ"""
1253
+ return (
1254
+ gr.update(visible=True), # ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ‘œ์‹œ
1255
+ gr.update(visible=False), # ๋ฉ”์ธ ํŽ˜์ด์ง€ ์ˆจ๊น€
1256
+ None, # ์„ธ์…˜ ์ดˆ๊ธฐํ™”
1257
+ gr.update(value="") # ๋ฉ”์‹œ์ง€ ์ดˆ๊ธฐํ™”
1258
+ )
1259
 
1260
+ # ๋กœ๊ทธ์ธ/๋กœ๊ทธ์•„์›ƒ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
1261
+ login_btn.click(
1262
+ handle_login,
1263
+ inputs=[username_input, password_input],
1264
+ outputs=[login_page, main_page, session_user, login_msg]
1265
  )
1266
 
1267
+ logout_btn.click(
1268
+ handle_logout,
1269
+ outputs=[login_page, main_page, session_user, login_msg]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1270
  )
1271
 
1272
 
 
1277
  app.launch(
1278
  share=True,
1279
  show_error=True,
 
1280
  ssr_mode=False
1281
  )