diff --git a/docs/image-v2.md b/docs/image-v2.md
index ac704e7..924065d 100644
--- a/docs/image-v2.md
+++ b/docs/image-v2.md
@@ -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.
diff --git a/pages/index.vue b/pages/index.vue
index 281f969..36e222e 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -793,31 +793,33 @@
-
- Concept LoRA — Model
-
-
-
- Concept LoRA — CLIP
-
-
-
No Krea concept LoRA is configured.
+
+
+ Concept LoRA — Model
+
+
+
+ Concept LoRA — CLIP
+
+
+ No Krea concept LoRA is configured.
+
Consistency — Model
@@ -2275,8 +2277,8 @@ const v2Engine = ref('flux')
const v2Task = ref('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([])
const clips = ref([])
const stills = ref([])
@@ -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 (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)
+ 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
- v2SnofsModel.value = IMAGE_V2_REFINE_FACE.snofsModel
- v2SnofsClip.value = IMAGE_V2_REFINE_FACE.snofsClip
+ 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
- v2SnofsModel.value = IMAGE_V2_REFINE_HAND.snofsModel
- v2SnofsClip.value = IMAGE_V2_REFINE_HAND.snofsClip
+ 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)))
diff --git a/server/api/v2/generate.post.ts b/server/api/v2/generate.post.ts
index 16f4545..6db1079 100644
--- a/server/api/v2/generate.post.ts
+++ b/server/api/v2/generate.post.ts
@@ -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,
diff --git a/server/utils/generationPresets.ts b/server/utils/generationPresets.ts
index bb6e6cb..2fa7ba1 100644
--- a/server/utils/generationPresets.ts
+++ b/server/utils/generationPresets.ts
@@ -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
}
}
diff --git a/server/utils/imageWorkflowV2.ts b/server/utils/imageWorkflowV2.ts
index 881051b..2ef69cc 100644
--- a/server/utils/imageWorkflowV2.ts
+++ b/server/utils/imageWorkflowV2.ts
@@ -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)
- setInput(graph, SNOFS, 'lora_name', resolveRequiredLora(IMAGE_V2_SNOFS_LORA, 'SNOFS'))
- setInput(graph, SNOFS, 'strength_model', snofsModel)
- setInput(graph, SNOFS, 'strength_clip', snofsClip)
+ 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)
diff --git a/server/utils/studioQueue.ts b/server/utils/studioQueue.ts
index d09d81f..6ff39ed 100644
--- a/server/utils/studioQueue.ts
+++ b/server/utils/studioQueue.ts
@@ -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,
diff --git a/utils/libraryGeneration.ts b/utils/libraryGeneration.ts
index e6a7b0b..378bdfb 100644
--- a/utils/libraryGeneration.ts
+++ b/utils/libraryGeneration.ts
@@ -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)) {
diff --git a/utils/loras.ts b/utils/loras.ts
index 01d7809..507aecd 100644
--- a/utils/loras.ts
+++ b/utils/loras.ts
@@ -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. */