Better seed randomizer
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {}
|
||||
@@ -1,3 +1,2 @@
|
||||
export { default as ComfyReroute } from "./ComfyReroute"
|
||||
export { ComfySaveImageNode, ComfyPreviewImageNode } from "./ComfyImageNodes"
|
||||
export { ComfyKSamplerNode, ComfyKSamplerAdvancedNode } from "./ComfyKSamplerNodes"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -9,4 +9,5 @@ export interface ComfyGalleryWidgetOptions extends WidgetPanelOptions {
|
||||
|
||||
export default class ComfyGalleryWidget extends ComfyWidget<ComfyGalleryWidgetOptions, ComfyGalleryEntry[]> {
|
||||
override type = "comfy/gallery";
|
||||
override isVirtual = true;
|
||||
}
|
||||
|
||||
55
src/lib/widgets/ComfyValueControlWidget.ts
Normal file
55
src/lib/widgets/ComfyValueControlWidget.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user