Prompt serializer and test fixes

This commit is contained in:
space-nuko
2023-05-20 21:42:38 -05:00
parent 8d031120f7
commit 09e806bd3e
17 changed files with 196 additions and 106 deletions

View File

@@ -42,7 +42,7 @@ import type { ComfyBoxStdPrompt } from "$lib/ComfyBoxStdPrompt";
import ComfyBoxStdPromptSerializer from "$lib/ComfyBoxStdPromptSerializer";
import selectionState from "$lib/stores/selectionState";
import layoutStates from "$lib/stores/layoutStates";
import { ComfyWorkflow } from "$lib/stores/workflowState";
import { ComfyWorkflow, type WorkflowAttributes } from "$lib/stores/workflowState";
import workflowState from "$lib/stores/workflowState";
export const COMFYBOX_SERIAL_VERSION = 1;
@@ -80,8 +80,8 @@ export type SerializedAppState = {
commitHash?: string,
/** Graph state */
workflow: SerializedLGraph,
/** Workflow name */
workflowName: string,
/** Workflow attributes */
attrs: WorkflowAttributes,
/** UI state */
layout: SerializedLayoutState,
/** Position/offset of the canvas at the time of saving */
@@ -165,7 +165,7 @@ export default class ComfyApp {
async setup(): Promise<void> {
if (get(this.alreadySetup)) {
console.error("Already setup")
console.log("Already setup")
return;
}
@@ -241,7 +241,7 @@ export default class ComfyApp {
if (layoutState == null)
throw new Error("Workflow has no layout!")
const { graph, layout } = workflow.serialize(layoutState);
const { graph, layout, attrs } = workflow.serialize(layoutState);
const canvas = this.lCanvas.serialize();
return {
@@ -249,6 +249,7 @@ export default class ComfyApp {
version: COMFYBOX_SERIAL_VERSION,
commitHash: __GIT_COMMIT_HASH__,
workflow: graph,
attrs,
layout,
canvas
}
@@ -566,7 +567,7 @@ export default class ComfyApp {
}
}
if (get(workflow.layout).attrs.queuePromptButtonRunWorkflow) {
if (workflow.attrs.queuePromptButtonRunWorkflow) {
// Hold control to queue at the front
const num = this.ctrlDown ? -1 : 0;
this.queuePrompt(num, 1);

View File

@@ -35,7 +35,15 @@ export function isActiveBackendNode(node: LGraphNode, tag: string | null = null)
if (!(node as any).isBackendNode)
return false;
return isActiveNode(node, tag);
if (!isActiveNode(node, tag))
return false;
// Make sure this node is not contained in an inactive subgraph, even if the
// node itself is active
if (node.is(Subgraph) && !Array.from(node.iterateParentNodes()).every(n => isActiveNode(n, tag)))
return false;
return true;
}
export class UpstreamNodeLocator {
@@ -166,7 +174,7 @@ export default class ComfyPromptSerializer {
// We don't check tags for non-backend nodes.
// Just check for node inactivity (so you can toggle groups of
// tagged frontend nodes on/off)
if (inputNode && inputNode.mode === NodeMode.NEVER) {
if (inputNode && inputNode.mode !== NodeMode.ALWAYS) {
console.debug("Skipping inactive node", inputNode)
continue;
}
@@ -248,6 +256,8 @@ export default class ComfyPromptSerializer {
const inputs = this.serializeInputValues(node);
const links = this.serializeBackendLinks(node, tag);
console.warn("OUTPUT", node.id, node.comfyClass, node.mode)
output[String(node.id)] = {
inputs: { ...inputs, ...links },
class_type: node.comfyClass,

View File

@@ -4,6 +4,7 @@
import { LGraphNode } from "@litegraph-ts/core"
import { type IDragItem, type WidgetLayout, ALL_ATTRIBUTES, type AttributesSpec, type WritableLayoutStateStore } from "$lib/stores/layoutStates"
import uiState from "$lib/stores/uiState"
import workflowState from "$lib/stores/workflowState"
import layoutStates from "$lib/stores/layoutStates"
import selectionState from "$lib/stores/selectionState"
import { get, type Writable, writable } from "svelte/store"
@@ -127,7 +128,10 @@
if (spec.location !== "workflow")
return false;
return spec.name in $layoutState.attrs
if (workflow == null)
return false;
return spec.name in workflow.attrs
}
function getAttribute(target: IDragItem, spec: AttributesSpec): any {
@@ -240,7 +244,10 @@
}
function getWorkflowAttribute(spec: AttributesSpec): any {
let value = $layoutState.attrs[spec.name]
if (workflow == null)
throw new Error("Active workflow is null!");
let value = workflow.attrs[spec.name]
if (value == null)
value = spec.defaultValue
else if (spec.serialize)
@@ -253,17 +260,20 @@
if (!spec.editable)
return;
if (workflow == null)
throw new Error("Active workflow is null!");
const name = spec.name
// console.warn("[ComfyProperties] updateWorkflowAttribute", name, value)
const prevValue = value
$layoutState.attrs[name] = value
$layoutState = $layoutState
workflow.attrs[name] = value
$workflowState = $workflowState;
if (spec.onChanged)
spec.onChanged($layoutState, value, prevValue)
if (spec.refreshPanelOnChange)
// if (spec.refreshPanelOnChange)
doRefreshPanel()
}

View File

@@ -13,6 +13,7 @@
import { tick } from "svelte";
import Modal from "./Modal.svelte";
import DropZone from "./DropZone.svelte";
import workflowState from "$lib/stores/workflowState";
export let app: ComfyApp;
@@ -71,10 +72,17 @@
const subgraphs: string[] | null = entry.extraData?.extra_pnginfo?.comfyBoxSubgraphs;
let message = "Prompt";
if (subgraphs?.length > 0)
message = `Prompt: ${subgraphs.join(', ')}`
if (entry.workflowID != null) {
const workflow = workflowState.getWorkflow(entry.workflowID);
if (workflow != null && workflow.attrs.title) {
message = `Workflow: ${workflow.attrs.title}`
}
if (subgraphs?.length > 0)
message += ` (${subgraphs.join(', ')})`
}
let submessage = `Nodes: ${Object.keys(entry.prompt).length}`
if (Object.keys(entry.outputs).length > 0) {
const imageCount = Object.values(entry.outputs).flatMap(o => o.images).length
submessage = `Images: ${imageCount}`
@@ -84,7 +92,7 @@
entry,
message,
submessage,
dateStr,
date: dateStr,
status: "pending",
images: []
}
@@ -387,7 +395,7 @@
&.all_cached, &.interrupted {
filter: brightness(80%);
color: var(--neutral-300);
color: var(--comfy-accent-soft);
}
}

View File

@@ -10,7 +10,7 @@
import { get, writable, type Writable } from "svelte/store";
import ComfyProperties from "./ComfyProperties.svelte";
import uiState from "$lib/stores/uiState";
import workflowState from "$lib/stores/workflowState";
import workflowState, { ComfyWorkflow } from "$lib/stores/workflowState";
import selectionState from "$lib/stores/selectionState";
import type ComfyApp from './ComfyApp';
import { onMount } from "svelte";
@@ -19,7 +19,7 @@
export let app: ComfyApp;
export let uiTheme: string = "gradio-dark" // TODO config
let layoutState: WritableLayoutStateStore | null = null;
let workflow: ComfyWorkflow | null = null;
let containerElem: HTMLDivElement;
let resizeTimeout: NodeJS.Timeout | null;
@@ -29,7 +29,7 @@
let appSetupPromise: Promise<void> = null;
$: layoutState = $workflowState.activeWorkflow?.layout;
$: workflow = $workflowState.activeWorkflow;
onMount(async () => {
appSetupPromise = app.setup().then(() => {
@@ -189,10 +189,10 @@
<button class="workflow-tab"
class:selected={index === $workflowState.activeWorkflowIdx}
on:click={() => app.setActiveWorkflow(index)}>
<span class="workflow-tab-title">{workflow.title}</span>
<span class="workflow-tab-title">{workflow.attrs.title}</span>
<button class="workflow-close-button"
on:click={(e) => closeWorkflow(e, index)}>
X
</button>
</button>
{/each}
@@ -200,9 +200,9 @@
<div id="bottombar">
<div class="bottombar-content">
<div class="left">
{#if layoutState != null && $layoutState.attrs.queuePromptButtonName != ""}
{#if workflow != null && workflow.attrs.queuePromptButtonName != ""}
<Button variant="primary" disabled={!$alreadySetup} on:click={queuePrompt}>
{$layoutState.attrs.queuePromptButtonName}
{workflow.attrs.queuePromptButtonName}
</Button>
{/if}
<Button variant="secondary" disabled={!$alreadySetup} on:click={toggleGraph}>
@@ -395,11 +395,12 @@
width: 1.5rem;
height: 1.5rem;
border-radius: 50%;
opacity: 50%;
background: var(--neutral-500);
color: var(--neutral-300);
&:hover {
background: var(--neutral-400);
opacity: 100%;
color: var(--neutral-100);
}
}