Move Concept and Consistency into the Image v2 LoRA chain.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+65
-98
@@ -833,41 +833,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<template v-if="v2ConceptLoraEnabled">
|
||||
<label class="block text-sm">
|
||||
<span class="mb-1 block text-zinc-400">Concept LoRA — Model</span>
|
||||
<input
|
||||
v-model.number="v2SnofsModel"
|
||||
type="number"
|
||||
min="0"
|
||||
max="2"
|
||||
step="0.05"
|
||||
:disabled="v2Engine === 'krea' && !kreaConceptConfigured"
|
||||
class="w-full rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 focus:ring-2 disabled:opacity-50"
|
||||
>
|
||||
</label>
|
||||
<label class="block text-sm">
|
||||
<span class="mb-1 block text-zinc-400">Concept LoRA — CLIP</span>
|
||||
<input
|
||||
v-model.number="v2SnofsClip"
|
||||
type="number"
|
||||
min="0"
|
||||
max="2"
|
||||
step="0.05"
|
||||
:disabled="v2Engine === 'krea' && !kreaConceptConfigured"
|
||||
class="w-full rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 focus:ring-2 disabled:opacity-50"
|
||||
>
|
||||
</label>
|
||||
<p v-if="v2Engine === 'krea' && !kreaConceptConfigured" class="col-span-2 text-xs text-zinc-500">No Krea concept LoRA is configured.</p>
|
||||
</template>
|
||||
<label v-if="v2Mode !== 'generate' && v2Engine !== 'krea'" class="block text-sm">
|
||||
<span class="mb-1 block text-zinc-400">Consistency — Model</span>
|
||||
<input v-model.number="v2ConsistencyModel" type="number" min="0" max="2" step="0.05" class="w-full rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 focus:ring-2">
|
||||
</label>
|
||||
<label v-if="v2Mode !== 'generate' && v2Engine !== 'krea'" class="block text-sm">
|
||||
<span class="mb-1 block text-zinc-400">Consistency — CLIP</span>
|
||||
<input v-model.number="v2ConsistencyClip" type="number" min="0" max="2" step="0.05" class="w-full rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 focus:ring-2">
|
||||
</label>
|
||||
<label class="block text-sm">
|
||||
<span class="mb-1 block text-zinc-400">Steps</span>
|
||||
<input v-model.number="v2Steps" type="number" :min="IMAGE_STEPS_MIN" :max="IMAGE_STEPS_MAX" step="1" :disabled="v2Turbo" class="w-full rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 focus:ring-2 disabled:opacity-50">
|
||||
@@ -2032,8 +1997,7 @@ import {
|
||||
} from '~/utils/libraryGeneration'
|
||||
import {
|
||||
IMAGE_V2_CFG_DEFAULT,
|
||||
IMAGE_V2_CONSISTENCY_CLIP,
|
||||
IMAGE_V2_CONSISTENCY_MODEL,
|
||||
IMAGE_V2_CONSISTENCY_LORA,
|
||||
IMAGE_V2_DENOISE_DEFAULT,
|
||||
IMAGE_V2_DENOISE_MAX,
|
||||
IMAGE_V2_DENOISE_MIN,
|
||||
@@ -2050,13 +2014,16 @@ import {
|
||||
IMAGE_V2_REFINE_FACE_PROMPT,
|
||||
IMAGE_V2_REFINE_HAND,
|
||||
IMAGE_V2_REFINE_HEAVY,
|
||||
IMAGE_V2_SNOFS_CLIP,
|
||||
IMAGE_V2_SNOFS_MODEL,
|
||||
IMAGE_V2_SNOFS_LORA,
|
||||
IMAGE_V2_STEPS_DEFAULT,
|
||||
clampImageV2Denoise,
|
||||
clampImageV2Size,
|
||||
clampImageV2Strength,
|
||||
defaultImageV2LoraStack,
|
||||
isImageV2ConceptLora,
|
||||
isImageV2ConsistencyLora,
|
||||
mergeLegacyImageV2Loras,
|
||||
parseImageV2Engine,
|
||||
upsertImageV2Lora,
|
||||
type ImageV2Engine,
|
||||
type ImageV2GenerateAspect,
|
||||
type ImageV2Mode,
|
||||
@@ -2340,12 +2307,7 @@ const editRefPreview = ref('')
|
||||
const v2Mode = ref<ImageV2Mode>('edit')
|
||||
const v2Engine = ref<ImageV2Engine>('flux')
|
||||
const v2Task = ref<ImageV2Task>('scene')
|
||||
const kreaConceptConfigured = computed(() => Boolean(String(runtimeConfig.public.kreaConceptLora || IMAGE_V2_KREA_CONCEPT_LORA || '').trim()))
|
||||
const v2Negative = ref('')
|
||||
const v2SnofsModel = ref(isXaigenStudio(runtimeConfig.public) ? IMAGE_V2_SNOFS_MODEL : 0)
|
||||
const v2SnofsClip = ref(isXaigenStudio(runtimeConfig.public) ? IMAGE_V2_SNOFS_CLIP : 0)
|
||||
const v2ConsistencyModel = ref(IMAGE_V2_CONSISTENCY_MODEL)
|
||||
const v2ConsistencyClip = ref(IMAGE_V2_CONSISTENCY_CLIP)
|
||||
const v2Steps = ref(IMAGE_V2_STEPS_DEFAULT)
|
||||
const v2Cfg = ref(IMAGE_V2_CFG_DEFAULT)
|
||||
const v2Megapixels = ref(1)
|
||||
@@ -2401,6 +2363,23 @@ const v2ConceptLoraEnabled = computed(() => isXaigenStudio({
|
||||
studio: runtimeConfig.public.studio,
|
||||
instanceName: instanceName.value
|
||||
}))
|
||||
|
||||
function imageV2EngineLoras(stack?: unknown) {
|
||||
return filterLoraStackForImageEngine(
|
||||
filterLoraStackForStudio(stack ?? imageV2LoraStack.value, ltxEnabled.value),
|
||||
v2Engine.value
|
||||
)
|
||||
}
|
||||
|
||||
function seedImageV2LorasIfEmpty() {
|
||||
if (imageV2LoraStack.value.length) return
|
||||
imageV2LoraStack.value = defaultImageV2LoraStack({
|
||||
engine: v2Engine.value,
|
||||
mode: v2Mode.value,
|
||||
xaigen: v2ConceptLoraEnabled.value,
|
||||
kreaConcept: String(runtimeConfig.public.kreaConceptLora || IMAGE_V2_KREA_CONCEPT_LORA || '').trim()
|
||||
})
|
||||
}
|
||||
const folders = ref<LibraryFolder[]>([])
|
||||
const clips = ref<LibraryClip[]>([])
|
||||
const stills = ref<LibraryStill[]>([])
|
||||
@@ -3345,6 +3324,7 @@ onMounted(async () => {
|
||||
videoLoraStack.value = readStoredLoraStack('aigen-video-lora')
|
||||
imageLoraStack.value = readStoredLoraStack('aigen-image-lora')
|
||||
imageV2LoraStack.value = readStoredLoraStack('aigen-image-v2-lora')
|
||||
seedImageV2LorasIfEmpty()
|
||||
globalLocks.value = localStorage.getItem(LOCKS_STORE) || ''
|
||||
try {
|
||||
const savedRefs = JSON.parse(localStorage.getItem(REFS_STORE) || '')
|
||||
@@ -3707,10 +3687,10 @@ function currentPresetSnapshot() {
|
||||
engine: v2Engine.value,
|
||||
task: v2Mode.value === 'compose' ? v2Task.value : v2Mode.value === 'refine' ? 'refine' : v2Mode.value === 'generate' ? 't2i' : 'scene',
|
||||
negative: v2Negative.value,
|
||||
snofsModel: v2ConceptLoraEnabled.value ? clampImageV2Strength(v2SnofsModel.value, IMAGE_V2_SNOFS_MODEL) : 0,
|
||||
snofsClip: v2ConceptLoraEnabled.value ? clampImageV2Strength(v2SnofsClip.value, IMAGE_V2_SNOFS_CLIP) : 0,
|
||||
consistencyModel: v2Mode.value === 'generate' || v2Engine.value === 'krea' ? 0 : clampImageV2Strength(v2ConsistencyModel.value, IMAGE_V2_CONSISTENCY_MODEL),
|
||||
consistencyClip: v2Mode.value === 'generate' || v2Engine.value === 'krea' ? 0 : clampImageV2Strength(v2ConsistencyClip.value, IMAGE_V2_CONSISTENCY_CLIP),
|
||||
snofsModel: imageV2EngineLoras().find(item => isImageV2ConceptLora(item.name))?.strengthModel ?? 0,
|
||||
snofsClip: imageV2EngineLoras().find(item => isImageV2ConceptLora(item.name))?.strengthClip ?? 0,
|
||||
consistencyModel: imageV2EngineLoras().find(item => isImageV2ConsistencyLora(item.name))?.strengthModel ?? 0,
|
||||
consistencyClip: imageV2EngineLoras().find(item => isImageV2ConsistencyLora(item.name))?.strengthClip ?? 0,
|
||||
steps: clampImageSteps(v2Steps.value, v2Engine.value === 'krea' ? IMAGE_V2_KREA_STEPS : IMAGE_V2_STEPS_DEFAULT),
|
||||
cfg: clampImageCfg(v2Cfg.value, v2Engine.value === 'krea' ? IMAGE_V2_KREA_CFG : IMAGE_V2_CFG_DEFAULT),
|
||||
megapixels: v2Mode.value === 'generate' ? undefined : clampImageScaleMegapixels(v2Megapixels.value, 1),
|
||||
@@ -3760,10 +3740,16 @@ function applyGenerationPreset(preset: GenerationPreset) {
|
||||
v2Engine.value = parseImageV2Engine(settings.engine, 'flux')
|
||||
v2Task.value = v2Mode.value === 'compose' ? (settings.task || 'scene') : v2Mode.value === 'refine' ? 'refine' : v2Mode.value === 'generate' ? 't2i' : 'scene'
|
||||
if (typeof settings.negative === 'string') v2Negative.value = settings.negative
|
||||
v2SnofsModel.value = v2ConceptLoraEnabled.value ? clampImageV2Strength(settings.snofsModel, IMAGE_V2_SNOFS_MODEL) : 0
|
||||
v2SnofsClip.value = v2ConceptLoraEnabled.value ? clampImageV2Strength(settings.snofsClip, IMAGE_V2_SNOFS_CLIP) : 0
|
||||
v2ConsistencyModel.value = v2Mode.value === 'generate' || v2Engine.value === 'krea' ? 0 : clampImageV2Strength(settings.consistencyModel, IMAGE_V2_CONSISTENCY_MODEL)
|
||||
v2ConsistencyClip.value = v2Mode.value === 'generate' || v2Engine.value === 'krea' ? 0 : clampImageV2Strength(settings.consistencyClip, IMAGE_V2_CONSISTENCY_CLIP)
|
||||
imageV2LoraStack.value = mergeLegacyImageV2Loras(filterLoraStackForImageEngine(stack, v2Engine.value), {
|
||||
engine: v2Engine.value,
|
||||
mode: v2Mode.value,
|
||||
xaigen: v2ConceptLoraEnabled.value,
|
||||
snofsModel: settings.snofsModel,
|
||||
snofsClip: settings.snofsClip,
|
||||
consistencyModel: settings.consistencyModel,
|
||||
consistencyClip: settings.consistencyClip,
|
||||
kreaConcept: String(runtimeConfig.public.kreaConceptLora || IMAGE_V2_KREA_CONCEPT_LORA || '').trim()
|
||||
})
|
||||
v2Steps.value = clampImageSteps(settings.steps, v2Engine.value === 'krea' ? IMAGE_V2_KREA_STEPS : IMAGE_V2_STEPS_DEFAULT)
|
||||
v2Cfg.value = clampImageCfg(settings.cfg, v2Engine.value === 'krea' ? IMAGE_V2_KREA_CFG : IMAGE_V2_CFG_DEFAULT)
|
||||
v2Megapixels.value = clampImageScaleMegapixels(settings.megapixels, 1)
|
||||
@@ -3774,7 +3760,6 @@ function applyGenerationPreset(preset: GenerationPreset) {
|
||||
v2Width.value = size.width
|
||||
v2Height.value = size.height
|
||||
}
|
||||
imageV2LoraStack.value = filterLoraStackForImageEngine(stack, v2Engine.value)
|
||||
void ensureRefineCanvas()
|
||||
imageV2PresetId.value = preset.id
|
||||
imageV2PresetName.value = preset.name
|
||||
@@ -5044,17 +5029,6 @@ function applyStillSettings(still: LibraryStill) {
|
||||
v2Engine.value = parseImageV2Engine(settings?.engine, 'flux')
|
||||
if (!settings) return
|
||||
if (typeof settings.negative === 'string') v2Negative.value = settings.negative
|
||||
if (v2ConceptLoraEnabled.value) {
|
||||
if (settings.snofsModel != null) v2SnofsModel.value = clampImageV2Strength(settings.snofsModel, IMAGE_V2_SNOFS_MODEL)
|
||||
if (settings.snofsClip != null) v2SnofsClip.value = clampImageV2Strength(settings.snofsClip, IMAGE_V2_SNOFS_CLIP)
|
||||
} else {
|
||||
v2SnofsModel.value = 0
|
||||
v2SnofsClip.value = 0
|
||||
}
|
||||
if (mode !== 'generate' && v2Engine.value !== 'krea') {
|
||||
if (settings.consistencyModel != null) v2ConsistencyModel.value = clampImageV2Strength(settings.consistencyModel, IMAGE_V2_CONSISTENCY_MODEL)
|
||||
if (settings.consistencyClip != null) v2ConsistencyClip.value = clampImageV2Strength(settings.consistencyClip, IMAGE_V2_CONSISTENCY_CLIP)
|
||||
}
|
||||
if (settings.steps != null) v2Steps.value = clampImageSteps(settings.steps, IMAGE_V2_STEPS_DEFAULT)
|
||||
if (settings.cfg != null) v2Cfg.value = clampImageCfg(settings.cfg, IMAGE_V2_CFG_DEFAULT)
|
||||
if (settings.megapixels != null) v2Megapixels.value = clampImageScaleMegapixels(settings.megapixels, 1)
|
||||
@@ -5067,12 +5041,19 @@ function applyStillSettings(still: LibraryStill) {
|
||||
}
|
||||
if (mode === 'compose' && settings.task) v2Task.value = settings.task
|
||||
if (settings.seed != null) seedInput.value = String(Math.round(settings.seed))
|
||||
if (settings.loraStack?.length || settings.loraName) {
|
||||
imageV2LoraStack.value = filterLoraStackForImageEngine(
|
||||
filterLoraStackForStudio(readLoraStack(settings), ltxEnabled.value),
|
||||
v2Engine.value
|
||||
)
|
||||
imageV2LoraStack.value = mergeLegacyImageV2Loras(
|
||||
settings.loraStack?.length || settings.loraName ? readLoraStack(settings) : imageV2LoraStack.value,
|
||||
{
|
||||
engine: v2Engine.value,
|
||||
mode,
|
||||
xaigen: v2ConceptLoraEnabled.value,
|
||||
snofsModel: settings.snofsModel,
|
||||
snofsClip: settings.snofsClip,
|
||||
consistencyModel: settings.consistencyModel,
|
||||
consistencyClip: settings.consistencyClip,
|
||||
kreaConcept: String(runtimeConfig.public.kreaConceptLora || IMAGE_V2_KREA_CONCEPT_LORA || '').trim()
|
||||
}
|
||||
)
|
||||
return
|
||||
}
|
||||
studioMode.value = 'edit'
|
||||
@@ -5663,7 +5644,6 @@ async function editImage() {
|
||||
}
|
||||
|
||||
function setV2Mode(mode: ImageV2Mode) {
|
||||
const previous = v2Mode.value
|
||||
v2Mode.value = mode
|
||||
if (mode === 'edit') v2Task.value = 'scene'
|
||||
if (mode === 'refine') {
|
||||
@@ -5672,11 +5652,6 @@ function setV2Mode(mode: ImageV2Mode) {
|
||||
}
|
||||
if (mode === 'generate') {
|
||||
v2Task.value = 't2i'
|
||||
v2ConsistencyModel.value = 0
|
||||
v2ConsistencyClip.value = 0
|
||||
} else if (previous === 'generate' && v2Engine.value === 'flux' && v2ConsistencyModel.value === 0 && v2ConsistencyClip.value === 0) {
|
||||
v2ConsistencyModel.value = IMAGE_V2_CONSISTENCY_MODEL
|
||||
v2ConsistencyClip.value = IMAGE_V2_CONSISTENCY_CLIP
|
||||
}
|
||||
if (v2Engine.value === 'krea' && mode === 'edit') v2Denoise.value = IMAGE_V2_KREA_EDIT_DENOISE
|
||||
if (v2Engine.value === 'krea' && mode === 'compose') v2Denoise.value = IMAGE_V2_KREA_COMPOSE_DENOISE
|
||||
@@ -5688,14 +5663,11 @@ function setV2Engine(engine: ImageV2Engine) {
|
||||
if (engine === 'krea') {
|
||||
v2Steps.value = IMAGE_V2_KREA_STEPS
|
||||
v2Cfg.value = IMAGE_V2_KREA_CFG
|
||||
v2SnofsModel.value = 0
|
||||
v2SnofsClip.value = 0
|
||||
v2ConsistencyModel.value = 0
|
||||
v2ConsistencyClip.value = 0
|
||||
v2Turbo.value = false
|
||||
const dropped = imageV2LoraStack.value.filter(item => isKleinImageLora(item.name))
|
||||
if (dropped.length) {
|
||||
imageV2LoraStack.value = filterLoraStackForImageEngine(imageV2LoraStack.value, 'krea')
|
||||
seedImageV2LorasIfEmpty()
|
||||
toast(dropped.length === 1
|
||||
? kleinLoraOnKreaMessage(dropped[0].name)
|
||||
: 'Flux LoRAs were removed. They cannot be used with Krea.')
|
||||
@@ -5707,12 +5679,7 @@ function setV2Engine(engine: ImageV2Engine) {
|
||||
if (previous === 'krea') {
|
||||
v2Steps.value = IMAGE_V2_STEPS_DEFAULT
|
||||
v2Cfg.value = IMAGE_V2_CFG_DEFAULT
|
||||
v2SnofsModel.value = v2ConceptLoraEnabled.value ? IMAGE_V2_SNOFS_MODEL : 0
|
||||
v2SnofsClip.value = v2ConceptLoraEnabled.value ? IMAGE_V2_SNOFS_CLIP : 0
|
||||
if (v2Mode.value !== 'generate') {
|
||||
v2ConsistencyModel.value = IMAGE_V2_CONSISTENCY_MODEL
|
||||
v2ConsistencyClip.value = IMAGE_V2_CONSISTENCY_CLIP
|
||||
}
|
||||
seedImageV2LorasIfEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5725,23 +5692,23 @@ function setGenerateSize(aspect: ImageV2GenerateAspect) {
|
||||
function applyRefinePreset(kind: 'face' | 'hand' | 'heavy') {
|
||||
if (kind === 'face') {
|
||||
v2Denoise.value = IMAGE_V2_REFINE_FACE.strength
|
||||
if (v2Engine.value === 'flux') {
|
||||
if (v2ConceptLoraEnabled.value) {
|
||||
v2SnofsModel.value = IMAGE_V2_REFINE_FACE.snofsModel
|
||||
v2SnofsClip.value = IMAGE_V2_REFINE_FACE.snofsClip
|
||||
imageV2LoraStack.value = upsertImageV2Lora(imageV2LoraStack.value, IMAGE_V2_SNOFS_LORA, IMAGE_V2_REFINE_FACE.snofsModel, IMAGE_V2_REFINE_FACE.snofsClip)
|
||||
}
|
||||
imageV2LoraStack.value = upsertImageV2Lora(imageV2LoraStack.value, IMAGE_V2_CONSISTENCY_LORA, IMAGE_V2_REFINE_FACE.consistencyModel, IMAGE_V2_REFINE_FACE.consistencyClip)
|
||||
}
|
||||
v2ConsistencyModel.value = IMAGE_V2_REFINE_FACE.consistencyModel
|
||||
v2ConsistencyClip.value = IMAGE_V2_REFINE_FACE.consistencyClip
|
||||
if (!prompt.value.trim()) prompt.value = IMAGE_V2_REFINE_FACE_PROMPT
|
||||
return
|
||||
}
|
||||
if (kind === 'hand') {
|
||||
v2Denoise.value = IMAGE_V2_REFINE_HAND.strength
|
||||
if (v2Engine.value === 'flux') {
|
||||
if (v2ConceptLoraEnabled.value) {
|
||||
v2SnofsModel.value = IMAGE_V2_REFINE_HAND.snofsModel
|
||||
v2SnofsClip.value = IMAGE_V2_REFINE_HAND.snofsClip
|
||||
imageV2LoraStack.value = upsertImageV2Lora(imageV2LoraStack.value, IMAGE_V2_SNOFS_LORA, IMAGE_V2_REFINE_HAND.snofsModel, IMAGE_V2_REFINE_HAND.snofsClip)
|
||||
}
|
||||
imageV2LoraStack.value = upsertImageV2Lora(imageV2LoraStack.value, IMAGE_V2_CONSISTENCY_LORA, IMAGE_V2_REFINE_HAND.consistencyModel, IMAGE_V2_REFINE_HAND.consistencyClip)
|
||||
}
|
||||
v2ConsistencyModel.value = IMAGE_V2_REFINE_HAND.consistencyModel
|
||||
v2ConsistencyClip.value = IMAGE_V2_REFINE_HAND.consistencyClip
|
||||
return
|
||||
}
|
||||
v2Denoise.value = IMAGE_V2_REFINE_HEAVY.strength
|
||||
@@ -5825,10 +5792,10 @@ async function editImageV2() {
|
||||
body.append('engine', v2Engine.value)
|
||||
body.append('prompt', prompt.value.trim())
|
||||
body.append('negative', v2Negative.value)
|
||||
body.append('snofs_model', String(v2ConceptLoraEnabled.value ? clampImageV2Strength(v2SnofsModel.value, v2Engine.value === 'krea' ? 0 : IMAGE_V2_SNOFS_MODEL) : 0))
|
||||
body.append('snofs_clip', String(v2ConceptLoraEnabled.value ? clampImageV2Strength(v2SnofsClip.value, v2Engine.value === 'krea' ? 0 : IMAGE_V2_SNOFS_CLIP) : 0))
|
||||
body.append('consistency_model', String(v2Mode.value === 'generate' || v2Engine.value === 'krea' ? 0 : clampImageV2Strength(v2ConsistencyModel.value, IMAGE_V2_CONSISTENCY_MODEL)))
|
||||
body.append('consistency_clip', String(v2Mode.value === 'generate' || v2Engine.value === 'krea' ? 0 : clampImageV2Strength(v2ConsistencyClip.value, IMAGE_V2_CONSISTENCY_CLIP)))
|
||||
body.append('snofs_model', String(imageV2EngineLoras().find(item => isImageV2ConceptLora(item.name))?.strengthModel ?? 0))
|
||||
body.append('snofs_clip', String(imageV2EngineLoras().find(item => isImageV2ConceptLora(item.name))?.strengthClip ?? 0))
|
||||
body.append('consistency_model', String(imageV2EngineLoras().find(item => isImageV2ConsistencyLora(item.name))?.strengthModel ?? 0))
|
||||
body.append('consistency_clip', String(imageV2EngineLoras().find(item => isImageV2ConsistencyLora(item.name))?.strengthClip ?? 0))
|
||||
body.append('steps', String(clampImageSteps(v2Steps.value, v2Engine.value === 'krea' ? IMAGE_V2_KREA_STEPS : IMAGE_V2_STEPS_DEFAULT)))
|
||||
body.append('cfg', String(clampImageCfg(v2Cfg.value, v2Engine.value === 'krea' ? IMAGE_V2_KREA_CFG : IMAGE_V2_CFG_DEFAULT)))
|
||||
if (v2Mode.value !== 'generate') body.append('megapixels', String(clampImageScaleMegapixels(v2Megapixels.value, 1)))
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
clampImageV2Strength,
|
||||
composeImageV2Prompt,
|
||||
imageV2WorkflowFile,
|
||||
mergeLegacyImageV2Loras,
|
||||
parseImageV2Engine,
|
||||
type ImageV2Engine,
|
||||
type ImageV2Mode,
|
||||
@@ -401,7 +402,18 @@ function applyKreaConceptLora(graph: WorkflowGraph, loraName: string, model: num
|
||||
}
|
||||
|
||||
function applyKreaConceptIfNeeded(graph: WorkflowGraph, params: ImageV2BuildParams) {
|
||||
const merged = mergeLegacyImageV2Loras(params.loraStack, {
|
||||
engine: 'krea',
|
||||
mode: params.mode,
|
||||
xaigen: isXaigenStudio(),
|
||||
snofsModel: params.snofsModel,
|
||||
snofsClip: params.snofsClip,
|
||||
kreaConcept: params.kreaConceptLora
|
||||
})
|
||||
const conceptName = isXaigenStudio() ? String(params.kreaConceptLora || '').trim() : ''
|
||||
if (conceptName && merged.some(item => loraIdentityKey(item.name) === loraIdentityKey(conceptName))) {
|
||||
return { snofsModel: 0, snofsClip: 0 }
|
||||
}
|
||||
const snofsModel = conceptName ? clampImageV2Strength(params.snofsModel, 0) : 0
|
||||
const snofsClip = conceptName ? clampImageV2Strength(params.snofsClip, 0) : 0
|
||||
if (!conceptName || (snofsModel <= 0 && snofsClip <= 0)) return { snofsModel: 0, snofsClip: 0 }
|
||||
@@ -413,6 +425,19 @@ function applyKreaConceptIfNeeded(graph: WorkflowGraph, params: ImageV2BuildPara
|
||||
return { snofsModel, snofsClip, name: resolved }
|
||||
}
|
||||
|
||||
function imageV2UserStack(params: ImageV2BuildParams, engine: ImageV2Engine) {
|
||||
return mergeLegacyImageV2Loras(params.loraStack, {
|
||||
engine,
|
||||
mode: params.mode,
|
||||
xaigen: isXaigenStudio(),
|
||||
snofsModel: params.snofsModel,
|
||||
snofsClip: params.snofsClip,
|
||||
consistencyModel: params.consistencyModel,
|
||||
consistencyClip: params.consistencyClip,
|
||||
kreaConcept: params.kreaConceptLora
|
||||
})
|
||||
}
|
||||
|
||||
function requireKreaModels(params: ImageV2BuildParams) {
|
||||
if (!params.kreaUnetName || !params.kreaClipName || !params.kreaVaeName) {
|
||||
throw createError({
|
||||
@@ -463,7 +488,7 @@ function buildKreaItiWorkflow(params: ImageV2BuildParams) {
|
||||
setInput(graph, SAVE, 'filename_prefix', params.filenamePrefix || `aigen-v2-krea-${params.mode}`)
|
||||
patchScaleMegapixels(graph, params.megapixels ?? 1)
|
||||
const concept = applyKreaConceptIfNeeded(graph, params)
|
||||
const userLoras = applyImageV2UserLoras(graph, params.loraStack, 'krea')
|
||||
const userLoras = applyImageV2UserLoras(graph, imageV2UserStack(params, 'krea'), 'krea')
|
||||
|
||||
assertImageV2Graph(graph, params.mode, compose ? params.imageBName : undefined, 'krea')
|
||||
const loaders = loadImageNames(graph)
|
||||
@@ -514,7 +539,7 @@ function buildKreaGenerateWorkflow(params: ImageV2BuildParams) {
|
||||
setInput(graph, '15', 'scheduler', 'simple')
|
||||
setInput(graph, SAVE, 'filename_prefix', params.filenamePrefix || 'aigen-v2-krea')
|
||||
const concept = applyKreaConceptIfNeeded(graph, params)
|
||||
const userLoras = applyImageV2UserLoras(graph, params.loraStack, 'krea')
|
||||
const userLoras = applyImageV2UserLoras(graph, imageV2UserStack(params, 'krea'), 'krea')
|
||||
|
||||
assertImageV2Graph(graph, 'generate', undefined, 'krea')
|
||||
const loaders = loadImageNames(graph)
|
||||
@@ -596,22 +621,9 @@ export function buildImageV2Workflow(params: ImageV2BuildParams) {
|
||||
setInput(graph, SAVE, 'filename_prefix', params.filenamePrefix || (generate ? 'aigen-v2-generate' : 'aigen-v2'))
|
||||
if (!generate) patchScaleMegapixels(graph, params.megapixels ?? 1)
|
||||
|
||||
if (conceptAllowed) {
|
||||
setInput(graph, SNOFS, 'lora_name', resolveRequiredLora(IMAGE_V2_SNOFS_LORA, 'SNOFS'))
|
||||
setInput(graph, SNOFS, 'strength_model', snofsModel)
|
||||
setInput(graph, SNOFS, 'strength_clip', snofsClip)
|
||||
} else {
|
||||
bypassLoraToBaseLoaders(graph, SNOFS)
|
||||
}
|
||||
if (generate && consistencyModel <= 0 && consistencyClip <= 0) {
|
||||
if (graph[SNOFS]) bypassLoraNode(graph, CONSISTENCY, SNOFS, SNOFS)
|
||||
else bypassLoraToBaseLoaders(graph, CONSISTENCY)
|
||||
} else {
|
||||
setInput(graph, CONSISTENCY, 'lora_name', resolveRequiredLora(IMAGE_V2_CONSISTENCY_LORA, 'Consistency'))
|
||||
setInput(graph, CONSISTENCY, 'strength_model', consistencyModel)
|
||||
setInput(graph, CONSISTENCY, 'strength_clip', consistencyClip)
|
||||
}
|
||||
const userLoras = applyImageV2UserLoras(graph, params.loraStack, 'flux')
|
||||
if (graph[CONSISTENCY]) bypassLoraToBaseLoaders(graph, CONSISTENCY)
|
||||
if (graph[SNOFS]) bypassLoraToBaseLoaders(graph, SNOFS)
|
||||
const userLoras = applyImageV2UserLoras(graph, imageV2UserStack(params, 'flux'), 'flux')
|
||||
|
||||
assertImageV2Graph(graph, params.mode, generate || refine ? undefined : params.imageBName, engine)
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
import {
|
||||
filterLoraStackForImageEngine,
|
||||
loraIdentityKey,
|
||||
makeLoraStackItem,
|
||||
normalizeLoraStack,
|
||||
type LoraStackItem
|
||||
} from '~/utils/loras'
|
||||
|
||||
export const IMAGE_V2_MODES = ['edit', 'compose', 'refine', 'generate'] as const
|
||||
export const IMAGE_V2_TASKS = ['scene', 'identity', 'outfit', 'face_lock', 'refine', 't2i'] as const
|
||||
export const IMAGE_V2_ENGINES = ['flux', 'krea'] as const
|
||||
@@ -166,3 +174,88 @@ export type ImageV2PresetSettings = {
|
||||
width?: number
|
||||
height?: number
|
||||
}
|
||||
|
||||
export function isImageV2ConceptLora(name: string) {
|
||||
const id = loraIdentityKey(name)
|
||||
return id === loraIdentityKey(IMAGE_V2_SNOFS_LORA) || /klein_snofs/i.test(id)
|
||||
}
|
||||
|
||||
export function isImageV2ConsistencyLora(name: string) {
|
||||
const id = loraIdentityKey(name)
|
||||
return id === loraIdentityKey(IMAGE_V2_CONSISTENCY_LORA) || /flux2-klein-9b-consistency/i.test(id)
|
||||
}
|
||||
|
||||
export function upsertImageV2Lora(stack: unknown, name: string, model: number, clip: number): LoraStackItem[] {
|
||||
const item = makeLoraStackItem(name, model, clip)
|
||||
const current = normalizeLoraStack(stack)
|
||||
if (!item) return current
|
||||
const key = loraIdentityKey(name)
|
||||
const index = current.findIndex(entry => loraIdentityKey(entry.name) === key)
|
||||
if (index >= 0) {
|
||||
const next = [...current]
|
||||
next[index] = { ...next[index], strengthModel: item.strengthModel, strengthClip: item.strengthClip }
|
||||
return next
|
||||
}
|
||||
if (isImageV2ConsistencyLora(name)) {
|
||||
const conceptAt = current.findIndex(entry => isImageV2ConceptLora(entry.name))
|
||||
if (conceptAt >= 0) return [...current.slice(0, conceptAt + 1), item, ...current.slice(conceptAt + 1)]
|
||||
}
|
||||
return [item, ...current]
|
||||
}
|
||||
|
||||
export function defaultImageV2LoraStack(opts: {
|
||||
engine: ImageV2Engine
|
||||
mode: ImageV2Mode
|
||||
xaigen: boolean
|
||||
kreaConcept?: string
|
||||
}): LoraStackItem[] {
|
||||
if (opts.engine === 'krea') {
|
||||
const name = String(opts.kreaConcept || '').trim()
|
||||
if (!opts.xaigen || !name) return []
|
||||
const item = makeLoraStackItem(name, IMAGE_V2_SNOFS_MODEL, IMAGE_V2_SNOFS_CLIP)
|
||||
return item ? [item] : []
|
||||
}
|
||||
const out: LoraStackItem[] = []
|
||||
if (opts.xaigen) {
|
||||
const concept = makeLoraStackItem(IMAGE_V2_SNOFS_LORA, IMAGE_V2_SNOFS_MODEL, IMAGE_V2_SNOFS_CLIP)
|
||||
if (concept) out.push(concept)
|
||||
}
|
||||
if (opts.mode !== 'generate') {
|
||||
const consistency = makeLoraStackItem(IMAGE_V2_CONSISTENCY_LORA, IMAGE_V2_CONSISTENCY_MODEL, IMAGE_V2_CONSISTENCY_CLIP)
|
||||
if (consistency) out.push(consistency)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
export function mergeLegacyImageV2Loras(stack: unknown, opts: {
|
||||
engine: ImageV2Engine
|
||||
mode: ImageV2Mode
|
||||
xaigen: boolean
|
||||
snofsModel?: number
|
||||
snofsClip?: number
|
||||
consistencyModel?: number
|
||||
consistencyClip?: number
|
||||
kreaConcept?: string
|
||||
}): LoraStackItem[] {
|
||||
let items = filterLoraStackForImageEngine(stack, opts.engine)
|
||||
if (opts.engine === 'krea') {
|
||||
const name = String(opts.kreaConcept || '').trim()
|
||||
const model = Number(opts.snofsModel) || 0
|
||||
const clip = Number(opts.snofsClip) || 0
|
||||
if (name && (model > 0 || clip > 0) && !items.some(item => loraIdentityKey(item.name) === loraIdentityKey(name))) {
|
||||
return upsertImageV2Lora(items, name, model, clip)
|
||||
}
|
||||
return items
|
||||
}
|
||||
const conceptModel = opts.xaigen ? Number(opts.snofsModel) || 0 : 0
|
||||
const conceptClip = opts.xaigen ? Number(opts.snofsClip) || 0 : 0
|
||||
if ((conceptModel > 0 || conceptClip > 0) && !items.some(item => isImageV2ConceptLora(item.name))) {
|
||||
items = upsertImageV2Lora(items, IMAGE_V2_SNOFS_LORA, conceptModel, conceptClip)
|
||||
}
|
||||
const consistencyModel = opts.mode === 'generate' ? 0 : Number(opts.consistencyModel) || 0
|
||||
const consistencyClip = opts.mode === 'generate' ? 0 : Number(opts.consistencyClip) || 0
|
||||
if ((consistencyModel > 0 || consistencyClip > 0) && !items.some(item => isImageV2ConsistencyLora(item.name))) {
|
||||
items = upsertImageV2Lora(items, IMAGE_V2_CONSISTENCY_LORA, consistencyModel, consistencyClip)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user