Better seed randomizer

This commit is contained in:
space-nuko
2023-04-25 07:34:27 -07:00
parent cd0fde0f55
commit f0a520b9a1
11 changed files with 108 additions and 92 deletions

View File

@@ -206,8 +206,6 @@ export default class ComfyApp {
private registerNodeTypeOverrides() {
ComfyApp.node_type_overrides["SaveImage"] = nodes.ComfySaveImageNode;
ComfyApp.node_type_overrides["PreviewImage"] = nodes.ComfyPreviewImageNode;
ComfyApp.node_type_overrides["KSampler"] = nodes.ComfyKSamplerNode;
ComfyApp.node_type_overrides["KSamplerAdvanced"] = nodes.ComfyKSamplerAdvancedNode;
}
private registerWidgetTypeOverrides() {
@@ -389,10 +387,6 @@ export default class ComfyApp {
this.api.addEventListener("executing", ({ detail }: CustomEvent) => {
queueState.executingUpdated(detail.node);
const node = this.lGraph.getNodeById(detail.node) as ComfyGraphNode;
if (node?.onExecuting) {
node.onExecuting();
}
this.lGraph.setDirtyCanvas(true, false);
});
@@ -496,7 +490,10 @@ export default class ComfyApp {
if (widgets) {
for (let i = 0; i < widgets.length; i++) {
const widget = widgets[i];
if (!widget.options || widget.options.serialize !== false) {
let isVirtual = false;
if ("isVirtual" in widget)
isVirtual = (widget as ComfyWidget<any, any>).isVirtual;
if ((!widget.options || widget.options.serialize !== false) && !isVirtual) {
let value = widget.serializeValue ? await widget.serializeValue(n, i) : widget.value;
inputs[widget.name] = value
}
@@ -575,9 +572,9 @@ export default class ComfyApp {
for (const widget of node.widgets) {
// Allow widgets to run callbacks after a prompt has been queued
// e.g. random seed after every gen
// if (widget.afterQueued) {
// widget.afterQueued();
// }
if ("afterQueued" in widget) {
(widget as ComfyWidget<any, any>).afterQueued();
}
}
}
}

View File

@@ -60,20 +60,18 @@
let ctor: any = null;
// custom widgets with TypeScript sources
if (item.isVirtual) {
let override = ComfyApp.widget_type_overrides[item.widget.type]
if (override) {
return override;
}
let override = ComfyApp.widget_type_overrides[item.widget.type]
if (override) {
return override;
}
// litegraph.ts built-in widgets
switch (item.widget.type) {
case "combo":
case "combo":
return ComboWidget;
case "number":
case "number":
return RangeWidget;
case "text":
case "text":
return TextWidget;
}
@@ -81,8 +79,7 @@
}
function updateNodeName(node: LGraphNode, value: string) {
console.log("CHA")
nodeState.nodeStateChanged(node);
nodeState.nodeStateChanged(node);
}
</script>
@@ -98,20 +95,20 @@
<div class="animation-wrapper" class:is-executing={dragItem.isNodeExecuting} animate:flip={{duration:flipDurationMs}}>
<Block>
{#if $uiState.unlocked}
<div class="handle" on:mousedown={startDrag} on:touchstart={startDrag} on:mouseup={stopDrag} on:touchend={stopDrag}>
<Move/>
</div>
<div class="handle" on:mousedown={startDrag} on:touchstart={startDrag} on:mouseup={stopDrag} on:touchend={stopDrag}>
<Move/>
</div>
{/if}
<label for={String(id)}>
<BlockTitle>
{#if $uiState.unlocked}
<input bind:value={dragItem.node.title} type="text" minlength="1" on:input="{(v) => { updateNodeName(node, v) }}"/>
{:else}
{node.title}
{/if}
{#if node.title !== node.type}
<span class="node-type">({node.type})</span>
{/if}
{#if $uiState.unlocked}
<input bind:value={dragItem.node.title} type="text" minlength="1" on:input="{(v) => { updateNodeName(node, v) }}"/>
{:else}
{node.title}
{/if}
{#if node.title !== node.type}
<span class="node-type">({node.type})</span>
{/if}
</BlockTitle>
</label>
{#each $widgetState[id] as item}
@@ -166,7 +163,7 @@
}
.node-type {
font-size: smaller;
color: var(--neutral-400);
}
font-size: smaller;
color: var(--neutral-400);
}
</style>

View File

@@ -4,12 +4,6 @@ import { LGraphNode } from "@litegraph-ts/core";
export default class ComfyGraphNode extends LGraphNode {
isVirtualNode: boolean = false;
/*
* Widgets that aren't a part of the graph, but are used for rendering
* purposes only.
*/
virtualWidgets: ComfyWidget[] = [];
onExecuting?(): void;
afterQueued?(): void;
onExecuted?(output: any): void;
}

View File

@@ -20,7 +20,7 @@ class ComfyImageNode extends ComfyGraphNode {
constructor(title?: any) {
super(title)
this._galleryWidget = new ComfyGalleryWidget("Images", [], this);
this.virtualWidgets.push(this._galleryWidget)
this.addCustomWidget(this._galleryWidget);
}
override onExecuted(output: ComfyImageExecOutput) {

View File

@@ -1,34 +0,0 @@
import { get } from 'svelte/store';
import ComfyGraphNode from "./ComfyGraphNode";
import widgetState from "$lib/stores/widgetState"
/*
* Autorefreshes seed (until bangs/main inlets are implemented)
*/
class ComfyBaseKSamplerNode extends ComfyGraphNode {
constructor(title?: any) {
super(title)
}
override onExecuting() {
console.log(this);
const widget = widgetState.findWidgetByName(this.id, "seed")
if (!widget)
return;
// TODO cleanup&remove
let min = widget.widget.options.min;
let max = widget.widget.options.max;
// limit to something that javascript can handle
max = Math.min(1125899906842624, max);
min = Math.max(-1125899906842624, min);
const range = (max - min) / (widget.widget.options.step);
const v = Math.floor(Math.floor(Math.random() * range) * (widget.widget.options.step) + min);
widget.widget.value = v;
widgetState.widgetStateChanged(this.id, widget.widget);
}
}
export class ComfyKSamplerNode extends ComfyBaseKSamplerNode {}
export class ComfyKSamplerAdvancedNode extends ComfyBaseKSamplerNode {}

View File

@@ -1,3 +1,2 @@
export { default as ComfyReroute } from "./ComfyReroute"
export { ComfySaveImageNode, ComfyPreviewImageNode } from "./ComfyImageNodes"
export { ComfyKSamplerNode, ComfyKSamplerAdvancedNode } from "./ComfyKSamplerNodes"

View File

@@ -52,19 +52,13 @@ function nodeAdded(node: LGraphNode) {
let state = get(store)
if (node.widgets) {
for (const widget of node.widgets) {
for (const [index, widget] of node.widgets.entries()) {
if (!state[node.id])
state[node.id] = []
state[node.id].push({ node, widget, value: writable(widget.value), isVirtual: false })
}
}
if ("virtualWidgets" in node) {
const comfyNode = node as ComfyGraphNode;
for (const widget of comfyNode.virtualWidgets) {
if (!state[comfyNode.id])
state[comfyNode.id] = []
state[comfyNode.id].push({ node, widget, value: writable(widget.value), isVirtual: true })
let isVirtual = false;
if ("isVirtual" in widget)
isVirtual = (widget as ComfyWidget<any, any>).isVirtual;
state[node.id].push({ index, node, widget, value: writable(widget.value), isVirtual: isVirtual })
}
}
@@ -103,11 +97,11 @@ function configureFinished(graph: LGraph) {
for (const node of graph.computeExecutionOrder(false, null)) {
if (node.widgets_values) {
for (const [i, value] of node.widgets_values.entries()) {
if (i < state[node.id].length && !state[node.id][i].isVirtual) { // Virtual widgets always come after real widgets
if (i < state[node.id].length && !state[node.id][i].isVirtual) {
state[node.id][i].value.set(value);
}
else {
console.error("Mismatch in widgets_values!", state[node.id].map(i => i.value), node.widgets_values)
console.error("Mismatch in widgets_values!", node.id, node.type, state[node.id].map(i => get(i.value)), node.widgets_values)
break;
}
}

View File

@@ -1,5 +1,6 @@
import type { IWidget, LGraphNode } from "@litegraph-js/core";
import type ComfyApp from "$lib/components/ComfyApp";
import ComfyValueControlWidget from "./widgets/ComfyValueControlWidget";
export interface WidgetData {
widget: IWidget,
@@ -48,6 +49,15 @@ const INT: WidgetFactory = (node: LGraphNode, inputName: string, inputData: any)
};
};
function seedWidget(node, inputName, inputData, app) {
const seed = INT(node, inputName, inputData, app);
const seedControl = new ComfyValueControlWidget("control_after_generate", "randomize", node, seed.widget);
node.addCustomWidget(seedControl);
// seed.widget.linkedWidgets = [seedControl];
return seed;
}
const STRING: WidgetFactory = (node: LGraphNode, inputName: string, inputData: any, app: ComfyApp): WidgetData => {
const defaultVal = inputData[1].default || "";
const multiline = !!inputData[1].multiline;
@@ -127,8 +137,8 @@ const IMAGEUPLOAD: WidgetFactory = (node: LGraphNode, inputName: string, inputDa
export type WidgetRepository = Record<string, WidgetFactory>
export const ComfyWidgets: WidgetRepository = {
"INT:seed": INT,
"INT:noise_seed": INT,
"INT:seed": seedWidget,
"INT:noise_seed": seedWidget,
FLOAT,
INT,
STRING,

View File

@@ -9,4 +9,5 @@ export interface ComfyGalleryWidgetOptions extends WidgetPanelOptions {
export default class ComfyGalleryWidget extends ComfyWidget<ComfyGalleryWidgetOptions, ComfyGalleryEntry[]> {
override type = "comfy/gallery";
override isVirtual = true;
}

View File

@@ -0,0 +1,55 @@
import type { IEnumWidget, IEnumWidgetOptions, INumberWidget, LGraphNode, WidgetPanelOptions } from "@litegraph-ts/core";
import ComfyWidget from "./ComfyWidget";
import type { ComfyImageResult } from "$lib/nodes/ComfySaveImageNode";
import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
import widgetState from "$lib/stores/widgetState"
export interface ComfyValueControlWidgetOptions extends IEnumWidgetOptions {
}
export default class ComfyValueControlWidget extends ComfyWidget<ComfyValueControlWidgetOptions, string> {
override type = "combo";
targetWidget: INumberWidget;
constructor(name: string, value: string, node: ComfyGraphNode, targetWidget: INumberWidget) {
super(name, value, node)
this.targetWidget = targetWidget;
this.options = { values: ["fixed", "increment", "decrement", "randomize"], serialize: false };
}
override afterQueued() {
var v = this.value;
let min = this.targetWidget.options.min;
let max = this.targetWidget.options.max;
// limit to something that javascript can handle
max = Math.min(1125899906842624, max);
min = Math.max(-1125899906842624, min);
let range = (max - min) / (this.targetWidget.options.step);
//adjust values based on valueControl Behaviour
switch (v) {
case "fixed":
break;
case "increment":
this.targetWidget.value += this.targetWidget.options.step;
break;
case "decrement":
this.targetWidget.value -= this.targetWidget.options.step;
break;
case "randomize":
this.targetWidget.value = Math.floor(Math.random() * range) * (this.targetWidget.options.step) + min;
default:
break;
}
/*check if values are over or under their respective
* ranges and set them to min or max.*/
if (this.targetWidget.value < min)
this.targetWidget.value = min;
if (this.targetWidget.value > max)
this.targetWidget.value = max;
widgetState.widgetStateChanged(this.node.id, this.targetWidget);
}
}

View File

@@ -13,6 +13,7 @@ export default abstract class ComfyWidget<T = any, V = any> implements IWidget<T
this.node = node;
}
isVirtual?: boolean;
options?: T;
type?: WidgetTypes | string | any;
y?: number;
@@ -35,5 +36,7 @@ export default abstract class ComfyWidget<T = any, V = any> implements IWidget<T
computeSize?(width: number): [number, number];
afterQueued?(): void;
serializeValue?(serialized: SerializedLGraphNode<LGraphNode>, slot: number): Promise<any>;
}