feat(ui): generate iterations graph

This commit is contained in:
Mary Hipp
2023-04-06 11:17:06 -04:00
committed by psychedelicious
parent 18aa0c91da
commit 2386d5d786
5 changed files with 201 additions and 214 deletions

View File

@@ -1,9 +1,13 @@
import { v4 as uuidv4 } from 'uuid';
import { RootState } from 'app/store';
import { InvokeTabName, tabMap } from 'features/ui/store/tabMap';
import { Graph } from 'services/api';
import { buildImg2ImgNode, buildTxt2ImgNode } from './buildNodes';
import {
Graph,
ImageToImageInvocation,
TextToImageInvocation,
} from 'services/api';
import { buildTxt2ImgNode } from './nodes/textToimage';
import { buildImg2ImgNode } from './nodes/imageToImage';
import { buildIteration } from './nodes/iteration';
function mapTabToFunction(activeTabName: InvokeTabName) {
switch (activeTabName) {
@@ -18,74 +22,22 @@ function mapTabToFunction(activeTabName: InvokeTabName) {
}
}
const exampleGraphs: Record<string, Graph> = {
iterations: {
nodes: {
'0': {
id: '0',
type: 'range',
start: 0,
stop: 5,
step: 1,
},
'1': {
collection: [],
id: '1',
index: 0,
type: 'iterate',
},
'2': {
cfg_scale: 7.5,
height: 512,
id: '2',
model: '',
progress_images: false,
prompt: 'dog',
sampler_name: 'k_lms',
seamless: false,
steps: 11,
type: 'txt2img',
width: 512,
},
},
edges: [
{
source: {
field: 'collection',
node_id: '0',
},
destination: {
field: 'collection',
node_id: '1',
},
},
{
source: {
field: 'item',
node_id: '1',
},
destination: {
field: 'seed',
node_id: '2',
},
},
],
},
const buildBaseNode = (
state: RootState
): Record<string, TextToImageInvocation | ImageToImageInvocation> => {
const { activeTab } = state.ui;
const activeTabName = tabMap[activeTab];
return mapTabToFunction(activeTabName)(state);
};
export const buildGraph = (state: RootState): Graph => {
const { activeTab } = state.ui;
const activeTabName = tabMap[activeTab];
const nodeId = uuidv4();
const { iterations } = state.generation;
const baseNode = buildBaseNode(state);
// return exampleGraphs.iterations;
if (iterations > 1) {
return buildIteration({ baseNode, iterations });
}
return {
nodes: {
[nodeId]: {
id: nodeId,
...mapTabToFunction(activeTabName)(state),
},
},
};
return { nodes: baseNode };
};

View File

@@ -1,145 +0,0 @@
import { RootState } from 'app/store';
import {
ImageToImageInvocation,
RestoreFaceInvocation,
TextToImageInvocation,
UpscaleInvocation,
} from 'services/api';
import { _Image } from 'app/invokeai';
import { initialImageSelector } from 'features/parameters/store/generationSelectors';
// fe todo fix model type (frontend uses null, backend uses undefined)
// fe todo update front end to store to have whole image field (vs just name)
// be todo add symmetry fields
// be todo variations....
export function buildTxt2ImgNode(
state: RootState
): Omit<TextToImageInvocation, 'id'> {
const { generation, system } = state;
const { shouldDisplayInProgressType, model } = system;
const {
prompt,
seed,
steps,
width,
height,
cfgScale: cfg_scale,
sampler,
seamless,
shouldRandomizeSeed,
} = generation;
// missing fields in TextToImageInvocation: strength, hires_fix
return {
type: 'txt2img',
prompt,
seed: shouldRandomizeSeed ? -1 : seed,
steps,
width,
height,
cfg_scale,
sampler_name: sampler as TextToImageInvocation['sampler_name'],
seamless,
model,
progress_images: shouldDisplayInProgressType === 'full-res',
};
}
export function buildImg2ImgNode(
state: RootState
): Omit<ImageToImageInvocation, 'id'> {
const { generation, system } = state;
const { shouldDisplayInProgressType, model } = system;
const {
prompt,
seed,
steps,
width,
height,
cfgScale,
sampler,
seamless,
img2imgStrength: strength,
shouldFitToWidthHeight: fit,
shouldRandomizeSeed,
} = generation;
const initialImage = initialImageSelector(state);
if (!initialImage) {
// TODO: handle this
throw 'no initial image';
}
return {
type: 'img2img',
prompt,
seed: shouldRandomizeSeed ? -1 : seed,
steps,
width,
height,
cfg_scale: cfgScale,
sampler_name: sampler as ImageToImageInvocation['sampler_name'],
seamless,
model,
progress_images: shouldDisplayInProgressType === 'full-res',
image: {
image_name: initialImage.name,
image_type: initialImage.type,
},
strength,
fit,
};
}
export function buildFacetoolNode(
state: RootState
): Omit<RestoreFaceInvocation, 'id'> {
const { generation, postprocessing } = state;
const { initialImage } = generation;
const { facetoolStrength: strength } = postprocessing;
// missing fields in RestoreFaceInvocation: type, codeformer_fidelity
return {
type: 'restore_face',
image: {
image_name:
(typeof initialImage === 'string' ? initialImage : initialImage?.url) ||
'',
image_type: 'results',
},
strength,
};
}
// is this ESRGAN??
export function buildUpscaleNode(
state: RootState
): Omit<UpscaleInvocation, 'id'> {
const { generation, postprocessing } = state;
const { initialImage } = generation;
const { upscalingLevel: level, upscalingStrength: strength } = postprocessing;
// missing fields in UpscaleInvocation: denoise_str
return {
type: 'upscale',
image: {
image_name:
(typeof initialImage === 'string' ? initialImage : initialImage?.url) ||
'',
image_type: 'results',
},
strength,
level,
};
}

View File

@@ -0,0 +1,58 @@
import { v4 as uuidv4 } from 'uuid';
import { RootState } from 'app/store';
import { ImageToImageInvocation } from 'services/api';
import { _Image } from 'app/invokeai';
import { initialImageSelector } from 'features/parameters/store/generationSelectors';
export function buildImg2ImgNode(
state: RootState
): Record<string, ImageToImageInvocation> {
const nodeId = uuidv4();
const { generation, system } = state;
const { shouldDisplayInProgressType, model } = system;
const {
prompt,
seed,
steps,
width,
height,
cfgScale,
sampler,
seamless,
img2imgStrength: strength,
shouldFitToWidthHeight: fit,
shouldRandomizeSeed,
} = generation;
const initialImage = initialImageSelector(state);
if (!initialImage) {
// TODO: handle this
throw 'no initial image';
}
return {
[nodeId]: {
id: nodeId,
type: 'img2img',
prompt,
seed: shouldRandomizeSeed ? -1 : seed,
steps,
width,
height,
cfg_scale: cfgScale,
sampler_name: sampler as ImageToImageInvocation['sampler_name'],
seamless,
model,
progress_images: shouldDisplayInProgressType === 'full-res',
image: {
image_name: initialImage.name,
image_type: initialImage.type,
},
strength,
fit,
},
};
}

View File

@@ -0,0 +1,79 @@
import { v4 as uuidv4 } from 'uuid';
import {
Edge,
Graph,
ImageToImageInvocation,
IterateInvocation,
RangeInvocation,
TextToImageInvocation,
} from 'services/api';
type BuildIteration = {
baseNode: Record<string, TextToImageInvocation | ImageToImageInvocation>;
iterations: number;
};
const buildRangeNode = (
iterations: number
): Record<string, RangeInvocation> => {
const nodeId = uuidv4();
return {
[nodeId]: {
id: nodeId,
type: 'range',
start: 0,
stop: iterations,
step: 1,
},
};
};
const buildIterateNode = (): Record<string, IterateInvocation> => {
const nodeId = uuidv4();
return {
[nodeId]: {
id: nodeId,
type: 'iterate',
collection: [],
index: 0,
},
};
};
export const buildIteration = ({
baseNode,
iterations,
}: BuildIteration): Graph => {
const rangeNode = buildRangeNode(iterations);
const iterateNode = buildIterateNode();
const edges: Edge[] = [
{
source: {
field: 'collection',
node_id: Object.keys(rangeNode)[0],
},
destination: {
field: 'collection',
node_id: Object.keys(iterateNode)[0],
},
},
{
source: {
field: 'item',
node_id: Object.keys(iterateNode)[0],
},
destination: {
field: 'seed',
node_id: Object.keys(baseNode)[0],
},
},
];
return {
nodes: {
...rangeNode,
...iterateNode,
...baseNode,
},
edges,
};
};

View File

@@ -0,0 +1,43 @@
import { v4 as uuidv4 } from 'uuid';
import { RootState } from 'app/store';
import { TextToImageInvocation } from 'services/api';
import { _Image } from 'app/invokeai';
export function buildTxt2ImgNode(
state: RootState
): Record<string, TextToImageInvocation> {
const nodeId = uuidv4();
const { generation, system } = state;
const { shouldDisplayInProgressType, model } = system;
const {
prompt,
seed,
steps,
width,
height,
cfgScale: cfg_scale,
sampler,
seamless,
shouldRandomizeSeed,
} = generation;
// missing fields in TextToImageInvocation: strength, hires_fix
return {
[nodeId]: {
id: nodeId,
type: 'txt2img',
prompt,
seed: shouldRandomizeSeed ? -1 : seed,
steps,
width,
height,
cfg_scale,
sampler_name: sampler as TextToImageInvocation['sampler_name'],
seamless,
model,
progress_images: shouldDisplayInProgressType === 'full-res',
},
};
}