dk-image-worldcup / ui /image_gen_tab.py
Kimilhee
이미지 생성 포멧 선택 가능하게 수정.
9d0c0d4
"""
이미지 생성 UI 컴포넌트 및 기능
"""
import gradio as gr
import time
from config import (
HIGH_PRICE_OPTION,
LOW_PRICE_OPTION,
CUSTOM,
GEN_IMAGE_DESC,
WORLDCUPABLE_IMAGE_CNT,
imageStyleMap,
)
from image_generator import genPromptAndImage
def create_image_tab():
"""이미지 생성 탭 UI 생성 함수"""
with gr.Tab("이미지 생성"):
current_img_url = gr.State("")
selectedImageIndex = gr.State(0)
entryImageUrls = gr.State([]) # 저장된 URL 목록
with gr.Column(): # Column을 사용하여 수직 배열
with gr.Row():
with gr.Column(): # Column을 사용하여 수직 배열
userPrompt = gr.TextArea(
label="교재 지문 (필수)",
value=GEN_IMAGE_DESC,
max_lines=5,
)
additionalComment = gr.Textbox(
label="추가 희망사항 (옵셔널)", lines=2, value=""
)
with gr.Column():
with gr.Accordion("상세 설정", open=False):
with gr.Column(): # Column을 사용하여 수직 배열
with gr.Row():
highImgCnt = gr.Textbox(
label="비싼 이미지",
value="0",
interactive=False,
)
lowImgCnt = gr.Textbox(
label="싼 이미지", value="0", interactive=False
)
totalPrice = gr.Textbox(
label="총 이미지 생성 비용(원)",
value="0",
interactive=False,
)
genModelKind = gr.Radio(
[LOW_PRICE_OPTION, HIGH_PRICE_OPTION],
label="이미지 생성 모델",
value=LOW_PRICE_OPTION,
)
with gr.Row():
aspectRatio = gr.Radio(
["1:1", "4:3", "16:9", CUSTOM],
label="이미지 비율",
value="16:9",
scale=4,
)
imgWidth = gr.Number(
label="너비 (32의배수)",
value=1440,
scale=1,
visible=False,
maximum=1440,
minimum=256,
step=32,
)
imgHeight = gr.Number(
label="높이 (32의배수)",
value=768,
scale=1,
visible=False,
maximum=1440,
minimum=256,
step=32,
)
def custom_aspect_ratio(ratio):
if ratio == CUSTOM:
return (
gr.update(
value=HIGH_PRICE_OPTION,
interactive=False,
),
gr.update(visible=True),
gr.update(visible=True),
)
else:
return (
gr.update(interactive=True),
gr.update(visible=False),
gr.update(visible=False),
)
aspectRatio.change(
fn=custom_aspect_ratio,
inputs=aspectRatio,
outputs=[genModelKind, imgWidth, imgHeight],
)
imageFormatList = ["png", "jpg", "webp"]
imageFormatRadio = gr.Radio(
imageFormatList, label="이미지 포멧", value="webp"
)
styleList = list(imageStyleMap.keys())
imageStyleRadio = gr.Radio(
styleList, label="이미지 스타일", value="알아서"
)
with gr.Accordion("Prompt info", open=False):
fluxPrompt = gr.Textbox(
label="Flux Prompt", value="", lines=10
)
with gr.Row():
genSmartImage = gr.Button("교재 지문 삽화 이미지 생성!")
removeEntryWorldcupBtn = gr.Button("현재 이미지 제거")
with gr.Column():
progressBar = gr.Image(
label=None, interactive=False, visible=False, height=28
)
entryListGallery = gr.Gallery(
label="이미지 월드컵 진출 이미지",
preview=True,
allow_preview=True,
interactive=False,
)
with gr.Row():
entryCount = gr.Markdown("## 이미지 월드컵 진출 이미지 수: 0")
goImageWorldCupBtn = gr.Button(
"이미지 월드컵 하러가기", visible=False
)
@entryListGallery.select(outputs=selectedImageIndex)
def setSelectedImageIndex(evt: gr.SelectData, state=None):
try:
if evt is None:
return 0
return evt.index
except:
return 0
def removeSelectedEntry(entryList, selectedIndex):
if selectedIndex is None or len(entryList) == 0:
return gr.update(value=entryList), entryList
del entryList[selectedIndex]
return (
entryList,
entryList,
f"## 이미지 월드컵 진출 이미지 수: {len(entryList)}",
)
# 왠지 모르게 마지막 요소를 지우면 preview=True 가 안되서 이렇게 함.
def reSelectedEntry(entryList):
return gr.update(selected_index=len(entryList) - 1, preview=True)
removeEntryWorldcupBtn.click(
fn=removeSelectedEntry,
inputs=[entryImageUrls, selectedImageIndex],
outputs=[entryListGallery, entryImageUrls, entryCount],
).then(
fn=reSelectedEntry,
inputs=entryImageUrls,
outputs=entryListGallery,
)
# 이벤트 처리.
# 입력값이 변경될 때마다 Flux Prompt 초기화
for component in [
userPrompt,
aspectRatio,
imageStyleRadio,
additionalComment,
]:
component.change(fn=lambda x: "", inputs=fluxPrompt, outputs=fluxPrompt)
genImageInputs = [
userPrompt,
additionalComment,
fluxPrompt,
aspectRatio,
imageStyleRadio,
imageFormatRadio,
genModelKind,
highImgCnt,
lowImgCnt,
imgWidth,
imgHeight,
]
def show_progress():
return gr.update(label="이미지 생성 중", visible=True)
def hide_progress():
return gr.update(visible=False)
genSmartImage.click(fn=show_progress, outputs=progressBar).then(
fn=genPromptAndImage,
inputs=genImageInputs,
outputs=[
fluxPrompt,
highImgCnt,
lowImgCnt,
totalPrice,
current_img_url,
progressBar,
],
).then(
fn=lambda entryList, imgUrl: (
gr.update(
value=[*entryList, imgUrl],
preview=True,
selected_index=len(entryList),
),
entryList + [imgUrl],
len(entryList),
gr.update(visible=False),
),
inputs=[entryImageUrls, current_img_url],
outputs=[
entryListGallery,
entryImageUrls,
selectedImageIndex,
progressBar,
],
).then(
fn=lambda entryImageUrls: f"## 이미지 월드컵 진출 이미지 수: {len(entryImageUrls)}",
inputs=entryImageUrls,
outputs=entryCount,
).then(
fn=lambda entryCountTxt, entryList: (
[
entryCountTxt + " (이미지 월드컵 가능!)",
gr.update(visible=False),
gr.Info(
f"{len(entryList)}개의 이미지가 만들어졌습니다. '이미지 월드컵'을 시작하실 수 있습니다!",
duration=5,
),
]
if len(entryList) in WORLDCUPABLE_IMAGE_CNT
else [entryCountTxt, gr.update(visible=False)]
),
inputs=[entryCount, entryImageUrls],
outputs=[entryCount, goImageWorldCupBtn],
)
return entryImageUrls