import { atom, selector } from 'recoil' import _ from 'lodash' import { HDStrategy, LDMSampler } from '../components/Settings/HDSettingBlock' import { ToastState } from '../components/shared/Toast' export enum AIModel { LAMA = 'lama', LDM = 'ldm', ZITS = 'zits', MAT = 'mat', FCF = 'fcf', SD14 = 'sd1.4', CV2 = 'cv2', } export const fileState = atom({ key: 'fileState', default: undefined, }) export interface Rect { x: number y: number width: number height: number } interface AppState { disableShortCuts: boolean isInpainting: boolean } export const appState = atom({ key: 'appState', default: { disableShortCuts: false, isInpainting: false, }, }) export const propmtState = atom({ key: 'promptState', 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 croperState = atom({ key: 'croperState', default: { x: 0, y: 0, width: 512, height: 512, }, }) export const croperX = selector({ key: 'croperX', get: ({ get }) => get(croperState).x, set: ({ get, set }, newValue: any) => { const rect = get(croperState) set(croperState, { ...rect, x: newValue }) }, }) export const croperY = selector({ key: 'croperY', get: ({ get }) => get(croperState).y, set: ({ get, set }, newValue: any) => { const rect = get(croperState) set(croperState, { ...rect, y: newValue }) }, }) export const croperHeight = selector({ key: 'croperHeight', get: ({ get }) => get(croperState).height, set: ({ get, set }, newValue: any) => { const rect = get(croperState) set(croperState, { ...rect, height: newValue }) }, }) export const croperWidth = selector({ key: 'croperWidth', get: ({ get }) => get(croperState).width, set: ({ get, set }, newValue: any) => { const rect = get(croperState) set(croperState, { ...rect, width: newValue }) }, }) interface ToastAtomState { open: boolean desc: string state: ToastState duration: number } export const toastState = atom({ key: 'toastState', default: { open: false, desc: '', state: 'default', duration: 3000, }, }) export const shortcutsState = atom({ 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 downloadMask: boolean graduallyInpainting: boolean runInpaintingManually: boolean model: AIModel hdSettings: ModelsHDSettings // For LDM ldmSteps: number ldmSampler: LDMSampler // For ZITS zitsWireframe: boolean // For SD sdMaskBlur: number sdMode: SDMode sdStrength: number sdSteps: number sdGuidanceScale: number sdSampler: SDSampler sdSeed: number sdSeedFixed: boolean // true: use sdSeed, false: random generate seed on backend sdNumSamples: number // For OpenCV2 cv2Radius: number cv2Flag: CV2Flag } const defaultHDSettings: ModelsHDSettings = { [AIModel.LAMA]: { hdStrategy: HDStrategy.RESIZE, hdStrategyResizeLimit: 2048, hdStrategyCropTrigerSize: 2048, hdStrategyCropMargin: 128, enabled: true, }, [AIModel.LDM]: { hdStrategy: HDStrategy.CROP, hdStrategyResizeLimit: 1080, hdStrategyCropTrigerSize: 1080, hdStrategyCropMargin: 128, enabled: true, }, [AIModel.ZITS]: { hdStrategy: HDStrategy.CROP, hdStrategyResizeLimit: 1024, hdStrategyCropTrigerSize: 1024, hdStrategyCropMargin: 128, enabled: true, }, [AIModel.MAT]: { hdStrategy: HDStrategy.CROP, hdStrategyResizeLimit: 1024, hdStrategyCropTrigerSize: 512, hdStrategyCropMargin: 128, enabled: true, }, [AIModel.FCF]: { hdStrategy: HDStrategy.CROP, hdStrategyResizeLimit: 512, hdStrategyCropTrigerSize: 512, hdStrategyCropMargin: 128, enabled: false, }, [AIModel.SD14]: { hdStrategy: HDStrategy.ORIGINAL, hdStrategyResizeLimit: 768, hdStrategyCropTrigerSize: 512, hdStrategyCropMargin: 128, enabled: true, }, [AIModel.CV2]: { hdStrategy: HDStrategy.RESIZE, hdStrategyResizeLimit: 1080, hdStrategyCropTrigerSize: 512, hdStrategyCropMargin: 128, enabled: true, }, } export enum SDSampler { ddim = 'ddim', pndm = 'pndm', klms = 'k_lms', } export enum SDMode { text2img = 'text2img', img2img = 'img2img', inpainting = 'inpainting', } export const settingStateDefault: Settings = { show: false, showCroper: false, downloadMask: false, graduallyInpainting: true, runInpaintingManually: false, model: AIModel.LAMA, hdSettings: defaultHDSettings, ldmSteps: 25, ldmSampler: LDMSampler.plms, zitsWireframe: true, // SD sdMaskBlur: 5, sdMode: SDMode.inpainting, sdStrength: 0.75, sdSteps: 50, sdGuidanceScale: 7.5, sdSampler: SDSampler.klms, sdSeed: 42, sdSeedFixed: true, sdNumSamples: 1, // CV2 cv2Radius: 5, cv2Flag: CV2Flag.INPAINT_NS, } const localStorageEffect = (key: string) => ({ setSelf, onSet }: any) => { const savedValue = localStorage.getItem(key) if (savedValue != null) { const storageSettings = JSON.parse(savedValue) storageSettings.show = false const restored = _.merge( _.cloneDeep(settingStateDefault), storageSettings ) setSelf(restored) } onSet((newValue: Settings, val: string, isReset: boolean) => isReset ? localStorage.removeItem(key) : localStorage.setItem(key, JSON.stringify(newValue)) ) } const ROOT_STATE_KEY = 'settingsState3' // Each atom can reference an array of these atom effect functions which are called in priority order when the atom is initialized // https://recoiljs.org/docs/guides/atom-effects/#local-storage-persistence export const settingState = atom({ key: ROOT_STATE_KEY, default: settingStateDefault, effects: [localStorageEffect(ROOT_STATE_KEY)], }) export const seedState = selector({ key: 'seed', get: ({ get }) => { const settings = get(settingState) return settings.sdSeed }, set: ({ get, set }, newValue: any) => { const settings = get(settingState) set(settingState, { ...settings, sdSeed: newValue }) }, }) export const hdSettingsState = selector({ key: 'hdSettings', get: ({ get }) => { const settings = get(settingState) return settings.hdSettings[settings.model] }, set: ({ get, set }, newValue: any) => { const settings = get(settingState) const hdSettings = settings.hdSettings[settings.model] const newHDSettings = { ...hdSettings, ...newValue } set(settingState, { ...settings, hdSettings: { ...settings.hdSettings, [settings.model]: newHDSettings }, }) }, }) export const isSDState = selector({ key: 'isSD', get: ({ get }) => { const settings = get(settingState) return settings.model === AIModel.SD14 }, }) export const runManuallyState = selector({ key: 'runManuallyState', get: ({ get }) => { const settings = get(settingState) const isSD = get(isSDState) return settings.runInpaintingManually || isSD }, })