Nad54 commited on
Commit
ad5043a
·
verified ·
1 Parent(s): 1d343f6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +24 -11
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py — InstantID SDXL (robuste: OMP + InsightFace fallback + downloads sûrs)
2
 
3
  # 0) Environnement AVANT TOUT IMPORT
4
  import os, sys
@@ -19,7 +19,7 @@ DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
19
  DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32
20
 
21
  # 2) Chemins & Hub
22
- ASSETS_REPO = "InstantX/InstantID"
23
  CHECKPOINTS_DIR = "./checkpoints"
24
  CN_LOCAL_DIR = os.path.join(CHECKPOINTS_DIR, "ControlNetModel")
25
  IP_ADAPTER_LOCAL = os.path.join(CHECKPOINTS_DIR, "ip-adapter.bin")
@@ -52,11 +52,13 @@ def ensure_assets_or_download():
52
  safe_download(ASSETS_REPO, "ControlNetModel/diffusion_pytorch_model.safetensors", CHECKPOINTS_DIR, 100_000_000, "IdentityNet weights")
53
  safe_download(ASSETS_REPO, "ip-adapter.bin", CHECKPOINTS_DIR, 100_000_000, "ip-adapter")
54
 
55
- # 4) Import dynamique de la pipeline InstantID
56
  def import_pipeline_or_fail():
57
  pipeline_file = "./instantid/pipeline_stable_diffusion_xl_instantid.py"
58
  if not os.path.exists(pipeline_file):
59
  raise RuntimeError("❌ Fichier pipeline manquant : ./instantid/pipeline_stable_diffusion_xl_instantid.py")
 
 
60
  spec = importlib.util.spec_from_file_location("instantid_pipeline", pipeline_file)
61
  mod = importlib.util.module_from_spec(spec)
62
  spec.loader.exec_module(mod)
@@ -64,7 +66,8 @@ def import_pipeline_or_fail():
64
  if isinstance(obj, type) and "InstantID" in name and hasattr(obj, "from_pretrained"):
65
  print(f"✅ Pipeline trouvée : {name}")
66
  return obj
67
- raise RuntimeError("❌ Aucune classe pipeline InstantID trouvée dans la pipeline.")
 
68
 
69
  # 5) draw_kps local (remplace la dépendance au draw_kps du fichier)
70
  def draw_kps_local(img_pil, kps):
@@ -76,7 +79,7 @@ def draw_kps_local(img_pil, kps):
76
  d.ellipse((x - r, y - r, x + r, y + r), fill="black")
77
  return out
78
 
79
- # 6) Chargement pipeline
80
  load_logs = []
81
  try:
82
  SDXLInstantID = import_pipeline_or_fail()
@@ -86,9 +89,11 @@ try:
86
  load_logs.append(f"Chargement base: {BASE_MODEL}")
87
 
88
  controlnet_identitynet = ControlNetModel.from_pretrained(CN_LOCAL_DIR, torch_dtype=DTYPE)
 
 
89
  pipe = SDXLInstantID.from_pretrained(
90
  BASE_MODEL,
91
- controlnet=[controlnet_identitynet],
92
  torch_dtype=DTYPE,
93
  safety_checker=None,
94
  feature_extractor=None,
@@ -140,13 +145,19 @@ def generate(face_image, prompt, negative_prompt, identity_strength, adapter_str
140
  try:
141
  if face_image is None:
142
  return None, "Merci d'ajouter une photo visage.", "\n".join(load_logs)
 
143
  gen = None if seed is None or int(seed) < 0 else torch.Generator(device=DEVICE).manual_seed(int(seed))
 
144
  face = ImageOps.exif_transpose(face_image).convert("RGB")
145
  ms = min(face.size); x=(face.width-ms)//2; y=(face.height-ms)//2
146
  face_sq = face.crop((x, y, x+ms, y+ms)).resize((512,512), Image.Resampling.LANCZOS)
 
147
  kps_img = extract_kps_image(face_sq)
 
148
  if hasattr(pipe, "set_ip_adapter_scale"):
149
  pipe.set_ip_adapter_scale(float(adapter_strength))
 
 
150
  images = pipe(
151
  prompt=prompt.strip(),
152
  negative_prompt=(negative_prompt or "").strip(),
@@ -158,7 +169,9 @@ def generate(face_image, prompt, negative_prompt, identity_strength, adapter_str
158
  height=int(height),
159
  generator=gen,
160
  ).images
 
161
  return images[0], "", "\n".join(load_logs)
 
162
  except torch.cuda.OutOfMemoryError as oom:
163
  return None, "CUDA OOM: baisse la résolution/steps.", "\n".join(load_logs)
164
  except Exception:
@@ -176,15 +189,15 @@ EX_NEG = (
176
  )
177
 
178
  with gr.Blocks(css="footer{display:none !important}") as demo:
179
- gr.Markdown("# 🏴‍☠️ One Piece – InstantID SDXL (robuste)")
180
 
181
  with gr.Row():
182
  with gr.Column():
183
  face_image = gr.Image(type="pil", label="Photo visage", height=360)
184
- prompt = gr.Textbox(label="Prompt", value=EX_PROMPT)
185
- negative = gr.Textbox(label="Negative Prompt", value=EX_NEG)
186
- identity_strength = gr.Slider(0.2, 1.5, 0.95, 0.05, label="Fidélité visage")
187
- adapter_strength = gr.Slider(0.2, 1.5, 0.85, 0.05, label="Détails anime")
188
  steps = gr.Slider(10, 60, 30, 1, label="Steps")
189
  cfg = gr.Slider(0.1, 12.0, 5.5, 0.1, label="CFG")
190
  width = gr.Dropdown(choices=[576, 640, 704, 768, 896], value=704, label="Largeur")
 
1
+ # app.py — InstantID SDXL (stable) : ControlNet objet unique, téléchargements sûrs, InsightFace fallback
2
 
3
  # 0) Environnement AVANT TOUT IMPORT
4
  import os, sys
 
19
  DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32
20
 
21
  # 2) Chemins & Hub
22
+ ASSETS_REPO = "InstantX/InstantID" # repo Model public qui contient les poids
23
  CHECKPOINTS_DIR = "./checkpoints"
24
  CN_LOCAL_DIR = os.path.join(CHECKPOINTS_DIR, "ControlNetModel")
25
  IP_ADAPTER_LOCAL = os.path.join(CHECKPOINTS_DIR, "ip-adapter.bin")
 
52
  safe_download(ASSETS_REPO, "ControlNetModel/diffusion_pytorch_model.safetensors", CHECKPOINTS_DIR, 100_000_000, "IdentityNet weights")
53
  safe_download(ASSETS_REPO, "ip-adapter.bin", CHECKPOINTS_DIR, 100_000_000, "ip-adapter")
54
 
55
+ # 4) Import dynamique de la pipeline InstantID (fichier texte local)
56
  def import_pipeline_or_fail():
57
  pipeline_file = "./instantid/pipeline_stable_diffusion_xl_instantid.py"
58
  if not os.path.exists(pipeline_file):
59
  raise RuntimeError("❌ Fichier pipeline manquant : ./instantid/pipeline_stable_diffusion_xl_instantid.py")
60
+ if os.path.getsize(pipeline_file) < 1024:
61
+ raise RuntimeError("❌ Fichier pipeline trop petit (vide ?). Colle le contenu depuis GitHub InstantID.")
62
  spec = importlib.util.spec_from_file_location("instantid_pipeline", pipeline_file)
63
  mod = importlib.util.module_from_spec(spec)
64
  spec.loader.exec_module(mod)
 
66
  if isinstance(obj, type) and "InstantID" in name and hasattr(obj, "from_pretrained"):
67
  print(f"✅ Pipeline trouvée : {name}")
68
  return obj
69
+ avail = [n for n, o in vars(mod).items() if isinstance(o, type)]
70
+ raise RuntimeError("❌ Aucune classe pipeline InstantID trouvée. Classes dispo: " + ", ".join(avail))
71
 
72
  # 5) draw_kps local (remplace la dépendance au draw_kps du fichier)
73
  def draw_kps_local(img_pil, kps):
 
79
  d.ellipse((x - r, y - r, x + r, y + r), fill="black")
80
  return out
81
 
82
+ # 6) Chargement pipeline (ControlNet en OBJET, pas liste)
83
  load_logs = []
84
  try:
85
  SDXLInstantID = import_pipeline_or_fail()
 
89
  load_logs.append(f"Chargement base: {BASE_MODEL}")
90
 
91
  controlnet_identitynet = ControlNetModel.from_pretrained(CN_LOCAL_DIR, torch_dtype=DTYPE)
92
+
93
+ # 🔧 Ici: controlnet=controlnet_identitynet (objet unique)
94
  pipe = SDXLInstantID.from_pretrained(
95
  BASE_MODEL,
96
+ controlnet=controlnet_identitynet,
97
  torch_dtype=DTYPE,
98
  safety_checker=None,
99
  feature_extractor=None,
 
145
  try:
146
  if face_image is None:
147
  return None, "Merci d'ajouter une photo visage.", "\n".join(load_logs)
148
+
149
  gen = None if seed is None or int(seed) < 0 else torch.Generator(device=DEVICE).manual_seed(int(seed))
150
+
151
  face = ImageOps.exif_transpose(face_image).convert("RGB")
152
  ms = min(face.size); x=(face.width-ms)//2; y=(face.height-ms)//2
153
  face_sq = face.crop((x, y, x+ms, y+ms)).resize((512,512), Image.Resampling.LANCZOS)
154
+
155
  kps_img = extract_kps_image(face_sq)
156
+
157
  if hasattr(pipe, "set_ip_adapter_scale"):
158
  pipe.set_ip_adapter_scale(float(adapter_strength))
159
+
160
+ # Ici, controlnet est un objet unique → image et scale ne sont PAS en liste
161
  images = pipe(
162
  prompt=prompt.strip(),
163
  negative_prompt=(negative_prompt or "").strip(),
 
169
  height=int(height),
170
  generator=gen,
171
  ).images
172
+
173
  return images[0], "", "\n".join(load_logs)
174
+
175
  except torch.cuda.OutOfMemoryError as oom:
176
  return None, "CUDA OOM: baisse la résolution/steps.", "\n".join(load_logs)
177
  except Exception:
 
189
  )
190
 
191
  with gr.Blocks(css="footer{display:none !important}") as demo:
192
+ gr.Markdown("# 🏴‍☠️ One Piece – InstantID SDXL (stable)")
193
 
194
  with gr.Row():
195
  with gr.Column():
196
  face_image = gr.Image(type="pil", label="Photo visage", height=360)
197
+ prompt = gr.Textbox(label="Prompt", value=EX_PROMPT, lines=3)
198
+ negative = gr.Textbox(label="Negative Prompt", value=EX_NEG, lines=3)
199
+ identity_strength = gr.Slider(0.2, 1.5, 0.95, 0.05, label="Fidélité visage (IdentityNet)")
200
+ adapter_strength = gr.Slider(0.2, 1.5, 0.85, 0.05, label="Détails anime (Adapter)")
201
  steps = gr.Slider(10, 60, 30, 1, label="Steps")
202
  cfg = gr.Slider(0.1, 12.0, 5.5, 0.1, label="CFG")
203
  width = gr.Dropdown(choices=[576, 640, 704, 768, 896], value=704, label="Largeur")