mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
Merge branch 'development' of https://github.com/lstein/stable-diffusion into development
This commit is contained in:
@@ -3,20 +3,20 @@ import { isEqual } from 'lodash';
|
||||
import { useMemo } from 'react';
|
||||
import { useAppSelector } from '../../app/store';
|
||||
import { RootState } from '../../app/store';
|
||||
import { SDState } from '../../features/sd/sdSlice';
|
||||
import { OptionsState } from '../../features/options/optionsSlice';
|
||||
import { SystemState } from '../../features/system/systemSlice';
|
||||
import { validateSeedWeights } from '../util/seedWeightPairs';
|
||||
|
||||
const sdSelector = createSelector(
|
||||
(state: RootState) => state.sd,
|
||||
(sd: SDState) => {
|
||||
const optionsSelector = createSelector(
|
||||
(state: RootState) => state.options,
|
||||
(options: OptionsState) => {
|
||||
return {
|
||||
prompt: sd.prompt,
|
||||
shouldGenerateVariations: sd.shouldGenerateVariations,
|
||||
seedWeights: sd.seedWeights,
|
||||
maskPath: sd.maskPath,
|
||||
initialImagePath: sd.initialImagePath,
|
||||
seed: sd.seed,
|
||||
prompt: options.prompt,
|
||||
shouldGenerateVariations: options.shouldGenerateVariations,
|
||||
seedWeights: options.seedWeights,
|
||||
maskPath: options.maskPath,
|
||||
initialImagePath: options.initialImagePath,
|
||||
seed: options.seed,
|
||||
};
|
||||
},
|
||||
{
|
||||
@@ -53,7 +53,7 @@ const useCheckParameters = (): boolean => {
|
||||
maskPath,
|
||||
initialImagePath,
|
||||
seed,
|
||||
} = useAppSelector(sdSelector);
|
||||
} = useAppSelector(optionsSelector);
|
||||
|
||||
const { isProcessing, isConnected } = useAppSelector(systemSelector);
|
||||
|
||||
|
||||
@@ -1,188 +1,190 @@
|
||||
|
||||
/*
|
||||
These functions translate frontend state into parameters
|
||||
suitable for consumption by the backend, and vice-versa.
|
||||
*/
|
||||
|
||||
import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from "../../app/constants";
|
||||
import { SDState } from "../../features/sd/sdSlice";
|
||||
import { SystemState } from "../../features/system/systemSlice";
|
||||
import randomInt from "./randomInt";
|
||||
import { seedWeightsToString, stringToSeedWeights } from "./seedWeightPairs";
|
||||
import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from '../../app/constants';
|
||||
import { OptionsState } from '../../features/options/optionsSlice';
|
||||
import { SystemState } from '../../features/system/systemSlice';
|
||||
import {
|
||||
seedWeightsToString,
|
||||
stringToSeedWeightsArray,
|
||||
} from './seedWeightPairs';
|
||||
import randomInt from './randomInt';
|
||||
|
||||
export const frontendToBackendParameters = (
|
||||
sdState: SDState,
|
||||
systemState: SystemState
|
||||
optionsState: OptionsState,
|
||||
systemState: SystemState
|
||||
): { [key: string]: any } => {
|
||||
const {
|
||||
prompt,
|
||||
iterations,
|
||||
steps,
|
||||
cfgScale,
|
||||
threshold,
|
||||
perlin,
|
||||
height,
|
||||
width,
|
||||
sampler,
|
||||
seed,
|
||||
seamless,
|
||||
shouldUseInitImage,
|
||||
img2imgStrength,
|
||||
initialImagePath,
|
||||
maskPath,
|
||||
shouldFitToWidthHeight,
|
||||
shouldGenerateVariations,
|
||||
variationAmount,
|
||||
seedWeights,
|
||||
shouldRunESRGAN,
|
||||
upscalingLevel,
|
||||
upscalingStrength,
|
||||
shouldRunGFPGAN,
|
||||
gfpganStrength,
|
||||
shouldRandomizeSeed,
|
||||
} = sdState;
|
||||
const {
|
||||
prompt,
|
||||
iterations,
|
||||
steps,
|
||||
cfgScale,
|
||||
threshold,
|
||||
perlin,
|
||||
height,
|
||||
width,
|
||||
sampler,
|
||||
seed,
|
||||
seamless,
|
||||
shouldUseInitImage,
|
||||
img2imgStrength,
|
||||
initialImagePath,
|
||||
maskPath,
|
||||
shouldFitToWidthHeight,
|
||||
shouldGenerateVariations,
|
||||
variationAmount,
|
||||
seedWeights,
|
||||
shouldRunESRGAN,
|
||||
upscalingLevel,
|
||||
upscalingStrength,
|
||||
shouldRunGFPGAN,
|
||||
gfpganStrength,
|
||||
shouldRandomizeSeed,
|
||||
} = optionsState;
|
||||
|
||||
const { shouldDisplayInProgress } = systemState;
|
||||
const { shouldDisplayInProgress } = systemState;
|
||||
|
||||
const generationParameters: { [k: string]: any } = {
|
||||
prompt,
|
||||
iterations,
|
||||
steps,
|
||||
cfg_scale: cfgScale,
|
||||
threshold,
|
||||
perlin,
|
||||
height,
|
||||
width,
|
||||
sampler_name: sampler,
|
||||
seed,
|
||||
seamless,
|
||||
progress_images: shouldDisplayInProgress,
|
||||
const generationParameters: { [k: string]: any } = {
|
||||
prompt,
|
||||
iterations,
|
||||
steps,
|
||||
cfg_scale: cfgScale,
|
||||
threshold,
|
||||
perlin,
|
||||
height,
|
||||
width,
|
||||
sampler_name: sampler,
|
||||
seed,
|
||||
seamless,
|
||||
progress_images: shouldDisplayInProgress,
|
||||
};
|
||||
|
||||
generationParameters.seed = shouldRandomizeSeed
|
||||
? randomInt(NUMPY_RAND_MIN, NUMPY_RAND_MAX)
|
||||
: seed;
|
||||
|
||||
if (shouldUseInitImage) {
|
||||
generationParameters.init_img = initialImagePath;
|
||||
generationParameters.strength = img2imgStrength;
|
||||
generationParameters.fit = shouldFitToWidthHeight;
|
||||
if (maskPath) {
|
||||
generationParameters.init_mask = maskPath;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldGenerateVariations) {
|
||||
generationParameters.variation_amount = variationAmount;
|
||||
if (seedWeights) {
|
||||
generationParameters.with_variations =
|
||||
stringToSeedWeightsArray(seedWeights);
|
||||
}
|
||||
} else {
|
||||
generationParameters.variation_amount = 0;
|
||||
}
|
||||
|
||||
let esrganParameters: false | { [k: string]: any } = false;
|
||||
let gfpganParameters: false | { [k: string]: any } = false;
|
||||
|
||||
if (shouldRunESRGAN) {
|
||||
esrganParameters = {
|
||||
level: upscalingLevel,
|
||||
strength: upscalingStrength,
|
||||
};
|
||||
}
|
||||
|
||||
generationParameters.seed = shouldRandomizeSeed
|
||||
? randomInt(NUMPY_RAND_MIN, NUMPY_RAND_MAX)
|
||||
: seed;
|
||||
|
||||
if (shouldUseInitImage) {
|
||||
generationParameters.init_img = initialImagePath;
|
||||
generationParameters.strength = img2imgStrength;
|
||||
generationParameters.fit = shouldFitToWidthHeight;
|
||||
if (maskPath) {
|
||||
generationParameters.init_mask = maskPath;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldGenerateVariations) {
|
||||
generationParameters.variation_amount = variationAmount;
|
||||
if (seedWeights) {
|
||||
generationParameters.with_variations =
|
||||
stringToSeedWeights(seedWeights);
|
||||
}
|
||||
} else {
|
||||
generationParameters.variation_amount = 0;
|
||||
}
|
||||
|
||||
let esrganParameters: false | { [k: string]: any } = false;
|
||||
let gfpganParameters: false | { [k: string]: any } = false;
|
||||
|
||||
if (shouldRunESRGAN) {
|
||||
esrganParameters = {
|
||||
level: upscalingLevel,
|
||||
strength: upscalingStrength,
|
||||
};
|
||||
}
|
||||
|
||||
if (shouldRunGFPGAN) {
|
||||
gfpganParameters = {
|
||||
strength: gfpganStrength,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
generationParameters,
|
||||
esrganParameters,
|
||||
gfpganParameters,
|
||||
if (shouldRunGFPGAN) {
|
||||
gfpganParameters = {
|
||||
strength: gfpganStrength,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
generationParameters,
|
||||
esrganParameters,
|
||||
gfpganParameters,
|
||||
};
|
||||
};
|
||||
|
||||
export const backendToFrontendParameters = (parameters: {
|
||||
[key: string]: any;
|
||||
[key: string]: any;
|
||||
}) => {
|
||||
const {
|
||||
prompt,
|
||||
iterations,
|
||||
steps,
|
||||
cfg_scale,
|
||||
threshold,
|
||||
perlin,
|
||||
height,
|
||||
width,
|
||||
sampler_name,
|
||||
seed,
|
||||
seamless,
|
||||
progress_images,
|
||||
variation_amount,
|
||||
with_variations,
|
||||
gfpgan_strength,
|
||||
upscale,
|
||||
init_img,
|
||||
init_mask,
|
||||
strength,
|
||||
} = parameters;
|
||||
const {
|
||||
prompt,
|
||||
iterations,
|
||||
steps,
|
||||
cfg_scale,
|
||||
threshold,
|
||||
perlin,
|
||||
height,
|
||||
width,
|
||||
sampler_name,
|
||||
seed,
|
||||
seamless,
|
||||
progress_images,
|
||||
variation_amount,
|
||||
with_variations,
|
||||
gfpgan_strength,
|
||||
upscale,
|
||||
init_img,
|
||||
init_mask,
|
||||
strength,
|
||||
} = parameters;
|
||||
|
||||
const sd: { [key: string]: any } = {
|
||||
shouldDisplayInProgress: progress_images,
|
||||
// init
|
||||
shouldGenerateVariations: false,
|
||||
shouldRunESRGAN: false,
|
||||
shouldRunGFPGAN: false,
|
||||
initialImagePath: '',
|
||||
maskPath: '',
|
||||
};
|
||||
const options: { [key: string]: any } = {
|
||||
shouldDisplayInProgress: progress_images,
|
||||
// init
|
||||
shouldGenerateVariations: false,
|
||||
shouldRunESRGAN: false,
|
||||
shouldRunGFPGAN: false,
|
||||
initialImagePath: '',
|
||||
maskPath: '',
|
||||
};
|
||||
|
||||
if (variation_amount > 0) {
|
||||
sd.shouldGenerateVariations = true;
|
||||
sd.variationAmount = variation_amount;
|
||||
if (with_variations) {
|
||||
sd.seedWeights = seedWeightsToString(with_variations);
|
||||
}
|
||||
if (variation_amount > 0) {
|
||||
options.shouldGenerateVariations = true;
|
||||
options.variationAmount = variation_amount;
|
||||
if (with_variations) {
|
||||
options.seedWeights = seedWeightsToString(with_variations);
|
||||
}
|
||||
}
|
||||
|
||||
if (gfpgan_strength > 0) {
|
||||
sd.shouldRunGFPGAN = true;
|
||||
sd.gfpganStrength = gfpgan_strength;
|
||||
if (gfpgan_strength > 0) {
|
||||
options.shouldRunGFPGAN = true;
|
||||
options.gfpganStrength = gfpgan_strength;
|
||||
}
|
||||
|
||||
if (upscale) {
|
||||
options.shouldRunESRGAN = true;
|
||||
options.upscalingLevel = upscale[0];
|
||||
options.upscalingStrength = upscale[1];
|
||||
}
|
||||
|
||||
if (init_img) {
|
||||
options.shouldUseInitImage = true;
|
||||
options.initialImagePath = init_img;
|
||||
options.strength = strength;
|
||||
if (init_mask) {
|
||||
options.maskPath = init_mask;
|
||||
}
|
||||
}
|
||||
|
||||
if (upscale) {
|
||||
sd.shouldRunESRGAN = true;
|
||||
sd.upscalingLevel = upscale[0];
|
||||
sd.upscalingStrength = upscale[1];
|
||||
}
|
||||
// if we had a prompt, add all the metadata, but if we don't have a prompt,
|
||||
// we must have only done ESRGAN or GFPGAN so do not add that metadata
|
||||
if (prompt) {
|
||||
options.prompt = prompt;
|
||||
options.iterations = iterations;
|
||||
options.steps = steps;
|
||||
options.cfgScale = cfg_scale;
|
||||
options.threshold = threshold;
|
||||
options.perlin = perlin;
|
||||
options.height = height;
|
||||
options.width = width;
|
||||
options.sampler = sampler_name;
|
||||
options.seed = seed;
|
||||
options.seamless = seamless;
|
||||
}
|
||||
|
||||
if (init_img) {
|
||||
sd.shouldUseInitImage = true
|
||||
sd.initialImagePath = init_img;
|
||||
sd.strength = strength;
|
||||
if (init_mask) {
|
||||
sd.maskPath = init_mask;
|
||||
}
|
||||
}
|
||||
|
||||
// if we had a prompt, add all the metadata, but if we don't have a prompt,
|
||||
// we must have only done ESRGAN or GFPGAN so do not add that metadata
|
||||
if (prompt) {
|
||||
sd.prompt = prompt;
|
||||
sd.iterations = iterations;
|
||||
sd.steps = steps;
|
||||
sd.cfgScale = cfg_scale;
|
||||
sd.threshold = threshold;
|
||||
sd.perlin = perlin;
|
||||
sd.height = height;
|
||||
sd.width = width;
|
||||
sd.sampler = sampler_name;
|
||||
sd.seed = seed;
|
||||
sd.seamless = seamless;
|
||||
}
|
||||
|
||||
return sd;
|
||||
return options;
|
||||
};
|
||||
|
||||
16
frontend/src/common/util/promptToString.ts
Normal file
16
frontend/src/common/util/promptToString.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as InvokeAI from '../../app/invokeai';
|
||||
|
||||
const promptToString = (prompt: InvokeAI.Prompt): string => {
|
||||
if (prompt.length === 1) {
|
||||
return prompt[0].prompt;
|
||||
}
|
||||
|
||||
return prompt
|
||||
.map(
|
||||
(promptItem: InvokeAI.PromptItem): string =>
|
||||
`${promptItem.prompt}:${promptItem.weight}`
|
||||
)
|
||||
.join(' ');
|
||||
};
|
||||
|
||||
export default promptToString;
|
||||
@@ -1,56 +1,68 @@
|
||||
export interface SeedWeightPair {
|
||||
seed: number;
|
||||
weight: number;
|
||||
}
|
||||
import * as InvokeAI from '../../app/invokeai';
|
||||
|
||||
export type SeedWeights = Array<Array<number>>;
|
||||
export const stringToSeedWeights = (
|
||||
string: string
|
||||
): InvokeAI.SeedWeights | boolean => {
|
||||
const stringPairs = string.split(',');
|
||||
const arrPairs = stringPairs.map((p) => p.split(':'));
|
||||
const pairs = arrPairs.map((p: Array<string>): InvokeAI.SeedWeightPair => {
|
||||
return { seed: parseInt(p[0]), weight: parseFloat(p[1]) };
|
||||
});
|
||||
|
||||
export const stringToSeedWeights = (string: string): SeedWeights | boolean => {
|
||||
const stringPairs = string.split(',');
|
||||
const arrPairs = stringPairs.map((p) => p.split(':'));
|
||||
const pairs = arrPairs.map((p) => {
|
||||
return [parseInt(p[0]), parseFloat(p[1])];
|
||||
});
|
||||
if (!validateSeedWeights(pairs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!validateSeedWeights(pairs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return pairs;
|
||||
return pairs;
|
||||
};
|
||||
|
||||
export const validateSeedWeights = (
|
||||
seedWeights: SeedWeights | string
|
||||
seedWeights: InvokeAI.SeedWeights | string
|
||||
): boolean => {
|
||||
return typeof seedWeights === 'string'
|
||||
? Boolean(stringToSeedWeights(seedWeights))
|
||||
: Boolean(
|
||||
seedWeights.length &&
|
||||
!seedWeights.some((pair) => {
|
||||
const [seed, weight] = pair;
|
||||
const isSeedValid = !isNaN(parseInt(seed.toString(), 10));
|
||||
const isWeightValid =
|
||||
!isNaN(parseInt(weight.toString(), 10)) &&
|
||||
weight >= 0 &&
|
||||
weight <= 1;
|
||||
return !(isSeedValid && isWeightValid);
|
||||
})
|
||||
);
|
||||
return typeof seedWeights === 'string'
|
||||
? Boolean(stringToSeedWeights(seedWeights))
|
||||
: Boolean(
|
||||
seedWeights.length &&
|
||||
!seedWeights.some((pair: InvokeAI.SeedWeightPair) => {
|
||||
const { seed, weight } = pair;
|
||||
const isSeedValid = !isNaN(parseInt(seed.toString(), 10));
|
||||
const isWeightValid =
|
||||
!isNaN(parseInt(weight.toString(), 10)) &&
|
||||
weight >= 0 &&
|
||||
weight <= 1;
|
||||
return !(isSeedValid && isWeightValid);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
export const seedWeightsToString = (
|
||||
seedWeights: SeedWeights
|
||||
): string | boolean => {
|
||||
if (!validateSeedWeights(seedWeights)) {
|
||||
return false;
|
||||
seedWeights: InvokeAI.SeedWeights
|
||||
): string => {
|
||||
return seedWeights.reduce((acc, pair, i, arr) => {
|
||||
const { seed, weight } = pair;
|
||||
acc += `${seed}:${weight}`;
|
||||
if (i !== arr.length - 1) {
|
||||
acc += ',';
|
||||
}
|
||||
|
||||
return seedWeights.reduce((acc, pair, i, arr) => {
|
||||
const [seed, weight] = pair;
|
||||
acc += `${seed}:${weight}`;
|
||||
if (i !== arr.length - 1) {
|
||||
acc += ',';
|
||||
}
|
||||
return acc;
|
||||
}, '');
|
||||
return acc;
|
||||
}, '');
|
||||
};
|
||||
|
||||
export const seedWeightsToArray = (
|
||||
seedWeights: InvokeAI.SeedWeights
|
||||
): Array<Array<number>> => {
|
||||
return seedWeights.map((pair: InvokeAI.SeedWeightPair) => [
|
||||
pair.seed,
|
||||
pair.weight,
|
||||
]);
|
||||
};
|
||||
|
||||
export const stringToSeedWeightsArray = (
|
||||
string: string
|
||||
): Array<Array<number>> => {
|
||||
const stringPairs = string.split(',');
|
||||
const arrPairs = stringPairs.map((p) => p.split(':'));
|
||||
return arrPairs.map(
|
||||
(p: Array<string>): Array<number> => [parseInt(p[0]), parseFloat(p[1])]
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user