import os import logging from PIL import Image import gradio as gr from dotenv import load_dotenv from db_examples import product_background_examples # 환경 변수 로드 load_dotenv() # 로깅 설정 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # 캐시된 이미지 저장소 IMAGE_CACHE = {} # 커스텀 CSS 스타일 (원본과 완전 동일) custom_css = """ :root { --primary-color: #FB7F0D; --secondary-color: #ff9a8b; --accent-color: #FF6B6B; --background-color: #FFFFFF; --card-bg: #ffffff; --text-color: #334155; --border-radius: 18px; --shadow: 0 8px 30px rgba(251, 127, 13, 0.08); } .example-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); /* 200px → 150px */ gap: 20px; padding: 20px; } .example-item { cursor: pointer; border: 1px solid rgba(0, 0, 0, 0.1); border-radius: var(--border-radius); overflow: hidden; transition: all 0.3s ease; background: white; } .example-item:hover { box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); transform: translateY(-2px); } .example-item img { width: 100%; height: 80px; /* 100px → 80px */ object-fit: cover; } .image-container { border-radius: var(--border-radius); overflow: hidden; border: 1px solid rgba(0, 0, 0, 0.08); transition: all 0.3s ease; background-color: white; aspect-ratio: 1 / 1; } .image-container:hover { box-shadow: var(--shadow); } .image-container img { width: 100%; height: 100%; object-fit: contain; } .section-title { display: flex; align-items: center; font-size: 20px; font-weight: 700; color: #333333; margin-bottom: 10px; padding-bottom: 5px; border-bottom: 2px solid #FB7F0D; font-family: 'Pretendard', 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif; } .section-title img { margin-right: 10px; width: 24px; height: 24px; } body { font-family: 'Pretendard', 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif; background-color: var(--background-color); color: var(--text-color); line-height: 1.6; margin: 0; padding: 0; } footer { visibility: hidden; } """ # FontAwesome 링크 fontawesome_link = """ """ # 예시 이미지 캐싱 및 로드 함수 def load_image_cached(path): if path not in IMAGE_CACHE: try: img = Image.open(path) IMAGE_CACHE[path] = img except Exception as e: logger.error(f"이미지 로드 실패: {path} - {e}") return None return IMAGE_CACHE[path] def preload_example_images(): for ex in product_background_examples: load_image_cached(ex[0]) load_image_cached(ex[5]) # 예시 선택 핸들러 def load_example(evt: gr.SelectData): ex = product_background_examples[evt.index] return ex[0], ex[1], ex[2], ex[3], ex[4] or "(없음)", ex[5] # 첫 번째 예시 자동 로드 def load_first_example(): if product_background_examples: ex = product_background_examples[0] return ex[0], ex[1], ex[2], ex[3], ex[4] or "(없음)", ex[5] return None, "", "", "", "", None # Gradio 앱 생성 def create_app(): with gr.Blocks(css=custom_css, theme=gr.themes.Default( primary_hue="orange", secondary_hue="orange", font=[gr.themes.GoogleFont("Noto Sans KR"), "ui-sans-serif", "system-ui"] )) as demo: gr.HTML(fontawesome_link) # 메인 뷰: 첫 번째 예시 with gr.Column(elem_classes="custom-section-group custom-frame"): gr.HTML('
배경 유형별 예시
') with gr.Row(): example_input_image = gr.Image(label="입력 이미지", elem_classes="image-container") with gr.Column(): example_bg_type = gr.Textbox(label="배경 유형", interactive=False) example_bg_option = gr.Textbox(label="배경 선택", interactive=False) example_product_name = gr.Textbox(label="상품명", interactive=False) example_additional_info = gr.Textbox(label="추가 요청사항", interactive=False) example_output_image = gr.Image(label="결과 이미지", elem_classes="image-container") # 배경 유형별 갤러리 뷰 with gr.Column(elem_classes="custom-section-group"): # 유형별 그룹핑 bg_groups = {} for idx, ex in enumerate(product_background_examples): bg_groups.setdefault(ex[1], []).append((idx, ex)) for bg_type, items in bg_groups.items(): # 그룹 헤더 gr.HTML(f'
{bg_type}
') # 그룹 아이템 with gr.Row(elem_classes="example-gallery"): for idx, ex in items: item = gr.Image(value=ex[5], show_label=False, elem_classes="example-item") item.select( fn=load_example, inputs=None, outputs=[ example_input_image, example_bg_type, example_bg_option, example_product_name, example_additional_info, example_output_image ] ) # 첫 번째 예시 자동 로드 demo.load( fn=load_first_example, outputs=[ example_input_image, example_bg_type, example_bg_option, example_product_name, example_additional_info, example_output_image ] ) return demo if __name__ == "__main__": preload_example_images() app = create_app() app.launch(share=False, inbrowser=True, width="100%")