Filter image LoRAs by flux- / krea- filename so each engine only lists its own.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+11
-10
@@ -837,7 +837,7 @@
|
|||||||
@insert-trigger="insertLoraTrigger($event)"
|
@insert-trigger="insertLoraTrigger($event)"
|
||||||
@update-trigger="saveLoraTrigger"
|
@update-trigger="saveLoraTrigger"
|
||||||
/>
|
/>
|
||||||
<p v-if="v2Engine === 'krea'" class="mt-1 text-[11px] text-zinc-500">Flux LoRAs stay on the Flux engine. Switch back to restore that chain.</p>
|
<p v-if="v2Engine === 'krea'" class="mt-1 text-[11px] text-zinc-500">Krea only lists krea LoRAs. Flux files stay on the Flux engine.</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<AspectRatioPick :model-value="aspect" heading="Aspect ratio" :options="imageAspects" @update:model-value="setImageAspect" />
|
<AspectRatioPick :model-value="aspect" heading="Aspect ratio" :options="imageAspects" @update:model-value="setImageAspect" />
|
||||||
@@ -2215,8 +2215,8 @@ import {
|
|||||||
filterLorasForUse,
|
filterLorasForUse,
|
||||||
insertActivationInShotScript,
|
insertActivationInShotScript,
|
||||||
insertActivationPhrase,
|
insertActivationPhrase,
|
||||||
isKleinImageLora,
|
imageLoraEngineMismatchMessage,
|
||||||
kleinLoraOnKreaMessage,
|
imageLoraEngineOf,
|
||||||
loraIdentityKey,
|
loraIdentityKey,
|
||||||
loraStacksEqual,
|
loraStacksEqual,
|
||||||
normalizeLoraStack,
|
normalizeLoraStack,
|
||||||
@@ -6813,7 +6813,7 @@ function setV2Engine(engine: ImageV2Engine) {
|
|||||||
v2Steps.value = IMAGE_V2_KREA_STEPS
|
v2Steps.value = IMAGE_V2_KREA_STEPS
|
||||||
v2Cfg.value = IMAGE_V2_KREA_CFG
|
v2Cfg.value = IMAGE_V2_KREA_CFG
|
||||||
v2Turbo.value = false
|
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.')
|
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
|
if (v2Mode.value === 'edit') v2Denoise.value = IMAGE_V2_KREA_EDIT_DENOISE
|
||||||
@@ -6971,12 +6971,13 @@ async function editImageV2() {
|
|||||||
filterLoraStackForStudio(imageV2LoraStack.value, ltxEnabled.value),
|
filterLoraStackForStudio(imageV2LoraStack.value, ltxEnabled.value),
|
||||||
v2Engine.value
|
v2Engine.value
|
||||||
)
|
)
|
||||||
if (v2Engine.value === 'krea') {
|
const wrongEngine = imageV2LoraStack.value.find((item) => {
|
||||||
const klein = imageV2LoraStack.value.find(item => isKleinImageLora(item.name))
|
const tagged = imageLoraEngineOf(item.name)
|
||||||
if (klein) {
|
return tagged != null && tagged !== v2Engine.value
|
||||||
toast(kleinLoraOnKreaMessage(klein.name))
|
})
|
||||||
return
|
if (wrongEngine) {
|
||||||
}
|
toast(imageLoraEngineMismatchMessage(wrongEngine.name, v2Engine.value))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
body.append('loraStack', JSON.stringify(v2Stack))
|
body.append('loraStack', JSON.stringify(v2Stack))
|
||||||
const downloadName = clipFileName(clipName.value.trim() || autoOutputName.value)
|
const downloadName = clipFileName(clipName.value.trim() || autoOutputName.value)
|
||||||
|
|||||||
+14
-11
@@ -4,9 +4,9 @@ import {
|
|||||||
XAIGEN_LORA_MESSAGE,
|
XAIGEN_LORA_MESSAGE,
|
||||||
MINIMAX_TURBO_LORA,
|
MINIMAX_TURBO_LORA,
|
||||||
filterLorasForStudio,
|
filterLorasForStudio,
|
||||||
isKleinImageLora,
|
imageLoraEngineMismatchMessage,
|
||||||
|
imageLoraEngineOf,
|
||||||
isXaigenOnlyLora,
|
isXaigenOnlyLora,
|
||||||
kleinLoraOnKreaMessage,
|
|
||||||
loraIdentityKey,
|
loraIdentityKey,
|
||||||
normalizeLoraName,
|
normalizeLoraName,
|
||||||
normalizeLoraStack,
|
normalizeLoraStack,
|
||||||
@@ -400,10 +400,12 @@ function linkRef(value: unknown): [string, number] | null {
|
|||||||
|
|
||||||
export function assertImageV2LoraStack(stack: unknown, engine: 'flux' | 'krea') {
|
export function assertImageV2LoraStack(stack: unknown, engine: 'flux' | 'krea') {
|
||||||
const items = normalizeLoraStack(stack)
|
const items = normalizeLoraStack(stack)
|
||||||
if (engine !== 'krea') return items
|
const wrong = items.find((item) => {
|
||||||
const klein = items.find(item => isKleinImageLora(item.name))
|
const tagged = imageLoraEngineOf(item.name)
|
||||||
if (klein) {
|
return tagged != null && tagged !== engine
|
||||||
throw createError({ statusCode: 400, statusMessage: kleinLoraOnKreaMessage(klein.name) })
|
})
|
||||||
|
if (wrong) {
|
||||||
|
throw createError({ statusCode: 400, statusMessage: imageLoraEngineMismatchMessage(wrong.name, engine) })
|
||||||
}
|
}
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
@@ -451,11 +453,12 @@ export function applyImageV2UserLoras(
|
|||||||
}))
|
}))
|
||||||
.filter(item => item.name && (xaigen || !isXaigenOnlyLora(item.name)) && (item.strengthModel !== 0 || item.strengthClip !== 0))
|
.filter(item => item.name && (xaigen || !isXaigenOnlyLora(item.name)) && (item.strengthModel !== 0 || item.strengthClip !== 0))
|
||||||
|
|
||||||
if (engine === 'krea') {
|
const wrong = items.find((item) => {
|
||||||
const klein = items.find(item => isKleinImageLora(item.name))
|
const tagged = imageLoraEngineOf(item.name)
|
||||||
if (klein) {
|
return tagged != null && tagged !== engine
|
||||||
throw createError({ statusCode: 400, statusMessage: kleinLoraOnKreaMessage(klein.name) })
|
})
|
||||||
}
|
if (wrong) {
|
||||||
|
throw createError({ statusCode: 400, statusMessage: imageLoraEngineMismatchMessage(wrong.name, engine) })
|
||||||
}
|
}
|
||||||
|
|
||||||
const guiders = modelConsumers(graph)
|
const guiders = modelConsumers(graph)
|
||||||
|
|||||||
+27
-8
@@ -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)
|
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') {
|
export function filterLorasForImageEngine(names: string[], engine: 'flux' | 'krea') {
|
||||||
if (engine !== 'krea') return names
|
return names.filter(name => loraMatchesImageEngine(name, engine))
|
||||||
return names.filter(name => !isKleinImageLora(name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function filterLoraStackForImageEngine(stack: unknown, engine: 'flux' | 'krea') {
|
export function filterLoraStackForImageEngine(stack: unknown, engine: 'flux' | 'krea') {
|
||||||
const items = normalizeLoraStack(stack)
|
return normalizeLoraStack(stack).filter(item => loraMatchesImageEngine(item.name, engine))
|
||||||
if (engine !== 'krea') return items
|
}
|
||||||
return items.filter(item => !isKleinImageLora(item.name))
|
|
||||||
|
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) {
|
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'
|
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. */
|
/** Filename hints. `null` means the LoRA can appear in any picker. */
|
||||||
export function inferLoraUse(name: string): LoraUse[] | null {
|
export function inferLoraUse(name: string): LoraUse[] | null {
|
||||||
|
const imageEngine = imageLoraEngineOf(name)
|
||||||
|
if (imageEngine) return [imageEngine]
|
||||||
const id = loraIdentityKey(name)
|
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 (/(^|[_-])ltx([_-]|$)|ltx-2/i.test(id)) return ['ltx']
|
||||||
if (/minimax|h3_fl2v|fl2v_turbo/i.test(id)) return ['minimax']
|
if (/minimax|h3_fl2v|fl2v_turbo/i.test(id)) return ['minimax']
|
||||||
return null
|
return null
|
||||||
|
|||||||
Reference in New Issue
Block a user