Add Krea as a second Image v2 Generate engine beside Flux.
Generate can queue krea_v2_generate.json without sharing Klein encoders or falling back if Krea assets are missing. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
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
|
||||
|
||||
export type ImageV2Mode = (typeof IMAGE_V2_MODES)[number]
|
||||
export type ImageV2Task = (typeof IMAGE_V2_TASKS)[number]
|
||||
export type ImageV2Engine = (typeof IMAGE_V2_ENGINES)[number]
|
||||
|
||||
export const IMAGE_V2_STEPS_DEFAULT = 24
|
||||
export const IMAGE_V2_CFG_DEFAULT = 4
|
||||
@@ -52,6 +54,18 @@ export type ImageV2GenerateAspect = keyof typeof IMAGE_V2_GENERATE_ASPECTS
|
||||
export const IMAGE_V2_GENERATE_SFW = { snofsModel: 0, snofsClip: 0 }
|
||||
export const IMAGE_V2_GENERATE_SNOFS = { snofsModel: 0.65, snofsClip: 0.35 }
|
||||
|
||||
export const IMAGE_V2_KREA_STEPS = 8
|
||||
export const IMAGE_V2_KREA_CFG = 1
|
||||
export const IMAGE_V2_KREA_CLIP = 'qwen3vl_4b_fp8_scaled.safetensors'
|
||||
export const IMAGE_V2_KREA_CLIP_TYPE = 'krea2'
|
||||
export const IMAGE_V2_KREA_VAE = 'qwen_image_vae.safetensors'
|
||||
export const IMAGE_V2_KREA_UNET_CANDIDATES = [
|
||||
'krea2_turbo_mxfp8.safetensors',
|
||||
'krea2_turbo_nvfp4.safetensors',
|
||||
'krea2_turbo_fp8_scaled.safetensors'
|
||||
] as const
|
||||
export const IMAGE_V2_KREA_CONCEPT_LORA = ''
|
||||
|
||||
export const IMAGE_V2_ROLE_HEADERS: Record<Exclude<ImageV2Task, 'scene' | 'refine' | 't2i'>, string> = {
|
||||
outfit: 'Person, face, body, pose, and background from image 1. Clothing only from image 2. Fit the outfit from image 2 to the body in image 1. Do not copy image 2’s face, body shape, or pose.',
|
||||
face_lock: 'Body, pose, and scene from image 1. Exact face from image 2.',
|
||||
@@ -68,6 +82,19 @@ export function parseImageV2Task(raw: unknown, fallback: ImageV2Task = 'scene'):
|
||||
return IMAGE_V2_TASKS.includes(value as ImageV2Task) ? value as ImageV2Task : fallback
|
||||
}
|
||||
|
||||
export function parseImageV2Engine(raw: unknown, fallback: ImageV2Engine = 'flux'): ImageV2Engine {
|
||||
const value = String(raw || '').trim().toLowerCase()
|
||||
return IMAGE_V2_ENGINES.includes(value as ImageV2Engine) ? value as ImageV2Engine : fallback
|
||||
}
|
||||
|
||||
export function imageV2WorkflowFile(mode: ImageV2Mode, engine: ImageV2Engine = 'flux') {
|
||||
if (mode === 'generate' && engine === 'krea') return 'krea_v2_generate.json'
|
||||
if (mode === 'generate') return 'klein_v2_generate.json'
|
||||
if (mode === 'refine') return 'klein_v2_refine.json'
|
||||
if (mode === 'compose') return 'klein_v2_compose.json'
|
||||
return 'klein_v2_edit.json'
|
||||
}
|
||||
|
||||
export function clampImageV2Strength(raw: unknown, fallback: number) {
|
||||
const value = Number(raw)
|
||||
if (!Number.isFinite(value)) return fallback
|
||||
@@ -118,6 +145,7 @@ export function composeImageV2Prompt(mode: ImageV2Mode, task: ImageV2Task, promp
|
||||
export type ImageV2PresetSettings = {
|
||||
mode?: ImageV2Mode
|
||||
task?: ImageV2Task
|
||||
engine?: ImageV2Engine
|
||||
negative?: string
|
||||
snofsModel?: number
|
||||
snofsClip?: number
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { loraDisplayName, normalizeLoraStack, type LoraStackItem } from '~/utils/loras'
|
||||
import type { ImageV2Mode, ImageV2Task } from '~/utils/imageV2'
|
||||
import type { ImageV2Engine, ImageV2Mode, ImageV2Task } from '~/utils/imageV2'
|
||||
import type { VideoWorkflowId } from '~/utils/videoModels'
|
||||
|
||||
export type StillGenerationKind = 'image' | 'imagev2'
|
||||
@@ -7,6 +7,7 @@ export type StillGenerationKind = 'image' | 'imagev2'
|
||||
export type StillGenerationSettings = {
|
||||
kind: StillGenerationKind
|
||||
mode?: ImageV2Mode
|
||||
engine?: ImageV2Engine
|
||||
task?: ImageV2Task
|
||||
negative?: string
|
||||
snofsModel?: number
|
||||
@@ -64,6 +65,7 @@ export function normalizeStillSettings(raw: unknown): StillGenerationSettings |
|
||||
const mode = value.mode === 'compose' || value.mode === 'refine' || value.mode === 'generate' || value.mode === 'edit'
|
||||
? value.mode
|
||||
: undefined
|
||||
const engine = value.engine === 'krea' || value.engine === 'flux' ? value.engine : undefined
|
||||
const kind: StillGenerationKind | undefined = value.kind === 'imagev2' || mode
|
||||
? 'imagev2'
|
||||
: value.kind === 'image'
|
||||
@@ -77,6 +79,7 @@ export function normalizeStillSettings(raw: unknown): StillGenerationSettings |
|
||||
return {
|
||||
kind,
|
||||
mode,
|
||||
engine,
|
||||
task,
|
||||
negative: typeof value.negative === 'string' ? value.negative : undefined,
|
||||
snofsModel: finiteNumber(value.snofsModel),
|
||||
@@ -127,7 +130,8 @@ export function stillModeLabel(still: { filename?: string; settings?: StillGener
|
||||
? 'Refine'
|
||||
: 'Edit'
|
||||
const task = settings.mode === 'compose' ? composeTaskLabel(settings.task) : ''
|
||||
return task ? `Image v2 · ${mode} · ${task}` : `Image v2 · ${mode}`
|
||||
const engine = settings.mode === 'generate' && settings.engine === 'krea' ? 'Krea' : ''
|
||||
return [mode === 'Generate' && engine ? `Image v2 · ${mode} · ${engine}` : `Image v2 · ${mode}`, task].filter(Boolean).join(' · ')
|
||||
}
|
||||
if (settings?.kind === 'image') return 'Image edit'
|
||||
if (/aigen_v2_/i.test(String(still.filename || ''))) return 'Image v2'
|
||||
@@ -147,8 +151,11 @@ export function stillSettingsRows(still: { width?: number; height?: number; sett
|
||||
} else if (still.width && still.height) {
|
||||
rows.push({ label: 'Output', value: `${still.width}×${still.height}` })
|
||||
}
|
||||
if (settings.mode === 'generate' && settings.engine) {
|
||||
rows.push({ label: 'Engine', value: settings.engine === 'krea' ? 'Krea' : 'Flux' })
|
||||
}
|
||||
if (settings.snofsModel != null || settings.snofsClip != null) {
|
||||
rows.push({ label: 'SNOFS', value: formatPair(settings.snofsModel, settings.snofsClip) })
|
||||
rows.push({ label: 'Concept LoRA', value: formatPair(settings.snofsModel, settings.snofsClip) })
|
||||
}
|
||||
if (settings.mode !== 'generate' && (settings.consistencyModel != null || settings.consistencyClip != null)) {
|
||||
rows.push({ label: 'Consistency', value: formatPair(settings.consistencyModel, settings.consistencyClip) })
|
||||
|
||||
Reference in New Issue
Block a user