From cfcc923688bcca287beb212149a99c109bf7468a Mon Sep 17 00:00:00 2001 From: bymyself Date: Wed, 9 Apr 2025 09:52:06 -0700 Subject: [PATCH] migrate manager menu items --- src/composables/useCoreCommands.ts | 80 +++++++++++++++++++++++++++++- src/constants/coreMenuCommands.ts | 10 ++++ src/constants/coreSettings.ts | 7 +++ src/locales/en/main.json | 4 +- src/schemas/apiSchema.ts | 3 +- src/scripts/api.ts | 52 +++++++++++++++++++ 6 files changed, 153 insertions(+), 3 deletions(-) diff --git a/src/composables/useCoreCommands.ts b/src/composables/useCoreCommands.ts index 62039684cf..03613ae329 100644 --- a/src/composables/useCoreCommands.ts +++ b/src/composables/useCoreCommands.ts @@ -17,7 +17,7 @@ import { app } from '@/scripts/app' import { useDialogService } from '@/services/dialogService' import { useLitegraphService } from '@/services/litegraphService' import { useWorkflowService } from '@/services/workflowService' -import type { ComfyCommand } from '@/stores/commandStore' +import { type ComfyCommand, useCommandStore } from '@/stores/commandStore' import { useTitleEditorStore } from '@/stores/graphStore' import { useQueueSettingsStore, useQueueStore } from '@/stores/queueStore' import { useSettingStore } from '@/stores/settingStore' @@ -718,6 +718,84 @@ export function useCoreCommands(): ComfyCommand[] { label: 'Move Selected Nodes Right', versionAdded: moveSelectedNodesVersionAdded, function: () => moveSelectedNodes(([x, y], gridSize) => [x + gridSize, y]) + }, + { + id: 'Comfy.Manager.CustomNodesManager.ShowLegacyCustomNodesMenu', + icon: 'pi pi-bars', + label: 'Custom Nodes (Legacy)', + versionAdded: '1.16.4', + function: () => { + try { + void useCommandStore().execute( + 'Comfy.Manager.CustomNodesManager.ToggleVisibility' + ) + } catch (error) { + useToastStore().add({ + severity: 'error', + summary: t('g.error'), + detail: t('manager.legacyMenuNotAvailable'), + life: 3000 + }) + } + } + }, + { + id: 'Comfy.Manager.ShowLegacyManagerMenu', + icon: 'mdi mdi-puzzle', + label: 'Manager Menu (Legacy)', + versionAdded: '1.16.4', + function: () => { + try { + void useCommandStore().execute('Comfy.Manager.Menu.ToggleVisibility') + } catch (error) { + useToastStore().add({ + severity: 'error', + summary: t('g.error'), + detail: t('manager.legacyMenuNotAvailable'), + life: 3000 + }) + } + } + }, + { + id: 'Comfy.Memory.UnloadModels', + icon: 'mdi mdi-vacuum-outline', + label: 'Unload Models', + versionAdded: '1.16.4', + function: async () => { + if (!useSettingStore().get('Comfy.Memory.AllowManualUnload')) { + useToastStore().add({ + severity: 'error', + summary: t('g.error'), + detail: t('g.commandProhibited', { + command: 'Comfy.Memory.UnloadModels' + }), + life: 3000 + }) + return + } + await api.freeMemory({ freeExecutionCache: false }) + } + }, + { + id: 'Comfy.Memory.UnloadModelsAndExecutionCache', + icon: 'mdi mdi-vacuum-outline', + label: 'Unload Models and Execution Cache', + versionAdded: '1.16.4', + function: async () => { + if (!useSettingStore().get('Comfy.Memory.AllowManualUnload')) { + useToastStore().add({ + severity: 'error', + summary: t('g.error'), + detail: t('g.commandProhibited', { + command: 'Comfy.Memory.UnloadModelsAndExecutionCache' + }), + life: 3000 + }) + return + } + await api.freeMemory({ freeExecutionCache: true }) + } } ] diff --git a/src/constants/coreMenuCommands.ts b/src/constants/coreMenuCommands.ts index 9173366a4f..9fc0561ebb 100644 --- a/src/constants/coreMenuCommands.ts +++ b/src/constants/coreMenuCommands.ts @@ -14,6 +14,16 @@ export const CORE_MENU_COMMANDS = [ [['Edit'], ['Comfy.RefreshNodeDefinitions']], [['Edit'], ['Comfy.ClearWorkflow']], [['Edit'], ['Comfy.OpenClipspace']], + [ + ['Manager'], + [ + 'Comfy.Manager.ShowLegacyManagerMenu', + 'Comfy.Manager.CustomNodesManager.ShowLegacyCustomNodesMenu', + 'Comfy.Manager.CustomNodesManager.ShowCustomNodesMenu', + 'Comfy.Memory.UnloadModels', + 'Comfy.Memory.UnloadModelsAndExecutionCache' + ] + ], [ ['Help'], [ diff --git a/src/constants/coreSettings.ts b/src/constants/coreSettings.ts index ec554f632b..44a943bd60 100644 --- a/src/constants/coreSettings.ts +++ b/src/constants/coreSettings.ts @@ -847,5 +847,12 @@ export const CORE_SETTINGS: SettingParams[] = [ type: 'boolean', defaultValue: false, versionAdded: '1.19.1' + }, + { + id: 'Comfy.Memory.AllowManualUnload', + name: 'Allow manual unload of models and execution cache via user command', + type: 'hidden', + defaultValue: true, + versionAdded: '1.18.0' } ] diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 10192509c9..a950708c6a 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -123,10 +123,12 @@ "copy": "Copy", "imageUrl": "Image URL", "clear": "Clear", - "copyURL": "Copy URL" + "copyURL": "Copy URL", + "commandProhibited": "Command {command} is prohibited. Contact an administrator for more information." }, "manager": { "title": "Custom Nodes Manager", + "legacyMenuNotAvailable": "Legacy manager menu is not available in this version of ComfyUI. Please use the new manager menu instead.", "failed": "Failed ({count})", "noNodesFound": "No nodes found", "noNodesFoundDescription": "The pack's nodes either could not be parsed, or the pack is a frontend extension only and doesn't have any nodes.", diff --git a/src/schemas/apiSchema.ts b/src/schemas/apiSchema.ts index c93e3e4511..a2aa83b87f 100644 --- a/src/schemas/apiSchema.ts +++ b/src/schemas/apiSchema.ts @@ -477,7 +477,8 @@ const zSettings = z.object({ 'main.sub.setting.name': z.any(), 'single.setting': z.any(), 'LiteGraph.Node.DefaultPadding': z.boolean(), - 'LiteGraph.Pointer.TrackpadGestures': z.boolean() + 'LiteGraph.Pointer.TrackpadGestures': z.boolean(), + 'Comfy.Memory.AllowManualUnload': z.boolean() }) export type EmbeddingsResponse = z.infer diff --git a/src/scripts/api.ts b/src/scripts/api.ts index 85316a74a7..09d7227da2 100644 --- a/src/scripts/api.ts +++ b/src/scripts/api.ts @@ -35,6 +35,7 @@ import { type ComfyNodeDef, validateComfyNodeDef } from '@/schemas/nodeDefSchema' +import { useToastStore } from '@/stores/toastStore' import { WorkflowTemplates } from '@/types/workflowTemplateTypes' interface QueuePromptRequestBody { @@ -956,6 +957,57 @@ export class ComfyApi extends EventTarget { async getCustomNodesI18n(): Promise> { return (await axios.get(this.apiURL('/i18n'))).data } + + /** + * Frees memory by unloading models and optionally freeing execution cache + * @param {Object} options - The options object + * @param {boolean} options.freeExecutionCache - If true, also frees execution cache + */ + async freeMemory(options: { freeExecutionCache: boolean }) { + try { + let mode = '' + if (options.freeExecutionCache) { + mode = '{"unload_models": true, "free_memory": true}' + } else { + mode = '{"unload_models": true}' + } + + const res = await this.fetchApi(`/free`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: mode + }) + + if (res.status === 200) { + if (options.freeExecutionCache) { + useToastStore().add({ + severity: 'success', + summary: 'Models and Execution Cache have been cleared.', + life: 3000 + }) + } else { + useToastStore().add({ + severity: 'success', + summary: 'Models have been unloaded.', + life: 3000 + }) + } + } else { + useToastStore().add({ + severity: 'error', + summary: + 'Unloading of models failed. Installed ComfyUI may be an outdated version.', + life: 5000 + }) + } + } catch (error) { + useToastStore().add({ + severity: 'error', + summary: 'An error occurred while trying to unload models.', + life: 5000 + }) + } + } } export const api = new ComfyApi()