temp
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
import workflowState from '$lib/stores/workflowState';
|
||||
import type { WritableJourneyStateStore } from '$lib/stores/journeyStates';
|
||||
import JourneyRenderer from './JourneyRenderer.svelte';
|
||||
import { Plus } from "svelte-bootstrap-icons";
|
||||
|
||||
export let app: ComfyApp;
|
||||
|
||||
@@ -21,11 +22,42 @@
|
||||
|
||||
<div class="journey-view">
|
||||
<JourneyRenderer {workflow} {journey} />
|
||||
<div class="bottom">
|
||||
<button class="mode-button ternary"
|
||||
title={"Add new"}
|
||||
on:click={() => {}}>
|
||||
<Plus width="100%" height="100%" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
$button-height: 2.5rem;
|
||||
|
||||
.journey-view {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: calc(100% - $button-height);
|
||||
}
|
||||
|
||||
.bottom {
|
||||
height: $button-height;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
color: var(--comfy-accent-soft);
|
||||
|
||||
.mode-button {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
|
||||
@include square-button;
|
||||
|
||||
&:hover {
|
||||
color: var(--body-text-color);
|
||||
}
|
||||
&.selected {
|
||||
background-color: var(--panel-background-fill);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -29,10 +29,10 @@ export interface RestoreParamSource<T extends RestoreParamType = any> {
|
||||
*/
|
||||
export interface RestoreParamSourceWorkflowNode extends RestoreParamSource<"workflow"> {
|
||||
type: "workflow",
|
||||
|
||||
sourceNode: SerializedComfyWidgetNode
|
||||
}
|
||||
|
||||
export type RestoreParamWorkflowNodeTargets = Record<NodeID, RestoreParamSourceWorkflowNode>
|
||||
|
||||
/*
|
||||
* A value received by the ComfyUI *backend* that corresponds to a value that
|
||||
* was held in a ComfyWidgetNode. These may not necessarily be one-to-one
|
||||
@@ -59,6 +59,9 @@ export interface RestoreParamSourceBackendNodeInput extends RestoreParamSource<"
|
||||
|
||||
/*
|
||||
* A value contained in the standard prompt extracted from the saved workflow.
|
||||
*
|
||||
* This should only be necessary to fall back on if one workflow's parameters
|
||||
* are to be used in a completely separate workflow's.
|
||||
*/
|
||||
export interface RestoreParamSourceStdPrompt<T, K extends keyof T> extends RestoreParamSource<"stdPrompt"> {
|
||||
type: "stdPrompt",
|
||||
@@ -102,19 +105,7 @@ export interface RestoreParamSourceStdPrompt<T, K extends keyof T> extends Resto
|
||||
finalValue: any
|
||||
}
|
||||
|
||||
export type RestoreParamTarget = {
|
||||
/*
|
||||
* Node that will receive the parameter from the prompt
|
||||
*/
|
||||
targetNode: ComfyWidgetNode;
|
||||
|
||||
/*
|
||||
* Possible sources of values to insert into the target node
|
||||
*/
|
||||
sources: RestoreParamSource[]
|
||||
}
|
||||
|
||||
export type RestoreParamTargets = Record<NodeID, RestoreParamTarget>
|
||||
export type RestoreParamTargets = Record<NodeID, RestoreParamSource[]>
|
||||
|
||||
function isSerializedComfyWidgetNode(param: any): param is SerializedComfyWidgetNode {
|
||||
return param != null && typeof param === "object" && "id" in param && "comfyValue" in param
|
||||
@@ -146,24 +137,35 @@ function findUpstreamSerializedWidgetNode(prompt: SerializedPrompt, input: INode
|
||||
}
|
||||
|
||||
const addSource = (result: RestoreParamTargets, targetNode: ComfyWidgetNode, source: RestoreParamSource) => {
|
||||
result[targetNode.id] ||= { targetNode, sources: [] }
|
||||
result[targetNode.id].sources.push(source);
|
||||
result[targetNode.id] ||= []
|
||||
result[targetNode.id].push(source);
|
||||
}
|
||||
|
||||
const mergeSources = (a: RestoreParamTargets, b: RestoreParamTargets) => {
|
||||
for (const [k, vs] of Object.entries(b)) {
|
||||
a[vs.targetNode.id] ||= { targetNode: vs.targetNode, sources: [] }
|
||||
for (const source of vs.sources) {
|
||||
a[vs.targetNode.id].sources.push(source);
|
||||
export function concatRestoreParams(a: RestoreParamTargets, b: Record<NodeID, RestoreParamSource>): RestoreParamTargets {
|
||||
for (const [targetNodeID, source] of Object.entries(b)) {
|
||||
a[targetNodeID] ||= []
|
||||
a[targetNodeID].push(source);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
export function concatRestoreParams2(a: RestoreParamTargets, b: RestoreParamTargets): RestoreParamTargets {
|
||||
for (const [targetNodeID, vs] of Object.entries(b)) {
|
||||
a[targetNodeID] ||= []
|
||||
for (const source of vs) {
|
||||
a[targetNodeID].push(source);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
export function getWorkflowRestoreParams(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): RestoreParamTargets {
|
||||
export function getWorkflowRestoreParams(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): RestoreParamWorkflowNodeTargets {
|
||||
const result = {}
|
||||
|
||||
const graph = workflow.graph;
|
||||
|
||||
// Find nodes that correspond to *this* workflow exactly, since we can
|
||||
// easily match up the nodes between each (their IDs will be the same)
|
||||
for (const serNode of prompt.workflow.nodes) {
|
||||
const foundNode = graph.getNodeByIdRecursive(serNode.id);
|
||||
if (isComfyWidgetNode(foundNode) && foundNode.type === serNode.type) {
|
||||
@@ -172,9 +174,8 @@ export function getWorkflowRestoreParams(workflow: ComfyBoxWorkflow, prompt: Ser
|
||||
const source: RestoreParamSourceWorkflowNode = {
|
||||
type: "workflow",
|
||||
finalValue,
|
||||
sourceNode: serNode
|
||||
}
|
||||
addSource(result, foundNode, source)
|
||||
result[foundNode.id] = source;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,11 +183,14 @@ export function getWorkflowRestoreParams(workflow: ComfyBoxWorkflow, prompt: Ser
|
||||
return result
|
||||
}
|
||||
|
||||
export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): RestoreParamTargets {
|
||||
export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): Record<NodeID, RestoreParamSourceBackendNodeInput[]> {
|
||||
const result = {}
|
||||
|
||||
const graph = workflow.graph;
|
||||
|
||||
// Figure out what parameters the backend received. If there was a widget
|
||||
// node attached to a backend node's input upstream, then we can use that
|
||||
// value.
|
||||
for (const [serNodeID, inputs] of Object.entries(prompt.output)) {
|
||||
const serNode = prompt.workflow.nodes.find(sn => sn.id === serNodeID)
|
||||
if (serNode == null)
|
||||
@@ -223,16 +227,11 @@ export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: Seri
|
||||
export default function restoreParameters(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): RestoreParamTargets {
|
||||
const result = {}
|
||||
|
||||
// Step 1: Find nodes that correspond to *this* workflow exactly, since we
|
||||
// can easily match up the nodes between each (their IDs will be the same)
|
||||
const workflowParams = getWorkflowRestoreParams(workflow, prompt);
|
||||
mergeSources(result, workflowParams);
|
||||
concatRestoreParams(result, workflowParams);
|
||||
|
||||
// Step 2: Figure out what parameters the backend received. If there was a
|
||||
// widget node attached to a backend node's input upstream, then we can
|
||||
// use that value.
|
||||
const backendParams = getBackendRestoreParams(workflow, prompt);
|
||||
mergeSources(result, backendParams);
|
||||
concatRestoreParams2(result, backendParams);
|
||||
|
||||
// Step 3: Extract the standard prompt from the workflow and use that to
|
||||
// infer parameter types
|
||||
|
||||
@@ -1,7 +1,66 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import type { Readable, Writable } from 'svelte/store';
|
||||
import type { DragItemID, IDragItem } from './layoutStates';
|
||||
import type { LGraphNode, NodeID } from '@litegraph-ts/core';
|
||||
import type { LGraphNode, NodeID, UUID } from '@litegraph-ts/core';
|
||||
import type { SerializedAppState } from '$lib/components/ComfyApp';
|
||||
import type { RestoreParamTargets, RestoreParamWorkflowNodeTargets } from '$lib/restoreParameters';
|
||||
|
||||
export type JourneyNodeType = "root" | "patch";
|
||||
|
||||
export type JourneyNodeID = UUID;
|
||||
|
||||
export interface JourneyNode {
|
||||
id: JourneyNodeID,
|
||||
type: JourneyNodeType,
|
||||
children: JourneyPatchNode[]
|
||||
}
|
||||
|
||||
export interface JourneyRootNode extends JourneyNode {
|
||||
type: "root"
|
||||
|
||||
/*
|
||||
* This contains all the values of the workflow to set
|
||||
*/
|
||||
base: RestoreParamWorkflowNodeTargets
|
||||
}
|
||||
|
||||
export interface JourneyPatchNode extends JourneyNode {
|
||||
type: "patch"
|
||||
|
||||
parent: JourneyNode,
|
||||
|
||||
/*
|
||||
* This contains only the subset of parameters that were changed from the
|
||||
* parent
|
||||
*/
|
||||
patch: RestoreParamWorkflowNodeTargets
|
||||
}
|
||||
|
||||
export function resolvePatch(node: JourneyNode): RestoreParamWorkflowNodeTargets {
|
||||
if (node.type === "root") {
|
||||
return { ...(node as JourneyRootNode).base }
|
||||
}
|
||||
|
||||
const patchNode = (node as JourneyPatchNode);
|
||||
const patch = { ...patchNode.patch };
|
||||
const base = resolvePatch(patchNode.parent);
|
||||
for (const [k, v] of Object.entries(patch)) {
|
||||
base[k] = v;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
function diffParams(base: RestoreParamWorkflowNodeTargets, updated: RestoreParamWorkflowNodeTargets): RestoreParamWorkflowNodeTargets {
|
||||
const result = {}
|
||||
|
||||
for (const [k, v] of Object.entries(updated)) {
|
||||
if (!(k in base) || base[k].finalValue !== v) {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* A "journey" is like browser history for prompts, except organized in a
|
||||
@@ -9,27 +68,8 @@ import type { LGraphNode, NodeID } from '@litegraph-ts/core';
|
||||
* jump between past and present sets of parameters.
|
||||
*/
|
||||
export type JourneyState = {
|
||||
/*
|
||||
* Selected drag items.
|
||||
* NOTE: Order is important, for node grouping actions.
|
||||
*/
|
||||
currentJourney: DragItemID[],
|
||||
|
||||
/*
|
||||
* Hovered drag items.
|
||||
*/
|
||||
currentHovered: Set<DragItemID>,
|
||||
|
||||
/*
|
||||
* Selected LGraphNodes inside the litegraph canvas.
|
||||
* NOTE: Order is important, for node grouping actions.
|
||||
*/
|
||||
currentJourneyNodes: LGraphNode[],
|
||||
|
||||
/*
|
||||
* Currently hovered nodes.
|
||||
*/
|
||||
currentHoveredNodes: Set<NodeID>
|
||||
tree: JourneyNode,
|
||||
nodesByID: Record<JourneyNodeID, JourneyNode>
|
||||
}
|
||||
|
||||
type JourneyStateOps = {
|
||||
@@ -41,18 +81,10 @@ export type WritableJourneyStateStore = Writable<JourneyState> & JourneyStateOps
|
||||
function create() {
|
||||
const store: Writable<JourneyState> = writable(
|
||||
{
|
||||
currentJourney: [],
|
||||
currentJourneyNodes: [],
|
||||
currentHovered: new Set(),
|
||||
currentHoveredNodes: new Set(),
|
||||
})
|
||||
|
||||
function clear() {
|
||||
store.set({
|
||||
currentJourney: [],
|
||||
currentJourneyNodes: [],
|
||||
currentHovered: new Set(),
|
||||
currentHoveredNodes: new Set(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user