diff --git a/README.md b/README.md index 4ff03133..4a1d76c6 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,11 @@ This ui will let you design and execute advanced stable diffusion pipelines usin Workflow examples can be found on the [Examples page](https://comfyanonymous.github.io/ComfyUI_examples/) +## Shortcuts +- **Ctrl + A** select all nodes +- **Ctrl + M** mute/unmute selected nodes +- **Delete** or **Backspace** delete selected nodes + # Installing ## Windows @@ -64,7 +69,7 @@ AMD users can install rocm and pytorch with pip if you don't have it already ins Nvidia users should install torch and xformers using this command: -```pip install torch==1.13.1 torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu117 xformers``` +```pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu118 xformers``` #### Troubleshooting diff --git a/notebooks/comfyui_colab.ipynb b/notebooks/comfyui_colab.ipynb index 276579c9..a86ccc75 100644 --- a/notebooks/comfyui_colab.ipynb +++ b/notebooks/comfyui_colab.ipynb @@ -47,7 +47,7 @@ " !git pull\n", "\n", "!echo -= Install dependencies =-\n", - "!pip -q install xformers==0.0.16 -r requirements.txt" + "!pip install xformers==0.0.16 -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cu117" ] }, { diff --git a/requirements.txt b/requirements.txt index bc8b3c55..3b4040a2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ torchdiffeq torchsde einops open-clip-torch -transformers +transformers>=4.25.1 safetensors pytorch_lightning aiohttp diff --git a/web/scripts/app.js b/web/scripts/app.js index cd7fb5d1..3b1f5450 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -417,6 +417,59 @@ class ComfyApp { }; } + /** + * Handle keypress + * + * Ctrl + M mute/unmute selected nodes + */ + #addProcessKeyHandler() { + const self = this; + const origProcessKey = LGraphCanvas.prototype.processKey; + LGraphCanvas.prototype.processKey = function(e) { + const res = origProcessKey.apply(this, arguments); + + if (res === false) { + return res; + } + + if (!this.graph) { + return; + } + + var block_default = false; + + if (e.target.localName == "input") { + return; + } + + if (e.type == "keydown") { + // Ctrl + M mute/unmute + if (e.keyCode == 77 && e.ctrlKey) { + if (this.selected_nodes) { + for (var i in this.selected_nodes) { + if (this.selected_nodes[i].mode === 2) { // never + this.selected_nodes[i].mode = 0; // always + } else { + this.selected_nodes[i].mode = 2; // never + } + } + } + block_default = true; + } + } + + this.graph.change(); + + if (block_default) { + e.preventDefault(); + e.stopImmediatePropagation(); + return false; + } + + return res; + }; + } + /** * Draws group header bar */ @@ -465,10 +518,11 @@ class ComfyApp { * Draws node highlights (executing, drag drop) and progress bar */ #addDrawNodeHandler() { - const orig = LGraphCanvas.prototype.drawNodeShape; + const origDrawNodeShape = LGraphCanvas.prototype.drawNodeShape; const self = this; + LGraphCanvas.prototype.drawNodeShape = function (node, ctx, size, fgcolor, bgcolor, selected, mouse_over) { - const res = orig.apply(this, arguments); + const res = origDrawNodeShape.apply(this, arguments); let color = null; if (node.id === +self.runningNodeId) { @@ -517,6 +571,21 @@ class ComfyApp { return res; }; + + const origDrawNode = LGraphCanvas.prototype.drawNode; + LGraphCanvas.prototype.drawNode = function (node, ctx) { + var editor_alpha = this.editor_alpha; + + if (node.mode === 2) { // never + this.editor_alpha = 0.4; + } + + const res = origDrawNode.apply(this, arguments); + + this.editor_alpha = editor_alpha; + + return res; + }; } /** @@ -588,6 +657,7 @@ class ComfyApp { document.body.prepend(canvasEl); this.#addProcessMouseHandler(); + this.#addProcessKeyHandler(); this.graph = new LGraph(); const canvas = (this.canvas = new LGraphCanvas(canvasEl, this.graph)); @@ -777,6 +847,11 @@ class ComfyApp { continue; } + if (node.mode === 2) { + // Don't serialize muted nodes + continue; + } + const inputs = {}; const widgets = node.widgets; @@ -816,6 +891,18 @@ class ComfyApp { }; } + // Remove inputs connected to removed nodes + + for (const o in output) { + for (const i in output[o].inputs) { + if (Array.isArray(output[o].inputs[i]) + && output[o].inputs[i].length === 2 + && !output[output[o].inputs[i][0]]) { + delete output[o].inputs[i]; + } + } + } + return { workflow, output }; } diff --git a/web/style.css b/web/style.css index 7c3d7efa..943fd6c3 100644 --- a/web/style.css +++ b/web/style.css @@ -101,6 +101,12 @@ body { display: flex; flex-direction: column; align-items: center; + color: #999; + background-color: #353535; + font-family: sans-serif; + padding: 10px; + border-radius: 0 8px 8px 8px; + box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.4); } .comfy-menu button { @@ -115,6 +121,22 @@ body { .comfy-menu-btns button { font-size: 10px; width: 50%; + color: #999 !important; +} + +.comfy-menu > button { + width: 100%; +} + +.comfy-menu > button, +.comfy-menu-btns button, +.comfy-menu .comfy-list button { + color: #ddd; + background-color: #222; + border-radius: 8px; + border-color: #4e4e4e; + border-style: solid; + margin-top: 2px; } .comfy-menu span.drag-handle { @@ -147,14 +169,18 @@ body { } .comfy-list { - background-color: rgb(225, 225, 225); + color: #999; + background-color: #333; margin-bottom: 10px; + border-color: #4e4e4e; + border-style: solid; } .comfy-list-items { overflow-y: scroll; max-height: 100px; - background-color: #d0d0d0; + min-height: 25px; + background-color: #222; padding: 5px; } @@ -181,6 +207,7 @@ body { } button.comfy-settings-btn { + background-color: rgba(0, 0, 0, 0); font-size: 12px; padding: 0; position: absolute; @@ -188,6 +215,10 @@ button.comfy-settings-btn { border: none; } +button.comfy-queue-btn { + margin: 6px 0 !important; +} + .comfy-modal.comfy-settings { background-color: var(--bg-color); color: var(--fg-color);