aiqtech commited on
Commit
fedbad2
ยท
verified ยท
1 Parent(s): 7f8a139

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +99 -210
app.py CHANGED
@@ -6,7 +6,6 @@ import insightface
6
  import gradio as gr
7
  import numpy as np
8
  import os
9
- import shutil
10
  from huggingface_hub import snapshot_download, login
11
  from transformers import CLIPVisionModelWithProjection, CLIPImageProcessor
12
  from kolors.pipelines.pipeline_stable_diffusion_xl_chatglm_256_ipadapter_FaceID import StableDiffusionXLPipeline
@@ -19,148 +18,67 @@ from PIL import Image
19
  from insightface.app import FaceAnalysis
20
  from insightface.data import get_image as ins_get_image
21
 
22
- # ์บ์‹œ ํด๋ฆฌ์–ด (์„ ํƒ์ )
23
- def clear_cache():
24
- cache_dir = "/home/user/.cache/huggingface/hub"
25
- if os.path.exists(cache_dir):
26
- try:
27
- # CLIP ๋ชจ๋ธ ์บ์‹œ๋งŒ ์‚ญ์ œ
28
- clip_cache = os.path.join(cache_dir, "models--openai--clip-vit-large-patch14-336")
29
- if os.path.exists(clip_cache):
30
- shutil.rmtree(clip_cache)
31
- print("Cleared CLIP cache")
32
- except Exception as e:
33
- print(f"Could not clear cache: {e}")
34
-
35
- # ์บ์‹œ ํด๋ฆฌ์–ด (ํ•„์š”์‹œ)
36
- # clear_cache()
37
-
38
  # Hugging Face ํ† ํฐ์œผ๋กœ ๋กœ๊ทธ์ธ
39
  HF_TOKEN = os.getenv("HF_TOKEN")
40
  if HF_TOKEN:
41
  login(token=HF_TOKEN)
42
  print("Successfully logged in to Hugging Face Hub")
43
- else:
44
- print("Warning: HF_TOKEN not found. Using public access only.")
45
-
46
- # GPU ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ
47
- device = "cuda" if torch.cuda.is_available() else "cpu"
48
- dtype = torch.float16 if device == "cuda" else torch.float32
49
-
50
- print(f"Using device: {device}")
51
- print(f"Using dtype: {dtype}")
52
 
53
- # ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ (ํ† ํฐ ์‚ฌ์šฉ)
54
- try:
55
- print("Downloading Kolors models...")
56
- ckpt_dir = snapshot_download(
57
- repo_id="Kwai-Kolors/Kolors",
58
- token=HF_TOKEN,
59
- local_dir_use_symlinks=False,
60
- resume_download=True
61
- )
62
-
63
- print("Downloading FaceID models...")
64
- ckpt_dir_faceid = snapshot_download(
65
- repo_id="Kwai-Kolors/Kolors-IP-Adapter-FaceID-Plus",
66
- token=HF_TOKEN,
67
- local_dir_use_symlinks=False,
68
- resume_download=True
69
- )
70
- except Exception as e:
71
- print(f"Error downloading models: {e}")
72
- raise
73
 
74
- # ๋ชจ๋ธ ๋กœ๋”ฉ
75
- print("Loading text encoder...")
76
  text_encoder = ChatGLMModel.from_pretrained(
77
  f'{ckpt_dir}/text_encoder',
78
- torch_dtype=dtype,
79
  token=HF_TOKEN,
80
- trust_remote_code=True
 
81
  )
82
- if device == "cuda":
83
- text_encoder = text_encoder.half().to(device)
84
 
85
- print("Loading tokenizer...")
86
  tokenizer = ChatGLMTokenizer.from_pretrained(
87
  f'{ckpt_dir}/text_encoder',
88
  token=HF_TOKEN,
89
  trust_remote_code=True
90
  )
91
 
92
- print("Loading VAE...")
93
  vae = AutoencoderKL.from_pretrained(
94
  f"{ckpt_dir}/vae",
95
- revision=None,
96
- torch_dtype=dtype,
97
  token=HF_TOKEN
98
  )
99
- if device == "cuda":
100
- vae = vae.half().to(device)
101
 
102
- print("Loading scheduler...")
103
- scheduler = EulerDiscreteScheduler.from_pretrained(
104
- f"{ckpt_dir}/scheduler",
105
- token=HF_TOKEN
106
- )
107
 
108
- print("Loading UNet...")
109
  unet = UNet2DConditionModel.from_pretrained(
110
  f"{ckpt_dir}/unet",
111
- revision=None,
112
- torch_dtype=dtype,
113
  token=HF_TOKEN
114
  )
115
- if device == "cuda":
116
- unet = unet.half().to(device)
117
 
118
- # CLIP ๋ชจ๋ธ ๋กœ๋”ฉ - safetensors ์šฐ์„  ์‚ฌ์šฉ
119
- print("Loading CLIP model...")
120
  try:
121
- # ๋จผ์ € ๋กœ์ปฌ FaceID ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์‹œ๋„
122
- local_clip_path = f'{ckpt_dir_faceid}/clip-vit-large-patch14-336'
123
- if os.path.exists(local_clip_path):
124
- print(f"Trying to load CLIP from local: {local_clip_path}")
125
- clip_image_encoder = CLIPVisionModelWithProjection.from_pretrained(
126
- local_clip_path,
127
- torch_dtype=dtype,
128
- ignore_mismatched_sizes=True,
129
- token=HF_TOKEN,
130
- use_safetensors=True, # safetensors ์šฐ์„  ์‚ฌ์šฉ
131
- local_files_only=True
132
- )
133
- else:
134
- raise FileNotFoundError("Local CLIP not found")
135
- except Exception as e:
136
- print(f"Local loading failed: {e}")
137
- try:
138
- # OpenAI์—์„œ ์ง์ ‘ ๋‹ค์šด๋กœ๋“œ (safetensors ๋ฒ„์ „)
139
- print("Downloading CLIP from OpenAI...")
140
- clip_image_encoder = CLIPVisionModelWithProjection.from_pretrained(
141
- 'openai/clip-vit-large-patch14-336',
142
- torch_dtype=dtype,
143
- ignore_mismatched_sizes=True,
144
- token=HF_TOKEN,
145
- use_safetensors=True, # safetensors ์šฐ์„  ์‚ฌ์šฉ
146
- revision="main"
147
- )
148
- except Exception as e2:
149
- print(f"SafeTensors loading failed: {e2}")
150
- # ์ตœํ›„์˜ ์ˆ˜๋‹จ: pytorch_model.bin ์‚ฌ์šฉ
151
- print("Trying with pytorch format...")
152
- clip_image_encoder = CLIPVisionModelWithProjection.from_pretrained(
153
- 'openai/clip-vit-large-patch14-336',
154
- torch_dtype=dtype,
155
- ignore_mismatched_sizes=True,
156
- token=HF_TOKEN,
157
- use_safetensors=False
158
- )
159
 
160
- clip_image_encoder.to(device)
161
  clip_image_processor = CLIPImageProcessor(size=336, crop_size=336)
162
 
163
- print("Creating pipeline...")
164
  pipe = StableDiffusionXLPipeline(
165
  vae=vae,
166
  text_encoder=text_encoder,
@@ -172,12 +90,16 @@ pipe = StableDiffusionXLPipeline(
172
  force_zeros_for_empty_prompt=False,
173
  )
174
 
175
- print("Models loaded successfully!")
176
 
177
  class FaceInfoGenerator():
178
  def __init__(self, root_dir="./.insightface/"):
179
- providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if device == "cuda" else ['CPUExecutionProvider']
180
- self.app = FaceAnalysis(name='antelopev2', root=root_dir, providers=providers)
 
 
 
 
181
  self.app.prepare(ctx_id=0, det_size=(640, 640))
182
 
183
  def get_faceinfo_one_img(self, face_image):
@@ -185,34 +107,32 @@ class FaceInfoGenerator():
185
  return None
186
 
187
  face_info = self.app.get(cv2.cvtColor(np.array(face_image), cv2.COLOR_RGB2BGR))
188
-
189
  if len(face_info) == 0:
190
  return None
191
  else:
192
- # only use the maximum face
193
  face_info = sorted(face_info, key=lambda x:(x['bbox'][2]-x['bbox'][0])*(x['bbox'][3]-x['bbox'][1]))[-1]
194
  return face_info
195
 
196
  def face_bbox_to_square(bbox):
197
- ## l, t, r, b to square l, t, r, b
198
  l, t, r, b = bbox
199
  cent_x = (l + r) / 2
200
  cent_y = (t + b) / 2
201
  w, h = r - l, b - t
202
  r = max(w, h) / 2
203
-
204
  l0 = cent_x - r
205
  r0 = cent_x + r
206
  t0 = cent_y - r
207
  b0 = cent_y + r
208
-
209
  return [l0, t0, r0, b0]
210
 
211
  MAX_SEED = np.iinfo(np.int32).max
212
- MAX_IMAGE_SIZE = 1024
213
  face_info_generator = FaceInfoGenerator()
214
 
215
- @spaces.GPU(duration=60)
 
216
  def infer(prompt,
217
  image=None,
218
  negative_prompt="low quality, blurry, distorted",
@@ -225,44 +145,38 @@ def infer(prompt,
225
  gr.Warning("Please upload an image with a face.")
226
  return None, 0
227
 
228
- if randomize_seed:
229
- seed = random.randint(0, MAX_SEED)
 
 
230
 
231
- generator = torch.Generator(device=device).manual_seed(seed)
 
 
 
 
232
 
 
 
233
  global pipe
 
 
234
  pipe = pipe.to(device)
 
235
 
236
  # IP Adapter ๋กœ๋”ฉ
237
- try:
238
- pipe.load_ip_adapter_faceid_plus(f'{ckpt_dir_faceid}/ipa-faceid-plus.bin', device=device)
239
- scale = 0.8
240
- pipe.set_face_fidelity_scale(scale)
241
- except Exception as e:
242
- print(f"Error loading IP adapter: {e}")
243
- raise gr.Error(f"Failed to load face adapter: {str(e)}")
244
-
245
- # Face ์ •๋ณด ์ถ”์ถœ
246
- face_info = face_info_generator.get_faceinfo_one_img(image)
247
- if face_info is None:
248
- raise gr.Error("No face detected in the image. Please provide an image with a clear face.")
249
 
250
- try:
251
- face_bbox_square = face_bbox_to_square(face_info["bbox"])
252
- crop_image = image.crop(face_bbox_square)
253
- crop_image = crop_image.resize((336, 336))
254
- crop_image = [crop_image]
255
-
256
- face_embeds = torch.from_numpy(np.array([face_info["embedding"]]))
257
- face_embeds = face_embeds.to(device, dtype=dtype)
258
- except Exception as e:
259
- print(f"Error processing face: {e}")
260
- raise gr.Error(f"Failed to process face: {str(e)}")
261
-
262
  # ์ด๋ฏธ์ง€ ์ƒ์„ฑ
263
- try:
264
- with torch.no_grad():
265
- image = pipe(
266
  prompt=prompt,
267
  negative_prompt=negative_prompt,
268
  height=1024,
@@ -274,93 +188,68 @@ def infer(prompt,
274
  face_crop_image=crop_image,
275
  face_insightface_embeds=face_embeds
276
  ).images[0]
277
- except Exception as e:
278
- print(f"Error during inference: {e}")
279
- raise gr.Error(f"Failed to generate image: {str(e)}")
280
-
281
- return image, seed
282
 
283
  css = """
284
  footer {
285
  visibility: hidden;
286
  }
287
- .container {
288
- max-width: 1200px;
289
  margin: 0 auto;
290
- padding: 20px;
 
 
 
 
291
  }
292
  """
293
 
294
- # Gradio Interface
295
  with gr.Blocks(theme="soft", css=css) as Kolors:
296
  gr.HTML(
297
  """
298
- <div class='container' style='display:flex; justify-content:center; gap:12px;'>
299
- <a href="https://huggingface.co/spaces/openfree/Best-AI" target="_blank">
300
- <img src="https://img.shields.io/static/v1?label=OpenFree&message=BEST%20AI%20Services&color=%230000ff&labelColor=%23000080&logo=huggingface&logoColor=%23ffa500&style=for-the-badge" alt="OpenFree badge">
301
- </a>
302
-
303
- <a href="https://discord.gg/openfreeai" target="_blank">
304
- <img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=%230000ff&labelColor=%23800080&logo=discord&logoColor=white&style=for-the-badge" alt="Discord badge">
305
- </a>
 
 
 
306
  </div>
307
- <h1 style="text-align: center;">Kolors Face ID - AI Portrait Generator</h1>
308
- <p style="text-align: center;">Upload a face photo and create stunning AI portraits with text prompts!</p>
309
  """
310
  )
311
 
312
  with gr.Row():
313
  with gr.Column(elem_id="col-left"):
314
- with gr.Row():
315
- prompt = gr.Textbox(
316
- label="Prompt",
317
- placeholder="e.g., A professional portrait in business attire, studio lighting",
318
- lines=3,
319
- value="A professional portrait photo, high quality, detailed face"
320
- )
321
- with gr.Row():
322
- image = gr.Image(
323
- label="Upload Face Image",
324
- type="pil",
325
- height=400
326
- )
327
  with gr.Accordion("Advanced Settings", open=False):
328
  negative_prompt = gr.Textbox(
329
  label="Negative prompt",
330
- placeholder="Things to avoid in the image",
331
- value="low quality, blurry, distorted, disfigured",
332
- visible=True,
333
- )
334
- seed = gr.Slider(
335
- label="Seed",
336
- minimum=0,
337
- maximum=MAX_SEED,
338
- step=1,
339
- value=66,
340
  )
 
341
  randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
342
  with gr.Row():
343
- guidance_scale = gr.Slider(
344
- label="Guidance scale",
345
- minimum=0.0,
346
- maximum=10.0,
347
- step=0.1,
348
- value=5.0,
349
- )
350
- num_inference_steps = gr.Slider(
351
- label="Number of inference steps",
352
- minimum=10,
353
- maximum=50,
354
- step=1,
355
- value=25,
356
- )
357
- with gr.Row():
358
- button = gr.Button("๐ŸŽจ Generate Portrait", elem_id="button", variant="primary", scale=1)
359
 
360
  with gr.Column(elem_id="col-right"):
361
  result = gr.Image(label="Generated Portrait", show_label=True)
362
  seed_used = gr.Number(label="Seed Used", precision=0)
363
-
364
  button.click(
365
  fn=infer,
366
  inputs=[prompt, image, negative_prompt, seed, randomize_seed, guidance_scale, num_inference_steps],
@@ -368,4 +257,4 @@ with gr.Blocks(theme="soft", css=css) as Kolors:
368
  )
369
 
370
  if __name__ == "__main__":
371
- Kolors.queue(max_size=10).launch(debug=True, share=False)
 
6
  import gradio as gr
7
  import numpy as np
8
  import os
 
9
  from huggingface_hub import snapshot_download, login
10
  from transformers import CLIPVisionModelWithProjection, CLIPImageProcessor
11
  from kolors.pipelines.pipeline_stable_diffusion_xl_chatglm_256_ipadapter_FaceID import StableDiffusionXLPipeline
 
18
  from insightface.app import FaceAnalysis
19
  from insightface.data import get_image as ins_get_image
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  # Hugging Face ํ† ํฐ์œผ๋กœ ๋กœ๊ทธ์ธ
22
  HF_TOKEN = os.getenv("HF_TOKEN")
23
  if HF_TOKEN:
24
  login(token=HF_TOKEN)
25
  print("Successfully logged in to Hugging Face Hub")
 
 
 
 
 
 
 
 
 
26
 
27
+ # ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ (CPU์—์„œ)
28
+ print("Downloading models...")
29
+ ckpt_dir = snapshot_download(repo_id="Kwai-Kolors/Kolors", token=HF_TOKEN)
30
+ ckpt_dir_faceid = snapshot_download(repo_id="Kwai-Kolors/Kolors-IP-Adapter-FaceID-Plus", token=HF_TOKEN)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ # CPU์—์„œ ๋ชจ๋ธ ์ดˆ๊ธฐํ™”
33
+ print("Loading models on CPU first...")
34
  text_encoder = ChatGLMModel.from_pretrained(
35
  f'{ckpt_dir}/text_encoder',
36
+ torch_dtype=torch.float16,
37
  token=HF_TOKEN,
38
+ trust_remote_code=True,
39
+ device_map=None # CPU์—์„œ ๋จผ์ € ๋กœ๋“œ
40
  )
 
 
41
 
 
42
  tokenizer = ChatGLMTokenizer.from_pretrained(
43
  f'{ckpt_dir}/text_encoder',
44
  token=HF_TOKEN,
45
  trust_remote_code=True
46
  )
47
 
 
48
  vae = AutoencoderKL.from_pretrained(
49
  f"{ckpt_dir}/vae",
50
+ torch_dtype=torch.float16,
 
51
  token=HF_TOKEN
52
  )
 
 
53
 
54
+ scheduler = EulerDiscreteScheduler.from_pretrained(f"{ckpt_dir}/scheduler")
 
 
 
 
55
 
 
56
  unet = UNet2DConditionModel.from_pretrained(
57
  f"{ckpt_dir}/unet",
58
+ torch_dtype=torch.float16,
 
59
  token=HF_TOKEN
60
  )
 
 
61
 
62
+ # CLIP ๋ชจ๋ธ ๋กœ๋”ฉ
 
63
  try:
64
+ clip_image_encoder = CLIPVisionModelWithProjection.from_pretrained(
65
+ 'openai/clip-vit-large-patch14-336',
66
+ torch_dtype=torch.float16,
67
+ ignore_mismatched_sizes=True,
68
+ token=HF_TOKEN,
69
+ use_safetensors=True
70
+ )
71
+ except:
72
+ clip_image_encoder = CLIPVisionModelWithProjection.from_pretrained(
73
+ 'openai/clip-vit-large-patch14-336',
74
+ torch_dtype=torch.float16,
75
+ ignore_mismatched_sizes=True,
76
+ token=HF_TOKEN
77
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
 
79
  clip_image_processor = CLIPImageProcessor(size=336, crop_size=336)
80
 
81
+ # Pipeline ์ƒ์„ฑ (CPU์—์„œ)
82
  pipe = StableDiffusionXLPipeline(
83
  vae=vae,
84
  text_encoder=text_encoder,
 
90
  force_zeros_for_empty_prompt=False,
91
  )
92
 
93
+ print("Models loaded on CPU successfully!")
94
 
95
  class FaceInfoGenerator():
96
  def __init__(self, root_dir="./.insightface/"):
97
+ # CPU๋งŒ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค์ •
98
+ self.app = FaceAnalysis(
99
+ name='antelopev2',
100
+ root=root_dir,
101
+ providers=['CPUExecutionProvider'] # CPU๋งŒ ์‚ฌ์šฉ
102
+ )
103
  self.app.prepare(ctx_id=0, det_size=(640, 640))
104
 
105
  def get_faceinfo_one_img(self, face_image):
 
107
  return None
108
 
109
  face_info = self.app.get(cv2.cvtColor(np.array(face_image), cv2.COLOR_RGB2BGR))
110
+
111
  if len(face_info) == 0:
112
  return None
113
  else:
 
114
  face_info = sorted(face_info, key=lambda x:(x['bbox'][2]-x['bbox'][0])*(x['bbox'][3]-x['bbox'][1]))[-1]
115
  return face_info
116
 
117
  def face_bbox_to_square(bbox):
 
118
  l, t, r, b = bbox
119
  cent_x = (l + r) / 2
120
  cent_y = (t + b) / 2
121
  w, h = r - l, b - t
122
  r = max(w, h) / 2
123
+
124
  l0 = cent_x - r
125
  r0 = cent_x + r
126
  t0 = cent_y - r
127
  b0 = cent_y + r
128
+
129
  return [l0, t0, r0, b0]
130
 
131
  MAX_SEED = np.iinfo(np.int32).max
 
132
  face_info_generator = FaceInfoGenerator()
133
 
134
+ # GPU ํ•จ์ˆ˜๋Š” @spaces.GPU ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋‚ด์—์„œ๋งŒ GPU ์‚ฌ์šฉ
135
+ @spaces.GPU(duration=120) # GPU ์‹œ๊ฐ„ ๋Š˜๋ฆผ
136
  def infer(prompt,
137
  image=None,
138
  negative_prompt="low quality, blurry, distorted",
 
145
  gr.Warning("Please upload an image with a face.")
146
  return None, 0
147
 
148
+ # Face detection (CPU์—์„œ)
149
+ face_info = face_info_generator.get_faceinfo_one_img(image)
150
+ if face_info is None:
151
+ raise gr.Error("No face detected in the image. Please provide an image with a clear face.")
152
 
153
+ face_bbox_square = face_bbox_to_square(face_info["bbox"])
154
+ crop_image = image.crop(face_bbox_square)
155
+ crop_image = crop_image.resize((336, 336))
156
+ crop_image = [crop_image]
157
+ face_embeds = torch.from_numpy(np.array([face_info["embedding"]]))
158
 
159
+ # GPU๋กœ ์ด๋™ (spaces.GPU ๋‚ด์—์„œ๋งŒ)
160
+ device = "cuda"
161
  global pipe
162
+
163
+ # ๋ชจ๋ธ์„ GPU๋กœ ์ด๋™
164
  pipe = pipe.to(device)
165
+ face_embeds = face_embeds.to(device, dtype=torch.float16)
166
 
167
  # IP Adapter ๋กœ๋”ฉ
168
+ pipe.load_ip_adapter_faceid_plus(f'{ckpt_dir_faceid}/ipa-faceid-plus.bin', device=device)
169
+ pipe.set_face_fidelity_scale(0.8)
170
+
171
+ if randomize_seed:
172
+ seed = random.randint(0, MAX_SEED)
173
+
174
+ generator = torch.Generator(device=device).manual_seed(seed)
 
 
 
 
 
175
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  # ์ด๋ฏธ์ง€ ์ƒ์„ฑ
177
+ with torch.no_grad():
178
+ with torch.autocast(device):
179
+ result = pipe(
180
  prompt=prompt,
181
  negative_prompt=negative_prompt,
182
  height=1024,
 
188
  face_crop_image=crop_image,
189
  face_insightface_embeds=face_embeds
190
  ).images[0]
191
+
192
+ return result, seed
 
 
 
193
 
194
  css = """
195
  footer {
196
  visibility: hidden;
197
  }
198
+ #col-left {
 
199
  margin: 0 auto;
200
+ max-width: 640px;
201
+ }
202
+ #col-right {
203
+ margin: 0 auto;
204
+ max-width: 640px;
205
  }
206
  """
207
 
 
208
  with gr.Blocks(theme="soft", css=css) as Kolors:
209
  gr.HTML(
210
  """
211
+ <div style='text-align: center;'>
212
+ <h1>๐ŸŽจ Kolors Face ID - AI Portrait Generator</h1>
213
+ <p>Upload a face photo and create stunning AI portraits with text prompts!</p>
214
+ <div style='display:flex; justify-content:center; gap:12px; margin-top:20px;'>
215
+ <a href="https://huggingface.co/spaces/openfree/Best-AI" target="_blank">
216
+ <img src="https://img.shields.io/static/v1?label=OpenFree&message=BEST%20AI%20Services&color=%230000ff&labelColor=%23000080&logo=huggingface&logoColor=%23ffa500&style=for-the-badge" alt="OpenFree badge">
217
+ </a>
218
+ <a href="https://discord.gg/openfreeai" target="_blank">
219
+ <img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=%230000ff&labelColor=%23800080&logo=discord&logoColor=white&style=for-the-badge" alt="Discord badge">
220
+ </a>
221
+ </div>
222
  </div>
 
 
223
  """
224
  )
225
 
226
  with gr.Row():
227
  with gr.Column(elem_id="col-left"):
228
+ prompt = gr.Textbox(
229
+ label="Prompt",
230
+ placeholder="e.g., A professional portrait in business attire, studio lighting",
231
+ lines=3,
232
+ value="A professional portrait photo, high quality, detailed face"
233
+ )
234
+ image = gr.Image(label="Upload Face Image", type="pil", height=400)
235
+
 
 
 
 
 
236
  with gr.Accordion("Advanced Settings", open=False):
237
  negative_prompt = gr.Textbox(
238
  label="Negative prompt",
239
+ value="low quality, blurry, distorted, disfigured"
 
 
 
 
 
 
 
 
 
240
  )
241
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=66)
242
  randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
243
  with gr.Row():
244
+ guidance_scale = gr.Slider(label="Guidance scale", minimum=0.0, maximum=10.0, step=0.1, value=5.0)
245
+ num_inference_steps = gr.Slider(label="Inference steps", minimum=10, maximum=50, step=1, value=25)
246
+
247
+ button = gr.Button("๐ŸŽจ Generate Portrait", variant="primary", scale=1)
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
  with gr.Column(elem_id="col-right"):
250
  result = gr.Image(label="Generated Portrait", show_label=True)
251
  seed_used = gr.Number(label="Seed Used", precision=0)
252
+
253
  button.click(
254
  fn=infer,
255
  inputs=[prompt, image, negative_prompt, seed, randomize_seed, guidance_scale, num_inference_steps],
 
257
  )
258
 
259
  if __name__ == "__main__":
260
+ Kolors.queue(max_size=20).launch(debug=True)