ssboost commited on
Commit
9a19108
·
verified ·
1 Parent(s): 0eaf572

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +161 -200
app.py CHANGED
@@ -1,223 +1,181 @@
1
- import os
2
- import logging
3
- from PIL import Image
4
- import gradio as gr
5
- from dotenv import load_dotenv
6
- from db_examples import product_background_examples
7
-
8
- # 환경 변수 로드
9
- load_dotenv()
10
-
11
- # 로깅 설정
12
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
13
- logger = logging.getLogger(__name__)
14
-
15
- # 이미지 캐시
16
- IMAGE_CACHE = {}
17
-
18
- # CSS (원본 스타일 유지 + 예시 크기 축소)
19
- custom_css = """
20
- :root {
21
- --primary-color: #FB7F0D;
22
- --secondary-color: #ff9a8b;
23
- --accent-color: #FF6B6B;
24
- --background-color: #FFFFFF;
25
- --card-bg: #ffffff;
26
- --text-color: #334155;
27
- --border-radius: 18px;
28
- --shadow: 0 8px 30px rgba(251, 127, 13, 0.08);
29
- }
30
-
31
- .example-gallery {
32
- display: grid;
33
- grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
34
- gap: 20px;
35
- padding: 20px;
36
- }
37
- .example-item {
38
- cursor: pointer;
39
- border: 1px solid rgba(0, 0, 0, 0.1);
40
- border-radius: var(--border-radius);
41
- overflow: hidden;
42
- transition: all 0.3s ease;
43
- background: white;
44
- }
45
- .example-item:hover {
46
- box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
47
- transform: translateY(-2px);
48
- }
49
- .example-item img {
50
- width: 80%;
51
- height: 80px;
52
- object-fit: cover;
53
- }
54
-
55
- .image-container {
56
- border-radius: var(--border-radius);
57
- overflow: hidden;
58
- border: 1px solid rgba(0, 0, 0, 0.08);
59
- transition: all 0.3s ease;
60
- background-color: white;
61
- aspect-ratio: 1 / 1;
62
- }
63
- .image-container:hover {
64
- box-shadow: var(--shadow);
65
- }
66
- .image-container img {
67
- width: 100%;
68
- height: 100%;
69
- object-fit: contain;
70
- }
71
-
72
- .section-title {
73
- display: flex;
74
- align-items: center;
75
- font-size: 20px;
76
- font-weight: 700;
77
- color: #333333;
78
- margin-bottom: 10px;
79
- padding-bottom: 5px;
80
- border-bottom: 2px solid #FB7F0D;
81
- font-family: 'Pretendard', 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif;
82
- }
83
- .section-title img {
84
- margin-right: 10px;
85
- width: 24px;
86
- height: 24px;
87
- }
88
-
89
- body {
90
- font-family: 'Pretendard', 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif;
91
- background-color: var(--background-color);
92
- color: var(--text-color);
93
- line-height: 1.6;
94
- margin: 0;
95
- padding: 0;
96
- }
97
- footer { visibility: hidden; }
98
- .gradio-container {
99
- padding-bottom: 0 !important;
100
- margin-bottom: 0 !important;
101
- }
102
- .gr-block, .gr-row, .gr-column {
103
- margin: 0 !important;
104
- padding: 0 !important;
105
- }
106
- html, body, .gradio-container, .gr-block, .gr-row, .gr-column {
107
- height: auto !important;
108
- }
109
- """
110
-
111
- # 아이콘 링크
112
- fontawesome_link = """
113
- <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" />
114
- """
115
-
116
- # 이미지 로드 및 캐시
117
-
118
- def load_image_cached(path):
119
- if path not in IMAGE_CACHE:
120
  try:
121
- img = Image.open(path)
122
- # 최대 크기 1000px로 축소
123
- max_dim = max(img.size)
124
- if max_dim > 1000:
125
- ratio = 1000 / max_dim
126
- img = img.resize((int(img.width*ratio), int(img.height*ratio)), Image.Resampling.LANCZOS)
127
- IMAGE_CACHE[path] = img
128
  except Exception as e:
129
- logger.error(f"이미지 로드 실패: {path} - {e}")
130
  return None
131
- return IMAGE_CACHE[path]
132
-
133
- # 예시 미리 로드
134
 
135
  def preload_example_images():
136
- for ex in product_background_examples:
137
- load_image_cached(ex[0])
138
- load_image_cached(ex[5])
139
-
140
- # 예시 선택 핸들러
141
-
142
- def load_example(evt: gr.SelectData):
143
- ex = product_background_examples[evt.index]
144
- return ex[0], ex[1], ex[2], ex[3], ex[4] or "(없음)", ex[5]
145
-
146
- # 첫 번째 예시 자동 로드
147
-
148
- def load_first_example():
149
- if product_background_examples:
150
- ex = product_background_examples[0]
151
- return ex[0], ex[1], ex[2], ex[3], ex[4] or "(없음)", ex[5]
152
- return None, "", "", "", "", None
153
-
154
- # Gradio 앱 생성
155
 
156
  def create_app():
157
  with gr.Blocks(css=custom_css, theme=gr.themes.Default(
158
- primary_hue="orange", secondary_hue="orange",
 
159
  font=[gr.themes.GoogleFont("Noto Sans KR"), "ui-sans-serif", "system-ui"]
160
  )) as demo:
161
  gr.HTML(fontawesome_link)
162
-
163
- # 메인 뷰: 번째 예시
164
- with gr.Column(elem_classes="custom-section-group custom-frame"):
165
- gr.HTML('<div class="section-title"><img src="https://cdn-icons-png.flaticon.com/512/681/681443.png"> 배경 유형별 예시</div>')
 
 
166
  with gr.Row():
167
  example_input_image = gr.Image(
168
- label="입력 이미지",
 
 
169
  elem_classes="image-container",
170
- interactive=False,
171
- show_download_button=False,
172
- show_share_button=False,
173
- container=False
174
  )
175
- with gr.Column():
176
  example_bg_type = gr.Textbox(label="배경 유형", interactive=False)
177
  example_bg_option = gr.Textbox(label="배경 선택", interactive=False)
178
  example_product_name = gr.Textbox(label="상품명", interactive=False)
179
  example_additional_info = gr.Textbox(label="추가 요청사항", interactive=False)
180
  example_output_image = gr.Image(
181
- label="결과 이미지",
 
 
182
  elem_classes="image-container",
183
- interactive=False,
184
- show_download_button=False,
185
- show_share_button=False,
186
- container=False
187
  )
188
-
189
- # 갤러리 뷰: 유형별 그룹화
190
- with gr.Column(elem_classes="custom-section-group"):
191
- bg_groups = {}
192
- for idx, ex in enumerate(product_background_examples):
193
- bg_groups.setdefault(ex[1], []).append((idx, ex))
194
- for bg_type, items in bg_groups.items():
195
- gr.HTML(f'<div class="section-title">{bg_type}</div>')
196
- with gr.Row(elem_classes="example-gallery"):
197
- for idx, ex in items:
198
- item = gr.Image(
199
- value=ex[5],
200
- show_label=False,
201
- elem_classes="example-item",
202
- interactive=False,
203
- show_download_button=False,
204
- show_share_button=False,
205
- container=False
206
- )
207
- item.select(
208
- fn=load_example,
209
- inputs=None,
210
- outputs=[
211
- example_input_image,
212
- example_bg_type,
213
- example_bg_option,
214
- example_product_name,
215
- example_additional_info,
216
- example_output_image
217
- ]
218
- )
219
-
220
- # 번째 예시 자동 로드
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  demo.load(
222
  fn=load_first_example,
223
  outputs=[
@@ -229,9 +187,12 @@ def create_app():
229
  example_output_image
230
  ]
231
  )
 
232
  return demo
233
 
234
  if __name__ == "__main__":
235
- preload_example_images()
 
236
  app = create_app()
237
- app.launch(share=False, inbrowser=True, width="100%")
 
 
1
+ global SPECIAL_BACKGROUNDS
2
+
3
+ logger.info(f"Backgrounds 디렉토리 경로: {BACKGROUNDS_DIR}")
4
+ logger.info(f"디렉토리 파일 목록: {os.listdir(BACKGROUNDS_DIR)}")
5
+
6
+ SIMPLE_BACKGROUNDS = load_background_json("simple_backgrounds.json")
7
+ STUDIO_BACKGROUNDS = load_background_json("studio_backgrounds.json")
8
+ NATURE_BACKGROUNDS = load_background_json("nature_backgrounds.json")
9
+ INDOOR_BACKGROUNDS = load_background_json("indoor_backgrounds.json")
10
+ SPECIAL_BACKGROUNDS = load_background_json("special_backgrounds.json")
11
+
12
+ # 기본값 설정 (파일이 없거나 비어있는 경우)
13
+ if not SIMPLE_BACKGROUNDS:
14
+ SIMPLE_BACKGROUNDS = {"클래식 화이트": "clean white background with soft even lighting"}
15
+ if not STUDIO_BACKGROUNDS:
16
+ STUDIO_BACKGROUNDS = {"미니멀 플랫레이": "minimalist flat lay with clean white background"}
17
+ if not NATURE_BACKGROUNDS:
18
+ NATURE_BACKGROUNDS = {"열대 해변": "tropical beach with crystal clear water"}
19
+ if not INDOOR_BACKGROUNDS:
20
+ INDOOR_BACKGROUNDS = {"미니멀 스칸디나비안 거실": "minimalist Scandinavian living room"}
21
+ if not SPECIAL_BACKGROUNDS:
22
+ SPECIAL_BACKGROUNDS = {"네온 라이트": "neon light background with vibrant glowing elements"}
23
+
24
+ logger.info("모든 배경 옵션 초기화 완료")
25
+
26
+ # ------------------- 예시 탭을 위한 함수 -------------------
27
+ def load_image_cached(image_path):
28
+ """이미지를 캐시하여 로드하는 함수"""
29
+ global IMAGE_CACHE
30
+ if image_path not in IMAGE_CACHE:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  try:
32
+ img = Image.open(image_path)
33
+ # 이미지는 미리 리사이즈하여 캐시
34
+ if max(img.size) > 1000:
35
+ ratio = 1000 / max(img.size)
36
+ new_size = (int(img.size[0] * ratio), int(img.size[1] * ratio))
37
+ img = img.resize(new_size, Image.Resampling.LANCZOS)
38
+ IMAGE_CACHE[image_path] = img
39
  except Exception as e:
40
+ logger.error(f"이미지 로드 실패: {image_path}, 에러: {e}")
41
  return None
42
+ return IMAGE_CACHE[image_path]
 
 
43
 
44
  def preload_example_images():
45
+ """예시 이미지들을 미리 로드하는 함수"""
46
+ for example in product_background_examples:
47
+ load_image_cached(example[0]) # 입력 이미지
48
+ load_image_cached(example[5]) # 결과 이미지
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
  def create_app():
51
  with gr.Blocks(css=custom_css, theme=gr.themes.Default(
52
+ primary_hue="orange",
53
+ secondary_hue="orange",
54
  font=[gr.themes.GoogleFont("Noto Sans KR"), "ui-sans-serif", "system-ui"]
55
  )) as demo:
56
  gr.HTML(fontawesome_link)
57
+
58
+ # 상품 배경 이미지 예시 갤러리 섹션
59
+ with gr.Column(elem_classes="custom-frame"):
60
+ gr.HTML('<div class="section-title"><img src="https://cdn-icons-png.flaticon.com/512/681/681443.png"> 상품 배경 이미지 예시 갤러리</div>')
61
+
62
+ # 상단 메인 뷰 영역
63
  with gr.Row():
64
  example_input_image = gr.Image(
65
+ label="입력 이미지",
66
+ height=400,
67
+ width=400,
68
  elem_classes="image-container",
69
+ show_label=True,
70
+ show_download_button=True,
71
+ container=True,
72
+ scale=1
73
  )
74
+ with gr.Column(elem_classes="example-params"):
75
  example_bg_type = gr.Textbox(label="배경 유형", interactive=False)
76
  example_bg_option = gr.Textbox(label="배경 선택", interactive=False)
77
  example_product_name = gr.Textbox(label="상품명", interactive=False)
78
  example_additional_info = gr.Textbox(label="추가 요청사항", interactive=False)
79
  example_output_image = gr.Image(
80
+ label="결과 이미지",
81
+ height=400,
82
+ width=400,
83
  elem_classes="image-container",
84
+ show_label=True,
85
+ show_download_button=True,
86
+ container=True,
87
+ scale=1
88
  )
89
+
90
+ # 배경 유형별 갤러리 섹션
91
+ with gr.Column(elem_classes="custom-frame"):
92
+ gr.HTML('<div class="section-title"><img src="https://cdn-icons-png.flaticon.com/512/3068/3068327.png"> 배경 유형별 예시</div>')
93
+
94
+ # 예시들을 배경 유형별로 그룹화
95
+ examples_by_type = {}
96
+ for example in product_background_examples:
97
+ bg_type = example[1] # 배경 유형
98
+ if bg_type not in examples_by_type:
99
+ examples_by_type[bg_type] = []
100
+ examples_by_type[bg_type].append(example)
101
+
102
+ # 배경 유형별 갤러리 섹션 생성
103
+ for bg_type, examples in examples_by_type.items():
104
+ gr.Markdown(f"### {bg_type}")
105
+ # 10개씩 한 줄로 표시
106
+ for i in range(0, len(examples), 10):
107
+ with gr.Row():
108
+ for j in range(10):
109
+ if i + j < len(examples):
110
+ example = examples[i + j]
111
+ with gr.Column(scale=1, min_width=100):
112
+ # 결과 이미지만 표시
113
+ display_img = gr.Image(
114
+ value=example[5],
115
+ label=None, # 레이블 제거
116
+ elem_classes="example-item",
117
+ height=120, # 크기 축소
118
+ width=120, # 크기 축소
119
+ show_label=False, # 레이블 숨기기
120
+ show_download_button=False, # 다운로드 버튼 숨기기
121
+ show_share_button=False, # 공유 버튼 숨기기
122
+ container=False # 컨테이너 테두리 제거
123
+ )
124
+
125
+ def make_example_handler(ex):
126
+ def handler():
127
+ # 로딩 상태 표시를 위한 중간 업데이트
128
+ yield (
129
+ gr.update(value=None), # 임시로 이미지 비우기
130
+ gr.update(value="로딩 중..."),
131
+ gr.update(value="로딩 중..."),
132
+ gr.update(value="로딩 중..."),
133
+ gr.update(value="로딩 중..."),
134
+ gr.update(value=None)
135
+ )
136
+
137
+ # 실제 데이터 로드
138
+ yield (
139
+ ex[0], # 입력 이미지
140
+ ex[1], # 배경 유형
141
+ ex[2], # 배경 선택
142
+ ex[3], # 상품명
143
+ ex[4] if ex[4] else "(없음)", # 추가 요청사항
144
+ ex[5] # 결과 이미지
145
+ )
146
+ return handler
147
+
148
+ display_img.select(
149
+ fn=make_example_handler(example),
150
+ outputs=[
151
+ example_input_image,
152
+ example_bg_type,
153
+ example_bg_option,
154
+ example_product_name,
155
+ example_additional_info,
156
+ example_output_image
157
+ ],
158
+ queue=True # 요청을 큐에 넣어 순차적으로 처리
159
+ )
160
+ else:
161
+ # 빈 공간 유지
162
+ with gr.Column(scale=1, min_width=100):
163
+ pass
164
+
165
+ # 페이지 로드 시 첫 번째 예시 자동 표시
166
+ def load_first_example():
167
+ if product_background_examples:
168
+ first_example = product_background_examples[0]
169
+ return (
170
+ first_example[0], # 입력 이미지
171
+ first_example[1], # 배경 유형
172
+ first_example[2], # 배경 선택
173
+ first_example[3], # 상품명
174
+ first_example[4] if first_example[4] else "(없음)", # 추가 요청사항
175
+ first_example[5] # 결과 이미지
176
+ )
177
+ return None, "", "", "", "", None
178
+
179
  demo.load(
180
  fn=load_first_example,
181
  outputs=[
 
187
  example_output_image
188
  ]
189
  )
190
+
191
  return demo
192
 
193
  if __name__ == "__main__":
194
+ initialize_backgrounds()
195
+ preload_example_images() # 예시 이미지 미리 로드
196
  app = create_app()
197
+ app.queue(max_size=10) # 요청을 순차적으로 처리하도록 큐 설정
198
+ app.launch(share=False, inbrowser=True, width="100%")