|
import os |
|
import sys |
|
import logging |
|
import tempfile |
|
import traceback |
|
from typing import List, Tuple, Optional, Any |
|
import gradio as gr |
|
from gradio_client import Client, handle_file |
|
from dotenv import load_dotenv |
|
|
|
|
|
load_dotenv() |
|
|
|
|
|
logging.basicConfig( |
|
level=logging.INFO, |
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', |
|
handlers=[ |
|
logging.FileHandler("app.log"), |
|
logging.StreamHandler(sys.stdout) |
|
] |
|
) |
|
logger = logging.getLogger("image-enhancer-control-tower") |
|
|
|
class GradioClientController: |
|
"""ํ๊น
ํ์ด์ค ๊ทธ๋ผ๋์ค API ํด๋ผ์ด์ธํธ ์ปจํธ๋กค๋ฌ""" |
|
|
|
def __init__(self): |
|
self.client = None |
|
self._initialize_client() |
|
|
|
def _initialize_client(self): |
|
"""ํด๋ผ์ด์ธํธ ์ด๊ธฐํ (์๋ํฌ์ธํธ ์ ๋ณด๋ ๋ก๊ทธ์ ๋จ๊ธฐ์ง ์์)""" |
|
try: |
|
api_endpoint = os.environ.get("API_ENDPOINT") |
|
if not api_endpoint: |
|
logger.error("API_ENDPOINT ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.") |
|
raise ValueError("API_ENDPOINT ํ๊ฒฝ ๋ณ์๊ฐ ํ์ํฉ๋๋ค.") |
|
|
|
self.client = Client(api_endpoint) |
|
logger.info("API ํด๋ผ์ด์ธํธ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์ด๊ธฐํ๋์์ต๋๋ค.") |
|
|
|
except Exception as e: |
|
logger.error(f"ํด๋ผ์ด์ธํธ ์ด๊ธฐํ ์คํจ: {e}") |
|
self.client = None |
|
|
|
def update_dropdowns(self, bg_type: str) -> Tuple: |
|
"""๋ฐฐ๊ฒฝ ์ ํ์ ๋ฐ๋ฅธ ๋๋กญ๋ค์ด ์
๋ฐ์ดํธ""" |
|
try: |
|
if not self.client: |
|
logger.error("ํด๋ผ์ด์ธํธ๊ฐ ์ด๊ธฐํ๋์ง ์์์ต๋๋ค.") |
|
return tuple([gr.update() for _ in range(7)]) |
|
|
|
result = self.client.predict( |
|
bg_type=bg_type, |
|
api_name="/update_dropdowns" |
|
) |
|
|
|
logger.info(f"๋๋กญ๋ค์ด ์
๋ฐ์ดํธ ์๋ฃ: {bg_type}") |
|
|
|
|
|
updates = [] |
|
for i, choices in enumerate(result): |
|
if i == 0: |
|
updates.append(gr.update(visible=(bg_type == "์ฌํ ๋ฐฐ๊ฒฝ"), choices=choices, value=choices[0] if choices else None)) |
|
elif i == 1: |
|
updates.append(gr.update(visible=(bg_type == "์คํ๋์ค ๋ฐฐ๊ฒฝ"), choices=choices, value=choices[0] if choices else None)) |
|
elif i == 2: |
|
updates.append(gr.update(visible=(bg_type == "์์ฐ ํ๊ฒฝ"), choices=choices, value=choices[0] if choices else None)) |
|
elif i == 3: |
|
updates.append(gr.update(visible=(bg_type == "์ค๋ด ํ๊ฒฝ"), choices=choices, value=choices[0] if choices else None)) |
|
elif i == 4: |
|
updates.append(gr.update(visible=(bg_type == "ํน์๋ฐฐ๊ฒฝ"), choices=choices, value=choices[0] if choices else None)) |
|
elif i == 5: |
|
updates.append(gr.update(visible=(bg_type == "์ฃผ์ผ๋ฆฌ"), choices=choices, value=choices[0] if choices else None)) |
|
elif i == 6: |
|
updates.append(gr.update(visible=(bg_type == "ํน์ํจ๊ณผ"), choices=choices, value=choices[0] if choices else None)) |
|
|
|
return tuple(updates) |
|
|
|
except Exception as e: |
|
logger.error(f"๋๋กญ๋ค์ด ์
๋ฐ์ดํธ ์ค๋ฅ: {e}") |
|
return tuple([gr.update() for _ in range(7)]) |
|
|
|
def generate_prompt_only(self, password: str, bg_type: str, simple: str, studio: str, |
|
nature: str, indoor: str, special: str, jewelry: str, |
|
special_effects: str, request_text: str, aspect_ratio: str) -> str: |
|
"""ํ๋กฌํํธ๋ง ์์ฑ""" |
|
try: |
|
if not self.client: |
|
logger.error("ํด๋ผ์ด์ธํธ๊ฐ ์ด๊ธฐํ๋์ง ์์์ต๋๋ค.") |
|
return "ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ์ค๋ฅ" |
|
|
|
result = self.client.predict( |
|
password=password, |
|
bg_type=bg_type, |
|
simple=simple, |
|
studio=studio, |
|
nature=nature, |
|
indoor=indoor, |
|
special=special, |
|
jewelry=jewelry, |
|
special_effects=special_effects, |
|
request_text=request_text, |
|
aspect_ratio=aspect_ratio, |
|
api_name="/generate_prompt_with_password_check" |
|
) |
|
|
|
logger.info("ํ๋กฌํํธ ์์ฑ ์๋ฃ") |
|
return result |
|
|
|
except Exception as e: |
|
logger.error(f"ํ๋กฌํํธ ์์ฑ ์ค๋ฅ: {e}") |
|
return f"ํ๋กฌํํธ ์์ฑ ์ค๋ฅ: {str(e)}" |
|
|
|
def process_image(self, password: str, image, bg_type: str, simple: str, studio: str, |
|
nature: str, indoor: str, special: str, jewelry: str, special_effects: str, |
|
request_text: str, quality_level: str, aspect_ratio: str, |
|
output_format: str, enable_enhancement: bool) -> Tuple: |
|
"""์ด๋ฏธ์ง ์ฒ๋ฆฌ (ํธ์ง ๋ฐ ํ์ง ๊ฐ์ )""" |
|
try: |
|
if not self.client: |
|
logger.error("ํด๋ผ์ด์ธํธ๊ฐ ์ด๊ธฐํ๋์ง ์์์ต๋๋ค.") |
|
return ([], None, [], None, "", "", "ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ์ค๋ฅ") |
|
|
|
|
|
temp_path = None |
|
if image is not None: |
|
temp_path = tempfile.mktemp(suffix='.png') |
|
image.save(temp_path) |
|
|
|
|
|
result = self.client.predict( |
|
password=password, |
|
param_1=handle_file(temp_path) if temp_path else None, |
|
param_2=bg_type, |
|
param_3=simple, |
|
param_4=studio, |
|
param_5=nature, |
|
param_6=indoor, |
|
param_7=special, |
|
param_8=jewelry, |
|
param_9=special_effects, |
|
param_10=request_text, |
|
param_11=quality_level, |
|
param_12=aspect_ratio, |
|
param_13=output_format, |
|
param_14=enable_enhancement, |
|
api_name="/check_password" |
|
) |
|
|
|
|
|
if temp_path and os.path.exists(temp_path): |
|
try: |
|
os.remove(temp_path) |
|
except: |
|
pass |
|
|
|
logger.info("์ด๋ฏธ์ง ์ฒ๋ฆฌ ์๋ฃ") |
|
|
|
|
|
return result |
|
|
|
except Exception as e: |
|
logger.error(f"์ด๋ฏธ์ง ์ฒ๋ฆฌ ์ค๋ฅ: {e}") |
|
|
|
if 'temp_path' in locals() and temp_path and os.path.exists(temp_path): |
|
try: |
|
os.remove(temp_path) |
|
except: |
|
pass |
|
return ([], None, [], None, "", "", f"์ด๋ฏธ์ง ์ฒ๋ฆฌ ์ค๋ฅ: {str(e)}") |
|
|
|
|
|
controller = GradioClientController() |
|
|
|
def create_gradio_interface(): |
|
"""Gradio ์ธํฐํ์ด์ค ์์ฑ""" |
|
try: |
|
logger.info("Gradio ์ธํฐํ์ด์ค ์์ฑ ์์") |
|
|
|
|
|
background_types = ["์ฌํ ๋ฐฐ๊ฒฝ", "์คํ๋์ค ๋ฐฐ๊ฒฝ", "์์ฐ ํ๊ฒฝ", "์ค๋ด ํ๊ฒฝ", "ํน์๋ฐฐ๊ฒฝ", "์ฃผ์ผ๋ฆฌ", "ํน์ํจ๊ณผ"] |
|
|
|
with gr.Blocks(title="AI ์ด๋ฏธ์ง ํธ์ง ๋ฐ ํ์ง ๊ฐ์ ") as app: |
|
gr.Markdown("# AI ์ด๋ฏธ์ง ํธ์ง ๋ฐ ํ์ง ๊ฐ์ ๋๊ตฌ") |
|
|
|
|
|
password_box = gr.Textbox( |
|
label="๋น๋ฐ๋ฒํธ", |
|
type="password", |
|
placeholder="์ฌ์ฉํ๋ ค๋ฉด ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํ์ธ์", |
|
interactive=True |
|
) |
|
|
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
|
|
image = gr.Image(label="์ํ ์ด๋ฏธ์ง ์
๋ก๋", type="pil") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
background_type = gr.Radio( |
|
choices=background_types, |
|
label="๋ฐฐ๊ฒฝ ์ ํ", |
|
value="์ฌํ ๋ฐฐ๊ฒฝ" |
|
) |
|
|
|
|
|
simple_dropdown = gr.Dropdown( |
|
choices=[], |
|
label="์ฌํ ๋ฐฐ๊ฒฝ ์ ํ", |
|
visible=True, |
|
interactive=True |
|
) |
|
|
|
studio_dropdown = gr.Dropdown( |
|
choices=[], |
|
label="์คํ๋์ค ๋ฐฐ๊ฒฝ ์ ํ", |
|
visible=False, |
|
interactive=True |
|
) |
|
|
|
nature_dropdown = gr.Dropdown( |
|
choices=[], |
|
label="์์ฐ ํ๊ฒฝ ์ ํ", |
|
visible=False, |
|
interactive=True |
|
) |
|
|
|
indoor_dropdown = gr.Dropdown( |
|
choices=[], |
|
label="์ค๋ด ํ๊ฒฝ ์ ํ", |
|
visible=False, |
|
interactive=True |
|
) |
|
|
|
special_dropdown = gr.Dropdown( |
|
choices=[], |
|
label="ํน์๋ฐฐ๊ฒฝ ์ ํ", |
|
visible=False, |
|
interactive=True |
|
) |
|
|
|
jewelry_dropdown = gr.Dropdown( |
|
choices=[], |
|
label="์ฃผ์ผ๋ฆฌ ๋ฐฐ๊ฒฝ ์ ํ", |
|
visible=False, |
|
interactive=True |
|
) |
|
|
|
special_effects_dropdown = gr.Dropdown( |
|
choices=[], |
|
label="ํน์ํจ๊ณผ ๋ฐฐ๊ฒฝ ์ ํ", |
|
visible=False, |
|
interactive=True |
|
) |
|
|
|
|
|
background_type.change( |
|
fn=controller.update_dropdowns, |
|
inputs=[background_type], |
|
outputs=[simple_dropdown, studio_dropdown, nature_dropdown, |
|
indoor_dropdown, special_dropdown, jewelry_dropdown, special_effects_dropdown] |
|
) |
|
|
|
|
|
request_text = gr.Textbox( |
|
label="์์ฒญ์ฌํญ", |
|
placeholder="์ํ ์ด๋ฏธ์ง์ ์ ์ฉํ ์คํ์ผ, ๋ถ์๊ธฐ, ํน๋ณ ์์ฒญ์ฌํญ ๋ฑ์ ์
๋ ฅํ์ธ์.", |
|
lines=3 |
|
) |
|
|
|
|
|
quality_level = gr.Radio( |
|
label="ํ์ง ๋ ๋ฒจ", |
|
choices=["gpt", "flux"], |
|
value="flux", |
|
info="GPT: GPT ๋ชจ๋ธ (๊ณ ํ์ง), ์ผ๋ฐ: Flux ๋ชจ๋ธ (๋น ๋ฅธ ์ฒ๋ฆฌ + ๊ธฐ๋ณธ ํ์ง๊ฐ์ )" |
|
) |
|
|
|
aspect_ratio = gr.Dropdown( |
|
label="์ข
ํก๋น", |
|
choices=["1:1", "3:2", "2:3"], |
|
value="1:1" |
|
) |
|
|
|
output_format = gr.Dropdown( |
|
label="์ด๋ฏธ์ง ํ์", |
|
choices=["jpg", "png"], |
|
value="jpg" |
|
) |
|
|
|
|
|
enable_enhancement = gr.Checkbox( |
|
label="์ถ๊ฐ ํ์ง ๊ฐ์ ", |
|
value=False, |
|
info="GPT: 1ํ ํ์ง๊ฐ์ , Flux: 2์ฐจ ํ์ง๊ฐ์ (๊ธฐ๋ณธ 1ํ + ์ถ๊ฐ 1ํ)" |
|
) |
|
|
|
|
|
generate_prompt_btn = gr.Button("ํ๋กฌํํธ๋ง ์์ฑ") |
|
|
|
|
|
edit_btn = gr.Button("์ด๋ฏธ์ง ํธ์ง ๋ฐ ํ์ง ๊ฐ์ ") |
|
|
|
with gr.Column(): |
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.Markdown("## ํธ์ง๋ ์ด๋ฏธ์ง") |
|
original_output = gr.Gallery(label="ํธ์ง ๊ฒฐ๊ณผ", preview=True) |
|
original_download = gr.File(label="ํธ์ง ์ด๋ฏธ์ง ๋ค์ด๋ก๋", interactive=False) |
|
|
|
with gr.Column(): |
|
gr.Markdown("## ํ์ง ๊ฐ์ ๋ ์ด๋ฏธ์ง") |
|
enhanced_output = gr.Gallery(label="ํ์ง ๊ฐ์ ๊ฒฐ๊ณผ", preview=True) |
|
enhanced_download = gr.File(label="๊ฐ์ ์ด๋ฏธ์ง ๋ค์ด๋ก๋", interactive=False) |
|
|
|
|
|
prompt_output = gr.Textbox(label="์์ฑ๋ ํ๋กฌํํธ", lines=10, interactive=False) |
|
info = gr.Textbox(label="์ฒ๋ฆฌ ์ ๋ณด", interactive=False) |
|
error = gr.Textbox(label="์ค๋ฅ ๋ฉ์์ง", interactive=False, visible=True) |
|
|
|
|
|
generate_prompt_btn.click( |
|
fn=controller.generate_prompt_only, |
|
inputs=[ |
|
password_box, |
|
background_type, |
|
simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, special_dropdown, |
|
jewelry_dropdown, special_effects_dropdown, |
|
request_text, aspect_ratio |
|
], |
|
outputs=[prompt_output] |
|
) |
|
|
|
|
|
edit_btn.click( |
|
fn=controller.process_image, |
|
inputs=[ |
|
password_box, |
|
image, background_type, |
|
simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, special_dropdown, |
|
jewelry_dropdown, special_effects_dropdown, |
|
request_text, quality_level, aspect_ratio, output_format, enable_enhancement |
|
], |
|
outputs=[ |
|
original_output, original_download, |
|
enhanced_output, enhanced_download, |
|
prompt_output, info, error |
|
] |
|
) |
|
|
|
|
|
app.load( |
|
fn=controller.update_dropdowns, |
|
inputs=[background_type], |
|
outputs=[simple_dropdown, studio_dropdown, nature_dropdown, |
|
indoor_dropdown, special_dropdown, jewelry_dropdown, special_effects_dropdown] |
|
) |
|
|
|
logger.info("Gradio ์ธํฐํ์ด์ค ์์ฑ ์๋ฃ") |
|
return app |
|
|
|
except Exception as e: |
|
logger.error(f"Gradio ์ธํฐํ์ด์ค ์์ฑ ์ค๋ฅ: {e}") |
|
logger.error(traceback.format_exc()) |
|
raise |
|
|
|
|
|
if __name__ == "__main__": |
|
try: |
|
logger.info("์ ํ๋ฆฌ์ผ์ด์
์์") |
|
|
|
|
|
os.makedirs("imgs", exist_ok=True) |
|
logger.info("์ด๋ฏธ์ง ๋๋ ํ ๋ฆฌ ์ค๋น ์๋ฃ") |
|
|
|
app = create_gradio_interface() |
|
logger.info("Gradio ์ฑ ์์") |
|
app.launch(share=True) |
|
|
|
except Exception as e: |
|
logger.error(f"์ฑ ์คํ ์ค๋ฅ: {e}") |
|
logger.error(traceback.format_exc()) |