diff --git a/WebUI/src/assets/js/store/imageGeneration.ts b/WebUI/src/assets/js/store/imageGeneration.ts index c62344f9..e0a3d81d 100644 --- a/WebUI/src/assets/js/store/imageGeneration.ts +++ b/WebUI/src/assets/js/store/imageGeneration.ts @@ -116,6 +116,13 @@ const ComfyBooleanInputSchema = z.object({ }); export type ComfyBooleanInput = z.infer; +const ComfyDynamicInputSchema = z.discriminatedUnion('type', [ + ComfyNumberInputSchema, + ComfyImageInputSchema, + ComfyStringInputSchema, + ComfyBooleanInputSchema, +]); +type ComfyDynamicInput = z.infer; const ComfyUiWorkflowSchema = z.object({ name: z.string(), backend: z.literal('comfyui'), @@ -126,12 +133,7 @@ const ComfyUiWorkflowSchema = z.object({ tags: z.array(z.string()), requiredModels: z.array(z.string()).optional(), requirements: z.array(WorkflowRequirementSchema), - inputs: z.array(z.discriminatedUnion('type',[ - ComfyNumberInputSchema, - ComfyImageInputSchema, - ComfyStringInputSchema, - ComfyBooleanInputSchema - ])), + inputs: z.array(ComfyDynamicInputSchema), outputs: z.array(z.object({ name: z.string(), type: z.literal('image') @@ -153,6 +155,7 @@ export type Workflow = z.infer; const globalDefaultSettings = { + seed: -1, width: 512, height: 512, inferenceSteps: 20, @@ -201,6 +204,7 @@ export const useImageGeneration = defineStore("imageGeneration", () => { modifiableSettings: [ 'resolution', 'seed', + 'inferenceSteps', 'negativePrompt', 'batchSize', 'imagePreview', @@ -226,12 +230,12 @@ export const useImageGeneration = defineStore("imageGeneration", () => { 'imageModel', 'inpaintModel', 'guidanceScale', - 'inferenceSteps', 'scheduler', ], modifiableSettings: [ 'resolution', 'seed', + 'inferenceSteps', 'negativePrompt', 'batchSize', 'imagePreview', @@ -258,13 +262,13 @@ export const useImageGeneration = defineStore("imageGeneration", () => { 'imageModel', 'inpaintModel', 'guidanceScale', - 'inferenceSteps', 'scheduler', 'lora' ], modifiableSettings: [ 'resolution', 'seed', + 'inferenceSteps', 'negativePrompt', 'batchSize', 'imagePreview', @@ -291,12 +295,12 @@ export const useImageGeneration = defineStore("imageGeneration", () => { 'imageModel', 'inpaintModel', 'guidanceScale', - 'inferenceSteps', 'scheduler', ], modifiableSettings: [ 'resolution', 'seed', + 'inferenceSteps', 'negativePrompt', 'batchSize', 'imagePreview', @@ -323,12 +327,12 @@ export const useImageGeneration = defineStore("imageGeneration", () => { 'imageModel', 'inpaintModel', 'guidanceScale', - 'inferenceSteps', 'scheduler', ], modifiableSettings: [ 'resolution', 'seed', + 'inferenceSteps', 'negativePrompt', 'batchSize', 'imagePreview', @@ -355,12 +359,12 @@ export const useImageGeneration = defineStore("imageGeneration", () => { 'imageModel', 'inpaintModel', 'guidanceScale', - 'inferenceSteps', 'scheduler', ], modifiableSettings: [ 'resolution', 'seed', + 'inferenceSteps', 'negativePrompt', 'batchSize', 'imagePreview', @@ -424,6 +428,7 @@ export const useImageGeneration = defineStore("imageGeneration", () => { imagePreview.value = generalDefaultSettings.imagePreview; safeCheck.value = generalDefaultSettings.safeCheck; settingsPerWorkflow.value[activeWorkflowName.value ?? ''] = undefined; + comfyInputsPerWorkflow.value[activeWorkflowName.value ?? ''] = undefined; loadSettingsForActiveWorkflow(); } // model specific settings @@ -444,25 +449,68 @@ export const useImageGeneration = defineStore("imageGeneration", () => { [width.value, height.value] = newValue.split('x').map(Number); } }) - - const settings = { inferenceSteps, width, height, resolution, batchSize, negativePrompt, lora, scheduler, guidanceScale, imageModel, inpaintModel }; + + const settings = { seed, inferenceSteps, width, height, resolution, batchSize, negativePrompt, lora, scheduler, guidanceScale, imageModel, inpaintModel }; type ModifiableSettings = keyof typeof settings; const backend = computed({ get() { return activeWorkflow.value.backend; }, set(newValue) { - activeWorkflowName.value = workflows.value.find(w => w.backend === newValue)?.name ?? activeWorkflowName.value; + activeWorkflowName.value = workflows.value + .filter(w => w.backend === newValue) + .find(w => w.name === lastWorkflowPerBackend.value[newValue])?.name ?? workflows.value.find(w => w.backend === newValue)?.name ?? activeWorkflowName.value; } }); + const lastWorkflowPerBackend = ref>({ + comfyui: null, + default: null + }); + + const comfyInputs = computed(() => { + if (activeWorkflow.value.backend !== 'comfyui') return [] + const inputRef = (input: ComfyDynamicInput): NodeInputReference => `${input.nodeTitle}.${input.nodeInput}`; + const savePerWorkflow = (input: ComfyDynamicInput, newValue: ComfyDynamicInput['defaultValue']) => { + if (!activeWorkflowName.value) return; + comfyInputsPerWorkflow.value[activeWorkflowName.value] = { + ...comfyInputsPerWorkflow.value[activeWorkflowName.value], + [inputRef(input)]: newValue + } + console.log('saving', { nodeTitle: input.nodeTitle, nodeInput: input.nodeInput, newValue }); + } + const getSavedOrDefault = (input: ComfyDynamicInput) => { + if (!activeWorkflowName.value) return input.defaultValue; + const saved = comfyInputsPerWorkflow.value[activeWorkflowName.value]?.[inputRef(input)]; + if (saved) console.log('got saved dynamic input', { nodeTitle: input.nodeTitle, nodeInput: input.nodeInput, saved }); + return saved ?? input.defaultValue; + }; + + return activeWorkflow.value.inputs.map(input => { + const _current = ref(getSavedOrDefault(input)) + + const current = computed({ + get() { + return _current.value; + }, + set(newValue) { + _current.value = newValue; + savePerWorkflow(input, newValue) + } + }) - const comfyInputs = computed(() => activeWorkflow.value.backend === 'comfyui' ? activeWorkflow.value.inputs.map(input => ({ ...input, current: ref(input.defaultValue) })) : []); + return { ...input, current } + }) + }); - const settingsPerWorkflow = ref>({}); + type WorkflowName = string; + type NodeInputReference = string; // nodeTitle.nodeInput + const comfyInputsPerWorkflow = ref | undefined>>({}); + const settingsPerWorkflow = ref>({}); const isModifiable = (settingName: ModifiableSettings) => activeWorkflow.value.modifiableSettings.includes(settingName); watch([activeWorkflowName, workflows], () => { + setTimeout(() => lastWorkflowPerBackend.value[activeWorkflow.value.backend] = activeWorkflowName.value) loadSettingsForActiveWorkflow(); }, {}); @@ -484,6 +532,7 @@ export const useImageGeneration = defineStore("imageGeneration", () => { console.log('saving', { settingName, value: settings[settingName].value }); } } + saveToSettingsPerWorkflow('seed'); saveToSettingsPerWorkflow('inferenceSteps'); saveToSettingsPerWorkflow('width'); saveToSettingsPerWorkflow('height'); @@ -516,6 +565,7 @@ export const useImageGeneration = defineStore("imageGeneration", () => { settings[settingName].value = saved ?? activeWorkflow.value?.defaultSettings?.[settingName] ?? globalDefaultSettings[settingName]; }; + getSavedOrDefault('seed'); getSavedOrDefault('inferenceSteps'); getSavedOrDefault('width'); getSavedOrDefault('height'); @@ -670,7 +720,9 @@ export const useImageGeneration = defineStore("imageGeneration", () => { batchSize, negativePrompt, settingsPerWorkflow, + comfyInputsPerWorkflow, comfyInputs, + lastWorkflowPerBackend, resetActiveWorkflowSettings, loadWorkflowsFromJson, loadWorkflowsFromIntel, @@ -683,7 +735,7 @@ export const useImageGeneration = defineStore("imageGeneration", () => { }, { persist: { debug: true, - pick: ['backend', 'activeWorkflowName', 'settingsPerWorkflow', 'hdWarningDismissed'] + pick: ['backend', 'activeWorkflowName', 'settingsPerWorkflow', 'comfyInputsPerWorkflow', 'hdWarningDismissed', 'lastWorkflowPerBackend'] } }); diff --git a/WebUI/src/components/SettingsImageComfyDynamic.vue b/WebUI/src/components/SettingsImageComfyDynamic.vue index bc0aab9a..b6ef7533 100644 --- a/WebUI/src/components/SettingsImageComfyDynamic.vue +++ b/WebUI/src/components/SettingsImageComfyDynamic.vue @@ -1,5 +1,5 @@ diff --git a/WebUI/src/components/ui/loadImage/LoadImage.vue b/WebUI/src/components/ui/loadImage/LoadImage.vue new file mode 100644 index 00000000..02b72c29 --- /dev/null +++ b/WebUI/src/components/ui/loadImage/LoadImage.vue @@ -0,0 +1,69 @@ + + + diff --git a/WebUI/src/components/ui/loadImage/index.ts b/WebUI/src/components/ui/loadImage/index.ts new file mode 100644 index 00000000..62fb309e --- /dev/null +++ b/WebUI/src/components/ui/loadImage/index.ts @@ -0,0 +1 @@ +export { default as LoadImage } from './LoadImage.vue'