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
|
||||||
|
|
||||||
from fastapi import APIRouter, Body, HTTPException, Path, Query
|
|
||||||
|
|
||||||
from invokeai.app.api.dependencies import ApiDependencies
|
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 (
|
from invokeai.app.services.style_preset_records.style_preset_records_common import (
|
||||||
StylePresetChanges,
|
StylePresetChanges,
|
||||||
StylePresetNotFoundError,
|
StylePresetNotFoundError,
|
||||||
StylePresetRecordDTO,
|
StylePresetRecordDTO,
|
||||||
StylePresetWithoutId,
|
StylePresetWithoutId,
|
||||||
StylePresetRecordOrderBy,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
style_presets_router = APIRouter(prefix="/v1/style_presets", tags=["style_presets"])
|
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",
|
operation_id="list_style_presets",
|
||||||
responses={
|
responses={
|
||||||
200: {"model": PaginatedResults[StylePresetRecordDTO]},
|
200: {"model": list[StylePresetRecordDTO]},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
async def list_style_presets(
|
async def list_style_presets() -> list[StylePresetRecordDTO]:
|
||||||
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]:
|
|
||||||
"""Gets a page of style presets"""
|
"""Gets a page of style presets"""
|
||||||
return ApiDependencies.invoker.services.style_preset_records.get_many(
|
return ApiDependencies.invoker.services.style_preset_records.get_many()
|
||||||
page=page,
|
|
||||||
per_page=per_page,
|
|
||||||
order_by=order_by,
|
|
||||||
direction=direction,
|
|
||||||
query=query,
|
|
||||||
)
|
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
from abc import ABC, abstractmethod
|
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 (
|
from invokeai.app.services.style_preset_records.style_preset_records_common import (
|
||||||
StylePresetChanges,
|
StylePresetChanges,
|
||||||
StylePresetRecordDTO,
|
StylePresetRecordDTO,
|
||||||
StylePresetWithoutId,
|
StylePresetWithoutId,
|
||||||
StylePresetRecordOrderBy,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -35,13 +31,6 @@ class StylePresetRecordsStorageBase(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_many(
|
def get_many(self) -> list[StylePresetRecordDTO]:
|
||||||
self,
|
|
||||||
page: int,
|
|
||||||
per_page: int,
|
|
||||||
order_by: StylePresetRecordOrderBy,
|
|
||||||
direction: SQLiteDirection,
|
|
||||||
query: Optional[str],
|
|
||||||
) -> PaginatedResults[StylePresetRecordDTO]:
|
|
||||||
"""Gets many workflows."""
|
"""Gets many workflows."""
|
||||||
pass
|
pass
|
||||||
|
@ -10,13 +10,6 @@ class StylePresetNotFoundError(Exception):
|
|||||||
"""Raised when a style preset is not found"""
|
"""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"):
|
class PresetData(BaseModel, extra="forbid"):
|
||||||
positive_prompt: str = Field(description="Positive prompt")
|
positive_prompt: str = Field(description="Positive prompt")
|
||||||
negative_prompt: str = Field(description="Negative 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,
|
StylePresetNotFoundError,
|
||||||
StylePresetRecordDTO,
|
StylePresetRecordDTO,
|
||||||
StylePresetWithoutId,
|
StylePresetWithoutId,
|
||||||
StylePresetRecordOrderBy,
|
|
||||||
)
|
)
|
||||||
from invokeai.app.util.misc import uuid_string
|
from invokeai.app.util.misc import uuid_string
|
||||||
|
|
||||||
@ -128,50 +127,21 @@ class SqliteStylePresetRecordsStorage(StylePresetRecordsStorageBase):
|
|||||||
|
|
||||||
def get_many(
|
def get_many(
|
||||||
self,
|
self,
|
||||||
page: int,
|
) -> list[StylePresetRecordDTO]:
|
||||||
per_page: int,
|
|
||||||
order_by: StylePresetRecordOrderBy,
|
|
||||||
direction: SQLiteDirection,
|
|
||||||
query: Optional[str] = None,
|
|
||||||
) -> PaginatedResults[StylePresetRecordDTO]:
|
|
||||||
try:
|
try:
|
||||||
self._lock.acquire()
|
self._lock.acquire()
|
||||||
# sanitize!
|
|
||||||
assert order_by in StylePresetRecordOrderBy
|
|
||||||
assert direction in SQLiteDirection
|
|
||||||
count_query = "SELECT COUNT(*) FROM style_presets"
|
|
||||||
main_query = """
|
main_query = """
|
||||||
SELECT
|
SELECT
|
||||||
*
|
*
|
||||||
FROM style_presets
|
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 ?;"
|
self._cursor.execute(main_query)
|
||||||
main_params.extend([per_page, page * per_page])
|
|
||||||
self._cursor.execute(main_query, main_params)
|
|
||||||
rows = self._cursor.fetchall()
|
rows = self._cursor.fetchall()
|
||||||
style_presets = [StylePresetRecordDTO.from_dict(dict(row)) for row in rows]
|
style_presets = [StylePresetRecordDTO.from_dict(dict(row)) for row in rows]
|
||||||
|
|
||||||
self._cursor.execute(count_query, count_params)
|
return style_presets
|
||||||
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,
|
|
||||||
)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self._conn.rollback()
|
self._conn.rollback()
|
||||||
raise
|
raise
|
||||||
|
@ -53,7 +53,6 @@ import type { AppDispatch, RootState } from 'app/store/store';
|
|||||||
|
|
||||||
import { addArchivedOrDeletedBoardListener } from './listeners/addArchivedOrDeletedBoardListener';
|
import { addArchivedOrDeletedBoardListener } from './listeners/addArchivedOrDeletedBoardListener';
|
||||||
import { addEnqueueRequestedUpscale } from './listeners/enqueueRequestedUpscale';
|
import { addEnqueueRequestedUpscale } from './listeners/enqueueRequestedUpscale';
|
||||||
import { addActiveStylePresetChanged } from './listeners/activeStylePresetChanged';
|
|
||||||
|
|
||||||
export const listenerMiddleware = createListenerMiddleware();
|
export const listenerMiddleware = createListenerMiddleware();
|
||||||
|
|
||||||
@ -147,7 +146,6 @@ addAdHocPostProcessingRequestedListener(startAppListening);
|
|||||||
|
|
||||||
// Prompts
|
// Prompts
|
||||||
addDynamicPromptsListener(startAppListening);
|
addDynamicPromptsListener(startAppListening);
|
||||||
addActiveStylePresetChanged(startAppListening)
|
|
||||||
|
|
||||||
addSetDefaultSettingsListener(startAppListening);
|
addSetDefaultSettingsListener(startAppListening);
|
||||||
addControlAdapterPreprocessor(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 { queueSlice } from 'features/queue/store/queueSlice';
|
||||||
import { sdxlPersistConfig, sdxlSlice } from 'features/sdxl/store/sdxlSlice';
|
import { sdxlPersistConfig, sdxlSlice } from 'features/sdxl/store/sdxlSlice';
|
||||||
import { stylePresetModalSlice } from 'features/stylePresets/store/stylePresetModalSlice';
|
import { stylePresetModalSlice } from 'features/stylePresets/store/stylePresetModalSlice';
|
||||||
|
import { stylePresetSlice } from 'features/stylePresets/store/stylePresetSlice';
|
||||||
import { configSlice } from 'features/system/store/configSlice';
|
import { configSlice } from 'features/system/store/configSlice';
|
||||||
import { systemPersistConfig, systemSlice } from 'features/system/store/systemSlice';
|
import { systemPersistConfig, systemSlice } from 'features/system/store/systemSlice';
|
||||||
import { uiPersistConfig, uiSlice } from 'features/ui/store/uiSlice';
|
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 { actionsDenylist } from './middleware/devtools/actionsDenylist';
|
||||||
import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
||||||
import { listenerMiddleware } from './middleware/listenerMiddleware';
|
import { listenerMiddleware } from './middleware/listenerMiddleware';
|
||||||
import { stylePresetSlice } from '../../features/stylePresets/store/stylePresetSlice';
|
|
||||||
|
|
||||||
const allReducers = {
|
const allReducers = {
|
||||||
[canvasSlice.name]: canvasSlice.reducer,
|
[canvasSlice.name]: canvasSlice.reducer,
|
||||||
|
@ -22,11 +22,10 @@ import {
|
|||||||
} from './constants';
|
} from './constants';
|
||||||
import { addLoRAs } from './generation/addLoRAs';
|
import { addLoRAs } from './generation/addLoRAs';
|
||||||
import { addSDXLLoRas } from './generation/addSDXLLoRAs';
|
import { addSDXLLoRas } from './generation/addSDXLLoRAs';
|
||||||
import { getBoardField, getSDXLStylePrompts } from './graphBuilderUtils';
|
import { getBoardField, getPresetModifiedPrompts } from './graphBuilderUtils';
|
||||||
|
|
||||||
export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise<GraphType> => {
|
export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise<GraphType> => {
|
||||||
const { model, cfgScale: cfg_scale, scheduler, steps, vaePrecision, seed, vae } = state.generation;
|
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;
|
const { upscaleModel, upscaleInitialImage, structure, creativity, tileControlnetModel, scale } = state.upscale;
|
||||||
|
|
||||||
assert(model, 'No model found in state');
|
assert(model, 'No model found in state');
|
||||||
@ -99,7 +98,7 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise
|
|||||||
let modelNode;
|
let modelNode;
|
||||||
|
|
||||||
if (model.base === 'sdxl') {
|
if (model.base === 'sdxl') {
|
||||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||||
|
|
||||||
posCondNode = g.addNode({
|
posCondNode = g.addNode({
|
||||||
type: 'sdxl_compel_prompt',
|
type: 'sdxl_compel_prompt',
|
||||||
@ -140,6 +139,8 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise
|
|||||||
vae: vae ?? undefined,
|
vae: vae ?? undefined,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||||
|
|
||||||
posCondNode = g.addNode({
|
posCondNode = g.addNode({
|
||||||
type: 'compel',
|
type: 'compel',
|
||||||
id: POSITIVE_CONDITIONING,
|
id: POSITIVE_CONDITIONING,
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
SDXL_REFINER_POSITIVE_CONDITIONING,
|
SDXL_REFINER_POSITIVE_CONDITIONING,
|
||||||
SDXL_REFINER_SEAMLESS,
|
SDXL_REFINER_SEAMLESS,
|
||||||
} from 'features/nodes/util/graph/constants';
|
} 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 type { NonNullableGraph } from 'services/api/types';
|
||||||
import { isRefinerMainModelModelConfig } 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;
|
const modelLoaderId = modelLoaderNodeId ? modelLoaderNodeId : SDXL_MODEL_LOADER;
|
||||||
|
|
||||||
// Construct Style Prompt
|
// Construct Style Prompt
|
||||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
const { positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||||
|
|
||||||
// Unplug SDXL Latents Generation To Latents To Image
|
// Unplug SDXL Latents Generation To Latents To Image
|
||||||
graph.edges = graph.edges.filter((e) => !(e.source.node_id === baseNodeId && ['latents'].includes(e.source.field)));
|
graph.edges = graph.edges.filter((e) => !(e.source.node_id === baseNodeId && ['latents'].includes(e.source.field)));
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
POSITIVE_CONDITIONING,
|
POSITIVE_CONDITIONING,
|
||||||
SEAMLESS,
|
SEAMLESS,
|
||||||
} from 'features/nodes/util/graph/constants';
|
} 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 type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||||
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
||||||
|
|
||||||
@ -51,7 +51,6 @@ export const buildCanvasImageToImageGraph = async (
|
|||||||
seamlessXAxis,
|
seamlessXAxis,
|
||||||
seamlessYAxis,
|
seamlessYAxis,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
|
|
||||||
// The bounding box determines width and height, not the width and height params
|
// The bounding box determines width and height, not the width and height params
|
||||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||||
@ -71,6 +70,8 @@ export const buildCanvasImageToImageGraph = async (
|
|||||||
|
|
||||||
const use_cpu = shouldUseCpuNoise;
|
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
|
* 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
|
* full graph here as a template. Then use the parameters from app state and set friendlier node
|
||||||
|
@ -19,7 +19,7 @@ import {
|
|||||||
POSITIVE_CONDITIONING,
|
POSITIVE_CONDITIONING,
|
||||||
SEAMLESS,
|
SEAMLESS,
|
||||||
} from 'features/nodes/util/graph/constants';
|
} 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 type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||||
|
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
@ -58,7 +58,6 @@ export const buildCanvasInpaintGraph = async (
|
|||||||
canvasCoherenceEdgeSize,
|
canvasCoherenceEdgeSize,
|
||||||
maskBlur,
|
maskBlur,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
|
|
||||||
if (!model) {
|
if (!model) {
|
||||||
log.error('No model found in state');
|
log.error('No model found in state');
|
||||||
@ -79,6 +78,8 @@ export const buildCanvasInpaintGraph = async (
|
|||||||
|
|
||||||
const use_cpu = shouldUseCpuNoise;
|
const use_cpu = shouldUseCpuNoise;
|
||||||
|
|
||||||
|
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||||
|
|
||||||
const graph: NonNullableGraph = {
|
const graph: NonNullableGraph = {
|
||||||
id: CANVAS_INPAINT_GRAPH,
|
id: CANVAS_INPAINT_GRAPH,
|
||||||
nodes: {
|
nodes: {
|
||||||
|
@ -23,7 +23,7 @@ import {
|
|||||||
POSITIVE_CONDITIONING,
|
POSITIVE_CONDITIONING,
|
||||||
SEAMLESS,
|
SEAMLESS,
|
||||||
} from 'features/nodes/util/graph/constants';
|
} 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 type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||||
|
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
@ -70,7 +70,6 @@ export const buildCanvasOutpaintGraph = async (
|
|||||||
canvasCoherenceEdgeSize,
|
canvasCoherenceEdgeSize,
|
||||||
maskBlur,
|
maskBlur,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
|
|
||||||
if (!model) {
|
if (!model) {
|
||||||
log.error('No model found in state');
|
log.error('No model found in state');
|
||||||
@ -91,6 +90,8 @@ export const buildCanvasOutpaintGraph = async (
|
|||||||
|
|
||||||
const use_cpu = shouldUseCpuNoise;
|
const use_cpu = shouldUseCpuNoise;
|
||||||
|
|
||||||
|
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||||
|
|
||||||
const graph: NonNullableGraph = {
|
const graph: NonNullableGraph = {
|
||||||
id: CANVAS_OUTPAINT_GRAPH,
|
id: CANVAS_OUTPAINT_GRAPH,
|
||||||
nodes: {
|
nodes: {
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
SDXL_REFINER_SEAMLESS,
|
SDXL_REFINER_SEAMLESS,
|
||||||
SEAMLESS,
|
SEAMLESS,
|
||||||
} from 'features/nodes/util/graph/constants';
|
} 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 type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||||
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
||||||
|
|
||||||
@ -51,7 +51,6 @@ export const buildCanvasSDXLImageToImageGraph = async (
|
|||||||
seamlessYAxis,
|
seamlessYAxis,
|
||||||
img2imgStrength: strength,
|
img2imgStrength: strength,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
|
|
||||||
const { refinerModel, refinerStart } = state.sdxl;
|
const { refinerModel, refinerStart } = state.sdxl;
|
||||||
|
|
||||||
@ -75,7 +74,7 @@ export const buildCanvasSDXLImageToImageGraph = async (
|
|||||||
const use_cpu = shouldUseCpuNoise;
|
const use_cpu = shouldUseCpuNoise;
|
||||||
|
|
||||||
// Construct Style Prompt
|
// 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
|
* 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,
|
SDXL_REFINER_SEAMLESS,
|
||||||
SEAMLESS,
|
SEAMLESS,
|
||||||
} from 'features/nodes/util/graph/constants';
|
} 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 type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||||
|
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
@ -58,7 +58,6 @@ export const buildCanvasSDXLInpaintGraph = async (
|
|||||||
canvasCoherenceEdgeSize,
|
canvasCoherenceEdgeSize,
|
||||||
maskBlur,
|
maskBlur,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
|
|
||||||
const { refinerModel, refinerStart } = state.sdxl;
|
const { refinerModel, refinerStart } = state.sdxl;
|
||||||
|
|
||||||
@ -83,7 +82,7 @@ export const buildCanvasSDXLInpaintGraph = async (
|
|||||||
const use_cpu = shouldUseCpuNoise;
|
const use_cpu = shouldUseCpuNoise;
|
||||||
|
|
||||||
// Construct Style Prompt
|
// Construct Style Prompt
|
||||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||||
|
|
||||||
const graph: NonNullableGraph = {
|
const graph: NonNullableGraph = {
|
||||||
id: SDXL_CANVAS_INPAINT_GRAPH,
|
id: SDXL_CANVAS_INPAINT_GRAPH,
|
||||||
|
@ -23,7 +23,7 @@ import {
|
|||||||
SDXL_REFINER_SEAMLESS,
|
SDXL_REFINER_SEAMLESS,
|
||||||
SEAMLESS,
|
SEAMLESS,
|
||||||
} from 'features/nodes/util/graph/constants';
|
} 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 type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types';
|
||||||
|
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
@ -70,7 +70,6 @@ export const buildCanvasSDXLOutpaintGraph = async (
|
|||||||
canvasCoherenceEdgeSize,
|
canvasCoherenceEdgeSize,
|
||||||
maskBlur,
|
maskBlur,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
|
|
||||||
const { refinerModel, refinerStart } = state.sdxl;
|
const { refinerModel, refinerStart } = state.sdxl;
|
||||||
|
|
||||||
@ -94,7 +93,7 @@ export const buildCanvasSDXLOutpaintGraph = async (
|
|||||||
const use_cpu = shouldUseCpuNoise;
|
const use_cpu = shouldUseCpuNoise;
|
||||||
|
|
||||||
// Construct Style Prompt
|
// Construct Style Prompt
|
||||||
const { positiveStylePrompt, negativeStylePrompt } = getSDXLStylePrompts(state);
|
const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state);
|
||||||
|
|
||||||
const graph: NonNullableGraph = {
|
const graph: NonNullableGraph = {
|
||||||
id: SDXL_CANVAS_OUTPAINT_GRAPH,
|
id: SDXL_CANVAS_OUTPAINT_GRAPH,
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
SDXL_REFINER_SEAMLESS,
|
SDXL_REFINER_SEAMLESS,
|
||||||
SEAMLESS,
|
SEAMLESS,
|
||||||
} from 'features/nodes/util/graph/constants';
|
} 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 { isNonRefinerMainModelConfig, type NonNullableGraph } from 'services/api/types';
|
||||||
|
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
@ -44,7 +44,6 @@ export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise
|
|||||||
seamlessXAxis,
|
seamlessXAxis,
|
||||||
seamlessYAxis,
|
seamlessYAxis,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
|
|
||||||
// The bounding box determines width and height, not the width and height params
|
// The bounding box determines width and height, not the width and height params
|
||||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||||
@ -67,7 +66,7 @@ export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise
|
|||||||
let modelLoaderNodeId = SDXL_MODEL_LOADER;
|
let modelLoaderNodeId = SDXL_MODEL_LOADER;
|
||||||
|
|
||||||
// Construct Style Prompt
|
// 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
|
* 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,
|
POSITIVE_CONDITIONING,
|
||||||
SEAMLESS,
|
SEAMLESS,
|
||||||
} from 'features/nodes/util/graph/constants';
|
} 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 { isNonRefinerMainModelConfig, type NonNullableGraph } from 'services/api/types';
|
||||||
|
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
@ -44,7 +44,6 @@ export const buildCanvasTextToImageGraph = async (state: RootState): Promise<Non
|
|||||||
seamlessXAxis,
|
seamlessXAxis,
|
||||||
seamlessYAxis,
|
seamlessYAxis,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
|
|
||||||
// The bounding box determines width and height, not the width and height params
|
// The bounding box determines width and height, not the width and height params
|
||||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||||
@ -64,6 +63,8 @@ export const buildCanvasTextToImageGraph = async (state: RootState): Promise<Non
|
|||||||
|
|
||||||
let modelLoaderNodeId = MAIN_MODEL_LOADER;
|
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
|
* 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
|
* 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 { addWatermarker } from 'features/nodes/util/graph/generation/addWatermarker';
|
||||||
import type { GraphType } from 'features/nodes/util/graph/generation/Graph';
|
import type { GraphType } from 'features/nodes/util/graph/generation/Graph';
|
||||||
import { Graph } 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 type { Invocation } from 'services/api/types';
|
||||||
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
||||||
import { assert } from 'tsafe';
|
import { assert } from 'tsafe';
|
||||||
@ -40,11 +40,12 @@ export const buildGenerationTabGraph = async (state: RootState): Promise<GraphTy
|
|||||||
seed,
|
seed,
|
||||||
vae,
|
vae,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
const { width, height } = state.controlLayers.present.size;
|
const { width, height } = state.controlLayers.present.size;
|
||||||
|
|
||||||
assert(model, 'No model found in state');
|
assert(model, 'No model found in state');
|
||||||
|
|
||||||
|
const { positivePrompt, negativePrompt } = getPresetModifiedPrompts(state);
|
||||||
|
|
||||||
const g = new Graph(CONTROL_LAYERS_GRAPH);
|
const g = new Graph(CONTROL_LAYERS_GRAPH);
|
||||||
const modelLoader = g.addNode({
|
const modelLoader = g.addNode({
|
||||||
type: 'main_model_loader',
|
type: 'main_model_loader',
|
||||||
@ -104,10 +105,10 @@ export const buildGenerationTabGraph = async (state: RootState): Promise<GraphTy
|
|||||||
const vaeLoader =
|
const vaeLoader =
|
||||||
vae?.base === model.base
|
vae?.base === model.base
|
||||||
? g.addNode({
|
? g.addNode({
|
||||||
type: 'vae_loader',
|
type: 'vae_loader',
|
||||||
id: VAE_LOADER,
|
id: VAE_LOADER,
|
||||||
vae_model: vae,
|
vae_model: vae,
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
let imageOutput: Invocation<'l2i'> | Invocation<'img_nsfw'> | Invocation<'img_watermark'> = l2i;
|
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 { addSeamless } from 'features/nodes/util/graph/generation/addSeamless';
|
||||||
import { addWatermarker } from 'features/nodes/util/graph/generation/addWatermarker';
|
import { addWatermarker } from 'features/nodes/util/graph/generation/addWatermarker';
|
||||||
import { Graph } from 'features/nodes/util/graph/generation/Graph';
|
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 type { Invocation, NonNullableGraph } from 'services/api/types';
|
||||||
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
import { isNonRefinerMainModelConfig } from 'services/api/types';
|
||||||
import { assert } from 'tsafe';
|
import { assert } from 'tsafe';
|
||||||
@ -36,14 +36,13 @@ export const buildGenerationTabSDXLGraph = async (state: RootState): Promise<Non
|
|||||||
vaePrecision,
|
vaePrecision,
|
||||||
vae,
|
vae,
|
||||||
} = state.generation;
|
} = state.generation;
|
||||||
const { positivePrompt, negativePrompt } = state.controlLayers.present;
|
|
||||||
const { width, height } = state.controlLayers.present.size;
|
const { width, height } = state.controlLayers.present.size;
|
||||||
|
|
||||||
const { refinerModel, refinerStart } = state.sdxl;
|
const { refinerModel, refinerStart } = state.sdxl;
|
||||||
|
|
||||||
assert(model, 'No model found in state');
|
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 g = new Graph(SDXL_CONTROL_LAYERS_GRAPH);
|
||||||
const modelLoader = g.addNode({
|
const modelLoader = g.addNode({
|
||||||
@ -94,10 +93,10 @@ export const buildGenerationTabSDXLGraph = async (state: RootState): Promise<Non
|
|||||||
const vaeLoader =
|
const vaeLoader =
|
||||||
vae?.base === model.base
|
vae?.base === model.base
|
||||||
? g.addNode({
|
? g.addNode({
|
||||||
type: 'vae_loader',
|
type: 'vae_loader',
|
||||||
id: VAE_LOADER,
|
id: VAE_LOADER,
|
||||||
vae_model: vae,
|
vae_model: vae,
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
let imageOutput: Invocation<'l2i'> | Invocation<'img_nsfw'> | Invocation<'img_watermark'> = l2i;
|
let imageOutput: Invocation<'l2i'> | Invocation<'img_nsfw'> | Invocation<'img_watermark'> = l2i;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import type { BoardField } from 'features/nodes/types/common';
|
import type { BoardField } from 'features/nodes/types/common';
|
||||||
|
import { buildPresetModifiedPrompt } from 'features/stylePresets/hooks/usePresetModifiedPrompts';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
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 } =
|
const { positivePrompt, negativePrompt, positivePrompt2, negativePrompt2, shouldConcatPrompts } =
|
||||||
state.controlLayers.present;
|
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 {
|
return {
|
||||||
|
positivePrompt,
|
||||||
|
negativePrompt,
|
||||||
positiveStylePrompt: shouldConcatPrompts ? positivePrompt : positivePrompt2,
|
positiveStylePrompt: shouldConcatPrompts ? positivePrompt : positivePrompt2,
|
||||||
negativeStylePrompt: shouldConcatPrompts ? negativePrompt : negativePrompt2,
|
negativeStylePrompt: shouldConcatPrompts ? negativePrompt : negativePrompt2,
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@ import { ParamPositivePrompt } from 'features/parameters/components/Core/ParamPo
|
|||||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||||
import { ParamSDXLNegativeStylePrompt } from 'features/sdxl/components/SDXLPrompts/ParamSDXLNegativeStylePrompt';
|
import { ParamSDXLNegativeStylePrompt } from 'features/sdxl/components/SDXLPrompts/ParamSDXLNegativeStylePrompt';
|
||||||
import { ParamSDXLPositiveStylePrompt } from 'features/sdxl/components/SDXLPrompts/ParamSDXLPositiveStylePrompt';
|
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';
|
import { memo } from 'react';
|
||||||
|
|
||||||
const concatPromptsSelector = createSelector(
|
const concatPromptsSelector = createSelector(
|
||||||
@ -19,16 +19,14 @@ const concatPromptsSelector = createSelector(
|
|||||||
|
|
||||||
export const Prompts = memo(() => {
|
export const Prompts = memo(() => {
|
||||||
const shouldConcatPrompts = useAppSelector(concatPromptsSelector);
|
const shouldConcatPrompts = useAppSelector(concatPromptsSelector);
|
||||||
const calculatedPosPrompt = useAppSelector((s) => s.stylePreset.calculatedPosPrompt);
|
const { presetModifiedPositivePrompt, presetModifiedNegativePrompt } = usePresetModifiedPrompts();
|
||||||
const calculatedNegPrompt = useAppSelector((s) => s.stylePreset.calculatedNegPrompt);
|
|
||||||
return (
|
return (
|
||||||
<Flex flexDir="column" gap={2}>
|
<Flex flexDir="column" gap={2}>
|
||||||
<StylePresetMenuTrigger />
|
|
||||||
<ParamPositivePrompt />
|
<ParamPositivePrompt />
|
||||||
<Flex>{calculatedPosPrompt}</Flex>
|
<Flex>{presetModifiedPositivePrompt}</Flex>
|
||||||
{!shouldConcatPrompts && <ParamSDXLPositiveStylePrompt />}
|
{!shouldConcatPrompts && <ParamSDXLPositiveStylePrompt />}
|
||||||
<ParamNegativePrompt />
|
<ParamNegativePrompt />
|
||||||
<Flex>{calculatedNegPrompt}</Flex>
|
<Flex>{presetModifiedNegativePrompt}</Flex>
|
||||||
{!shouldConcatPrompts && <ParamSDXLNegativeStylePrompt />}
|
{!shouldConcatPrompts && <ParamSDXLNegativeStylePrompt />}
|
||||||
</Flex>
|
</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 { useAppDispatch } from 'app/store/storeHooks';
|
||||||
|
import { useStylePresetFields } from 'features/stylePresets/hooks/useStylePresetFields';
|
||||||
import { isModalOpenChanged, updatingStylePresetChanged } from 'features/stylePresets/store/stylePresetModalSlice';
|
import { isModalOpenChanged, updatingStylePresetChanged } from 'features/stylePresets/store/stylePresetModalSlice';
|
||||||
import { toast } from 'features/toast/toast';
|
import { toast } from 'features/toast/toast';
|
||||||
import type { ChangeEventHandler } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useCallback, useEffect, useState } 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 type { StylePresetRecordDTO } from 'services/api/endpoints/stylePresets';
|
||||||
import { useCreateStylePresetMutation, useUpdateStylePresetMutation } 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 }) => {
|
export const StylePresetForm = ({ updatingPreset }: { updatingPreset: StylePresetRecordDTO | null }) => {
|
||||||
const [createStylePreset] = useCreateStylePresetMutation();
|
const [createStylePreset] = useCreateStylePresetMutation();
|
||||||
const [updateStylePreset] = useUpdateStylePresetMutation();
|
const [updateStylePreset] = useUpdateStylePresetMutation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const [name, setName] = useState(updatingPreset ? updatingPreset.name : '');
|
const stylePresetFieldDefaults = useStylePresetFields(updatingPreset);
|
||||||
const [posPrompt, setPosPrompt] = useState(updatingPreset ? updatingPreset.preset_data.positive_prompt : '');
|
|
||||||
const [negPrompt, setNegPrompt] = useState(updatingPreset ? updatingPreset.preset_data.negative_prompt : '');
|
|
||||||
|
|
||||||
const handleChangeName = useCallback<ChangeEventHandler<HTMLInputElement>>((e) => {
|
const { handleSubmit, control, formState, reset, register } = useForm<StylePresetFormData>({
|
||||||
setName(e.target.value);
|
defaultValues: stylePresetFieldDefaults,
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
const handleChangePosPrompt = useCallback<ChangeEventHandler<HTMLTextAreaElement>>((e) => {
|
const handleClickSave = useCallback<SubmitHandler<StylePresetFormData>>(
|
||||||
setPosPrompt(e.target.value);
|
async (data) => {
|
||||||
}, []);
|
try {
|
||||||
|
if (updatingPreset) {
|
||||||
const handleChangeNegPrompt = useCallback<ChangeEventHandler<HTMLTextAreaElement>>((e) => {
|
await updateStylePreset({
|
||||||
setNegPrompt(e.target.value);
|
id: updatingPreset.id,
|
||||||
}, []);
|
changes: {
|
||||||
|
name: data.name,
|
||||||
useEffect(() => {
|
preset_data: { positive_prompt: data.positivePrompt, negative_prompt: data.negativePrompt },
|
||||||
if (updatingPreset) {
|
},
|
||||||
setName(updatingPreset.name);
|
}).unwrap();
|
||||||
setPosPrompt(updatingPreset.preset_data.positive_prompt);
|
} else {
|
||||||
setNegPrompt(updatingPreset.preset_data.negative_prompt);
|
await createStylePreset({
|
||||||
} else {
|
name: data.name,
|
||||||
setName('');
|
preset_data: { positive_prompt: data.positivePrompt, negative_prompt: data.negativePrompt },
|
||||||
setPosPrompt('');
|
}).unwrap();
|
||||||
setNegPrompt('');
|
}
|
||||||
}
|
} catch (error) {
|
||||||
}, [updatingPreset]);
|
toast({
|
||||||
|
status: 'error',
|
||||||
const handleClickSave = useCallback(async () => {
|
title: 'Failed to save style preset',
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
toast({
|
|
||||||
status: 'error',
|
|
||||||
title: 'Failed to save style preset',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(updatingStylePresetChanged(null));
|
dispatch(updatingStylePresetChanged(null));
|
||||||
dispatch(isModalOpenChanged(false));
|
dispatch(isModalOpenChanged(false));
|
||||||
}, [dispatch, updatingPreset, name, posPrompt, negPrompt, updateStylePreset, createStylePreset]);
|
},
|
||||||
|
[dispatch, updatingPreset, updateStylePreset, createStylePreset]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex flexDir="column" gap="4">
|
<Flex flexDir="column" gap="4">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<FormLabel>Name</FormLabel>
|
<FormLabel>Name</FormLabel>
|
||||||
<Input value={name} onChange={handleChangeName} />
|
<Input size="md" {...register('name')} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl>
|
<Flex flexDir="column" bgColor="base.750" borderRadius="base" padding="10px" gap="10px">
|
||||||
<FormLabel>Positive Prompt</FormLabel>
|
<Text variant="subtext">
|
||||||
<Textarea value={posPrompt} onChange={handleChangePosPrompt} />
|
Use the <Icon as={PiBracketsCurlyBold} /> button to specify where your manual prompt should be included in the
|
||||||
</FormControl>
|
template. If you do not provide one, the template will be appended to your prompt.
|
||||||
<FormControl>
|
</Text>
|
||||||
<FormLabel>Negative Prompt</FormLabel>
|
<StylePresetPromptField label="Positive Prompt" control={control} name="positivePrompt" />
|
||||||
<Textarea value={negPrompt} onChange={handleChangeNegPrompt} />
|
<StylePresetPromptField label="Negative Prompt" control={control} name="negativePrompt" />
|
||||||
</FormControl>
|
</Flex>
|
||||||
<Button onClick={handleClickSave}>Save</Button>
|
|
||||||
|
<Button onClick={handleSubmit(handleClickSave)}>Save</Button>
|
||||||
</Flex>
|
</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 { Badge, Flex, IconButton, Text } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import ModelImage from 'features/modelManagerV2/subpanels/ModelManagerPanel/ModelImage';
|
||||||
import { isModalOpenChanged, updatingStylePresetChanged } from 'features/stylePresets/store/stylePresetModalSlice';
|
import { isModalOpenChanged, updatingStylePresetChanged } from 'features/stylePresets/store/stylePresetModalSlice';
|
||||||
|
import { activeStylePresetChanged, isMenuOpenChanged } from 'features/stylePresets/store/stylePresetSlice';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { PiPencilBold, PiTrashBold } from 'react-icons/pi';
|
||||||
import type { StylePresetRecordDTO } from 'services/api/endpoints/stylePresets';
|
import type { StylePresetRecordDTO } from 'services/api/endpoints/stylePresets';
|
||||||
import { useDeleteStylePresetMutation } from 'services/api/endpoints/stylePresets';
|
import { useDeleteStylePresetMutation } from 'services/api/endpoints/stylePresets';
|
||||||
import { activeStylePresetChanged, isMenuOpenChanged } from '../store/stylePresetSlice';
|
|
||||||
|
|
||||||
export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordDTO }) => {
|
export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordDTO }) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const [deleteStylePreset] = useDeleteStylePresetMutation();
|
const [deleteStylePreset] = useDeleteStylePresetMutation();
|
||||||
|
const activeStylePreset = useAppSelector((s) => s.stylePreset.activeStylePreset);
|
||||||
|
|
||||||
const handleClickEdit = useCallback(() => {
|
const handleClickEdit = useCallback(() => {
|
||||||
dispatch(updatingStylePresetChanged(preset));
|
dispatch(updatingStylePresetChanged(preset));
|
||||||
@ -27,10 +30,47 @@ export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordDTO }
|
|||||||
}, [preset]);
|
}, [preset]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Flex
|
||||||
<Flex flexDir="column" gap="2">
|
gap="4"
|
||||||
<Text fontSize="md">{preset.name}</Text>
|
onClick={handleClickApply}
|
||||||
<Flex flexDir="column" layerStyle="third" borderRadius="base" padding="10px">
|
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 fontSize="xs">
|
||||||
<Text as="span" fontWeight="semibold">
|
<Text as="span" fontWeight="semibold">
|
||||||
Positive prompt:
|
Positive prompt:
|
||||||
@ -43,11 +83,8 @@ export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordDTO }
|
|||||||
</Text>{' '}
|
</Text>{' '}
|
||||||
{preset.preset_data.negative_prompt}
|
{preset.preset_data.negative_prompt}
|
||||||
</Text>
|
</Text>
|
||||||
<Button onClick={handleClickEdit}>Edit</Button>
|
|
||||||
<Button onClick={handleDeletePreset}>Delete</Button>
|
|
||||||
<Button onClick={handleClickApply}>Apply</Button>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,13 +1,42 @@
|
|||||||
import { Button, Flex, Text } from '@invoke-ai/ui-library';
|
import { Flex, IconButton, Text } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { EMPTY_ARRAY } from 'app/store/constants';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { isModalOpenChanged, updatingStylePresetChanged } from 'features/stylePresets/store/stylePresetModalSlice';
|
import { isModalOpenChanged, updatingStylePresetChanged } from 'features/stylePresets/store/stylePresetModalSlice';
|
||||||
import { useCallback } from 'react';
|
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 { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
||||||
|
|
||||||
import { StylePresetListItem } from './StylePresetListItem';
|
import { StylePresetList } from './StylePresetList';
|
||||||
|
import StylePresetSearch from './StylePresetSearch';
|
||||||
|
|
||||||
export const StylePresetMenu = () => {
|
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 dispatch = useAppDispatch();
|
||||||
|
|
||||||
const handleClickAddNew = useCallback(() => {
|
const handleClickAddNew = useCallback(() => {
|
||||||
@ -16,19 +45,30 @@ export const StylePresetMenu = () => {
|
|||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Flex flexDir="column" gap="2" padding="10px">
|
||||||
<Flex flexDir="column" gap="2">
|
<Flex alignItems="center" gap="10" w="full" justifyContent="space-between">
|
||||||
<Flex alignItems="center" gap="10" w="full" justifyContent="space-between">
|
<StylePresetSearch />
|
||||||
<Text fontSize="sm" fontWeight="semibold" userSelect="none" color="base.500">
|
<IconButton
|
||||||
Style Presets
|
icon={<PiPlusBold />}
|
||||||
</Text>
|
tooltip="Create Preset"
|
||||||
<Button size="sm" onClick={handleClickAddNew}>
|
aria-label="Create Preset"
|
||||||
Add New
|
onClick={handleClickAddNew}
|
||||||
</Button>
|
size="md"
|
||||||
</Flex>
|
variant="link"
|
||||||
|
w={8}
|
||||||
{data?.items.map((preset) => <StylePresetListItem preset={preset} key={preset.id} />)}
|
h={8}
|
||||||
|
/>
|
||||||
</Flex>
|
</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 { Flex, Icon } from '@invoke-ai/ui-library';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { StylePresetMenu } from './StylePresetMenu';
|
import { isMenuOpenChanged } from 'features/stylePresets/store/stylePresetSlice';
|
||||||
import { useAppDispatch, useAppSelector } from '../../../app/store/storeHooks';
|
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { isMenuOpenChanged } from '../store/stylePresetSlice';
|
import { PiCaretDownBold } from 'react-icons/pi';
|
||||||
|
|
||||||
|
import { ActiveStylePreset } from './ActiveStylePreset';
|
||||||
|
|
||||||
export const StylePresetMenuTrigger = () => {
|
export const StylePresetMenuTrigger = () => {
|
||||||
const isMenuOpen = useAppSelector((s) => s.stylePreset.isMenuOpen);
|
const isMenuOpen = useAppSelector((s) => s.stylePreset.isMenuOpen);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const handleClose = useCallback(() => {
|
|
||||||
dispatch(isMenuOpenChanged(false));
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
const handleToggle = useCallback(() => {
|
const handleToggle = useCallback(() => {
|
||||||
dispatch(isMenuOpenChanged(!isMenuOpen));
|
dispatch(isMenuOpenChanged(!isMenuOpen));
|
||||||
}, [dispatch, isMenuOpen]);
|
}, [dispatch, isMenuOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover isOpen={isMenuOpen} onClose={handleClose}>
|
<Flex
|
||||||
<PopoverTrigger>
|
onClick={handleToggle}
|
||||||
<Button size="sm" onClick={handleToggle}>
|
backgroundColor="base.800"
|
||||||
Style Presets
|
justifyContent="space-between"
|
||||||
</Button>
|
alignItems="center"
|
||||||
</PopoverTrigger>
|
padding="5px 10px"
|
||||||
<PopoverContent>
|
borderRadius="base"
|
||||||
<PopoverBody>
|
>
|
||||||
<StylePresetMenu />
|
<ActiveStylePreset />
|
||||||
</PopoverBody>
|
|
||||||
</PopoverContent>
|
<Icon as={PiCaretDownBold} />
|
||||||
</Popover>
|
</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 = {
|
export const initialState: StylePresetState = {
|
||||||
isMenuOpen: false,
|
isMenuOpen: false,
|
||||||
activeStylePreset: null,
|
activeStylePreset: null,
|
||||||
calculatedPosPrompt: undefined,
|
searchTerm: ""
|
||||||
calculatedNegPrompt: undefined
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -24,15 +23,12 @@ export const stylePresetSlice = createSlice({
|
|||||||
activeStylePresetChanged: (state, action: PayloadAction<StylePresetRecordDTO | null>) => {
|
activeStylePresetChanged: (state, action: PayloadAction<StylePresetRecordDTO | null>) => {
|
||||||
state.activeStylePreset = action.payload;
|
state.activeStylePreset = action.payload;
|
||||||
},
|
},
|
||||||
calculatedPosPromptChanged: (state, action: PayloadAction<string | undefined>) => {
|
searchTermChanged: (state, action: PayloadAction<string>) => {
|
||||||
state.calculatedPosPrompt = action.payload;
|
state.searchTerm = action.payload;
|
||||||
},
|
|
||||||
calculatedNegPromptChanged: (state, action: PayloadAction<string | undefined>) => {
|
|
||||||
state.calculatedNegPrompt = action.payload;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { isMenuOpenChanged, activeStylePresetChanged, calculatedPosPromptChanged, calculatedNegPromptChanged } = stylePresetSlice.actions;
|
export const { isMenuOpenChanged, activeStylePresetChanged, searchTermChanged } = stylePresetSlice.actions;
|
||||||
|
|
||||||
export const selectStylePresetSlice = (state: RootState) => state.stylePreset;
|
export const selectStylePresetSlice = (state: RootState) => state.stylePreset;
|
||||||
|
@ -8,7 +8,6 @@ export type StylePresetModalState = {
|
|||||||
export type StylePresetState = {
|
export type StylePresetState = {
|
||||||
isMenuOpen: boolean;
|
isMenuOpen: boolean;
|
||||||
activeStylePreset: StylePresetRecordDTO | null;
|
activeStylePreset: StylePresetRecordDTO | null;
|
||||||
calculatedPosPrompt?: string
|
searchTerm: string
|
||||||
calculatedNegPrompt?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { ChakraProps } from '@invoke-ai/ui-library';
|
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 { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
||||||
import { ControlLayersPanelContent } from 'features/controlLayers/components/ControlLayersPanelContent';
|
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 { GenerationSettingsAccordion } from 'features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion';
|
||||||
import { ImageSettingsAccordion } from 'features/settingsAccordions/components/ImageSettingsAccordion/ImageSettingsAccordion';
|
import { ImageSettingsAccordion } from 'features/settingsAccordions/components/ImageSettingsAccordion/ImageSettingsAccordion';
|
||||||
import { RefinerSettingsAccordion } from 'features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion';
|
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 { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||||
import type { CSSProperties } from 'react';
|
import type { CSSProperties } from 'react';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const overlayScrollbarsStyles: CSSProperties = {
|
const overlayScrollbarsStyles: CSSProperties = {
|
||||||
@ -58,11 +60,31 @@ const ParametersPanelTextToImage = () => {
|
|||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const isMenuOpen = useAppSelector((s) => s.stylePreset.isMenuOpen);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex w="full" h="full" flexDir="column" gap={2}>
|
<Flex w="full" h="full" flexDir="column" gap={2}>
|
||||||
<QueueControls />
|
<QueueControls />
|
||||||
|
<StylePresetMenuTrigger />
|
||||||
<Flex w="full" h="full" position="relative">
|
<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}>
|
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
|
||||||
<Flex gap={2} flexDirection="column" h="full" w="full">
|
<Flex gap={2} flexDirection="column" h="full" w="full">
|
||||||
<Prompts />
|
<Prompts />
|
||||||
|
@ -67,11 +67,10 @@ export const stylePresetsApi = api.injectEndpoints({
|
|||||||
}),
|
}),
|
||||||
listStylePresets: build.query<
|
listStylePresets: build.query<
|
||||||
paths['/api/v1/style_presets/']['get']['responses']['200']['content']['application/json'],
|
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(),
|
url: buildStylePresetsUrl(),
|
||||||
params,
|
|
||||||
}),
|
}),
|
||||||
providesTags: ['FetchOnReconnect', { type: 'StylePreset', id: LIST_TAG }],
|
providesTags: ['FetchOnReconnect', { type: 'StylePreset', id: LIST_TAG }],
|
||||||
}),
|
}),
|
||||||
|
@ -7345,147 +7345,147 @@ export type components = {
|
|||||||
project_id: string | null;
|
project_id: string | null;
|
||||||
};
|
};
|
||||||
InvocationOutputMap: {
|
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"];
|
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"];
|
tiled_multi_diffusion_denoise_latents: components["schemas"]["LatentsOutput"];
|
||||||
save_image: components["schemas"]["ImageOutput"];
|
conditioning_collection: components["schemas"]["ConditioningCollectionOutput"];
|
||||||
show_image: components["schemas"]["ImageOutput"];
|
merge_metadata: components["schemas"]["MetadataOutput"];
|
||||||
string_collection: components["schemas"]["StringCollectionOutput"];
|
lresize: components["schemas"]["LatentsOutput"];
|
||||||
calculate_image_tiles_even_split: components["schemas"]["CalculateImageTilesOutput"];
|
string_split_neg: components["schemas"]["StringPosNegOutput"];
|
||||||
infill_patchmatch: components["schemas"]["ImageOutput"];
|
img_channel_multiply: components["schemas"]["ImageOutput"];
|
||||||
main_model_loader: components["schemas"]["ModelLoaderOutput"];
|
add: components["schemas"]["IntegerOutput"];
|
||||||
lora_loader: components["schemas"]["LoRALoaderOutput"];
|
lscale: components["schemas"]["LatentsOutput"];
|
||||||
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"];
|
|
||||||
string_replace: components["schemas"]["StringOutput"];
|
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"];
|
spandrel_image_to_image_autoscale: components["schemas"]["ImageOutput"];
|
||||||
ip_adapter: components["schemas"]["IPAdapterOutput"];
|
create_denoise_mask: components["schemas"]["DenoiseMaskOutput"];
|
||||||
tile_to_properties: components["schemas"]["TileToPropertiesOutput"];
|
denoise_latents: components["schemas"]["LatentsOutput"];
|
||||||
integer_math: components["schemas"]["IntegerOutput"];
|
image_collection: components["schemas"]["ImageCollectionOutput"];
|
||||||
range: components["schemas"]["IntegerCollectionOutput"];
|
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"];
|
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"];
|
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
|
* InvocationStartedEvent
|
||||||
@ -10142,34 +10142,6 @@ export type components = {
|
|||||||
/** Ui Order */
|
/** Ui Order */
|
||||||
ui_order: number | null;
|
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] */
|
||||||
PaginatedResults_WorkflowRecordListItemDTO_: {
|
PaginatedResults_WorkflowRecordListItemDTO_: {
|
||||||
/**
|
/**
|
||||||
@ -12700,12 +12672,6 @@ export type components = {
|
|||||||
*/
|
*/
|
||||||
is_default: boolean;
|
is_default: boolean;
|
||||||
};
|
};
|
||||||
/**
|
|
||||||
* StylePresetRecordOrderBy
|
|
||||||
* @description The order by options for workflow records
|
|
||||||
* @enum {string}
|
|
||||||
*/
|
|
||||||
StylePresetRecordOrderBy: "created_at" | "name";
|
|
||||||
/** StylePresetWithoutId */
|
/** StylePresetWithoutId */
|
||||||
StylePresetWithoutId: {
|
StylePresetWithoutId: {
|
||||||
/**
|
/**
|
||||||
@ -16331,31 +16297,11 @@ export type operations = {
|
|||||||
* @description Gets a page of style presets
|
* @description Gets a page of style presets
|
||||||
*/
|
*/
|
||||||
list_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: {
|
responses: {
|
||||||
/** @description Successful Response */
|
/** @description Successful Response */
|
||||||
200: {
|
200: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": components["schemas"]["PaginatedResults_StylePresetRecordDTO_"];
|
"application/json": components["schemas"]["StylePresetRecordDTO"][];
|
||||||
};
|
|
||||||
};
|
|
||||||
/** @description Validation Error */
|
|
||||||
422: {
|
|
||||||
content: {
|
|
||||||
"application/json": components["schemas"]["HTTPValidationError"];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user