diff --git a/CHANGELOG.md b/CHANGELOG.md index c58588c..ca1042b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ ## v0.0 +## v0.0.7 (2025-01-29) + +- improve node `List: Random Seeds` + +## v0.0.6 (2025-01-29) + +- adjust project description + ## v0.0.5 (2025-01-29) - new List utility nodes: Random Seeds / Checkpoints / LoRAs / Samplers/ Schedulers diff --git a/dist/js/nodes/list.js b/dist/js/nodes/list.js index e296df7..55fad62 100644 --- a/dist/js/nodes/list.js +++ b/dist/js/nodes/list.js @@ -1,5 +1,5 @@ import { findWidget, loadTextFile } from '../shared/utils.js'; -import { makeComboWidget } from '../widgets/factories.js'; +import { makeComboWidget, makeButtonWidget } from '../widgets/factories.js'; export function ListFromMultiline(nodeType) { const original_onNodeCreated = nodeType.prototype.onNodeCreated; nodeType.prototype.onNodeCreated = function (...args) { @@ -89,3 +89,26 @@ export function ListFromSelection(nodeType, selection_type) { refreshFromSelection(this, selectionWidget); }; } +export function ListRandomSeeds(nodeType) { + const reset = (widget) => { + widget.value = new Date().getTime(); + }; + const original_onNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = function (...args) { + original_onNodeCreated?.apply(this, ...args); + const resetBtn = makeButtonWidget(this, 'reset_btn', 'Reset', { + tooltip: 'reset seeds', + }); + resetBtn.callback = () => { + reset(resetBtn); + }; + reset(resetBtn); + }; + const original_onConfigure = nodeType.prototype.onConfigure; + nodeType.prototype.onConfigure = function (...args) { + original_onConfigure?.apply(this, ...args); + const resetBtn = findWidget(this, 'reset_btn'); + if (resetBtn) + reset(resetBtn); + }; +} diff --git a/dist/js/register.js b/dist/js/register.js index ae9dca5..9d9a3c0 100644 --- a/dist/js/register.js +++ b/dist/js/register.js @@ -5,7 +5,7 @@ import { setupDynamicConnections } from './shared/dynamic_connections.js'; import { QUEUE_STATUS } from './widgets/queue.js'; import { HIDDEN, BTN, ERROR_DISPLAY, SELECTION_LIST } from './widgets/misc.js'; import { OutputConfigBackend, OutputConfigLocal } from './nodes/config.js'; -import { ListFromMultiline, ListFromSelection } from './nodes/list.js'; +import { ListFromMultiline, ListFromSelection, ListRandomSeeds, } from './nodes/list.js'; import { InputMultiline } from './nodes/input.js'; import { DebugJSONYAML, DebugWidgetVisibility } from './nodes/debug.js'; globalThis[CATEGORY] = { log: 'debug' }; @@ -43,6 +43,9 @@ app.registerExtension({ case 'ListSchedulers': ListFromSelection(nodeType, 'scheduler'); break; + case 'ListRandomSeeds': + ListRandomSeeds(nodeType); + break; case 'InputMultiline': InputMultiline(nodeType); break; diff --git a/package.json b/package.json index d87cc13..486a48a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "confylab-pack", "private": true, - "version": "0.0.5", + "version": "0.0.7", "type": "module", "scripts": { "watch": "tsc-watch -p tsconfig.json --onSuccess 'tsc-alias -p tsconfig.json -r build/replacers.js/mock.js'", diff --git a/pyproject.toml b/pyproject.toml index 5e798ba..f960b9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfylab-pack" description = "Nodes: fully-customizable and versatile XY Plot grid, dynamic outputs from config files, Format String, various List utilities, ... visit the wiki for a complete list, tutorials and more." -version = "0.0.6" +version = "0.0.7" authors = [{ name = "bugltd" }] license = {file = "LICENSE"} readme = "README.md" diff --git a/src/python/nodes/list.py b/src/python/nodes/list.py index 485e2d6..5ba4d1b 100644 --- a/src/python/nodes/list.py +++ b/src/python/nodes/list.py @@ -366,11 +366,6 @@ class ListRandomSeeds: ) DESCRIPTION = 'Create a list of random seeds.' - # ensure the list is regenerated - @classmethod - def IS_CHANGED(cls, **kwargs): - return float('NaN') - def run(self, count): values = [] for i in range(0, count): diff --git a/src/python/nodes/plot.py b/src/python/nodes/plot.py index a7d4c26..bca6559 100644 --- a/src/python/nodes/plot.py +++ b/src/python/nodes/plot.py @@ -82,9 +82,6 @@ class XYPlotQueue: ) DESCRIPTION = 'Loop through all values of dim1, optionally combined with dim2 values, and send them to outputs.\nIMPORTANT: for a given dim1 value, all dim2 values are first iterated, before going to the next dim1 value.\nSo it is advised to associate slow operations (e.g. loading checkpoints) to dim1, to ensure better performance.' - dim1 = [] - dim2 = [] - def run( self, dim1: list[str], @@ -93,15 +90,8 @@ class XYPlotQueue: index: int, dim2: list[str] = [''], ): - # store the input lists, to allow using input nodes that change at each prompt (ex. ListRandomSeeds) - if index == 0: - if len(dim2) == 0: - dim2 = [''] - self.dim1 = dim1 - self.dim2 = dim2 - else: - dim1 = self.dim1 - dim2 = self.dim2 + if len(dim2) == 0: + dim2 = [''] # to simplify code below size = (len(dim1), len(dim2)) diff --git a/src/python/nodes/queue.py b/src/python/nodes/queue.py index fb2e092..aba1e85 100644 --- a/src/python/nodes/queue.py +++ b/src/python/nodes/queue.py @@ -33,15 +33,7 @@ class GenericQueue: OUTPUT_TOOLTIPS = ('current value (not typed)', 'current index', 'total elements') DESCRIPTION = 'Loop through all values of input list, and send them to output.' - input_list = [] - def run(self, input_list: list[Any], index: int): - # store the input list, to allow using input nodes that change at each prompt (ex. ListRandomSeeds) - if index == 0: - self.input_list = input_list - else: - input_list = self.input_list - total = len(input_list) if total == 0: raise Exception('Empty input list') diff --git a/src/ts/nodes/list.ts b/src/ts/nodes/list.ts index 1959a0b..bc0ab07 100644 --- a/src/ts/nodes/list.ts +++ b/src/ts/nodes/list.ts @@ -1,7 +1,7 @@ import type { LGraphNode, IWidget } from '@comfyorg/litegraph' import { findWidget, loadTextFile } from '~/shared/utils.js' -import { makeComboWidget } from '~/widgets/factories.js' +import { makeComboWidget, makeButtonWidget } from '~/widgets/factories.js' export function ListFromMultiline( nodeType: LGraphNode, @@ -128,3 +128,28 @@ export function ListFromSelection( refreshFromSelection(this, selectionWidget) } } + +export function ListRandomSeeds(nodeType: LGraphNode) { + const reset = (widget: IWidget) => { + widget.value = new Date().getTime() + } + + const original_onNodeCreated = nodeType.prototype.onNodeCreated + nodeType.prototype.onNodeCreated = function (...args: unknown[]) { + original_onNodeCreated?.apply(this, ...args) + const resetBtn = makeButtonWidget(this, 'reset_btn', 'Reset', { + tooltip: 'reset seeds', + }) + resetBtn.callback = () => { + reset(resetBtn) + } + reset(resetBtn) + } + + const original_onConfigure = nodeType.prototype.onConfigure + nodeType.prototype.onConfigure = function (...args: unknown[]) { + original_onConfigure?.apply(this, ...args) + const resetBtn = findWidget(this, 'reset_btn') + if (resetBtn) reset(resetBtn) + } +} diff --git a/src/ts/register.ts b/src/ts/register.ts index ee4c80e..a809775 100644 --- a/src/ts/register.ts +++ b/src/ts/register.ts @@ -9,7 +9,11 @@ import { setupDynamicConnections } from '~/shared/dynamic_connections.js' import { QUEUE_STATUS } from '~/widgets/queue.js' import { HIDDEN, BTN, ERROR_DISPLAY, SELECTION_LIST } from '~/widgets/misc.js' import { OutputConfigBackend, OutputConfigLocal } from '~/nodes/config.js' -import { ListFromMultiline, ListFromSelection } from '~/nodes/list.js' +import { + ListFromMultiline, + ListFromSelection, + ListRandomSeeds, +} from '~/nodes/list.js' import { InputMultiline } from '~/nodes/input.js' import { DebugJSONYAML, DebugWidgetVisibility } from '~/nodes/debug.js' @@ -57,6 +61,9 @@ app.registerExtension({ case 'ListSchedulers': ListFromSelection(nodeType, 'scheduler') break + case 'ListRandomSeeds': + ListRandomSeeds(nodeType) + break // INPUT case 'InputMultiline': InputMultiline(nodeType) diff --git a/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/LoRA testing - epochs vs random seeds.json b/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/LoRA testing - epochs vs random seeds.json index 6932438..0baa1fb 100644 --- a/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/LoRA testing - epochs vs random seeds.json +++ b/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/LoRA testing - epochs vs random seeds.json @@ -1,6 +1,6 @@ { - "last_node_id": 31, - "last_link_id": 50, + "last_node_id": 32, + "last_link_id": 51, "nodes": [ { "id": 10, @@ -778,7 +778,7 @@ { "name": "dim2", "type": "LIST", - "link": 50, + "link": 51, "shape": 6, "label": "dim2 (opt)" } @@ -957,7 +957,7 @@ "bgcolor": "#3f5159" }, { - "id": 31, + "id": 32, "type": "ListRandomSeeds", "pos": [ -130, @@ -965,7 +965,7 @@ ], "size": [ 230, - 80 + 102 ], "flags": {}, "order": 4, @@ -976,9 +976,8 @@ "name": "list", "type": "LIST", "links": [ - 50 - ], - "slot_index": 0 + 51 + ] }, { "name": "count", @@ -990,7 +989,8 @@ "Node name for S&R": "ListRandomSeeds" }, "widgets_values": [ - 3 + 3, + 1738158785373 ], "color": "#232", "bgcolor": "#353" @@ -1222,8 +1222,8 @@ "INT" ], [ - 50, - 31, + 51, + 32, 0, 16, 1, @@ -1234,15 +1234,15 @@ "config": {}, "extra": { "ds": { - "scale": 0.9090909090909091, + "scale": 1.6808936603591031, "offset": [ - 435.64777679120135, - 222.60346593966682 + 180.8378676307794, + 164.9507228954187 ] }, "node_versions": { "comfy-core": "0.3.10", - "ComfyLab-Pack": "a5b98e8f22d230e90c12de548f71815788f2d50d" + "ComfyLab-Pack": "97697d8542327e3825980ee57f250646c25a6b0d" } }, "version": 0.4 diff --git a/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/LoRA testing - epochs vs random seeds.png b/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/LoRA testing - epochs vs random seeds.png index d813663..4ddcd64 100644 Binary files a/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/LoRA testing - epochs vs random seeds.png and b/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/LoRA testing - epochs vs random seeds.png differ diff --git a/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/README.md b/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/README.md index 2c9dc12..0526d0c 100644 --- a/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/README.md +++ b/wiki/examples/XY Plot/LoRA testing/Epochs vs Seeds/README.md @@ -79,4 +79,4 @@ Load either `LoRA testing - epochs vs random seeds.json` or `LoRA testing - epoc This example is similar to first one, except that we replace the `List: from Multiline` node with `List: Random Seeds`. -Thanks to it, we generate a new list of random seeds each time we generate a new grid. +Thanks to it, we generate a new list of random seeds each time we want: either by refreshing the page, or by clicking the `Reset` button. diff --git a/wiki/tutorials/XY Plot/3 - complex variations/README.md b/wiki/tutorials/XY Plot/3 - complex variations/README.md index 0ec8163..c31c1e5 100644 --- a/wiki/tutorials/XY Plot/3 - complex variations/README.md +++ b/wiki/tutorials/XY Plot/3 - complex variations/README.md @@ -13,7 +13,7 @@ Each of these approaches will generate the same results: depending on your speci > [!TIP] > In the following, we vary checkpoints vs a fixed list of seeds. -> If you prefer to have a new set of **random seeds** each time you generate the grid, just replace the corresponding `List: ftom Multiline` node with `List: Random Seeds`. +> If you prefer to have a new set of **random seeds** each time you want, just replace the corresponding `List: ftom Multiline` node with `List: Random Seeds`. Tutorial sections: