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