fix(assets): le test de reproductibilité ne vidait pas le cache ComfyUI
Correction d'une preuve qui n'en était pas une. Ma vérification lançait le même plan deux fois et comparait les empreintes. Le porteur ayant indiqué où ComfyUI écrit ses images, le dossier a pu être inspecté : UN SEUL fichier y figurait alors que deux exécutions avaient été lancées. ComfyUI met en cache le résultat d'un graphe identique. La « deuxième exécution » n'avait rien recalculé — elle avait relu la première. Comparer deux empreintes dans ces conditions ne mesure que le cache. Après POST /free, une exécution authentique produit decor_00002_.png, bit-identique au premier. La conclusion était juste, la méthode ne l'était pas. Le test devient un mode de l'outil plutôt qu'une manipulation : --reproductibilite génère, vide le cache, régénère et compare. Un test de reproductibilité qui ne vide pas le cache se ment à lui-même. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,29 @@ def empreinte(chemin: Path) -> str:
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def vider_cache(serveur: str) -> None:
|
||||
"""
|
||||
Vide le cache d'exécution de ComfyUI.
|
||||
|
||||
INDISPENSABLE avant tout test de reproductibilité. ComfyUI met en cache le résultat
|
||||
d'un graphe identique : relancer le même workflow ne recalcule rien et renvoie la
|
||||
sortie précédente. Comparer deux « exécutions » sans vider le cache ne prouve donc
|
||||
rien du tout — seulement que le cache fonctionne.
|
||||
|
||||
Constaté en session 3 : la deuxième exécution n'avait écrit aucun fichier dans le
|
||||
dossier de sortie de ComfyUI. Le hasard a voulu que la conclusion soit juste ; la
|
||||
méthode, elle, était fausse.
|
||||
"""
|
||||
corps = json.dumps({"unload_models": True, "free_memory": True}).encode("utf-8")
|
||||
requete = urllib.request.Request(
|
||||
urllib.parse.urljoin(serveur, "/free"),
|
||||
data=corps,
|
||||
headers={"Content-Type": "application/json"},
|
||||
)
|
||||
with urllib.request.urlopen(requete, timeout=30):
|
||||
pass
|
||||
|
||||
|
||||
def poster(serveur: str, workflow: dict, client_id: str) -> str:
|
||||
"""Envoie un workflow à ComfyUI et renvoie l'identifiant de la tâche."""
|
||||
corps = json.dumps({"prompt": workflow, "client_id": client_id}).encode("utf-8")
|
||||
@@ -190,6 +213,41 @@ def generer(args: argparse.Namespace) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def reproductibilite(args: argparse.Namespace) -> int:
|
||||
"""
|
||||
Test de reproductibilité RÉEL : génère, vide le cache, régénère, compare.
|
||||
|
||||
Sans le vidage intermédiaire, ce test ne mesure que le cache de ComfyUI.
|
||||
"""
|
||||
args_gen = argparse.Namespace(**vars(args))
|
||||
args_gen.sec = False
|
||||
|
||||
print("— première génération")
|
||||
generer(args_gen)
|
||||
premier = json.loads((SORTIE / "manifeste.json").read_text(encoding="utf-8"))
|
||||
|
||||
print("\n— vidage du cache d'exécution")
|
||||
vider_cache(args.serveur)
|
||||
|
||||
print("\n— seconde génération, cache vidé")
|
||||
generer(args_gen)
|
||||
second = json.loads((SORTIE / "manifeste.json").read_text(encoding="utf-8"))
|
||||
|
||||
identiques = True
|
||||
print()
|
||||
for a, b in zip(premier, second):
|
||||
egal = a["sha256"] == b["sha256"]
|
||||
identiques &= egal
|
||||
print(f"{'✔' if egal else '✘'} {a['cle']} — seed {a['seed']} — {a['sha256'][:24]}")
|
||||
|
||||
print(
|
||||
"\n✔ Sorties bit-identiques après vidage du cache : la reproductibilité est réelle."
|
||||
if identiques
|
||||
else "\n✘ Sorties divergentes : la reproductibilité n'est PAS acquise."
|
||||
)
|
||||
return 0 if identiques else 1
|
||||
|
||||
|
||||
def verifier(_args: argparse.Namespace) -> int:
|
||||
"""
|
||||
Contrôle que les seeds sont bien déterministes.
|
||||
@@ -218,10 +276,19 @@ def main() -> int:
|
||||
parseur.add_argument("--serveur", default=COMFY_DEFAUT)
|
||||
parseur.add_argument("--sec", action="store_true", help="calcule les seeds sans appeler ComfyUI")
|
||||
parseur.add_argument("--verifier", action="store_true", help="teste le déterminisme des seeds")
|
||||
parseur.add_argument(
|
||||
"--reproductibilite",
|
||||
action="store_true",
|
||||
help="génère deux fois en vidant le cache entre les deux, et compare les empreintes",
|
||||
)
|
||||
args = parseur.parse_args()
|
||||
|
||||
if args.verifier:
|
||||
return verifier(args)
|
||||
if args.reproductibilite:
|
||||
if not args.workflow or not args.plan:
|
||||
parseur.error("--workflow et --plan sont requis pour --reproductibilite")
|
||||
return reproductibilite(args)
|
||||
if not args.workflow or not args.plan:
|
||||
parseur.error("--workflow et --plan sont requis (ou --verifier)")
|
||||
return generer(args)
|
||||
|
||||
Reference in New Issue
Block a user