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
+18 -4
View File
@@ -2,16 +2,17 @@ import { createJob, emitJob, type Job } from '~/server/utils/jobs'
import { ensureComfyReady } from '~/server/utils/comfyLifecycle'
import { assertImageScaleToTotalPixelsNode, getComfyHost, uploadImage, queuePrompt, purgeComfyArtifacts } from '~/server/utils/comfy'
import { withImageComfyHost, waitForImageEdit, downloadEditedImage } from '~/server/utils/imageComfy'
import { buildImageV2Workflow } from '~/server/utils/imageWorkflowV2'
import { buildImageV2Workflow, resolveKreaGenerateAssets } from '~/server/utils/imageWorkflowV2'
import { ensureComfyLoraNames } from '~/server/utils/loras'
import { imageDimensions } from '~/server/utils/resolution'
import { emitChainJob } from '~/server/utils/watch'
import { saveStill } from '~/server/utils/library'
import type { ImageV2Mode, ImageV2Task } from '~/utils/imageV2'
import { parseImageV2Engine, type ImageV2Engine, type ImageV2Mode, type ImageV2Task } from '~/utils/imageV2'
import type { EditImageFile } from '~/server/utils/imageChain'
export type EditV2RunParams = {
mode: ImageV2Mode
engine?: ImageV2Engine
task: ImageV2Task
image?: EditImageFile | null
reference: EditImageFile | null
@@ -64,10 +65,16 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
await withImageComfyHost(job.imageComfyHost, async () => {
const generate = params.mode === 'generate'
const engine = generate ? parseImageV2Engine(params.engine, 'flux') : 'flux'
if (engine === 'krea' && params.mode !== 'generate') {
throw new Error('Krea is available on Generate first.')
}
emitChainJob(job, {
type: 'status',
message: generate
? 'Queueing Klein v2 generate on Beast...'
? engine === 'krea'
? 'Queueing Krea generate on Beast...'
: 'Queueing Flux generate on Beast...'
: params.mode === 'refine'
? 'Uploading canvas and mask to Beast...'
: params.mode === 'compose' ? 'Uploading stills A and B to Beast...' : 'Uploading still A to Beast...',
@@ -103,8 +110,10 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
}
await ensureComfyLoraNames('image')
if (!generate) await assertImageScaleToTotalPixelsNode()
const krea = engine === 'krea' ? await resolveKreaGenerateAssets() : null
const built = buildImageV2Workflow({
mode: params.mode,
engine,
task: params.task,
prompt: params.prompt,
negative: params.negative,
@@ -123,7 +132,11 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
width: params.width,
height: params.height,
turbo: params.turbo === true,
filenamePrefix: `aigen_v2_${job.id.slice(0, 8)}`
filenamePrefix: `aigen_v2_${job.id.slice(0, 8)}`,
kreaUnetName: krea?.unet,
kreaClipName: krea?.clip,
kreaVaeName: krea?.vae,
kreaConceptLora: krea?.conceptLora
})
const queued = await queuePrompt(built.graph, job.clientId)
job.promptId = queued.prompt_id
@@ -169,6 +182,7 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
settings: {
kind: 'imagev2',
mode: params.mode,
engine,
task: params.task,
negative: params.negative,
snofsModel: params.snofsModel,