ssboost commited on
Commit
a91da0a
·
verified ·
1 Parent(s): 3368484

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -272
app.py CHANGED
@@ -20,13 +20,60 @@ load_dotenv()
20
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
21
  logger = logging.getLogger(__name__)
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  # ========== 이미지 생성기 관련 함수 ==========
24
  def save_binary_file(file_name, data):
25
  with open(file_name, "wb") as f:
26
  f.write(data)
27
 
28
- def translate_prompt_to_english(prompt, api_key=None):
29
- # 기존 함수 유지하되 API 키 파라미터 추가
30
  if not re.search("[가-힣]", prompt):
31
  return prompt
32
 
@@ -35,16 +82,15 @@ def translate_prompt_to_english(prompt, api_key=None):
35
  prompt = prompt.replace("#3", "IMAGE_TAG_THREE")
36
 
37
  try:
38
- # 사용자 입력 API 키 또는 환경변수 사용
39
- used_api_key = api_key if api_key else os.environ.get("GEMINI_API_KEY")
40
- if not used_api_key:
41
  logger.error("Gemini API 키가 설정되지 않았습니다.")
42
  prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
43
  prompt = prompt.replace("IMAGE_TAG_TWO", "#2")
44
  prompt = prompt.replace("IMAGE_TAG_THREE", "#3")
45
  return prompt
46
 
47
- client = genai.Client(api_key=used_api_key)
48
  translation_prompt = f"""
49
  Translate the following Korean text to English:
50
 
@@ -140,15 +186,13 @@ def preprocess_prompt(prompt, image1, image2, image3):
140
  prompt += " 이미지를 생성해주세요. 이미지에 텍스트나 글자를 포함하지 마세요."
141
  return prompt
142
 
143
- def generate_with_images(prompt, images, variation_index=0, api_key=None):
144
- # API 키 파라미터 추가
145
  try:
146
- # 사용자 입력 API 키 또는 환경변수 사용
147
- used_api_key = api_key if api_key else os.environ.get("GEMINI_API_KEY")
148
- if not used_api_key:
149
- return None, "API 키가 설정되지 않았습니다. API 키를 입력하거나 환경변수를 확인해주세요."
150
 
151
- client = genai.Client(api_key=used_api_key)
152
  logger.info(f"Gemini API 요청 시작 - 프롬프트: {prompt}, 변형 인덱스: {variation_index}")
153
 
154
  variation_suffixes = [
@@ -203,8 +247,7 @@ def generate_with_images(prompt, images, variation_index=0, api_key=None):
203
  logger.exception("이미지 생성 중 오류 발생:")
204
  return None, f"오류 발생: {str(e)}"
205
 
206
- def process_images_with_prompt(image1, image2, image3, prompt, variation_index=0, max_retries=3, api_key=None):
207
- # API 키 파라미터 추가
208
  retry_count = 0
209
  last_error = None
210
 
@@ -218,7 +261,7 @@ def process_images_with_prompt(image1, image2, image3, prompt, variation_index=0
218
  if prompt and prompt.strip():
219
  processed_prompt = preprocess_prompt(prompt, image1, image2, image3)
220
  if re.search("[가-힣]", processed_prompt):
221
- final_prompt = translate_prompt_to_english(processed_prompt, api_key)
222
  else:
223
  final_prompt = processed_prompt
224
  else:
@@ -232,7 +275,7 @@ def process_images_with_prompt(image1, image2, image3, prompt, variation_index=0
232
  final_prompt = "Please creatively composite these three images, combining their main elements into a cohesive and natural scene. Do not include any text or watermarks in the generated image."
233
  logger.info("Default prompt generated for three images")
234
 
235
- result_img, status = generate_with_images(final_prompt, valid_images, variation_index, api_key)
236
  if result_img is not None:
237
  return result_img, status, final_prompt
238
  else:
@@ -248,8 +291,7 @@ def process_images_with_prompt(image1, image2, image3, prompt, variation_index=0
248
 
249
  return None, f"최대 재시도 횟수({max_retries}회) 초과 후 실패: {last_error}", prompt
250
 
251
- def generate_multiple_images(image1, image2, image3, prompt, api_key=None, progress=gr.Progress()):
252
- # API 키 파라미터 추가
253
  results = []
254
  statuses = []
255
  prompts = []
@@ -261,7 +303,7 @@ def generate_multiple_images(image1, image2, image3, prompt, api_key=None, progr
261
 
262
  for i in range(num_images):
263
  progress((i / num_images), desc=f"{i+1}/{num_images} 이미지 생성 중...")
264
- result_img, status, final_prompt = process_images_with_prompt(image1, image2, image3, prompt, i, max_retries, api_key)
265
 
266
  if result_img is not None:
267
  results.append(result_img)
@@ -451,30 +493,6 @@ body {
451
  max-width: 100% !important;
452
  }
453
 
454
- /* 상단 헤더 */
455
- .app-header {
456
- background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
457
- color: white;
458
- padding: 2rem;
459
- border-radius: var(--border-radius);
460
- margin-bottom: 1.5rem;
461
- box-shadow: var(--shadow);
462
- text-align: center;
463
- }
464
-
465
- .app-header h1 {
466
- margin: 0;
467
- font-size: 2.5rem;
468
- font-weight: 700;
469
- letter-spacing: -0.5px;
470
- }
471
-
472
- .app-header p {
473
- margin: 0.75rem 0 0;
474
- font-size: 1.1rem;
475
- opacity: 0.9;
476
- }
477
-
478
  /* 패널 스타일링 */
479
  .gr-group {
480
  background-color: var(--card-bg);
@@ -605,85 +623,6 @@ body {
605
  margin-bottom: 1.2rem;
606
  }
607
 
608
- /* 사용자 매뉴얼 */
609
- .user-manual {
610
- background-color: white;
611
- padding: 2rem;
612
- border-radius: var(--border-radius);
613
- box-shadow: var(--shadow);
614
- margin-top: 2rem;
615
- }
616
-
617
- .manual-title {
618
- font-size: 1.8rem;
619
- font-weight: 700;
620
- color: var(--primary-color);
621
- margin-bottom: 1.5rem;
622
- text-align: center;
623
- display: flex;
624
- align-items: center;
625
- justify-content: center;
626
- }
627
-
628
- .manual-title i {
629
- margin-right: 0.5rem;
630
- font-size: 1.8rem;
631
- }
632
-
633
- .manual-section {
634
- margin-bottom: 1.5rem;
635
- padding: 1.2rem;
636
- background-color: #f8faff;
637
- border-radius: calc(var(--border-radius) - 5px);
638
- }
639
-
640
- .manual-section-title {
641
- font-size: 1.3rem;
642
- font-weight: 700;
643
- margin-bottom: 1rem;
644
- color: var(--primary-color);
645
- display: flex;
646
- align-items: center;
647
- }
648
-
649
- .manual-section-title i {
650
- margin-right: 0.5rem;
651
- font-size: 1.2rem;
652
- }
653
-
654
- .manual-text {
655
- font-size: 1rem;
656
- line-height: 1.7;
657
- }
658
-
659
- .manual-text strong {
660
- color: var(--accent-color);
661
- }
662
-
663
- .tip-box {
664
- background-color: rgba(255, 107, 107, 0.1);
665
- border-left: 3px solid var(--accent-color);
666
- padding: 1rem 1.2rem;
667
- margin: 1rem 0;
668
- border-radius: 8px;
669
- }
670
-
671
- /* 로딩 애니메이션 */
672
- .progress-container {
673
- background-color: rgba(255, 255, 255, 0.9);
674
- border-radius: var(--border-radius);
675
- padding: 2rem;
676
- box-shadow: var(--shadow);
677
- text-align: center;
678
- }
679
-
680
- .progress-bar {
681
- height: 8px;
682
- border-radius: 4px;
683
- background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
684
- margin: 1rem 0;
685
- }
686
-
687
  /* 메인 컨텐츠 스크롤바 */
688
  ::-webkit-scrollbar {
689
  width: 8px;
@@ -760,74 +699,6 @@ body {
760
  animation: fadeIn 0.5s ease-out;
761
  }
762
 
763
- /* 사용 가이드 스타일 */
764
- .guide-container {
765
- background-color: var(--card-bg);
766
- border-radius: var(--border-radius);
767
- box-shadow: var(--shadow);
768
- padding: 1.5rem;
769
- margin-bottom: 1.5rem;
770
- border: 1px solid rgba(0, 0, 0, 0.04);
771
- }
772
-
773
- .guide-title {
774
- font-size: 1.5rem;
775
- font-weight: 700;
776
- color: var(--primary-color);
777
- margin-bottom: 1.5rem;
778
- padding-bottom: 0.5rem;
779
- border-bottom: 2px solid var(--primary-color);
780
- display: flex;
781
- align-items: center;
782
- }
783
-
784
- .guide-title i {
785
- margin-right: 0.8rem;
786
- font-size: 1.5rem;
787
- }
788
-
789
- .guide-item {
790
- display: flex;
791
- margin-bottom: 1rem;
792
- align-items: flex-start;
793
- }
794
-
795
- .guide-number {
796
- background-color: var(--primary-color);
797
- color: white;
798
- width: 25px;
799
- height: 25px;
800
- border-radius: 50%;
801
- display: flex;
802
- align-items: center;
803
- justify-content: center;
804
- font-weight: bold;
805
- margin-right: 10px;
806
- flex-shrink: 0;
807
- }
808
-
809
- .guide-text {
810
- flex: 1;
811
- line-height: 1.6;
812
- }
813
-
814
- .guide-text a {
815
- color: var(--primary-color);
816
- text-decoration: underline;
817
- font-weight: 600;
818
- }
819
-
820
- .guide-text a:hover {
821
- color: var(--accent-color);
822
- }
823
-
824
- .guide-highlight {
825
- background-color: rgba(251, 127, 13, 0.1);
826
- padding: 2px 5px;
827
- border-radius: 4px;
828
- font-weight: 500;
829
- }
830
-
831
  /* Examples 섹션 스타일 */
832
  .examples-section {
833
  display: grid;
@@ -865,64 +736,10 @@ fontawesome_link = """
865
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
866
  """
867
 
868
- # 헤더 HTML
869
- header_html = """
870
- <div class="app-header">
871
- <h1>✨ 끝장AI - 이커머스전문 이미지생성기(Ver 1.3) ✨</h1>
872
- <p style="font-size:18px; margin-top:10px;">
873
- 이커머스에 최적화된 이미지생성 서비스입니다. 다양한 메뉴를 제공하오니 업무에 잘 활용하시기 바랍니다.
874
- </p>
875
- </div>
876
- """
877
-
878
- # 섹션 간 여백용 HTML
879
- section_spacing_html = """
880
- <div style="margin-bottom: 2rem;"></div>
881
- """
882
-
883
- # 이미지 생성기 사용 가이드 HTML
884
- image_generator_guide_html = """
885
- <div class="guide-container">
886
- <div class="guide-title"><i class="fas fa-book"></i> 이미지 생성기 사용 가이드</div>
887
- <div class="guide-item">
888
- <div class="guide-number">1</div>
889
- <div class="guide-text">
890
- <strong class="guide-highlight">Gemini API 키가 필요합니다.</strong> 무료이니 <a href="https://aistudio.google.com/apikey" target="_blank">Google AI Studio</a>를 통해 발급받아 사용해주세요.
891
- </div>
892
- </div>
893
- <div class="guide-item">
894
- <div class="guide-number">2</div>
895
- <div class="guide-text">
896
- 구글 이미지 생성 모델의 특성상 원본 유지가 잘되지 않습니다. 예시와 프롬프트 템플릿을 참고하여 여러번 이미지를 생성해주세요.
897
- </div>
898
- </div>
899
- <div class="guide-item">
900
- <div class="guide-number">3</div>
901
- <div class="guide-text">
902
- 자세한 사용법은 <a href="http://xn--ai-7i4i628e.com/링크" target="_blank">활용법 보러가기</a>에서 확인해주세요.
903
- </div>
904
- </div>
905
- </div>
906
- """
907
-
908
- # 이미지 편집기 사용 가이드 HTML
909
- image_editor_guide_html = """
910
- <div class="guide-container">
911
- <div class="guide-title"><i class="fas fa-book"></i> 이미지 편집기 사용 가이드</div>
912
- <div class="guide-item">
913
- <div class="guide-number">1</div>
914
- <div class="guide-text">
915
- 생성된 이미지를 추가적으로 다양한 필터를 적용하여 실시간으로 편집이 가능합니다.
916
- </div>
917
- </div>
918
- <div class="guide-item">
919
- <div class="guide-number">2</div>
920
- <div class="guide-text">
921
- 자세한 사용법은 <a href="http://xn--ai-7i4i628e.com/링크" target="_blank">활용법 보러가기</a>에서 확인해주세요.
922
- </div>
923
- </div>
924
- </div>
925
- """
926
 
927
  # UI 구성
928
  with gr.Blocks(css=custom_css, theme=gr.themes.Default(
@@ -931,24 +748,17 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Default(
931
  font=[gr.themes.GoogleFont("Noto Sans KR"), "ui-sans-serif", "system-ui"]
932
  )) as demo:
933
  gr.HTML(fontawesome_link)
934
- gr.HTML(header_html)
 
935
 
936
  with gr.Tabs(elem_classes="tabs") as tabs:
937
  # 이미지 생성기 탭
938
  with gr.Tab("✨ 이미지 생성기", elem_classes="tab-content"):
939
- # 사용 가이드 섹션 추가
940
- gr.HTML(image_generator_guide_html)
941
  with gr.Row(equal_height=True):
942
  with gr.Column(scale=1):
943
- # ======== API 키 설정 섹션 ========
944
- with gr.Group():
945
- gr.HTML('<div class="section-title"><i class="fas fa-key"></i> <span>API 키 설정</span></div>')
946
- api_key_input = gr.Textbox(
947
- type="password",
948
- label="Gemini API 키 (선택사항)",
949
- placeholder="API 키를 입력하세요",
950
- elem_classes="gr-text-input"
951
- )
952
 
953
  # ======== 이미지 업로드 및 설정 섹션 ========
954
  with gr.Group():
@@ -1039,8 +849,8 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Default(
1039
 
1040
  # 이미지 편집기 탭 추가
1041
  with gr.Tab("🎨 이미지 편집기", elem_classes="tab-content"):
1042
- # 사용 가이드 섹션 추가
1043
- gr.HTML(image_editor_guide_html)
1044
 
1045
  with gr.Row():
1046
  # 왼쪽 열: 비율 1
@@ -1154,21 +964,20 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Default(
1154
  outputs=prompt_input
1155
  )
1156
 
1157
-
1158
- # 단일 이미지 생성 버튼 이벤트 연결 - API 키 입력값 활용
1159
- def generate_single_image_with_key(image1, image2, image3, prompt, api_key):
1160
- return process_images_with_prompt(image1, image2, image3, prompt, 0, 3, api_key)
1161
 
1162
  submit_single_btn.click(
1163
- fn=lambda image1, image2, image3, prompt, api_key: generate_single_image_with_key(image1, image2, image3, prompt, api_key),
1164
- inputs=[image1_input, image2_input, image3_input, prompt_input, api_key_input],
1165
  outputs=[output_image1, output_text, prompt_display],
1166
  )
1167
 
1168
- # 4장 이미지 생성 버튼 이벤트 연결 - API 키 입력값 활용
1169
  submit_btn.click(
1170
- fn=lambda image1, image2, image3, prompt, api_key: generate_multiple_images(image1, image2, image3, prompt, api_key),
1171
- inputs=[image1_input, image2_input, image3_input, prompt_input, api_key_input],
1172
  outputs=[output_image1, output_image2, output_image3, output_image4, output_text, prompt_display],
1173
  )
1174
 
@@ -1220,5 +1029,7 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Default(
1220
  outputs=download_output
1221
  )
1222
 
 
 
1223
  demo.queue()
1224
  demo.launch(share=False, inbrowser=True, width="100%") # width 파라미터 추가
 
20
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
21
  logger = logging.getLogger(__name__)
22
 
23
+ # ------------------- API 키 순환 시스템 -------------------
24
+ API_KEYS = [] # API 키 목록
25
+ current_key_index = 0 # 현재 사용 중인 키 인덱스
26
+
27
+ def initialize_api_keys():
28
+ """API 키 목록을 초기화하는 함수"""
29
+ global API_KEYS
30
+ # 환경 변수에서 API 키 가져오기
31
+ key1 = os.environ.get("GEMINI_API_KEY_1", "")
32
+ key2 = os.environ.get("GEMINI_API_KEY_2", "")
33
+ key3 = os.environ.get("GEMINI_API_KEY_3", "")
34
+ key4 = os.environ.get("GEMINI_API_KEY_4", "")
35
+ key5 = os.environ.get("GEMINI_API_KEY_5", "")
36
+
37
+ # 빈 문자열이 아닌 키만 추가
38
+ if key1:
39
+ API_KEYS.append(key1)
40
+ if key2:
41
+ API_KEYS.append(key2)
42
+ if key3:
43
+ API_KEYS.append(key3)
44
+ if key4:
45
+ API_KEYS.append(key4)
46
+ if key5:
47
+ API_KEYS.append(key5)
48
+
49
+ # 기존 GEMINI_API_KEY가 있으면 추가
50
+ default_key = os.environ.get("GEMINI_API_KEY", "")
51
+ if default_key and default_key not in API_KEYS:
52
+ API_KEYS.append(default_key)
53
+
54
+ logger.info(f"API 키 {len(API_KEYS)}개가 로드되었습니다.")
55
+
56
+ def get_next_api_key():
57
+ """다음 API 키를 가져오는 함수"""
58
+ global current_key_index
59
+
60
+ if not API_KEYS:
61
+ return None
62
+
63
+ # 현재 키 가져오기
64
+ api_key = API_KEYS[current_key_index]
65
+
66
+ # 다음 키 인덱스로 업데이트
67
+ current_key_index = (current_key_index + 1) % len(API_KEYS)
68
+
69
+ return api_key
70
+
71
  # ========== 이미지 생성기 관련 함수 ==========
72
  def save_binary_file(file_name, data):
73
  with open(file_name, "wb") as f:
74
  f.write(data)
75
 
76
+ def translate_prompt_to_english(prompt):
 
77
  if not re.search("[가-힣]", prompt):
78
  return prompt
79
 
 
82
  prompt = prompt.replace("#3", "IMAGE_TAG_THREE")
83
 
84
  try:
85
+ api_key = get_next_api_key()
86
+ if not api_key:
 
87
  logger.error("Gemini API 키가 설정되지 않았습니다.")
88
  prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
89
  prompt = prompt.replace("IMAGE_TAG_TWO", "#2")
90
  prompt = prompt.replace("IMAGE_TAG_THREE", "#3")
91
  return prompt
92
 
93
+ client = genai.Client(api_key=api_key)
94
  translation_prompt = f"""
95
  Translate the following Korean text to English:
96
 
 
186
  prompt += " 이미지를 생성해주세요. 이미지에 텍스트나 글자를 포함하지 마세요."
187
  return prompt
188
 
189
+ def generate_with_images(prompt, images, variation_index=0):
 
190
  try:
191
+ api_key = get_next_api_key()
192
+ if not api_key:
193
+ return None, "API 키가 설정되지 않았습니다. 환경 변수에 GEMINI_API_KEY_1, GEMINI_API_KEY_2, GEMINI_API_KEY_3, GEMINI_API_KEY_4, GEMINI_API_KEY_5 중 하나 이상을 설정해주세요."
 
194
 
195
+ client = genai.Client(api_key=api_key)
196
  logger.info(f"Gemini API 요청 시작 - 프롬프트: {prompt}, 변형 인덱스: {variation_index}")
197
 
198
  variation_suffixes = [
 
247
  logger.exception("이미지 생성 중 오류 발생:")
248
  return None, f"오류 발생: {str(e)}"
249
 
250
+ def process_images_with_prompt(image1, image2, image3, prompt, variation_index=0, max_retries=3):
 
251
  retry_count = 0
252
  last_error = None
253
 
 
261
  if prompt and prompt.strip():
262
  processed_prompt = preprocess_prompt(prompt, image1, image2, image3)
263
  if re.search("[가-힣]", processed_prompt):
264
+ final_prompt = translate_prompt_to_english(processed_prompt)
265
  else:
266
  final_prompt = processed_prompt
267
  else:
 
275
  final_prompt = "Please creatively composite these three images, combining their main elements into a cohesive and natural scene. Do not include any text or watermarks in the generated image."
276
  logger.info("Default prompt generated for three images")
277
 
278
+ result_img, status = generate_with_images(final_prompt, valid_images, variation_index)
279
  if result_img is not None:
280
  return result_img, status, final_prompt
281
  else:
 
291
 
292
  return None, f"최대 재시도 횟수({max_retries}회) 초과 후 실패: {last_error}", prompt
293
 
294
+ def generate_multiple_images(image1, image2, image3, prompt, progress=gr.Progress()):
 
295
  results = []
296
  statuses = []
297
  prompts = []
 
303
 
304
  for i in range(num_images):
305
  progress((i / num_images), desc=f"{i+1}/{num_images} 이미지 생성 중...")
306
+ result_img, status, final_prompt = process_images_with_prompt(image1, image2, image3, prompt, i, max_retries)
307
 
308
  if result_img is not None:
309
  results.append(result_img)
 
493
  max-width: 100% !important;
494
  }
495
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
  /* 패널 스타일링 */
497
  .gr-group {
498
  background-color: var(--card-bg);
 
623
  margin-bottom: 1.2rem;
624
  }
625
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
626
  /* 메인 컨텐츠 스크롤바 */
627
  ::-webkit-scrollbar {
628
  width: 8px;
 
699
  animation: fadeIn 0.5s ease-out;
700
  }
701
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
702
  /* Examples 섹션 스타일 */
703
  .examples-section {
704
  display: grid;
 
736
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
737
  """
738
 
739
+ # 제목과 사용 가이드 제거
740
+ header_html = ""
741
+ image_generator_guide_html = ""
742
+ image_editor_guide_html = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
743
 
744
  # UI 구성
745
  with gr.Blocks(css=custom_css, theme=gr.themes.Default(
 
748
  font=[gr.themes.GoogleFont("Noto Sans KR"), "ui-sans-serif", "system-ui"]
749
  )) as demo:
750
  gr.HTML(fontawesome_link)
751
+ # 제목 제거
752
+ # gr.HTML(header_html)
753
 
754
  with gr.Tabs(elem_classes="tabs") as tabs:
755
  # 이미지 생성기 탭
756
  with gr.Tab("✨ 이미지 생성기", elem_classes="tab-content"):
757
+ # 사용 가이드 섹션 제거
758
+ # gr.HTML(image_generator_guide_html)
759
  with gr.Row(equal_height=True):
760
  with gr.Column(scale=1):
761
+ # API 키 입력 섹션 제거
 
 
 
 
 
 
 
 
762
 
763
  # ======== 이미지 업로드 및 설정 섹션 ========
764
  with gr.Group():
 
849
 
850
  # 이미지 편집기 탭 추가
851
  with gr.Tab("🎨 이미지 편집기", elem_classes="tab-content"):
852
+ # 사용 가이드 섹션 제거
853
+ # gr.HTML(image_editor_guide_html)
854
 
855
  with gr.Row():
856
  # 왼쪽 열: 비율 1
 
964
  outputs=prompt_input
965
  )
966
 
967
+ # 단일 이미지 생성 버튼 이벤트 연결 - API 키 입력값 제거
968
+ def generate_single_image(image1, image2, image3, prompt):
969
+ return process_images_with_prompt(image1, image2, image3, prompt, 0, 3)
 
970
 
971
  submit_single_btn.click(
972
+ fn=generate_single_image,
973
+ inputs=[image1_input, image2_input, image3_input, prompt_input],
974
  outputs=[output_image1, output_text, prompt_display],
975
  )
976
 
977
+ # 4장 이미지 생성 버튼 이벤트 연결 - API 키 입력값 제거
978
  submit_btn.click(
979
+ fn=generate_multiple_images,
980
+ inputs=[image1_input, image2_input, image3_input, prompt_input],
981
  outputs=[output_image1, output_image2, output_image3, output_image4, output_text, prompt_display],
982
  )
983
 
 
1029
  outputs=download_output
1030
  )
1031
 
1032
+ # API 키 초기화 및 애플리케이션 실행
1033
+ initialize_api_keys() # API 키 초기화 함수 호출
1034
  demo.queue()
1035
  demo.launch(share=False, inbrowser=True, width="100%") # width 파라미터 추가