| """ |
| ๋ชฝ๊ธ๋ง์ ํผ๋ ์ด๋ฏธ์ง ์์ฑ๊ธฐ |
| ์
๋ ฅ: ์บ๋ฆญํฐ ์ธํ(Florence-2 ์ถ์ถ) + ํ์คํธ(์์ด) |
| ์ถ๋ ฅ: ํผ๋ ์ด๋ฏธ์ง (์บ๋ฆญํฐ๊ฐ ํ์คํธ๋ฅผ ์ํํ๋ ์ฅ๋ฉด) |
| """ |
| import os as _os; _os.chdir(_os.path.dirname(_os.path.dirname(_os.path.dirname(_os.path.abspath(__file__))))) |
| import os, gc |
| from pathlib import Path |
| os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1" |
|
|
| from diffusers import StableDiffusionXLPipeline, DPMSolverMultistepScheduler |
| import torch |
|
|
| CHARACTER_LORA = "models/lora_v3_32bit/pytorch_lora_weights.safetensors" |
| BG_LORA = "models/lora_bg_v1/pytorch_lora_weights.safetensors" |
|
|
| NEGATIVE = ( |
| "realistic, 3d render, photograph, blurry, dark, gloomy, " |
| "watercolor, sketch, painterly, smooth illustration, " |
| "modern city, urban, scary, violence, text, watermark, " |
| "multiple characters, tiling, repeated" |
| ) |
|
|
|
|
| def _to_appearance_str(appearance) -> str: |
| """dict ๋๋ string โ ์ธํ ํ
์คํธ ๋ณํ""" |
| if isinstance(appearance, str): |
| return appearance.strip() |
| if not isinstance(appearance, dict): |
| return str(appearance).strip() |
|
|
| animal = appearance.get("animal_type", "bear") |
| color = appearance.get("body_color", "") |
| shape = appearance.get("body_shape", "") |
| eye = appearance.get("eye_style", "") |
| nose = appearance.get("nose_mouth") or appearance.get("nose_shape", "") |
| cheeks = appearance.get("cheeks", "") |
| ears = appearance.get("ear_shape", "") |
| texture = appearance.get("texture", "") |
| acc = appearance.get("accessories", "") |
| features = appearance.get("distinctive_features", []) |
| secondary = appearance.get("secondary_colors", []) |
|
|
| parts = [f"a {color} pixel art stuffed {animal} character".strip()] |
| if shape: parts.append(shape) |
| if isinstance(secondary, list): |
| |
| parts.extend(s for s in secondary[:2] if s and len(str(s).split()) <= 3) |
| if eye: parts.append(eye) |
| if cheeks and "no" not in cheeks.lower(): parts.append(cheeks) |
| if ears: parts.append(ears) |
| if nose: parts.append(nose) |
| if texture: parts.append(texture) |
| if isinstance(acc, list): |
| acc = ", ".join(str(a) for a in acc if a) |
| if acc and str(acc).lower() != "none": parts.append(acc) |
| |
|
|
| return ", ".join(p for p in parts if p) |
|
|
|
|
| def build_prompt(appearance, quest_en: str): |
| """ |
| prompt โ ์ฅ๋ฉด/์คํ์ผ (CLIP-L) |
| prompt_2 โ ์ฅ๋ฉด + ์บ๋ฆญํฐ ์ธํ (OpenCLIP-bigG, ๋ ๊ฐํ ์ธ์ฝ๋์ ๋ ๋ค ์ ๋ฌ) |
| """ |
| appearance_str = _to_appearance_str(appearance) |
| prompt = ( |
| f"monglestyle, {quest_en}, " |
| f"cute chibi stuffed animal character in action, " |
| f"full body pose, 32-bit pixel art scene, pastel colors" |
| ) |
| prompt_2 = f"monglestyle, {appearance_str}" |
| return prompt, prompt_2 |
|
|
|
|
| def load_pipeline(): |
| print("SDXL ๋ก๋ ์ค (์บ๋ฆญํฐ LoRA + ๋ฐฐ๊ฒฝ LoRA)...") |
| pipe = StableDiffusionXLPipeline.from_pretrained( |
| "stabilityai/stable-diffusion-xl-base-1.0", |
| torch_dtype=torch.float16, |
| use_safetensors=True, |
| ).to("cuda") |
|
|
| if not Path(CHARACTER_LORA).exists(): |
| raise FileNotFoundError(f"Character LoRA not found: {CHARACTER_LORA}") |
| if not Path(BG_LORA).exists(): |
| raise FileNotFoundError(f"Background LoRA not found: {BG_LORA}") |
|
|
| pipe.load_lora_weights(CHARACTER_LORA, adapter_name="character") |
| pipe.load_lora_weights(BG_LORA, adapter_name="bg") |
| pipe.set_adapters( |
| ["character", "bg"], |
| adapter_weights=[0.8, 0.8], |
| ) |
| pipe.scheduler = DPMSolverMultistepScheduler.from_config( |
| pipe.scheduler.config, use_karras_sigmas=True |
| ) |
| pipe.enable_attention_slicing() |
| print("๋ก๋ ์๋ฃ!\n") |
| return pipe |
|
|
|
|
| def generate(appearance, quest_en: str, pipe, seed: int = 42): |
| prompt, prompt_2 = build_prompt(appearance, quest_en) |
| print(f" prompt : {prompt}") |
| print(f" prompt_2: {prompt_2}") |
|
|
| return pipe( |
| prompt=prompt, |
| prompt_2=prompt_2, |
| negative_prompt=NEGATIVE, |
| num_inference_steps=20, |
| guidance_scale=7.5, |
| height=1024, |
| width=1024, |
| generator=torch.Generator("cuda").manual_seed(seed), |
| ).images[0] |
|
|
|
|
| def unload_pipeline(pipe): |
| del pipe |
| gc.collect() |
| torch.cuda.empty_cache() |
| print("ํ์ดํ๋ผ์ธ VRAM ํด์ ์๋ฃ") |
|
|