seawolf2357 commited on
Commit
94f3bc2
ยท
verified ยท
1 Parent(s): 8a86340

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +178 -166
app.py CHANGED
@@ -1,14 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import spaces
3
  import torch
 
4
  from diffusers import FluxKontextPipeline
5
  from diffusers.utils import load_image
6
  from PIL import Image
7
- import os
8
 
9
- # ----------------------------------------------
10
- # Style โ†’ LoRA file mapping
11
- # ----------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  STYLE_LORA_MAP = {
13
  "3D_Chibi": "3D_Chibi_lora_weights.safetensors",
14
  "American_Cartoon": "American_Cartoon_lora_weights.safetensors",
@@ -31,116 +79,106 @@ STYLE_LORA_MAP = {
31
  "Vector": "Vector_lora_weights.safetensors",
32
  "Picasso": "Picasso_lora_weights.safetensors",
33
  "Macaron": "Macaron_lora_weights.safetensors",
34
- "Rick_Morty": "Rick_Morty_lora_weights.safetensors"
35
  }
36
 
37
- # ----------------------------------------------
38
- # Style descriptions (ํˆดํŒ์šฉ)
39
- # ----------------------------------------------
40
  STYLE_DESCRIPTIONS = {
41
- "3D_Chibi": "๊ท€์—ฌ์šด SD ์บ๋ฆญํ„ฐ์˜ 3D ๋А๋‚Œ",
42
- "American_Cartoon": "๊ณ ์ „์ ์ธ ๋ฏธ๊ตญ ์นดํˆฐ ์Šคํƒ€์ผ",
43
- "Chinese_Ink": "์ˆ˜๋ฌตํ™”์˜ ๋ฒˆ์ง๊ณผ ๋†๋‹ด ํ‘œํ˜„",
44
- "Clay_Toy": "์ฐฐํ™ยทํ”Œ๋ผ์Šคํ‹ด ์žฅ๋‚œ๊ฐ่ณช",
45
- "Fabric": "์„ฌ์œ ยทํŒจ๋ธŒ๋ฆญ ์งˆ๊ฐ",
46
- "Ghibli": "์ง€๋ธŒ๋ฆฌํ’ ๋”ฐ๋œปํ•œ ์ƒ‰๊ฐ & ์—ฐํ•„์„ ",
47
- "Irasutoya": "์ผ๋Ÿฌ์Šคํ† ์•ผ ๋ฏธ๋‹ˆ๋ฉ€ ํ‰๋ฉด ๊ทธ๋ฆผ",
48
- "Jojo": "์ฃ ์ฃ ์˜ ๊ธฐ๋ฌ˜ํ•œ ๋ชจํ—˜ ๋ง๊ฐ€ ํ„ฐ์น˜",
49
- "Oil_Painting": "์œ ํ™” ๋ถ“ํ„ฐ์น˜์™€ ์งˆ๊ฐ",
50
- "Pixel": "16/32โ€‘bit ๋ ˆํŠธ๋กœ ํ”ฝ์…€์•„ํŠธ",
51
- "Snoopy": "ํ”ผ๋„ˆ์ธ  ์ŠคํŠธ๋ฆฝ(์Šค๋ˆ„ํ”ผ) ์Šคํƒ€์ผ",
52
- "Poly": "๋กœ์šฐํด๋ฆฌ 3D ๊ธฐํ•˜ํ•™์  ์Šคํƒ€์ผ",
53
- "LEGO": "๋ ˆ๊ณ  ๋ธ”๋ก ์กฐ๋ฆฝ ์Šคํƒ€์ผ",
54
- "Origami": "์ข…์ด์ ‘๊ธฐ ์งˆ๊ฐยท๊ฐ๋„",
55
- "Pop_Art": "ํŒ์•„ํŠธ์˜ ์„ ๋ช…ํ•œ ์ƒ‰๊ฐ๊ณผ ๋„ํŠธ",
56
- "Van_Gogh": "๋ฐ˜ ๊ณ ํ์˜ ๊ตต์€ ์ž„ํŒŒ์Šคํ† ",
57
- "Paper_Cutting": "์ข…์ด ์˜ค๋ฆฌ๊ธฐ ์‹ค๋ฃจ์—ฃ",
58
- "Line": "๊น”๋”ํ•œ ๋ผ์ธ ๋“œ๋กœ์ž‰",
59
- "Vector": "๋ฒกํ„ฐ ๊ทธ๋ž˜ํ”ฝยทํ”Œ๋žซ ๋””์ž์ธ",
60
- "Picasso": "ํ”ผ์นด์†Œ์‹ ์ž…์ฒด์ฃผ์˜ ํ๋น„์ฆ˜",
61
- "Macaron": "ํŒŒ์Šคํ…” ๋งˆ์นด๋กฑํ†ค ๋ถ€๋“œ๋Ÿฌ์›€",
62
- "Rick_Morty": "๋ฆญ ์•ค ๋ชจํ‹ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์Šคํƒ€์ผ"
63
  }
64
 
65
- # ์ „์—ญ ํŒŒ์ดํ”„๋ผ์ธ
66
- pipe = None
67
-
68
-
69
- def get_dtype():
70
- """์ตœ์  dtype(bf16 ์ง€์› ์‹œ bf16, ์•„๋‹ˆ๋ฉด fp16) ์„ ํƒ"""
71
- if torch.cuda.is_available():
72
- major, _ = torch.cuda.get_device_capability()
73
- if major >= 8: # Ada/Hopper GPU๋Š” bf16 ๋ณธ๊ฒฉ ์ง€์›
74
- return torch.bfloat16
75
- return torch.float16
76
 
77
 
78
  def load_pipeline():
79
- """FluxKontext ํŒŒ์ดํ”„๋ผ์ธ์„ (์ง€์—ฐ)๋กœ๋“œ"""
80
- global pipe
81
- if pipe is None:
82
- gr.Info("โฌ‡๏ธ FLUX.1โ€‘Kontext ๋ชจ๋ธ์„ ๋‹ค์šด๋กœ๋“œํ•ฉ๋‹ˆ๋‹คโ€ฆ")
83
-
84
- pipe = FluxKontextPipeline.from_pretrained(
85
- "black-forest-labs/FLUX.1-Kontext-dev",
86
- torch_dtype=get_dtype(),
87
- resume_download=True,
88
- )
89
-
90
- device = "cuda" if torch.cuda.is_available() else "cpu"
91
- pipe.to(device)
92
-
93
- # VRAM ์ ˆ์•ฝ ๋ชจ๋“œ
94
- if torch.cuda.is_available():
95
- pipe.enable_sequential_cpu_offload()
96
- pipe.vae.enable_tiling()
97
 
98
- return pipe
99
 
 
 
 
 
100
 
101
- @spaces.GPU(duration=600) # ์ดˆ๊ธฐ ๋‹ค์šด๋กœ๋“œ ์‹œ๊ฐ„ ํ™•๋ณด
102
- def style_transfer(
103
- input_image,
104
- style_name,
105
- prompt_suffix,
106
- num_inference_steps,
107
- guidance_scale,
108
- seed,
109
- ):
110
- """์„ ํƒํ•œ ์Šคํƒ€์ผ๋กœ ์ด๋ฏธ์ง€ ๋ณ€ํ™˜"""
111
 
 
 
 
 
 
 
112
  if input_image is None:
113
- gr.Warning("๐Ÿ–ผ๏ธ ๋จผ์ € ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜์„ธ์š”!")
114
  return None
115
 
116
  try:
117
  pipe = load_pipeline()
118
 
119
- # ์‹œ๋“œ ๊ณ ์ • (0์ด๋ฉด ๋‚œ์ˆ˜)
120
- generator = None
121
- if seed and int(seed) != 0:
122
- generator = torch.Generator(device=pipe.device).manual_seed(int(seed))
 
123
 
124
- # ์ด๋ฏธ์ง€ ๋กœ๋“œ & ๋ฆฌ์‚ฌ์ด์ฆˆ
125
- img = load_image(input_image) if isinstance(input_image, str) else input_image
126
  img = img.convert("RGB").resize((1024, 1024), Image.Resampling.LANCZOS)
127
 
128
- # LoRA ๋กœ๋”ฉ
129
  lora_file = STYLE_LORA_MAP[style_name]
130
  adapter_name = "style"
131
- pipe.load_lora_weights(
132
- "Owen777/Kontext-Style-Loras",
133
- weight_name=lora_file,
134
- adapter_name=adapter_name,
135
- )
136
- pipe.set_adapters([adapter_name], adapter_weights=[1.0])
137
 
138
- # ํ”„๋กฌํ”„ํŠธ ๊ตฌ์„ฑ
139
- prompt = f"Turn this image into the {style_name.replace('_', ' ')} style."
 
140
  if prompt_suffix and prompt_suffix.strip():
141
  prompt += f" {prompt_suffix.strip()}"
142
 
143
- gr.Info("๐ŸŽจ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑ ์ค‘โ€ฆ")
144
 
145
  result = pipe(
146
  image=img,
@@ -152,111 +190,85 @@ def style_transfer(
152
  width=1024,
153
  )
154
 
155
- # LoRA ์–ธ๋กœ๋“œ ๋ฐ ์บ์‹œ ์ •๋ฆฌ
156
- pipe.unload_lora_weights()
157
  torch.cuda.empty_cache()
158
 
159
  return result.images[0]
160
 
161
  except Exception as e:
162
- gr.Error(f"๐Ÿšจ ์˜ค๋ฅ˜: {e}")
163
  torch.cuda.empty_cache()
 
164
  return None
165
 
166
-
167
- def update_description(style):
168
- return STYLE_DESCRIPTIONS.get(style, "")
169
-
170
-
171
  with gr.Blocks(title="FLUX.1 Kontext Style Transfer", theme=gr.themes.Soft()) as demo:
172
- gr.Markdown(
173
- """
174
- # ๐ŸŽจ FLUX.1 Kontext Style Transfer
175
- FLUX.1โ€‘Kontextโ€‘dev ๋ชจ๋ธ๊ณผ 22๊ฐœ์˜ ๊ณ ํ’ˆ์งˆ LoRA๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์–‘ํ•œ ์˜ˆ์ˆ  ์Šคํƒ€์ผ๋กœ ๋ณ€ํ™˜ํ•˜์„ธ์š”.
176
- """
177
- )
178
 
179
  with gr.Row():
180
  with gr.Column(scale=1):
181
  input_image = gr.Image(label="Upload Image", type="pil", height=400)
182
-
183
  style_dropdown = gr.Dropdown(
184
  choices=list(STYLE_LORA_MAP.keys()),
185
  value="Ghibli",
186
  label="Select Style",
187
- info="Choose from 22 different artistic styles",
188
- )
189
-
190
- style_info = gr.Textbox(
191
- label="Style Description",
192
- value=STYLE_DESCRIPTIONS["Ghibli"],
193
- interactive=False,
194
- lines=2,
195
- )
196
-
197
- prompt_suffix = gr.Textbox(
198
- label="Additional Instructions (Optional)",
199
- placeholder="์˜ˆ: 'make it more colorful', 'add dramatic lighting' โ€ฆ",
200
- lines=2,
201
  )
 
 
202
 
203
  with gr.Accordion("Advanced Settings", open=False):
204
- num_steps = gr.Slider(
205
- 10,
206
- 50,
207
- value=24,
208
- step=1,
209
- label="Inference Steps",
210
- info="๋” ๋†’์„์ˆ˜๋ก ํ’ˆ์งˆโ†‘ ์†๋„โ†“",
211
- )
212
- guidance = gr.Slider(
213
- 1.0,
214
- 7.5,
215
- value=2.5,
216
- step=0.1,
217
- label="Guidance Scale",
218
- info="ํ”„๋กฌํ”„ํŠธ ์ค€์ˆ˜ ์ •๋„",
219
- )
220
- seed = gr.Number(label="Seed (0 = Random)", value=0)
221
-
222
- generate_btn = gr.Button(
223
- "๐ŸŽจ Transform Image", variant="primary", size="lg"
224
- )
225
 
226
  with gr.Column(scale=1):
227
  output_image = gr.Image(label="Styled Result", type="pil", height=400)
228
-
229
- gr.Markdown(
230
- """### ๐Ÿ’ก Tips:
231
- - ๋ชจ๋“  ์ด๋ฏธ์ง€๋Š” 1024ร—1024๋กœ ๋ฆฌ์‚ฌ์ด์ฆˆ๋ฉ๋‹ˆ๋‹ค.
232
- - ์ฒซ ์‹คํ–‰ ์‹œ 7โ€ฏGB ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
233
- - ์Šคํƒ€์ผ ๋ณ€ํ™˜์€ ์•ฝ 30โ€‘60โ€ฏ์ดˆ ์†Œ์š”๋ฉ๋‹ˆ๋‹ค.
234
- - ๋‹ค๋ฅธ ์Šคํƒ€์ผ๋„ ์‹œํ—˜ํ•ด ๋ณด์„ธ์š”!"""
235
- )
236
-
237
- # ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ
238
- style_dropdown.change(update_description, [style_dropdown], [style_info])
239
-
240
- generate_btn.click(
241
- style_transfer,
242
- inputs=[
243
- input_image,
244
- style_dropdown,
245
- prompt_suffix,
246
- num_steps,
247
- guidance,
248
- seed,
249
  ],
250
- outputs=[output_image],
 
 
 
251
  )
252
 
253
- gr.Markdown(
254
- """
255
- ---
256
- Created with โค๏ธ by [Blackโ€‘Forest Labs](https://huggingface.co/black-forest-labs) &
257
- [Owen777/Kontextโ€‘Styleโ€‘Loras](https://huggingface.co/Owen777/Kontext-Style-Loras)
258
- """
259
  )
260
 
 
 
 
 
 
261
  if __name__ == "__main__":
262
- demo.launch()
 
1
+ """
2
+ FLUX.1 Kontext Style Transfer
3
+ ==============================
4
+ Updated: 2025โ€‘07โ€‘12
5
+ ---------------------------------
6
+ ์ด ์Šคํฌ๋ฆฝํŠธ๋Š” Huggingโ€ฏFace **FLUX.1โ€‘Kontextโ€‘dev** ๋ชจ๋ธ๊ณผ
7
+ 22โ€ฏ์ข…์˜ ์Šคํƒ€์ผ LoRA ๊ฐ€์ค‘์น˜๋ฅผ ์ด์šฉํ•ด ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์–‘ํ•œ ์˜ˆ์ˆ 
8
+ ์Šคํƒ€์ผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” Gradio ๋ฐ๋ชจ์ž…๋‹ˆ๋‹ค.
9
+
10
+ ์ฃผ์š” ๊ฐœ์„  ์‚ฌํ•ญ
11
+ --------------
12
+ 1. **๋ชจ๋ธ ์บ์‹ฑ**โ€†โ€“ย `snapshot_download()`๋กœ ์‹คํ–‰ ์‹œ์ž‘ ์‹œ ํ•œ ๋ฒˆ๋งŒ
13
+ ๋ชจ๋ธ๊ณผ LoRA๋ฅผ ์บ์‹ฑํ•ด ์ดํ›„ GPU ์žก์—์„œ๋„ ์žฌ๋‹ค์šด๋กœ๋“œ๊ฐ€ ์—†๋„๋ก
14
+ ํ•จ.
15
+ 2. **GPUโ€ฏVRAM ์ž๋™ ํŒ๋ณ„**โ€†โ€“ย GPUโ€ฏVRAM์ด 24โ€ฏGBโ€ฏ๋ฏธ๋งŒ์ด๋ฉด
16
+ `torch.float16`ย / `enable_sequential_cpu_offload()`๋ฅผ ์ž๋™ ์ ์šฉ.
17
+ 3. **๋‹จ์ผ ๋กœ๋”ฉ ๋ฉ”์‹œ์ง€**โ€†โ€“ย Gradioย `gr.Info()` ๋ฉ”์‹œ์ง€๊ฐ€ ์ตœ์ดˆ 1ํšŒ๋งŒ
18
+ ํ‘œ์‹œ๋˜๋„๋ก ์ˆ˜์ •.
19
+ 4. **๋ฒ„๊ทธ ํ”ฝ์Šค**โ€†โ€“ย seed ์ฒ˜๋ฆฌ, LoRA ์–ธ๋กœ๋“œ, ์ด๋ฏธ์ง€ ๋ฆฌ์‚ฌ์ด์ฆˆ ๋กœ์ง
20
+ ๋“ฑ ์„ธ๋ถ€ ์˜ค๋ฅ˜ ์ˆ˜์ •.
21
+
22
+ ------------------------------------------------------------
23
+ """
24
+ import os
25
  import gradio as gr
26
  import spaces
27
  import torch
28
+ from huggingface_hub import snapshot_download
29
  from diffusers import FluxKontextPipeline
30
  from diffusers.utils import load_image
31
  from PIL import Image
 
32
 
33
+ # ------------------------------------------------------------------
34
+ # ํ™˜๊ฒฝ ์„ค์ • & ๋ชจ๋ธย /ย LoRA ์‚ฌ์ „ ๋‹ค์šด๋กœ๋“œ
35
+ # ------------------------------------------------------------------
36
+ # ํฐ ํŒŒ์ผ์„ ๋น ๋ฅด๊ฒŒ ๋ฐ›๋„๋ก ๊ฐ€์† ํ”Œ๋ž˜๊ทธ ํ™œ์„ฑํ™”
37
+ os.environ.setdefault("HF_HUB_ENABLE_HF_TRANSFER", "1")
38
+
39
+ MODEL_ID = "black-forest-labs/FLUX.1-Kontext-dev"
40
+ LORA_REPO = "Owen777/Kontext-Style-Loras"
41
+ CACHE_DIR = os.getenv("HF_HOME", os.path.expanduser("~/.cache/huggingface"))
42
+
43
+ # --- ์ตœ์ดˆ ์‹คํ–‰ ์‹œ์—๋งŒ ๋‹ค์šด๋กœ๋“œ(์ด๋ฏธ ์บ์‹œ์— ์žˆ์œผ๋ฉด ๊ฑด๋„ˆ๋œ€) ---
44
+ MODEL_DIR = snapshot_download(
45
+ repo_id=MODEL_ID,
46
+ cache_dir=CACHE_DIR,
47
+ resume_download=True,
48
+ token=True # HF ํ† ํฐ(ํ•„์š” ์‹œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ HF_TOKEN ์ง€์ •)
49
+ )
50
+ LORA_DIR = snapshot_download(
51
+ repo_id=LORA_REPO,
52
+ cache_dir=CACHE_DIR,
53
+ resume_download=True,
54
+ token=True
55
+ )
56
+
57
+ # ------------------------------------------------------------------
58
+ # ์Šคํƒ€์ผย โ†’ย LoRA ํŒŒ์ผ ๋งคํ•‘ & ์„ค๋ช…
59
+ # ------------------------------------------------------------------
60
  STYLE_LORA_MAP = {
61
  "3D_Chibi": "3D_Chibi_lora_weights.safetensors",
62
  "American_Cartoon": "American_Cartoon_lora_weights.safetensors",
 
79
  "Vector": "Vector_lora_weights.safetensors",
80
  "Picasso": "Picasso_lora_weights.safetensors",
81
  "Macaron": "Macaron_lora_weights.safetensors",
82
+ "Rick_Morty": "Rick_Morty_lora_weights.safetensors",
83
  }
84
 
 
 
 
85
  STYLE_DESCRIPTIONS = {
86
+ "3D_Chibi": "Cute, miniature 3D character style with big heads",
87
+ "American_Cartoon": "Classic American animation style",
88
+ "Chinese_Ink": "Traditional Chinese ink painting aesthetic",
89
+ "Clay_Toy": "Playful clay/plasticine toy appearance",
90
+ "Fabric": "Soft, textile-like rendering",
91
+ "Ghibli": "Studio Ghibli's distinctive anime style",
92
+ "Irasutoya": "Simple, flat Japanese illustration style",
93
+ "Jojo": "JoJo's Bizarre Adventure manga style",
94
+ "Oil_Painting": "Classic oil painting texture and strokes",
95
+ "Pixel": "Retro pixel art style",
96
+ "Snoopy": "Peanuts comic strip style",
97
+ "Poly": "Low-poly 3D geometric style",
98
+ "LEGO": "LEGO brick construction style",
99
+ "Origami": "Paper folding art style",
100
+ "Pop_Art": "Bold, colorful pop art style",
101
+ "Van_Gogh": "Van Gogh's expressive brushstroke style",
102
+ "Paper_Cutting": "Paper cut-out art style",
103
+ "Line": "Clean line art/sketch style",
104
+ "Vector": "Clean vector graphics style",
105
+ "Picasso": "Cubist art style inspired by Picasso",
106
+ "Macaron": "Soft, pastel macaron-like style",
107
+ "Rick_Morty": "Rick and Morty cartoon style",
108
  }
109
 
110
+ # ------------------------------------------------------------------
111
+ # ํŒŒ์ดํ”„๋ผ์ธ ๋กœ๋” (๋‹จ์ผ ์ธ์Šคํ„ด์Šค)
112
+ # ------------------------------------------------------------------
113
+ _pipeline = None # ๋‚ด๋ถ€ ๊ธ€๋กœ๋ฒŒ ์บ์‹œ
 
 
 
 
 
 
 
114
 
115
 
116
  def load_pipeline():
117
+ """Load (or return cached) FluxKontextPipeline."""
118
+ global _pipeline
119
+ if _pipeline is not None:
120
+ return _pipeline
121
+
122
+ # VRAM์ด 24โ€ฏGBย ๋ฏธ๋งŒ์ด๋ฉด FP16 ์‚ฌ์šฉ + CPU ์˜คํ”„๋กœ๋”ฉ
123
+ dtype = torch.bfloat16
124
+ vram_gb = torch.cuda.get_device_properties(0).total_memory / 1024**3
125
+ if vram_gb < 24:
126
+ dtype = torch.float16
127
+
128
+ gr.Info("FLUX.1โ€‘Kontext ํŒŒ์ดํ”„๋ผ์ธ ๋กœ๋”ฉ ์ค‘โ€ฆย (์ตœ์ดˆ 1ํšŒ)")
129
+
130
+ pipe = FluxKontextPipeline.from_pretrained(
131
+ MODEL_DIR,
132
+ torch_dtype=dtype,
133
+ local_files_only=True,
134
+ )
135
 
136
+ pipe.to("cuda")
137
 
138
+ if vram_gb < 24:
139
+ pipe.enable_sequential_cpu_offload()
140
+ else:
141
+ pipe.enable_model_cpu_offload()
142
 
143
+ _pipeline = pipe
144
+ return _pipeline
 
 
 
 
 
 
 
 
145
 
146
+ # ------------------------------------------------------------------
147
+ # ์Šคํƒ€์ผ ๋ณ€ํ™˜ ํ•จ์ˆ˜ (Spaces GPU ์žก)
148
+ # ------------------------------------------------------------------
149
+ @spaces.GPU(duration=600)
150
+ def style_transfer(input_image, style_name, prompt_suffix, num_inference_steps, guidance_scale, seed):
151
+ """Apply selected style to the uploaded image."""
152
  if input_image is None:
153
+ gr.Warning("Please upload an image first!")
154
  return None
155
 
156
  try:
157
  pipe = load_pipeline()
158
 
159
+ # --- Torchย Generator ์„ค์ • ---
160
+ if seed > 0:
161
+ generator = torch.Generator(device="cuda").manual_seed(int(seed))
162
+ else:
163
+ generator = None # random
164
 
165
+ # --- ์ž…๋ ฅ ์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ ---
166
+ img = input_image if isinstance(input_image, Image.Image) else load_image(input_image)
167
  img = img.convert("RGB").resize((1024, 1024), Image.Resampling.LANCZOS)
168
 
169
+ # --- LoRA ๋กœ๋“œ ---
170
  lora_file = STYLE_LORA_MAP[style_name]
171
  adapter_name = "style"
172
+ pipe.load_lora_weights(LORA_DIR, weight_name=lora_file, adapter_name=adapter_name)
173
+ pipe.set_adapters([adapter_name], [1.0])
 
 
 
 
174
 
175
+ # --- ํ”„๋กฌํ”„ํŠธ ๋นŒ๋“œ ---
176
+ human_readable_style = style_name.replace("_", " ")
177
+ prompt = f"Turn this image into the {human_readable_style} style."
178
  if prompt_suffix and prompt_suffix.strip():
179
  prompt += f" {prompt_suffix.strip()}"
180
 
181
+ gr.Info("Generating styled imageโ€ฆ (24โ€‘60โ€ฏs)")
182
 
183
  result = pipe(
184
  image=img,
 
190
  width=1024,
191
  )
192
 
193
+ # --- LoRA ์–ธ๋กœ๋“œ & GPU ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ---
194
+ pipe.unload_lora_weights(adapter_name=adapter_name)
195
  torch.cuda.empty_cache()
196
 
197
  return result.images[0]
198
 
199
  except Exception as e:
 
200
  torch.cuda.empty_cache()
201
+ gr.Error(f"Error during style transfer: {e}")
202
  return None
203
 
204
+ # ------------------------------------------------------------------
205
+ # Gradio UI ์ •์˜
206
+ # ------------------------------------------------------------------
 
 
207
  with gr.Blocks(title="FLUX.1 Kontext Style Transfer", theme=gr.themes.Soft()) as demo:
208
+ gr.Markdown("""
209
+ # ๐ŸŽจ FLUX.1 Kontext Style Transfer
210
+
211
+ ์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€๋ฅผ 22โ€ฏ์ข…์˜ ์˜ˆ์ˆ  ์Šคํƒ€์ผ๋กœ ๋ณ€ํ™˜ํ•˜์„ธ์š”!
212
+ (๋ชจ๋ธโ€ฏ/โ€ฏLoRA๋Š” ์ตœ์ดˆ ์‹คํ–‰ ์‹œ์—๋งŒ ๋‹ค์šด๋กœ๋“œ๋˜๋ฉฐ, ์ดํ›„ ์‹คํ–‰์€ ๋น ๋ฆ…๋‹ˆ๋‹ค.)
213
+ """)
214
 
215
  with gr.Row():
216
  with gr.Column(scale=1):
217
  input_image = gr.Image(label="Upload Image", type="pil", height=400)
 
218
  style_dropdown = gr.Dropdown(
219
  choices=list(STYLE_LORA_MAP.keys()),
220
  value="Ghibli",
221
  label="Select Style",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  )
223
+ style_info = gr.Textbox(label="Style Description", value=STYLE_DESCRIPTIONS["Ghibli"], interactive=False, lines=2)
224
+ prompt_suffix = gr.Textbox(label="Additional Instructions (Optional)", placeholder="e.g. add dramatic lighting", lines=2)
225
 
226
  with gr.Accordion("Advanced Settings", open=False):
227
+ num_steps = gr.Slider(minimum=10, maximum=50, value=24, step=1, label="Inference Steps")
228
+ guidance = gr.Slider(minimum=1.0, maximum=7.5, value=2.5, step=0.1, label="Guidance Scale")
229
+ seed = gr.Number(label="Seed (0 = random)", value=42)
230
+
231
+ generate_btn = gr.Button("๐ŸŽจ Transform Image", variant="primary", size="lg")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
  with gr.Column(scale=1):
234
  output_image = gr.Image(label="Styled Result", type="pil", height=400)
235
+ gr.Markdown("""
236
+ ### ๐Ÿ’ก Tips
237
+ * ์ด๋ฏธ์ง€ ํฌ๊ธฐ๋Š” 1024ร—1024๋กœ ๋ฆฌ์‚ฌ์ด์ฆˆ๋ฉ๋‹ˆ๋‹ค.
238
+ * ์ตœ์ดˆ 1ํšŒย ๋ชจ๋ธย +ย LoRA ๋‹ค์šด๋กœ๋“œ ํ›„์—๋Š” **์บ์‹œ**๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ 10โ€‘20โ€ฏs ๋‚ด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.
239
+ * "Additional Instructions"์— ์ƒ‰๊ฐยท์กฐ๋ช…ยทํšจ๊ณผ ๋“ฑ์„ ์˜์–ด๋กœ ๊ฐ„๋‹จํžˆ ์ ์œผ๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
240
+ """)
241
+
242
+ # --- ์Šคํƒ€์ผ ์„ค๋ช… ์ž๋™ ์—…๋ฐ์ดํŠธ ---
243
+ def _update_desc(style):
244
+ return STYLE_DESCRIPTIONS.get(style, "")
245
+
246
+ style_dropdown.change(fn=_update_desc, inputs=[style_dropdown], outputs=[style_info])
247
+
248
+ # --- ์˜ˆ์ œ ---
249
+ gr.Examples(
250
+ examples=[
251
+ ["https://huggingface.co/datasets/black-forest-labs/kontext-bench/resolve/main/test/images/0003.jpg", "Ghibli", ""],
252
+ ["https://huggingface.co/datasets/black-forest-labs/kontext-bench/resolve/main/test/images/0003.jpg", "3D_Chibi", "make it extra cute"],
253
+ ["https://huggingface.co/datasets/black-forest-labs/kontext-bench/resolve/main/test/images/0003.jpg", "Van_Gogh", "with swirling sky"],
 
 
254
  ],
255
+ inputs=[input_image, style_dropdown, prompt_suffix],
256
+ outputs=output_image,
257
+ fn=lambda img, style, prompt: style_transfer(img, style, prompt, 24, 2.5, 42),
258
+ cache_examples=False,
259
  )
260
 
261
+ # --- ๋ฒ„ํŠผ ์—ฐ๊ฒฐ ---
262
+ generate_btn.click(
263
+ fn=style_transfer,
264
+ inputs=[input_image, style_dropdown, prompt_suffix, num_steps, guidance, seed],
265
+ outputs=output_image,
 
266
  )
267
 
268
+ gr.Markdown("""
269
+ ---
270
+ **Created with โค๏ธ by GiniGEN (2025)**
271
+ """)
272
+
273
  if __name__ == "__main__":
274
+ demo.launch(inline=False)