Compile image style chips and restore complete input metadata
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { stylePrompt } from '~/shared/studio2/styles.mjs';
|
||||
import { purge } from './cleanup';
|
||||
import { watchProgress } from './progress';
|
||||
import { fitStill } from './media';
|
||||
@@ -87,7 +88,7 @@ async function prepareGraph(r: any) {
|
||||
const mode = q.mode === 'iterate' ? (a ? 'edit' : 'generate') : q.mode;
|
||||
const found = q.engine === 'krea' ? await resolveKreaGenerateAssets() : null;
|
||||
const assets = found ? { kreaUnetName: found.unet, kreaClipName: found.clip, kreaVaeName: found.vae, kreaConceptLora: found.conceptLora } : {};
|
||||
graph = buildImageV2Workflow({ ...s, ...assets, engine: q.engine, mode, task: 'scene', prompt: q.compiledPrompt, imageAName: a, imageBName: mode === 'compose' ? b : undefined, maskName: mode === 'refine' ? mask : undefined, filenamePrefix: prefix + '/image' }).graph;
|
||||
graph = buildImageV2Workflow({ ...s, ...assets, engine: q.engine, mode, task: 'scene', prompt: q.compiledPrompt, negative: stylePrompt(q.imageStyles, true), imageAName: a, imageBName: mode === 'compose' ? b : undefined, maskName: mode === 'refine' ? mask : undefined, filenamePrefix: prefix + '/image' }).graph;
|
||||
applyResolvedImageSize(graph,s);
|
||||
if (usesSourceLatent) sampleKleinSource(graph,.65);
|
||||
if (q.engine === 'flux')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {normalizeStyles,stylePrompt} from './styles.mjs'
|
||||
import { queueSeeds } from './seed.mjs'
|
||||
import { sectionsFrom, compileSections } from './prompt.mjs'
|
||||
export { sectionsFrom } from './prompt.mjs'
|
||||
@@ -14,7 +15,7 @@ export function compilePrompt(value, video = false, locks = {}) {
|
||||
const hasImage=!!(locks.imageAId || locks.identityStillId)
|
||||
const attached=hasImage && locks.engine !== 'krea'
|
||||
const reference=locks.mode!=='generate' && locks.identityStillId && locks.imageAId && locks.identityStillId!==locks.imageAId ? 'second (hero) reference' : 'image reference'
|
||||
return [sectionsFrom(value).action,
|
||||
return [sectionsFrom(value).action, stylePrompt(locks.imageStyles),
|
||||
attached && locks.lockFace !== false ? `Preserve the person’s face, glasses, hair, and body identity from the ${reference}.` : '',
|
||||
attached && locks.lockOutfit !== false ? `Preserve the wardrobe from the ${reference}.` : '',
|
||||
attached && locks.lockOutfit === false ? 'Clothing may follow the source and requested scene; do not restore the hero outfit.' : ''
|
||||
@@ -55,7 +56,7 @@ export function validateRequest(raw, xaigen = false) {
|
||||
}
|
||||
const frames=Math.ceil((duration*number('fps',24,1,60)-5)/17)*17+5
|
||||
const shotSeeds=queueSeeds(raw.settings,1+(Array.isArray(raw.batch)?raw.batch.length:0))
|
||||
return { mode, engine, shotSeeds, lockFace:raw.lockFace !== false, lockOutfit:raw.lockOutfit !== false, hideInput:!!raw.hideInput, folderId:String(raw.folderId), identityStillId:raw.identityStillId || '', imageAId:raw.imageAId || '', imageBId:raw.imageBId || '', maskId:raw.maskId || '', startClipId:raw.startClipId || '', endStillId:raw.endStillId || '',
|
||||
return { mode, engine, shotSeeds, imageStyles:video?{positive:[],negative:[]}:normalizeStyles(raw.imageStyles), hideOutput:!!raw.hideOutput, lockFace:raw.lockFace !== false, lockOutfit:raw.lockOutfit !== false, hideInput:!!raw.hideInput, folderId:String(raw.folderId), identityStillId:raw.identityStillId || '', imageAId:raw.imageAId || '', imageBId:raw.imageBId || '', maskId:raw.maskId || '', startClipId:raw.startClipId || '', endStillId:raw.endStillId || '',
|
||||
startFrameSource: raw.startClipId ? {kind:'previous-last-frame',clipId:raw.startClipId} : {kind:'still',stillId:raw.imageAId || ''},
|
||||
promptSections, compiledPrompt:compilePrompt(promptSections,video,raw),
|
||||
settings: { aspect:['auto','16:9','9:16','1:1'].includes(raw.settings?.aspect)?raw.settings.aspect:'auto', fps:number('fps',24,1,60), width:number('width',1344,256,4096),height:number('height',768,256,4096),steps:number('steps',video?8:24,1,100),cfg:number('cfg',video?1.5:4,0,20),seedMode:raw.settings?.seedMode==='locked'?'locked':'random',seed:shotSeeds[0],duration:number('duration',5,1,15),turbo:raw.settings?.turbo !== false, loraStack:Array.isArray(raw.settings?.loraStack)?raw.settings.loraStack:[] },
|
||||
|
||||
@@ -46,3 +46,11 @@ export function extendSelected(form, clip, xaigen = false) {
|
||||
export function changeSource(form) {
|
||||
return form.mode==='extend' ? form : {...form,startClipId:'',settings:{...form.settings,aspect:'auto'}}
|
||||
}
|
||||
|
||||
export function useAsHero(form, item) { return {...form,identityStillId:item.id} }
|
||||
export function useAsSource(form, item) { return {...form,imageAId:item.id} }
|
||||
export function restoreAll(form,item) {
|
||||
const restored=restoreInput(item),next={...form,...restored,settings:{...form.settings,...restored.settings,seedMode:'random'}}
|
||||
next.mode=restored.mode==='iterate'?'edit':restored.mode || (item.kind==='clip'?'video':'edit')
|
||||
return next
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export const styleGroups={Render:['Photorealistic','Pixar','3D Disney','Comic','Watercolor','Oil painting'],Quality:['Realistic skin','Skin pores','Fine detail','Natural texture'],Lighting:['Golden hour','Soft studio','Window light','Overcast','Cinematic lighting']}
|
||||
export function normalizeStyles(value={}) { const known=Object.values(styleGroups).flat();const positive=[...new Set((value.positive||[]).filter(s=>known.includes(s)))];return {positive,negative:[...new Set((value.negative||[]).filter(s=>known.includes(s)&&!positive.includes(s)))]} }
|
||||
export function toggleStyle(value,chip,negative=false) { const next=normalizeStyles(value),key=negative?'negative':'positive',other=negative?'positive':'negative';next[other]=next[other].filter(s=>s!==chip);next[key]=next[key].includes(chip)?next[key].filter(s=>s!==chip):[...next[key],chip];return next }
|
||||
export function stylePrompt(value,negative=false){return normalizeStyles(value)[negative?'negative':'positive'].join(', ')}
|
||||
export function parseBatch(value){return String(value||'').split(/\r?\n\s*\r?\n/).map(s=>s.trim()).filter(Boolean)}
|
||||
@@ -1,3 +1,4 @@
|
||||
import {stylePrompt} from '../shared/studio2/styles.mjs'
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
@@ -12,7 +13,7 @@ const fn=tree.statements.find(n=>ts.isFunctionDeclaration(n)&&n.name.text==='pre
|
||||
const js=ts.transpileModule(fn.getText(tree),{compilerOptions:{target:ts.ScriptTarget.ES2022}}).outputText
|
||||
async function prepare(request){
|
||||
const uploads=[]
|
||||
const scope={useRuntimeConfig:()=>({comfyFilenamePrefix:'preview'}),upload:async(r,label)=>{uploads.push(label);return label+'.png'},readFileSync:()=>Buffer.from('fixture'),stillPath:()=>'',getStill:(_,id)=>({id}),resolveRequestSize:async()=>{},saveRecord(){},
|
||||
const scope={stylePrompt,useRuntimeConfig:()=>({comfyFilenamePrefix:'preview'}),upload:async(r,label)=>{uploads.push(label);return label+'.png'},readFileSync:()=>Buffer.from('fixture'),stillPath:()=>'',getStill:(_,id)=>({id}),resolveRequestSize:async()=>{},saveRecord(){},
|
||||
buildImageV2Workflow:params=>{const graph=structuredClone(template);graph['1'].inputs.image=params.imageAName;return {graph}},sampleKleinSource,attachHeroReference,applyResolvedImageSize,ensureComfyLoraNames:async()=>{},resolveGraphLoraNames(){}}
|
||||
const run=new Function(...Object.keys(scope),`${js};return prepareGraph`)(...Object.values(scope))
|
||||
const record={request,owner:'o',id:'job',index:0};return {graph:await run(record),record,uploads}
|
||||
|
||||
Reference in New Issue
Block a user