diff --git a/src/components/graph/GraphCanvas.vue b/src/components/graph/GraphCanvas.vue index 5ae1cd628..95a4a80f8 100644 --- a/src/components/graph/GraphCanvas.vue +++ b/src/components/graph/GraphCanvas.vue @@ -171,7 +171,7 @@ onMounted(async () => { (widget) => widget.name === provider.key ) if (widget) { - widget.value = model.name + widget.value = model.file_name } } } diff --git a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue index c2060e876..bd4ac69b0 100644 --- a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue +++ b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue @@ -84,22 +84,26 @@ const root: ComputedRef = computed(() => { if (searchQuery.value) { const search = searchQuery.value.toLocaleLowerCase() modelList = modelList.filter((model: ComfyModelDef) => { - return model.name.toLocaleLowerCase().includes(search) + return model.file_name.toLocaleLowerCase().includes(search) }) } const tree: TreeNode = buildTree(modelList, (model: ComfyModelDef) => { - return [model.directory, ...model.name.replaceAll('\\', '/').split('/')] + return [ + model.directory, + ...model.file_name.replaceAll('\\', '/').split('/') + ] }) return tree }) const renderedRoot = computed>(() => { + const nameFormat = settingStore.get('Comfy.ModelLibrary.NameFormat') const fillNodeInfo = (node: TreeNode): TreeExplorerNode => { const children = node.children?.map(fillNodeInfo) const model: ComfyModelDef | null = node.leaf && node.data ? node.data : null if (model?.is_fake_object) { - if (model.name === '(No Content)') { + if (model.file_name === '(No Content)') { return { key: node.key, label: t('noContent'), @@ -126,7 +130,11 @@ const renderedRoot = computed>(() => { return { key: node.key, - label: model ? model.title : node.label, + label: model + ? nameFormat === 'title' + ? model.title + : model.simplified_file_name + : node.label, leaf: node.leaf, data: node.data, getIcon: (node: TreeExplorerNode) => { @@ -144,9 +152,9 @@ const renderedRoot = computed>(() => { if (node.children?.length === 1) { const onlyChild = node.children[0] if (onlyChild.data?.is_fake_object) { - if (onlyChild.data.name === '(No Content)') { + if (onlyChild.data.file_name === '(No Content)') { return '0' - } else if (onlyChild.data.name === 'Loading') { + } else if (onlyChild.data.file_name === 'Loading') { return '?' } } @@ -169,7 +177,7 @@ const renderedRoot = computed>(() => { (widget) => widget.name === provider.key ) if (widget) { - widget.value = model.name + widget.value = model.file_name } } } diff --git a/src/components/sidebar/tabs/modelLibrary/ModelPreview.vue b/src/components/sidebar/tabs/modelLibrary/ModelPreview.vue index 5b02843c8..212eb6af8 100644 --- a/src/components/sidebar/tabs/modelLibrary/ModelPreview.vue +++ b/src/components/sidebar/tabs/modelLibrary/ModelPreview.vue @@ -4,6 +4,9 @@ {{ modelDef.title }}
+
+ {{ modelDef.file_name }} +
Architecture: {{ modelDef.architecture_id }} @@ -75,7 +78,9 @@ const modelDef = props.modelDef } .model_preview_top_container { text-align: center; + line-height: 0.5; } +.model_preview_filename, .model_preview_author, .model_preview_architecture { display: inline-block; diff --git a/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue b/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue index 1cc333492..42465815a 100644 --- a/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue +++ b/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue @@ -90,6 +90,7 @@ const showPreview = computed(() => { !modelDef.value.is_fake_object && modelDef.value.has_loaded_metadata && (modelDef.value.author || + modelDef.value.simplified_file_name != modelDef.value.title || modelDef.value.description || modelDef.value.usage_hint || modelDef.value.trigger_phrase || diff --git a/src/stores/coreSettings.ts b/src/stores/coreSettings.ts index 6b82fc961..dbdda1053 100644 --- a/src/stores/coreSettings.ts +++ b/src/stores/coreSettings.ts @@ -249,6 +249,15 @@ export const CORE_SETTINGS: SettingParams[] = [ type: 'boolean', defaultValue: false }, + { + id: 'Comfy.ModelLibrary.NameFormat', + name: 'What name to display in the model library tree view', + tooltip: + 'Select "filename" to render a simplified view of the raw filename (without directory or ".safetensors" extension) in the model list. Select "title" to display the configurable model metadata title.', + type: 'combo', + options: ['filename', 'title'], + defaultValue: 'title' + }, { id: 'Comfy.Locale', name: 'Locale', diff --git a/src/stores/modelStore.ts b/src/stores/modelStore.ts index 5b76c54d6..e4c1a0373 100644 --- a/src/stores/modelStore.ts +++ b/src/stores/modelStore.ts @@ -19,9 +19,11 @@ function _findInMetadata(metadata: any, ...keys: string[]): string | null { /** Defines and holds metadata for a model */ export class ComfyModelDef { /** Proper filename of the model */ - name: string = '' + file_name: string = '' /** Directory containing the model, eg 'checkpoints' */ directory: string = '' + /** Simplified copy of name, used as a default title. Excludes the directory and the '.safetensors' file extension */ + simplified_file_name: string = '' /** Title / display name of the model, sometimes same as the name but not always */ title: string = '' /** Metadata: architecture ID for the model, such as 'stable-diffusion-xl-v1-base' */ @@ -48,11 +50,15 @@ export class ComfyModelDef { is_fake_object: boolean = false constructor(name: string, directory: string) { - this.name = name - this.title = name.replaceAll('\\', '/').split('/').pop() - if (this.title.endsWith('.safetensors')) { - this.title = this.title.slice(0, -'.safetensors'.length) + this.file_name = name + this.simplified_file_name = name.replaceAll('\\', '/').split('/').pop() + if (this.simplified_file_name.endsWith('.safetensors')) { + this.simplified_file_name = this.simplified_file_name.slice( + 0, + -'.safetensors'.length + ) } + this.title = this.simplified_file_name this.directory = directory } @@ -63,7 +69,7 @@ export class ComfyModelDef { } this.is_load_requested = true try { - const metadata = await api.viewMetadata(this.directory, this.name) + const metadata = await api.viewMetadata(this.directory, this.file_name) if (!metadata) { return } @@ -105,7 +111,7 @@ export class ComfyModelDef { this.tags = tagsCommaSeparated.split(',').map((tag) => tag.trim()) this.has_loaded_metadata = true } catch (error) { - console.error('Error loading model metadata', this.name, this, error) + console.error('Error loading model metadata', this.file_name, this, error) } } } diff --git a/tests-ui/tests/store/modelStore.test.ts b/tests-ui/tests/store/modelStore.test.ts index 8d6d5c2ae..9f8bd068a 100644 --- a/tests-ui/tests/store/modelStore.test.ts +++ b/tests-ui/tests/store/modelStore.test.ts @@ -69,7 +69,7 @@ describe('useModelStore', () => { const folderStore = await store.getModelsInFolderCached('checkpoints') const model = folderStore.models['noinfo.safetensors'] await model.load() - expect(model.name).toBe('noinfo.safetensors') + expect(model.file_name).toBe('noinfo.safetensors') expect(model.title).toBe('noinfo') expect(model.architecture_id).toBe('') expect(model.author).toBe('')