From 5fa6ce0290bbd54ab28482d8f88f9be758395d38 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 10 May 2026 18:56:52 +0200 Subject: [PATCH] fix: force deep model refresh by calling /refresh_models and re-fetching defs --- __init__.py | 19 +++++---- src/main/resources/comfyui-bridge/__init__.py | 19 +++++---- .../comfyui-bridge/web/downloader.js | 41 +++++++++++-------- web/downloader.js | 41 +++++++++++-------- 4 files changed, 72 insertions(+), 48 deletions(-) diff --git a/__init__.py b/__init__.py index 25e99d5..a71a0e3 100644 --- a/__init__.py +++ b/__init__.py @@ -15,7 +15,7 @@ async def model_downloaded(request): # 1. Dateisystem-Cache löschen (Kurze Pause für Windows-Dateisystem-Handles) await asyncio.sleep(0.5) - # Robusteres Löschen der Caches in folder_paths + # Alle Caches in folder_paths radikal leeren if hasattr(folder_paths, "folder_names"): for k in list(folder_paths.folder_names.keys()): folder_paths.folder_names[k] = [] @@ -32,21 +32,26 @@ async def model_downloaded(request): # Dies zwingt ComfyUI, die Node-Metadaten (inkl. Modell-Listen) neu zu generieren server.PromptServer.instance.object_info = None - # 3. Aktiven Scan triggern - # Durch den Aufruf von get_filename_list wird ComfyUI gezwungen, die Ordner neu zu indizieren - for folder in ["checkpoints", "loras", "vae", "controlnet", "diffusion_models", "upscale_models", "clip", "unet", "gligen"]: + # 3. Aktiven Scan triggern (Offizieller Weg via get_filename_list) + # Wir decken hier alle gängigen Modell-Typen ab + folders = ["checkpoints", "loras", "vae", "controlnet", "diffusion_models", "upscale_models", + "clip", "unet", "gligen", "embeddings", "configs", "hypernetworks", "style_models"] + for folder in folders: try: folder_paths.get_filename_list(folder) except: pass - print("[Model-Downloader] Backend-Reset und Scan abgeschlossen.") + print(f"[Model-Downloader] Backend-Reset abgeschlossen. Gescannte Ordner: {len(folders)}") except Exception as e: print(f"[Model-Downloader] Fehler beim Reset: {e}") - # 4. Signale an alle Browser (jetzt mit frischen Daten) - # "refresh" ist ein Standard-Signal, "kippster-refresh-ui" ist unser spezieller Trigger für Deep-Update + # 4. Signale an alle Browser + # "refresh_models" wird von vielen Extensions abgefangen + server.PromptServer.instance.send_sync("refresh_models", {}) + # "refresh" ist der Standard für ComfyUI server.PromptServer.instance.send_sync("refresh", {}) + # Unser spezieller Trigger server.PromptServer.instance.send_sync("kippster-refresh-ui", {"message": "ready"}) return web.json_response({"status": "success", "message": "Backend reset and rescan complete"}) diff --git a/src/main/resources/comfyui-bridge/__init__.py b/src/main/resources/comfyui-bridge/__init__.py index 25e99d5..a71a0e3 100644 --- a/src/main/resources/comfyui-bridge/__init__.py +++ b/src/main/resources/comfyui-bridge/__init__.py @@ -15,7 +15,7 @@ async def model_downloaded(request): # 1. Dateisystem-Cache löschen (Kurze Pause für Windows-Dateisystem-Handles) await asyncio.sleep(0.5) - # Robusteres Löschen der Caches in folder_paths + # Alle Caches in folder_paths radikal leeren if hasattr(folder_paths, "folder_names"): for k in list(folder_paths.folder_names.keys()): folder_paths.folder_names[k] = [] @@ -32,21 +32,26 @@ async def model_downloaded(request): # Dies zwingt ComfyUI, die Node-Metadaten (inkl. Modell-Listen) neu zu generieren server.PromptServer.instance.object_info = None - # 3. Aktiven Scan triggern - # Durch den Aufruf von get_filename_list wird ComfyUI gezwungen, die Ordner neu zu indizieren - for folder in ["checkpoints", "loras", "vae", "controlnet", "diffusion_models", "upscale_models", "clip", "unet", "gligen"]: + # 3. Aktiven Scan triggern (Offizieller Weg via get_filename_list) + # Wir decken hier alle gängigen Modell-Typen ab + folders = ["checkpoints", "loras", "vae", "controlnet", "diffusion_models", "upscale_models", + "clip", "unet", "gligen", "embeddings", "configs", "hypernetworks", "style_models"] + for folder in folders: try: folder_paths.get_filename_list(folder) except: pass - print("[Model-Downloader] Backend-Reset und Scan abgeschlossen.") + print(f"[Model-Downloader] Backend-Reset abgeschlossen. Gescannte Ordner: {len(folders)}") except Exception as e: print(f"[Model-Downloader] Fehler beim Reset: {e}") - # 4. Signale an alle Browser (jetzt mit frischen Daten) - # "refresh" ist ein Standard-Signal, "kippster-refresh-ui" ist unser spezieller Trigger für Deep-Update + # 4. Signale an alle Browser + # "refresh_models" wird von vielen Extensions abgefangen + server.PromptServer.instance.send_sync("refresh_models", {}) + # "refresh" ist der Standard für ComfyUI server.PromptServer.instance.send_sync("refresh", {}) + # Unser spezieller Trigger server.PromptServer.instance.send_sync("kippster-refresh-ui", {"message": "ready"}) return web.json_response({"status": "success", "message": "Backend reset and rescan complete"}) diff --git a/src/main/resources/comfyui-bridge/web/downloader.js b/src/main/resources/comfyui-bridge/web/downloader.js index 8a0c5a8..2b1e72a 100644 --- a/src/main/resources/comfyui-bridge/web/downloader.js +++ b/src/main/resources/comfyui-bridge/web/downloader.js @@ -3,7 +3,7 @@ let app = null; let api = null; const initializeExtension = async () => { - // 1. Try to find ComfyUI app and api objects + // 1. Suche nach ComfyUI App/API const paths = ["../../scripts/app.js", "/scripts/app.js", "../../../scripts/app.js"]; const apiPaths = ["../../scripts/api.js", "/scripts/api.js", "../../../scripts/api.js"]; for (const path of paths) { try { const mod = await import(path); if (mod.app) { app = mod.app; break; } } catch (e) {} } @@ -11,27 +11,31 @@ const initializeExtension = async () => { if (!app || !api) { setTimeout(initializeExtension, 2000); return; } - // 2. Setup WebSocket Listener for Deep-Sync + // 2. WebSocket Listener für den "Sync"-Trigger api.addEventListener("kippster-refresh-ui", async (event) => { - console.log("%c🔥 [Model-Downloader] SIGNAL EMPFANGEN! Starte Deep-Node-Update...", "background: #ff0000; color: #fff; font-size: 14px;"); + console.log("%c🔥 [Model-Downloader] SIGNAL ERHALTEN! Erzwinge harten UI-Refresh...", "background: #ff0000; color: #fff; font-size: 14px;"); try { - // Backend Zeit zum Scannen geben (wichtig für Windows HDDs) + // A. Offiziellen ComfyUI Refresh-Endpoint triggern (wie der Button im Manager) + console.log("[Model-Downloader] Trigger /refresh_models..."); + await fetch('/refresh_models', { method: 'POST' }); + + // B. Kurze Pause für das Backend await new Promise(r => setTimeout(r, 1000)); - // Definitionen neu laden (Zwingt den Browser die neuesten Modell-Listen vom Backend anzufragen) + // C. Node-Definitionen neu laden (Zwingt den Browser die neuen Listen anzufragen) + console.log("[Model-Downloader] Re-fetching Node Definitions..."); const nodeDefs = await api.getNodeDefs(); let updatedCount = 0; - // Bestehende Nodes auf dem Canvas aktualisieren + // D. Nodes auf dem Canvas manuell aktualisieren if (app.graph && app.graph._nodes) { for (const node of app.graph._nodes) { const def = nodeDefs[node.type]; - if (def && def.input && def.input.required) { + if (def?.input?.required) { for (const widgetName in def.input.required) { const inputDef = def.input.required[widgetName]; - // Falls es ein Dropdown (Combo) ist (Array an Position 0) - if (Array.isArray(inputDef[0])) { + if (Array.isArray(inputDef[0])) { // Es ist ein Dropdown (Combo) const newValues = inputDef[0]; const widget = node.widgets?.find(w => w.name === widgetName); @@ -39,7 +43,7 @@ const initializeExtension = async () => { const oldValue = widget.value; widget.options.values = newValues; - // Validierung: Ist das aktuell gewählte Modell jetzt verfügbar? + // Check ob das ehemals rote Modell jetzt da ist if (newValues.includes(oldValue)) { if (node.color === "#322" || node.color === "#a22") { node.color = ""; @@ -47,7 +51,7 @@ const initializeExtension = async () => { updatedCount++; } } else if (oldValue && oldValue !== "None" && !newValues.includes(oldValue)) { - // Markiere fehlende Modelle rot + // Modell fehlt immer noch -> rot markieren node.color = "#322"; node.bgcolor = "#a22"; } @@ -59,24 +63,27 @@ const initializeExtension = async () => { } } + // E. ComfyUI Standard-Refresh (lädt Sidebars etc. neu) if (app.refresh) await app.refresh(); + + // F. Canvas neu zeichnen app.graph.setDirtyCanvas(true, true); - console.log(`[Model-Downloader] Deep-Sync fertig. ${updatedCount} Nodes geheilt.`); + console.log(`[Model-Downloader] Sync abgeschlossen. ${updatedCount} Nodes aktualisiert.`); const msg = updatedCount > 0 - ? `✅ Synchronisation abgeschlossen!\n${updatedCount} Nodes wurden aktualisiert und sind jetzt bereit.` - : "✅ Synchronisation abgeschlossen! Die Modell-Listen sind auf dem neuesten Stand."; + ? `✅ Deep-Sync abgeschlossen!\n${updatedCount} Nodes wurden aktualisiert.` + : "✅ Synchronisation abgeschlossen! Die Modell-Listen sind aktuell."; if (app.ui?.dialog?.show) app.ui.dialog.show(msg); else alert(msg); } catch (e) { - console.error("[Model-Downloader] Fehler beim Deep-Node-Update:", e); + console.error("[Model-Downloader] Fehler beim erzwungenen Refresh:", e); } }); - // 3. Load Token and setup UI + // 3. Token & FAB UI let apiToken = null; const loadConfig = async () => { try { @@ -109,7 +116,7 @@ const initializeExtension = async () => { if (app.ui?.dialog?.show) app.ui.dialog.show("🚀 Workflow an Downloader gesendet!"); } } catch (e) { - alert("❌ Downloader App nicht erreichbar! Läuft sie?"); + alert("❌ Downloader App nicht erreichbar!"); } }; document.body.appendChild(fab); diff --git a/web/downloader.js b/web/downloader.js index 8a0c5a8..2b1e72a 100644 --- a/web/downloader.js +++ b/web/downloader.js @@ -3,7 +3,7 @@ let app = null; let api = null; const initializeExtension = async () => { - // 1. Try to find ComfyUI app and api objects + // 1. Suche nach ComfyUI App/API const paths = ["../../scripts/app.js", "/scripts/app.js", "../../../scripts/app.js"]; const apiPaths = ["../../scripts/api.js", "/scripts/api.js", "../../../scripts/api.js"]; for (const path of paths) { try { const mod = await import(path); if (mod.app) { app = mod.app; break; } } catch (e) {} } @@ -11,27 +11,31 @@ const initializeExtension = async () => { if (!app || !api) { setTimeout(initializeExtension, 2000); return; } - // 2. Setup WebSocket Listener for Deep-Sync + // 2. WebSocket Listener für den "Sync"-Trigger api.addEventListener("kippster-refresh-ui", async (event) => { - console.log("%c🔥 [Model-Downloader] SIGNAL EMPFANGEN! Starte Deep-Node-Update...", "background: #ff0000; color: #fff; font-size: 14px;"); + console.log("%c🔥 [Model-Downloader] SIGNAL ERHALTEN! Erzwinge harten UI-Refresh...", "background: #ff0000; color: #fff; font-size: 14px;"); try { - // Backend Zeit zum Scannen geben (wichtig für Windows HDDs) + // A. Offiziellen ComfyUI Refresh-Endpoint triggern (wie der Button im Manager) + console.log("[Model-Downloader] Trigger /refresh_models..."); + await fetch('/refresh_models', { method: 'POST' }); + + // B. Kurze Pause für das Backend await new Promise(r => setTimeout(r, 1000)); - // Definitionen neu laden (Zwingt den Browser die neuesten Modell-Listen vom Backend anzufragen) + // C. Node-Definitionen neu laden (Zwingt den Browser die neuen Listen anzufragen) + console.log("[Model-Downloader] Re-fetching Node Definitions..."); const nodeDefs = await api.getNodeDefs(); let updatedCount = 0; - // Bestehende Nodes auf dem Canvas aktualisieren + // D. Nodes auf dem Canvas manuell aktualisieren if (app.graph && app.graph._nodes) { for (const node of app.graph._nodes) { const def = nodeDefs[node.type]; - if (def && def.input && def.input.required) { + if (def?.input?.required) { for (const widgetName in def.input.required) { const inputDef = def.input.required[widgetName]; - // Falls es ein Dropdown (Combo) ist (Array an Position 0) - if (Array.isArray(inputDef[0])) { + if (Array.isArray(inputDef[0])) { // Es ist ein Dropdown (Combo) const newValues = inputDef[0]; const widget = node.widgets?.find(w => w.name === widgetName); @@ -39,7 +43,7 @@ const initializeExtension = async () => { const oldValue = widget.value; widget.options.values = newValues; - // Validierung: Ist das aktuell gewählte Modell jetzt verfügbar? + // Check ob das ehemals rote Modell jetzt da ist if (newValues.includes(oldValue)) { if (node.color === "#322" || node.color === "#a22") { node.color = ""; @@ -47,7 +51,7 @@ const initializeExtension = async () => { updatedCount++; } } else if (oldValue && oldValue !== "None" && !newValues.includes(oldValue)) { - // Markiere fehlende Modelle rot + // Modell fehlt immer noch -> rot markieren node.color = "#322"; node.bgcolor = "#a22"; } @@ -59,24 +63,27 @@ const initializeExtension = async () => { } } + // E. ComfyUI Standard-Refresh (lädt Sidebars etc. neu) if (app.refresh) await app.refresh(); + + // F. Canvas neu zeichnen app.graph.setDirtyCanvas(true, true); - console.log(`[Model-Downloader] Deep-Sync fertig. ${updatedCount} Nodes geheilt.`); + console.log(`[Model-Downloader] Sync abgeschlossen. ${updatedCount} Nodes aktualisiert.`); const msg = updatedCount > 0 - ? `✅ Synchronisation abgeschlossen!\n${updatedCount} Nodes wurden aktualisiert und sind jetzt bereit.` - : "✅ Synchronisation abgeschlossen! Die Modell-Listen sind auf dem neuesten Stand."; + ? `✅ Deep-Sync abgeschlossen!\n${updatedCount} Nodes wurden aktualisiert.` + : "✅ Synchronisation abgeschlossen! Die Modell-Listen sind aktuell."; if (app.ui?.dialog?.show) app.ui.dialog.show(msg); else alert(msg); } catch (e) { - console.error("[Model-Downloader] Fehler beim Deep-Node-Update:", e); + console.error("[Model-Downloader] Fehler beim erzwungenen Refresh:", e); } }); - // 3. Load Token and setup UI + // 3. Token & FAB UI let apiToken = null; const loadConfig = async () => { try { @@ -109,7 +116,7 @@ const initializeExtension = async () => { if (app.ui?.dialog?.show) app.ui.dialog.show("🚀 Workflow an Downloader gesendet!"); } } catch (e) { - alert("❌ Downloader App nicht erreichbar! Läuft sie?"); + alert("❌ Downloader App nicht erreichbar!"); } }; document.body.appendChild(fab);