Add Image Iterate: nested multi-prompt still families.
Iterate runs a series of prompts as generate (no still), edit (still A), or compose (A+B), saves each output under one library collection like video extensions, and defaults to iterating from the original still.
This commit is contained in:
+25
-10
@@ -6,13 +6,26 @@ import {
|
||||
type LoraStackItem
|
||||
} from '~/utils/loras'
|
||||
|
||||
export const IMAGE_V2_MODES = ['edit', 'compose', 'refine', 'generate'] as const
|
||||
export const IMAGE_V2_MODES = ['edit', 'compose', 'refine', 'generate', 'iterate'] 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 type ImageV2GraphMode = Exclude<ImageV2Mode, 'iterate'>
|
||||
|
||||
/** Iterate picks a real graph from the attached stills: none → generate, A → edit, A+B → compose. */
|
||||
export function iterateGraphMode(opts: { hasImage?: boolean; hasReference?: boolean }): Exclude<ImageV2GraphMode, 'refine'> {
|
||||
if (!opts.hasImage) return 'generate'
|
||||
if (opts.hasReference) return 'compose'
|
||||
return 'edit'
|
||||
}
|
||||
|
||||
export function imageV2GraphMode(mode: ImageV2Mode, opts: { hasImage?: boolean; hasReference?: boolean } = {}): ImageV2GraphMode {
|
||||
if (mode === 'iterate') return iterateGraphMode(opts)
|
||||
return mode
|
||||
}
|
||||
|
||||
export const IMAGE_V2_STEPS_DEFAULT = 24
|
||||
export const IMAGE_V2_CFG_DEFAULT = 4
|
||||
@@ -97,16 +110,17 @@ export function parseImageV2Engine(raw: unknown, fallback: ImageV2Engine = 'flux
|
||||
return IMAGE_V2_ENGINES.includes(value as ImageV2Engine) ? value as ImageV2Engine : fallback
|
||||
}
|
||||
|
||||
export function imageV2WorkflowFile(mode: ImageV2Mode, engine: ImageV2Engine = 'flux') {
|
||||
export function imageV2WorkflowFile(mode: ImageV2Mode, engine: ImageV2Engine = 'flux', opts: { hasImage?: boolean; hasReference?: boolean } = {}) {
|
||||
const graph = imageV2GraphMode(mode, opts)
|
||||
if (engine === 'krea') {
|
||||
if (mode === 'generate') return 'krea_v2_generate.json'
|
||||
if (mode === 'refine') return 'krea_v2_refine.json'
|
||||
if (mode === 'compose') return 'krea_v2_compose.json'
|
||||
if (graph === 'generate') return 'krea_v2_generate.json'
|
||||
if (graph === 'refine') return 'krea_v2_refine.json'
|
||||
if (graph === 'compose') return 'krea_v2_compose.json'
|
||||
return 'krea_v2_edit.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'
|
||||
if (graph === 'generate') return 'klein_v2_generate.json'
|
||||
if (graph === 'refine') return 'klein_v2_refine.json'
|
||||
if (graph === 'compose') return 'klein_v2_compose.json'
|
||||
return 'klein_v2_edit.json'
|
||||
}
|
||||
|
||||
@@ -150,9 +164,10 @@ export function clampImageV2Size(width: unknown, height: unknown, aspect?: unkno
|
||||
}
|
||||
}
|
||||
|
||||
export function composeImageV2Prompt(mode: ImageV2Mode, task: ImageV2Task, prompt: string) {
|
||||
export function composeImageV2Prompt(mode: ImageV2Mode, task: ImageV2Task, prompt: string, opts: { hasImage?: boolean; hasReference?: boolean } = {}) {
|
||||
const body = String(prompt || '').trim()
|
||||
if (mode === 'generate' || mode === 'refine' || mode !== 'compose' || task === 'scene' || task === 't2i') return body
|
||||
const graph = imageV2GraphMode(mode, opts)
|
||||
if (graph === 'generate' || graph === 'refine' || graph !== 'compose' || task === 'scene' || task === 't2i') return body
|
||||
const header = IMAGE_V2_ROLE_HEADERS[task as Exclude<ImageV2Task, 'scene' | 'refine' | 't2i'>]
|
||||
return header ? `${header}\n\n${body}` : body
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user