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:
Towsty
2026-08-29 07:05:01 -05:00
co-authored by Cursor
parent be5211f488
commit f6663444f5
11 changed files with 567 additions and 108 deletions
+28
View File
@@ -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