diff --git a/tests/test_downloads_tab_workflow_route.mjs b/tests/test_downloads_tab_workflow_route.mjs index 207df58..156b350 100644 --- a/tests/test_downloads_tab_workflow_route.mjs +++ b/tests/test_downloads_tab_workflow_route.mjs @@ -18,6 +18,7 @@ import { toResolverContextModel, } from '../web/resolver/node_context_menu.js'; import { startSplitterDrag } from '../web/resolver/utils/splitter_drag.js'; +import { baseModelAliasMethods } from '../web/resolver/search/base_model_alias_methods.js'; import { getCustomNodeModelAdapter, getCustomNodeModelCategory, @@ -3007,10 +3008,12 @@ test('native Xet progress bar uses live network bytes against the known final fi }); test('base model alias resolves FLUX KREA as Flux.1 Krea', () => { - const normalizeBaseModelToken = eval(`(${extractMethod(searchPanelMethodsSource, 'normalizeBaseModelToken')})`); - const getBaseModelTokenVariants = eval(`(${extractMethod(searchPanelMethodsSource, 'getBaseModelTokenVariants')})`); - const resolveBaseModelAliasExact = eval(`(${extractMethod(searchPanelMethodsSource, 'resolveBaseModelAliasExact')})`); - const resolveBaseModelAlias = eval(`(${extractMethod(searchPanelMethodsSource, 'resolveBaseModelAlias')})`); + const { + normalizeBaseModelToken, + getBaseModelTokenVariants, + resolveBaseModelAliasExact, + resolveBaseModelAlias, + } = baseModelAliasMethods; const dialog = { baseModels: { base_models: [ @@ -3126,10 +3129,12 @@ test('auto base model keeps workflow path context when a delayed search result d }); test('base model path mapping ignores conflicting full-path base model', () => { - const normalizeBaseModelToken = eval(`(${extractMethod(searchPanelMethodsSource, 'normalizeBaseModelToken')})`); - const getBaseModelTokenVariants = eval(`(${extractMethod(searchPanelMethodsSource, 'getBaseModelTokenVariants')})`); - const resolveBaseModelAliasExact = eval(`(${extractMethod(searchPanelMethodsSource, 'resolveBaseModelAliasExact')})`); - const resolveBaseModelAlias = eval(`(${extractMethod(searchPanelMethodsSource, 'resolveBaseModelAlias')})`); + const { + normalizeBaseModelToken, + getBaseModelTokenVariants, + resolveBaseModelAliasExact, + resolveBaseModelAlias, + } = baseModelAliasMethods; const isBaseModelPathMappingCompatible = eval(`(${extractMethod(downloadTargetMethodsSource, 'isBaseModelPathMappingCompatible')})`); const resolveBaseModelPathMapping = eval(`(${extractMethod(downloadTargetMethodsSource, 'resolveBaseModelPathMapping')})`); const dialog = { diff --git a/web/resolver/resolver_dialog.js b/web/resolver/resolver_dialog.js index dcd43d2..9818fee 100644 --- a/web/resolver/resolver_dialog.js +++ b/web/resolver/resolver_dialog.js @@ -13,6 +13,7 @@ import { tabsLoadedMethods } from "./views/tabs_loaded_methods.js"; import { downloadTargetMethods } from "./search/download_target_methods.js"; import { searchPanelMethods } from "./search/search_panel.js"; import { searchSourceMethods } from "./search/search_source_methods.js"; +import { baseModelAliasMethods } from "./search/base_model_alias_methods.js"; import { queueMethods } from "./actions/queue_methods.js"; import { queueStorageMethods } from "./actions/queue_storage_methods.js"; import { downloadProgressMethods } from "./actions/download_progress_methods.js"; @@ -335,6 +336,7 @@ function applyDialogMethods(...sources) { applyDialogMethods( searchSourceMethods, + baseModelAliasMethods, searchPanelMethods, modelInfoMethods, renderFormatMethods, diff --git a/web/resolver/search/base_model_alias_methods.js b/web/resolver/search/base_model_alias_methods.js new file mode 100644 index 0000000..e7cf992 --- /dev/null +++ b/web/resolver/search/base_model_alias_methods.js @@ -0,0 +1,102 @@ +export const baseModelAliasMethods = { + getBaseModelAliases() { + const baseModelsList = this.baseModels?.base_models; + if (Array.isArray(baseModelsList) && baseModelsList.length > 0) { + return baseModelsList.map(m => ({ value: m.name, aliases: m.aliases || [] })); + } + // Fallback to hardcoded list + return [ + { value: 'Z-Image', aliases: ['zimage', 'z image', 'z-image', 'z_image', 'zImageTurbo', 'z image turbo'] }, + { value: 'Pony', aliases: ['pony', 'ponyxl', 'pony diffusion', 'pony realism'] }, + { value: 'Illustrious', aliases: ['illustrious', 'illustriousxl', 'illustrious xl'] }, + { value: 'SDXL 1.0', aliases: ['sdxl', 'sdxl10', 'sdxl 1.0', 'stable diffusion xl'] }, + { value: 'SD 1.5', aliases: ['sd15', 'sd 1.5', 'sd1.5', 'stable diffusion 1.5'] }, + { value: 'Flux.1 D', aliases: ['flux', 'flux1', 'flux.1', 'flux dev', 'flux.1 d', 'flux1d'] }, + { value: 'Flux.1 S', aliases: ['flux schnell', 'flux.1 s', 'flux1s'] }, + { value: 'Qwen Image', aliases: ['qwen image', 'qwenimage', 'qwen-image'] }, + { value: 'Hunyuan 1', aliases: ['hunyuan', 'hunyuan1'] }, + { value: 'WAN Video', aliases: ['wan', 'wan video', 'wanvideo'] }, + { value: 'NoobAI', aliases: ['noobai', 'noob ai'] }, + { value: 'HiDream', aliases: ['hidream', 'hi dream'] } + ]; + }, + + normalizeBaseModelToken(value = '') { + return String(value || '') + .toLowerCase() + .replace(/[^a-z0-9]+/g, ''); + }, + + getBaseModelTokenVariants(value = '') { + const text = String(value || '').trim(); + if (!text) return new Set(); + const variants = [ + text, + text.replace(/(\d+)(?:[\s._-]+0)+(?!\d)/g, '$1') + ]; + const normalized = this.normalizeBaseModelToken(text); + if (normalized.startsWith('flux1') && normalized.length > 'flux1'.length) { + variants.push(`flux${normalized.slice('flux1'.length)}`); + } + return new Set( + variants + .map(item => this.normalizeBaseModelToken(item)) + .filter(Boolean) + ); + }, + + resolveBaseModelAliasExact(value = '') { + const tokens = this.getBaseModelTokenVariants(value); + if (!tokens.size) return ''; + for (const entry of this.getBaseModelAliases()) { + const aliases = [entry.value, ...(entry.aliases || [])]; + if (aliases.some(alias => { + const aliasTokens = this.getBaseModelTokenVariants(alias); + return [...aliasTokens].some(aliasToken => tokens.has(aliasToken)); + })) { + return entry.value; + } + } + return ''; + }, + + resolveBaseModelAlias(value = '') { + const tokens = this.getBaseModelTokenVariants(value); + if (!tokens.size) return ''; + const exact = this.resolveBaseModelAliasExact(value); + if (exact) return exact; + + for (const entry of this.getBaseModelAliases()) { + const aliases = [entry.value, ...(entry.aliases || [])]; + if (aliases.some(alias => { + const aliasTokens = this.getBaseModelTokenVariants(alias); + return [...aliasTokens].some(aliasToken => ( + aliasToken && [...tokens].some(token => ( + aliasToken.includes(token) || token.includes(aliasToken) + )) + )); + })) { + return entry.value; + } + } + return ''; + }, + + resolveBaseModelAliasFromPath(path = '') { + const text = String(path || '').trim(); + if (!text) return ''; + + const parts = text + .split(/[\\/]+/) + .map(part => part.trim()) + .filter(Boolean); + const directoryParts = parts.filter(part => !this.hasModelExtension(part)); + + for (const part of directoryParts) { + const exact = this.resolveBaseModelAliasExact(part); + if (exact) return exact; + } + + return ''; + }, +}; diff --git a/web/resolver/search/search_panel.js b/web/resolver/search/search_panel.js index f18fdfc..25a1bbc 100644 --- a/web/resolver/search/search_panel.js +++ b/web/resolver/search/search_panel.js @@ -88,85 +88,6 @@ export const searchPanelMethods = { ]; }, - normalizeBaseModelToken(value = '') { - return String(value || '') - .toLowerCase() - .replace(/[^a-z0-9]+/g, ''); - }, - - getBaseModelTokenVariants(value = '') { - const text = String(value || '').trim(); - if (!text) return new Set(); - const variants = [ - text, - text.replace(/(\d+)(?:[\s._-]+0)+(?!\d)/g, '$1') - ]; - const normalized = this.normalizeBaseModelToken(text); - if (normalized.startsWith('flux1') && normalized.length > 'flux1'.length) { - variants.push(`flux${normalized.slice('flux1'.length)}`); - } - return new Set( - variants - .map(item => this.normalizeBaseModelToken(item)) - .filter(Boolean) - ); - }, - - resolveBaseModelAliasExact(value = '') { - const tokens = this.getBaseModelTokenVariants(value); - if (!tokens.size) return ''; - for (const entry of this.getBaseModelAliases()) { - const aliases = [entry.value, ...(entry.aliases || [])]; - if (aliases.some(alias => { - const aliasTokens = this.getBaseModelTokenVariants(alias); - return [...aliasTokens].some(aliasToken => tokens.has(aliasToken)); - })) { - return entry.value; - } - } - return ''; - }, - - resolveBaseModelAlias(value = '') { - const tokens = this.getBaseModelTokenVariants(value); - if (!tokens.size) return ''; - const exact = this.resolveBaseModelAliasExact(value); - if (exact) return exact; - - for (const entry of this.getBaseModelAliases()) { - const aliases = [entry.value, ...(entry.aliases || [])]; - if (aliases.some(alias => { - const aliasTokens = this.getBaseModelTokenVariants(alias); - return [...aliasTokens].some(aliasToken => ( - aliasToken && [...tokens].some(token => ( - aliasToken.includes(token) || token.includes(aliasToken) - )) - )); - })) { - return entry.value; - } - } - return ''; - }, - - resolveBaseModelAliasFromPath(path = '') { - const text = String(path || '').trim(); - if (!text) return ''; - - const parts = text - .split(/[\\/]+/) - .map(part => part.trim()) - .filter(Boolean); - const directoryParts = parts.filter(part => !this.hasModelExtension(part)); - - for (const part of directoryParts) { - const exact = this.resolveBaseModelAliasExact(part); - if (exact) return exact; - } - - return ''; - }, - getMissingLocalBaseModel(missing = {}, minConfidence = 70) { const bestMatch = this.getBestLocalMatch?.(missing, minConfidence); const matchModel = bestMatch?.model || {}; @@ -367,28 +288,6 @@ export const searchPanelMethods = { return this.getMissingAutoBaseModelInfo(missing).message; }, - getBaseModelAliases() { - const baseModelsList = this.baseModels?.base_models; - if (Array.isArray(baseModelsList) && baseModelsList.length > 0) { - return baseModelsList.map(m => ({ value: m.name, aliases: m.aliases || [] })); - } - // Fallback to hardcoded list - return [ - { value: 'Z-Image', aliases: ['zimage', 'z image', 'z-image', 'z_image', 'zImageTurbo', 'z image turbo'] }, - { value: 'Pony', aliases: ['pony', 'ponyxl', 'pony diffusion', 'pony realism'] }, - { value: 'Illustrious', aliases: ['illustrious', 'illustriousxl', 'illustrious xl'] }, - { value: 'SDXL 1.0', aliases: ['sdxl', 'sdxl10', 'sdxl 1.0', 'stable diffusion xl'] }, - { value: 'SD 1.5', aliases: ['sd15', 'sd 1.5', 'sd1.5', 'stable diffusion 1.5'] }, - { value: 'Flux.1 D', aliases: ['flux', 'flux1', 'flux.1', 'flux dev', 'flux.1 d', 'flux1d'] }, - { value: 'Flux.1 S', aliases: ['flux schnell', 'flux.1 s', 'flux1s'] }, - { value: 'Qwen Image', aliases: ['qwen image', 'qwenimage', 'qwen-image'] }, - { value: 'Hunyuan 1', aliases: ['hunyuan', 'hunyuan1'] }, - { value: 'WAN Video', aliases: ['wan', 'wan video', 'wanvideo'] }, - { value: 'NoobAI', aliases: ['noobai', 'noob ai'] }, - { value: 'HiDream', aliases: ['hidream', 'hi dream'] } - ]; - }, - getWorkflowModelReferenceText() { const workflow = this.getCurrentWorkflow?.(); if (!workflow) return '';