openfree commited on
Commit
917653c
ยท
verified ยท
1 Parent(s): 66db587

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +377 -51
app.py CHANGED
@@ -1,86 +1,412 @@
1
  import time
2
  import gradio as gr
3
  import torch
4
- import spaces
5
  from PIL import Image
6
  import numpy as np
 
 
 
 
7
 
8
- # ์ถ•์†Œ๋œ ๋ชจ๋ธ ๋กœ๋“œ - ๋ฌดํ•œ ์Šคํƒ€ํŒ… ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•œ ๊ฐ„์†Œํ™”
9
- class SimpleModel:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  def __init__(self):
11
- self.initialized = True
12
- print("๊ฐ„์†Œํ™”๋œ ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- def process_image(self, image, prompt, strength):
15
- print(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘: {prompt}, ๊ฐ•๋„: {strength}")
16
- # ์›๋ณธ ์ด๋ฏธ์ง€ ๋ณ€ํ™˜ - ์‹ค์ œ ๋ชจ๋ธ ์—†์ด ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ ๊ตฌํ˜„
17
- img_array = np.array(image).astype(np.float32)
18
- # ๊ฐ„๋‹จํ•œ ์ด๋ฏธ์ง€ ๋ณ€ํ™˜ (์ƒ‰์ƒ ๋ฐ˜์ „)
19
- modified = 255 - img_array
20
- return Image.fromarray(modified.astype('uint8'))
21
-
22
- # ๊ฐ„์†Œํ™”๋œ ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
23
- model = SimpleModel()
24
-
25
- # Spaces GPU ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ
26
- @spaces.GPU(duration=60)
27
- def generate_image(prompt, image, strength=0.5):
28
- if image is None:
29
- return None, "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”."
30
 
31
  try:
32
- # ๊ธฐ๋ณธ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ
33
- result = model.process_image(image, prompt, strength)
34
- return result, f"์ƒ์„ฑ ์™„๋ฃŒ: {prompt}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  except Exception as e:
36
  import traceback
37
- error_msg = f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}\n{traceback.format_exc()}"
38
  print(error_msg)
39
  return None, error_msg
40
 
 
41
  def create_demo():
42
  with gr.Blocks() as demo:
43
- gr.Markdown("# ๊ฐ„์†Œํ™”๋œ ์ด๋ฏธ์ง€ ๋ณ€ํ™˜ ๋„๊ตฌ")
44
 
 
 
 
 
 
45
  with gr.Row():
46
  with gr.Column():
47
- prompt = gr.Textbox(label="๋ณ€ํ™˜ ํ”„๋กฌํ”„ํŠธ", value="artistic portrait")
48
- image = gr.Image(label="์›๋ณธ ์ด๋ฏธ์ง€", type="pil")
49
- strength = gr.Slider(0.0, 1.0, 0.5, step=0.1, label="๋ณ€ํ™˜ ๊ฐ•๋„")
50
- generate_btn = gr.Button("๋ณ€ํ™˜ ์‹œ์ž‘")
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  with gr.Column():
53
- output_image = gr.Image(label="๋ณ€ํ™˜๋œ ์ด๋ฏธ์ง€")
54
- output_text = gr.Textbox(label="๊ฒฐ๊ณผ ๋ฉ”์‹œ์ง€")
 
55
 
56
- # ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  generate_btn.click(
58
  fn=generate_image,
59
- inputs=[prompt, image, strength],
60
- outputs=[output_image, output_text],
61
- )
62
-
63
- # ์˜ˆ์ œ ์ด๋ฏธ์ง€ (Hugging Face Spaces์˜ ์˜ˆ์ œ ํด๋”์— ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •)
64
- example_inputs = [
65
- ["portrait in the style of van gogh", "examples/face.jpg", 0.7],
66
- ["cyberpunk character", "examples/face.jpg", 0.9]
67
- ]
68
-
69
- gr.Examples(
70
- examples=example_inputs,
71
- inputs=[prompt, image, strength]
72
  )
73
 
74
  return demo
75
 
 
76
  if __name__ == "__main__":
77
  import argparse
78
- parser = argparse.ArgumentParser(description="Simple Image Transformer")
79
- parser.add_argument("--port", type=int, default=7860)
 
 
 
80
  args = parser.parse_args()
81
 
82
- print("๊ฐ„์†Œํ™”๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์ค‘...")
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
- # ๋ฐ๋ชจ ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ๋ฐ ์‹คํ–‰
85
  demo = create_demo()
86
- demo.launch(debug=True) # ๋””๋ฒ„๊ทธ ๋ชจ๋“œ ํ™œ์„ฑํ™”
 
 
1
  import time
2
  import gradio as gr
3
  import torch
4
+ from einops import rearrange, repeat
5
  from PIL import Image
6
  import numpy as np
7
+ import spaces # Hugging Face Spaces ์ž„ํฌํŠธ ์ถ”๊ฐ€
8
+ import threading
9
+ import sys
10
+ import os
11
 
12
+ # ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์ƒํƒœ ํ”Œ๋ž˜๊ทธ
13
+ model_initialized = False
14
+ flux_generator = None
15
+ initialization_message = "๋ชจ๋ธ ๋กœ๋”ฉ ์ค‘... ์ž ์‹œ๋งŒ ๊ธฐ๋‹ค๋ ค์ฃผ์„ธ์š”."
16
+
17
+ # ๊ฐ„๋‹จํ•œ ์ธ์šฉ ์ •๋ณด ์ถ”๊ฐ€
18
+ _CITE_ = """PuLID: Person-under-Language Image Diffusion Model"""
19
+
20
+ # GPU ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ ๋ฐ ์žฅ์น˜ ์„ค์ •
21
+ def get_device():
22
+ if torch.cuda.is_available():
23
+ return torch.device('cuda')
24
+ else:
25
+ print("CUDA GPU๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. CPU๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
26
+ return torch.device('cpu')
27
+
28
+ def get_models(name: str, device, offload: bool):
29
+ try:
30
+ # ํ•„์š”ํ•œ ๋ชจ๋“ˆ๋งŒ ์ง€์—ฐ ์ž„ํฌํŠธ
31
+ from flux.util import load_ae, load_clip, load_flow_model, load_t5
32
+
33
+ print(f"๋ชจ๋ธ์„ {device}์— ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.")
34
+ t5 = load_t5(device, max_length=128)
35
+ clip_model = load_clip(device)
36
+ model = load_flow_model(name, device="cpu" if offload else device)
37
+ model.eval()
38
+ ae = load_ae(name, device="cpu" if offload else device)
39
+ return model, ae, t5, clip_model
40
+ except Exception as e:
41
+ print(f"๋ชจ๋ธ ๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")
42
+ return None, None, None, None
43
+
44
+
45
+ class FluxGenerator:
46
  def __init__(self):
47
+ # GPU ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์žฅ์น˜ ์„ค์ •
48
+ self.device = get_device()
49
+ self.offload = False
50
+ self.model_name = 'flux-dev'
51
+ self.initialized = False
52
+ self.model = None
53
+ self.ae = None
54
+ self.t5 = None
55
+ self.clip_model = None
56
+ self.pulid_model = None
57
+
58
+ def initialize(self):
59
+ try:
60
+ # ํ•„์š”ํ•œ ๋ชจ๋“ˆ ์ง€์—ฐ ์ž„ํฌํŠธ
61
+ from pulid.pipeline_flux import PuLIDPipeline
62
+ from flux.sampling import prepare
63
+
64
+ print("๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์‹œ์ž‘...")
65
+ self.model, self.ae, self.t5, self.clip_model = get_models(
66
+ self.model_name,
67
+ device=self.device,
68
+ offload=self.offload,
69
+ )
70
+
71
+ if None in [self.model, self.ae, self.t5, self.clip_model]:
72
+ print("๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์‹คํŒจ: ํ•˜๋‚˜ ์ด์ƒ์˜ ๋ชจ๋ธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
73
+ self.initialized = False
74
+ return
75
+
76
+ self.pulid_model = PuLIDPipeline(
77
+ self.model,
78
+ 'cuda' if torch.cuda.is_available() else 'cpu',
79
+ weight_dtype=torch.bfloat16 if self.device.type == 'cuda' else torch.float32
80
+ )
81
+ self.pulid_model.load_pretrain()
82
+ self.initialized = True
83
+ print("๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ!")
84
+
85
+ # UI ๋ฉ”์‹œ์ง€ ์—…๋ฐ์ดํŠธ
86
+ global initialization_message
87
+ initialization_message = "๋ชจ๋ธ ๋กœ๋”ฉ ์™„๋ฃŒ! ์ด์ œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."
88
+
89
+ except Exception as e:
90
+ import traceback
91
+ error_msg = f"๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}\n{traceback.format_exc()}"
92
+ print(error_msg)
93
+ self.initialized = False
94
+
95
+ # UI ๋ฉ”์‹œ์ง€ ์—…๋ฐ์ดํŠธ
96
+ global initialization_message
97
+ initialization_message = f"๋ชจ๋ธ ๋กœ๋”ฉ ์‹คํŒจ: {str(e)}"
98
+
99
+
100
+ # ์ง€์—ฐ ๋กœ๋”ฉ์„ ์œ„ํ•œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
101
+ def initialize_models_in_background():
102
+ global flux_generator, model_initialized
103
+
104
+ print("๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์‹œ์ž‘...")
105
+
106
+ try:
107
+ # ์ง€์—ฐ ์ž„ํฌํŠธ
108
+ from flux.sampling import denoise, get_noise, get_schedule, prepare, rf_denoise, rf_inversion, unpack
109
+ from flux.util import SamplingOptions
110
+ from pulid.utils import resize_numpy_image_long, seed_everything
111
+
112
+ # ๋ชจ๋ธ ์ดˆ๊ธฐํ™”
113
+ flux_generator = FluxGenerator()
114
+
115
+ # 30์ดˆ ํ›„์— ์ดˆ๊ธฐํ™” ์‹œ์ž‘ (UI๊ฐ€ ๋จผ์ € ๋กœ๋“œ๋˜๋„๋ก)
116
+ time.sleep(30)
117
+ flux_generator.initialize()
118
+
119
+ model_initialized = flux_generator.initialized
120
+
121
+ except Exception as e:
122
+ import traceback
123
+ error_msg = f"๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ดˆ๊ธฐํ™” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}\n{traceback.format_exc()}"
124
+ print(error_msg)
125
+ model_initialized = False
126
+
127
+
128
+ # ๋ชจ๋ธ ์ƒํƒœ ํ™•์ธ ํ•จ์ˆ˜
129
+ def check_model_status():
130
+ global initialization_message
131
+ return initialization_message
132
+
133
+
134
+ # Spaces GPU ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ถ”๊ฐ€ (120์ดˆ GPU ์‚ฌ์šฉ)
135
+ @spaces.GPU(duration=120)
136
+ @torch.inference_mode()
137
+ def generate_image(
138
+ prompt: str,
139
+ id_image,
140
+ num_steps: int,
141
+ guidance: float,
142
+ seed,
143
+ id_weight: float,
144
+ neg_prompt: str,
145
+ true_cfg: float,
146
+ gamma: float,
147
+ eta: float,
148
+ ):
149
+ global flux_generator, model_initialized
150
+
151
+ # ๋ชจ๋ธ์ด ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜์œผ๋ฉด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
152
+ if not model_initialized:
153
+ return None, "๋ชจ๋ธ ์ดˆ๊ธฐํ™”๊ฐ€ ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”."
154
 
155
+ # ID ์ด๋ฏธ์ง€๊ฐ€ ์—†์œผ๋ฉด ์‹คํ–‰ ๋ถˆ๊ฐ€
156
+ if id_image is None:
157
+ return None, "์˜ค๋ฅ˜: ID ์ด๋ฏธ์ง€๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค."
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
  try:
160
+ # ํ•„์š”ํ•œ ๋ชจ๋“ˆ ์ง€์—ฐ ์ž„ํฌํŠธ
161
+ from flux.sampling import denoise, get_noise, get_schedule, prepare, rf_denoise, rf_inversion, unpack
162
+ from flux.util import SamplingOptions
163
+ from pulid.utils import resize_numpy_image_long, seed_everything
164
+
165
+ # ๊ณ ์ • ๋งค๊ฐœ๋ณ€์ˆ˜
166
+ width = 512
167
+ height = 512
168
+ start_step = 0
169
+ timestep_to_start_cfg = 1
170
+ max_sequence_length = 128
171
+ s = 0
172
+ tau = 5
173
+
174
+ flux_generator.t5.max_length = max_sequence_length
175
+
176
+ # ์‹œ๋“œ ์„ค์ •
177
+ try:
178
+ seed = int(seed)
179
+ except:
180
+ seed = -1
181
+
182
+ if seed == -1:
183
+ seed = None
184
+
185
+ opts = SamplingOptions(
186
+ prompt=prompt,
187
+ width=width,
188
+ height=height,
189
+ num_steps=num_steps,
190
+ guidance=guidance,
191
+ seed=seed,
192
+ )
193
+
194
+ if opts.seed is None:
195
+ opts.seed = torch.Generator(device="cpu").seed()
196
+
197
+ seed_everything(opts.seed)
198
+ print(f"Generating prompt: '{opts.prompt}' (seed={opts.seed})...")
199
+ t0 = time.perf_counter()
200
+
201
+ use_true_cfg = abs(true_cfg - 1.0) > 1e-6
202
+
203
+ # 1) ์ž…๋ ฅ ๋…ธ์ด์ฆˆ ์ค€๋น„
204
+ noise = get_noise(
205
+ num_samples=1,
206
+ height=opts.height,
207
+ width=opts.width,
208
+ device=flux_generator.device,
209
+ dtype=torch.bfloat16 if flux_generator.device.type == 'cuda' else torch.float32,
210
+ seed=opts.seed,
211
+ )
212
+ bs, c, h, w = noise.shape
213
+ noise = rearrange(noise, "b c (h ph) (w pw) -> b (h w) (c ph pw)", ph=2, pw=2)
214
+ if noise.shape[0] == 1 and bs > 1:
215
+ noise = repeat(noise, "1 ... -> bs ...", bs=bs)
216
+
217
+ # ID ์ด๋ฏธ์ง€ ์ธ์ฝ”๋”ฉ
218
+ encode_t0 = time.perf_counter()
219
+ id_image = id_image.resize((opts.width, opts.height), resample=Image.LANCZOS)
220
+ x = torch.from_numpy(np.array(id_image).astype(np.float32))
221
+ x = (x / 127.5) - 1.0
222
+ x = rearrange(x, "h w c -> 1 c h w")
223
+ x = x.to(flux_generator.device)
224
+
225
+ dtype = torch.bfloat16 if flux_generator.device.type == 'cuda' else torch.float32
226
+ with torch.autocast(device_type=flux_generator.device.type, dtype=dtype):
227
+ x = flux_generator.ae.encode(x)
228
+ x = x.to(dtype)
229
+
230
+ encode_t1 = time.perf_counter()
231
+ print(f"Encoded in {encode_t1 - encode_t0:.2f} seconds.")
232
+
233
+ timesteps = get_schedule(opts.num_steps, x.shape[-1] * x.shape[-2] // 4, shift=False)
234
+
235
+ # 2) ํ…์ŠคํŠธ ์ž„๋ฒ ๋”ฉ ์ค€๋น„
236
+ inp = prepare(t5=flux_generator.t5, clip=flux_generator.clip_model, img=x, prompt=opts.prompt)
237
+ inp_inversion = prepare(t5=flux_generator.t5, clip=flux_generator.clip_model, img=x, prompt="")
238
+ inp_neg = None
239
+ if use_true_cfg:
240
+ inp_neg = prepare(t5=flux_generator.t5, clip=flux_generator.clip_model, img=x, prompt=neg_prompt)
241
+
242
+ # 3) ID ์ž„๋ฒ ๋”ฉ ์ƒ์„ฑ
243
+ id_embeddings = None
244
+ uncond_id_embeddings = None
245
+ if id_image is not None:
246
+ id_image = np.array(id_image)
247
+ id_image = resize_numpy_image_long(id_image, 1024)
248
+ id_embeddings, uncond_id_embeddings = flux_generator.pulid_model.get_id_embedding(id_image, cal_uncond=use_true_cfg)
249
+
250
+ y_0 = inp["img"].clone().detach()
251
+
252
+ # ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ๊ณผ์ •
253
+ inverted = rf_inversion(
254
+ flux_generator.model,
255
+ **inp_inversion,
256
+ timesteps=timesteps,
257
+ guidance=opts.guidance,
258
+ id=id_embeddings,
259
+ id_weight=id_weight,
260
+ start_step=start_step,
261
+ uncond_id=uncond_id_embeddings,
262
+ true_cfg=true_cfg,
263
+ timestep_to_start_cfg=timestep_to_start_cfg,
264
+ neg_txt=inp_neg["txt"] if use_true_cfg else None,
265
+ neg_txt_ids=inp_neg["txt_ids"] if use_true_cfg else None,
266
+ neg_vec=inp_neg["vec"] if use_true_cfg else None,
267
+ aggressive_offload=False,
268
+ y_1=noise,
269
+ gamma=gamma
270
+ )
271
+
272
+ inp["img"] = inverted
273
+ inp_inversion["img"] = inverted
274
+
275
+ edited = rf_denoise(
276
+ flux_generator.model,
277
+ **inp,
278
+ timesteps=timesteps,
279
+ guidance=opts.guidance,
280
+ id=id_embeddings,
281
+ id_weight=id_weight,
282
+ start_step=start_step,
283
+ uncond_id=uncond_id_embeddings,
284
+ true_cfg=true_cfg,
285
+ timestep_to_start_cfg=timestep_to_start_cfg,
286
+ neg_txt=inp_neg["txt"] if use_true_cfg else None,
287
+ neg_txt_ids=inp_neg["txt_ids"] if use_true_cfg else None,
288
+ neg_vec=inp_neg["vec"] if use_true_cfg else None,
289
+ aggressive_offload=False,
290
+ y_0=y_0,
291
+ eta=eta,
292
+ s=s,
293
+ tau=tau,
294
+ )
295
+
296
+ # ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋””์ฝ”๋”ฉ
297
+ edited = unpack(edited.float(), opts.height, opts.width)
298
+ with torch.autocast(device_type=flux_generator.device.type, dtype=dtype):
299
+ edited = flux_generator.ae.decode(edited)
300
+
301
+ t1 = time.perf_counter()
302
+ print(f"Done in {t1 - t0:.2f} seconds.")
303
+
304
+ # PIL ์ด๋ฏธ์ง€๋กœ ๋ณ€ํ™˜
305
+ edited = edited.clamp(-1, 1)
306
+ edited = rearrange(edited[0], "c h w -> h w c")
307
+ edited = Image.fromarray((127.5 * (edited + 1.0)).cpu().byte().numpy())
308
+
309
+ return edited, str(opts.seed)
310
+
311
  except Exception as e:
312
  import traceback
313
+ error_msg = f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}\n{traceback.format_exc()}"
314
  print(error_msg)
315
  return None, error_msg
316
 
317
+
318
  def create_demo():
319
  with gr.Blocks() as demo:
320
+ gr.Markdown("# PuLID: ์ธ๋ฌผ ์ด๋ฏธ์ง€ ๋ณ€ํ™˜ ๋„๊ตฌ")
321
 
322
+ # ๋ชจ๋ธ ์ƒํƒœ ํ‘œ์‹œ
323
+ status_box = gr.Textbox(label="๋ชจ๋ธ ์ƒํƒœ", value=initialization_message)
324
+ refresh_btn = gr.Button("์ƒํƒœ ์ƒˆ๋กœ๊ณ ์นจ")
325
+ refresh_btn.click(fn=check_model_status, inputs=[], outputs=[status_box])
326
+
327
  with gr.Row():
328
  with gr.Column():
329
+ prompt = gr.Textbox(label="ํ”„๋กฌํ”„ํŠธ", value="portrait, color, cinematic")
330
+ id_image = gr.Image(label="ID ์ด๋ฏธ์ง€", type="pil")
331
+ id_weight = gr.Slider(0.0, 1.0, 0.4, step=0.05, label="ID ๊ฐ€์ค‘์น˜")
332
+ num_steps = gr.Slider(1, 24, 16, step=1, label="๋‹จ๊ณ„ ์ˆ˜")
333
+ guidance = gr.Slider(1.0, 10.0, 3.5, step=0.1, label="๊ฐ€์ด๋˜์Šค")
334
+
335
+ with gr.Accordion("๊ณ ๊ธ‰ ์˜ต์…˜", open=False):
336
+ neg_prompt = gr.Textbox(label="๋„ค๊ฑฐํ‹ฐ๋ธŒ ํ”„๋กฌํ”„ํŠธ", value="")
337
+ true_cfg = gr.Slider(1.0, 10.0, 3.5, step=0.1, label="CFG ์Šค์ผ€์ผ")
338
+ seed = gr.Textbox(value="-1", label="์‹œ๋“œ (-1: ๋žœ๋ค)")
339
+ gr.Markdown("### ๊ธฐํƒ€ ์˜ต์…˜")
340
+ gamma = gr.Slider(0.0, 1.0, 0.5, step=0.1, label="๊ฐ๋งˆ")
341
+ eta = gr.Slider(0.0, 1.0, 0.8, step=0.1, label="์—ํƒ€")
342
+
343
+ generate_btn = gr.Button("์ด๋ฏธ์ง€ ์ƒ์„ฑ")
344
 
345
  with gr.Column():
346
+ output_image = gr.Image(label="์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€")
347
+ seed_output = gr.Textbox(label="๊ฒฐ๊ณผ/์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€")
348
+ gr.Markdown(_CITE_)
349
 
350
+ # ์˜ˆ์ œ ์ถ”๊ฐ€
351
+ with gr.Row():
352
+ gr.Markdown("## ์˜ˆ์ œ")
353
+ example_inps = [
354
+ [
355
+ 'a portrait of a clown',
356
+ 'example_inputs/unsplash/lhon-karwan-11tbHtK5STE-unsplash.jpg',
357
+ 16, 3.5, "-1", 0.4, "", 3.5, 0.5, 0.8
358
+ ],
359
+ [
360
+ 'a portrait of a zombie',
361
+ 'example_inputs/unsplash/baruk-granda-cfLL_jHQ-Iw-unsplash.jpg',
362
+ 16, 3.5, "42", 0.4, "", 3.5, 0.5, 0.8
363
+ ]
364
+ ]
365
+ gr.Examples(
366
+ examples=example_inps,
367
+ inputs=[prompt, id_image, num_steps, guidance, seed,
368
+ id_weight, neg_prompt, true_cfg, gamma, eta]
369
+ )
370
+
371
+ # ์ฃผ๊ธฐ์  ์ƒํƒœ ์—…๋ฐ์ดํŠธ ์„ค์ •
372
+ demo.load(fn=check_model_status, inputs=[], outputs=[status_box], every=5) # 5์ดˆ๋งˆ๋‹ค ์—…๋ฐ์ดํŠธ
373
+
374
+ # Gradio ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
375
  generate_btn.click(
376
  fn=generate_image,
377
+ inputs=[
378
+ prompt, id_image, num_steps, guidance, seed,
379
+ id_weight, neg_prompt, true_cfg, gamma, eta
380
+ ],
381
+ outputs=[output_image, seed_output],
 
 
 
 
 
 
 
 
382
  )
383
 
384
  return demo
385
 
386
+
387
  if __name__ == "__main__":
388
  import argparse
389
+
390
+ parser = argparse.ArgumentParser(description="PuLID for FLUX.1-dev")
391
+ parser.add_argument('--version', type=str, default='v0.9.1')
392
+ parser.add_argument("--name", type=str, default="flux-dev")
393
+ parser.add_argument("--port", type=int, default=8080)
394
  args = parser.parse_args()
395
 
396
+ print("Hugging Face Spaces ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค. GPU ํ• ๋‹น์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.")
397
+
398
+ # UI๊ฐ€ ๋จผ์ € ๋กœ๋“œ๋˜๋„๋ก ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์‹œ์ž‘
399
+ threading.Thread(target=initialize_models_in_background, daemon=True).start()
400
+
401
+ # ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ œํ•œ ์„ค์ • (ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ์กฐ์ • ํ•„์š”)
402
+ try:
403
+ import torch.cuda
404
+ if torch.cuda.is_available():
405
+ # GPU ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ œํ•œ (ํ•„์š”์‹œ ์กฐ์ •)
406
+ torch.cuda.set_per_process_memory_fraction(0.8) # ์ตœ๋Œ€ 80% GPU ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ
407
+ except Exception as e:
408
+ print(f"๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ ์„ค์ • ์ค‘ ์˜ค๋ฅ˜: {e}")
409
 
 
410
  demo = create_demo()
411
+ # ๋””๋ฒ„๊ทธ ๋ชจ๋“œ ํ™œ์„ฑํ™”
412
+ demo.queue().launch(server_name="0.0.0.0", server_port=args.port, debug=True)