58 lines
2.0 KiB
Python
58 lines
2.0 KiB
Python
"""스타일링 ② — 레퍼런스 이미지에서 화풍 명세를 뽑는다
|
|
|
|
번들 템플릿 빌드와 사용자 업로드가 같은 경로를 탄다.
|
|
둘이 갈라지면 사용자 템플릿만 품질이 떨어지고 원인을 찾기 어려워진다.
|
|
"""
|
|
import io
|
|
|
|
from PIL import Image
|
|
|
|
from answers.style_prompt_answer import StylePromptAnswer
|
|
from models.styling import ReferenceVariants
|
|
from settings import settings
|
|
from utils.common_llm import StructuredLLM
|
|
from utils.image import to_data_uri
|
|
from utils.prompt import load_prompt
|
|
|
|
REFERENCE_LONG_EDGE = 2400 # 붓질이 보이는 최소선
|
|
THUMBNAIL_LONG_EDGE = 600 # 화면 카드
|
|
VISION_SIZE = (1536, 1536)
|
|
SMALL_REFERENCE_WARN = 600 # 이보다 작으면 결과가 나빠진다. 막지는 않는다
|
|
|
|
REFERENCE_QUALITY = 92
|
|
THUMBNAIL_QUALITY = 88
|
|
|
|
STYLE_PROMPT_PROMPT = load_prompt("style_prompt")
|
|
|
|
style_llm = StructuredLLM("gpt-4o", settings.chatgpt_api_key)
|
|
|
|
|
|
def encode(image: Image.Image, quality: int) -> bytes:
|
|
buffer = io.BytesIO()
|
|
image.save(buffer, "JPEG", quality=quality, optimize=True)
|
|
return buffer.getvalue()
|
|
|
|
|
|
def build_variants(raw: bytes) -> ReferenceVariants:
|
|
"""올린 바이트에서 전이용 고해상본과 카드용 썸네일을 만든다"""
|
|
Image.MAX_IMAGE_PIXELS = None
|
|
source = Image.open(io.BytesIO(raw)).convert("RGB")
|
|
source.thumbnail((REFERENCE_LONG_EDGE, REFERENCE_LONG_EDGE), Image.LANCZOS)
|
|
|
|
thumbnail = source.copy()
|
|
thumbnail.thumbnail((THUMBNAIL_LONG_EDGE, THUMBNAIL_LONG_EDGE), Image.LANCZOS)
|
|
|
|
return ReferenceVariants(reference=encode(source, REFERENCE_QUALITY),
|
|
thumbnail=encode(thumbnail, THUMBNAIL_QUALITY),
|
|
size=source.size)
|
|
|
|
|
|
async def analyze_style(reference: bytes) -> str:
|
|
Image.MAX_IMAGE_PIXELS = None
|
|
image = Image.open(io.BytesIO(reference)).convert("RGB")
|
|
|
|
answer = await style_llm.ask_with_images(
|
|
StylePromptAnswer, STYLE_PROMPT_PROMPT,
|
|
[("레퍼런스", to_data_uri(image, VISION_SIZE))], temperature=0.2)
|
|
return answer.style_prompt
|