aiqtech commited on
Commit
584e173
·
verified ·
1 Parent(s): bfd5472

Update app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +277 -200
app-backup.py CHANGED
@@ -268,16 +268,14 @@ def resize_object(image: Image.Image, scale_percent: float) -> Image.Image:
268
  def combine_with_background(foreground: Image.Image, background: Image.Image,
269
  position: str = "bottom-center", scale_percent: float = 100) -> Image.Image:
270
  """전경과 배경 합성 함수"""
271
- # 배경 이미지 준비
272
- result = background.convert('RGBA')
273
 
274
- # 오브젝트 크기 조정
275
  scaled_foreground = resize_object(foreground, scale_percent)
276
 
277
- # 오브젝트 위치 계산
278
  x, y = calculate_object_position(position, result.size, scaled_foreground.size)
 
279
 
280
- # 합성
281
  result.paste(scaled_foreground, (x, y), scaled_foreground)
282
  return result
283
 
@@ -348,7 +346,6 @@ def on_change_prompt(img: Image.Image | None, prompt: str | None, bg_prompt: str
348
  return gr.update(interactive=bool(img and prompt))
349
 
350
 
351
-
352
  def process_prompt(img: Image.Image, prompt: str, bg_prompt: str | None = None,
353
  aspect_ratio: str = "1:1", position: str = "bottom-center",
354
  scale_percent: float = 100) -> tuple[Image.Image, Image.Image]:
@@ -356,7 +353,7 @@ def process_prompt(img: Image.Image, prompt: str, bg_prompt: str | None = None,
356
  if img is None or prompt.strip() == "":
357
  raise gr.Error("Please provide both image and prompt")
358
 
359
- print(f"Processing with position: {position}, scale: {scale_percent}")
360
 
361
  try:
362
  prompt = translate_to_english(prompt)
@@ -369,25 +366,34 @@ def process_prompt(img: Image.Image, prompt: str, bg_prompt: str | None = None,
369
 
370
  if bg_prompt:
371
  try:
 
 
 
 
 
 
 
 
 
372
  combined = combine_with_background(
373
  foreground=results[2],
374
  background=results[1],
375
  position=position,
376
  scale_percent=scale_percent
377
  )
378
- print(f"Combined image created with position: {position}")
379
  return combined, results[2]
380
  except Exception as e:
381
  print(f"Combination error: {str(e)}")
382
  return results[1], results[2]
383
 
384
- return results[1], results[2]
385
  except Exception as e:
386
  print(f"Error in process_prompt: {str(e)}")
387
  raise gr.Error(str(e))
388
  finally:
389
  clear_memory()
390
-
 
391
  def process_bbox(img: Image.Image, box_input: str) -> tuple[Image.Image, Image.Image]:
392
  try:
393
  if img is None or box_input.strip() == "":
@@ -427,71 +433,117 @@ 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
  """
492
 
493
 
494
-
495
  def add_text_with_stroke(draw, text, x, y, font, text_color, stroke_width):
496
  """Helper function to draw text with stroke"""
497
  # Draw the stroke/outline
@@ -628,171 +680,212 @@ def add_text_to_image(
628
  return input_image
629
 
630
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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,21 +900,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,
821
- outputs=[aspect_ratio, object_controls],
822
- queue=False
823
- )
824
-
825
  process_btn.click(
826
  fn=process_prompt,
827
  inputs=[
@@ -836,7 +914,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 +926,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
  )
 
268
  def combine_with_background(foreground: Image.Image, background: Image.Image,
269
  position: str = "bottom-center", scale_percent: float = 100) -> Image.Image:
270
  """전경과 배경 합성 함수"""
271
+ print(f"Combining with position: {position}, scale: {scale_percent}")
 
272
 
273
+ result = background.convert('RGBA')
274
  scaled_foreground = resize_object(foreground, scale_percent)
275
 
 
276
  x, y = calculate_object_position(position, result.size, scaled_foreground.size)
277
+ print(f"Calculated position coordinates: ({x}, {y})")
278
 
 
279
  result.paste(scaled_foreground, (x, y), scaled_foreground)
280
  return result
281
 
 
346
  return gr.update(interactive=bool(img and prompt))
347
 
348
 
 
349
  def process_prompt(img: Image.Image, prompt: str, bg_prompt: str | None = None,
350
  aspect_ratio: str = "1:1", position: str = "bottom-center",
351
  scale_percent: float = 100) -> tuple[Image.Image, Image.Image]:
 
353
  if img is None or prompt.strip() == "":
354
  raise gr.Error("Please provide both image and prompt")
355
 
356
+ print(f"Processing with position: {position}, scale: {scale_percent}") # 디버깅용
357
 
358
  try:
359
  prompt = translate_to_english(prompt)
 
366
 
367
  if bg_prompt:
368
  try:
369
+ print(f"Using position: {position}") # 디버깅용
370
+ # 위치 값 검증
371
+ valid_positions = ["top-left", "top-center", "top-right",
372
+ "middle-left", "middle-center", "middle-right",
373
+ "bottom-left", "bottom-center", "bottom-right"]
374
+ if position not in valid_positions:
375
+ position = "bottom-center"
376
+ print(f"Invalid position, using default: {position}")
377
+
378
  combined = combine_with_background(
379
  foreground=results[2],
380
  background=results[1],
381
  position=position,
382
  scale_percent=scale_percent
383
  )
 
384
  return combined, results[2]
385
  except Exception as e:
386
  print(f"Combination error: {str(e)}")
387
  return results[1], results[2]
388
 
389
+ return results[1], results[2] # 기본 반환 추가
390
  except Exception as e:
391
  print(f"Error in process_prompt: {str(e)}")
392
  raise gr.Error(str(e))
393
  finally:
394
  clear_memory()
395
+
396
+
397
  def process_bbox(img: Image.Image, box_input: str) -> tuple[Image.Image, Image.Image]:
398
  try:
399
  if img is None or box_input.strip() == "":
 
433
  return gr.update(interactive=False, variant="secondary")
434
 
435
 
 
436
  css = """
437
  footer {display: none}
438
  .main-title {
439
  text-align: center;
440
+ margin: 1em 0;
441
+ padding: 1.5em;
442
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
443
+ border-radius: 15px;
444
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
445
  }
446
  .main-title h1 {
447
  color: #2196F3;
448
+ font-size: 2.8em;
449
+ margin-bottom: 0.3em;
450
+ font-weight: 700;
451
  }
452
  .main-title p {
453
+ color: #555;
454
+ font-size: 1.3em;
455
+ line-height: 1.4;
456
  }
457
  .container {
458
  max-width: 1200px;
459
  margin: auto;
460
  padding: 20px;
461
  }
462
+ .input-panel, .output-panel {
 
 
 
463
  background: white;
464
+ padding: 1.5em;
465
+ border-radius: 12px;
466
+ box-shadow: 0 2px 8px rgba(0,0,0,0.08);
467
+ margin-bottom: 1em;
468
+ }
469
+ .controls-panel {
470
+ background: #f8f9fa;
471
  padding: 1em;
472
  border-radius: 8px;
473
+ margin: 1em 0;
474
  }
475
+ .image-display {
476
+ min-height: 512px;
477
+ display: flex;
478
+ align-items: center;
479
+ justify-content: center;
480
+ background: #fafafa;
481
  border-radius: 8px;
482
+ margin: 1em 0;
483
  }
484
+ .example-section {
485
+ text-align: center;
486
+ padding: 2em;
487
+ background: #f5f5f5;
488
+ border-radius: 12px;
489
+ margin-top: 2em;
490
+ }
491
+ .example-section img {
492
+ max-width: 100%;
493
+ border-radius: 8px;
494
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
495
+ }
496
+ .accordion {
497
+ border: 1px solid #e0e0e0;
498
+ border-radius: 8px;
499
+ margin: 1em 0;
500
+ }
501
+ .accordion-header {
502
+ padding: 1em;
503
+ background: #f5f5f5;
504
  cursor: pointer;
 
505
  }
506
+ .accordion-content {
507
+ padding: 1em;
508
+ display: none;
509
+ }
510
+ .accordion.open .accordion-content {
511
+ display: block;
512
  }
513
+ .position-grid {
514
+ display: grid;
515
+ grid-template-columns: repeat(3, 1fr);
516
+ gap: 8px;
517
+ margin: 1em 0;
518
+ }
519
+
520
+
521
  .position-btn {
522
+ padding: 10px;
523
+ border: 1px solid #ddd;
524
+ border-radius: 4px;
525
+ background: white;
526
+ cursor: pointer;
527
  transition: all 0.3s ease;
528
+ width: 40px;
529
+ height: 40px;
530
+ display: flex;
531
+ align-items: center;
532
+ justify-content: center;
533
  }
534
+
535
  .position-btn:hover {
536
+ background: #e3f2fd;
537
  }
538
+
539
  .position-btn.selected {
540
  background-color: #2196F3;
541
  color: white;
542
+ border-color: #1976D2;
543
  }
544
  """
545
 
546
 
 
547
  def add_text_with_stroke(draw, text, x, y, font, text_color, stroke_width):
548
  """Helper function to draw text with stroke"""
549
  # Draw the stroke/outline
 
680
  return input_image
681
 
682
 
683
+ def update_position(new_position):
684
+ """위치 업데이트 함수"""
685
+ print(f"Position updated to: {new_position}")
686
+ return new_position
687
+
688
+ def update_controls(bg_prompt):
689
+ """배경 프롬프트 입력 여부에 따라 컨트롤 표시 업데이트"""
690
+ is_visible = bool(bg_prompt)
691
+ return [
692
+ gr.update(visible=is_visible), # aspect_ratio
693
+ gr.update(visible=is_visible), # object_controls
694
+ ]
695
+
696
  with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
697
+ position = gr.State(value="bottom-center") # 여기로 이동
698
+
699
  gr.HTML("""
700
  <div class="main-title">
701
+ <h1>🎨 GiniGen Canvas-o3</h1>
702
  <p>Remove background of specified objects, generate new backgrounds, and insert text over or behind images with prompts.</p>
703
  </div>
704
  """)
705
 
706
+ with gr.Row(equal_height=True):
707
+ # 왼쪽 패널 (입력)
708
  with gr.Column(scale=1):
709
+ with gr.Group(elem_classes="input-panel"):
710
+ input_image = gr.Image(
711
+ type="pil",
712
+ label="Upload Image",
 
 
 
 
 
 
 
 
 
 
713
  interactive=True,
714
+ height=400
715
  )
716
+ text_prompt = gr.Textbox(
717
+ label="Object to Extract",
718
+ placeholder="Enter what you want to extract...",
719
+ interactive=True
 
 
 
720
  )
721
+ with gr.Row():
722
+ bg_prompt = gr.Textbox(
723
+ label="Background Prompt (optional)",
724
+ placeholder="Describe the background...",
725
+ interactive=True,
726
+ scale=3
727
+ )
728
+ aspect_ratio = gr.Dropdown(
729
+ choices=["1:1", "16:9", "9:16", "4:3"],
730
+ value="1:1",
731
+ label="Aspect Ratio",
732
+ interactive=True,
733
+ visible=True,
734
+ scale=1
 
 
 
 
 
 
 
 
 
735
  )
736
 
737
+ with gr.Group(elem_classes="controls-panel", visible=False) as object_controls:
738
+ with gr.Column(scale=1):
739
+ position = gr.State(value="bottom-center") # 초기값 설정
740
+ with gr.Row():
741
+ btn_top_left = gr.Button("↖", elem_classes="position-btn")
742
+ btn_top_center = gr.Button("↑", elem_classes="position-btn")
743
+ btn_top_right = gr.Button("↗", elem_classes="position-btn")
744
+ with gr.Row():
745
+ btn_middle_left = gr.Button("←", elem_classes="position-btn")
746
+ btn_middle_center = gr.Button("•", elem_classes="position-btn")
747
+ btn_middle_right = gr.Button("→", elem_classes="position-btn")
748
+ with gr.Row():
749
+ btn_bottom_left = gr.Button("↙", elem_classes="position-btn")
750
+ btn_bottom_center = gr.Button("↓", elem_classes="position-btn", value="selected")
751
+ btn_bottom_right = gr.Button("↘", elem_classes="position-btn")
752
+ with gr.Column(scale=1):
753
+ scale_slider = gr.Slider(
754
+ minimum=10,
755
+ maximum=200,
756
+ value=50,
757
+ step=5,
758
+ label="Object Size (%)"
759
+ )
760
 
761
+ process_btn = gr.Button(
762
+ "Process",
763
+ variant="primary",
764
+ interactive=False,
765
+ size="lg"
 
 
766
  )
767
+
768
+ # 오른쪽 패널 (출력)
769
+ with gr.Column(scale=1):
770
+ with gr.Group(elem_classes="output-panel"):
771
+ with gr.Tab("Result"):
772
+ combined_image = gr.Image(
773
+ label="Combined Result",
774
+ show_download_button=True,
775
+ type="pil",
776
+ height=400
777
+ )
 
 
 
 
778
 
779
+ # 텍스트 삽입 옵션을 Accordion으로 변경
780
+ with gr.Accordion("Text Insertion Options", open=False):
781
+ with gr.Group():
782
+ with gr.Row():
783
+ text_input = gr.Textbox(
784
+ label="Text Content",
785
+ placeholder="Enter text to add..."
786
+ )
787
+ text_position_type = gr.Radio(
788
+ choices=["Text Over Image", "Text Behind Image"],
789
+ value="Text Over Image",
790
+ label="Text Position"
791
+ )
792
+
793
+ with gr.Row():
794
+ with gr.Column(scale=1):
795
+ font_choice = gr.Dropdown(
796
+ choices=["Default", "Korean Regular", "Korean Son"],
797
+ value="Default",
798
+ label="Font Selection",
799
+ interactive=True
800
+ )
801
+ font_size = gr.Slider(
802
+ minimum=10,
803
+ maximum=200,
804
+ value=40,
805
+ step=5,
806
+ label="Font Size"
807
+ )
808
+ color_dropdown = gr.Dropdown(
809
+ choices=["White", "Black", "Red", "Green", "Blue", "Yellow", "Purple"],
810
+ value="White",
811
+ label="Text Color"
812
+ )
813
+ thickness = gr.Slider(
814
+ minimum=0,
815
+ maximum=10,
816
+ value=1,
817
+ step=1,
818
+ label="Text Thickness"
819
+ )
820
+ with gr.Column(scale=1):
821
+ opacity_slider = gr.Slider(
822
+ minimum=0,
823
+ maximum=255,
824
+ value=255,
825
+ step=1,
826
+ label="Opacity"
827
+ )
828
+ x_position = gr.Slider(
829
+ minimum=0,
830
+ maximum=100,
831
+ value=50,
832
+ step=1,
833
+ label="X Position (%)"
834
+ )
835
+ y_position = gr.Slider(
836
+ minimum=0,
837
+ maximum=100,
838
+ value=50,
839
+ step=1,
840
+ label="Y Position (%)"
841
+ )
842
+ add_text_btn = gr.Button("Apply Text", variant="primary")
843
 
 
844
  extracted_image = gr.Image(
845
  label="Extracted Object",
846
  show_download_button=True,
847
  type="pil",
848
+ height=200
849
  )
850
 
851
+ # CSS 클래스를 위한 스타일 추가
852
+ gr.HTML("""
853
+ <style>
854
+ .position-btn.selected {
855
+ background-color: #2196F3 !important;
856
+ color: white !important;
857
+ }
858
+ </style>
859
+ """)
860
+
861
+ # 버튼 클릭 이벤트 바인딩
862
+ position_mapping = {
863
+ btn_top_left: "top-left",
864
+ btn_top_center: "top-center",
865
+ btn_top_right: "top-right",
866
+ btn_middle_left: "middle-left",
867
+ btn_middle_center: "middle-center",
868
+ btn_middle_right: "middle-right",
869
+ btn_bottom_left: "bottom-left",
870
+ btn_bottom_center: "bottom-center",
871
+ btn_bottom_right: "bottom-right"
872
+ }
873
+
874
+ for btn, pos in position_mapping.items():
875
+ btn.click(
876
+ fn=lambda pos=pos: update_position(pos), # 클로저 문제 해결을 위해 수정
877
+ outputs=position
878
+ )
879
+
880
+
881
+ # 이벤트 바인딩
882
+ bg_prompt.change(
883
+ fn=update_controls,
884
+ inputs=bg_prompt,
885
+ outputs=[aspect_ratio, object_controls],
886
+ queue=False
887
+ )
888
+
889
  input_image.change(
890
  fn=update_process_button,
891
  inputs=[input_image, text_prompt],
 
900
  queue=False
901
  )
902
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
903
  process_btn.click(
904
  fn=process_prompt,
905
  inputs=[
 
914
  queue=True
915
  )
916
 
 
917
  add_text_btn.click(
918
  fn=add_text_to_image,
919
  inputs=[
 
926
  y_position,
927
  thickness,
928
  text_position_type,
929
+ font_choice
930
  ],
931
  outputs=combined_image
932
  )
933
 
934
+ demo.queue(max_size=5)
935
  demo.launch(
936
  server_name="0.0.0.0",
937
  server_port=7860,
938
  share=False,
939
+ max_threads=2
940
  )