From 856b5fa1f7244475e1e9e0454cbd5c5754dc2bec Mon Sep 17 00:00:00 2001 From: AI Lab <129358391+1038lab@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:20:43 -0700 Subject: [PATCH] Add files via upload --- web/js/appearance.js | 102 +++++++++++----------- web/js/downloader.js | 199 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+), 49 deletions(-) create mode 100644 web/js/downloader.js diff --git a/web/js/appearance.js b/web/js/appearance.js index 72fce90..eca72d7 100644 --- a/web/js/appearance.js +++ b/web/js/appearance.js @@ -1,50 +1,54 @@ -import { app } from "/scripts/app.js"; - -const COLOR_THEMES = { - QwenVL: { nodeColor: "#28403f", nodeBgColor: "#374539", width: 340 }, - QwenVLGGUF: { nodeColor: "#474539", nodeBgColor: "#2c4045", width: 340 }, - Tools: { nodeColor: "#28403f", nodeBgColor: "#233238", width: 300 }, - Enhancer: { nodeColor: "#374445", nodeBgColor: "#474539", width: 340 }, -}; - -const NODE_COLORS = { - // QwenVL nodes - "AILab_QwenVL": "QwenVL", - "AILab_QwenVL_Advanced": "QwenVL", - "AILab_QwenVL_PromptEnhancer": "Enhancer", - "AILab_QwenVL_GGUF": "QwenVLGGUF", - "AILab_QwenVL_GGUF_Advanced": "QwenVLGGUF", - "AILab_QwenVL_GGUF_PromptEnhancer": "Enhancer", - - // Tools - "AILab_QwenVL_PromptLibrary": "Tools", -}; - -function setNodeColors(node, theme) { - if (!theme) { return; } - if (theme.nodeColor) { - node.color = theme.nodeColor; - } - if (theme.nodeBgColor) { - node.bgcolor = theme.nodeBgColor; - } - if (theme.width) { - node.size = node.size || [140, 80]; - node.size[0] = theme.width; - } -} - -const ext = { - name: "QwenVL.appearance", - - nodeCreated(node) { - const nclass = node.comfyClass; - if (NODE_COLORS.hasOwnProperty(nclass)) { - let colorKey = NODE_COLORS[nclass]; - const theme = COLOR_THEMES[colorKey]; - setNodeColors(node, theme); - } - } -}; - +import { app } from "/scripts/app.js"; + +const COLOR_THEMES = { + QwenVL: { nodeColor: "#28403f", nodeBgColor: "#28403f", width: 340 }, + QwenVLGGUF: { nodeColor: "#474539", nodeBgColor: "#474539", width: 340 }, + Tools: { nodeColor: "#28403f", nodeBgColor: "#233238", width: 420 }, + Enhancer: { nodeColor: "#374445", nodeBgColor: "#474539", width: 340 }, +}; + +const NODE_COLORS = { + // QwenVL nodes + "AILab_QwenVL": "QwenVL", + "AILab_QwenVL_Advanced": "QwenVL", + "AILab_QwenVL_PromptEnhancer": "Enhancer", + "AILab_QwenVL_GGUF": "QwenVLGGUF", + "AILab_QwenVL_GGUF_Advanced": "QwenVLGGUF", + "AILab_QwenVL_GGUF_PromptEnhancer": "Enhancer", + "AILab_QwenVL_VideoPromptEnhancer": "Enhancer", + "AILab_QwenVL_MiniMax_H3_Director": "Enhancer", + "AILab_QwenVL_LTX_Video_Enhancer": "Enhancer", + + // Tools + "AILab_QwenVL_PromptLibrary": "Tools", + "AILab_HuggingFaceDownloader": "Tools", +}; + +function setNodeColors(node, theme) { + if (!theme) { return; } + if (theme.nodeColor) { + node.color = theme.nodeColor; + } + if (theme.nodeBgColor) { + node.bgcolor = theme.nodeBgColor; + } + if (theme.width) { + node.size = node.size || [140, 80]; + node.size[0] = theme.width; + } +} + +const ext = { + name: "QwenVL.appearance", + + nodeCreated(node) { + const nclass = node.comfyClass; + if (NODE_COLORS.hasOwnProperty(nclass)) { + let colorKey = NODE_COLORS[nclass]; + const theme = COLOR_THEMES[colorKey]; + setNodeColors(node, theme); + } + } +}; + app.registerExtension(ext); \ No newline at end of file diff --git a/web/js/downloader.js b/web/js/downloader.js new file mode 100644 index 0000000..cfd8281 --- /dev/null +++ b/web/js/downloader.js @@ -0,0 +1,199 @@ +import { app } from "/scripts/app.js"; + +function escapeHtml(str) { + if (!str) return ""; + return String(str) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function buildRichSummaryHTML(data, rawText) { + if (data && data.status === "success") { + const filesListHtml = (data.files || []) + .map((f) => `
• ${escapeHtml(f)}
`) + .join(""); + + let regHtml = ""; + if (data.registration && data.registration.entry) { + const regSnippet = JSON.stringify({ [data.registration.key]: data.registration.entry }, null, 2); + regHtml = ` +
+ • Registered in custom_models.json [${escapeHtml(data.registration.section)}]: +
${escapeHtml(regSnippet)}
+
+ `; + } + + return ` +
+
+ + 📥 QwenVL Downloader Summary + + + ✅ Completed + +
+
+ • Repository: + ${escapeHtml(data.repo_id)} +
+
+ • Save Location: + ${escapeHtml(data.save_folder)} +
+
+ • Downloaded Files: +
${filesListHtml}
+
+ ${regHtml} +
+ `; + } else if (data && data.status === "error") { + return ` +
+
+ ❌ Download Failed + Error +
+
+ • Repository: + ${escapeHtml(data.repo_id || "")} +
+
+ ${escapeHtml(data.error || "Unknown error occurred")} +
+
+ `; + } + + // Fallback: parse raw text with highlighting + const lines = (rawText || "").split("\n"); + let resultHtml = ""; + for (let line of lines) { + if (line.startsWith("==")) continue; + if (line.includes("Download Summary")) { + resultHtml += `
${escapeHtml(line)}
`; + } else if (line.includes("Status:") && line.includes("Completed")) { + resultHtml += `
• Status: ✅ Completed Successfully
`; + } else if (line.startsWith("• Repository:")) { + resultHtml += `
• Repository: ${escapeHtml(line.replace("• Repository:", "").trim())}
`; + } else if (line.startsWith("• Save Location:")) { + resultHtml += `
• Save Location: ${escapeHtml(line.replace("• Save Location:", "").trim())}
`; + } else if (line.startsWith("• Downloaded Files:")) { + resultHtml += `
• Downloaded Files:
`; + } else if (line.trim().startsWith("- ")) { + resultHtml += `
${escapeHtml(line.trim())}
`; + } else if (line.includes("Registered to custom_models.json")) { + resultHtml += `
${escapeHtml(line)}
`; + } else { + resultHtml += `
${escapeHtml(line)}
`; + } + } + return `
${resultHtml}
`; +} + +const BASE_INPUTS_HEIGHT = 184; +const INITIAL_NODE_HEIGHT = 188; + +function syncContentSize(node, size) { + const domWidget = node.widgets?.find((w) => w.name === "download_display"); + if (domWidget && domWidget.element) { + const nodeH = size ? size[1] : (node.size ? node.size[1] : INITIAL_NODE_HEIGHT); + const availableHeight = Math.max(120, Math.round(nodeH - BASE_INPUTS_HEIGHT)); + domWidget.element.style.height = `${availableHeight}px`; + } +} + +app.registerExtension({ + name: "AILab.HuggingFaceDownloader", + + nodeCreated(node) { + if (node.comfyClass === "AILab_HuggingFaceDownloader") { + requestAnimationFrame(() => { + node.size = [Math.max(node.size?.[0] || 420, 420), INITIAL_NODE_HEIGHT]; + if (typeof node.setSize === "function") { + node.setSize(node.size); + } + app.graph?.setDirtyCanvas(true, true); + }); + } + }, + + async beforeRegisterNodeDef(nodeType, nodeData, app) { + if (nodeData.name === "AILab_HuggingFaceDownloader") { + const origOnResize = nodeType.prototype.onResize; + nodeType.prototype.onResize = function (size) { + origOnResize?.apply(this, arguments); + size[0] = Math.max(size[0], 360); + size[1] = Math.max(size[1], INITIAL_NODE_HEIGHT); + syncContentSize(this, size); + }; + + const onExecuted = nodeType.prototype.onExecuted; + nodeType.prototype.onExecuted = function (message) { + onExecuted?.apply(this, arguments); + + const rawText = Array.isArray(message?.text) ? message.text.join("\n") : (message?.text || ""); + const summaryData = Array.isArray(message?.summary) ? message.summary[0] : message?.summary; + + if (rawText || summaryData) { + const richHtml = buildRichSummaryHTML(summaryData, rawText); + + let domWidget = this.widgets?.find((w) => w.name === "download_display"); + + if (!domWidget) { + const container = document.createElement("div"); + container.className = "ailab-download-display-container"; + container.style.boxSizing = "border-box"; + container.style.width = "100%"; + container.style.height = "100%"; + container.style.margin = "0"; + container.style.padding = "0 2px 4px 2px"; + container.style.userSelect = "text"; + container.style.cursor = "auto"; + container.style.display = "flex"; + container.style.flexDirection = "column"; + container.style.overflow = "hidden"; + + domWidget = this.addDOMWidget("download_display", "display_element", container, { + getValue() { + return container.innerHTML; + }, + setValue(val) { + container.innerHTML = val; + }, + }); + domWidget.element = container; + domWidget.serialize = false; + if (domWidget.options) { + domWidget.options.serialize = false; + } + } + + if (domWidget && domWidget.element) { + domWidget.element.innerHTML = richHtml; + + requestAnimationFrame(() => { + const card = domWidget.element.querySelector(".ailab-download-card") || domWidget.element; + const cardH = card ? (card.scrollHeight || card.offsetHeight) : 260; + const targetHeight = Math.ceil(BASE_INPUTS_HEIGHT + cardH + 10); + const targetWidth = Math.max(this.size ? this.size[0] : 420, 420); + + this.size = [targetWidth, targetHeight]; + syncContentSize(this, this.size); + if (typeof this.setSize === "function") { + this.setSize([targetWidth, targetHeight]); + } + this.setDirtyCanvas?.(true, true); + app.graph?.setDirtyCanvas(true, true); + }); + } + } + }; + } + }, +});