fix: implement true deep refresh by clearing api.nodeDefs cache in frontend
This commit is contained in:
+15
-53
@@ -1,75 +1,37 @@
|
||||
# ComfyUI Model Downloader Bridge
|
||||
import server
|
||||
import folder_paths
|
||||
import os
|
||||
import asyncio
|
||||
from aiohttp import web
|
||||
|
||||
print("\033[95m[Model-Downloader] UI Extension Bridge active\033[0m")
|
||||
|
||||
# Erzwungene Pfad-Registrierung für den User-Pfad
|
||||
USER_MODEL_PATH = r"C:\AI\comfyuidata\models"
|
||||
if os.path.exists(USER_MODEL_PATH):
|
||||
print(f"[Model-Downloader] Prüfe User-Modell-Pfad: {USER_MODEL_PATH}")
|
||||
# Wir fügen den Pfad zu den Standard-Modell-Pfaden hinzu, falls er fehlt
|
||||
# ComfyUI nutzt intern oft 'base_path' oder 'extra_model_paths'
|
||||
try:
|
||||
# Versuch, den Pfad als extra Modell-Pfad zu registrieren
|
||||
# folder_paths.add_model_folder_path("custom", USER_MODEL_PATH)
|
||||
pass
|
||||
except: pass
|
||||
|
||||
@server.PromptServer.instance.routes.post("/kippster/model-downloaded")
|
||||
async def model_downloaded(request):
|
||||
print("\033[92m🔥 [Model-Downloader] PING ERHALTEN! Erzwinge harten Backend-Reset...\033[0m")
|
||||
|
||||
print("\033[92m🔥 [Model-Downloader] PING ERHALTEN! Leere Backend-Caches...\033[0m")
|
||||
|
||||
try:
|
||||
# 1. Warte auf Dateisystem (besonders wichtig bei Windows/HDD)
|
||||
await asyncio.sleep(1.0)
|
||||
|
||||
# 2. Alle Caches in folder_paths radikal leeren
|
||||
# 1. Kurze Pause für das Dateisystem (wichtig beim Entpacken/Verschieben)
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
# 2. Lösche gezielt die generierten Dateilisten aus dem ComfyUI Cache
|
||||
if hasattr(folder_paths, "filename_list_cache"):
|
||||
folder_paths.filename_list_cache.clear()
|
||||
|
||||
if hasattr(folder_paths, "cache_helper"):
|
||||
if hasattr(folder_paths.cache_helper, "clear"):
|
||||
folder_paths.cache_helper.clear()
|
||||
|
||||
if hasattr(folder_paths, "cache"):
|
||||
if hasattr(folder_paths.cache, "clear"):
|
||||
folder_paths.cache.clear()
|
||||
else:
|
||||
folder_paths.cache = {}
|
||||
if hasattr(folder_paths, "cache_helper") and hasattr(folder_paths.cache_helper, "clear"):
|
||||
folder_paths.cache_helper.clear()
|
||||
|
||||
# 3. Aktiven Scan triggern für ALLE bekannten Kategorien
|
||||
folders = ["checkpoints", "loras", "vae", "controlnet", "diffusion_models", "upscale_models",
|
||||
"clip", "unet", "gligen", "embeddings", "configs", "hypernetworks", "style_models"]
|
||||
|
||||
if hasattr(folder_paths, "folder_names"):
|
||||
folders = list(folder_paths.folder_names.keys())
|
||||
|
||||
for folder in folders:
|
||||
try:
|
||||
# get_filename_list erzwingt bei leerem Cache einen neuen os.walk
|
||||
folder_paths.get_filename_list(folder)
|
||||
except: pass
|
||||
|
||||
# 4. Den globalen object_info Cache im Server zurücksetzen
|
||||
# Das zwingt den Server beim nächsten /object_info Aufruf alles neu zu berechnen
|
||||
# 3. Zwinge den Server, beim nächsten API-Call die Daten frisch zu generieren
|
||||
server.PromptServer.instance.object_info = None
|
||||
|
||||
print(f"[Model-Downloader] Backend-Scan & Object-Info Reset abgeschlossen.")
|
||||
|
||||
# 4. Sende das Signal an unser JavaScript (welches dann app.refresh() auslöst)
|
||||
server.PromptServer.instance.send_sync("kippster-refresh-ui", {"message": "ready"})
|
||||
|
||||
return web.json_response({"status": "success", "message": "Cache cleared and frontend notified"})
|
||||
|
||||
except Exception as e:
|
||||
print(f"[Model-Downloader] Fehler beim Backend-Reset: {e}")
|
||||
|
||||
# 5. Signale an alle Browser senden
|
||||
# Wir senden "refresh" (Standard für ComfyUI UI-Refresh)
|
||||
server.PromptServer.instance.send_sync("refresh", {})
|
||||
# Unser spezieller Trigger für den Deep-UI-Sync
|
||||
server.PromptServer.instance.send_sync("kippster-refresh-ui", {"message": "ready"})
|
||||
|
||||
return web.json_response({"status": "success", "message": "Backend reset and rescan complete"})
|
||||
return web.json_response({"status": "error", "message": str(e)})
|
||||
|
||||
WEB_DIRECTORY = "web"
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
|
||||
@@ -1,75 +1,37 @@
|
||||
# ComfyUI Model Downloader Bridge
|
||||
import server
|
||||
import folder_paths
|
||||
import os
|
||||
import asyncio
|
||||
from aiohttp import web
|
||||
|
||||
print("\033[95m[Model-Downloader] UI Extension Bridge active\033[0m")
|
||||
|
||||
# Erzwungene Pfad-Registrierung für den User-Pfad
|
||||
USER_MODEL_PATH = r"C:\AI\comfyuidata\models"
|
||||
if os.path.exists(USER_MODEL_PATH):
|
||||
print(f"[Model-Downloader] Prüfe User-Modell-Pfad: {USER_MODEL_PATH}")
|
||||
# Wir fügen den Pfad zu den Standard-Modell-Pfaden hinzu, falls er fehlt
|
||||
# ComfyUI nutzt intern oft 'base_path' oder 'extra_model_paths'
|
||||
try:
|
||||
# Versuch, den Pfad als extra Modell-Pfad zu registrieren
|
||||
# folder_paths.add_model_folder_path("custom", USER_MODEL_PATH)
|
||||
pass
|
||||
except: pass
|
||||
|
||||
@server.PromptServer.instance.routes.post("/kippster/model-downloaded")
|
||||
async def model_downloaded(request):
|
||||
print("\033[92m🔥 [Model-Downloader] PING ERHALTEN! Erzwinge harten Backend-Reset...\033[0m")
|
||||
|
||||
print("\033[92m🔥 [Model-Downloader] PING ERHALTEN! Leere Backend-Caches...\033[0m")
|
||||
|
||||
try:
|
||||
# 1. Warte auf Dateisystem (besonders wichtig bei Windows/HDD)
|
||||
await asyncio.sleep(1.0)
|
||||
|
||||
# 2. Alle Caches in folder_paths radikal leeren
|
||||
# 1. Kurze Pause für das Dateisystem (wichtig beim Entpacken/Verschieben)
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
# 2. Lösche gezielt die generierten Dateilisten aus dem ComfyUI Cache
|
||||
if hasattr(folder_paths, "filename_list_cache"):
|
||||
folder_paths.filename_list_cache.clear()
|
||||
|
||||
if hasattr(folder_paths, "cache_helper"):
|
||||
if hasattr(folder_paths.cache_helper, "clear"):
|
||||
folder_paths.cache_helper.clear()
|
||||
|
||||
if hasattr(folder_paths, "cache"):
|
||||
if hasattr(folder_paths.cache, "clear"):
|
||||
folder_paths.cache.clear()
|
||||
else:
|
||||
folder_paths.cache = {}
|
||||
if hasattr(folder_paths, "cache_helper") and hasattr(folder_paths.cache_helper, "clear"):
|
||||
folder_paths.cache_helper.clear()
|
||||
|
||||
# 3. Aktiven Scan triggern für ALLE bekannten Kategorien
|
||||
folders = ["checkpoints", "loras", "vae", "controlnet", "diffusion_models", "upscale_models",
|
||||
"clip", "unet", "gligen", "embeddings", "configs", "hypernetworks", "style_models"]
|
||||
|
||||
if hasattr(folder_paths, "folder_names"):
|
||||
folders = list(folder_paths.folder_names.keys())
|
||||
|
||||
for folder in folders:
|
||||
try:
|
||||
# get_filename_list erzwingt bei leerem Cache einen neuen os.walk
|
||||
folder_paths.get_filename_list(folder)
|
||||
except: pass
|
||||
|
||||
# 4. Den globalen object_info Cache im Server zurücksetzen
|
||||
# Das zwingt den Server beim nächsten /object_info Aufruf alles neu zu berechnen
|
||||
# 3. Zwinge den Server, beim nächsten API-Call die Daten frisch zu generieren
|
||||
server.PromptServer.instance.object_info = None
|
||||
|
||||
print(f"[Model-Downloader] Backend-Scan & Object-Info Reset abgeschlossen.")
|
||||
|
||||
# 4. Sende das Signal an unser JavaScript (welches dann app.refresh() auslöst)
|
||||
server.PromptServer.instance.send_sync("kippster-refresh-ui", {"message": "ready"})
|
||||
|
||||
return web.json_response({"status": "success", "message": "Cache cleared and frontend notified"})
|
||||
|
||||
except Exception as e:
|
||||
print(f"[Model-Downloader] Fehler beim Backend-Reset: {e}")
|
||||
|
||||
# 5. Signale an alle Browser senden
|
||||
# Wir senden "refresh" (Standard für ComfyUI UI-Refresh)
|
||||
server.PromptServer.instance.send_sync("refresh", {})
|
||||
# Unser spezieller Trigger für den Deep-UI-Sync
|
||||
server.PromptServer.instance.send_sync("kippster-refresh-ui", {"message": "ready"})
|
||||
|
||||
return web.json_response({"status": "success", "message": "Backend reset and rescan complete"})
|
||||
return web.json_response({"status": "error", "message": str(e)})
|
||||
|
||||
WEB_DIRECTORY = "web"
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
|
||||
@@ -13,9 +13,10 @@ const initializeExtension = async () => {
|
||||
|
||||
// 2. WebSocket Listener für den "Sync"-Trigger
|
||||
api.addEventListener("kippster-refresh-ui", async (event) => {
|
||||
console.log("%c🔥 [Model-Downloader] SIGNAL ERHALTEN! Erzwinge harten UI-Refresh...", "background: #ff0000; color: #fff; font-size: 14px;");
|
||||
|
||||
console.log("%c🔥 [Model-Downloader] SIGNAL ERHALTEN! Starte echten UI-Refresh...", "background: #ff0000; color: #fff; font-size: 14px;");
|
||||
|
||||
try {
|
||||
// Zeige Feedback an
|
||||
const showToast = (text) => {
|
||||
const toast = document.createElement("div");
|
||||
toast.style = "position:fixed; top:20px; left:50%; transform:translateX(-50%); background:rgba(255,204,0,0.9); color:black; padding:10px 20px; border-radius:5px; z-index:10001; font-weight:bold; font-family:sans-serif; pointer-events:none; transition: opacity 0.5s;";
|
||||
@@ -23,77 +24,24 @@ const initializeExtension = async () => {
|
||||
document.body.appendChild(toast);
|
||||
setTimeout(() => { toast.style.opacity = "0"; setTimeout(() => document.body.removeChild(toast), 500); }, 3000);
|
||||
};
|
||||
showToast("🔄 Erzwinge Refresh der Node-Definitionen...");
|
||||
showToast("🔄 Lade Node-Definitionen neu...");
|
||||
|
||||
// A. Manager-spezifische Endpunkte triggern falls vorhanden
|
||||
try { await fetch('/refresh_models', { method: 'POST' }); } catch(e) {}
|
||||
try { await fetch('/manager/refresh_node_definitions', { method: 'POST' }); } catch(e) {}
|
||||
// WICHTIG: Das ist der Gamechanger! Löscht den Frontend-Cache von ComfyUI.
|
||||
// Ohne das hier lädt ComfyUI immer die alten Modell-Listen aus dem Browser-RAM.
|
||||
api.nodeDefs = null;
|
||||
|
||||
// B. Pause für Backend-Stabilität
|
||||
await new Promise(r => setTimeout(r, 1500));
|
||||
// Gib dem Windows-Dateisystem kurz Zeit, die kopierten/verschobenen Dateien zu registrieren
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
|
||||
// C. HARTER UI REFRESH (Der Kern-Befehl der das "Refresh Node Definitions" Button imitiert)
|
||||
console.log("[Model-Downloader] Executing Deep Refresh...");
|
||||
|
||||
// 1. Hole frische Definitionen vom Server (triggert /object_info)
|
||||
const nodeDefs = await api.getNodeDefs();
|
||||
|
||||
// 2. Aktualisiere die Custom Nodes Liste
|
||||
if (api.getCustomNodes) await api.getCustomNodes();
|
||||
|
||||
// 3. Wenn ComfyUI V2 (app.refresh existiert)
|
||||
// Ruft die offizielle ComfyUI Refresh-Funktion auf (das entspricht exakt dem Klick auf "Refresh" im Menü)
|
||||
// app.refresh() zieht sich automatisch die neuen nodeDefs vom Server und "heilt" fehlerhafte Nodes.
|
||||
if (app.refresh) {
|
||||
await app.refresh();
|
||||
}
|
||||
|
||||
let healedCount = 0;
|
||||
|
||||
// 4. Jede Node auf dem Canvas zwingen, ihre Widgets neu zu evaluieren
|
||||
if (app.graph && app.graph._nodes) {
|
||||
for (const node of app.graph._nodes) {
|
||||
const def = nodeDefs[node.type];
|
||||
if (def?.input?.required) {
|
||||
for (const widgetName in def.input.required) {
|
||||
const inputDef = def.input.required[widgetName];
|
||||
if (Array.isArray(inputDef[0])) { // Dropdown / Combo
|
||||
const newValues = inputDef[0];
|
||||
const widget = node.widgets?.find(w => w.name === widgetName);
|
||||
|
||||
if (widget && widget.type === "combo") {
|
||||
const oldValue = widget.value;
|
||||
widget.options.values = newValues;
|
||||
|
||||
// Validierung & Heilung
|
||||
if (newValues.includes(oldValue)) {
|
||||
if (node.color === "#322" || node.color === "#a22") {
|
||||
node.color = "";
|
||||
node.bgcolor = "";
|
||||
healedCount++;
|
||||
}
|
||||
} else if (oldValue && oldValue !== "None" && !newValues.includes(oldValue)) {
|
||||
node.color = "#322";
|
||||
node.bgcolor = "#a22";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// WICHTIG: Trigger node internal refresh
|
||||
if (node.onRefresh) node.onRefresh();
|
||||
}
|
||||
|
||||
// 5. Den Graphen zwingen, die Nodes neu zu zeichnen (entspricht graph.refreshNodes)
|
||||
if (app.graph.refreshNodes) app.graph.refreshNodes();
|
||||
}
|
||||
|
||||
// F. Canvas neu zeichnen
|
||||
// Canvas zwingen, sich neu zu zeichnen
|
||||
app.graph.setDirtyCanvas(true, true);
|
||||
|
||||
console.log(`[Model-Downloader] Deep-Sync abgeschlossen. Healed: ${healedCount}`);
|
||||
|
||||
if (app.ui?.dialog?.show) {
|
||||
app.ui.dialog.show("✅ Node-Definitionen wurden erzwungen aktualisiert!\nAlle Modell-Listen sind nun auf dem neuesten Stand.");
|
||||
}
|
||||
console.log("[Model-Downloader] Sync erfolgreich abgeschlossen.");
|
||||
|
||||
} catch (e) {
|
||||
console.error("[Model-Downloader] Fehler beim erzwungenen Refresh:", e);
|
||||
|
||||
+13
-65
@@ -13,9 +13,10 @@ const initializeExtension = async () => {
|
||||
|
||||
// 2. WebSocket Listener für den "Sync"-Trigger
|
||||
api.addEventListener("kippster-refresh-ui", async (event) => {
|
||||
console.log("%c🔥 [Model-Downloader] SIGNAL ERHALTEN! Erzwinge harten UI-Refresh...", "background: #ff0000; color: #fff; font-size: 14px;");
|
||||
|
||||
console.log("%c🔥 [Model-Downloader] SIGNAL ERHALTEN! Starte echten UI-Refresh...", "background: #ff0000; color: #fff; font-size: 14px;");
|
||||
|
||||
try {
|
||||
// Zeige Feedback an
|
||||
const showToast = (text) => {
|
||||
const toast = document.createElement("div");
|
||||
toast.style = "position:fixed; top:20px; left:50%; transform:translateX(-50%); background:rgba(255,204,0,0.9); color:black; padding:10px 20px; border-radius:5px; z-index:10001; font-weight:bold; font-family:sans-serif; pointer-events:none; transition: opacity 0.5s;";
|
||||
@@ -23,77 +24,24 @@ const initializeExtension = async () => {
|
||||
document.body.appendChild(toast);
|
||||
setTimeout(() => { toast.style.opacity = "0"; setTimeout(() => document.body.removeChild(toast), 500); }, 3000);
|
||||
};
|
||||
showToast("🔄 Erzwinge Refresh der Node-Definitionen...");
|
||||
showToast("🔄 Lade Node-Definitionen neu...");
|
||||
|
||||
// A. Manager-spezifische Endpunkte triggern falls vorhanden
|
||||
try { await fetch('/refresh_models', { method: 'POST' }); } catch(e) {}
|
||||
try { await fetch('/manager/refresh_node_definitions', { method: 'POST' }); } catch(e) {}
|
||||
// WICHTIG: Das ist der Gamechanger! Löscht den Frontend-Cache von ComfyUI.
|
||||
// Ohne das hier lädt ComfyUI immer die alten Modell-Listen aus dem Browser-RAM.
|
||||
api.nodeDefs = null;
|
||||
|
||||
// B. Pause für Backend-Stabilität
|
||||
await new Promise(r => setTimeout(r, 1500));
|
||||
// Gib dem Windows-Dateisystem kurz Zeit, die kopierten/verschobenen Dateien zu registrieren
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
|
||||
// C. HARTER UI REFRESH (Der Kern-Befehl der das "Refresh Node Definitions" Button imitiert)
|
||||
console.log("[Model-Downloader] Executing Deep Refresh...");
|
||||
|
||||
// 1. Hole frische Definitionen vom Server (triggert /object_info)
|
||||
const nodeDefs = await api.getNodeDefs();
|
||||
|
||||
// 2. Aktualisiere die Custom Nodes Liste
|
||||
if (api.getCustomNodes) await api.getCustomNodes();
|
||||
|
||||
// 3. Wenn ComfyUI V2 (app.refresh existiert)
|
||||
// Ruft die offizielle ComfyUI Refresh-Funktion auf (das entspricht exakt dem Klick auf "Refresh" im Menü)
|
||||
// app.refresh() zieht sich automatisch die neuen nodeDefs vom Server und "heilt" fehlerhafte Nodes.
|
||||
if (app.refresh) {
|
||||
await app.refresh();
|
||||
}
|
||||
|
||||
let healedCount = 0;
|
||||
|
||||
// 4. Jede Node auf dem Canvas zwingen, ihre Widgets neu zu evaluieren
|
||||
if (app.graph && app.graph._nodes) {
|
||||
for (const node of app.graph._nodes) {
|
||||
const def = nodeDefs[node.type];
|
||||
if (def?.input?.required) {
|
||||
for (const widgetName in def.input.required) {
|
||||
const inputDef = def.input.required[widgetName];
|
||||
if (Array.isArray(inputDef[0])) { // Dropdown / Combo
|
||||
const newValues = inputDef[0];
|
||||
const widget = node.widgets?.find(w => w.name === widgetName);
|
||||
|
||||
if (widget && widget.type === "combo") {
|
||||
const oldValue = widget.value;
|
||||
widget.options.values = newValues;
|
||||
|
||||
// Validierung & Heilung
|
||||
if (newValues.includes(oldValue)) {
|
||||
if (node.color === "#322" || node.color === "#a22") {
|
||||
node.color = "";
|
||||
node.bgcolor = "";
|
||||
healedCount++;
|
||||
}
|
||||
} else if (oldValue && oldValue !== "None" && !newValues.includes(oldValue)) {
|
||||
node.color = "#322";
|
||||
node.bgcolor = "#a22";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// WICHTIG: Trigger node internal refresh
|
||||
if (node.onRefresh) node.onRefresh();
|
||||
}
|
||||
|
||||
// 5. Den Graphen zwingen, die Nodes neu zu zeichnen (entspricht graph.refreshNodes)
|
||||
if (app.graph.refreshNodes) app.graph.refreshNodes();
|
||||
}
|
||||
|
||||
// F. Canvas neu zeichnen
|
||||
// Canvas zwingen, sich neu zu zeichnen
|
||||
app.graph.setDirtyCanvas(true, true);
|
||||
|
||||
console.log(`[Model-Downloader] Deep-Sync abgeschlossen. Healed: ${healedCount}`);
|
||||
|
||||
if (app.ui?.dialog?.show) {
|
||||
app.ui.dialog.show("✅ Node-Definitionen wurden erzwungen aktualisiert!\nAlle Modell-Listen sind nun auf dem neuesten Stand.");
|
||||
}
|
||||
console.log("[Model-Downloader] Sync erfolgreich abgeschlossen.");
|
||||
|
||||
} catch (e) {
|
||||
console.error("[Model-Downloader] Fehler beim erzwungenen Refresh:", e);
|
||||
|
||||
Reference in New Issue
Block a user