ginipick commited on
Commit
56445b0
·
verified ·
1 Parent(s): 22170aa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +223 -184
app.py CHANGED
@@ -427,65 +427,102 @@ def update_box_button(img, box_input):
427
  return gr.update(interactive=False, variant="secondary")
428
 
429
 
430
- # CSS 정의
431
  css = """
432
  footer {display: none}
433
  .main-title {
434
  text-align: center;
435
- margin: 2em 0;
436
- padding: 1em;
437
- background: #f7f7f7;
438
- border-radius: 10px;
 
439
  }
440
  .main-title h1 {
441
  color: #2196F3;
442
- font-size: 2.5em;
443
- margin-bottom: 0.5em;
 
444
  }
445
  .main-title p {
446
- color: #666;
447
- font-size: 1.2em;
 
448
  }
449
  .container {
450
  max-width: 1200px;
451
  margin: auto;
452
  padding: 20px;
453
  }
454
- .tabs {
455
- margin-top: 1em;
456
- }
457
- .input-group {
458
  background: white;
 
 
 
 
 
 
 
459
  padding: 1em;
460
  border-radius: 8px;
461
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
462
  }
463
- .output-group {
464
- background: white;
465
- padding: 1em;
 
 
 
466
  border-radius: 8px;
467
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
468
  }
469
- button.primary {
470
- background: #2196F3;
471
- border: none;
472
- color: white;
473
- padding: 0.5em 1em;
474
- border-radius: 4px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  cursor: pointer;
476
- transition: background 0.3s ease;
477
  }
478
- button.primary:hover {
479
- background: #1976D2;
 
 
 
 
 
 
 
 
 
 
480
  }
481
  .position-btn {
 
 
 
 
 
482
  transition: all 0.3s ease;
483
  }
484
  .position-btn:hover {
485
- background-color: #e3f2fd;
486
  }
487
  .position-btn.selected {
488
- background-color: #2196F3;
489
  color: white;
490
  }
491
  """
@@ -631,168 +668,165 @@ def add_text_to_image(
631
  with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
632
  gr.HTML("""
633
  <div class="main-title">
634
- <h1>🎨GiniGen Canvas-o3</h1>
635
- <p>Remove background of specified objects, generate new backgrounds, and insert text over or behind images with prompts.</p>
636
  </div>
637
  """)
638
 
639
- with gr.Row():
 
640
  with gr.Column(scale=1):
641
- input_image = gr.Image(
642
- type="pil",
643
- label="Upload Image",
644
- interactive=True
645
- )
646
- text_prompt = gr.Textbox(
647
- label="Object to Extract",
648
- placeholder="Enter what you want to extract...",
649
- interactive=True
650
- )
651
- with gr.Row():
652
- bg_prompt = gr.Textbox(
653
- label="Background Prompt (optional)",
654
- placeholder="Describe the background...",
655
  interactive=True,
656
- scale=3
657
  )
658
- aspect_ratio = gr.Dropdown(
659
- choices=["1:1", "16:9", "9:16", "4:3"],
660
- value="1:1",
661
- label="Aspect Ratio",
662
- interactive=True,
663
- visible=True,
664
- scale=1
665
  )
666
-
667
- with gr.Row(visible=False) as object_controls:
668
- with gr.Column(scale=1):
669
- with gr.Row():
670
- position = gr.State(value="bottom-center")
671
- btn_top_left = gr.Button("↖")
672
- btn_top_center = gr.Button("↑")
673
- btn_top_right = gr.Button("↗")
674
- with gr.Row():
675
- btn_middle_left = gr.Button("")
676
- btn_middle_center = gr.Button("•")
677
- btn_middle_right = gr.Button("→")
678
- with gr.Row():
679
- btn_bottom_left = gr.Button("↙")
680
- btn_bottom_center = gr.Button("↓")
681
- btn_bottom_right = gr.Button("↘")
682
- with gr.Column(scale=1):
683
- scale_slider = gr.Slider(
684
- minimum=10,
685
- maximum=200,
686
- value=50,
687
- step=5,
688
- label="Object Size (%)"
689
  )
690
 
691
- process_btn = gr.Button(
692
- "Process",
693
- variant="primary",
694
- interactive=False
695
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
696
 
697
- with gr.Column(scale=1):
698
- with gr.Tab("Result"):
699
- combined_image = gr.Image(
700
- label="Combined Result",
701
- show_download_button=True,
702
- type="pil",
703
- height=512
704
  )
705
-
706
- # 텍스트 삽입 컨트롤을 더 명확하게 구분
707
- with gr.Group():
708
- gr.Markdown("### Add Text to Image")
709
- with gr.Row():
710
- text_input = gr.Textbox(
711
- label="Text Content",
712
- placeholder="Enter text to add to image..."
713
- )
714
- text_position_type = gr.Radio(
715
- choices=["Text Over Image", "Text Behind Image"],
716
- value="Text Over Image",
717
- label="Text Position Type",
718
- interactive=True
719
- )
720
 
721
- with gr.Row():
722
- with gr.Column(scale=1):
723
- # 폰트 선택 Dropdown 추가
724
- font_choice = gr.Dropdown(
725
- choices=["Default", "Korean Regular", "Korean Son"],
726
- value="Default",
727
- label="Font Selection",
728
- interactive=True
729
- )
730
- font_size = gr.Slider(
731
- minimum=10,
732
- maximum=200,
733
- value=40,
734
- step=5,
735
- label="Font Size"
736
- )
737
- color_dropdown = gr.Dropdown(
738
- choices=["White", "Black", "Red", "Green", "Blue", "Yellow", "Purple"],
739
- value="White",
740
- label="Text Color"
741
- )
742
- thickness = gr.Slider(
743
- minimum=0,
744
- maximum=10,
745
- value=1,
746
- step=1,
747
- label="Text Thickness"
748
- )
749
- with gr.Column(scale=1):
750
- opacity_slider = gr.Slider(
751
- minimum=0,
752
- maximum=255,
753
- value=255,
754
- step=1,
755
- label="Opacity"
756
- )
757
- x_position = gr.Slider(
758
- minimum=0,
759
- maximum=100,
760
- value=50,
761
- step=1,
762
- label="X Position (%)"
763
- )
764
- y_position = gr.Slider(
765
- minimum=0,
766
- maximum=100,
767
- value=50,
768
- step=1,
769
- label="Y Position (%)"
770
- )
771
- add_text_btn = gr.Button("Apply Text", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
772
 
773
- with gr.Row():
774
  extracted_image = gr.Image(
775
  label="Extracted Object",
776
  show_download_button=True,
777
  type="pil",
778
- height=256
779
  )
780
 
781
- # 버튼에 대한 클릭 이벤트 처리
782
- def update_position(new_position):
783
- return new_position
784
-
785
- btn_top_left.click(fn=lambda: update_position("top-left"), outputs=position)
786
- btn_top_center.click(fn=lambda: update_position("top-center"), outputs=position)
787
- btn_top_right.click(fn=lambda: update_position("top-right"), outputs=position)
788
- btn_middle_left.click(fn=lambda: update_position("middle-left"), outputs=position)
789
- btn_middle_center.click(fn=lambda: update_position("middle-center"), outputs=position)
790
- btn_middle_right.click(fn=lambda: update_position("middle-right"), outputs=position)
791
- btn_bottom_left.click(fn=lambda: update_position("bottom-left"), outputs=position)
792
- btn_bottom_center.click(fn=lambda: update_position("bottom-center"), outputs=position)
793
- btn_bottom_right.click(fn=lambda: update_position("bottom-right"), outputs=position)
794
-
795
- # Event bindings
796
  input_image.change(
797
  fn=update_process_button,
798
  inputs=[input_image, text_prompt],
@@ -807,14 +841,6 @@ with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
807
  queue=False
808
  )
809
 
810
- def update_controls(bg_prompt):
811
- """배경 프롬프트 입력 여부에 따라 컨트롤 표시 업데이트"""
812
- is_visible = bool(bg_prompt)
813
- return [
814
- gr.update(visible=is_visible), # aspect_ratio
815
- gr.update(visible=is_visible), # object_controls
816
- ]
817
-
818
  bg_prompt.change(
819
  fn=update_controls,
820
  inputs=bg_prompt,
@@ -822,6 +848,20 @@ with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
822
  queue=False
823
  )
824
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
825
  process_btn.click(
826
  fn=process_prompt,
827
  inputs=[
@@ -836,7 +876,6 @@ with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
836
  queue=True
837
  )
838
 
839
- # 텍스트 추가 버튼 이벤트 연결 수정
840
  add_text_btn.click(
841
  fn=add_text_to_image,
842
  inputs=[
@@ -849,15 +888,15 @@ with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
849
  y_position,
850
  thickness,
851
  text_position_type,
852
- font_choice # 새로운 입력 추가
853
  ],
854
  outputs=combined_image
855
  )
856
 
857
- demo.queue(max_size=5) # 큐 크기 제한
858
  demo.launch(
859
  server_name="0.0.0.0",
860
  server_port=7860,
861
  share=False,
862
- max_threads=2 # 스레드 수 제한
863
  )
 
427
  return gr.update(interactive=False, variant="secondary")
428
 
429
 
 
430
  css = """
431
  footer {display: none}
432
  .main-title {
433
  text-align: center;
434
+ margin: 1em 0;
435
+ padding: 1.5em;
436
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
437
+ border-radius: 15px;
438
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
439
  }
440
  .main-title h1 {
441
  color: #2196F3;
442
+ font-size: 2.8em;
443
+ margin-bottom: 0.3em;
444
+ font-weight: 700;
445
  }
446
  .main-title p {
447
+ color: #555;
448
+ font-size: 1.3em;
449
+ line-height: 1.4;
450
  }
451
  .container {
452
  max-width: 1200px;
453
  margin: auto;
454
  padding: 20px;
455
  }
456
+ .input-panel, .output-panel {
 
 
 
457
  background: white;
458
+ padding: 1.5em;
459
+ border-radius: 12px;
460
+ box-shadow: 0 2px 8px rgba(0,0,0,0.08);
461
+ margin-bottom: 1em;
462
+ }
463
+ .controls-panel {
464
+ background: #f8f9fa;
465
  padding: 1em;
466
  border-radius: 8px;
467
+ margin: 1em 0;
468
  }
469
+ .image-display {
470
+ min-height: 512px;
471
+ display: flex;
472
+ align-items: center;
473
+ justify-content: center;
474
+ background: #fafafa;
475
  border-radius: 8px;
476
+ margin: 1em 0;
477
  }
478
+ .example-section {
479
+ text-align: center;
480
+ padding: 2em;
481
+ background: #f5f5f5;
482
+ border-radius: 12px;
483
+ margin-top: 2em;
484
+ }
485
+ .example-section img {
486
+ max-width: 100%;
487
+ border-radius: 8px;
488
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
489
+ }
490
+ .accordion {
491
+ border: 1px solid #e0e0e0;
492
+ border-radius: 8px;
493
+ margin: 1em 0;
494
+ }
495
+ .accordion-header {
496
+ padding: 1em;
497
+ background: #f5f5f5;
498
  cursor: pointer;
 
499
  }
500
+ .accordion-content {
501
+ padding: 1em;
502
+ display: none;
503
+ }
504
+ .accordion.open .accordion-content {
505
+ display: block;
506
+ }
507
+ .position-grid {
508
+ display: grid;
509
+ grid-template-columns: repeat(3, 1fr);
510
+ gap: 8px;
511
+ margin: 1em 0;
512
  }
513
  .position-btn {
514
+ padding: 10px;
515
+ border: 1px solid #ddd;
516
+ border-radius: 4px;
517
+ background: white;
518
+ cursor: pointer;
519
  transition: all 0.3s ease;
520
  }
521
  .position-btn:hover {
522
+ background: #e3f2fd;
523
  }
524
  .position-btn.selected {
525
+ background: #2196F3;
526
  color: white;
527
  }
528
  """
 
668
  with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
669
  gr.HTML("""
670
  <div class="main-title">
671
+ <h1>🎨 GiniGen Canvas-o3</h1>
672
+ <p>Advanced Image Processing Tool: Remove backgrounds, generate new ones, and add customized text to your images.</p>
673
  </div>
674
  """)
675
 
676
+ with gr.Row(equal_height=True):
677
+ # 왼쪽 패널 (입력)
678
  with gr.Column(scale=1):
679
+ with gr.Box(elem_classes="input-panel"):
680
+ input_image = gr.Image(
681
+ type="pil",
682
+ label="Upload Image",
 
 
 
 
 
 
 
 
 
 
683
  interactive=True,
684
+ height=400
685
  )
686
+ text_prompt = gr.Textbox(
687
+ label="Object to Extract",
688
+ placeholder="Enter what you want to extract...",
689
+ interactive=True
 
 
 
690
  )
691
+ with gr.Row():
692
+ bg_prompt = gr.Textbox(
693
+ label="Background Prompt (optional)",
694
+ placeholder="Describe the background...",
695
+ interactive=True,
696
+ scale=3
697
+ )
698
+ aspect_ratio = gr.Dropdown(
699
+ choices=["1:1", "16:9", "9:16", "4:3"],
700
+ value="1:1",
701
+ label="Aspect Ratio",
702
+ interactive=True,
703
+ visible=True,
704
+ scale=1
 
 
 
 
 
 
 
 
 
705
  )
706
 
707
+ with gr.Box(elem_classes="controls-panel", visible=False) as object_controls:
708
+ with gr.Column(scale=1):
709
+ with gr.Row():
710
+ position = gr.State(value="bottom-center")
711
+ btn_top_left = gr.Button("↖")
712
+ btn_top_center = gr.Button("↑")
713
+ btn_top_right = gr.Button("↗")
714
+ with gr.Row():
715
+ btn_middle_left = gr.Button("←")
716
+ btn_middle_center = gr.Button("•")
717
+ btn_middle_right = gr.Button("→")
718
+ with gr.Row():
719
+ btn_bottom_left = gr.Button("↙")
720
+ btn_bottom_center = gr.Button("↓")
721
+ btn_bottom_right = gr.Button("↘")
722
+ with gr.Column(scale=1):
723
+ scale_slider = gr.Slider(
724
+ minimum=10,
725
+ maximum=200,
726
+ value=50,
727
+ step=5,
728
+ label="Object Size (%)"
729
+ )
730
 
731
+ process_btn = gr.Button(
732
+ "Process",
733
+ variant="primary",
734
+ interactive=False,
735
+ size="lg"
 
 
736
  )
737
+
738
+ # 오른쪽 패널 (출력)
739
+ with gr.Column(scale=1):
740
+ with gr.Box(elem_classes="output-panel"):
741
+ with gr.Tab("Result"):
742
+ combined_image = gr.Image(
743
+ label="Combined Result",
744
+ show_download_button=True,
745
+ type="pil",
746
+ height=400
747
+ )
 
 
 
 
748
 
749
+ # 텍스트 삽입 옵션을 Accordion으로 변경
750
+ with gr.Accordion("Text Insertion Options", open=False):
751
+ with gr.Group():
752
+ with gr.Row():
753
+ text_input = gr.Textbox(
754
+ label="Text Content",
755
+ placeholder="Enter text to add..."
756
+ )
757
+ text_position_type = gr.Radio(
758
+ choices=["Text Over Image", "Text Behind Image"],
759
+ value="Text Over Image",
760
+ label="Text Position"
761
+ )
762
+
763
+ with gr.Row():
764
+ with gr.Column(scale=1):
765
+ font_choice = gr.Dropdown(
766
+ choices=["Default", "Korean Regular", "Korean Son"],
767
+ value="Default",
768
+ label="Font Selection",
769
+ interactive=True
770
+ )
771
+ font_size = gr.Slider(
772
+ minimum=10,
773
+ maximum=200,
774
+ value=40,
775
+ step=5,
776
+ label="Font Size"
777
+ )
778
+ color_dropdown = gr.Dropdown(
779
+ choices=["White", "Black", "Red", "Green", "Blue", "Yellow", "Purple"],
780
+ value="White",
781
+ label="Text Color"
782
+ )
783
+ thickness = gr.Slider(
784
+ minimum=0,
785
+ maximum=10,
786
+ value=1,
787
+ step=1,
788
+ label="Text Thickness"
789
+ )
790
+ with gr.Column(scale=1):
791
+ opacity_slider = gr.Slider(
792
+ minimum=0,
793
+ maximum=255,
794
+ value=255,
795
+ step=1,
796
+ label="Opacity"
797
+ )
798
+ x_position = gr.Slider(
799
+ minimum=0,
800
+ maximum=100,
801
+ value=50,
802
+ step=1,
803
+ label="X Position (%)"
804
+ )
805
+ y_position = gr.Slider(
806
+ minimum=0,
807
+ maximum=100,
808
+ value=50,
809
+ step=1,
810
+ label="Y Position (%)"
811
+ )
812
+ add_text_btn = gr.Button("Apply Text", variant="primary")
813
 
 
814
  extracted_image = gr.Image(
815
  label="Extracted Object",
816
  show_download_button=True,
817
  type="pil",
818
+ height=200
819
  )
820
 
821
+ # 예제 이미지 섹션 추가
822
+ gr.HTML("""
823
+ <div class="example-section">
824
+ <h3>Example Results</h3>
825
+ <img src="example.png" alt="Example results" />
826
+ </div>
827
+ """)
828
+
829
+ # 이벤트 바인딩
 
 
 
 
 
 
830
  input_image.change(
831
  fn=update_process_button,
832
  inputs=[input_image, text_prompt],
 
841
  queue=False
842
  )
843
 
 
 
 
 
 
 
 
 
844
  bg_prompt.change(
845
  fn=update_controls,
846
  inputs=bg_prompt,
 
848
  queue=False
849
  )
850
 
851
+ # 위치 버튼 이벤트
852
+ for btn, pos in [
853
+ (btn_top_left, "top-left"), (btn_top_center, "top-center"),
854
+ (btn_top_right, "top-right"), (btn_middle_left, "middle-left"),
855
+ (btn_middle_center, "middle-center"), (btn_middle_right, "middle-right"),
856
+ (btn_bottom_left, "bottom-left"), (btn_bottom_center, "bottom-center"),
857
+ (btn_bottom_right, "bottom-right")
858
+ ]:
859
+ btn.click(
860
+ fn=lambda p=pos: p,
861
+ outputs=position,
862
+ queue=False
863
+ )
864
+
865
  process_btn.click(
866
  fn=process_prompt,
867
  inputs=[
 
876
  queue=True
877
  )
878
 
 
879
  add_text_btn.click(
880
  fn=add_text_to_image,
881
  inputs=[
 
888
  y_position,
889
  thickness,
890
  text_position_type,
891
+ font_choice
892
  ],
893
  outputs=combined_image
894
  )
895
 
896
+ demo.queue(max_size=5)
897
  demo.launch(
898
  server_name="0.0.0.0",
899
  server_port=7860,
900
  share=False,
901
+ max_threads=2
902
  )