Leteint commited on
Commit
2fd0b9a
·
verified ·
1 Parent(s): 71113c4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -42
app.py CHANGED
@@ -11,9 +11,6 @@ from huggingface_hub import hf_hub_download
11
  from diffusers.models import ControlNetModel
12
  from insightface.app import FaceAnalysis
13
 
14
- # IMPORTANT :
15
- # Assure-toi d'avoir `pipeline_stable_diffusion_xl_instantid.py`
16
- # dans le même dossier, contenant la classe StableDiffusionXLInstantIDPipeline
17
  from pipeline_stable_diffusion_xl_instantid import StableDiffusionXLInstantIDPipeline
18
 
19
 
@@ -29,30 +26,24 @@ CHECKPOINT_DIR = "./checkpoints"
29
 
30
 
31
  # ---------------------------
32
- # Téléchargement des poids InstantID depuis le Hub
33
  # ---------------------------
34
 
35
  def download_checkpoints():
36
- # ControlNet (IdentityNet)
37
  hf_hub_download(
38
  repo_id="InstantX/InstantID",
39
  filename="ControlNetModel/config.json",
40
  local_dir=CHECKPOINT_DIR,
41
- local_dir_use_symlinks=False,
42
  )
43
  hf_hub_download(
44
  repo_id="InstantX/InstantID",
45
  filename="ControlNetModel/diffusion_pytorch_model.safetensors",
46
  local_dir=CHECKPOINT_DIR,
47
- local_dir_use_symlinks=False,
48
  )
49
-
50
- # IP-Adapter / InstantID adapter
51
  hf_hub_download(
52
  repo_id="InstantX/InstantID",
53
  filename="ip-adapter.bin",
54
  local_dir=CHECKPOINT_DIR,
55
- local_dir_use_symlinks=False,
56
  )
57
 
58
 
@@ -63,12 +54,12 @@ IP_ADAPTER_PATH = f"{CHECKPOINT_DIR}/ip-adapter.bin"
63
 
64
 
65
  # ---------------------------
66
- # InsightFace pour l'ID de visage
67
  # ---------------------------
68
 
69
  def setup_face_analyzer():
70
  app = FaceAnalysis(name="buffalo_l")
71
- app.prepare(ctx_id=0 if DEVICE == "cuda" else -1)
72
  return app
73
 
74
 
@@ -76,16 +67,18 @@ face_app = setup_face_analyzer()
76
 
77
 
78
  def extract_face_emb(image: Image.Image):
79
- # Insightface attend du BGR numpy
80
  img = np.array(image.convert("RGB"))
81
  img_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
82
 
83
  faces = face_app.get(img_bgr)
84
  if len(faces) == 0:
85
- raise RuntimeError("Aucun visage détecté sur l'image d'entrée.")
86
 
87
- # On prend le plus grand visage
88
- face = sorted(faces, key=lambda f: (f.bbox[2] - f.bbox[0]) * (f.bbox[3] - f.bbox[1]), reverse=True)[0]
 
 
 
89
  face_emb = face.normed_embedding
90
  return np.array(face_emb, dtype=np.float32)
91
 
@@ -95,13 +88,11 @@ def extract_face_emb(image: Image.Image):
95
  # ---------------------------
96
 
97
  def load_pipeline():
98
- # 1) ControlNet
99
  controlnet = ControlNetModel.from_pretrained(
100
  CONTROLNET_PATH,
101
  torch_dtype=DTYPE,
102
  )
103
 
104
- # 2) Pipeline InstantID (custom) basé sur SDXL
105
  pipe = StableDiffusionXLInstantIDPipeline.from_pretrained(
106
  BASE_MODEL_ID,
107
  controlnet=controlnet,
@@ -111,10 +102,7 @@ def load_pipeline():
111
  if DEVICE == "cuda":
112
  pipe.to("cuda")
113
 
114
- # 3) Charger l'adapter InstantID (IP-Adapter-like)
115
  pipe.load_ip_adapter_instantid(IP_ADAPTER_PATH)
116
-
117
- # Réglage de l'influence de l'adapter (ID strength)
118
  pipe.set_ip_adapter_scale(0.8)
119
 
120
  return pipe
@@ -128,39 +116,40 @@ pipe = load_pipeline()
128
  # ---------------------------
129
 
130
  @spaces.GPU
131
- def generate(image, prompt, negative_prompt="", steps=20, strength=0.45, guidance_scale=1.0):
 
 
 
 
 
132
  try:
 
 
 
 
 
133
  # Device
134
  if DEVICE == "cuda":
135
  pipe.to("cuda")
136
  else:
137
  pipe.to("cpu")
138
 
139
- # 1) Embedding de visage via insightface
140
- face_emb = extract_face_emb(image) # shape (512,)
141
- face_emb_batch = face_emb[None] # shape (1, 512)
142
 
143
- # 2) Embeddings d'image pour InstantID
144
- # Dans ton pipeline (paste.txt), tu as une méthode encode_image(...)
145
- # qui renvoie (image_embeds, negative_image_embeds).
146
- image_embeds, negative_image_embeds = pipe.encode_image(image)
147
-
148
- # 3) Appel du pipeline InstantID SDXL
149
  out = pipe(
150
  prompt=prompt,
151
  negative_prompt=negative_prompt,
152
- image=image, # img2img input
153
- image_embeds=image_embeds, # embeddings image positifs
154
- negative_image_embeds=negative_image_embeds, # embeddings image négatifs
155
- face_embeds=face_emb_batch, # embedding identité
156
  num_inference_steps=int(steps),
157
  strength=float(strength),
158
  guidance_scale=float(guidance_scale),
159
-
160
  )
161
 
162
-
163
-
164
  return out.images[0]
165
 
166
  except Exception as e:
@@ -168,16 +157,18 @@ def generate(image, prompt, negative_prompt="", steps=20, strength=0.45, guidanc
168
  traceback.print_exc()
169
  raise gr.Error(str(e))
170
 
 
171
  # ---------------------------
172
  # UI Gradio
173
  # ---------------------------
174
 
175
  with gr.Blocks() as demo:
176
- gr.Markdown("## Face Swap (InstantID + SDXL, ZeroGPU)")
177
 
178
  with gr.Row():
179
  with gr.Column():
180
- input_img = gr.Image(type="pil", label="Upload Face Photo")
 
181
 
182
  prompt = gr.Textbox(
183
  label="Prompt",
@@ -191,7 +182,7 @@ with gr.Blocks() as demo:
191
  )
192
 
193
  steps = gr.Slider(5, 40, 20, step=1, label="Steps")
194
- strength = gr.Slider(0.2, 0.9, 0.45, step=0.05, label="Strength (img2img / modification)")
195
  guidance = gr.Slider(0.0, 3.0, 1.0, step=0.1, label="Guidance scale (InstantID, rester bas)")
196
 
197
  btn = gr.Button("Generate")
@@ -201,7 +192,7 @@ with gr.Blocks() as demo:
201
 
202
  btn.click(
203
  generate,
204
- [input_img, prompt, neg_prompt, steps, strength, guidance],
205
  output,
206
  )
207
 
 
11
  from diffusers.models import ControlNetModel
12
  from insightface.app import FaceAnalysis
13
 
 
 
 
14
  from pipeline_stable_diffusion_xl_instantid import StableDiffusionXLInstantIDPipeline
15
 
16
 
 
26
 
27
 
28
  # ---------------------------
29
+ # Téléchargement des poids InstantID
30
  # ---------------------------
31
 
32
  def download_checkpoints():
 
33
  hf_hub_download(
34
  repo_id="InstantX/InstantID",
35
  filename="ControlNetModel/config.json",
36
  local_dir=CHECKPOINT_DIR,
 
37
  )
38
  hf_hub_download(
39
  repo_id="InstantX/InstantID",
40
  filename="ControlNetModel/diffusion_pytorch_model.safetensors",
41
  local_dir=CHECKPOINT_DIR,
 
42
  )
 
 
43
  hf_hub_download(
44
  repo_id="InstantX/InstantID",
45
  filename="ip-adapter.bin",
46
  local_dir=CHECKPOINT_DIR,
 
47
  )
48
 
49
 
 
54
 
55
 
56
  # ---------------------------
57
+ # InsightFace (CPU pour éviter les galères GPU dans ZeroGPU)
58
  # ---------------------------
59
 
60
  def setup_face_analyzer():
61
  app = FaceAnalysis(name="buffalo_l")
62
+ app.prepare(ctx_id=-1) # CPU
63
  return app
64
 
65
 
 
67
 
68
 
69
  def extract_face_emb(image: Image.Image):
 
70
  img = np.array(image.convert("RGB"))
71
  img_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
72
 
73
  faces = face_app.get(img_bgr)
74
  if len(faces) == 0:
75
+ raise RuntimeError("Aucun visage détecté sur l'image de référence.")
76
 
77
+ face = sorted(
78
+ faces,
79
+ key=lambda f: (f.bbox[2] - f.bbox[0]) * (f.bbox[3] - f.bbox[1]),
80
+ reverse=True,
81
+ )[0]
82
  face_emb = face.normed_embedding
83
  return np.array(face_emb, dtype=np.float32)
84
 
 
88
  # ---------------------------
89
 
90
  def load_pipeline():
 
91
  controlnet = ControlNetModel.from_pretrained(
92
  CONTROLNET_PATH,
93
  torch_dtype=DTYPE,
94
  )
95
 
 
96
  pipe = StableDiffusionXLInstantIDPipeline.from_pretrained(
97
  BASE_MODEL_ID,
98
  controlnet=controlnet,
 
102
  if DEVICE == "cuda":
103
  pipe.to("cuda")
104
 
 
105
  pipe.load_ip_adapter_instantid(IP_ADAPTER_PATH)
 
 
106
  pipe.set_ip_adapter_scale(0.8)
107
 
108
  return pipe
 
116
  # ---------------------------
117
 
118
  @spaces.GPU
119
+ def generate(face_image, body_image, prompt, negative_prompt="", steps=20, strength=0.45, guidance_scale=1.0):
120
+ """
121
+ face_image : image pour l'identité (visage)
122
+ body_image : image pour la pose/corps (img2img de base)
123
+ """
124
+
125
  try:
126
+ if face_image is None:
127
+ raise RuntimeError("Merci de fournir une image de visage.")
128
+ if body_image is None:
129
+ raise RuntimeError("Merci de fournir une image de corps/pose.")
130
+
131
  # Device
132
  if DEVICE == "cuda":
133
  pipe.to("cuda")
134
  else:
135
  pipe.to("cpu")
136
 
137
+ # 1) Embedding de visage (ID) depuis face_image
138
+ face_emb = extract_face_emb(face_image) # (512,)
139
+ face_emb_batch = face_emb[None] # (1, 512)
140
 
141
+ # 2) Appel du pipeline InstantID SDXL
142
+ # body_image sert d'input img2img (corps/pose), le prompt décrit la tenue / contexte.
 
 
 
 
143
  out = pipe(
144
  prompt=prompt,
145
  negative_prompt=negative_prompt,
146
+ image=body_image, # image de base (corps/pose)
147
+ face_embeds=face_emb_batch, # identité venant de face_image
 
 
148
  num_inference_steps=int(steps),
149
  strength=float(strength),
150
  guidance_scale=float(guidance_scale),
 
151
  )
152
 
 
 
153
  return out.images[0]
154
 
155
  except Exception as e:
 
157
  traceback.print_exc()
158
  raise gr.Error(str(e))
159
 
160
+
161
  # ---------------------------
162
  # UI Gradio
163
  # ---------------------------
164
 
165
  with gr.Blocks() as demo:
166
+ gr.Markdown("## InstantID + SDXL (ZeroGPU) – Visage A sur Corps B")
167
 
168
  with gr.Row():
169
  with gr.Column():
170
+ face_img = gr.Image(type="pil", label="Image visage (référence ID)")
171
+ body_img = gr.Image(type="pil", label="Image corps/pose (img2img)")
172
 
173
  prompt = gr.Textbox(
174
  label="Prompt",
 
182
  )
183
 
184
  steps = gr.Slider(5, 40, 20, step=1, label="Steps")
185
+ strength = gr.Slider(0.2, 0.9, 0.45, step=0.05, label="Strength (img2img)")
186
  guidance = gr.Slider(0.0, 3.0, 1.0, step=0.1, label="Guidance scale (InstantID, rester bas)")
187
 
188
  btn = gr.Button("Generate")
 
192
 
193
  btn.click(
194
  generate,
195
+ [face_img, body_img, prompt, neg_prompt, steps, strength, guidance],
196
  output,
197
  )
198