Linear history mode
This commit is contained in:
@@ -12,10 +12,10 @@
|
|||||||
import type { ComfyBoxWorkflow } from '$lib/stores/workflowState';
|
import type { ComfyBoxWorkflow } from '$lib/stores/workflowState';
|
||||||
import workflowState from '$lib/stores/workflowState';
|
import workflowState from '$lib/stores/workflowState';
|
||||||
import uiState from '$lib/stores/uiState';
|
import uiState from '$lib/stores/uiState';
|
||||||
import { calculateWorkflowParamsPatch, resolvePatch, type JourneyPatchNode, type WritableJourneyStateStore, diffParams, JourneyNode } from '$lib/stores/journeyStates';
|
import { resolvePatch, type JourneyPatchNode, type WritableJourneyStateStore, diffParams, type JourneyNode } from '$lib/stores/journeyStates';
|
||||||
import JourneyRenderer, { type JourneyNodeEvent } from './JourneyRenderer.svelte';
|
import JourneyRenderer, { type JourneyNodeEvent } from './JourneyRenderer.svelte';
|
||||||
import { Trash, ClockHistory, Diagram3 } from "svelte-bootstrap-icons";
|
import { Trash, ClockHistory, Diagram3 } from "svelte-bootstrap-icons";
|
||||||
import { getWorkflowRestoreParams, getWorkflowRestoreParamsFromWorkflow } from '$lib/restoreParameters';
|
import { getWorkflowRestoreParamsFromWorkflow } from '$lib/restoreParameters';
|
||||||
import notify from '$lib/notify';
|
import notify from '$lib/notify';
|
||||||
import selectionState from '$lib/stores/selectionState';
|
import selectionState from '$lib/stores/selectionState';
|
||||||
import { Checkbox } from '@gradio/form';
|
import { Checkbox } from '@gradio/form';
|
||||||
@@ -41,11 +41,6 @@
|
|||||||
$: workflow = $workflowState.activeWorkflow
|
$: workflow = $workflowState.activeWorkflow
|
||||||
$: {
|
$: {
|
||||||
journey = workflow?.journey
|
journey = workflow?.journey
|
||||||
activeNode = null;
|
|
||||||
updateActiveNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateActiveNode() {
|
|
||||||
activeNode = journey?.getActiveNode()
|
activeNode = journey?.getActiveNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +146,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{#key $journey.version}
|
{#key $journey.version}
|
||||||
<JourneyRenderer {workflow} {journey} {mode} {activeNode}
|
<JourneyRenderer {workflow} {journey} {mode}
|
||||||
on:select_node={onSelectNode}
|
on:select_node={onSelectNode}
|
||||||
on:right_click_node={onRightClickNode}
|
on:right_click_node={onRightClickNode}
|
||||||
on:hover_node={onHoverNode}
|
on:hover_node={onHoverNode}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { JourneyNode, JourneyPatchNode, WritableJourneyStateStore } from '$lib/stores/journeyStates';
|
import { resolvePatch, type JourneyNode, type JourneyPatchNode, type WritableJourneyStateStore } from '$lib/stores/journeyStates';
|
||||||
import { ComfyBoxWorkflow } from '$lib/stores/workflowState';
|
import { ComfyBoxWorkflow } from '$lib/stores/workflowState';
|
||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
import Graph from './graph/Graph.svelte'
|
import Graph from './graph/Graph.svelte'
|
||||||
@@ -18,11 +18,11 @@
|
|||||||
import { convertComfyOutputToComfyURL, countNewLines } from '$lib/utils';
|
import { convertComfyOutputToComfyURL, countNewLines } from '$lib/utils';
|
||||||
import type { ElementDefinition } from 'cytoscape';
|
import type { ElementDefinition } from 'cytoscape';
|
||||||
import type { JourneyMode } from './ComfyJourneyView.svelte';
|
import type { JourneyMode } from './ComfyJourneyView.svelte';
|
||||||
|
import type { RestoreParamWorkflowNodeTargets } from '$lib/restoreParameters';
|
||||||
|
|
||||||
export let workflow: ComfyBoxWorkflow | null = null
|
export let workflow: ComfyBoxWorkflow | null = null
|
||||||
export let journey: WritableJourneyStateStore | null = null
|
export let journey: WritableJourneyStateStore | null = null
|
||||||
export let mode: JourneyMode = "linear";
|
export let mode: JourneyMode = "linear";
|
||||||
export let activeNode: JourneyNode | null = null;
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
select_node: JourneyNodeEvent;
|
select_node: JourneyNodeEvent;
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
hover_node_out: JourneyNodeEvent;
|
hover_node_out: JourneyNodeEvent;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let lastSelected = null;
|
|
||||||
let lastMode = null;
|
let lastMode = null;
|
||||||
let lastVersion = -1;
|
let lastVersion = -1;
|
||||||
|
|
||||||
@@ -43,6 +42,34 @@
|
|||||||
lastMode = mode;
|
lastMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makePatchText(patch: RestoreParamWorkflowNodeTargets, prev: RestoreParamWorkflowNodeTargets): string {
|
||||||
|
const lines = []
|
||||||
|
|
||||||
|
let sorted = Array.from(Object.entries(patch))
|
||||||
|
sorted.sort((a, b) => {
|
||||||
|
return a[1].name > b[1].name ? 1 : -1
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const [nodeID, source] of sorted) {
|
||||||
|
let line = ""
|
||||||
|
switch (source.nodeType) {
|
||||||
|
case "ui/text":
|
||||||
|
line = `${source.name} (changed)`
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
const prevValue = prev[nodeID];
|
||||||
|
let prevValueStr = "???"
|
||||||
|
if (prevValue)
|
||||||
|
prevValueStr = prevValue.finalValue
|
||||||
|
line = `${source.name}: ${prevValueStr} -> ${source.finalValue}`
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lines.push(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Converts the journey tree into the renderable graph format Cytoscape expects
|
* Converts the journey tree into the renderable graph format Cytoscape expects
|
||||||
*/
|
*/
|
||||||
@@ -51,19 +78,31 @@
|
|||||||
return [[], []]
|
return [[], []]
|
||||||
}
|
}
|
||||||
|
|
||||||
const journeyState = get(journey);
|
let activeNode = journey.getActiveNode()
|
||||||
|
|
||||||
const nodes: ElementDefinition[] = []
|
const nodes: ElementDefinition[] = []
|
||||||
const edges: ElementDefinition[] = []
|
const edges: ElementDefinition[] = []
|
||||||
|
|
||||||
for (const node of journey.iterateBreadthFirst()) {
|
let iter: Iterable<JourneyNode> = [];
|
||||||
|
if (mode === "linear") {
|
||||||
|
if (activeNode != null)
|
||||||
|
iter = journey.iterateLinearPath(activeNode.id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iter = journey.iterateBreadthFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
const showPatches = mode === "linear";
|
||||||
|
|
||||||
|
const memoize = {}
|
||||||
|
|
||||||
|
for (const node of iter) {
|
||||||
if (node.type === "root") {
|
if (node.type === "root") {
|
||||||
nodes.push({
|
nodes.push({
|
||||||
data: {
|
data: {
|
||||||
id: node.id,
|
id: node.id,
|
||||||
label: "Start",
|
label: "Start",
|
||||||
},
|
},
|
||||||
selected: node.id === activeNode?.id,
|
|
||||||
classes: "historyNode"
|
classes: "historyNode"
|
||||||
})
|
})
|
||||||
continue;
|
continue;
|
||||||
@@ -75,16 +114,22 @@
|
|||||||
id: patchNode.id,
|
id: patchNode.id,
|
||||||
label: "P",
|
label: "P",
|
||||||
},
|
},
|
||||||
selected: node.id === activeNode?.id,
|
|
||||||
classes: "historyNode"
|
classes: "historyNode"
|
||||||
})
|
})
|
||||||
|
|
||||||
// Display a small node between with the patch details
|
// Display a small node between with the patch details
|
||||||
const midNodeID = `${patchNode.id}_patch`;
|
const midNodeID = `${patchNode.id}_patch`;
|
||||||
|
|
||||||
const patchText = "cfg: 8 -> 10\nsteps: 20->30\na";
|
console.debug("get", patchNode);
|
||||||
|
|
||||||
|
if (showPatches) {
|
||||||
|
// show a node with the changes between gens
|
||||||
|
const prev = resolvePatch(patchNode.parent, memoize);
|
||||||
|
const patchText = makePatchText(patchNode.patch, prev);
|
||||||
const patchNodeHeight = countNewLines(patchText) * 11 + 22;
|
const patchNodeHeight = countNewLines(patchText) * 11 + 22;
|
||||||
|
|
||||||
|
console.debug("[JourneyRenderer] Patch text", prev, patchText);
|
||||||
|
|
||||||
nodes.push({
|
nodes.push({
|
||||||
data: {
|
data: {
|
||||||
id: midNodeID,
|
id: midNodeID,
|
||||||
@@ -114,14 +159,27 @@
|
|||||||
locked: true
|
locked: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
edges.push({
|
||||||
|
data: {
|
||||||
|
id: `${patchNode.parent.id}_${patchNode.id}`,
|
||||||
|
source: patchNode.parent.id,
|
||||||
|
target: patchNode.id,
|
||||||
|
},
|
||||||
|
selectable: false,
|
||||||
|
locked: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [nodes, edges]
|
return [nodes, edges]
|
||||||
}
|
}
|
||||||
|
|
||||||
function onNodeSelected(e: cytoscape.InputEventObject) {
|
function onNodeSelected(e: cytoscape.InputEventObject) {
|
||||||
console.warn("SELECT", e)
|
console.warn("[JourneyNode] onNodeSelected", e)
|
||||||
const node = e.target as cytoscape.NodeSingular;
|
const node = e.target as cytoscape.NodeSingular;
|
||||||
|
|
||||||
journey.selectNode(node.id());
|
journey.selectNode(node.id());
|
||||||
|
|
||||||
e.cy.animate({
|
e.cy.animate({
|
||||||
@@ -154,9 +212,12 @@
|
|||||||
function onRebuilt(e: CustomEvent<{cyto: cytoscape.Core}>) {
|
function onRebuilt(e: CustomEvent<{cyto: cytoscape.Core}>) {
|
||||||
const { cyto } = e.detail;
|
const { cyto } = e.detail;
|
||||||
|
|
||||||
for (const node of cyto.nodes().components()) {
|
const activeNode = journey.getActiveNode();
|
||||||
|
|
||||||
|
for (const node of cyto.nodes(".historyNode").components()) {
|
||||||
const nodeID = node.id()
|
const nodeID = node.id()
|
||||||
if (nodeID === lastSelected) {
|
if (nodeID === activeNode?.id) {
|
||||||
|
node.select();
|
||||||
cyto.zoom(1.25);
|
cyto.zoom(1.25);
|
||||||
cyto.center(node)
|
cyto.center(node)
|
||||||
}
|
}
|
||||||
@@ -171,7 +232,6 @@
|
|||||||
if (outputs) {
|
if (outputs) {
|
||||||
node.data("bgImage", outputs[0]);
|
node.data("bgImage", outputs[0]);
|
||||||
}
|
}
|
||||||
console.warn("node.classes", node.classes())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,8 +239,9 @@
|
|||||||
|
|
||||||
$selectionState.currentPatchHoveredNodes = new Set()
|
$selectionState.currentPatchHoveredNodes = new Set()
|
||||||
|
|
||||||
cyto.nodes()
|
cyto.nodes().lock()
|
||||||
.lock()
|
|
||||||
|
cyto.nodes(".historyNode")
|
||||||
.on("select", onNodeSelected)
|
.on("select", onNodeSelected)
|
||||||
.on("cxttapend ", onNodeRightClicked)
|
.on("cxttapend ", onNodeRightClicked)
|
||||||
.on("mouseout", onNodeHoveredOut)
|
.on("mouseout", onNodeHoveredOut)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
import ComfyBoxStdPromptSerializer from "$lib/ComfyBoxStdPromptSerializer";
|
import ComfyBoxStdPromptSerializer from "$lib/ComfyBoxStdPromptSerializer";
|
||||||
import JsonView from "./JsonView.svelte";
|
import JsonView from "./JsonView.svelte";
|
||||||
import type { ZodError } from "zod";
|
import type { ZodError } from "zod";
|
||||||
import { concatRestoreParams, getWorkflowRestoreParams, type RestoreParamTargets, type RestoreParamWorkflowNodeTargets } from "$lib/restoreParameters";
|
import { concatRestoreParams, getWorkflowRestoreParams, getWorkflowRestoreParamsUsingLayout, type RestoreParamTargets, type RestoreParamWorkflowNodeTargets } from "$lib/restoreParameters";
|
||||||
|
|
||||||
const splitLength = 50;
|
const splitLength = 50;
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
// TODO other sources than serialized workflow
|
// TODO other sources than serialized workflow
|
||||||
if (workflow != null) {
|
if (workflow != null) {
|
||||||
const workflowParams = getWorkflowRestoreParams(workflow.workflow)
|
const workflowParams = getWorkflowRestoreParamsUsingLayout(workflow.workflow, workflow.layout)
|
||||||
restoreParams = concatRestoreParams(restoreParams, workflowParams);
|
restoreParams = concatRestoreParams(restoreParams, workflowParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,9 +57,10 @@ const styles: Stylesheet[] = [
|
|||||||
{
|
{
|
||||||
selector: ".patchNode",
|
selector: ".patchNode",
|
||||||
style: {
|
style: {
|
||||||
"width": "100",
|
"width": "label",
|
||||||
"height": "data(patchNodeHeight)",
|
"height": "label",
|
||||||
"shape": "round-rectangle",
|
"shape": "round-rectangle",
|
||||||
|
"padding": "20",
|
||||||
"font-family": "Arial",
|
"font-family": "Arial",
|
||||||
"font-size": "11",
|
"font-size": "11",
|
||||||
"font-weight": "normal",
|
"font-weight": "normal",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { INodeInputSlot, NodeID, SerializedLGraph } from "@litegraph-ts/cor
|
|||||||
import type { SerializedPrompt } from "./components/ComfyApp";
|
import type { SerializedPrompt } from "./components/ComfyApp";
|
||||||
import type { ComfyWidgetNode } from "./nodes/widgets";
|
import type { ComfyWidgetNode } from "./nodes/widgets";
|
||||||
import type { SerializedComfyWidgetNode } from "./nodes/widgets/ComfyWidgetNode";
|
import type { SerializedComfyWidgetNode } from "./nodes/widgets/ComfyWidgetNode";
|
||||||
import { isComfyWidgetNode } from "./stores/layoutStates";
|
import { isComfyWidgetNode, type SerializedLayoutState } from "./stores/layoutStates";
|
||||||
import type { ComfyBoxWorkflow } from "./stores/workflowState";
|
import type { ComfyBoxWorkflow } from "./stores/workflowState";
|
||||||
import { isSerializedPromptInputLink } from "./utils";
|
import { isSerializedPromptInputLink } from "./utils";
|
||||||
import ComfyBoxStdPromptSerializer from "./ComfyBoxStdPromptSerializer";
|
import ComfyBoxStdPromptSerializer from "./ComfyBoxStdPromptSerializer";
|
||||||
@@ -15,6 +15,16 @@ export type RestoreParamType = "workflow" | "backend" | "stdPrompt";
|
|||||||
export interface RestoreParamSource<T extends RestoreParamType = any> {
|
export interface RestoreParamSource<T extends RestoreParamType = any> {
|
||||||
type: T,
|
type: T,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A human-readable name for this parameter
|
||||||
|
*/
|
||||||
|
name?: string,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LiteGraph type of the widget node
|
||||||
|
*/
|
||||||
|
nodeType: string,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The actual value to copy to the widget after all conversions have been
|
* The actual value to copy to the widget after all conversions have been
|
||||||
* applied.
|
* applied.
|
||||||
@@ -172,10 +182,22 @@ export function getWorkflowRestoreParamsFromWorkflow(workflow: ComfyBoxWorkflow,
|
|||||||
if (!noExclude && node.properties.excludeFromJourney)
|
if (!noExclude && node.properties.excludeFromJourney)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
let name = null;
|
||||||
|
const realNode = workflow.graph.getNodeByIdRecursive(node.id);
|
||||||
|
if (realNode != null && isComfyWidgetNode(realNode)) {
|
||||||
|
name = realNode.title || name;
|
||||||
|
const widget = realNode.dragItem;
|
||||||
|
if (widget != null) {
|
||||||
|
name = widget.attrs.title || name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const finalValue = node.getValue();
|
const finalValue = node.getValue();
|
||||||
if (finalValue != null) {
|
if (finalValue != null) {
|
||||||
const source: RestoreParamSourceWorkflowNode = {
|
const source: RestoreParamSourceWorkflowNode = {
|
||||||
type: "workflow",
|
type: "workflow",
|
||||||
|
nodeType: node.type,
|
||||||
|
name,
|
||||||
finalValue,
|
finalValue,
|
||||||
}
|
}
|
||||||
result[node.id] = source;
|
result[node.id] = source;
|
||||||
@@ -185,7 +207,7 @@ export function getWorkflowRestoreParamsFromWorkflow(workflow: ComfyBoxWorkflow,
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWorkflowRestoreParams(serGraph: SerializedLGraph, noExclude: boolean = false): RestoreParamWorkflowNodeTargets {
|
export function getWorkflowRestoreParams(serGraph: SerializedLGraph, workflow?: ComfyBoxWorkflow, noExclude: boolean = false): RestoreParamWorkflowNodeTargets {
|
||||||
const result = {}
|
const result = {}
|
||||||
|
|
||||||
for (const node of serGraph.nodes) {
|
for (const node of serGraph.nodes) {
|
||||||
@@ -195,10 +217,22 @@ export function getWorkflowRestoreParams(serGraph: SerializedLGraph, noExclude:
|
|||||||
if (!noExclude && node.properties.excludeFromJourney)
|
if (!noExclude && node.properties.excludeFromJourney)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
let name = null;
|
||||||
|
const realNode = workflow.graph.getNodeByIdRecursive(node.id);
|
||||||
|
if (realNode != null && isComfyWidgetNode(realNode)) {
|
||||||
|
name = realNode.title || name;
|
||||||
|
const widget = realNode.dragItem;
|
||||||
|
if (widget != null) {
|
||||||
|
name = widget.attrs.title || name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const finalValue = node.comfyValue
|
const finalValue = node.comfyValue
|
||||||
if (finalValue != null) {
|
if (finalValue != null) {
|
||||||
const source: RestoreParamSourceWorkflowNode = {
|
const source: RestoreParamSourceWorkflowNode = {
|
||||||
type: "workflow",
|
type: "workflow",
|
||||||
|
nodeType: node.type,
|
||||||
|
name,
|
||||||
finalValue,
|
finalValue,
|
||||||
}
|
}
|
||||||
result[node.id] = source;
|
result[node.id] = source;
|
||||||
@@ -208,6 +242,37 @@ export function getWorkflowRestoreParams(serGraph: SerializedLGraph, noExclude:
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getWorkflowRestoreParamsUsingLayout(serGraph: SerializedLGraph, layout?: SerializedLayoutState, noExclude: boolean = false): RestoreParamWorkflowNodeTargets {
|
||||||
|
const result = {}
|
||||||
|
|
||||||
|
for (const serNode of serGraph.nodes) {
|
||||||
|
if (!isSerializedComfyWidgetNode(serNode))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!noExclude && serNode.properties.excludeFromJourney)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let name = null;
|
||||||
|
const serWidget = Array.from(Object.values(layout?.allItems || {})).find(di => di.dragItem.type === "widget" && di.dragItem.nodeId === serNode.id)
|
||||||
|
if (serWidget) {
|
||||||
|
name = serWidget.dragItem.attrs.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
const finalValue = serNode.comfyValue
|
||||||
|
if (finalValue != null) {
|
||||||
|
const source: RestoreParamSourceWorkflowNode = {
|
||||||
|
type: "workflow",
|
||||||
|
nodeType: serNode.type,
|
||||||
|
name,
|
||||||
|
finalValue,
|
||||||
|
}
|
||||||
|
result[serNode.id] = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): Record<NodeID, RestoreParamSourceBackendNodeInput[]> {
|
export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): Record<NodeID, RestoreParamSourceBackendNodeInput[]> {
|
||||||
const result = {}
|
const result = {}
|
||||||
|
|
||||||
@@ -236,6 +301,7 @@ export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: Seri
|
|||||||
if (isComfyWidgetNode(foundNode) && foundNode.type === serNode.type) {
|
if (isComfyWidgetNode(foundNode) && foundNode.type === serNode.type) {
|
||||||
const source: RestoreParamSourceBackendNodeInput = {
|
const source: RestoreParamSourceBackendNodeInput = {
|
||||||
type: "backend",
|
type: "backend",
|
||||||
|
nodeType: foundNode.type,
|
||||||
finalValue: inputValue,
|
finalValue: inputValue,
|
||||||
backendNode: serNode,
|
backendNode: serNode,
|
||||||
isDirectAttachment
|
isDirectAttachment
|
||||||
@@ -252,7 +318,7 @@ export function getBackendRestoreParams(workflow: ComfyBoxWorkflow, prompt: Seri
|
|||||||
export default function getRestoreParameters(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): RestoreParamTargets {
|
export default function getRestoreParameters(workflow: ComfyBoxWorkflow, prompt: SerializedPrompt): RestoreParamTargets {
|
||||||
const result = {}
|
const result = {}
|
||||||
|
|
||||||
const workflowParams = getWorkflowRestoreParams(prompt.workflow);
|
const workflowParams = getWorkflowRestoreParams(prompt.workflow, workflow);
|
||||||
concatRestoreParams(result, workflowParams);
|
concatRestoreParams(result, workflowParams);
|
||||||
|
|
||||||
const backendParams = getBackendRestoreParams(workflow, prompt);
|
const backendParams = getBackendRestoreParams(workflow, prompt);
|
||||||
|
|||||||
@@ -45,17 +45,33 @@ export interface JourneyPatchNode extends JourneyNode {
|
|||||||
patch: RestoreParamWorkflowNodeTargets
|
patch: RestoreParamWorkflowNodeTargets
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolvePatch(node: JourneyNode): RestoreParamWorkflowNodeTargets {
|
function isRoot(node: JourneyNode): node is JourneyRootNode {
|
||||||
|
return node.type === "root";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPatch(node: JourneyNode): node is JourneyPatchNode {
|
||||||
|
return node.type === "patch";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolvePatch(node: JourneyNode, memoize?: Record<JourneyNodeID, RestoreParamWorkflowNodeTargets>): RestoreParamWorkflowNodeTargets {
|
||||||
if (node.type === "root") {
|
if (node.type === "root") {
|
||||||
return { ...(node as JourneyRootNode).base }
|
return { ...(node as JourneyRootNode).base }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (memoize && memoize[node.id] != null)
|
||||||
|
return { ...memoize[node.id] }
|
||||||
|
|
||||||
const patchNode = (node as JourneyPatchNode);
|
const patchNode = (node as JourneyPatchNode);
|
||||||
const patch = { ...patchNode.patch };
|
const patch = { ...patchNode.patch };
|
||||||
const base = resolvePatch(patchNode.parent);
|
const base = resolvePatch(patchNode.parent);
|
||||||
for (const [k, v] of Object.entries(patch)) {
|
for (const [k, v] of Object.entries(patch)) {
|
||||||
base[k] = v;
|
base[k] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (memoize) {
|
||||||
|
memoize[node.id] = base;
|
||||||
|
}
|
||||||
|
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,6 +115,7 @@ type JourneyStateOps = {
|
|||||||
// addNode: (params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID | JourneyNode) => JourneyNode,
|
// addNode: (params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID | JourneyNode) => JourneyNode,
|
||||||
selectNode: (id?: JourneyNodeID | JourneyNode) => void,
|
selectNode: (id?: JourneyNodeID | JourneyNode) => void,
|
||||||
iterateBreadthFirst: (id?: JourneyNodeID | null) => Iterable<JourneyNode>,
|
iterateBreadthFirst: (id?: JourneyNodeID | null) => Iterable<JourneyNode>,
|
||||||
|
iterateLinearPath: (id: JourneyNodeID) => Iterable<JourneyNode>,
|
||||||
pushPatchOntoActive: (workflow: ComfyBoxWorkflow, activeNode?: JourneyNode, showNotification?: boolean) => JourneyNode | null
|
pushPatchOntoActive: (workflow: ComfyBoxWorkflow, activeNode?: JourneyNode, showNotification?: boolean) => JourneyNode | null
|
||||||
onExecuted: (promptID: PromptID, nodeID: ComfyNodeID, output: SerializedPromptOutput, queueEntry: QueueEntry) => void
|
onExecuted: (promptID: PromptID, nodeID: ComfyNodeID, output: SerializedPromptOutput, queueEntry: QueueEntry) => void
|
||||||
}
|
}
|
||||||
@@ -265,9 +282,38 @@ function create() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* iterateNodeParents(node: JourneyNode): Iterable<JourneyNode> {
|
||||||
|
while (isPatch(node)) {
|
||||||
|
yield node.parent;
|
||||||
|
node = node.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function iterateLinearPath(id: JourneyNodeID): Iterable<JourneyNode> {
|
||||||
|
const state = get(store);
|
||||||
|
|
||||||
|
const node = state.nodesByID[id];
|
||||||
|
if (node == null) {
|
||||||
|
console.error("[journeyStates] Journey node not found!", id);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = Array.from(iterateNodeParents(node)).reverse()
|
||||||
|
path.push(node)
|
||||||
|
|
||||||
|
// pick first child for nodes downstream
|
||||||
|
let child = node.children[0]
|
||||||
|
while (child != null) {
|
||||||
|
path.push(child);
|
||||||
|
child = child.children[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
function onExecuted(promptID: PromptID, nodeID: ComfyNodeID, output: SerializedPromptOutput, queueEntry: QueueEntry) {
|
function onExecuted(promptID: PromptID, nodeID: ComfyNodeID, output: SerializedPromptOutput, queueEntry: QueueEntry) {
|
||||||
const journeyNode = Array.from(iterateBreadthFirst()).find(j => j.promptID === promptID);
|
const journeyNode = Array.from(iterateBreadthFirst()).find(j => j.promptID === promptID);
|
||||||
if (journeyNode === null)
|
if (journeyNode == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@@ -286,6 +332,7 @@ function create() {
|
|||||||
pushPatchOntoActive,
|
pushPatchOntoActive,
|
||||||
selectNode,
|
selectNode,
|
||||||
iterateBreadthFirst,
|
iterateBreadthFirst,
|
||||||
|
iterateLinearPath,
|
||||||
onExecuted
|
onExecuted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user