Merge branch 'release/invokeai-3-0-alpha' of https://github.com/invoke-ai/InvokeAI into release/invokeai-3-0-alpha

This commit is contained in:
blessedcoolant 2023-07-08 06:30:04 +12:00
commit f32a2f135c
55 changed files with 1084 additions and 589 deletions

View File

@ -92,6 +92,7 @@ class CompelInvocation(BaseInvocation):
with ModelPatcher.apply_lora_text_encoder(text_encoder_info.context.model, _lora_loader()),\
ModelPatcher.apply_ti(tokenizer_info.context.model, text_encoder_info.context.model, ti_list) as (tokenizer, ti_manager),\
ModelPatcher.apply_clip_skip(text_encoder_info.context.model, self.clip.skipped_layers),\
text_encoder_info as text_encoder:
compel = Compel(
@ -131,6 +132,24 @@ class CompelInvocation(BaseInvocation):
),
)
class ClipSkipInvocationOutput(BaseInvocationOutput):
"""Clip skip node output"""
type: Literal["clip_skip_output"] = "clip_skip_output"
clip: ClipField = Field(None, description="Clip with skipped layers")
class ClipSkipInvocation(BaseInvocation):
"""Skip layers in clip text_encoder model."""
type: Literal["clip_skip"] = "clip_skip"
clip: ClipField = Field(None, description="Clip to use")
skipped_layers: int = Field(0, description="Number of layers to skip in text_encoder")
def invoke(self, context: InvocationContext) -> ClipSkipInvocationOutput:
self.clip.skipped_layers += self.skipped_layers
return ClipSkipInvocationOutput(
clip=self.clip,
)
def get_max_token_count(
tokenizer, prompt: Union[FlattenedPrompt, Blend, Conjunction],

View File

@ -30,6 +30,7 @@ class UNetField(BaseModel):
class ClipField(BaseModel):
tokenizer: ModelInfo = Field(description="Info to load tokenizer submodel")
text_encoder: ModelInfo = Field(description="Info to load text_encoder submodel")
skipped_layers: int = Field(description="Number of skipped layers in text_encoder")
loras: List[LoraInfo] = Field(description="Loras to apply on model loading")
@ -154,6 +155,7 @@ class MainModelLoaderInvocation(BaseInvocation):
submodel=SubModelType.TextEncoder,
),
loras=[],
skipped_layers=0,
),
vae=VaeField(
vae=ModelInfo(

View File

@ -615,6 +615,24 @@ class ModelPatcher:
text_encoder.resize_token_embeddings(init_tokens_count)
@classmethod
@contextmanager
def apply_clip_skip(
cls,
text_encoder: CLIPTextModel,
clip_skip: int,
):
skipped_layers = []
try:
for i in range(clip_skip):
skipped_layers.append(text_encoder.text_model.encoder.layers.pop(-1))
yield
finally:
while len(skipped_layers) > 0:
text_encoder.text_model.encoder.layers.append(skipped_layers.pop())
class TextualInversionModel:
name: str
embedding: torch.Tensor # [n, 768]|[n, 1280]

View File

@ -23,7 +23,7 @@
"dev": "concurrently \"vite dev\" \"yarn run theme:watch\"",
"dev:host": "concurrently \"vite dev --host\" \"yarn run theme:watch\"",
"build": "yarn run lint && vite build",
"typegen": "npx openapi-typescript http://localhost:9090/openapi.json --output src/services/api/schema.d.ts -t",
"typegen": "npx ts-node scripts/typegen.ts",
"preview": "vite preview",
"lint:madge": "madge --circular src/main.tsx",
"lint:eslint": "eslint --max-warnings=0 .",
@ -83,7 +83,7 @@
"konva": "^9.2.0",
"lodash-es": "^4.17.21",
"nanostores": "^0.9.2",
"openapi-fetch": "0.4.0",
"openapi-fetch": "^0.6.1",
"overlayscrollbars": "^2.2.0",
"overlayscrollbars-react": "^0.5.0",
"patch-package": "^7.0.0",

View File

@ -1,55 +0,0 @@
diff --git a/node_modules/openapi-fetch/dist/index.js b/node_modules/openapi-fetch/dist/index.js
index cd4528a..8976b51 100644
--- a/node_modules/openapi-fetch/dist/index.js
+++ b/node_modules/openapi-fetch/dist/index.js
@@ -1,5 +1,5 @@
// settings & const
-const DEFAULT_HEADERS = {
+const CONTENT_TYPE_APPLICATION_JSON = {
"Content-Type": "application/json",
};
const TRAILING_SLASH_RE = /\/*$/;
@@ -29,18 +29,29 @@ export function createFinalURL(url, options) {
}
return finalURL;
}
+function stringifyBody(body) {
+ if (body instanceof ArrayBuffer || body instanceof File || body instanceof DataView || body instanceof Blob || ArrayBuffer.isView(body) || body instanceof URLSearchParams || body instanceof FormData) {
+ return;
+ }
+
+ if (typeof body === "string") {
+ return body;
+ }
+
+ return JSON.stringify(body);
+ }
+
export default function createClient(clientOptions = {}) {
const { fetch = globalThis.fetch, ...options } = clientOptions;
- const defaultHeaders = new Headers({
- ...DEFAULT_HEADERS,
- ...(options.headers ?? {}),
- });
+ const defaultHeaders = new Headers(options.headers ?? {});
async function coreFetch(url, fetchOptions) {
const { headers, body: requestBody, params = {}, parseAs = "json", querySerializer = defaultSerializer, ...init } = fetchOptions || {};
// URL
const finalURL = createFinalURL(url, { baseUrl: options.baseUrl, params, querySerializer });
+ // Stringify body if needed
+ const stringifiedBody = stringifyBody(requestBody);
// headers
- const baseHeaders = new Headers(defaultHeaders); // clone defaults (dont overwrite!)
+ const baseHeaders = new Headers(stringifiedBody ? { ...CONTENT_TYPE_APPLICATION_JSON, ...defaultHeaders } : defaultHeaders); // clone defaults (dont overwrite!)
const headerOverrides = new Headers(headers);
for (const [k, v] of headerOverrides.entries()) {
if (v === undefined || v === null)
@@ -54,7 +65,7 @@ export default function createClient(clientOptions = {}) {
...options,
...init,
headers: baseHeaders,
- body: typeof requestBody === "string" ? requestBody : JSON.stringify(requestBody),
+ body: stringifiedBody ?? requestBody,
});
// handle empty content
// note: we return `{}` because we want user truthy checks for `.data` or `.error` to succeed

View File

@ -527,7 +527,8 @@
"showOptionsPanel": "Show Options Panel",
"hidePreview": "Hide Preview",
"showPreview": "Show Preview",
"controlNetControlMode": "Control Mode"
"controlNetControlMode": "Control Mode",
"clipSkip": "Clip Skip"
},
"settings": {
"models": "Models",
@ -551,7 +552,8 @@
"generation": "Generation",
"ui": "User Interface",
"favoriteSchedulers": "Favorite Schedulers",
"favoriteSchedulersPlaceholder": "No schedulers favorited"
"favoriteSchedulersPlaceholder": "No schedulers favorited",
"showAdvancedOptions": "Show Advanced Options"
},
"toast": {
"serverError": "Server Error",

View File

@ -0,0 +1,3 @@
{
"type": "module"
}

View File

@ -0,0 +1,23 @@
import fs from 'node:fs';
import openapiTS from 'openapi-typescript';
const OPENAPI_URL = 'http://localhost:9090/openapi.json';
const OUTPUT_FILE = 'src/services/api/schema.d.ts';
async function main() {
process.stdout.write(
`Generating types "${OPENAPI_URL}" --> "${OUTPUT_FILE}"...`
);
const types = await openapiTS(OPENAPI_URL, {
exportType: true,
transform: (schemaObject, metadata) => {
if ('format' in schemaObject && schemaObject.format === 'binary') {
return schemaObject.nullable ? 'Blob | null' : 'Blob';
}
},
});
fs.writeFileSync(OUTPUT_FILE, types);
process.stdout.write(` OK!\r\n`);
}
main();

View File

@ -86,6 +86,7 @@ import { addRequestedBoardImageDeletionListener } from './listeners/boardImagesD
import { addSelectionAddedToBatchListener } from './listeners/selectionAddedToBatch';
import { addImageDroppedListener } from './listeners/imageDropped';
import { addImageToDeleteSelectedListener } from './listeners/imageToDeleteSelected';
import { addModelSelectedListener } from './listeners/modelSelected';
export const listenerMiddleware = createListenerMiddleware();
@ -220,3 +221,6 @@ addSelectionAddedToBatchListener();
// DND
addImageDroppedListener();
// Models
addModelSelectedListener();

View File

@ -0,0 +1,42 @@
import { makeToast } from 'app/components/Toaster';
import { modelSelected } from 'features/parameters/store/actions';
import {
modelChanged,
vaeSelected,
} from 'features/parameters/store/generationSlice';
import { zMainModel } from 'features/parameters/store/parameterZodSchemas';
import { addToast } from 'features/system/store/systemSlice';
import { startAppListening } from '..';
import { lorasCleared } from '../../../../../features/lora/store/loraSlice';
export const addModelSelectedListener = () => {
startAppListening({
actionCreator: modelSelected,
effect: (action, { getState, dispatch }) => {
const state = getState();
const [base_model, type, name] = action.payload.split('/');
if (state.generation.model?.base_model !== base_model) {
dispatch(
addToast(
makeToast({
title: 'Base model changed, clearing submodels',
status: 'warning',
})
)
);
dispatch(vaeSelected(null));
dispatch(lorasCleared());
// TODO: controlnet cleared
}
const newModel = zMainModel.parse({
id: action.payload,
base_model,
name,
});
dispatch(modelChanged(newModel));
},
});
};

View File

@ -93,7 +93,8 @@ export type AppFeature =
| 'discordLink'
| 'bugLink'
| 'localization'
| 'consoleLogging';
| 'consoleLogging'
| 'dynamicPrompting';
/**
* A disable-able Stable Diffusion feature
@ -104,7 +105,10 @@ export type SDFeature =
| 'variation'
| 'symmetry'
| 'seamless'
| 'hires';
| 'hires'
| 'lora'
| 'embedding'
| 'vae';
/**
* Configuration options for the InvokeAI UI.

View File

@ -32,7 +32,7 @@ const IAIMantineMultiSelect = (props: IAIMultiSelectProps) => {
const { colorMode } = useColorMode();
return (
<Tooltip label={tooltip} placement="top" hasArrow>
<Tooltip label={tooltip} placement="top" hasArrow isOpen={true}>
<MultiSelect
ref={inputRef}
searchable={searchable}
@ -66,6 +66,7 @@ const IAIMantineMultiSelect = (props: IAIMultiSelectProps) => {
'&[data-disabled]': {
backgroundColor: mode(base300, base700)(colorMode),
color: mode(base600, base400)(colorMode),
cursor: 'not-allowed',
},
},
value: {
@ -108,6 +109,10 @@ const IAIMantineMultiSelect = (props: IAIMultiSelectProps) => {
color: mode('white', base50)(colorMode),
},
},
'&[data-disabled]': {
color: mode(base500, base600)(colorMode),
cursor: 'not-allowed',
},
},
rightSection: {
width: 24,

View File

@ -67,6 +67,7 @@ const IAIMantineSelect = (props: IAISelectProps) => {
'&[data-disabled]': {
backgroundColor: mode(base300, base700)(colorMode),
color: mode(base600, base400)(colorMode),
cursor: 'not-allowed',
},
},
value: {
@ -109,6 +110,10 @@ const IAIMantineSelect = (props: IAISelectProps) => {
color: mode('white', base50)(colorMode),
},
},
'&[data-disabled]': {
color: mode(base500, base600)(colorMode),
cursor: 'not-allowed',
},
},
rightSection: {
width: 32,

View File

@ -0,0 +1,31 @@
import { Box, Tooltip } from '@chakra-ui/react';
import { Text } from '@mantine/core';
import { forwardRef, memo } from 'react';
interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
label: string;
description?: string;
tooltip?: string;
disabled?: boolean;
}
const IAIMantineSelectItemWithTooltip = forwardRef<HTMLDivElement, ItemProps>(
({ label, tooltip, description, disabled, ...others }: ItemProps, ref) => (
<Tooltip label={tooltip} placement="top" hasArrow>
<Box ref={ref} {...others}>
<Box>
<Text>{label}</Text>
{description && (
<Text size="xs" color="base.600">
{description}
</Text>
)}
</Box>
</Box>
</Tooltip>
)
);
IAIMantineSelectItemWithTooltip.displayName = 'IAIMantineSelectItemWithTooltip';
export default memo(IAIMantineSelectItemWithTooltip);

View File

@ -26,7 +26,7 @@ import {
} from '@chakra-ui/react';
import { clamp } from 'lodash-es';
import { useTranslation } from 'react-i18next';
import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
import {
FocusEvent,
memo,
@ -36,9 +36,9 @@ import {
useMemo,
useState,
} from 'react';
import { useTranslation } from 'react-i18next';
import { BiReset } from 'react-icons/bi';
import IAIIconButton, { IAIIconButtonProps } from './IAIIconButton';
import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
const SLIDER_MARK_STYLES: ChakraProps['sx'] = {
mt: 1.5,

View File

@ -7,6 +7,7 @@ import IAICollapse from 'common/components/IAICollapse';
import ParamDynamicPromptsCombinatorial from './ParamDynamicPromptsCombinatorial';
import ParamDynamicPromptsToggle from './ParamDynamicPromptsEnabled';
import ParamDynamicPromptsMaxPrompts from './ParamDynamicPromptsMaxPrompts';
import { useFeatureStatus } from '../../system/hooks/useFeatureStatus';
const selector = createSelector(
stateSelector,
@ -21,6 +22,13 @@ const selector = createSelector(
const ParamDynamicPromptsCollapse = () => {
const { activeLabel } = useAppSelector(selector);
const isDynamicPromptingEnabled =
useFeatureStatus('dynamicPrompting').isFeatureEnabled;
if (!isDynamicPromptingEnabled) {
return null;
}
return (
<IAICollapse label="Dynamic Prompts" activeLabel={activeLabel}>
<Flex sx={{ gap: 2, flexDir: 'column' }}>

View File

@ -1,6 +1,6 @@
import IAIIconButton from 'common/components/IAIIconButton';
import { memo } from 'react';
import { BiCode } from 'react-icons/bi';
import { FaCode } from 'react-icons/fa';
type Props = {
onClick: () => void;
@ -13,15 +13,24 @@ const AddEmbeddingButton = (props: Props) => {
size="sm"
aria-label="Add Embedding"
tooltip="Add Embedding"
icon={<BiCode />}
icon={<FaCode />}
sx={{
p: 2,
color: 'base.700',
color: 'base.500',
_hover: {
color: 'base.550',
color: 'base.600',
},
_active: {
color: 'base.700',
},
_dark: {
color: 'base.500',
_hover: {
color: 'base.400',
},
_active: {
color: 'base.300',
},
},
}}
variant="link"

View File

@ -6,24 +6,17 @@ import {
PopoverTrigger,
Text,
} from '@chakra-ui/react';
import { SelectItem } from '@mantine/core';
import { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import IAIMantineMultiSelect from 'common/components/IAIMantineMultiSelect';
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
import { MODEL_TYPE_MAP } from 'features/system/components/ModelSelect';
import { forEach } from 'lodash-es';
import {
PropsWithChildren,
forwardRef,
useCallback,
useMemo,
useRef,
} from 'react';
import { PropsWithChildren, useCallback, useMemo, useRef } from 'react';
import { useGetTextualInversionModelsQuery } from 'services/api/endpoints/models';
import { PARAMETERS_PANEL_WIDTH } from 'theme/util/constants';
type EmbeddingSelectItem = {
label: string;
value: string;
description?: string;
};
type Props = PropsWithChildren & {
onSelect: (v: string) => void;
isOpen: boolean;
@ -35,25 +28,37 @@ const ParamEmbeddingPopover = (props: Props) => {
const { data: embeddingQueryData } = useGetTextualInversionModelsQuery();
const inputRef = useRef<HTMLInputElement>(null);
const currentMainModel = useAppSelector(
(state: RootState) => state.generation.model
);
const data = useMemo(() => {
if (!embeddingQueryData) {
return [];
}
const data: EmbeddingSelectItem[] = [];
const data: SelectItem[] = [];
forEach(embeddingQueryData.entities, (embedding, _) => {
if (!embedding) return;
if (!embedding) {
return;
}
const disabled = currentMainModel?.base_model !== embedding.base_model;
data.push({
value: embedding.name,
label: embedding.name,
description: embedding.description,
group: MODEL_TYPE_MAP[embedding.base_model],
disabled,
tooltip: disabled
? `Incompatible base model: ${embedding.base_model}`
: undefined,
});
});
return data;
}, [embeddingQueryData]);
return data.sort((a, b) => (a.disabled && !b.disabled ? 1 : -1));
}, [embeddingQueryData, currentMainModel?.base_model]);
const handleChange = useCallback(
(v: string[]) => {
@ -108,10 +113,12 @@ const ParamEmbeddingPopover = (props: Props) => {
data={data}
maxDropdownHeight={400}
nothingFound="No Matching Embeddings"
itemComponent={SelectItem}
itemComponent={IAIMantineSelectItemWithTooltip}
disabled={data.length === 0}
filter={(value, selected, item: EmbeddingSelectItem) =>
item.label.toLowerCase().includes(value.toLowerCase().trim()) ||
filter={(value, selected, item: SelectItem) =>
item.label
?.toLowerCase()
.includes(value.toLowerCase().trim()) ||
item.value.toLowerCase().includes(value.toLowerCase().trim())
}
onChange={handleChange}
@ -124,28 +131,3 @@ const ParamEmbeddingPopover = (props: Props) => {
};
export default ParamEmbeddingPopover;
interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
value: string;
label: string;
description?: string;
}
const SelectItem = forwardRef<HTMLDivElement, ItemProps>(
({ label, description, ...others }: ItemProps, ref) => {
return (
<div ref={ref} {...others}>
<div>
<Text>{label}</Text>
{description && (
<Text size="xs" color="base.600">
{description}
</Text>
)}
</div>
</div>
);
}
);
SelectItem.displayName = 'SelectItem';

View File

@ -8,6 +8,7 @@ import { size } from 'lodash-es';
import { memo } from 'react';
import ParamLoraList from './ParamLoraList';
import ParamLoraSelect from './ParamLoraSelect';
import { useFeatureStatus } from '../../system/hooks/useFeatureStatus';
const selector = createSelector(
stateSelector,
@ -23,6 +24,12 @@ const selector = createSelector(
const ParamLoraCollapse = () => {
const { activeLabel } = useAppSelector(selector);
const isLoraEnabled = useFeatureStatus('lora').isFeatureEnabled;
if (!isLoraEnabled) {
return null;
}
return (
<IAICollapse label={'LoRA'} activeLabel={activeLabel}>
<Flex sx={{ flexDir: 'column', gap: 2 }}>

View File

@ -1,19 +1,16 @@
import { Flex, Text } from '@chakra-ui/react';
import { SelectItem } from '@mantine/core';
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { RootState, stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIMantineMultiSelect from 'common/components/IAIMantineMultiSelect';
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
import { loraAdded } from 'features/lora/store/loraSlice';
import { MODEL_TYPE_MAP } from 'features/system/components/ModelSelect';
import { forEach } from 'lodash-es';
import { forwardRef, useCallback, useMemo } from 'react';
import { useCallback, useMemo } from 'react';
import { useGetLoRAModelsQuery } from 'services/api/endpoints/models';
import { loraAdded } from '../store/loraSlice';
type LoraSelectItem = {
label: string;
value: string;
description?: string;
};
const selector = createSelector(
stateSelector,
@ -28,27 +25,37 @@ const ParamLoraSelect = () => {
const { loras } = useAppSelector(selector);
const { data: lorasQueryData } = useGetLoRAModelsQuery();
const currentMainModel = useAppSelector(
(state: RootState) => state.generation.model
);
const data = useMemo(() => {
if (!lorasQueryData) {
return [];
}
const data: LoraSelectItem[] = [];
const data: SelectItem[] = [];
forEach(lorasQueryData.entities, (lora, id) => {
if (!lora || Boolean(id in loras)) {
return;
}
const disabled = currentMainModel?.base_model !== lora.base_model;
data.push({
value: id,
label: lora.name,
description: lora.description,
disabled,
group: MODEL_TYPE_MAP[lora.base_model],
tooltip: disabled
? `Incompatible base model: ${lora.base_model}`
: undefined,
});
});
return data;
}, [loras, lorasQueryData]);
return data.sort((a, b) => (a.disabled && !b.disabled ? 1 : -1));
}, [loras, lorasQueryData, currentMainModel?.base_model]);
const handleChange = useCallback(
(v: string[]) => {
@ -78,10 +85,10 @@ const ParamLoraSelect = () => {
data={data}
maxDropdownHeight={400}
nothingFound="No matching LoRAs"
itemComponent={SelectItem}
itemComponent={IAIMantineSelectItemWithTooltip}
disabled={data.length === 0}
filter={(value, selected, item: LoraSelectItem) =>
item.label.toLowerCase().includes(value.toLowerCase().trim()) ||
filter={(value, selected, item: SelectItem) =>
item.label?.toLowerCase().includes(value.toLowerCase().trim()) ||
item.value.toLowerCase().includes(value.toLowerCase().trim())
}
onChange={handleChange}
@ -89,29 +96,4 @@ const ParamLoraSelect = () => {
);
};
interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
value: string;
label: string;
description?: string;
}
const SelectItem = forwardRef<HTMLDivElement, ItemProps>(
({ label, description, ...others }: ItemProps, ref) => {
return (
<div ref={ref} {...others}>
<div>
<Text>{label}</Text>
{description && (
<Text size="xs" color="base.600">
{description}
</Text>
)}
</div>
</div>
);
}
);
SelectItem.displayName = 'SelectItem';
export default ParamLoraSelect;

View File

@ -1,18 +1,21 @@
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
import { LoRAModelParam } from 'features/parameters/store/parameterZodSchemas';
import { LoRAModelConfigEntity } from 'services/api/endpoints/models';
import { BaseModelType } from 'services/api/types';
export type Lora = {
id: string;
base_model: BaseModelType;
name: string;
weight: number;
};
export const defaultLoRAConfig: Omit<Lora, 'id' | 'name'> = {
export const defaultLoRAConfig = {
weight: 0.75,
};
export type LoraState = {
loras: Record<string, Lora>;
loras: Record<string, LoRAModelParam & { weight: number }>;
};
export const intialLoraState: LoraState = {
@ -24,13 +27,16 @@ export const loraSlice = createSlice({
initialState: intialLoraState,
reducers: {
loraAdded: (state, action: PayloadAction<LoRAModelConfigEntity>) => {
const { name, id } = action.payload;
state.loras[id] = { id, name, ...defaultLoRAConfig };
const { name, id, base_model } = action.payload;
state.loras[id] = { id, name, base_model, ...defaultLoRAConfig };
},
loraRemoved: (state, action: PayloadAction<string>) => {
const id = action.payload;
delete state.loras[id];
},
lorasCleared: (state) => {
state.loras = {};
},
loraWeightChanged: (
state,
action: PayloadAction<{ id: string; weight: number }>
@ -45,7 +51,12 @@ export const loraSlice = createSlice({
},
});
export const { loraAdded, loraRemoved, loraWeightChanged, loraWeightReset } =
loraSlice.actions;
export const {
loraAdded,
loraRemoved,
loraWeightChanged,
loraWeightReset,
lorasCleared,
} = loraSlice.actions;
export default loraSlice.reducer;

View File

@ -4,6 +4,7 @@ import { forEach, size } from 'lodash-es';
import { LoraLoaderInvocation } from 'services/api/types';
import { modelIdToLoRAModelField } from '../modelIdToLoRAName';
import {
CLIP_SKIP,
LORA_LOADER,
MAIN_MODEL_LOADER,
NEGATIVE_CONDITIONING,
@ -27,14 +28,19 @@ export const addLoRAsToGraph = (
const loraCount = size(loras);
if (loraCount > 0) {
// remove any existing connections from main model loader, we need to insert the lora nodes
// Remove MAIN_MODEL_LOADER unet connection to feed it to LoRAs
graph.edges = graph.edges.filter(
(e) =>
!(
e.source.node_id === MAIN_MODEL_LOADER &&
['unet', 'clip'].includes(e.source.field)
['unet'].includes(e.source.field)
)
);
// Remove CLIP_SKIP connections to conditionings to feed it through LoRAs
graph.edges = graph.edges.filter(
(e) =>
!(e.source.node_id === CLIP_SKIP && ['clip'].includes(e.source.field))
);
}
// we need to remember the last lora so we can chain from it
@ -73,7 +79,7 @@ export const addLoRAsToGraph = (
graph.edges.push({
source: {
node_id: MAIN_MODEL_LOADER,
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {

View File

@ -16,10 +16,12 @@ export const addVAEToGraph = (
graph: NonNullableGraph,
state: RootState
): void => {
const { vae: vaeId } = state.generation;
const vae_model = modelIdToVAEModelField(vaeId);
const { vae } = state.generation;
const vae_model = modelIdToVAEModelField(vae?.id || '');
if (vaeId !== 'auto') {
const isAutoVae = !vae;
if (!isAutoVae) {
graph.nodes[VAE_LOADER] = {
type: 'vae_loader',
id: VAE_LOADER,
@ -30,7 +32,7 @@ export const addVAEToGraph = (
if (graph.id === TEXT_TO_IMAGE_GRAPH || graph.id === IMAGE_TO_IMAGE_GRAPH) {
graph.edges.push({
source: {
node_id: vaeId === 'auto' ? MAIN_MODEL_LOADER : VAE_LOADER,
node_id: isAutoVae ? MAIN_MODEL_LOADER : VAE_LOADER,
field: 'vae',
},
destination: {
@ -43,7 +45,7 @@ export const addVAEToGraph = (
if (graph.id === IMAGE_TO_IMAGE_GRAPH) {
graph.edges.push({
source: {
node_id: vaeId === 'auto' ? MAIN_MODEL_LOADER : VAE_LOADER,
node_id: isAutoVae ? MAIN_MODEL_LOADER : VAE_LOADER,
field: 'vae',
},
destination: {
@ -56,7 +58,7 @@ export const addVAEToGraph = (
if (graph.id === INPAINT_GRAPH) {
graph.edges.push({
source: {
node_id: vaeId === 'auto' ? MAIN_MODEL_LOADER : VAE_LOADER,
node_id: isAutoVae ? MAIN_MODEL_LOADER : VAE_LOADER,
field: 'vae',
},
destination: {

View File

@ -12,6 +12,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addVAEToGraph } from './addVAEToGraph';
import {
CLIP_SKIP,
IMAGE_TO_IMAGE_GRAPH,
IMAGE_TO_LATENTS,
LATENTS_TO_IMAGE,
@ -35,11 +36,12 @@ export const buildCanvasImageToImageGraph = (
const {
positivePrompt,
negativePrompt,
model: modelId,
model: currentModel,
cfgScale: cfg_scale,
scheduler,
steps,
img2imgStrength: strength,
clipSkip,
iterations,
seed,
shouldRandomizeSeed,
@ -48,7 +50,7 @@ export const buildCanvasImageToImageGraph = (
// The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions;
const model = modelIdToMainModelField(modelId);
const model = modelIdToMainModelField(currentModel?.id || '');
/**
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
@ -82,6 +84,11 @@ export const buildCanvasImageToImageGraph = (
id: MAIN_MODEL_LOADER,
model,
},
[CLIP_SKIP]: {
type: 'clip_skip',
id: CLIP_SKIP,
skipped_layers: clipSkip,
},
[LATENTS_TO_IMAGE]: {
type: 'l2i',
id: LATENTS_TO_IMAGE,
@ -109,6 +116,16 @@ export const buildCanvasImageToImageGraph = (
node_id: MAIN_MODEL_LOADER,
field: 'clip',
},
destination: {
node_id: CLIP_SKIP,
field: 'clip',
},
},
{
source: {
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {
node_id: POSITIVE_CONDITIONING,
field: 'clip',
@ -116,7 +133,7 @@ export const buildCanvasImageToImageGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {

View File

@ -11,6 +11,7 @@ import { modelIdToMainModelField } from '../modelIdToMainModelField';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addVAEToGraph } from './addVAEToGraph';
import {
CLIP_SKIP,
INPAINT,
INPAINT_GRAPH,
ITERATE,
@ -34,7 +35,7 @@ export const buildCanvasInpaintGraph = (
const {
positivePrompt,
negativePrompt,
model: modelId,
model: currentModel,
cfgScale: cfg_scale,
scheduler,
steps,
@ -49,6 +50,7 @@ export const buildCanvasInpaintGraph = (
seamStrength,
tileSize,
infillMethod,
clipSkip,
} = state.generation;
// The bounding box determines width and height, not the width and height params
@ -57,7 +59,7 @@ export const buildCanvasInpaintGraph = (
// We may need to set the inpaint width and height to scale the image
const { scaledBoundingBoxDimensions, boundingBoxScaleMethod } = state.canvas;
const model = modelIdToMainModelField(modelId);
const model = modelIdToMainModelField(currentModel?.id || '');
const graph: NonNullableGraph = {
id: INPAINT_GRAPH,
@ -108,6 +110,11 @@ export const buildCanvasInpaintGraph = (
id: MAIN_MODEL_LOADER,
model,
},
[CLIP_SKIP]: {
type: 'clip_skip',
id: CLIP_SKIP,
skipped_layers: clipSkip,
},
[RANGE_OF_SIZE]: {
type: 'range_of_size',
id: RANGE_OF_SIZE,
@ -122,6 +129,46 @@ export const buildCanvasInpaintGraph = (
},
},
edges: [
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'unet',
},
destination: {
node_id: INPAINT,
field: 'unet',
},
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'clip',
},
destination: {
node_id: CLIP_SKIP,
field: 'clip',
},
},
{
source: {
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {
node_id: POSITIVE_CONDITIONING,
field: 'clip',
},
},
{
source: {
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {
node_id: NEGATIVE_CONDITIONING,
field: 'clip',
},
},
{
source: {
node_id: NEGATIVE_CONDITIONING,
@ -142,36 +189,6 @@ export const buildCanvasInpaintGraph = (
field: 'positive_conditioning',
},
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'clip',
},
destination: {
node_id: POSITIVE_CONDITIONING,
field: 'clip',
},
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'clip',
},
destination: {
node_id: NEGATIVE_CONDITIONING,
field: 'clip',
},
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'unet',
},
destination: {
node_id: INPAINT,
field: 'unet',
},
},
{
source: {
node_id: RANGE_OF_SIZE,

View File

@ -6,6 +6,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addVAEToGraph } from './addVAEToGraph';
import {
CLIP_SKIP,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
NEGATIVE_CONDITIONING,
@ -24,10 +25,11 @@ export const buildCanvasTextToImageGraph = (
const {
positivePrompt,
negativePrompt,
model: modelId,
model: currentModel,
cfgScale: cfg_scale,
scheduler,
steps,
clipSkip,
iterations,
seed,
shouldRandomizeSeed,
@ -36,7 +38,7 @@ export const buildCanvasTextToImageGraph = (
// The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions;
const model = modelIdToMainModelField(modelId);
const model = modelIdToMainModelField(currentModel?.id || '');
/**
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
@ -79,6 +81,11 @@ export const buildCanvasTextToImageGraph = (
id: MAIN_MODEL_LOADER,
model,
},
[CLIP_SKIP]: {
type: 'clip_skip',
id: CLIP_SKIP,
skipped_layers: clipSkip,
},
[LATENTS_TO_IMAGE]: {
type: 'l2i',
id: LATENTS_TO_IMAGE,
@ -110,6 +117,16 @@ export const buildCanvasTextToImageGraph = (
node_id: MAIN_MODEL_LOADER,
field: 'clip',
},
destination: {
node_id: CLIP_SKIP,
field: 'clip',
},
},
{
source: {
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {
node_id: POSITIVE_CONDITIONING,
field: 'clip',
@ -117,7 +134,7 @@ export const buildCanvasTextToImageGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {

View File

@ -13,6 +13,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addVAEToGraph } from './addVAEToGraph';
import {
CLIP_SKIP,
IMAGE_COLLECTION,
IMAGE_COLLECTION_ITERATE,
IMAGE_TO_IMAGE_GRAPH,
@ -37,7 +38,7 @@ export const buildLinearImageToImageGraph = (
const {
positivePrompt,
negativePrompt,
model: modelId,
model: currentModel,
cfgScale: cfg_scale,
scheduler,
steps,
@ -46,6 +47,7 @@ export const buildLinearImageToImageGraph = (
shouldFitToWidthHeight,
width,
height,
clipSkip,
} = state.generation;
const {
@ -71,12 +73,22 @@ export const buildLinearImageToImageGraph = (
throw new Error('No initial image found in state');
}
const model = modelIdToMainModelField(modelId);
const model = modelIdToMainModelField(currentModel?.id || '');
// copy-pasted graph from node editor, filled in with state values & friendly node ids
const graph: NonNullableGraph = {
id: IMAGE_TO_IMAGE_GRAPH,
nodes: {
[MAIN_MODEL_LOADER]: {
type: 'main_model_loader',
id: MAIN_MODEL_LOADER,
model,
},
[CLIP_SKIP]: {
type: 'clip_skip',
id: CLIP_SKIP,
skipped_layers: clipSkip,
},
[POSITIVE_CONDITIONING]: {
type: 'compel',
id: POSITIVE_CONDITIONING,
@ -91,11 +103,6 @@ export const buildLinearImageToImageGraph = (
type: 'noise',
id: NOISE,
},
[MAIN_MODEL_LOADER]: {
type: 'main_model_loader',
id: MAIN_MODEL_LOADER,
model,
},
[LATENTS_TO_IMAGE]: {
type: 'l2i',
id: LATENTS_TO_IMAGE,
@ -121,6 +128,26 @@ export const buildLinearImageToImageGraph = (
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'unet',
},
destination: {
node_id: LATENTS_TO_LATENTS,
field: 'unet',
},
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'clip',
},
destination: {
node_id: CLIP_SKIP,
field: 'clip',
},
},
{
source: {
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {
@ -130,7 +157,7 @@ export const buildLinearImageToImageGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {
@ -168,17 +195,6 @@ export const buildLinearImageToImageGraph = (
field: 'noise',
},
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'unet',
},
destination: {
node_id: LATENTS_TO_LATENTS,
field: 'unet',
},
},
{
source: {
node_id: NEGATIVE_CONDITIONING,

View File

@ -6,6 +6,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addVAEToGraph } from './addVAEToGraph';
import {
CLIP_SKIP,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
NEGATIVE_CONDITIONING,
@ -21,15 +22,16 @@ export const buildLinearTextToImageGraph = (
const {
positivePrompt,
negativePrompt,
model: modelId,
model: currentModel,
cfgScale: cfg_scale,
scheduler,
steps,
width,
height,
clipSkip,
} = state.generation;
const model = modelIdToMainModelField(modelId);
const model = modelIdToMainModelField(currentModel?.id || '');
/**
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
@ -44,6 +46,16 @@ export const buildLinearTextToImageGraph = (
const graph: NonNullableGraph = {
id: TEXT_TO_IMAGE_GRAPH,
nodes: {
[MAIN_MODEL_LOADER]: {
type: 'main_model_loader',
id: MAIN_MODEL_LOADER,
model,
},
[CLIP_SKIP]: {
type: 'clip_skip',
id: CLIP_SKIP,
skipped_layers: clipSkip,
},
[POSITIVE_CONDITIONING]: {
type: 'compel',
id: POSITIVE_CONDITIONING,
@ -67,11 +79,6 @@ export const buildLinearTextToImageGraph = (
scheduler,
steps,
},
[MAIN_MODEL_LOADER]: {
type: 'main_model_loader',
id: MAIN_MODEL_LOADER,
model,
},
[LATENTS_TO_IMAGE]: {
type: 'l2i',
id: LATENTS_TO_IMAGE,
@ -80,12 +87,42 @@ export const buildLinearTextToImageGraph = (
edges: [
{
source: {
node_id: NEGATIVE_CONDITIONING,
field: 'conditioning',
node_id: MAIN_MODEL_LOADER,
field: 'clip',
},
destination: {
node_id: CLIP_SKIP,
field: 'clip',
},
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'unet',
},
destination: {
node_id: TEXT_TO_LATENTS,
field: 'negative_conditioning',
field: 'unet',
},
},
{
source: {
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {
node_id: POSITIVE_CONDITIONING,
field: 'clip',
},
},
{
source: {
node_id: CLIP_SKIP,
field: 'clip',
},
destination: {
node_id: NEGATIVE_CONDITIONING,
field: 'clip',
},
},
{
@ -100,32 +137,12 @@ export const buildLinearTextToImageGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'clip',
},
destination: {
node_id: POSITIVE_CONDITIONING,
field: 'clip',
},
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'clip',
},
destination: {
node_id: NEGATIVE_CONDITIONING,
field: 'clip',
},
},
{
source: {
node_id: MAIN_MODEL_LOADER,
field: 'unet',
field: 'conditioning',
},
destination: {
node_id: TEXT_TO_LATENTS,
field: 'unet',
field: 'negative_conditioning',
},
},
{

View File

@ -10,6 +10,7 @@ export const ITERATE = 'iterate';
export const MAIN_MODEL_LOADER = 'main_model_loader';
export const VAE_LOADER = 'vae_loader';
export const LORA_LOADER = 'lora_loader';
export const CLIP_SKIP = 'clip_skip';
export const IMAGE_TO_LATENTS = 'image_to_latents';
export const LATENTS_TO_LATENTS = 'latents_to_latents';
export const RESIZE = 'resize_image';

View File

@ -0,0 +1,34 @@
import { Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { RootState, stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAICollapse from 'common/components/IAICollapse';
import ParamClipSkip from './ParamClipSkip';
const selector = createSelector(
stateSelector,
(state: RootState) => {
const clipSkip = state.generation.clipSkip;
return {
activeLabel: clipSkip > 0 ? 'Clip Skip' : undefined,
};
},
defaultSelectorOptions
);
export default function ParamAdvancedCollapse() {
const { activeLabel } = useAppSelector(selector);
const shouldShowAdvancedOptions = useAppSelector(
(state: RootState) => state.ui.shouldShowAdvancedOptions
);
return (
shouldShowAdvancedOptions && (
<IAICollapse label={'Advanced'} activeLabel={activeLabel}>
<Flex sx={{ flexDir: 'column', gap: 2 }}>
<ParamClipSkip />
</Flex>
</IAICollapse>
)
);
}

View File

@ -0,0 +1,70 @@
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAISlider from 'common/components/IAISlider';
import { setClipSkip } from 'features/parameters/store/generationSlice';
import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
export const clipSkipMap = {
'sd-1': {
maxClip: 12,
markers: [0, 1, 2, 3, 4, 8, 12],
},
'sd-2': {
maxClip: 24,
markers: [0, 1, 2, 3, 5, 10, 15, 20, 24],
},
};
export default function ParamClipSkip() {
const clipSkip = useAppSelector(
(state: RootState) => state.generation.clipSkip
);
const { model } = useAppSelector((state: RootState) => state.generation);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const handleClipSkipChange = useCallback(
(v: number) => {
dispatch(setClipSkip(v));
},
[dispatch]
);
const handleClipSkipReset = useCallback(() => {
dispatch(setClipSkip(0));
}, [dispatch]);
const max = useMemo(() => {
if (!model) {
return clipSkipMap['sd-1'].maxClip;
}
return clipSkipMap[model.base_model].maxClip;
}, [model]);
const sliderMarks = useMemo(() => {
if (!model) {
return clipSkipMap['sd-1'].markers;
}
return clipSkipMap[model.base_model].markers;
}, [model]);
return (
<IAISlider
label={t('parameters.clipSkip')}
aria-label={t('parameters.clipSkip')}
min={0}
max={max}
step={1}
value={clipSkip}
onChange={handleClipSkipChange}
withSliderMarks
sliderMarks={sliderMarks}
withInput
withReset
handleReset={handleClipSkipReset}
/>
);
}

View File

@ -1,19 +0,0 @@
import { Box, Flex } from '@chakra-ui/react';
import ModelSelect from 'features/system/components/ModelSelect';
import VAESelect from 'features/system/components/VAESelect';
import { memo } from 'react';
const ParamModelandVAE = () => {
return (
<Flex gap={3} w="full">
<Box w="full">
<ModelSelect />
</Box>
<Box w="full">
<VAESelect />
</Box>
</Flex>
);
};
export default memo(ParamModelandVAE);

View File

@ -0,0 +1,31 @@
import { Box, Flex } from '@chakra-ui/react';
import ModelSelect from 'features/system/components/ModelSelect';
import VAESelect from 'features/system/components/VAESelect';
import { memo } from 'react';
import { useFeatureStatus } from '../../../../system/hooks/useFeatureStatus';
import ParamScheduler from './ParamScheduler';
const ParamModelandVAEandScheduler = () => {
const isVaeEnabled = useFeatureStatus('vae').isFeatureEnabled;
return (
<Flex gap={3} w="full" flexWrap={isVaeEnabled ? 'wrap' : 'nowrap'}>
<Flex gap={3} w="full">
<Box w="full">
<ModelSelect />
</Box>
{isVaeEnabled && (
<Box w="full">
<VAESelect />
</Box>
)}
</Flex>
<Box w="full">
<ParamScheduler />
</Box>
</Flex>
);
};
export default memo(ParamModelandVAEandScheduler);

View File

@ -8,6 +8,7 @@ import { setNegativePrompt } from 'features/parameters/store/generationSlice';
import { ChangeEvent, KeyboardEvent, useCallback, useRef } from 'react';
import { flushSync } from 'react-dom';
import { useTranslation } from 'react-i18next';
import { useFeatureStatus } from '../../../../system/hooks/useFeatureStatus';
const ParamNegativeConditioning = () => {
const negativePrompt = useAppSelector(
@ -71,6 +72,8 @@ const ParamNegativeConditioning = () => {
[dispatch, onClose, negativePrompt]
);
const isEmbeddingEnabled = useFeatureStatus('embedding').isFeatureEnabled;
return (
<FormControl>
<ParamEmbeddingPopover
@ -85,13 +88,13 @@ const ParamNegativeConditioning = () => {
value={negativePrompt}
placeholder={t('parameters.negativePromptPlaceholder')}
onChange={handleChangePrompt}
onKeyDown={handleKeyDown}
resize="vertical"
fontSize="sm"
minH={16}
{...(isEmbeddingEnabled && { onKeyDown: handleKeyDown })}
/>
</ParamEmbeddingPopover>
{!isOpen && (
{!isOpen && isEmbeddingEnabled && (
<Box
sx={{
position: 'absolute',

View File

@ -1,11 +1,10 @@
import { Box, FormControl, useDisclosure } from '@chakra-ui/react';
import { RootState } from 'app/store/store';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { ChangeEvent, KeyboardEvent, useCallback, useRef } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import {
GenerationState,
clampSymmetrySteps,
setPositivePrompt,
} from 'features/parameters/store/generationSlice';
@ -20,12 +19,14 @@ import { isEqual } from 'lodash-es';
import { flushSync } from 'react-dom';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { useFeatureStatus } from '../../../../system/hooks/useFeatureStatus';
const promptInputSelector = createSelector(
[(state: RootState) => state.generation, activeTabNameSelector],
(parameters: GenerationState, activeTabName) => {
[stateSelector, activeTabNameSelector],
({ generation, ui }, activeTabName) => {
return {
prompt: parameters.positivePrompt,
shouldPinParametersPanel: ui.shouldPinParametersPanel,
prompt: generation.positivePrompt,
activeTabName,
};
},
@ -41,7 +42,8 @@ const promptInputSelector = createSelector(
*/
const ParamPositiveConditioning = () => {
const dispatch = useAppDispatch();
const { prompt, activeTabName } = useAppSelector(promptInputSelector);
const { prompt, shouldPinParametersPanel, activeTabName } =
useAppSelector(promptInputSelector);
const isReady = useIsReadyToInvoke();
const promptRef = useRef<HTMLTextAreaElement>(null);
const { isOpen, onClose, onOpen } = useDisclosure();
@ -100,6 +102,8 @@ const ParamPositiveConditioning = () => {
[dispatch, onClose, prompt]
);
const isEmbeddingEnabled = useFeatureStatus('embedding').isFeatureEnabled;
const handleKeyDown = useCallback(
(e: KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter' && e.shiftKey === false && isReady) {
@ -107,11 +111,11 @@ const ParamPositiveConditioning = () => {
dispatch(clampSymmetrySteps());
dispatch(userInvoked(activeTabName));
}
if (e.key === '<') {
if (isEmbeddingEnabled && e.key === '<') {
onOpen();
}
},
[isReady, dispatch, activeTabName, onOpen]
[isReady, dispatch, activeTabName, onOpen, isEmbeddingEnabled]
);
// const handleSelect = (e: MouseEvent<HTMLTextAreaElement>) => {
@ -120,7 +124,7 @@ const ParamPositiveConditioning = () => {
// };
return (
<Box>
<Box position="relative">
<FormControl>
<ParamEmbeddingPopover
isOpen={isOpen}
@ -140,11 +144,11 @@ const ParamPositiveConditioning = () => {
/>
</ParamEmbeddingPopover>
</FormControl>
{!isOpen && (
{!isOpen && isEmbeddingEnabled && (
<Box
sx={{
position: 'absolute',
top: 6,
top: shouldPinParametersPanel ? 6 : 0,
insetInlineEnd: 0,
}}
>

View File

@ -1,8 +1,11 @@
import { useAppToaster } from 'app/components/Toaster';
import { useAppDispatch } from 'app/store/storeHooks';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { isImageField } from 'services/api/guards';
import { ImageDTO } from 'services/api/types';
import { initialImageSelected, modelSelected } from '../store/actions';
import {
modelSelected,
setCfgScale,
setHeight,
setImg2imgStrength,
@ -13,14 +16,10 @@ import {
setSteps,
setWidth,
} from '../store/generationSlice';
import { isImageField } from 'services/api/guards';
import { initialImageSelected } from '../store/actions';
import { useAppToaster } from 'app/components/Toaster';
import { ImageDTO } from 'services/api/types';
import {
isValidCfgScale,
isValidHeight,
isValidModel,
isValidMainModel,
isValidNegativePrompt,
isValidPositivePrompt,
isValidScheduler,
@ -159,11 +158,11 @@ export const useRecallParameters = () => {
*/
const recallModel = useCallback(
(model: unknown) => {
if (!isValidModel(model)) {
if (!isValidMainModel(model)) {
parameterNotSetToast();
return;
}
dispatch(modelSelected(model));
dispatch(modelSelected(model?.id || ''));
parameterSetToast();
},
[dispatch, parameterSetToast, parameterNotSetToast]
@ -296,7 +295,7 @@ export const useRecallParameters = () => {
if (isValidCfgScale(cfg_scale)) {
dispatch(setCfgScale(cfg_scale));
}
if (isValidModel(model)) {
if (isValidMainModel(model)) {
dispatch(modelSelected(model));
}
if (isValidPositivePrompt(positive_conditioning)) {

View File

@ -4,3 +4,5 @@ import { ImageDTO } from 'services/api/types';
export const initialImageSelected = createAction<ImageDTO | string | undefined>(
'generation/initialImageSelected'
);
export const modelSelected = createAction<string>('generation/modelSelected');

View File

@ -2,20 +2,23 @@ import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { DEFAULT_SCHEDULER_NAME } from 'app/constants';
import { configChanged } from 'features/system/store/configSlice';
import { setShouldShowAdvancedOptions } from 'features/ui/store/uiSlice';
import { clamp } from 'lodash-es';
import { ImageDTO } from 'services/api/types';
import { clipSkipMap } from '../components/Parameters/Advanced/ParamClipSkip';
import {
CfgScaleParam,
HeightParam,
ModelParam,
MainModelParam,
NegativePromptParam,
PositivePromptParam,
SchedulerParam,
SeedParam,
StepsParam,
StrengthParam,
VAEParam,
VaeModelParam,
WidthParam,
zMainModel,
} from './parameterZodSchemas';
export interface GenerationState {
@ -47,10 +50,11 @@ export interface GenerationState {
shouldUseSymmetry: boolean;
horizontalSymmetrySteps: number;
verticalSymmetrySteps: number;
model: ModelParam;
vae: VAEParam;
model: MainModelParam | null;
vae: VaeModelParam | null;
seamlessXAxis: boolean;
seamlessYAxis: boolean;
clipSkip: number;
}
export const initialGenerationState: GenerationState = {
@ -81,10 +85,11 @@ export const initialGenerationState: GenerationState = {
shouldUseSymmetry: false,
horizontalSymmetrySteps: 0,
verticalSymmetrySteps: 0,
model: '',
vae: '',
model: null,
vae: null,
seamlessXAxis: false,
seamlessYAxis: false,
clipSkip: 0,
};
const initialState: GenerationState = initialGenerationState;
@ -212,19 +217,46 @@ export const generationSlice = createSlice({
state.initialImage = { imageName: image_name, width, height };
},
modelSelected: (state, action: PayloadAction<string>) => {
const [base_model, type, name] = action.payload.split('/');
state.model = zMainModel.parse({
id: action.payload,
base_model,
name,
type,
});
// Clamp ClipSkip Based On Selected Model
const { maxClip } = clipSkipMap[state.model.base_model];
state.clipSkip = clamp(state.clipSkip, 0, maxClip);
},
modelChanged: (state, action: PayloadAction<MainModelParam>) => {
state.model = action.payload;
},
vaeSelected: (state, action: PayloadAction<string>) => {
vaeSelected: (state, action: PayloadAction<VaeModelParam | null>) => {
state.vae = action.payload;
},
setClipSkip: (state, action: PayloadAction<number>) => {
state.clipSkip = action.payload;
},
},
extraReducers: (builder) => {
builder.addCase(configChanged, (state, action) => {
const defaultModel = action.payload.sd?.defaultModel;
if (defaultModel && !state.model) {
state.model = defaultModel;
const [base_model, model_type, model_name] = defaultModel.split('/');
state.model = zMainModel.parse({
id: defaultModel,
name: model_name,
base_model,
});
}
});
builder.addCase(setShouldShowAdvancedOptions, (state, action) => {
const advancedOptionsStatus = action.payload;
if (!advancedOptionsStatus) state.clipSkip = 0;
});
},
});
@ -260,11 +292,12 @@ export const {
setHorizontalSymmetrySteps,
setVerticalSymmetrySteps,
initialImageChanged,
modelSelected,
modelChanged,
vaeSelected,
setShouldUseNoiseSettings,
setSeamlessXAxis,
setSeamlessYAxis,
setClipSkip,
} = generationSlice.actions;
export default generationSlice.reducer;

View File

@ -126,29 +126,63 @@ export type HeightParam = z.infer<typeof zHeight>;
export const isValidHeight = (val: unknown): val is HeightParam =>
zHeight.safeParse(val).success;
const zBaseModel = z.enum(['sd-1', 'sd-2']);
export type BaseModelParam = z.infer<typeof zBaseModel>;
/**
* Zod schema for model parameter
* TODO: Make this a dynamically generated enum?
*/
export const zModel = z.string();
export const zMainModel = z.object({
id: z.string(),
name: z.string(),
base_model: zBaseModel,
});
/**
* Type alias for model parameter, inferred from its zod schema
*/
export type ModelParam = z.infer<typeof zModel>;
/**
* Zod schema for VAE parameter
* TODO: Make this a dynamically generated enum?
*/
export const zVAE = z.string();
/**
* Type alias for model parameter, inferred from its zod schema
*/
export type VAEParam = z.infer<typeof zVAE>;
export type MainModelParam = z.infer<typeof zMainModel>;
/**
* Validates/type-guards a value as a model parameter
*/
export const isValidModel = (val: unknown): val is ModelParam =>
zModel.safeParse(val).success;
export const isValidMainModel = (val: unknown): val is MainModelParam =>
zMainModel.safeParse(val).success;
/**
* Zod schema for VAE parameter
*/
export const zVaeModel = z.object({
id: z.string(),
name: z.string(),
base_model: zBaseModel,
});
/**
* Type alias for model parameter, inferred from its zod schema
*/
export type VaeModelParam = z.infer<typeof zVaeModel>;
/**
* Validates/type-guards a value as a model parameter
*/
export const isValidVaeModel = (val: unknown): val is VaeModelParam =>
zVaeModel.safeParse(val).success;
/**
* Zod schema for LoRA
*/
export const zLoRAModel = z.object({
id: z.string(),
name: z.string(),
base_model: zBaseModel,
});
/**
* Type alias for model parameter, inferred from its zod schema
*/
export type LoRAModelParam = z.infer<typeof zLoRAModel>;
/**
* Validates/type-guards a value as a model parameter
*/
export const isValidLoRAModel = (val: unknown): val is LoRAModelParam =>
zLoRAModel.safeParse(val).success;
/**
* Zod schema for l2l strength parameter

View File

@ -3,10 +3,10 @@ import { useTranslation } from 'react-i18next';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIMantineSelect from 'common/components/IAIMantineSelect';
import { modelSelected } from 'features/parameters/store/generationSlice';
import { SelectItem } from '@mantine/core';
import { RootState } from 'app/store/store';
import { modelSelected } from 'features/parameters/store/actions';
import { forEach, isString } from 'lodash-es';
import { useGetMainModelsQuery } from 'services/api/endpoints/models';
@ -19,7 +19,7 @@ const ModelSelect = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const selectedModelId = useAppSelector(
const currentModel = useAppSelector(
(state: RootState) => state.generation.model
);
@ -48,8 +48,8 @@ const ModelSelect = () => {
}, [mainModels]);
const selectedModel = useMemo(
() => mainModels?.entities[selectedModelId],
[mainModels?.entities, selectedModelId]
() => mainModels?.entities[currentModel?.id || ''],
[mainModels?.entities, currentModel]
);
const handleChangeModel = useCallback(
@ -63,7 +63,13 @@ const ModelSelect = () => {
);
useEffect(() => {
if (selectedModelId && mainModels?.ids.includes(selectedModelId)) {
if (isLoading) {
// return early here to avoid resetting model selection before we've loaded the available models
return;
}
if (selectedModel && mainModels?.ids.includes(selectedModel?.id)) {
// the selected model is an available model, no need to change it
return;
}
@ -74,7 +80,7 @@ const ModelSelect = () => {
}
handleChangeModel(firstModel);
}, [handleChangeModel, mainModels?.ids, selectedModelId]);
}, [handleChangeModel, isLoading, mainModels?.ids, selectedModel]);
return isLoading ? (
<IAIMantineSelect
@ -87,7 +93,7 @@ const ModelSelect = () => {
<IAIMantineSelect
tooltip={selectedModel?.description}
label={t('modelManager.model')}
value={selectedModelId}
value={selectedModel?.id}
placeholder={data.length > 0 ? 'Select a model' : 'No models detected!'}
data={data}
error={data.length === 0}

View File

@ -30,6 +30,7 @@ import {
} from 'features/system/store/systemSlice';
import { uiSelector } from 'features/ui/store/uiSelectors';
import {
setShouldShowAdvancedOptions,
setShouldShowProgressInViewer,
setShouldUseCanvasBetaLayout,
setShouldUseSliders,
@ -64,6 +65,7 @@ const selector = createSelector(
shouldUseCanvasBetaLayout,
shouldUseSliders,
shouldShowProgressInViewer,
shouldShowAdvancedOptions,
} = ui;
return {
@ -76,6 +78,7 @@ const selector = createSelector(
consoleLogLevel,
shouldLogToConsole,
shouldAntialiasProgressImage,
shouldShowAdvancedOptions,
};
},
{
@ -87,6 +90,7 @@ type ConfigOptions = {
shouldShowDeveloperSettings: boolean;
shouldShowResetWebUiText: boolean;
shouldShowBetaLayout: boolean;
shouldShowAdvancedOptionsSettings: boolean;
};
type SettingsModalProps = {
@ -103,6 +107,8 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
const shouldShowDeveloperSettings =
config?.shouldShowDeveloperSettings ?? true;
const shouldShowResetWebUiText = config?.shouldShowResetWebUiText ?? true;
const shouldShowAdvancedOptionsSettings =
config?.shouldShowAdvancedOptionsSettings ?? true;
useEffect(() => {
if (!shouldShowDeveloperSettings) {
@ -132,6 +138,7 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
consoleLogLevel,
shouldLogToConsole,
shouldAntialiasProgressImage,
shouldShowAdvancedOptions,
} = useAppSelector(selector);
const handleClickResetWebUI = useCallback(() => {
@ -189,6 +196,15 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
dispatch(setShouldConfirmOnDelete(e.target.checked))
}
/>
{shouldShowAdvancedOptionsSettings && (
<IAISwitch
label={t('settings.showAdvancedOptions')}
isChecked={shouldShowAdvancedOptions}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
dispatch(setShouldShowAdvancedOptions(e.target.checked))
}
/>
)}
</StyledFlex>
<StyledFlex>

View File

@ -9,7 +9,9 @@ import { forEach } from 'lodash-es';
import { useGetVaeModelsQuery } from 'services/api/endpoints/models';
import { RootState } from 'app/store/store';
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
import { vaeSelected } from 'features/parameters/store/generationSlice';
import { zVaeModel } from 'features/parameters/store/parameterZodSchemas';
import { MODEL_TYPE_MAP } from './ModelSelect';
const VAESelect = () => {
@ -18,7 +20,11 @@ const VAESelect = () => {
const { data: vaeModels } = useGetVaeModelsQuery();
const selectedModelId = useAppSelector(
const currentMainModel = useAppSelector(
(state: RootState) => state.generation.model
);
const selectedVae = useAppSelector(
(state: RootState) => state.generation.vae
);
@ -29,8 +35,8 @@ const VAESelect = () => {
const data: SelectItem[] = [
{
value: 'auto',
label: 'Automatic',
value: 'default',
label: 'Default',
group: 'Default',
},
];
@ -40,46 +46,65 @@ const VAESelect = () => {
return;
}
const disabled = currentMainModel?.base_model !== model.base_model;
data.push({
value: id,
label: model.name,
group: MODEL_TYPE_MAP[model.base_model],
disabled,
tooltip: disabled
? `Incompatible base model: ${model.base_model}`
: undefined,
});
});
return data;
}, [vaeModels]);
return data.sort((a, b) => (a.disabled && !b.disabled ? 1 : -1));
}, [vaeModels, currentMainModel?.base_model]);
const selectedModel = useMemo(
() => vaeModels?.entities[selectedModelId],
[vaeModels?.entities, selectedModelId]
const selectedVaeModel = useMemo(
() => (selectedVae?.id ? vaeModels?.entities[selectedVae?.id] : null),
[vaeModels?.entities, selectedVae]
);
const handleChangeModel = useCallback(
(v: string | null) => {
if (!v) {
if (!v || v === 'default') {
dispatch(vaeSelected(null));
return;
}
dispatch(vaeSelected(v));
const [base_model, type, name] = v.split('/');
const model = zVaeModel.parse({
id: v,
name,
base_model,
});
dispatch(vaeSelected(model));
},
[dispatch]
);
useEffect(() => {
if (selectedModelId && vaeModels?.ids.includes(selectedModelId)) {
if (selectedVae && vaeModels?.ids.includes(selectedVae.id)) {
return;
}
handleChangeModel('auto');
}, [handleChangeModel, vaeModels?.ids, selectedModelId]);
dispatch(vaeSelected(null));
}, [handleChangeModel, vaeModels?.ids, selectedVae, dispatch]);
return (
<IAIMantineSelect
tooltip={selectedModel?.description}
itemComponent={IAIMantineSelectItemWithTooltip}
tooltip={selectedVaeModel?.description}
label={t('modelManager.vae')}
value={selectedModelId}
placeholder="Pick one"
value={selectedVae?.id ?? 'default'}
placeholder="Default"
data={data}
onChange={handleChangeModel}
disabled={data.length === 0}
clearable
/>
);
};

View File

@ -33,12 +33,21 @@ const PinParametersPanelButton = (props: PinParametersPanelButtonProps) => {
variant="ghost"
size="sm"
sx={{
color: 'base.700',
color: 'base.500',
_hover: {
color: 'base.550',
color: 'base.600',
},
_active: {
color: 'base.700',
},
_dark: {
color: 'base.500',
_hover: {
color: 'base.400',
},
_active: {
color: 'base.300',
},
},
...sx,
}}

View File

@ -6,8 +6,7 @@ import IAICollapse from 'common/components/IAICollapse';
import ParamCFGScale from 'features/parameters/components/Parameters/Core/ParamCFGScale';
import ParamHeight from 'features/parameters/components/Parameters/Core/ParamHeight';
import ParamIterations from 'features/parameters/components/Parameters/Core/ParamIterations';
import ParamModelandVAE from 'features/parameters/components/Parameters/Core/ParamModelandVAE';
import ParamScheduler from 'features/parameters/components/Parameters/Core/ParamScheduler';
import ParamModelandVAEandScheduler from 'features/parameters/components/Parameters/Core/ParamModelandVAEandScheduler';
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
import ParamWidth from 'features/parameters/components/Parameters/Core/ParamWidth';
import ImageToImageFit from 'features/parameters/components/Parameters/ImageToImage/ImageToImageFit';
@ -48,7 +47,7 @@ const ImageToImageTabCoreParameters = () => {
>
{shouldUseSliders ? (
<>
<ParamModelandVAE />
<ParamModelandVAEandScheduler />
<Box pt={2}>
<ParamSeedFull />
</Box>
@ -65,8 +64,7 @@ const ImageToImageTabCoreParameters = () => {
<ParamSteps />
<ParamCFGScale />
</Flex>
<ParamModelandVAE />
<ParamScheduler />
<ParamModelandVAEandScheduler />
<Box pt={2}>
<ParamSeedFull />
</Box>

View File

@ -1,5 +1,6 @@
import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/ParamDynamicPromptsCollapse';
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
import ParamNegativeConditioning from 'features/parameters/components/Parameters/Core/ParamNegativeConditioning';
import ParamPositiveConditioning from 'features/parameters/components/Parameters/Core/ParamPositiveConditioning';
@ -25,6 +26,7 @@ const ImageToImageTabParameters = () => {
<ParamNoiseCollapse />
<ParamSymmetryCollapse />
<ParamSeamlessCollapse />
<ParamAdvancedCollapse />
</>
);
};

View File

@ -7,8 +7,7 @@ import IAICollapse from 'common/components/IAICollapse';
import ParamCFGScale from 'features/parameters/components/Parameters/Core/ParamCFGScale';
import ParamHeight from 'features/parameters/components/Parameters/Core/ParamHeight';
import ParamIterations from 'features/parameters/components/Parameters/Core/ParamIterations';
import ParamModelandVAE from 'features/parameters/components/Parameters/Core/ParamModelandVAE';
import ParamScheduler from 'features/parameters/components/Parameters/Core/ParamScheduler';
import ParamModelandVAEandScheduler from 'features/parameters/components/Parameters/Core/ParamModelandVAEandScheduler';
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
import ParamWidth from 'features/parameters/components/Parameters/Core/ParamWidth';
import ParamSeedFull from 'features/parameters/components/Parameters/Seed/ParamSeedFull';
@ -44,7 +43,7 @@ const TextToImageTabCoreParameters = () => {
>
{shouldUseSliders ? (
<>
<ParamModelandVAE />
<ParamModelandVAEandScheduler />
<Box pt={2}>
<ParamSeedFull />
</Box>
@ -61,8 +60,7 @@ const TextToImageTabCoreParameters = () => {
<ParamSteps />
<ParamCFGScale />
</Flex>
<ParamModelandVAE />
<ParamScheduler />
<ParamModelandVAEandScheduler />
<Box pt={2}>
<ParamSeedFull />
</Box>

View File

@ -1,5 +1,6 @@
import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/ParamDynamicPromptsCollapse';
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
import ParamNegativeConditioning from 'features/parameters/components/Parameters/Core/ParamNegativeConditioning';
import ParamPositiveConditioning from 'features/parameters/components/Parameters/Core/ParamPositiveConditioning';
@ -27,6 +28,7 @@ const TextToImageTabParameters = () => {
<ParamSymmetryCollapse />
<ParamHiresCollapse />
<ParamSeamlessCollapse />
<ParamAdvancedCollapse />
</>
);
};

View File

@ -8,8 +8,7 @@ import ParamBoundingBoxHeight from 'features/parameters/components/Parameters/Ca
import ParamBoundingBoxWidth from 'features/parameters/components/Parameters/Canvas/BoundingBox/ParamBoundingBoxWidth';
import ParamCFGScale from 'features/parameters/components/Parameters/Core/ParamCFGScale';
import ParamIterations from 'features/parameters/components/Parameters/Core/ParamIterations';
import ParamModelandVAE from 'features/parameters/components/Parameters/Core/ParamModelandVAE';
import ParamScheduler from 'features/parameters/components/Parameters/Core/ParamScheduler';
import ParamModelandVAEandScheduler from 'features/parameters/components/Parameters/Core/ParamModelandVAEandScheduler';
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
import ImageToImageStrength from 'features/parameters/components/Parameters/ImageToImage/ImageToImageStrength';
import ParamSeedFull from 'features/parameters/components/Parameters/Seed/ParamSeedFull';
@ -45,7 +44,7 @@ const UnifiedCanvasCoreParameters = () => {
>
{shouldUseSliders ? (
<>
<ParamModelandVAE />
<ParamModelandVAEandScheduler />
<Box pt={2}>
<ParamSeedFull />
</Box>
@ -62,8 +61,7 @@ const UnifiedCanvasCoreParameters = () => {
<ParamSteps />
<ParamCFGScale />
</Flex>
<ParamModelandVAE />
<ParamScheduler />
<ParamModelandVAEandScheduler />
<Box pt={2}>
<ParamSeedFull />
</Box>

View File

@ -1,5 +1,6 @@
import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/ParamDynamicPromptsCollapse';
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamInfillAndScalingCollapse from 'features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillAndScalingCollapse';
import ParamSeamCorrectionCollapse from 'features/parameters/components/Parameters/Canvas/SeamCorrection/ParamSeamCorrectionCollapse';
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
@ -25,6 +26,7 @@ const UnifiedCanvasParameters = () => {
<ParamSymmetryCollapse />
<ParamSeamCorrectionCollapse />
<ParamInfillAndScalingCollapse />
<ParamAdvancedCollapse />
</>
);
};

View File

@ -20,6 +20,7 @@ export const initialUIState: UIState = {
shouldHidePreview: false,
shouldShowProgressInViewer: true,
shouldShowEmbeddingPicker: false,
shouldShowAdvancedOptions: false,
favoriteSchedulers: [],
};
@ -100,6 +101,9 @@ export const uiSlice = createSlice({
toggleEmbeddingPicker: (state) => {
state.shouldShowEmbeddingPicker = !state.shouldShowEmbeddingPicker;
},
setShouldShowAdvancedOptions: (state, action: PayloadAction<boolean>) => {
state.shouldShowAdvancedOptions = action.payload;
},
},
extraReducers(builder) {
builder.addCase(initialImageChanged, (state) => {
@ -127,6 +131,7 @@ export const {
setShouldShowProgressInViewer,
favoriteSchedulersChanged,
toggleEmbeddingPicker,
setShouldShowAdvancedOptions,
} = uiSlice.actions;
export default uiSlice.reducer;

View File

@ -28,5 +28,6 @@ export interface UIState {
shouldShowGallery: boolean;
shouldShowProgressInViewer: boolean;
shouldShowEmbeddingPicker: boolean;
shouldShowAdvancedOptions: boolean;
favoriteSchedulers: SchedulerParam[];
}

View File

@ -75,25 +75,37 @@ export type paths = {
* @description Gets a list of models
*/
get: operations["list_models"];
/**
* Update Model
* @description Add Model
*/
post: operations["update_model"];
};
"/api/v1/models/import": {
/**
* Import Model
* @description Add a model using its local path, repo_id, or remote URL
*/
post: operations["import_model"];
};
"/api/v1/models/{model_name}": {
"/api/v1/models/{base_model}/{model_type}/{model_name}": {
/**
* Delete Model
* @description Delete Model
*/
delete: operations["del_model"];
/**
* Update Model
* @description Add Model
*/
patch: operations["update_model"];
};
"/api/v1/models/convert/{base_model}/{model_type}/{model_name}": {
/**
* Convert Model
* @description Convert a checkpoint model into a diffusers model
*/
put: operations["convert_model"];
};
"/api/v1/models/merge/{base_model}": {
/**
* Merge Models
* @description Convert a checkpoint model into a diffusers model
*/
put: operations["merge_models"];
};
"/api/v1/images/": {
/**
@ -234,23 +246,6 @@ export type components = {
*/
b?: number;
};
/** AddModelResult */
AddModelResult: {
/**
* Name
* @description The name of the model after import
*/
name: string;
/** @description The type of model */
model_type: components["schemas"]["ModelType"];
/** @description The base model */
base_model: components["schemas"]["BaseModelType"];
/**
* Config
* @description The configuration of the model
*/
config: components["schemas"]["ModelConfigBase"];
};
/**
* BaseModelType
* @description An enumeration.
@ -324,6 +319,48 @@ export type components = {
*/
image_name: string;
};
/** Body_import_model */
Body_import_model: {
/**
* Location
* @description A model path, repo_id or URL to import
*/
location: string;
/**
* Prediction Type
* @description Prediction type for SDv2 checkpoint files
* @default v_prediction
* @enum {string}
*/
prediction_type?: "v_prediction" | "epsilon" | "sample";
};
/** Body_merge_models */
Body_merge_models: {
/**
* Model Names
* @description model name
*/
model_names: (string)[];
/**
* Merged Model Name
* @description Name of destination model
*/
merged_model_name: string;
/**
* Alpha
* @description Alpha weighting strength to apply to 2d and 3d models
* @default 0.5
*/
alpha?: number;
/** @description Interpolation method */
interp: components["schemas"]["MergeInterpolationMethod"];
/**
* Force
* @description Force merging of models created with different versions of diffusers
* @default false
*/
force?: boolean;
};
/** Body_remove_board_image */
Body_remove_board_image: {
/**
@ -343,7 +380,7 @@ export type components = {
* File
* Format: binary
*/
file: string;
file: Blob;
};
/**
* CannyImageProcessorInvocation
@ -385,55 +422,6 @@ export type components = {
*/
high_threshold?: number;
};
/** CkptModelInfo */
CkptModelInfo: {
/**
* Description
* @description A description of the model
*/
description?: string;
/**
* Model Name
* @description The name of the model
*/
model_name: string;
/**
* Model Type
* @description The type of the model
*/
model_type: string;
/**
* Format
* @default ckpt
* @enum {string}
*/
format?: "ckpt";
/**
* Config
* @description The path to the model config
*/
config: string;
/**
* Weights
* @description The path to the model weights
*/
weights: string;
/**
* Vae
* @description The path to the model VAE
*/
vae: string;
/**
* Width
* @description The width of the model
*/
width?: number;
/**
* Height
* @description The height of the model
*/
height?: number;
};
/** ClipField */
ClipField: {
/**
@ -446,12 +434,68 @@ export type components = {
* @description Info to load text_encoder submodel
*/
text_encoder: components["schemas"]["ModelInfo"];
/**
* Skipped Layers
* @description Number of skipped layers in text_encoder
*/
skipped_layers: number;
/**
* Loras
* @description Loras to apply on model loading
*/
loras: (components["schemas"]["LoraInfo"])[];
};
/**
* ClipSkipInvocation
* @description Skip layers in clip text_encoder model.
*/
ClipSkipInvocation: {
/**
* Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
* Is Intermediate
* @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
* Type
* @default clip_skip
* @enum {string}
*/
type?: "clip_skip";
/**
* Clip
* @description Clip to use
*/
clip?: components["schemas"]["ClipField"];
/**
* Skipped Layers
* @description Number of layers to skip in text_encoder
* @default 0
*/
skipped_layers?: number;
};
/**
* ClipSkipInvocationOutput
* @description Clip skip node output
*/
ClipSkipInvocationOutput: {
/**
* Type
* @default clip_skip_output
* @enum {string}
*/
type?: "clip_skip_output";
/**
* Clip
* @description Clip with skipped layers
*/
clip?: components["schemas"]["ClipField"];
};
/**
* CollectInvocation
* @description Collects values into a collection
@ -780,19 +824,6 @@ export type components = {
*/
control?: components["schemas"]["ControlField"];
};
/** CreateModelRequest */
CreateModelRequest: {
/**
* Name
* @description The name of the model
*/
name: string;
/**
* Info
* @description The model info
*/
info: components["schemas"]["CkptModelInfo"] | components["schemas"]["DiffusersModelInfo"];
};
/**
* CvInpaintInvocation
* @description Simple inpaint using opencv.
@ -826,45 +857,6 @@ export type components = {
*/
mask?: components["schemas"]["ImageField"];
};
/** DiffusersModelInfo */
DiffusersModelInfo: {
/**
* Description
* @description A description of the model
*/
description?: string;
/**
* Model Name
* @description The name of the model
*/
model_name: string;
/**
* Model Type
* @description The type of the model
*/
model_type: string;
/**
* Format
* @default folder
* @enum {string}
*/
format?: "folder";
/**
* Vae
* @description The VAE repo to use for this model
*/
vae?: components["schemas"]["VaeRepo"];
/**
* Repo Id
* @description The repo ID to use for this model
*/
repo_id?: string;
/**
* Path
* @description The path to the model
*/
path?: string;
};
/**
* DivideInvocation
* @description Divides two numbers
@ -1054,7 +1046,7 @@ export type components = {
* @description The nodes in this graph
*/
nodes?: {
[key: string]: (components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["UpscaleInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"]) | undefined;
[key: string]: (components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["UpscaleInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"]) | undefined;
};
/**
* Edges
@ -1097,7 +1089,7 @@ export type components = {
* @description The results of node executions
*/
results: {
[key: string]: (components["schemas"]["ImageOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["PromptOutput"] | components["schemas"]["PromptCollectionOutput"] | components["schemas"]["CompelOutput"] | components["schemas"]["IntOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["IntCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]) | undefined;
[key: string]: (components["schemas"]["ImageOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["PromptOutput"] | components["schemas"]["PromptCollectionOutput"] | components["schemas"]["CompelOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["IntOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["IntCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]) | undefined;
};
/**
* Errors
@ -1999,24 +1991,6 @@ export type components = {
*/
thumbnail_url: string;
};
/** ImportModelResponse */
ImportModelResponse: {
/**
* Name
* @description The name of the imported model
*/
name: string;
/**
* Info
* @description The model info
*/
info: components["schemas"]["AddModelResult"];
/**
* Status
* @description The status of the API response
*/
status: string;
};
/**
* InfillColorInvocation
* @description Infills transparent areas of an image with a solid color
@ -2964,6 +2938,12 @@ export type components = {
*/
min_confidence?: number;
};
/**
* MergeInterpolationMethod
* @description An enumeration.
* @enum {string}
*/
MergeInterpolationMethod: "weighted_sum" | "sigmoid" | "inv_sigmoid" | "add_difference";
/**
* MidasDepthImageProcessorInvocation
* @description Applies Midas depth processing to image
@ -3056,16 +3036,6 @@ export type components = {
*/
thr_d?: number;
};
/** ModelConfigBase */
ModelConfigBase: {
/** Path */
path: string;
/** Description */
description?: string;
/** Model Format */
model_format?: string;
error?: components["schemas"]["ModelError"];
};
/**
* ModelError
* @description An enumeration.
@ -3128,7 +3098,7 @@ export type components = {
/** ModelsList */
ModelsList: {
/** Models */
models: (components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"])[];
models: (components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"])[];
};
/**
* MultiplyInvocation
@ -4406,24 +4376,6 @@ export type components = {
* @enum {string}
*/
VaeModelFormat: "checkpoint" | "diffusers";
/** VaeRepo */
VaeRepo: {
/**
* Repo Id
* @description The repo ID to use for this VAE
*/
repo_id: string;
/**
* Path
* @description The path to the VAE
*/
path?: string;
/**
* Subfolder
* @description The subfolder to use for this VAE
*/
subfolder?: string;
};
/** ValidationError */
ValidationError: {
/** Location */
@ -4461,18 +4413,18 @@ export type components = {
*/
image?: components["schemas"]["ImageField"];
};
/**
* StableDiffusion1ModelFormat
* @description An enumeration.
* @enum {string}
*/
StableDiffusion1ModelFormat: "checkpoint" | "diffusers";
/**
* StableDiffusion2ModelFormat
* @description An enumeration.
* @enum {string}
*/
StableDiffusion2ModelFormat: "checkpoint" | "diffusers";
/**
* StableDiffusion1ModelFormat
* @description An enumeration.
* @enum {string}
*/
StableDiffusion1ModelFormat: "checkpoint" | "diffusers";
};
responses: never;
parameters: never;
@ -4583,7 +4535,7 @@ export type operations = {
};
requestBody: {
content: {
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["UpscaleInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["UpscaleInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
};
};
responses: {
@ -4620,7 +4572,7 @@ export type operations = {
};
requestBody: {
content: {
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["UpscaleInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["UpscaleInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
};
};
responses: {
@ -4839,59 +4791,35 @@ export type operations = {
};
};
};
/**
* Update Model
* @description Add Model
*/
update_model: {
requestBody: {
content: {
"application/json": components["schemas"]["CreateModelRequest"];
};
};
responses: {
/** @description Successful Response */
200: {
content: {
"application/json": unknown;
};
};
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
/**
* Import Model
* @description Add a model using its local path, repo_id, or remote URL
*/
import_model: {
parameters: {
query: {
/** @description A model path, repo_id or URL to import */
name: string;
/** @description Prediction type for SDv2 checkpoint files */
prediction_type?: "v_prediction" | "epsilon" | "sample";
requestBody: {
content: {
"application/json": components["schemas"]["Body_import_model"];
};
};
responses: {
/** @description The model imported successfully */
201: {
content: {
"application/json": components["schemas"]["ImportModelResponse"];
"application/json": components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
};
};
/** @description The model could not be found */
404: never;
/** @description There is already a model corresponding to this path or repo_id */
409: never;
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
/** @description The model appeared to import successfully, but could not be found in the model manager */
424: never;
};
};
/**
@ -4901,6 +4829,11 @@ export type operations = {
del_model: {
parameters: {
path: {
/** @description Base model */
base_model: components["schemas"]["BaseModelType"];
/** @description The type of model */
model_type: components["schemas"]["ModelType"];
/** @description model name */
model_name: string;
};
};
@ -4923,6 +4856,114 @@ export type operations = {
};
};
};
/**
* Update Model
* @description Add Model
*/
update_model: {
parameters: {
path: {
/** @description Base model */
base_model: components["schemas"]["BaseModelType"];
/** @description The type of model */
model_type: components["schemas"]["ModelType"];
/** @description model name */
model_name: string;
};
};
requestBody: {
content: {
"application/json": components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
};
};
responses: {
/** @description The model was updated successfully */
200: {
content: {
"application/json": components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
};
};
/** @description Bad request */
400: never;
/** @description The model could not be found */
404: never;
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
/**
* Convert Model
* @description Convert a checkpoint model into a diffusers model
*/
convert_model: {
parameters: {
path: {
/** @description Base model */
base_model: components["schemas"]["BaseModelType"];
/** @description The type of model */
model_type: components["schemas"]["ModelType"];
/** @description model name */
model_name: string;
};
};
responses: {
/** @description Model converted successfully */
200: {
content: {
"application/json": components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
};
};
/** @description Bad request */
400: never;
/** @description Model not found */
404: never;
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
/**
* Merge Models
* @description Convert a checkpoint model into a diffusers model
*/
merge_models: {
parameters: {
path: {
/** @description Base model */
base_model: components["schemas"]["BaseModelType"];
};
};
requestBody: {
content: {
"application/json": components["schemas"]["Body_merge_models"];
};
};
responses: {
/** @description Model converted successfully */
200: {
content: {
"application/json": components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
};
};
/** @description Incompatible models */
400: never;
/** @description One or more models not found */
404: never;
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
/**
* List Images With Metadata
* @description Gets a list of images

View File

@ -157,8 +157,6 @@ export const imageUploaded = createAppAsyncThunk<
session_id,
} = arg;
const { post } = $client.get();
const formData = new FormData();
formData.append('file', file);
const { data, error, response } = await post('/api/v1/images/', {
params: {
query: {
@ -167,10 +165,12 @@ export const imageUploaded = createAppAsyncThunk<
session_id,
},
},
// TODO: Proper handling of `multipart/form-data` is coming soon, will fix type issues
// https://github.com/drwpow/openapi-typescript/issues/1123
// @ts-ignore
body: formData,
body: { file },
bodySerializer: (body) => {
const formData = new FormData();
formData.append('file', body.file);
return formData;
},
});
if (error) {

View File

@ -23,5 +23,11 @@
},
"include": ["src/**/*.ts", "src/**/*.tsx", "*.d.ts"],
"exclude": ["src/services/fixtures/*", "node_modules", "dist"],
"references": [{ "path": "./tsconfig.node.json" }]
"references": [{ "path": "./tsconfig.node.json" }],
"ts-node": {
"compilerOptions": {
"jsx": "preserve"
},
"esm": true
}
}

View File

@ -5386,10 +5386,10 @@ open@^8.4.0:
is-docker "^2.1.1"
is-wsl "^2.2.0"
openapi-fetch@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/openapi-fetch/-/openapi-fetch-0.4.0.tgz#45c368321ba6c15bc2e168e7dc3fbf322e9cca6d"
integrity sha512-4lzZtH5J1ZH9EXfmpcmKi0gOgjy0hc6BAcucAdCmLHY6jZopMeGP51vD3Cd4rE1nTFMfJzmYDc8ar0+364gBVw==
openapi-fetch@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/openapi-fetch/-/openapi-fetch-0.6.1.tgz#90d785ead213b82beb8f094a756ad9320ba28b32"
integrity sha512-CGWPqqtL31uC2e4eEU9NHoqYMXnJ7Jk4H/4Yguil4tO22MIZi91hlQJ/51E8CiaKdSTODh03yF4ndjIOABVHUw==
openapi-types@^12.1.3:
version "12.1.3"