mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
a whole bunch of stuff
This commit is contained in:
parent
857d74bbfe
commit
2604fd9fde
@ -1,19 +1,13 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Body, HTTPException, Path, Query
|
||||
from fastapi import APIRouter, Body, HTTPException, Path
|
||||
|
||||
from invokeai.app.api.dependencies import ApiDependencies
|
||||
from invokeai.app.services.shared.pagination import PaginatedResults
|
||||
from invokeai.app.services.shared.sqlite.sqlite_common import SQLiteDirection
|
||||
from invokeai.app.services.style_preset_records.style_preset_records_common import (
|
||||
StylePresetChanges,
|
||||
StylePresetNotFoundError,
|
||||
StylePresetRecordDTO,
|
||||
StylePresetWithoutId,
|
||||
StylePresetRecordOrderBy,
|
||||
)
|
||||
|
||||
|
||||
style_presets_router = APIRouter(prefix="/v1/style_presets", tags=["style_presets"])
|
||||
|
||||
|
||||
@ -78,23 +72,9 @@ async def create_style_preset(
|
||||
"/",
|
||||
operation_id="list_style_presets",
|
||||
responses={
|
||||
200: {"model": PaginatedResults[StylePresetRecordDTO]},
|
||||
200: {"model": list[StylePresetRecordDTO]},
|
||||
},
|
||||
)
|
||||
async def list_style_presets(
|
||||
page: int = Query(default=0, description="The page to get"),
|
||||
per_page: int = Query(default=10, description="The number of style presets per page"),
|
||||
order_by: StylePresetRecordOrderBy = Query(
|
||||
default=StylePresetRecordOrderBy.Name, description="The attribute to order by"
|
||||
),
|
||||
direction: SQLiteDirection = Query(default=SQLiteDirection.Ascending, description="The direction to order by"),
|
||||
query: Optional[str] = Query(default=None, description="The text to query by (matches name and description)"),
|
||||
) -> PaginatedResults[StylePresetRecordDTO]:
|
||||
async def list_style_presets() -> list[StylePresetRecordDTO]:
|
||||
"""Gets a page of style presets"""
|
||||
return ApiDependencies.invoker.services.style_preset_records.get_many(
|
||||
page=page,
|
||||
per_page=per_page,
|
||||
order_by=order_by,
|
||||
direction=direction,
|
||||
query=query,
|
||||
)
|
||||
return ApiDependencies.invoker.services.style_preset_records.get_many()
|
||||
|
@ -1,13 +1,9 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
|
||||
from invokeai.app.services.shared.pagination import PaginatedResults
|
||||
from invokeai.app.services.shared.sqlite.sqlite_common import SQLiteDirection
|
||||
from invokeai.app.services.style_preset_records.style_preset_records_common import (
|
||||
StylePresetChanges,
|
||||
StylePresetRecordDTO,
|
||||
StylePresetWithoutId,
|
||||
StylePresetRecordOrderBy,
|
||||
)
|
||||
|
||||
|
||||
@ -35,13 +31,6 @@ class StylePresetRecordsStorageBase(ABC):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_many(
|
||||
self,
|
||||
page: int,
|
||||
per_page: int,
|
||||
order_by: StylePresetRecordOrderBy,
|
||||
direction: SQLiteDirection,
|
||||
query: Optional[str],
|
||||
) -> PaginatedResults[StylePresetRecordDTO]:
|
||||
def get_many(self) -> list[StylePresetRecordDTO]:
|
||||
"""Gets many workflows."""
|
||||
pass
|
||||
|
@ -10,13 +10,6 @@ class StylePresetNotFoundError(Exception):
|
||||
"""Raised when a style preset is not found"""
|
||||
|
||||
|
||||
class StylePresetRecordOrderBy(str, Enum, metaclass=MetaEnum):
|
||||
"""The order by options for workflow records"""
|
||||
|
||||
CreatedAt = "created_at"
|
||||
Name = "name"
|
||||
|
||||
|
||||
class PresetData(BaseModel, extra="forbid"):
|
||||
positive_prompt: str = Field(description="Positive prompt")
|
||||
negative_prompt: str = Field(description="Negative prompt")
|
||||
|
@ -11,7 +11,6 @@ from invokeai.app.services.style_preset_records.style_preset_records_common impo
|
||||
StylePresetNotFoundError,
|
||||
StylePresetRecordDTO,
|
||||
StylePresetWithoutId,
|
||||
StylePresetRecordOrderBy,
|
||||
)
|
||||
from invokeai.app.util.misc import uuid_string
|
||||
|
||||
@ -128,50 +127,21 @@ class SqliteStylePresetRecordsStorage(StylePresetRecordsStorageBase):
|
||||
|
||||
def get_many(
|
||||
self,
|
||||
page: int,
|
||||
per_page: int,
|
||||
order_by: StylePresetRecordOrderBy,
|
||||
direction: SQLiteDirection,
|
||||
query: Optional[str] = None,
|
||||
) -> PaginatedResults[StylePresetRecordDTO]:
|
||||
) -> list[StylePresetRecordDTO]:
|
||||
try:
|
||||
self._lock.acquire()
|
||||
# sanitize!
|
||||
assert order_by in StylePresetRecordOrderBy
|
||||
assert direction in SQLiteDirection
|
||||
count_query = "SELECT COUNT(*) FROM style_presets"
|
||||
main_query = """
|
||||
SELECT
|
||||
*
|
||||
FROM style_presets
|
||||
ORDER BY name ASC
|
||||
"""
|
||||
main_params: list[int | str] = []
|
||||
count_params: list[int | str] = []
|
||||
stripped_query = query.strip() if query else None
|
||||
if stripped_query:
|
||||
wildcard_query = "%" + stripped_query + "%"
|
||||
main_query += " AND name LIKE ? "
|
||||
count_query += " AND name LIKE ?;"
|
||||
main_params.extend([wildcard_query, wildcard_query])
|
||||
count_params.extend([wildcard_query, wildcard_query])
|
||||
|
||||
main_query += f" ORDER BY {order_by.value} {direction.value} LIMIT ? OFFSET ?;"
|
||||
main_params.extend([per_page, page * per_page])
|
||||
self._cursor.execute(main_query, main_params)
|
||||
self._cursor.execute(main_query)
|
||||
rows = self._cursor.fetchall()
|
||||
style_presets = [StylePresetRecordDTO.from_dict(dict(row)) for row in rows]
|
||||
|
||||
self._cursor.execute(count_query, count_params)
|
||||
total = self._cursor.fetchone()[0]
|
||||
pages = total // per_page + (total % per_page > 0)
|
||||
|
||||
return PaginatedResults(
|
||||
items=style_presets,
|
||||
page=page,
|
||||
per_page=per_page,
|
||||
pages=pages,
|
||||
total=total,
|
||||
)
|
||||
return style_presets
|
||||
except Exception:
|
||||
self._conn.rollback()
|
||||
raise
|
||||
|
@ -53,7 +53,6 @@ import type { AppDispatch, RootState } from 'app/store/store';
|
||||
|
||||
import { addArchivedOrDeletedBoardListener } from './listeners/addArchivedOrDeletedBoardListener';
|
||||
import { addEnqueueRequestedUpscale } from './listeners/enqueueRequestedUpscale';
|
||||
import { addActiveStylePresetChanged } from './listeners/activeStylePresetChanged';
|
||||
|
||||
export const listenerMiddleware = createListenerMiddleware();
|
||||
|
||||
@ -147,7 +146,6 @@ addAdHocPostProcessingRequestedListener(startAppListening);
|
||||
|
||||
// Prompts
|
||||
addDynamicPromptsListener(startAppListening);
|
||||
addActiveStylePresetChanged(startAppListening)
|
||||
|
||||
addSetDefaultSettingsListener(startAppListening);
|
||||
addControlAdapterPreprocessor(startAppListening);
|
||||
|
@ -1,31 +0,0 @@
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import { negativePromptChanged, positivePromptChanged, } from 'features/controlLayers/store/controlLayersSlice';
|
||||
import { activeStylePresetChanged, calculatedNegPromptChanged, calculatedPosPromptChanged } from '../../../../../features/stylePresets/store/stylePresetSlice';
|
||||
import { isAnyOf } from '@reduxjs/toolkit';
|
||||
|
||||
export const addActiveStylePresetChanged = (startAppListening: AppStartListening) => {
|
||||
startAppListening({
|
||||
matcher: isAnyOf(activeStylePresetChanged, positivePromptChanged, negativePromptChanged),
|
||||
effect: async (action, { dispatch, getState }) => {
|
||||
const state = getState();
|
||||
|
||||
const activeStylePreset = state.stylePreset.activeStylePreset;
|
||||
const positivePrompt = state.controlLayers.present.positivePrompt
|
||||
const negativePrompt = state.controlLayers.present.negativePrompt
|
||||
|
||||
if (!activeStylePreset) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { positive_prompt: presetPositivePrompt, negative_prompt: presetNegativePrompt } = activeStylePreset.preset_data;
|
||||
|
||||
const calculatedPosPrompt = presetPositivePrompt.includes('{prompt}') ? presetPositivePrompt.replace('{prompt}', positivePrompt) : `${positivePrompt} ${presetPositivePrompt}`
|
||||
|
||||
const calculatedNegPrompt = presetNegativePrompt.includes('{prompt}') ? presetNegativePrompt.replace('{prompt}', negativePrompt) : `${negativePrompt} ${presetNegativePrompt}`
|
||||
|
||||
dispatch(calculatedPosPromptChanged(calculatedPosPrompt))
|
||||
|
||||
dispatch(calculatedNegPromptChanged(calculatedNegPrompt))
|
||||
},
|
||||
});
|
||||
};
|
@ -29,6 +29,7 @@ import { upscalePersistConfig, upscaleSlice } from 'features/parameters/store/up
|
||||
import { queueSlice } from 'features/queue/store/queueSlice';
|
||||
import { sdxlPersistConfig, sdxlSlice } from 'features/sdxl/store/sdxlSlice';
|
||||
import { stylePresetModalSlice } from 'features/stylePresets/store/stylePresetModalSlice';
|
||||
import { stylePresetSlice } from 'features/stylePresets/store/stylePresetSlice';
|
||||
import { configSlice } from 'features/system/store/configSlice';
|
||||
import { systemPersistConfig, systemSlice } from 'features/system/store/systemSlice';
|
||||
import { uiPersistConfig, uiSlice } from 'features/ui/store/uiSlice';
|
||||
@ -47,7 +48,6 @@ import { actionSanitizer } from './middleware/devtools/actionSanitizer';
|
||||
import { actionsDenylist } from './middleware/devtools/actionsDenylist';
|
||||
import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
||||
import { listenerMiddleware } from './middleware/listenerMiddleware';
|
||||
import { stylePresetSlice } from '../../features/stylePresets/store/stylePresetSlice';
|
||||
|
||||
const allReducers = {
|
||||
[canvasSlice.name]: canvasSlice.reducer,
|
||||
|
@ -22,11 +22,10 @@ import {
|
||||
} from './constants';
|
||||
import { addLoRAs } from './generation/addLoRAs';
|
||||
import { addSDXLLoRas } from './generation/addSDXLLoRAs';
|
||||
import { getBoardField, getSDXLStylePrompts } from './graphBuilderUtils';
|
||||
import { getBoardField, getPresetModifiedPrompts } from './graphBuilderUtils';
|
||||
|
||||
export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise<GraphType> => {
|
||||
const { model, cfgScale: cfg_scale, scheduler, steps, vaePrecision, seed, vae } = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
const { upscaleModel, upscaleInitialImage, structure, creativity, tileControlnetModel, scale } = state.upscale;
|
||||
|
||||
assert(model, 'No model found in state');
|
||||
@ -99,7 +98,7 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise
|
||||
let modelNode;
|
||||
|
||||
if (model.base === 'sdxl') {
|
||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
||||
const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
posCondNode = g.addNode({
|
||||
type: 'sdxl_compel_prompt',
|
||||
@ -140,6 +139,8 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise
|
||||
vae: vae ?? undefined,
|
||||
});
|
||||
} else {
|
||||
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
posCondNode = g.addNode({
|
||||
type: 'compel',
|
||||
id: POSITIVE_CONDITIONING,
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
SDXL_REFINER_POSITIVE_CONDITIONING,
|
||||
SDXL_REFINER_SEAMLESS,
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import { getSDXLStylePrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import type { NonNullableGraph } from 'services/api/types';
|
||||
import { isRefinerMainModelModelConfig } from 'services/api/types';
|
||||
|
||||
@ -59,7 +59,7 @@ export const addSDXLRefinerToGraph = async (
|
||||
const modelLoaderId = modelLoaderNodeId ? modelLoaderNodeId : SDXL_MODEL_LOADER;
|
||||
|
||||
// Construct Style Prompt
|
||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
||||
const { positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
// Unplug SDXL Latents Generation To Latents To Image
|
||||
graph.edges = graph.edges.filter((e) => !(e.source.node_id === baseNodeId && ['latents'].includes(e.source.field)));
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
POSITIVE_CONDITIONING,
|
||||
SEAMLESS,
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import { getBoardField, getIsIntermediate } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
||||
|
||||
@ -51,7 +51,6 @@ export const buildCanvasImageToImageGraph = async (
|
||||
seamlessXAxis,
|
||||
seamlessYAxis,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
|
||||
// The bounding box determines width and height, not the width and height params
|
||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||
@ -71,6 +70,8 @@ export const buildCanvasImageToImageGraph = async (
|
||||
|
||||
const use_cpu = shouldUseCpuNoise;
|
||||
|
||||
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
/**
|
||||
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
|
||||
* full graph here as a template. Then use the parameters from app state and set friendlier node
|
||||
|
@ -19,7 +19,7 @@ import {
|
||||
POSITIVE_CONDITIONING,
|
||||
SEAMLESS,
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import { getBoardField, getIsIntermediate } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||
|
||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||
@ -58,7 +58,6 @@ export const buildCanvasInpaintGraph = async (
|
||||
canvasCoherenceEdgeSize,
|
||||
maskBlur,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
|
||||
if (!model) {
|
||||
log.error('No model found in state');
|
||||
@ -79,6 +78,8 @@ export const buildCanvasInpaintGraph = async (
|
||||
|
||||
const use_cpu = shouldUseCpuNoise;
|
||||
|
||||
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
const graph: NonNullableGraph = {
|
||||
id: CANVAS_INPAINT_GRAPH,
|
||||
nodes: {
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
POSITIVE_CONDITIONING,
|
||||
SEAMLESS,
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import { getBoardField, getIsIntermediate } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||
|
||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||
@ -70,7 +70,6 @@ export const buildCanvasOutpaintGraph = async (
|
||||
canvasCoherenceEdgeSize,
|
||||
maskBlur,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
|
||||
if (!model) {
|
||||
log.error('No model found in state');
|
||||
@ -91,6 +90,8 @@ export const buildCanvasOutpaintGraph = async (
|
||||
|
||||
const use_cpu = shouldUseCpuNoise;
|
||||
|
||||
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
const graph: NonNullableGraph = {
|
||||
id: CANVAS_OUTPAINT_GRAPH,
|
||||
nodes: {
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
SDXL_REFINER_SEAMLESS,
|
||||
SEAMLESS,
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import { getBoardField, getIsIntermediate, getSDXLStylePrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
||||
|
||||
@ -51,7 +51,6 @@ export const buildCanvasSDXLImageToImageGraph = async (
|
||||
seamlessYAxis,
|
||||
img2imgStrength: strength,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
|
||||
@ -75,7 +74,7 @@ export const buildCanvasSDXLImageToImageGraph = async (
|
||||
const use_cpu = shouldUseCpuNoise;
|
||||
|
||||
// Construct Style Prompt
|
||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
||||
const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
/**
|
||||
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
|
||||
|
@ -19,7 +19,7 @@ import {
|
||||
SDXL_REFINER_SEAMLESS,
|
||||
SEAMLESS,
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import { getBoardField, getIsIntermediate, getSDXLStylePrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||
|
||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||
@ -58,7 +58,6 @@ export const buildCanvasSDXLInpaintGraph = async (
|
||||
canvasCoherenceEdgeSize,
|
||||
maskBlur,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
|
||||
@ -83,7 +82,7 @@ export const buildCanvasSDXLInpaintGraph = async (
|
||||
const use_cpu = shouldUseCpuNoise;
|
||||
|
||||
// Construct Style Prompt
|
||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
||||
const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
const graph: NonNullableGraph = {
|
||||
id: SDXL_CANVAS_INPAINT_GRAPH,
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
SDXL_REFINER_SEAMLESS,
|
||||
SEAMLESS,
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import { getBoardField, getIsIntermediate, getSDXLStylePrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||
|
||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||
@ -70,7 +70,6 @@ export const buildCanvasSDXLOutpaintGraph = async (
|
||||
canvasCoherenceEdgeSize,
|
||||
maskBlur,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
|
||||
@ -94,7 +93,7 @@ export const buildCanvasSDXLOutpaintGraph = async (
|
||||
const use_cpu = shouldUseCpuNoise;
|
||||
|
||||
// Construct Style Prompt
|
||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
||||
const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
const graph: NonNullableGraph = {
|
||||
id: SDXL_CANVAS_OUTPAINT_GRAPH,
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
SDXL_REFINER_SEAMLESS,
|
||||
SEAMLESS,
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import { getBoardField, getIsIntermediate, getSDXLStylePrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { isNonRefinerMainModelConfig, type NonNullableGraph } from 'services/api/types';
|
||||
|
||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||
@ -44,7 +44,6 @@ export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise
|
||||
seamlessXAxis,
|
||||
seamlessYAxis,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
|
||||
// The bounding box determines width and height, not the width and height params
|
||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||
@ -67,7 +66,7 @@ export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise
|
||||
let modelLoaderNodeId = SDXL_MODEL_LOADER;
|
||||
|
||||
// Construct Style Prompt
|
||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
||||
const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
/**
|
||||
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
POSITIVE_CONDITIONING,
|
||||
SEAMLESS,
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import { getBoardField, getIsIntermediate } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { isNonRefinerMainModelConfig, type NonNullableGraph } from 'services/api/types';
|
||||
|
||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||
@ -44,7 +44,6 @@ export const buildCanvasTextToImageGraph = async (state: RootState): Promise<Non
|
||||
seamlessXAxis,
|
||||
seamlessYAxis,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
|
||||
// The bounding box determines width and height, not the width and height params
|
||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||
@ -64,6 +63,8 @@ export const buildCanvasTextToImageGraph = async (state: RootState): Promise<Non
|
||||
|
||||
let modelLoaderNodeId = MAIN_MODEL_LOADER;
|
||||
|
||||
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
/**
|
||||
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
|
||||
* full graph here as a template. Then use the parameters from app state and set friendlier node
|
||||
|
@ -22,7 +22,7 @@ import { addSeamless } from 'features/nodes/util/graph/generation/addSeamless';
|
||||
import { addWatermarker } from 'features/nodes/util/graph/generation/addWatermarker';
|
||||
import type { GraphType } from 'features/nodes/util/graph/generation/Graph';
|
||||
import { Graph } from 'features/nodes/util/graph/generation/Graph';
|
||||
import { getBoardField } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import type { Invocation } from 'services/api/types';
|
||||
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
||||
import { assert } from 'tsafe';
|
||||
@ -40,11 +40,12 @@ export const buildGenerationTabGraph = async (state: RootState): Promise<GraphTy
|
||||
seed,
|
||||
vae,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
const { width, height } = state.controlLayers.present.size;
|
||||
|
||||
assert(model, 'No model found in state');
|
||||
|
||||
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
const g = new Graph(CONTROL_LAYERS_GRAPH);
|
||||
const modelLoader = g.addNode({
|
||||
type: 'main_model_loader',
|
||||
@ -104,10 +105,10 @@ export const buildGenerationTabGraph = async (state: RootState): Promise<GraphTy
|
||||
const vaeLoader =
|
||||
vae?.base === model.base
|
||||
? g.addNode({
|
||||
type: 'vae_loader',
|
||||
id: VAE_LOADER,
|
||||
vae_model: vae,
|
||||
})
|
||||
type: 'vae_loader',
|
||||
id: VAE_LOADER,
|
||||
vae_model: vae,
|
||||
})
|
||||
: null;
|
||||
|
||||
let imageOutput: Invocation<'l2i'> | Invocation<'img_nsfw'> | Invocation<'img_watermark'> = l2i;
|
||||
|
@ -19,7 +19,7 @@ import { addSDXLRefiner } from 'features/nodes/util/graph/generation/addSDXLRefi
|
||||
import { addSeamless } from 'features/nodes/util/graph/generation/addSeamless';
|
||||
import { addWatermarker } from 'features/nodes/util/graph/generation/addWatermarker';
|
||||
import { Graph } from 'features/nodes/util/graph/generation/Graph';
|
||||
import { getBoardField, getSDXLStylePrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { getBoardField, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import type { Invocation, NonNullableGraph } from 'services/api/types';
|
||||
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
||||
import { assert } from 'tsafe';
|
||||
@ -36,14 +36,13 @@ export const buildGenerationTabSDXLGraph = async (state: RootState): Promise<Non
|
||||
vaePrecision,
|
||||
vae,
|
||||
} = state.generation;
|
||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
||||
const { width, height } = state.controlLayers.present.size;
|
||||
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
|
||||
assert(model, 'No model found in state');
|
||||
|
||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
||||
const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||
|
||||
const g = new Graph(SDXL_CONTROL_LAYERS_GRAPH);
|
||||
const modelLoader = g.addNode({
|
||||
@ -94,10 +93,10 @@ export const buildGenerationTabSDXLGraph = async (state: RootState): Promise<Non
|
||||
const vaeLoader =
|
||||
vae?.base === model.base
|
||||
? g.addNode({
|
||||
type: 'vae_loader',
|
||||
id: VAE_LOADER,
|
||||
vae_model: vae,
|
||||
})
|
||||
type: 'vae_loader',
|
||||
id: VAE_LOADER,
|
||||
vae_model: vae,
|
||||
})
|
||||
: null;
|
||||
|
||||
let imageOutput: Invocation<'l2i'> | Invocation<'img_nsfw'> | Invocation<'img_watermark'> = l2i;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { RootState } from 'app/store/store';
|
||||
import type { BoardField } from 'features/nodes/types/common';
|
||||
import { buildPresetModifiedPrompt } from 'features/stylePresets/hooks/usePresetModifiedPrompts';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
|
||||
/**
|
||||
@ -14,13 +15,30 @@ export const getBoardField = (state: RootState): BoardField | undefined => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the SDXL style prompts, based on the concat setting.
|
||||
* Gets the prompts, modified for the active style preset.
|
||||
*/
|
||||
export const getSDXLStylePrompts = (state: RootState): { positiveStylePrompt: string; negativeStylePrompt: string } => {
|
||||
export const getPresetModifiedPrompts = (state: RootState): { positivePrompt: string; negativePrompt: string, positiveStylePrompt?: string; negativeStylePrompt?: string } => {
|
||||
const { positivePrompt, negativePrompt, positivePrompt2, negativePrompt2, shouldConcatPrompts } =
|
||||
state.controlLayers.present;
|
||||
const { activeStylePreset } = state.stylePreset
|
||||
|
||||
if (activeStylePreset) {
|
||||
const presetModifiedPositivePrompt = buildPresetModifiedPrompt(activeStylePreset.preset_data.positive_prompt, positivePrompt)
|
||||
|
||||
const presetModifiedNegativePrompt = buildPresetModifiedPrompt(activeStylePreset.preset_data.negative_prompt, negativePrompt)
|
||||
|
||||
return {
|
||||
positivePrompt: presetModifiedPositivePrompt,
|
||||
negativePrompt: presetModifiedNegativePrompt,
|
||||
positiveStylePrompt: shouldConcatPrompts ? presetModifiedPositivePrompt : positivePrompt2,
|
||||
negativeStylePrompt: shouldConcatPrompts ? presetModifiedNegativePrompt : negativePrompt2,
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
positivePrompt,
|
||||
negativePrompt,
|
||||
positiveStylePrompt: shouldConcatPrompts ? positivePrompt : positivePrompt2,
|
||||
negativeStylePrompt: shouldConcatPrompts ? negativePrompt : negativePrompt2,
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ import { ParamPositivePrompt } from 'features/parameters/components/Core/ParamPo
|
||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||
import { ParamSDXLNegativeStylePrompt } from 'features/sdxl/components/SDXLPrompts/ParamSDXLNegativeStylePrompt';
|
||||
import { ParamSDXLPositiveStylePrompt } from 'features/sdxl/components/SDXLPrompts/ParamSDXLPositiveStylePrompt';
|
||||
import { StylePresetMenuTrigger } from 'features/stylePresets/components/StylePresetMenuTrigger';
|
||||
import { usePresetModifiedPrompts } from 'features/stylePresets/hooks/usePresetModifiedPrompts';
|
||||
import { memo } from 'react';
|
||||
|
||||
const concatPromptsSelector = createSelector(
|
||||
@ -19,16 +19,14 @@ const concatPromptsSelector = createSelector(
|
||||
|
||||
export const Prompts = memo(() => {
|
||||
const shouldConcatPrompts = useAppSelector(concatPromptsSelector);
|
||||
const calculatedPosPrompt = useAppSelector((s) => s.stylePreset.calculatedPosPrompt);
|
||||
const calculatedNegPrompt = useAppSelector((s) => s.stylePreset.calculatedNegPrompt);
|
||||
const { presetModifiedPositivePrompt, presetModifiedNegativePrompt } = usePresetModifiedPrompts();
|
||||
return (
|
||||
<Flex flexDir="column" gap={2}>
|
||||
<StylePresetMenuTrigger />
|
||||
<ParamPositivePrompt />
|
||||
<Flex>{calculatedPosPrompt}</Flex>
|
||||
<Flex>{presetModifiedPositivePrompt}</Flex>
|
||||
{!shouldConcatPrompts && <ParamSDXLPositiveStylePrompt />}
|
||||
<ParamNegativePrompt />
|
||||
<Flex>{calculatedNegPrompt}</Flex>
|
||||
<Flex>{presetModifiedNegativePrompt}</Flex>
|
||||
{!shouldConcatPrompts && <ParamSDXLNegativeStylePrompt />}
|
||||
</Flex>
|
||||
);
|
||||
|
@ -0,0 +1,72 @@
|
||||
import { Flex, IconButton, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { negativePromptChanged, positivePromptChanged } from 'features/controlLayers/store/controlLayersSlice';
|
||||
import ModelImage from 'features/modelManagerV2/subpanels/ModelManagerPanel/ModelImage';
|
||||
import { usePresetModifiedPrompts } from 'features/stylePresets/hooks/usePresetModifiedPrompts';
|
||||
import { activeStylePresetChanged } from 'features/stylePresets/store/stylePresetSlice';
|
||||
import type { MouseEventHandler} from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { CgPushDown } from 'react-icons/cg';
|
||||
import { PiXBold } from 'react-icons/pi';
|
||||
|
||||
export const ActiveStylePreset = () => {
|
||||
const { activeStylePreset } = useAppSelector((s) => s.stylePreset);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { presetModifiedPositivePrompt, presetModifiedNegativePrompt } = usePresetModifiedPrompts();
|
||||
|
||||
const handleClearActiveStylePreset = useCallback<MouseEventHandler<HTMLButtonElement>>(
|
||||
(e) => {
|
||||
e.stopPropagation();
|
||||
dispatch(activeStylePresetChanged(null));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleFlattenPrompts = useCallback<MouseEventHandler<HTMLButtonElement>>(
|
||||
(e) => {
|
||||
e.stopPropagation();
|
||||
dispatch(positivePromptChanged(presetModifiedPositivePrompt));
|
||||
dispatch(negativePromptChanged(presetModifiedNegativePrompt));
|
||||
dispatch(activeStylePresetChanged(null));
|
||||
},
|
||||
[dispatch, presetModifiedPositivePrompt, presetModifiedNegativePrompt]
|
||||
);
|
||||
|
||||
if (!activeStylePreset) {
|
||||
return <>Choose Preset</>;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Flex justifyContent="space-between" w="full" alignItems="center">
|
||||
<Flex gap="2">
|
||||
<ModelImage image_url={null} />
|
||||
<Flex flexDir="column">
|
||||
<Text variant="subtext" fontSize="xs">
|
||||
Prompt Style
|
||||
</Text>
|
||||
<Text fontSize="md" fontWeight="semibold">
|
||||
{activeStylePreset.name}
|
||||
</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex gap="1">
|
||||
<IconButton
|
||||
onClick={handleFlattenPrompts}
|
||||
variant="ghost"
|
||||
size="md"
|
||||
aria-label="Flatten"
|
||||
icon={<CgPushDown />}
|
||||
/>
|
||||
<IconButton
|
||||
onClick={handleClearActiveStylePreset}
|
||||
variant="ghost"
|
||||
size="md"
|
||||
aria-label="Clear"
|
||||
icon={<PiXBold />}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,84 +1,80 @@
|
||||
import { Button, Flex, FormControl, FormLabel, Input, Textarea } from '@invoke-ai/ui-library';
|
||||
import { Button, Flex, FormControl, FormLabel, Icon, Input, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { useStylePresetFields } from 'features/stylePresets/hooks/useStylePresetFields';
|
||||
import { isModalOpenChanged, updatingStylePresetChanged } from 'features/stylePresets/store/stylePresetModalSlice';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import type { ChangeEventHandler } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import type { SubmitHandler} from 'react-hook-form';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { PiBracketsCurlyBold } from 'react-icons/pi';
|
||||
import type { StylePresetRecordDTO } from 'services/api/endpoints/stylePresets';
|
||||
import { useCreateStylePresetMutation, useUpdateStylePresetMutation } from 'services/api/endpoints/stylePresets';
|
||||
|
||||
import { StylePresetPromptField } from './StylePresetPromptField';
|
||||
|
||||
export type StylePresetFormData = {
|
||||
name: string;
|
||||
positivePrompt: string;
|
||||
negativePrompt: string;
|
||||
};
|
||||
|
||||
export const StylePresetForm = ({ updatingPreset }: { updatingPreset: StylePresetRecordDTO | null }) => {
|
||||
const [createStylePreset] = useCreateStylePresetMutation();
|
||||
const [updateStylePreset] = useUpdateStylePresetMutation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [name, setName] = useState(updatingPreset ? updatingPreset.name : '');
|
||||
const [posPrompt, setPosPrompt] = useState(updatingPreset ? updatingPreset.preset_data.positive_prompt : '');
|
||||
const [negPrompt, setNegPrompt] = useState(updatingPreset ? updatingPreset.preset_data.negative_prompt : '');
|
||||
const stylePresetFieldDefaults = useStylePresetFields(updatingPreset);
|
||||
|
||||
const handleChangeName = useCallback<ChangeEventHandler<HTMLInputElement>>((e) => {
|
||||
setName(e.target.value);
|
||||
}, []);
|
||||
const { handleSubmit, control, formState, reset, register } = useForm<StylePresetFormData>({
|
||||
defaultValues: stylePresetFieldDefaults,
|
||||
});
|
||||
|
||||
const handleChangePosPrompt = useCallback<ChangeEventHandler<HTMLTextAreaElement>>((e) => {
|
||||
setPosPrompt(e.target.value);
|
||||
}, []);
|
||||
|
||||
const handleChangeNegPrompt = useCallback<ChangeEventHandler<HTMLTextAreaElement>>((e) => {
|
||||
setNegPrompt(e.target.value);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (updatingPreset) {
|
||||
setName(updatingPreset.name);
|
||||
setPosPrompt(updatingPreset.preset_data.positive_prompt);
|
||||
setNegPrompt(updatingPreset.preset_data.negative_prompt);
|
||||
} else {
|
||||
setName('');
|
||||
setPosPrompt('');
|
||||
setNegPrompt('');
|
||||
}
|
||||
}, [updatingPreset]);
|
||||
|
||||
const handleClickSave = useCallback(async () => {
|
||||
try {
|
||||
if (updatingPreset) {
|
||||
await updateStylePreset({
|
||||
id: updatingPreset.id,
|
||||
changes: { name, preset_data: { positive_prompt: posPrompt, negative_prompt: negPrompt } },
|
||||
}).unwrap();
|
||||
} else {
|
||||
await createStylePreset({
|
||||
name: name,
|
||||
preset_data: { positive_prompt: posPrompt, negative_prompt: negPrompt },
|
||||
}).unwrap();
|
||||
const handleClickSave = useCallback<SubmitHandler<StylePresetFormData>>(
|
||||
async (data) => {
|
||||
try {
|
||||
if (updatingPreset) {
|
||||
await updateStylePreset({
|
||||
id: updatingPreset.id,
|
||||
changes: {
|
||||
name: data.name,
|
||||
preset_data: { positive_prompt: data.positivePrompt, negative_prompt: data.negativePrompt },
|
||||
},
|
||||
}).unwrap();
|
||||
} else {
|
||||
await createStylePreset({
|
||||
name: data.name,
|
||||
preset_data: { positive_prompt: data.positivePrompt, negative_prompt: data.negativePrompt },
|
||||
}).unwrap();
|
||||
}
|
||||
} catch (error) {
|
||||
toast({
|
||||
status: 'error',
|
||||
title: 'Failed to save style preset',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
toast({
|
||||
status: 'error',
|
||||
title: 'Failed to save style preset',
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(updatingStylePresetChanged(null));
|
||||
dispatch(isModalOpenChanged(false));
|
||||
}, [dispatch, updatingPreset, name, posPrompt, negPrompt, updateStylePreset, createStylePreset]);
|
||||
dispatch(updatingStylePresetChanged(null));
|
||||
dispatch(isModalOpenChanged(false));
|
||||
},
|
||||
[dispatch, updatingPreset, updateStylePreset, createStylePreset]
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" gap="4">
|
||||
<FormControl>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<Input value={name} onChange={handleChangeName} />
|
||||
<Input size="md" {...register('name')} />
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>Positive Prompt</FormLabel>
|
||||
<Textarea value={posPrompt} onChange={handleChangePosPrompt} />
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>Negative Prompt</FormLabel>
|
||||
<Textarea value={negPrompt} onChange={handleChangeNegPrompt} />
|
||||
</FormControl>
|
||||
<Button onClick={handleClickSave}>Save</Button>
|
||||
<Flex flexDir="column" bgColor="base.750" borderRadius="base" padding="10px" gap="10px">
|
||||
<Text variant="subtext">
|
||||
Use the <Icon as={PiBracketsCurlyBold} /> button to specify where your manual prompt should be included in the
|
||||
template. If you do not provide one, the template will be appended to your prompt.
|
||||
</Text>
|
||||
<StylePresetPromptField label="Positive Prompt" control={control} name="positivePrompt" />
|
||||
<StylePresetPromptField label="Negative Prompt" control={control} name="negativePrompt" />
|
||||
</Flex>
|
||||
|
||||
<Button onClick={handleSubmit(handleClickSave)}>Save</Button>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,31 @@
|
||||
import { Button, Collapse, Flex, Icon, Text, useDisclosure } from '@invoke-ai/ui-library';
|
||||
import { PiCaretDownBold } from 'react-icons/pi';
|
||||
import type { StylePresetRecordDTO } from 'services/api/endpoints/stylePresets';
|
||||
|
||||
import { StylePresetListItem } from './StylePresetListItem';
|
||||
|
||||
export const StylePresetList = ({ title, data }: { title: string; data: StylePresetRecordDTO[] }) => {
|
||||
const { onToggle, isOpen } = useDisclosure({ defaultIsOpen: true });
|
||||
|
||||
if (!data.length) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex flexDir="column">
|
||||
<Button variant="unstyled" onClick={onToggle}>
|
||||
<Flex gap="2" alignItems="center">
|
||||
<Icon boxSize={4} as={PiCaretDownBold} transform={isOpen ? undefined : 'rotate(-90deg)'} fill="base.500" />
|
||||
<Text fontSize="sm" fontWeight="semibold" userSelect="none" color="base.500">
|
||||
{title}
|
||||
</Text>
|
||||
</Flex>
|
||||
</Button>
|
||||
<Collapse in={isOpen}>
|
||||
{data.map((preset) => (
|
||||
<StylePresetListItem preset={preset} key={preset.id} />
|
||||
))}
|
||||
</Collapse>
|
||||
</Flex>
|
||||
);
|
||||
};
|
@ -1,14 +1,17 @@
|
||||
import { Button, Flex, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { Badge, Flex, IconButton, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import ModelImage from 'features/modelManagerV2/subpanels/ModelManagerPanel/ModelImage';
|
||||
import { isModalOpenChanged, updatingStylePresetChanged } from 'features/stylePresets/store/stylePresetModalSlice';
|
||||
import { activeStylePresetChanged, isMenuOpenChanged } from 'features/stylePresets/store/stylePresetSlice';
|
||||
import { useCallback } from 'react';
|
||||
import { PiPencilBold, PiTrashBold } from 'react-icons/pi';
|
||||
import type { StylePresetRecordDTO } from 'services/api/endpoints/stylePresets';
|
||||
import { useDeleteStylePresetMutation } from 'services/api/endpoints/stylePresets';
|
||||
import { activeStylePresetChanged, isMenuOpenChanged } from '../store/stylePresetSlice';
|
||||
|
||||
export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordDTO }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const [deleteStylePreset] = useDeleteStylePresetMutation();
|
||||
const activeStylePreset = useAppSelector((s) => s.stylePreset.activeStylePreset);
|
||||
|
||||
const handleClickEdit = useCallback(() => {
|
||||
dispatch(updatingStylePresetChanged(preset));
|
||||
@ -27,10 +30,47 @@ export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordDTO }
|
||||
}, [preset]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex flexDir="column" gap="2">
|
||||
<Text fontSize="md">{preset.name}</Text>
|
||||
<Flex flexDir="column" layerStyle="third" borderRadius="base" padding="10px">
|
||||
<Flex
|
||||
gap="4"
|
||||
onClick={handleClickApply}
|
||||
cursor="pointer"
|
||||
_hover={{ backgroundColor: 'base.750' }}
|
||||
padding="10px"
|
||||
borderRadius="base"
|
||||
alignItems="center"
|
||||
w="full"
|
||||
>
|
||||
<ModelImage image_url={null} />
|
||||
<Flex flexDir="column" w="full">
|
||||
<Flex w="full" justifyContent="space-between">
|
||||
<Flex alignItems="center" gap="2">
|
||||
<Text fontSize="md">{preset.name}</Text>
|
||||
{activeStylePreset && activeStylePreset.id === preset.id && (
|
||||
<Badge
|
||||
color="invokeBlue.400"
|
||||
borderColor="invokeBlue.700"
|
||||
borderWidth={1}
|
||||
bg="transparent"
|
||||
flexShrink={0}
|
||||
>
|
||||
Active
|
||||
</Badge>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<Flex alignItems="center" gap="1">
|
||||
<IconButton size="sm" variant="ghost" aria-label="Edit" onClick={handleClickEdit} icon={<PiPencilBold />} />
|
||||
<IconButton
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
aria-label="Delete"
|
||||
onClick={handleDeletePreset}
|
||||
icon={<PiTrashBold />}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Flex flexDir="column">
|
||||
<Text fontSize="xs">
|
||||
<Text as="span" fontWeight="semibold">
|
||||
Positive prompt:
|
||||
@ -43,11 +83,8 @@ export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordDTO }
|
||||
</Text>{' '}
|
||||
{preset.preset_data.negative_prompt}
|
||||
</Text>
|
||||
<Button onClick={handleClickEdit}>Edit</Button>
|
||||
<Button onClick={handleDeletePreset}>Delete</Button>
|
||||
<Button onClick={handleClickApply}>Apply</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -1,13 +1,42 @@
|
||||
import { Button, Flex, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { Flex, IconButton, Text } from '@invoke-ai/ui-library';
|
||||
import { EMPTY_ARRAY } from 'app/store/constants';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { isModalOpenChanged, updatingStylePresetChanged } from 'features/stylePresets/store/stylePresetModalSlice';
|
||||
import { useCallback } from 'react';
|
||||
import { PiPlusBold } from 'react-icons/pi';
|
||||
import type { StylePresetRecordDTO} from 'services/api/endpoints/stylePresets';
|
||||
import { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
||||
|
||||
import { StylePresetListItem } from './StylePresetListItem';
|
||||
import { StylePresetList } from './StylePresetList';
|
||||
import StylePresetSearch from './StylePresetSearch';
|
||||
|
||||
export const StylePresetMenu = () => {
|
||||
const { data } = useListStylePresetsQuery({});
|
||||
const searchTerm = useAppSelector((s) => s.stylePreset.searchTerm);
|
||||
const { data } = useListStylePresetsQuery(undefined, {
|
||||
selectFromResult: ({ data, error, isLoading }) => {
|
||||
const filteredData =
|
||||
data?.filter((preset) => preset.name.toLowerCase().includes(searchTerm.toLowerCase())) || EMPTY_ARRAY;
|
||||
|
||||
const groupedData = filteredData.reduce(
|
||||
(acc: { defaultPresets: StylePresetRecordDTO[]; presets: StylePresetRecordDTO[] }, preset) => {
|
||||
if (preset.is_default) {
|
||||
acc.defaultPresets.push(preset);
|
||||
} else {
|
||||
acc.presets.push(preset);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ defaultPresets: [], presets: [] }
|
||||
);
|
||||
|
||||
return {
|
||||
data: groupedData,
|
||||
error,
|
||||
isLoading,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleClickAddNew = useCallback(() => {
|
||||
@ -16,19 +45,30 @@ export const StylePresetMenu = () => {
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex flexDir="column" gap="2">
|
||||
<Flex alignItems="center" gap="10" w="full" justifyContent="space-between">
|
||||
<Text fontSize="sm" fontWeight="semibold" userSelect="none" color="base.500">
|
||||
Style Presets
|
||||
</Text>
|
||||
<Button size="sm" onClick={handleClickAddNew}>
|
||||
Add New
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
{data?.items.map((preset) => <StylePresetListItem preset={preset} key={preset.id} />)}
|
||||
<Flex flexDir="column" gap="2" padding="10px">
|
||||
<Flex alignItems="center" gap="10" w="full" justifyContent="space-between">
|
||||
<StylePresetSearch />
|
||||
<IconButton
|
||||
icon={<PiPlusBold />}
|
||||
tooltip="Create Preset"
|
||||
aria-label="Create Preset"
|
||||
onClick={handleClickAddNew}
|
||||
size="md"
|
||||
variant="link"
|
||||
w={8}
|
||||
h={8}
|
||||
/>
|
||||
</Flex>
|
||||
</>
|
||||
|
||||
{data.presets.length === 0 && data.defaultPresets.length === 0 && (
|
||||
<Text m="20px" textAlign="center">
|
||||
No matching presets
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<StylePresetList title="My Presets" data={data.presets} />
|
||||
|
||||
<StylePresetList title="Default Presets" data={data.defaultPresets} />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -1,34 +1,31 @@
|
||||
import { Button, Popover, PopoverBody, PopoverContent, PopoverTrigger } from '@invoke-ai/ui-library';
|
||||
|
||||
import { StylePresetMenu } from './StylePresetMenu';
|
||||
import { useAppDispatch, useAppSelector } from '../../../app/store/storeHooks';
|
||||
import { Flex, Icon } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { isMenuOpenChanged } from 'features/stylePresets/store/stylePresetSlice';
|
||||
import { useCallback } from 'react';
|
||||
import { isMenuOpenChanged } from '../store/stylePresetSlice';
|
||||
import { PiCaretDownBold } from 'react-icons/pi';
|
||||
|
||||
import { ActiveStylePreset } from './ActiveStylePreset';
|
||||
|
||||
export const StylePresetMenuTrigger = () => {
|
||||
const isMenuOpen = useAppSelector((s) => s.stylePreset.isMenuOpen);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
dispatch(isMenuOpenChanged(false));
|
||||
}, [dispatch]);
|
||||
|
||||
const handleToggle = useCallback(() => {
|
||||
dispatch(isMenuOpenChanged(!isMenuOpen));
|
||||
}, [dispatch, isMenuOpen]);
|
||||
|
||||
return (
|
||||
<Popover isOpen={isMenuOpen} onClose={handleClose}>
|
||||
<PopoverTrigger>
|
||||
<Button size="sm" onClick={handleToggle}>
|
||||
Style Presets
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<PopoverBody>
|
||||
<StylePresetMenu />
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Flex
|
||||
onClick={handleToggle}
|
||||
backgroundColor="base.800"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
padding="5px 10px"
|
||||
borderRadius="base"
|
||||
>
|
||||
<ActiveStylePreset />
|
||||
|
||||
<Icon as={PiCaretDownBold} />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,61 @@
|
||||
import { Flex, FormControl, FormLabel, IconButton, Textarea } from '@invoke-ai/ui-library';
|
||||
import type { ChangeEventHandler } from 'react';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import type { UseControllerProps } from 'react-hook-form';
|
||||
import { useController } from 'react-hook-form';
|
||||
import { PiBracketsCurlyBold } from 'react-icons/pi';
|
||||
|
||||
import type { StylePresetFormData } from './StylePresetForm';
|
||||
import { PRESET_PLACEHOLDER } from '../hooks/usePresetModifiedPrompts';
|
||||
|
||||
interface Props extends UseControllerProps<StylePresetFormData> {
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const StylePresetPromptField = (props: Props) => {
|
||||
const { field } = useController(props);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const onChange = useCallback<ChangeEventHandler<HTMLTextAreaElement>>(
|
||||
(v) => {
|
||||
field.onChange(v.target.value);
|
||||
},
|
||||
[field]
|
||||
);
|
||||
|
||||
const value = useMemo(() => {
|
||||
return field.value;
|
||||
}, [field.value]);
|
||||
|
||||
const insertPromptPlaceholder = useCallback(() => {
|
||||
if (textareaRef.current) {
|
||||
const cursorPos = textareaRef.current.selectionStart;
|
||||
const textBeforeCursor = value.slice(0, cursorPos);
|
||||
const textAfterCursor = value.slice(cursorPos);
|
||||
const newValue = textBeforeCursor + PRESET_PLACEHOLDER + textAfterCursor;
|
||||
|
||||
field.onChange(newValue);
|
||||
} else {
|
||||
field.onChange(value + PRESET_PLACEHOLDER);
|
||||
}
|
||||
}, [value, field, textareaRef]);
|
||||
|
||||
const isPromptPresent = useMemo(() => value.includes(PRESET_PLACEHOLDER), [value]);
|
||||
|
||||
return (
|
||||
<FormControl orientation="vertical">
|
||||
<Flex alignItems="center" gap="1">
|
||||
<FormLabel>{props.label}</FormLabel>
|
||||
<IconButton
|
||||
onClick={insertPromptPlaceholder}
|
||||
size="sm"
|
||||
icon={<PiBracketsCurlyBold />}
|
||||
aria-label="Insert placeholder"
|
||||
isDisabled={isPromptPresent}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
<Textarea size="sm" ref={textareaRef} value={value} onChange={onChange} />
|
||||
</FormControl>
|
||||
);
|
||||
};
|
@ -0,0 +1,60 @@
|
||||
import { IconButton, Input, InputGroup, InputRightElement } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { searchTermChanged } from 'features/stylePresets/store/stylePresetSlice';
|
||||
import type { ChangeEvent, KeyboardEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiXBold } from 'react-icons/pi';
|
||||
|
||||
const StylePresetSearch = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const searchTerm = useAppSelector((s) => s.stylePreset.searchTerm);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handlePresetSearch = useCallback(
|
||||
(newSearchTerm: string) => {
|
||||
dispatch(searchTermChanged(newSearchTerm));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const clearPresetSearch = useCallback(() => {
|
||||
dispatch(searchTermChanged(''));
|
||||
}, [dispatch]);
|
||||
|
||||
const handleKeydown = useCallback(
|
||||
(e: KeyboardEvent<HTMLInputElement>) => {
|
||||
// exit search mode on escape
|
||||
if (e.key === 'Escape') {
|
||||
clearPresetSearch();
|
||||
}
|
||||
},
|
||||
[clearPresetSearch]
|
||||
);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
handlePresetSearch(e.target.value);
|
||||
},
|
||||
[handlePresetSearch]
|
||||
);
|
||||
|
||||
return (
|
||||
<InputGroup>
|
||||
<Input placeholder="Search by name" value={searchTerm} onKeyDown={handleKeydown} onChange={handleChange} />
|
||||
{searchTerm && searchTerm.length && (
|
||||
<InputRightElement h="full" pe={2}>
|
||||
<IconButton
|
||||
onClick={clearPresetSearch}
|
||||
size="sm"
|
||||
variant="link"
|
||||
aria-label={t('boards.clearSearch')}
|
||||
icon={<PiXBold />}
|
||||
/>
|
||||
</InputRightElement>
|
||||
)}
|
||||
</InputGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(StylePresetSearch);
|
@ -0,0 +1,25 @@
|
||||
import { useAppSelector } from "app/store/storeHooks"
|
||||
|
||||
export const PRESET_PLACEHOLDER = `{prompt}`
|
||||
|
||||
export const buildPresetModifiedPrompt = (presetPrompt: string, currentPrompt: string) => {
|
||||
return presetPrompt.includes(PRESET_PLACEHOLDER) ? presetPrompt.replace(new RegExp(PRESET_PLACEHOLDER), currentPrompt) : `${currentPrompt} ${presetPrompt}`
|
||||
}
|
||||
|
||||
|
||||
export const usePresetModifiedPrompts = () => {
|
||||
const activeStylePreset = useAppSelector(s => s.stylePreset.activeStylePreset)
|
||||
const { positivePrompt, negativePrompt } = useAppSelector(s => s.controlLayers.present)
|
||||
|
||||
if (!activeStylePreset) {
|
||||
return { presetModifiedPositivePrompt: positivePrompt, presetModifiedNegativePrompt: negativePrompt }
|
||||
}
|
||||
|
||||
const { positive_prompt: presetPositivePrompt, negative_prompt: presetNegativePrompt } = activeStylePreset.preset_data;
|
||||
|
||||
const presetModifiedPositivePrompt = buildPresetModifiedPrompt(presetPositivePrompt, positivePrompt)
|
||||
|
||||
const presetModifiedNegativePrompt = buildPresetModifiedPrompt(presetNegativePrompt, negativePrompt)
|
||||
|
||||
return { presetModifiedPositivePrompt, presetModifiedNegativePrompt }
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { StylePresetRecordDTO } from 'services/api/endpoints/stylePresets';
|
||||
|
||||
|
||||
export const useStylePresetFields = (preset: StylePresetRecordDTO | null) => {
|
||||
const stylePresetFieldDefaults = useMemo(() => {
|
||||
return {
|
||||
name: preset ? preset.name : '',
|
||||
positivePrompt: preset ? preset.preset_data.positive_prompt : '',
|
||||
negativePrompt: preset ? preset.preset_data.negative_prompt : ''
|
||||
};
|
||||
}, [
|
||||
preset
|
||||
]);
|
||||
|
||||
return stylePresetFieldDefaults;
|
||||
};
|
@ -9,8 +9,7 @@ import type { StylePresetState } from './types';
|
||||
export const initialState: StylePresetState = {
|
||||
isMenuOpen: false,
|
||||
activeStylePreset: null,
|
||||
calculatedPosPrompt: undefined,
|
||||
calculatedNegPrompt: undefined
|
||||
searchTerm: ""
|
||||
};
|
||||
|
||||
|
||||
@ -24,15 +23,12 @@ export const stylePresetSlice = createSlice({
|
||||
activeStylePresetChanged: (state, action: PayloadAction<StylePresetRecordDTO | null>) => {
|
||||
state.activeStylePreset = action.payload;
|
||||
},
|
||||
calculatedPosPromptChanged: (state, action: PayloadAction<string | undefined>) => {
|
||||
state.calculatedPosPrompt = action.payload;
|
||||
},
|
||||
calculatedNegPromptChanged: (state, action: PayloadAction<string | undefined>) => {
|
||||
state.calculatedNegPrompt = action.payload;
|
||||
searchTermChanged: (state, action: PayloadAction<string>) => {
|
||||
state.searchTerm = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { isMenuOpenChanged, activeStylePresetChanged, calculatedPosPromptChanged, calculatedNegPromptChanged } = stylePresetSlice.actions;
|
||||
export const { isMenuOpenChanged, activeStylePresetChanged, searchTermChanged } = stylePresetSlice.actions;
|
||||
|
||||
export const selectStylePresetSlice = (state: RootState) => state.stylePreset;
|
||||
|
@ -8,7 +8,6 @@ export type StylePresetModalState = {
|
||||
export type StylePresetState = {
|
||||
isMenuOpen: boolean;
|
||||
activeStylePreset: StylePresetRecordDTO | null;
|
||||
calculatedPosPrompt?: string
|
||||
calculatedNegPrompt?: string
|
||||
searchTerm: string
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { ChakraProps } from '@invoke-ai/ui-library';
|
||||
import { Box, Flex, Tab, TabList, TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library';
|
||||
import { Box, Flex, Portal,Tab, TabList, TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
||||
import { ControlLayersPanelContent } from 'features/controlLayers/components/ControlLayersPanelContent';
|
||||
@ -13,10 +13,12 @@ import { ControlSettingsAccordion } from 'features/settingsAccordions/components
|
||||
import { GenerationSettingsAccordion } from 'features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion';
|
||||
import { ImageSettingsAccordion } from 'features/settingsAccordions/components/ImageSettingsAccordion/ImageSettingsAccordion';
|
||||
import { RefinerSettingsAccordion } from 'features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion';
|
||||
import { StylePresetMenu } from 'features/stylePresets/components/StylePresetMenu';
|
||||
import { StylePresetMenuTrigger } from 'features/stylePresets/components/StylePresetMenuTrigger';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useCallback, useMemo, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const overlayScrollbarsStyles: CSSProperties = {
|
||||
@ -58,11 +60,31 @@ const ParametersPanelTextToImage = () => {
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const isMenuOpen = useAppSelector((s) => s.stylePreset.isMenuOpen);
|
||||
|
||||
return (
|
||||
<Flex w="full" h="full" flexDir="column" gap={2}>
|
||||
<QueueControls />
|
||||
<StylePresetMenuTrigger />
|
||||
<Flex w="full" h="full" position="relative">
|
||||
<Box position="absolute" top={0} left={0} right={0} bottom={0}>
|
||||
<Box position="absolute" top={0} left={0} right={0} bottom={0} ref={ref}>
|
||||
<Portal containerRef={ref}>
|
||||
{isMenuOpen && (
|
||||
<Box position="absolute" top={0} left={0} right={0} bottom={0}>
|
||||
<OverlayScrollbarsComponent
|
||||
defer
|
||||
style={overlayScrollbarsStyles}
|
||||
options={overlayScrollbarsParams.options}
|
||||
// backgroundColor="rgba(0,0,0,0.5)"
|
||||
>
|
||||
<Flex gap={2} flexDirection="column" h="full" w="full" layerStyle="second">
|
||||
<StylePresetMenu />
|
||||
</Flex>
|
||||
</OverlayScrollbarsComponent>
|
||||
</Box>
|
||||
)}
|
||||
</Portal>
|
||||
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
|
||||
<Flex gap={2} flexDirection="column" h="full" w="full">
|
||||
<Prompts />
|
||||
|
@ -67,11 +67,10 @@ export const stylePresetsApi = api.injectEndpoints({
|
||||
}),
|
||||
listStylePresets: build.query<
|
||||
paths['/api/v1/style_presets/']['get']['responses']['200']['content']['application/json'],
|
||||
NonNullable<paths['/api/v1/style_presets/']['get']['parameters']['query']>
|
||||
void
|
||||
>({
|
||||
query: (params) => ({
|
||||
query: () => ({
|
||||
url: buildStylePresetsUrl(),
|
||||
params,
|
||||
}),
|
||||
providesTags: ['FetchOnReconnect', { type: 'StylePreset', id: LIST_TAG }],
|
||||
}),
|
||||
|
@ -7345,147 +7345,147 @@ export type components = {
|
||||
project_id: string | null;
|
||||
};
|
||||
InvocationOutputMap: {
|
||||
crop_latents: components["schemas"]["LatentsOutput"];
|
||||
sdxl_refiner_model_loader: components["schemas"]["SDXLRefinerModelLoaderOutput"];
|
||||
color_map_image_processor: components["schemas"]["ImageOutput"];
|
||||
img_paste: components["schemas"]["ImageOutput"];
|
||||
image_collection: components["schemas"]["ImageCollectionOutput"];
|
||||
img_channel_offset: components["schemas"]["ImageOutput"];
|
||||
compel: components["schemas"]["ConditioningOutput"];
|
||||
denoise_latents: components["schemas"]["LatentsOutput"];
|
||||
t2i_adapter: components["schemas"]["T2IAdapterOutput"];
|
||||
pair_tile_image: components["schemas"]["PairTileImageOutput"];
|
||||
invert_tensor_mask: components["schemas"]["MaskOutput"];
|
||||
img_conv: components["schemas"]["ImageOutput"];
|
||||
img_hue_adjust: components["schemas"]["ImageOutput"];
|
||||
sdxl_refiner_compel_prompt: components["schemas"]["ConditioningOutput"];
|
||||
conditioning: components["schemas"]["ConditioningOutput"];
|
||||
mlsd_image_processor: components["schemas"]["ImageOutput"];
|
||||
image_mask_to_tensor: components["schemas"]["MaskOutput"];
|
||||
float_to_int: components["schemas"]["IntegerOutput"];
|
||||
img_scale: components["schemas"]["ImageOutput"];
|
||||
color: components["schemas"]["ColorOutput"];
|
||||
midas_depth_image_processor: components["schemas"]["ImageOutput"];
|
||||
mul: components["schemas"]["IntegerOutput"];
|
||||
pidi_image_processor: components["schemas"]["ImageOutput"];
|
||||
img_crop: components["schemas"]["ImageOutput"];
|
||||
metadata_item: components["schemas"]["MetadataItemOutput"];
|
||||
sdxl_lora_loader: components["schemas"]["SDXLLoRALoaderOutput"];
|
||||
metadata: components["schemas"]["MetadataOutput"];
|
||||
dynamic_prompt: components["schemas"]["StringCollectionOutput"];
|
||||
lblend: components["schemas"]["LatentsOutput"];
|
||||
canvas_paste_back: components["schemas"]["ImageOutput"];
|
||||
lresize: components["schemas"]["LatentsOutput"];
|
||||
sdxl_model_loader: components["schemas"]["SDXLModelLoaderOutput"];
|
||||
normalbae_image_processor: components["schemas"]["ImageOutput"];
|
||||
random_range: components["schemas"]["IntegerCollectionOutput"];
|
||||
img_chan: components["schemas"]["ImageOutput"];
|
||||
alpha_mask_to_tensor: components["schemas"]["MaskOutput"];
|
||||
img_nsfw: components["schemas"]["ImageOutput"];
|
||||
mask_combine: components["schemas"]["ImageOutput"];
|
||||
color_correct: components["schemas"]["ImageOutput"];
|
||||
latents: components["schemas"]["LatentsOutput"];
|
||||
seamless: components["schemas"]["SeamlessModeOutput"];
|
||||
lscale: components["schemas"]["LatentsOutput"];
|
||||
string_join_three: components["schemas"]["StringOutput"];
|
||||
lineart_image_processor: components["schemas"]["ImageOutput"];
|
||||
lineart_anime_image_processor: components["schemas"]["ImageOutput"];
|
||||
face_mask_detection: components["schemas"]["FaceMaskOutput"];
|
||||
esrgan: components["schemas"]["ImageOutput"];
|
||||
mask_edge: components["schemas"]["ImageOutput"];
|
||||
segment_anything_processor: components["schemas"]["ImageOutput"];
|
||||
cv_inpaint: components["schemas"]["ImageOutput"];
|
||||
tomask: components["schemas"]["ImageOutput"];
|
||||
lora_collection_loader: components["schemas"]["LoRALoaderOutput"];
|
||||
infill_cv2: components["schemas"]["ImageOutput"];
|
||||
spandrel_image_to_image: components["schemas"]["ImageOutput"];
|
||||
conditioning_collection: components["schemas"]["ConditioningCollectionOutput"];
|
||||
img_resize: components["schemas"]["ImageOutput"];
|
||||
create_denoise_mask: components["schemas"]["DenoiseMaskOutput"];
|
||||
controlnet: components["schemas"]["ControlOutput"];
|
||||
merge_tiles_to_image: components["schemas"]["ImageOutput"];
|
||||
mediapipe_face_processor: components["schemas"]["ImageOutput"];
|
||||
img_mul: components["schemas"]["ImageOutput"];
|
||||
image: components["schemas"]["ImageOutput"];
|
||||
merge_metadata: components["schemas"]["MetadataOutput"];
|
||||
add: components["schemas"]["IntegerOutput"];
|
||||
mask_from_id: components["schemas"]["ImageOutput"];
|
||||
vae_loader: components["schemas"]["VAEOutput"];
|
||||
ideal_size: components["schemas"]["IdealSizeOutput"];
|
||||
noise: components["schemas"]["NoiseOutput"];
|
||||
sub: components["schemas"]["IntegerOutput"];
|
||||
freeu: components["schemas"]["UNetOutput"];
|
||||
lora_selector: components["schemas"]["LoRASelectorOutput"];
|
||||
integer: components["schemas"]["IntegerOutput"];
|
||||
l2i: components["schemas"]["ImageOutput"];
|
||||
integer_collection: components["schemas"]["IntegerCollectionOutput"];
|
||||
rand_float: components["schemas"]["FloatOutput"];
|
||||
iterate: components["schemas"]["IterateInvocationOutput"];
|
||||
sdxl_compel_prompt: components["schemas"]["ConditioningOutput"];
|
||||
content_shuffle_image_processor: components["schemas"]["ImageOutput"];
|
||||
dw_openpose_image_processor: components["schemas"]["ImageOutput"];
|
||||
zoe_depth_image_processor: components["schemas"]["ImageOutput"];
|
||||
hed_image_processor: components["schemas"]["ImageOutput"];
|
||||
infill_lama: components["schemas"]["ImageOutput"];
|
||||
boolean: components["schemas"]["BooleanOutput"];
|
||||
float: components["schemas"]["FloatOutput"];
|
||||
range_of_size: components["schemas"]["IntegerCollectionOutput"];
|
||||
float_collection: components["schemas"]["FloatCollectionOutput"];
|
||||
img_channel_multiply: components["schemas"]["ImageOutput"];
|
||||
prompt_from_file: components["schemas"]["StringCollectionOutput"];
|
||||
infill_rgba: components["schemas"]["ImageOutput"];
|
||||
rectangle_mask: components["schemas"]["MaskOutput"];
|
||||
depth_anything_image_processor: components["schemas"]["ImageOutput"];
|
||||
boolean_collection: components["schemas"]["BooleanCollectionOutput"];
|
||||
rand_int: components["schemas"]["IntegerOutput"];
|
||||
latents_collection: components["schemas"]["LatentsCollectionOutput"];
|
||||
string_split: components["schemas"]["String2Output"];
|
||||
round_float: components["schemas"]["FloatOutput"];
|
||||
canny_image_processor: components["schemas"]["ImageOutput"];
|
||||
calculate_image_tiles: components["schemas"]["CalculateImageTilesOutput"];
|
||||
float_range: components["schemas"]["FloatCollectionOutput"];
|
||||
img_ilerp: components["schemas"]["ImageOutput"];
|
||||
unsharp_mask: components["schemas"]["ImageOutput"];
|
||||
img_watermark: components["schemas"]["ImageOutput"];
|
||||
model_identifier: components["schemas"]["ModelIdentifierOutput"];
|
||||
string_split_neg: components["schemas"]["StringPosNegOutput"];
|
||||
calculate_image_tiles_min_overlap: components["schemas"]["CalculateImageTilesOutput"];
|
||||
collect: components["schemas"]["CollectInvocationOutput"];
|
||||
core_metadata: components["schemas"]["MetadataOutput"];
|
||||
img_pad_crop: components["schemas"]["ImageOutput"];
|
||||
i2l: components["schemas"]["LatentsOutput"];
|
||||
tiled_multi_diffusion_denoise_latents: components["schemas"]["LatentsOutput"];
|
||||
save_image: components["schemas"]["ImageOutput"];
|
||||
show_image: components["schemas"]["ImageOutput"];
|
||||
string_collection: components["schemas"]["StringCollectionOutput"];
|
||||
calculate_image_tiles_even_split: components["schemas"]["CalculateImageTilesOutput"];
|
||||
infill_patchmatch: components["schemas"]["ImageOutput"];
|
||||
main_model_loader: components["schemas"]["ModelLoaderOutput"];
|
||||
lora_loader: components["schemas"]["LoRALoaderOutput"];
|
||||
string: components["schemas"]["StringOutput"];
|
||||
heuristic_resize: components["schemas"]["ImageOutput"];
|
||||
create_gradient_mask: components["schemas"]["GradientMaskOutput"];
|
||||
div: components["schemas"]["IntegerOutput"];
|
||||
blank_image: components["schemas"]["ImageOutput"];
|
||||
float_math: components["schemas"]["FloatOutput"];
|
||||
infill_tile: components["schemas"]["ImageOutput"];
|
||||
sdxl_lora_collection_loader: components["schemas"]["SDXLLoRALoaderOutput"];
|
||||
face_off: components["schemas"]["FaceOffOutput"];
|
||||
tile_image_processor: components["schemas"]["ImageOutput"];
|
||||
leres_image_processor: components["schemas"]["ImageOutput"];
|
||||
face_identifier: components["schemas"]["ImageOutput"];
|
||||
clip_skip: components["schemas"]["CLIPSkipInvocationOutput"];
|
||||
scheduler: components["schemas"]["SchedulerOutput"];
|
||||
img_lerp: components["schemas"]["ImageOutput"];
|
||||
conditioning_collection: components["schemas"]["ConditioningCollectionOutput"];
|
||||
merge_metadata: components["schemas"]["MetadataOutput"];
|
||||
lresize: components["schemas"]["LatentsOutput"];
|
||||
string_split_neg: components["schemas"]["StringPosNegOutput"];
|
||||
img_channel_multiply: components["schemas"]["ImageOutput"];
|
||||
add: components["schemas"]["IntegerOutput"];
|
||||
lscale: components["schemas"]["LatentsOutput"];
|
||||
string_replace: components["schemas"]["StringOutput"];
|
||||
step_param_easing: components["schemas"]["FloatCollectionOutput"];
|
||||
sdxl_model_loader: components["schemas"]["SDXLModelLoaderOutput"];
|
||||
collect: components["schemas"]["CollectInvocationOutput"];
|
||||
face_off: components["schemas"]["FaceOffOutput"];
|
||||
ideal_size: components["schemas"]["IdealSizeOutput"];
|
||||
float_to_int: components["schemas"]["IntegerOutput"];
|
||||
mlsd_image_processor: components["schemas"]["ImageOutput"];
|
||||
sub: components["schemas"]["IntegerOutput"];
|
||||
midas_depth_image_processor: components["schemas"]["ImageOutput"];
|
||||
rectangle_mask: components["schemas"]["MaskOutput"];
|
||||
img_watermark: components["schemas"]["ImageOutput"];
|
||||
img_ilerp: components["schemas"]["ImageOutput"];
|
||||
pidi_image_processor: components["schemas"]["ImageOutput"];
|
||||
vae_loader: components["schemas"]["VAEOutput"];
|
||||
dynamic_prompt: components["schemas"]["StringCollectionOutput"];
|
||||
float_range: components["schemas"]["FloatCollectionOutput"];
|
||||
spandrel_image_to_image_autoscale: components["schemas"]["ImageOutput"];
|
||||
ip_adapter: components["schemas"]["IPAdapterOutput"];
|
||||
tile_to_properties: components["schemas"]["TileToPropertiesOutput"];
|
||||
integer_math: components["schemas"]["IntegerOutput"];
|
||||
range: components["schemas"]["IntegerCollectionOutput"];
|
||||
create_denoise_mask: components["schemas"]["DenoiseMaskOutput"];
|
||||
denoise_latents: components["schemas"]["LatentsOutput"];
|
||||
image_collection: components["schemas"]["ImageCollectionOutput"];
|
||||
t2i_adapter: components["schemas"]["T2IAdapterOutput"];
|
||||
normalbae_image_processor: components["schemas"]["ImageOutput"];
|
||||
calculate_image_tiles_even_split: components["schemas"]["CalculateImageTilesOutput"];
|
||||
mul: components["schemas"]["IntegerOutput"];
|
||||
image_mask_to_tensor: components["schemas"]["MaskOutput"];
|
||||
face_mask_detection: components["schemas"]["FaceMaskOutput"];
|
||||
save_image: components["schemas"]["ImageOutput"];
|
||||
blank_image: components["schemas"]["ImageOutput"];
|
||||
conditioning: components["schemas"]["ConditioningOutput"];
|
||||
img_chan: components["schemas"]["ImageOutput"];
|
||||
string_split: components["schemas"]["String2Output"];
|
||||
segment_anything_processor: components["schemas"]["ImageOutput"];
|
||||
unsharp_mask: components["schemas"]["ImageOutput"];
|
||||
boolean_collection: components["schemas"]["BooleanCollectionOutput"];
|
||||
color: components["schemas"]["ColorOutput"];
|
||||
range_of_size: components["schemas"]["IntegerCollectionOutput"];
|
||||
face_identifier: components["schemas"]["ImageOutput"];
|
||||
div: components["schemas"]["IntegerOutput"];
|
||||
invert_tensor_mask: components["schemas"]["MaskOutput"];
|
||||
step_param_easing: components["schemas"]["FloatCollectionOutput"];
|
||||
merge_tiles_to_image: components["schemas"]["ImageOutput"];
|
||||
latents: components["schemas"]["LatentsOutput"];
|
||||
lineart_anime_image_processor: components["schemas"]["ImageOutput"];
|
||||
mediapipe_face_processor: components["schemas"]["ImageOutput"];
|
||||
infill_lama: components["schemas"]["ImageOutput"];
|
||||
compel: components["schemas"]["ConditioningOutput"];
|
||||
round_float: components["schemas"]["FloatOutput"];
|
||||
string_join: components["schemas"]["StringOutput"];
|
||||
dw_openpose_image_processor: components["schemas"]["ImageOutput"];
|
||||
content_shuffle_image_processor: components["schemas"]["ImageOutput"];
|
||||
metadata: components["schemas"]["MetadataOutput"];
|
||||
lineart_image_processor: components["schemas"]["ImageOutput"];
|
||||
zoe_depth_image_processor: components["schemas"]["ImageOutput"];
|
||||
controlnet: components["schemas"]["ControlOutput"];
|
||||
sdxl_lora_collection_loader: components["schemas"]["SDXLLoRALoaderOutput"];
|
||||
img_lerp: components["schemas"]["ImageOutput"];
|
||||
scheduler: components["schemas"]["SchedulerOutput"];
|
||||
l2i: components["schemas"]["ImageOutput"];
|
||||
img_paste: components["schemas"]["ImageOutput"];
|
||||
tile_to_properties: components["schemas"]["TileToPropertiesOutput"];
|
||||
sdxl_refiner_compel_prompt: components["schemas"]["ConditioningOutput"];
|
||||
calculate_image_tiles: components["schemas"]["CalculateImageTilesOutput"];
|
||||
depth_anything_image_processor: components["schemas"]["ImageOutput"];
|
||||
prompt_from_file: components["schemas"]["StringCollectionOutput"];
|
||||
integer: components["schemas"]["IntegerOutput"];
|
||||
img_mul: components["schemas"]["ImageOutput"];
|
||||
rand_int: components["schemas"]["IntegerOutput"];
|
||||
string_join_three: components["schemas"]["StringOutput"];
|
||||
img_blur: components["schemas"]["ImageOutput"];
|
||||
float: components["schemas"]["FloatOutput"];
|
||||
sdxl_lora_loader: components["schemas"]["SDXLLoRALoaderOutput"];
|
||||
crop_latents: components["schemas"]["LatentsOutput"];
|
||||
model_identifier: components["schemas"]["ModelIdentifierOutput"];
|
||||
show_image: components["schemas"]["ImageOutput"];
|
||||
img_channel_offset: components["schemas"]["ImageOutput"];
|
||||
i2l: components["schemas"]["LatentsOutput"];
|
||||
core_metadata: components["schemas"]["MetadataOutput"];
|
||||
infill_cv2: components["schemas"]["ImageOutput"];
|
||||
lora_selector: components["schemas"]["LoRASelectorOutput"];
|
||||
rand_float: components["schemas"]["FloatOutput"];
|
||||
float_math: components["schemas"]["FloatOutput"];
|
||||
main_model_loader: components["schemas"]["ModelLoaderOutput"];
|
||||
image: components["schemas"]["ImageOutput"];
|
||||
infill_patchmatch: components["schemas"]["ImageOutput"];
|
||||
noise: components["schemas"]["NoiseOutput"];
|
||||
tile_image_processor: components["schemas"]["ImageOutput"];
|
||||
spandrel_image_to_image: components["schemas"]["ImageOutput"];
|
||||
hed_image_processor: components["schemas"]["ImageOutput"];
|
||||
heuristic_resize: components["schemas"]["ImageOutput"];
|
||||
img_hue_adjust: components["schemas"]["ImageOutput"];
|
||||
create_gradient_mask: components["schemas"]["GradientMaskOutput"];
|
||||
calculate_image_tiles_min_overlap: components["schemas"]["CalculateImageTilesOutput"];
|
||||
canvas_paste_back: components["schemas"]["ImageOutput"];
|
||||
ip_adapter: components["schemas"]["IPAdapterOutput"];
|
||||
img_nsfw: components["schemas"]["ImageOutput"];
|
||||
range: components["schemas"]["IntegerCollectionOutput"];
|
||||
string: components["schemas"]["StringOutput"];
|
||||
seamless: components["schemas"]["SeamlessModeOutput"];
|
||||
integer_collection: components["schemas"]["IntegerCollectionOutput"];
|
||||
iterate: components["schemas"]["IterateInvocationOutput"];
|
||||
img_scale: components["schemas"]["ImageOutput"];
|
||||
pair_tile_image: components["schemas"]["PairTileImageOutput"];
|
||||
canny_image_processor: components["schemas"]["ImageOutput"];
|
||||
integer_math: components["schemas"]["IntegerOutput"];
|
||||
leres_image_processor: components["schemas"]["ImageOutput"];
|
||||
clip_skip: components["schemas"]["CLIPSkipInvocationOutput"];
|
||||
float_collection: components["schemas"]["FloatCollectionOutput"];
|
||||
string_collection: components["schemas"]["StringCollectionOutput"];
|
||||
lora_collection_loader: components["schemas"]["LoRALoaderOutput"];
|
||||
mask_combine: components["schemas"]["ImageOutput"];
|
||||
latents_collection: components["schemas"]["LatentsCollectionOutput"];
|
||||
mask_edge: components["schemas"]["ImageOutput"];
|
||||
alpha_mask_to_tensor: components["schemas"]["MaskOutput"];
|
||||
img_conv: components["schemas"]["ImageOutput"];
|
||||
color_correct: components["schemas"]["ImageOutput"];
|
||||
lblend: components["schemas"]["LatentsOutput"];
|
||||
mask_from_id: components["schemas"]["ImageOutput"];
|
||||
img_pad_crop: components["schemas"]["ImageOutput"];
|
||||
metadata_item: components["schemas"]["MetadataItemOutput"];
|
||||
lora_loader: components["schemas"]["LoRALoaderOutput"];
|
||||
cv_inpaint: components["schemas"]["ImageOutput"];
|
||||
color_map_image_processor: components["schemas"]["ImageOutput"];
|
||||
img_resize: components["schemas"]["ImageOutput"];
|
||||
random_range: components["schemas"]["IntegerCollectionOutput"];
|
||||
img_crop: components["schemas"]["ImageOutput"];
|
||||
freeu: components["schemas"]["UNetOutput"];
|
||||
infill_tile: components["schemas"]["ImageOutput"];
|
||||
infill_rgba: components["schemas"]["ImageOutput"];
|
||||
tomask: components["schemas"]["ImageOutput"];
|
||||
sdxl_compel_prompt: components["schemas"]["ConditioningOutput"];
|
||||
sdxl_refiner_model_loader: components["schemas"]["SDXLRefinerModelLoaderOutput"];
|
||||
boolean: components["schemas"]["BooleanOutput"];
|
||||
};
|
||||
/**
|
||||
* InvocationStartedEvent
|
||||
@ -10142,34 +10142,6 @@ export type components = {
|
||||
/** Ui Order */
|
||||
ui_order: number | null;
|
||||
};
|
||||
/** PaginatedResults[StylePresetRecordDTO] */
|
||||
PaginatedResults_StylePresetRecordDTO_: {
|
||||
/**
|
||||
* Page
|
||||
* @description Current Page
|
||||
*/
|
||||
page: number;
|
||||
/**
|
||||
* Pages
|
||||
* @description Total number of pages
|
||||
*/
|
||||
pages: number;
|
||||
/**
|
||||
* Per Page
|
||||
* @description Number of items per page
|
||||
*/
|
||||
per_page: number;
|
||||
/**
|
||||
* Total
|
||||
* @description Total number of items in result
|
||||
*/
|
||||
total: number;
|
||||
/**
|
||||
* Items
|
||||
* @description Items
|
||||
*/
|
||||
items: components["schemas"]["StylePresetRecordDTO"][];
|
||||
};
|
||||
/** PaginatedResults[WorkflowRecordListItemDTO] */
|
||||
PaginatedResults_WorkflowRecordListItemDTO_: {
|
||||
/**
|
||||
@ -12700,12 +12672,6 @@ export type components = {
|
||||
*/
|
||||
is_default: boolean;
|
||||
};
|
||||
/**
|
||||
* StylePresetRecordOrderBy
|
||||
* @description The order by options for workflow records
|
||||
* @enum {string}
|
||||
*/
|
||||
StylePresetRecordOrderBy: "created_at" | "name";
|
||||
/** StylePresetWithoutId */
|
||||
StylePresetWithoutId: {
|
||||
/**
|
||||
@ -16331,31 +16297,11 @@ export type operations = {
|
||||
* @description Gets a page of style presets
|
||||
*/
|
||||
list_style_presets: {
|
||||
parameters: {
|
||||
query?: {
|
||||
/** @description The page to get */
|
||||
page?: number;
|
||||
/** @description The number of style presets per page */
|
||||
per_page?: number;
|
||||
/** @description The attribute to order by */
|
||||
order_by?: components["schemas"]["StylePresetRecordOrderBy"];
|
||||
/** @description The direction to order by */
|
||||
direction?: components["schemas"]["SQLiteDirection"];
|
||||
/** @description The text to query by (matches name and description) */
|
||||
query?: string | null;
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["PaginatedResults_StylePresetRecordDTO_"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
"application/json": components["schemas"]["StylePresetRecordDTO"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user