Keep the Klein Concept LoRA on xAIGen only.

AIGen hides the sliders, ignores snofs strengths, and strips the SNOFS node so that file cannot be queued from the public studio.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-29 07:08:33 -05:00
co-authored by Cursor
parent f6663444f5
commit ab5477c999
8 changed files with 108 additions and 68 deletions
+5 -5
View File
@@ -10,7 +10,7 @@ Image edit (v1) and Image v2 are siblings. v1 is unchanged. Do not mute-fix `wor
| Second still | Optional; switches branch | Compose only; required. Mismatch is a 400 |
| Mask | — | Refine only; required. Missing mask is a 400, not an Edit fallback |
| Input still | Required | Edit / Compose / Refine required. Generate ignores stills |
| LoRAs | Optional user picker | Concept LoRA + Consistency (Flux). Generate Consistency off. Krea Generate has no Consistency |
| LoRAs | Optional user picker | Consistency (Flux). Concept LoRA on xAIGen only. Generate Consistency off. Krea Generate has no Consistency |
| Defaults | 20 steps, CFG 1 | Flux: 24 steps, CFG 4 (turbo: 8 / 1). Krea Generate: 8 steps, CFG 1 |
Poll v2 jobs the same way as v1: `GET /api/generate/{id}/stream` and `GET /api/generate/{id}`.
@@ -97,7 +97,7 @@ Generate Krea (`krea_v2_generate.json`):
| `15` | `KSampler` euler / simple, default 8 steps, CFG 1 |
| `9` / `10` | Prompt / negative from the API |
Krea does not load Klein UNET, Klein CLIP, Klein VAE, Klein Consistency, or the Klein concept LoRA. Missing Krea diffusion / text encoder / VAE fails the job. Concept LoRA on Krea is off unless `NUXT_KREA_CONCEPT_LORA` is set.
Krea does not load Klein UNET, Klein CLIP, Klein VAE, Klein Consistency, or the Klein concept LoRA. Missing Krea diffusion / text encoder / VAE fails the job. Concept LoRA (`klein_snofs_v1_4`) is xAIGen only; AIGen bypasses that node. On Krea it stays off unless `NUXT_KREA_CONCEPT_LORA` is set on xAIGen.
There is no `LoadImage`. If the executed Generate graph has a required LoadImage, the job fails. v1 node 145 (muted T2I with a baked prompt) is not used.
@@ -107,8 +107,8 @@ If `image_b` is sent on Edit/Compose and the executed graph has fewer than two `
| Slider | Default |
|--------|---------|
| Concept LoRA — Model | 0.65 on Flux. 0 on Krea |
| Concept LoRA — CLIP | 0.35 on Flux. 0 on Krea |
| Concept LoRA — Model | xAIGen Flux: 0.65. Off on AIGen. 0 on Krea |
| Concept LoRA — CLIP | xAIGen Flux: 0.35. Off on AIGen. 0 on Krea |
| Consistency — Model | 0.70 on Flux Edit/Compose/Refine. Off on Generate |
| Consistency — CLIP | 0.70 on Flux Edit/Compose/Refine. Off on Generate |
| Steps | 24 (turbo 8) |
@@ -131,7 +131,7 @@ Do not raise Strength to rewrite the whole frame. If the face or background move
- **outfit** — keep Concept LoRA Model ~0.65 so cloth reads; do not raise it past ~0.85 or it starts rewriting the body from A. Consistency stays at 0.70 so the person in A does not become the person in B.
- **scene / edit** — start at the table defaults. Turbo is for drafts only.
- **refine** — prompt only the masked change. Face vs hand/chest chips set Strength and LoRAs together.
- **generate / Flux** — Concept LoRA defaults 0.65 / 0.35. Consistency stays 0. Turbo is 8 steps / CFG 1.
- **generate / Flux** — On xAIGen, Concept LoRA defaults 0.65 / 0.35. On AIGen the node is not loaded. Consistency stays 0. Turbo is 8 steps / CFG 1.
- **generate / Krea** — 8 steps, CFG 1, no Consistency. Concept LoRA stays 0 unless a Krea concept file is configured.
Presets on this tab store sliders + mode + task + engine (+ Strength when Refine, + size when Generate). They do not load v1 LoRA stacks or a cached latent. Missing engine on an old preset is Flux.
+25 -10
View File
@@ -793,6 +793,7 @@
</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
@@ -818,6 +819,7 @@
>
</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">
@@ -2275,8 +2277,8 @@ 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(IMAGE_V2_SNOFS_MODEL)
const v2SnofsClip = ref(IMAGE_V2_SNOFS_CLIP)
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)
@@ -2327,6 +2329,10 @@ const showPrivacyToggles = computed(() => isXaigenStudio({
studio: runtimeConfig.public.studio,
instanceName: instanceName.value
}))
const v2ConceptLoraEnabled = computed(() => isXaigenStudio({
studio: runtimeConfig.public.studio,
instanceName: instanceName.value
}))
const folders = ref<LibraryFolder[]>([])
const clips = ref<LibraryClip[]>([])
const stills = ref<LibraryStill[]>([])
@@ -3500,8 +3506,8 @@ function currentPresetSnapshot() {
engine: v2Mode.value === 'generate' ? v2Engine.value : 'flux',
task: v2Mode.value === 'compose' ? v2Task.value : v2Mode.value === 'refine' ? 'refine' : v2Mode.value === 'generate' ? 't2i' : 'scene',
negative: v2Negative.value,
snofsModel: clampImageV2Strength(v2SnofsModel.value, IMAGE_V2_SNOFS_MODEL),
snofsClip: clampImageV2Strength(v2SnofsClip.value, IMAGE_V2_SNOFS_CLIP),
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' ? 0 : clampImageV2Strength(v2ConsistencyModel.value, IMAGE_V2_CONSISTENCY_MODEL),
consistencyClip: v2Mode.value === 'generate' ? 0 : clampImageV2Strength(v2ConsistencyClip.value, IMAGE_V2_CONSISTENCY_CLIP),
steps: clampImageSteps(v2Steps.value, IMAGE_V2_STEPS_DEFAULT),
@@ -3553,8 +3559,8 @@ function applyGenerationPreset(preset: GenerationPreset) {
v2Engine.value = v2Mode.value === 'generate' ? parseImageV2Engine(settings.engine, 'flux') : '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 = clampImageV2Strength(settings.snofsModel, IMAGE_V2_SNOFS_MODEL)
v2SnofsClip.value = clampImageV2Strength(settings.snofsClip, IMAGE_V2_SNOFS_CLIP)
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' ? 0 : clampImageV2Strength(settings.consistencyModel, IMAGE_V2_CONSISTENCY_MODEL)
v2ConsistencyClip.value = v2Mode.value === 'generate' ? 0 : clampImageV2Strength(settings.consistencyClip, IMAGE_V2_CONSISTENCY_CLIP)
v2Steps.value = clampImageSteps(settings.steps, IMAGE_V2_STEPS_DEFAULT)
@@ -4836,8 +4842,13 @@ function applyStillSettings(still: LibraryStill) {
v2Engine.value = mode === 'generate' ? parseImageV2Engine(settings.engine, 'flux') : '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') {
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)
@@ -5481,8 +5492,8 @@ function setV2Engine(engine: ImageV2Engine) {
if (previous === 'krea') {
v2Steps.value = IMAGE_V2_STEPS_DEFAULT
v2Cfg.value = IMAGE_V2_CFG_DEFAULT
v2SnofsModel.value = IMAGE_V2_SNOFS_MODEL
v2SnofsClip.value = IMAGE_V2_SNOFS_CLIP
v2SnofsModel.value = v2ConceptLoraEnabled.value ? IMAGE_V2_SNOFS_MODEL : 0
v2SnofsClip.value = v2ConceptLoraEnabled.value ? IMAGE_V2_SNOFS_CLIP : 0
}
}
@@ -5495,8 +5506,10 @@ function setGenerateSize(aspect: ImageV2GenerateAspect) {
function applyRefinePreset(kind: 'face' | 'hand' | 'heavy') {
if (kind === 'face') {
v2Denoise.value = IMAGE_V2_REFINE_FACE.strength
if (v2ConceptLoraEnabled.value) {
v2SnofsModel.value = IMAGE_V2_REFINE_FACE.snofsModel
v2SnofsClip.value = IMAGE_V2_REFINE_FACE.snofsClip
}
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
@@ -5504,8 +5517,10 @@ function applyRefinePreset(kind: 'face' | 'hand' | 'heavy') {
}
if (kind === 'hand') {
v2Denoise.value = IMAGE_V2_REFINE_HAND.strength
if (v2ConceptLoraEnabled.value) {
v2SnofsModel.value = IMAGE_V2_REFINE_HAND.snofsModel
v2SnofsClip.value = IMAGE_V2_REFINE_HAND.snofsClip
}
v2ConsistencyModel.value = IMAGE_V2_REFINE_HAND.consistencyModel
v2ConsistencyClip.value = IMAGE_V2_REFINE_HAND.consistencyClip
return
@@ -5589,8 +5604,8 @@ async function editImageV2() {
}
body.append('prompt', prompt.value.trim())
body.append('negative', v2Negative.value)
body.append('snofs_model', String(clampImageV2Strength(v2SnofsModel.value, v2Engine.value === 'krea' ? 0 : IMAGE_V2_SNOFS_MODEL)))
body.append('snofs_clip', String(clampImageV2Strength(v2SnofsClip.value, v2Engine.value === 'krea' ? 0 : IMAGE_V2_SNOFS_CLIP)))
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('steps', String(clampImageSteps(v2Steps.value, v2Engine.value === 'krea' ? IMAGE_V2_KREA_STEPS : IMAGE_V2_STEPS_DEFAULT)))
+6 -4
View File
@@ -24,6 +24,7 @@ import {
type ImageV2Mode,
type ImageV2Task
} from '~/utils/imageV2'
import { isXaigenStudio } from '~/utils/videoModels'
import { getStill, rememberInputStill, stillPath } from '~/server/utils/library'
import { existsSync, readFileSync } from 'node:fs'
@@ -215,8 +216,9 @@ export default defineEventHandler(async (event) => {
fields.consistency_clip,
mode === 'generate' || engine === 'krea' ? 0 : IMAGE_V2_CONSISTENCY_CLIP
)
const generateSnofsFallback = engine === 'krea' ? 0 : IMAGE_V2_SNOFS_MODEL
const generateSnofsClipFallback = engine === 'krea' ? 0 : IMAGE_V2_SNOFS_CLIP
const conceptAllowed = isXaigenStudio()
const generateSnofsFallback = !conceptAllowed || engine === 'krea' ? 0 : IMAGE_V2_SNOFS_MODEL
const generateSnofsClipFallback = !conceptAllowed || engine === 'krea' ? 0 : IMAGE_V2_SNOFS_CLIP
const still = imageA
? await rememberInputStill({
@@ -287,8 +289,8 @@ export default defineEventHandler(async (event) => {
v2Mode,
v2Task,
engine,
snofsModel: clampImageV2Strength(fields.snofs_model, generateSnofsFallback),
snofsClip: clampImageV2Strength(fields.snofs_clip, generateSnofsClipFallback),
snofsModel: conceptAllowed ? clampImageV2Strength(fields.snofs_model, generateSnofsFallback) : 0,
snofsClip: conceptAllowed ? clampImageV2Strength(fields.snofs_clip, generateSnofsClipFallback) : 0,
consistencyModel: generateConsistencyModel,
consistencyClip: generateConsistencyClip,
maskStillId: savedMask?.id,
+8 -5
View File
@@ -124,8 +124,8 @@ function sanitizeImageV2Settings(raw: unknown): ImageV2PresetSettings {
engine,
task: mode === 'compose' ? parseImageV2Task(rec.task, 'scene') : mode === 'refine' ? 'refine' : mode === 'generate' ? 't2i' : 'scene',
negative: String(rec.negative || '').slice(0, 2000),
snofsModel: clampImageV2Strength(rec.snofsModel ?? rec.snofs_model, IMAGE_V2_SNOFS_MODEL),
snofsClip: clampImageV2Strength(rec.snofsClip ?? rec.snofs_clip, IMAGE_V2_SNOFS_CLIP),
snofsModel: isXaigenStudio() ? clampImageV2Strength(rec.snofsModel ?? rec.snofs_model, IMAGE_V2_SNOFS_MODEL) : 0,
snofsClip: isXaigenStudio() ? clampImageV2Strength(rec.snofsClip ?? rec.snofs_clip, IMAGE_V2_SNOFS_CLIP) : 0,
consistencyModel: clampImageV2Strength(rec.consistencyModel ?? rec.consistency_model, mode === 'generate' ? 0 : IMAGE_V2_CONSISTENCY_MODEL),
consistencyClip: clampImageV2Strength(rec.consistencyClip ?? rec.consistency_clip, mode === 'generate' ? 0 : IMAGE_V2_CONSISTENCY_CLIP),
steps: engine === 'krea' ? clampImageSteps(rec.steps, IMAGE_V2_KREA_STEPS) : turbo ? 8 : clampImageSteps(rec.steps, IMAGE_V2_STEPS_DEFAULT),
@@ -165,12 +165,15 @@ function normalizeStoredPreset(raw: unknown): GenerationPreset | null {
function publicPreset(preset: GenerationPreset): GenerationPreset {
const xaigen = isXaigenStudio()
const settings = preset.kind === 'video'
? { ...preset.settings, workflow: coerceVideoWorkflow((preset.settings as VideoPresetSettings).workflow) }
: preset.kind === 'imagev2' && !xaigen
? { ...preset.settings, snofsModel: 0, snofsClip: 0 }
: preset.settings
return {
...preset,
loraStack: filterLoraStackForStudio(preset.loraStack, xaigen),
settings: preset.kind === 'video'
? { ...preset.settings, workflow: coerceVideoWorkflow((preset.settings as VideoPresetSettings).workflow) }
: preset.settings
settings
}
}
+23 -4
View File
@@ -8,6 +8,7 @@ import { imageComfyFetch } from '~/server/utils/imageComfy'
import { cachedComfyLoraNames } from '~/server/utils/loras'
import { resolveComfyLoraName, loraIdentityKey } from '~/utils/loras'
import { clampImageCfg, clampImageScaleMegapixels, clampImageSteps } from '~/utils/generationPresets'
import { isXaigenStudio } from '~/utils/videoModels'
import {
IMAGE_V2_CONSISTENCY_CLIP,
IMAGE_V2_CONSISTENCY_LORA,
@@ -51,6 +52,8 @@ const NOISE = '15'
const SCHEDULER = '17'
const CFG = '18'
const SAVE = '21'
const UNET = '4'
const CLIP = '5'
const SNOFS = '7'
const CONSISTENCY = '8'
@@ -138,6 +141,16 @@ function bypassLoraNode(graph: WorkflowGraph, id: string, modelFrom: string, cli
}
}
function bypassLoraToBaseLoaders(graph: WorkflowGraph, id: string) {
delete graph[id]
for (const node of Object.values(graph)) {
for (const [key, value] of Object.entries(node.inputs)) {
if (!Array.isArray(value) || value[0] !== id) continue
node.inputs[key] = value[1] === 1 ? [CLIP, 0] : [UNET, 0]
}
}
}
function modelBasename(name: string) {
return String(name || '').replace(/\\/g, '/').split('/').pop() || ''
}
@@ -367,7 +380,7 @@ function buildKreaGenerateWorkflow(params: ImageV2BuildParams) {
const size = clampImageV2Size(params.width, params.height)
const steps = clampImageSteps(params.steps, IMAGE_V2_KREA_STEPS)
const cfg = clampImageCfg(params.cfg, IMAGE_V2_KREA_CFG)
const conceptName = String(params.kreaConceptLora || '').trim()
const conceptName = isXaigenStudio() ? String(params.kreaConceptLora || '').trim() : ''
const snofsModel = conceptName ? clampImageV2Strength(params.snofsModel, 0) : 0
const snofsClip = conceptName ? clampImageV2Strength(params.snofsClip, 0) : 0
const workflowFile = IMAGE_V2_KREA_GENERATE_WORKFLOW
@@ -434,8 +447,9 @@ export function buildImageV2Workflow(params: ImageV2BuildParams) {
) as WorkflowGraph
const prompt = composeImageV2Prompt(params.mode, params.task, params.prompt)
const negative = String(params.negative || '')
const snofsModel = clampImageV2Strength(params.snofsModel, IMAGE_V2_SNOFS_MODEL)
const snofsClip = clampImageV2Strength(params.snofsClip, IMAGE_V2_SNOFS_CLIP)
const conceptAllowed = isXaigenStudio()
const snofsModel = conceptAllowed ? clampImageV2Strength(params.snofsModel, IMAGE_V2_SNOFS_MODEL) : 0
const snofsClip = conceptAllowed ? clampImageV2Strength(params.snofsClip, IMAGE_V2_SNOFS_CLIP) : 0
const consistencyModel = clampImageV2Strength(
params.consistencyModel,
generate ? 0 : IMAGE_V2_CONSISTENCY_MODEL
@@ -470,11 +484,16 @@ 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) {
bypassLoraNode(graph, CONSISTENCY, SNOFS, SNOFS)
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)
+3 -3
View File
@@ -4,7 +4,7 @@ import { getJob, listJobs, emitJob, type Job } from '~/server/utils/jobs'
import { listPendingJobs, patchPendingJob, readPendingJob, deletePendingJob } from '~/server/utils/pending'
import { getShotQueue } from '~/server/utils/shotQueue'
import { fetchLiveQueue } from '~/server/utils/comfy'
import { isLtxWorkflow, isTextToVideo, LTX_DISABLED_MESSAGE, ltxWorkflowEnabled, parseVideoWorkflow, type VideoWorkflowId } from '~/utils/videoModels'
import { isLtxWorkflow, isTextToVideo, isXaigenStudio, LTX_DISABLED_MESSAGE, ltxWorkflowEnabled, parseVideoWorkflow, type VideoWorkflowId } from '~/utils/videoModels'
import { persistLoraFields } from '~/server/utils/loras'
import { resolveLoraStack } from '~/utils/loras'
import { allowIdentityRefs } from '~/utils/globalLocks'
@@ -764,8 +764,8 @@ async function startStudioEditJob(item: StudioJob) {
steps: payload.steps,
seed: live.library?.seed || payload.seed,
cfg: payload.cfg,
snofsModel: payload.snofsModel ?? 0.65,
snofsClip: payload.snofsClip ?? 0.35,
snofsModel: payload.snofsModel ?? (isXaigenStudio() ? 0.65 : 0),
snofsClip: payload.snofsClip ?? (isXaigenStudio() ? 0.35 : 0),
consistencyModel: payload.consistencyModel ?? (mode === 'generate' ? 0 : 0.7),
consistencyClip: payload.consistencyClip ?? (mode === 'generate' ? 0 : 0.7),
megapixels: payload.scaleMegapixels ?? 1,
+2 -2
View File
@@ -1,6 +1,6 @@
import { loraDisplayName, normalizeLoraStack, type LoraStackItem } from '~/utils/loras'
import type { ImageV2Engine, ImageV2Mode, ImageV2Task } from '~/utils/imageV2'
import type { VideoWorkflowId } from '~/utils/videoModels'
import { isXaigenStudio, type VideoWorkflowId } from '~/utils/videoModels'
export type StillGenerationKind = 'image' | 'imagev2'
@@ -154,7 +154,7 @@ export function stillSettingsRows(still: { width?: number; height?: number; sett
if (settings.mode === 'generate' && settings.engine) {
rows.push({ label: 'Engine', value: settings.engine === 'krea' ? 'Krea' : 'Flux' })
}
if (settings.snofsModel != null || settings.snofsClip != null) {
if (isXaigenStudio() && (settings.snofsModel != null || settings.snofsClip != null)) {
rows.push({ label: 'Concept LoRA', value: formatPair(settings.snofsModel, settings.snofsClip) })
}
if (settings.mode !== 'generate' && (settings.consistencyModel != null || settings.consistencyClip != null)) {
+2 -1
View File
@@ -30,7 +30,8 @@ export function loraIdentityKey(name: string) {
}
export function isXaigenOnlyLora(name: string) {
return /^xaigen/i.test(loraBasename(name))
const base = loraBasename(name)
return /^xaigen/i.test(base) || /klein_snofs/i.test(base)
}
/** Pick the real Comfy filename: exact path, then same basename ignoring `xaigen-`, then suffix/contains. */