This commit is contained in:
Qing
2023-11-23 16:28:47 +08:00
parent 7463a599a9
commit 43433c50eb
21 changed files with 776 additions and 524 deletions

2
web_app/src/lib/const.ts Normal file
View File

@@ -0,0 +1,2 @@
export const ACCENT_COLOR = "#ffcc00bb"
export const DEFAULT_BRUSH_SIZE = 40

118
web_app/src/lib/states.ts Normal file
View File

@@ -0,0 +1,118 @@
import { create, StoreApi, UseBoundStore } from "zustand"
import { persist } from "zustand/middleware"
import { immer } from "zustand/middleware/immer"
import { SortBy, SortOrder } from "./types"
import { DEFAULT_BRUSH_SIZE } from "./const"
type FileManagerState = {
sortBy: SortBy
sortOrder: SortOrder
layout: "rows" | "masonry"
searchText: string
}
type AppState = {
file: File | null
imageHeight: number
imageWidth: number
brushSize: number
brushSizeScale: number
isInpainting: boolean
isInteractiveSeg: boolean // 是否正处于 sam 状态
isInteractiveSegRunning: boolean
interactiveSegClicks: number[][]
prompt: string
fileManagerState: FileManagerState
}
type AppAction = {
setFile: (file: File) => void
setIsInpainting: (newValue: boolean) => void
setBrushSize: (newValue: number) => void
setImageSize: (width: number, height: number) => void
setFileManagerSortBy: (newValue: SortBy) => void
setFileManagerSortOrder: (newValue: SortOrder) => void
setFileManagerLayout: (
newValue: AppState["fileManagerState"]["layout"]
) => void
setFileManagerSearchText: (newValue: string) => void
setPrompt: (newValue: string) => void
}
export const useStore = create<AppState & AppAction>()(
immer(
persist(
(set, get) => ({
file: null,
imageHeight: 0,
imageWidth: 0,
brushSize: DEFAULT_BRUSH_SIZE,
brushSizeScale: 1,
isInpainting: false,
isInteractiveSeg: false,
isInteractiveSegRunning: false,
interactiveSegClicks: [],
prompt: "",
fileManagerState: {
sortBy: SortBy.CTIME,
sortOrder: SortOrder.DESCENDING,
layout: "masonry",
searchText: "",
},
setIsInpainting: (newValue: boolean) =>
set((state: AppState) => {
state.isInpainting = newValue
}),
setFile: (file: File) =>
set((state: AppState) => {
// TODO: 清空各种状态
state.file = file
}),
setBrushSize: (newValue: number) =>
set((state: AppState) => {
state.brushSize = newValue
}),
setImageSize: (width: number, height: number) => {
// 根据图片尺寸调整 brushSize 的 scale
set((state: AppState) => {
state.imageWidth = width
state.imageHeight = height
state.brushSizeScale = Math.max(Math.min(width, height), 512) / 512
})
},
setPrompt: (newValue: string) =>
set((state: AppState) => {
state.prompt = newValue
}),
setFileManagerSortBy: (newValue: SortBy) =>
set((state: AppState) => {
state.fileManagerState.sortBy = newValue
}),
setFileManagerSortOrder: (newValue: SortOrder) =>
set((state: AppState) => {
state.fileManagerState.sortOrder = newValue
}),
setFileManagerLayout: (newValue: "rows" | "masonry") =>
set((state: AppState) => {
state.fileManagerState.layout = newValue
}),
setFileManagerSearchText: (newValue: string) =>
set((state: AppState) => {
state.fileManagerState.searchText = newValue
}),
}),
{
name: "ZUSTAND_STATE", // name of the item in the storage (must be unique)
partialize: (state) =>
Object.fromEntries(
Object.entries(state).filter(([key]) =>
["fileManagerState", "prompt"].includes(key)
)
),
}
)
)
)

View File

@@ -1,23 +1,6 @@
import { atom, selector } from "recoil"
import _ from "lodash"
export enum HDStrategy {
ORIGINAL = "Original",
RESIZE = "Resize",
CROP = "Crop",
}
export enum LDMSampler {
ddim = "ddim",
plms = "plms",
}
function strEnum<T extends string>(o: Array<T>): { [K in T]: K } {
return o.reduce((res, key) => {
res[key] = key
return res
}, Object.create(null))
}
import { CV2Flag, HDStrategy, LDMSampler, ModelsHDSettings } from "./types"
export enum AIModel {
LAMA = "lama",
@@ -75,18 +58,12 @@ export interface Rect {
}
interface AppState {
file: File | undefined
imageHeight: number
imageWidth: number
disableShortCuts: boolean
isInpainting: boolean
isDisableModelSwitch: boolean
isEnableAutoSaving: boolean
isInteractiveSeg: boolean
isInteractiveSegRunning: boolean
interactiveSegClicks: number[][]
enableFileManager: boolean
brushSize: number
isControlNet: boolean
controlNetMethod: string
plugins: string[]
@@ -96,18 +73,12 @@ interface AppState {
export const appState = atom<AppState>({
key: "appState",
default: {
file: undefined,
imageHeight: 0,
imageWidth: 0,
disableShortCuts: false,
isInpainting: false,
isDisableModelSwitch: false,
isEnableAutoSaving: false,
isInteractiveSeg: false,
isInteractiveSegRunning: false,
interactiveSegClicks: [],
enableFileManager: false,
brushSize: 40,
isControlNet: false,
controlNetMethod: ControlNetMethod.canny,
plugins: [],
@@ -115,28 +86,11 @@ export const appState = atom<AppState>({
},
})
export const propmtState = atom<string>({
key: "promptState",
default: "",
})
export const negativePropmtState = atom<string>({
key: "negativePromptState",
default: "",
})
export const isInpaintingState = selector({
key: "isInpainting",
get: ({ get }) => {
const app = get(appState)
return app.isInpainting
},
set: ({ get, set }, newValue: any) => {
const app = get(appState)
set(appState, { ...app, isInpainting: newValue })
},
})
export const isPluginRunningState = selector({
key: "isPluginRunningState",
get: ({ get }) => {
@@ -175,42 +129,6 @@ export const serverConfigState = selector({
},
})
export const brushSizeState = selector({
key: "brushSizeState",
get: ({ get }) => {
const app = get(appState)
return app.brushSize
},
set: ({ get, set }, newValue: any) => {
const app = get(appState)
set(appState, { ...app, brushSize: newValue })
},
})
export const imageHeightState = selector({
key: "imageHeightState",
get: ({ get }) => {
const app = get(appState)
return app.imageHeight
},
set: ({ get, set }, newValue: any) => {
const app = get(appState)
set(appState, { ...app, imageHeight: newValue })
},
})
export const imageWidthState = selector({
key: "imageWidthState",
get: ({ get }) => {
const app = get(appState)
return app.imageWidth
},
set: ({ get, set }, newValue: any) => {
const app = get(appState)
set(appState, { ...app, imageWidth: newValue })
},
})
export const enableFileManagerState = selector({
key: "enableFileManagerState",
get: ({ get }) => {
@@ -223,30 +141,6 @@ export const enableFileManagerState = selector({
},
})
export const fileState = selector({
key: "fileState",
get: ({ get }) => {
const app = get(appState)
return app.file
},
set: ({ get, set }, newValue: any) => {
const app = get(appState)
set(appState, {
...app,
file: newValue,
interactiveSegClicks: [],
isInteractiveSeg: false,
isInteractiveSegRunning: false,
})
const setting = get(settingState)
set(settingState, {
...setting,
sdScale: 100,
})
},
})
export const isInteractiveSegState = selector({
key: "isInteractiveSegState",
get: ({ get }) => {
@@ -275,9 +169,7 @@ export const isProcessingState = selector({
key: "isProcessingState",
get: ({ get }) => {
const app = get(appState)
return (
app.isInteractiveSegRunning || app.isPluginRunning || app.isInpainting
)
return app.isInteractiveSegRunning || app.isPluginRunning
},
})
@@ -339,20 +231,6 @@ export const croperState = atom<Rect>({
},
})
export const SIDE_PANEL_TAB = strEnum(["inpainting", "outpainting"])
export type SIDE_PANEL_TAB_TYPE = keyof typeof SIDE_PANEL_TAB
export interface SidePanelState {
tab: SIDE_PANEL_TAB_TYPE
}
export const sidePanelTabState = atom<SidePanelState>({
key: "sidePanelTabState",
default: {
tab: SIDE_PANEL_TAB.inpainting,
},
})
export const croperX = selector({
key: "croperX",
get: ({ get }) => get(croperState).x,
@@ -435,43 +313,6 @@ export const extenderWidth = selector({
},
})
interface ToastAtomState {
open: boolean
desc: string
state: ToastState
duration: number
}
export const toastState = atom<ToastAtomState>({
key: "toastState",
default: {
open: false,
desc: "",
state: "default",
duration: 3000,
},
})
export const shortcutsState = atom<boolean>({
key: "shortcutsState",
default: false,
})
export interface HDSettings {
hdStrategy: HDStrategy
hdStrategyResizeLimit: number
hdStrategyCropTrigerSize: number
hdStrategyCropMargin: number
enabled: boolean
}
type ModelsHDSettings = { [key in AIModel]: HDSettings }
export enum CV2Flag {
INPAINT_NS = "INPAINT_NS",
INPAINT_TELEA = "INPAINT_TELEA",
}
export interface Settings {
show: boolean
showCroper: boolean
@@ -490,7 +331,6 @@ export interface Settings {
// For SD
sdMaskBlur: number
sdMode: SDMode
sdStrength: number
sdSteps: number
sdGuidanceScale: number
@@ -656,7 +496,6 @@ export const settingStateDefault: Settings = {
// SD
sdMaskBlur: 5,
sdMode: SDMode.inpainting,
sdStrength: 0.75,
sdSteps: 50,
sdGuidanceScale: 7.5,
@@ -819,70 +658,3 @@ export const isDiffusionModelsState = selector({
return isSD || isPaintByExample || isPix2Pix
},
})
export enum SortBy {
NAME = "name",
CTIME = "ctime",
MTIME = "mtime",
}
export enum SortOrder {
DESCENDING = "desc",
ASCENDING = "asc",
}
interface FileManagerState {
sortBy: SortBy
sortOrder: SortOrder
layout: "rows" | "masonry"
searchText: string
}
const FILE_MANAGER_STATE_KEY = "fileManagerState"
export const fileManagerState = atom<FileManagerState>({
key: FILE_MANAGER_STATE_KEY,
default: {
sortBy: SortBy.CTIME,
sortOrder: SortOrder.DESCENDING,
layout: "masonry",
searchText: "",
},
effects: [localStorageEffect(FILE_MANAGER_STATE_KEY)],
})
export const fileManagerSortBy = selector({
key: "fileManagerSortBy",
get: ({ get }) => get(fileManagerState).sortBy,
set: ({ get, set }, newValue: any) => {
const val = get(fileManagerState)
set(fileManagerState, { ...val, sortBy: newValue })
},
})
export const fileManagerSortOrder = selector({
key: "fileManagerSortOrder",
get: ({ get }) => get(fileManagerState).sortOrder,
set: ({ get, set }, newValue: any) => {
const val = get(fileManagerState)
set(fileManagerState, { ...val, sortOrder: newValue })
},
})
export const fileManagerLayout = selector({
key: "fileManagerLayout",
get: ({ get }) => get(fileManagerState).layout,
set: ({ get, set }, newValue: any) => {
const val = get(fileManagerState)
set(fileManagerState, { ...val, layout: newValue })
},
})
export const fileManagerSearchText = selector({
key: "fileManagerSearchText",
get: ({ get }) => get(fileManagerState).searchText,
set: ({ get, set }, newValue: any) => {
const val = get(fileManagerState)
set(fileManagerState, { ...val, searchText: newValue })
},
})

View File

@@ -6,3 +6,40 @@ export enum PluginName {
RestoreFormer = "RestoreFormer",
InteractiveSeg = "InteractiveSeg",
}
export enum SortBy {
NAME = "name",
CTIME = "ctime",
MTIME = "mtime",
}
export enum SortOrder {
DESCENDING = "desc",
ASCENDING = "asc",
}
export enum HDStrategy {
ORIGINAL = "Original",
RESIZE = "Resize",
CROP = "Crop",
}
export enum LDMSampler {
ddim = "ddim",
plms = "plms",
}
export enum CV2Flag {
INPAINT_NS = "INPAINT_NS",
INPAINT_TELEA = "INPAINT_TELEA",
}
export interface HDSettings {
hdStrategy: HDStrategy
hdStrategyResizeLimit: number
hdStrategyCropTrigerSize: number
hdStrategyCropMargin: number
enabled: boolean
}
export type ModelsHDSettings = { [key in AIModel]: HDSettings }