temp
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
import workflowState from '$lib/stores/workflowState';
|
import workflowState from '$lib/stores/workflowState';
|
||||||
import type { WritableJourneyStateStore } from '$lib/stores/journeyStates';
|
import type { WritableJourneyStateStore } from '$lib/stores/journeyStates';
|
||||||
import JourneyRenderer from './JourneyRenderer.svelte';
|
import JourneyRenderer from './JourneyRenderer.svelte';
|
||||||
|
import { Plus } from "svelte-bootstrap-icons";
|
||||||
|
|
||||||
export let app: ComfyApp;
|
export let app: ComfyApp;
|
||||||
|
|
||||||
@@ -21,11 +22,42 @@
|
|||||||
|
|
||||||
<div class="journey-view">
|
<div class="journey-view">
|
||||||
<JourneyRenderer {workflow} {journey} />
|
<JourneyRenderer {workflow} {journey} />
|
||||||
|
<div class="bottom">
|
||||||
|
<button class="mode-button ternary"
|
||||||
|
title={"Add new"}
|
||||||
|
on:click={() => {}}>
|
||||||
|
<Plus width="100%" height="100%" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
$button-height: 2.5rem;
|
||||||
|
|
||||||
.journey-view {
|
.journey-view {
|
||||||
width: 100%;
|
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>
|
</style>
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ export interface RestoreParamSource<T extends RestoreParamType = any> {
|
|||||||
*/
|
*/
|
||||||
export interface RestoreParamSourceWorkflowNode extends RestoreParamSource<"workflow"> {
|
export interface RestoreParamSourceWorkflowNode extends RestoreParamSource<"workflow"> {
|
||||||
type: "workflow",
|
type: "workflow",
|
||||||
|
|
||||||
sourceNode: SerializedComfyWidgetNode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type RestoreParamWorkflowNodeTargets = Record<NodeID, RestoreParamSourceWorkflowNode>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A value received by the ComfyUI *backend* that corresponds to a value that
|
* 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
|
* 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.
|
* 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"> {
|
export interface RestoreParamSourceStdPrompt<T, K extends keyof T> extends RestoreParamSource<"stdPrompt"> {
|
||||||
type: "stdPrompt",
|
type: "stdPrompt",
|
||||||
@@ -102,19 +105,7 @@ export interface RestoreParamSourceStdPrompt<T, K extends keyof T> extends Resto
|
|||||||
finalValue: any
|
finalValue: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RestoreParamTarget = {
|
export type RestoreParamTargets = Record<NodeID, RestoreParamSource[]>
|
||||||
/*
|
|
||||||
* 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>
|
|
||||||
|
|
||||||
function isSerializedComfyWidgetNode(param: any): param is SerializedComfyWidgetNode {
|
function isSerializedComfyWidgetNode(param: any): param is SerializedComfyWidgetNode {
|
||||||
return param != null && typeof param === "object" && "id" in param && "comfyValue" in param
|
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) => {
|
const addSource = (result: RestoreParamTargets, targetNode: ComfyWidgetNode, source: RestoreParamSource) => {
|
||||||
result[targetNode.id] ||= { targetNode, sources: [] }
|
result[targetNode.id] ||= []
|
||||||
result[targetNode.id].sources.push(source);
|
result[targetNode.id].push(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mergeSources = (a: RestoreParamTargets, b: RestoreParamTargets) => {
|
export function concatRestoreParams(a: RestoreParamTargets, b: Record<NodeID, RestoreParamSource>): RestoreParamTargets {
|
||||||
for (const [k, vs] of Object.entries(b)) {
|
for (const [targetNodeID, source] of Object.entries(b)) {
|
||||||
a[vs.targetNode.id] ||= { targetNode: vs.targetNode, sources: [] }
|
a[targetNodeID] ||= []
|
||||||
for (const source of vs.sources) {
|
a[targetNodeID].push(source);
|
||||||
a[vs.targetNode.id].sources.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 result = {}
|
||||||
|
|
||||||
const graph = workflow.graph;
|
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) {
|
for (const serNode of prompt.workflow.nodes) {
|
||||||
const foundNode = graph.getNodeByIdRecursive(serNode.id);
|
const foundNode = graph.getNodeByIdRecursive(serNode.id);
|
||||||
if (isComfyWidgetNode(foundNode) && foundNode.type === serNode.type) {
|
if (isComfyWidgetNode(foundNode) && foundNode.type === serNode.type) {
|
||||||
@@ -172,9 +174,8 @@ export function getWorkflowRestoreParams(workflow: ComfyBoxWorkflow, prompt: Ser
|
|||||||
const source: RestoreParamSourceWorkflowNode = {
|
const source: RestoreParamSourceWorkflowNode = {
|
||||||
type: "workflow",
|
type: "workflow",
|
||||||
finalValue,
|
finalValue,
|
||||||
sourceNode: serNode
|
|
||||||
}
|
}
|
||||||
addSource(result, foundNode, source)
|
result[foundNode.id] = source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,11 +183,14 @@ export function getWorkflowRestoreParams(workflow: ComfyBoxWorkflow, prompt: Ser
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): RestoreParamTargets {
|
export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): Record<NodeID, RestoreParamSourceBackendNodeInput[]> {
|
||||||
const result = {}
|
const result = {}
|
||||||
|
|
||||||
const graph = workflow.graph;
|
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)) {
|
for (const [serNodeID, inputs] of Object.entries(prompt.output)) {
|
||||||
const serNode = prompt.workflow.nodes.find(sn => sn.id === serNodeID)
|
const serNode = prompt.workflow.nodes.find(sn => sn.id === serNodeID)
|
||||||
if (serNode == null)
|
if (serNode == null)
|
||||||
@@ -223,16 +227,11 @@ export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: Seri
|
|||||||
export default function restoreParameters(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): RestoreParamTargets {
|
export default function restoreParameters(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): RestoreParamTargets {
|
||||||
const result = {}
|
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);
|
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);
|
const backendParams = getBackendRestoreParams(workflow, prompt);
|
||||||
mergeSources(result, backendParams);
|
concatRestoreParams2(result, backendParams);
|
||||||
|
|
||||||
// Step 3: Extract the standard prompt from the workflow and use that to
|
// Step 3: Extract the standard prompt from the workflow and use that to
|
||||||
// infer parameter types
|
// infer parameter types
|
||||||
|
|||||||
@@ -1,7 +1,66 @@
|
|||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import type { Readable, Writable } from 'svelte/store';
|
import type { Readable, Writable } from 'svelte/store';
|
||||||
import type { DragItemID, IDragItem } from './layoutStates';
|
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
|
* 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.
|
* jump between past and present sets of parameters.
|
||||||
*/
|
*/
|
||||||
export type JourneyState = {
|
export type JourneyState = {
|
||||||
/*
|
tree: JourneyNode,
|
||||||
* Selected drag items.
|
nodesByID: Record<JourneyNodeID, JourneyNode>
|
||||||
* 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>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type JourneyStateOps = {
|
type JourneyStateOps = {
|
||||||
@@ -41,18 +81,10 @@ export type WritableJourneyStateStore = Writable<JourneyState> & JourneyStateOps
|
|||||||
function create() {
|
function create() {
|
||||||
const store: Writable<JourneyState> = writable(
|
const store: Writable<JourneyState> = writable(
|
||||||
{
|
{
|
||||||
currentJourney: [],
|
|
||||||
currentJourneyNodes: [],
|
|
||||||
currentHovered: new Set(),
|
|
||||||
currentHoveredNodes: new Set(),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function clear() {
|
function clear() {
|
||||||
store.set({
|
store.set({
|
||||||
currentJourney: [],
|
|
||||||
currentJourneyNodes: [],
|
|
||||||
currentHovered: new Set(),
|
|
||||||
currentHoveredNodes: new Set(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user