Wire Qwen Edit Start still to image_1 and PE-I2I identity keep.
Edit no longer invents strangers when the prompt omits <image1> or PE drops image tokens; Hero stays Klein-only. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import qwen21PeEditTemplate from '../../assets/studio2_qwen21_pe_edit.json';
|
||||
import { nativeVideoGraph, attachHeroReference, applyResolvedImageSize } from '~/shared/studio2/graphs.mjs';
|
||||
import { compilePrompt, scopedFile } from '~/shared/studio2/contracts.mjs';
|
||||
import { resolveQwen21Size } from '~/shared/studio2/qwen21-size.mjs';
|
||||
import { ensureQwen21EditPrompt, stitchQwen21PeEditPrompt } from '~/shared/studio2/qwen21-edit.mjs';
|
||||
import { QWEN21_TURBO_LORA, QWEN21_TURBO_SIGMAS, QWEN21_TURBO_STEPS } from '~/shared/studio2/qwen21-turbo.mjs';
|
||||
import { createJob, restoreJob, getJob, emitJob, type Job } from '../jobs';
|
||||
import { markStudioLive, onLiveVideoSettled, type StudioJob } from '../studioQueue';
|
||||
@@ -98,16 +99,18 @@ async function runQwen21PromptEnhance(r: any, job: Job) {
|
||||
const q = r.request, s = q.settings
|
||||
if (!q.enhancePrompt || q.engine !== 'qwen21' || !['generate', 'edit'].includes(q.mode)) return
|
||||
const edit = q.mode === 'edit'
|
||||
if (edit && !q.imageAId) throw new Error('Choose the source still.')
|
||||
// Edit → PE-I2I only (pe_i2i). Generate → PE-T2I only. Never cross-feed.
|
||||
if (edit && !q.imageAId)
|
||||
throw new Error('Qwen Edit requires Start still (image_1). Hero is ignored.')
|
||||
update(r, 'enhancing')
|
||||
emitJob(job, { type: 'status', message: 'Enhancing prompt…' })
|
||||
let prompt = String(q.compiledPrompt || '')
|
||||
if (edit && !/<image1>/i.test(prompt))
|
||||
prompt = `Keep the subject in <image1>. ${prompt}`.trim()
|
||||
if (edit) prompt = ensureQwen21EditPrompt(prompt)
|
||||
const graph = structuredClone(edit ? qwen21PeEditTemplate : qwen21PeT2iTemplate)
|
||||
graph['9'].inputs.prompt = prompt
|
||||
graph['9'].inputs.seed = s.seed
|
||||
if (edit) {
|
||||
// Same Start still pixels as Edit image_1 — never Hero.
|
||||
const a = await upload(r, 'pe-source', readFileSync(stillPath(r.owner, getStill(r.owner, q.imageAId).id)))
|
||||
graph['10'].inputs.image = a
|
||||
graph['9'].inputs.image_1 = ['10', 0]
|
||||
@@ -131,7 +134,10 @@ async function runQwen21PromptEnhance(r: any, job: Job) {
|
||||
if (!result.parse_ok || !result.positive_prompt)
|
||||
throw new Error('Prompt enhance failed to parse a rewrite. Try again or turn Enhance prompt off.')
|
||||
r.request.promptRaw = q.compiledPrompt
|
||||
r.request.compiledPrompt = result.positive_prompt
|
||||
// PE-I2I: if rewrite dropped every <imageN>, stitch keep-identity onto the rewrite.
|
||||
r.request.compiledPrompt = edit
|
||||
? stitchQwen21PeEditPrompt(result.positive_prompt)
|
||||
: result.positive_prompt
|
||||
r.request.enhance = {
|
||||
wh_ratio: result.wh_ratio || '',
|
||||
...(edit ? { ratio_follow: result.ratio_follow || '' } : {}),
|
||||
@@ -172,7 +178,10 @@ async function prepareGraph(r: any) {
|
||||
const load = async (id: string, label: string) => id ? upload(r, label, readFileSync(stillPath(r.owner, getStill(r.owner, id).id))) : '';
|
||||
const video=['video','extend'].includes(q.mode);
|
||||
const identityPlan=kleinIdentityPlan(q);
|
||||
const sourceId=identityPlan ? identityPlan.sourceId : q.imageAId;
|
||||
// Qwen Edit: Start still (imageAId) only — never Hero / identityStillId.
|
||||
const sourceId = q.engine === 'qwen21'
|
||||
? (q.imageAId || '')
|
||||
: (identityPlan ? identityPlan.sourceId : q.imageAId);
|
||||
await resolveRequestSize(r.owner,identityPlan ? {...q,imageAId:sourceId} : q);
|
||||
saveRecord(r);
|
||||
const a=await load(sourceId,'source'),b=await load(q.imageBId,'compose'),mask=await load(q.maskId,'mask');
|
||||
@@ -247,12 +256,13 @@ async function prepareGraph(r: any) {
|
||||
}
|
||||
const negative = turbo ? '' : stylePrompt(q.imageStyles, true)
|
||||
if (q.mode === 'edit') {
|
||||
if (!a) throw new Error('Choose the source still.')
|
||||
let prompt = String(q.compiledPrompt || '')
|
||||
if (!/<image1>/i.test(prompt))
|
||||
prompt = `Keep the subject in <image1>. ${prompt}`.trim()
|
||||
// Start still → image_1 only. Never Hero. Never T2I / EmptyLatent.
|
||||
if (!q.imageAId || !a)
|
||||
throw new Error('Qwen Edit requires Start still (image_1). Hero is ignored.')
|
||||
const prompt = ensureQwen21EditPrompt(String(q.compiledPrompt || ''))
|
||||
graph = structuredClone(turbo ? qwen21EditTurboTemplate : qwen21EditTemplate)
|
||||
graph['10'].inputs.image = a
|
||||
graph['9'].inputs['images.image_1'] = ['10', 0]
|
||||
if (b) {
|
||||
graph['11'] = {
|
||||
inputs: { image: b },
|
||||
|
||||
Reference in New Issue
Block a user