feat: Enhance path correction functionality for widget nodes with pattern matching and user notifications

This commit is contained in:
Will Miao
2025-08-21 13:39:35 +08:00
parent fdec535559
commit 8895a64d24
2 changed files with 126 additions and 0 deletions

View File

@@ -1,6 +1,15 @@
// ComfyUI extension to track model usage statistics
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
import { showToast } from "./utils.js";
// Define target nodes and their widget configurations
const PATH_CORRECTION_TARGETS = [
{ comfyClass: "CheckpointLoaderSimple", widgetName: "ckpt_name", modelType: "checkpoints" },
{ comfyClass: "UNETLoader", widgetName: "unet_name", modelType: "checkpoints" },
{ comfyClass: "LoraLoader", widgetName: "lora_name", modelType: "loras" },
{ comfyClass: "easy loraStack", widgetNamePattern: "lora_\\d+_name", modelType: "loras" }
];
// Register the extension
app.registerExtension({
@@ -80,5 +89,100 @@ app.registerExtension({
} catch (error) {
console.error("Error refreshing registry:", error);
}
},
async loadedGraphNode(node) {
// Check if this node type needs path correction
const target = PATH_CORRECTION_TARGETS.find(t => t.comfyClass === node.comfyClass);
if (!target) {
return;
}
await this.correctNodePaths(node, target);
},
async correctNodePaths(node, target) {
try {
if (target.widgetNamePattern) {
// Handle pattern-based widget names (like lora_1_name, lora_2_name, etc.)
const pattern = new RegExp(target.widgetNamePattern);
const widgetIndexes = [];
if (node.widgets) {
node.widgets.forEach((widget, index) => {
if (pattern.test(widget.name)) {
widgetIndexes.push(index);
}
});
}
// Process each matching widget
for (const widgetIndex of widgetIndexes) {
await this.correctWidgetPath(node, widgetIndex, target.modelType);
}
} else {
// Handle single widget name
if (node.widgets) {
const widgetIndex = node.widgets.findIndex(w => w.name === target.widgetName);
if (widgetIndex !== -1) {
await this.correctWidgetPath(node, widgetIndex, target.modelType);
}
}
}
} catch (error) {
console.error("Error correcting node paths:", error);
}
},
async correctWidgetPath(node, widgetIndex, modelType) {
if (!node.widgets_values || !node.widgets_values[widgetIndex]) {
return;
}
const currentPath = node.widgets_values[widgetIndex];
if (!currentPath || typeof currentPath !== 'string') {
return;
}
// Extract filename from path (after last separator)
const fileName = currentPath.split(/[/\\]/).pop();
if (!fileName) {
return;
}
try {
// Search for current relative path
const response = await api.fetchApi(`/${modelType}/relative-paths?search=${encodeURIComponent(fileName)}&limit=2`);
const data = await response.json();
if (!data.success || !data.relative_paths || data.relative_paths.length === 0) {
return;
}
const foundPaths = data.relative_paths;
const firstPath = foundPaths[0];
// Check if we need to update the path
if (firstPath !== currentPath) {
// Update the widget value
// node.widgets_values[widgetIndex] = firstPath;
node.widgets[widgetIndex].value = firstPath;
if (foundPaths.length === 1) {
// Single match found - success
showToast(`Updated path for ${fileName}: ${firstPath}`, 'info');
} else {
// Multiple matches found - warning
showToast(`Multiple paths found for ${fileName}, using: ${firstPath}`, 'warning');
}
// Mark node as modified
if (node.setDirtyCanvas) {
node.setDirtyCanvas(true);
}
}
} catch (error) {
console.error(`Error correcting path for ${fileName}:`, error);
}
}
});

View File

@@ -23,6 +23,28 @@ export function getComfyUIFrontendVersion() {
return window['__COMFYUI_FRONTEND_VERSION__'] || "0.0.0";
}
/**
* Show a toast notification
* @param {string} message - The message to display
* @param {string} type - The type of toast (success, error, info, warning)
*/
export function showToast(message, type = 'info') {
if (app && app.extensionManager && app.extensionManager.toast) {
app.extensionManager.toast.add({
severity: type,
summary: type.charAt(0).toUpperCase() + type.slice(1),
detail: message,
life: 3000
});
} else {
console.log(`${type.toUpperCase()}: ${message}`);
// Fallback alert for critical errors only
if (type === 'error') {
alert(message);
}
}
}
// Dynamically import the appropriate widget based on app version
export async function dynamicImportByVersion(latestModulePath, legacyModulePath) {
// Parse app version and compare with 1.12.6 (version when tags widget API changed)