From 46629ca51b54891ce64bafdd5a1372d1d8d19797 Mon Sep 17 00:00:00 2001 From: Towsty Date: Wed, 2 Sep 2026 21:37:12 -0500 Subject: [PATCH] Filter image LoRAs by flux- / krea- filename so each engine only lists its own. Co-authored-by: Cursor --- pages/index.vue | 21 +++++++++++---------- server/utils/loras.ts | 25 ++++++++++++++----------- utils/loras.ts | 35 +++++++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/pages/index.vue b/pages/index.vue index 904d063..046dd1b 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -837,7 +837,7 @@ @insert-trigger="insertLoraTrigger($event)" @update-trigger="saveLoraTrigger" /> -

Flux LoRAs stay on the Flux engine. Switch back to restore that chain.

+

Krea only lists krea LoRAs. Flux files stay on the Flux engine.

@@ -2215,8 +2215,8 @@ import { filterLorasForUse, insertActivationInShotScript, insertActivationPhrase, - isKleinImageLora, - kleinLoraOnKreaMessage, + imageLoraEngineMismatchMessage, + imageLoraEngineOf, loraIdentityKey, loraStacksEqual, normalizeLoraStack, @@ -6813,7 +6813,7 @@ function setV2Engine(engine: ImageV2Engine) { v2Steps.value = IMAGE_V2_KREA_STEPS v2Cfg.value = IMAGE_V2_KREA_CFG v2Turbo.value = false - if (previousStack.some(item => isKleinImageLora(item.name))) { + if (previousStack.some(item => imageLoraEngineOf(item.name) === 'flux')) { toast('Flux LoRAs stay on the Flux engine. Switch back to restore that chain.') } if (v2Mode.value === 'edit') v2Denoise.value = IMAGE_V2_KREA_EDIT_DENOISE @@ -6971,12 +6971,13 @@ async function editImageV2() { filterLoraStackForStudio(imageV2LoraStack.value, ltxEnabled.value), v2Engine.value ) - if (v2Engine.value === 'krea') { - const klein = imageV2LoraStack.value.find(item => isKleinImageLora(item.name)) - if (klein) { - toast(kleinLoraOnKreaMessage(klein.name)) - return - } + const wrongEngine = imageV2LoraStack.value.find((item) => { + const tagged = imageLoraEngineOf(item.name) + return tagged != null && tagged !== v2Engine.value + }) + if (wrongEngine) { + toast(imageLoraEngineMismatchMessage(wrongEngine.name, v2Engine.value)) + return } body.append('loraStack', JSON.stringify(v2Stack)) const downloadName = clipFileName(clipName.value.trim() || autoOutputName.value) diff --git a/server/utils/loras.ts b/server/utils/loras.ts index 221b092..e82e6a7 100644 --- a/server/utils/loras.ts +++ b/server/utils/loras.ts @@ -4,9 +4,9 @@ import { XAIGEN_LORA_MESSAGE, MINIMAX_TURBO_LORA, filterLorasForStudio, - isKleinImageLora, + imageLoraEngineMismatchMessage, + imageLoraEngineOf, isXaigenOnlyLora, - kleinLoraOnKreaMessage, loraIdentityKey, normalizeLoraName, normalizeLoraStack, @@ -400,10 +400,12 @@ function linkRef(value: unknown): [string, number] | null { export function assertImageV2LoraStack(stack: unknown, engine: 'flux' | 'krea') { const items = normalizeLoraStack(stack) - if (engine !== 'krea') return items - const klein = items.find(item => isKleinImageLora(item.name)) - if (klein) { - throw createError({ statusCode: 400, statusMessage: kleinLoraOnKreaMessage(klein.name) }) + const wrong = items.find((item) => { + const tagged = imageLoraEngineOf(item.name) + return tagged != null && tagged !== engine + }) + if (wrong) { + throw createError({ statusCode: 400, statusMessage: imageLoraEngineMismatchMessage(wrong.name, engine) }) } return items } @@ -451,11 +453,12 @@ export function applyImageV2UserLoras( })) .filter(item => item.name && (xaigen || !isXaigenOnlyLora(item.name)) && (item.strengthModel !== 0 || item.strengthClip !== 0)) - if (engine === 'krea') { - const klein = items.find(item => isKleinImageLora(item.name)) - if (klein) { - throw createError({ statusCode: 400, statusMessage: kleinLoraOnKreaMessage(klein.name) }) - } + const wrong = items.find((item) => { + const tagged = imageLoraEngineOf(item.name) + return tagged != null && tagged !== engine + }) + if (wrong) { + throw createError({ statusCode: 400, statusMessage: imageLoraEngineMismatchMessage(wrong.name, engine) }) } const guiders = modelConsumers(graph) diff --git a/utils/loras.ts b/utils/loras.ts index 60639b9..1c4cc50 100644 --- a/utils/loras.ts +++ b/utils/loras.ts @@ -229,19 +229,38 @@ export function isKleinImageLora(name: string) { return /flux-?2-klein|klein_snofs|flux2-klein-9b-consistency|(^|[^a-z0-9])klein([^a-z0-9]|$)/i.test(id) } +/** + * Image engine from the filename: `xaigen-flux-…` / `flux-…` vs `xaigen-krea-…` / `krea-…`. + * Klein / SNOFS files without that prefix still count as Flux or Krea. + */ +export function imageLoraEngineOf(name: string): 'flux' | 'krea' | null { + const id = loraIdentityKey(name) + if (/snofs_krea|(^|[_-])krea([_-]|$)/i.test(id) || /^krea\d*[-_.]/i.test(id)) return 'krea' + if (isKleinImageLora(name) || /flux-?2-klein|flux2-klein/i.test(id) || /^flux\d*[-_.]/i.test(id)) return 'flux' + return null +} + +export function loraMatchesImageEngine(name: string, engine: 'flux' | 'krea') { + const tagged = imageLoraEngineOf(name) + return !tagged || tagged === engine +} + export function filterLorasForImageEngine(names: string[], engine: 'flux' | 'krea') { - if (engine !== 'krea') return names - return names.filter(name => !isKleinImageLora(name)) + return names.filter(name => loraMatchesImageEngine(name, engine)) } export function filterLoraStackForImageEngine(stack: unknown, engine: 'flux' | 'krea') { - const items = normalizeLoraStack(stack) - if (engine !== 'krea') return items - return items.filter(item => !isKleinImageLora(item.name)) + return normalizeLoraStack(stack).filter(item => loraMatchesImageEngine(item.name, engine)) +} + +export function imageLoraEngineMismatchMessage(name: string, engine: 'flux' | 'krea') { + const other = engine === 'krea' ? 'Flux' : 'Krea' + const current = engine === 'krea' ? 'Krea' : 'Flux' + return `${loraDisplayName(name)} is a ${other} LoRA and cannot be used with ${current}.` } export function kleinLoraOnKreaMessage(name: string) { - return `${loraDisplayName(name)} is a Flux LoRA and cannot be used with Krea.` + return imageLoraEngineMismatchMessage(name, 'krea') } export type LoraUse = 'minimax' | 'ltx' | 'flux' | 'krea' @@ -256,9 +275,9 @@ export function isSystemGraphLora(name: string) { /** Filename hints. `null` means the LoRA can appear in any picker. */ export function inferLoraUse(name: string): LoraUse[] | null { + const imageEngine = imageLoraEngineOf(name) + if (imageEngine) return [imageEngine] const id = loraIdentityKey(name) - if (/snofs_krea|(^|[_-])krea([_-]|$)/i.test(id)) return ['krea'] - if (isKleinImageLora(name) || /flux-?2-klein|flux2-klein/i.test(id)) return ['flux'] if (/(^|[_-])ltx([_-]|$)|ltx-2/i.test(id)) return ['ltx'] if (/minimax|h3_fl2v|fl2v_turbo/i.test(id)) return ['minimax'] return null