From b5e001dfc8033b3900286ee21a6ba0845cbd2a5c Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 23 Feb 2026 10:57:58 +0800 Subject: [PATCH] fix(agent): prevent scene edit prompts from collapsing to white background --- lib/ai/prompt-optimizer.ts | 105 ++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/lib/ai/prompt-optimizer.ts b/lib/ai/prompt-optimizer.ts index 8d301afba..78b7ec201 100644 --- a/lib/ai/prompt-optimizer.ts +++ b/lib/ai/prompt-optimizer.ts @@ -448,6 +448,52 @@ function shouldKeepBackgroundAsIs(originalPrompt: string, subIntent?: string): b ); } +function isSceneLikeEditPrompt(originalPrompt: string): boolean { + return /(客厅|卧室|书房|办公室|室内|室外|场景|墙面|墙|地面|地板|窗帘|沙发|桌|椅|柜|装饰画|地毯)/i.test( + originalPrompt + ); +} + +function isStructuralEditRequest(originalPrompt: string): boolean { + return /(替换|换成|换到|互换|交换|移动|移到|挪到|位置|放到|放在|贴紧|靠左|靠右|顶部|底部|左侧|右侧|对齐|其他.*不变|其余.*不变)/i.test( + originalPrompt + ); +} + +function isPureEnhanceRequest(originalPrompt: string): boolean { + return /(清晰|画质|锐化|降噪|高清|修复|增强|去噪|超分)/i.test(originalPrompt); +} + +function shouldForcePreciseEditFromEnhance(params: { + originalPrompt: string; + subIntent?: string; +}): boolean { + if (params.subIntent !== "enhance") return false; + return ( + isStructuralEditRequest(params.originalPrompt) && + !isPureEnhanceRequest(params.originalPrompt) + ); +} + +function buildPreciseEditPromptFromUserIntent(originalPrompt: string): string { + const base = `局部编辑:${originalPrompt}。要求:仅修改用户指定对象与位置关系;完整保留原场景背景(墙面、地面、家具、装饰)和光影,不要删除背景元素或抠成白底;主体比例、材质纹理、透视关系保持一致。`; + return ensureNanoBananaPromptStructure(base, "image_edit"); +} + +function extractOptimizedPromptFromNonJson(raw: string): string | null { + const text = String(raw || "") + .replace(/```[\s\S]*?```/g, " ") + .replace(/\s+/g, " ") + .trim(); + if (!text) return null; + + const labeledMatch = text.match(/(?:优化后的提示词|optimizedPrompt)\s*[::]\s*([\s\S]+)/i); + const candidate = (labeledMatch?.[1] || text).trim(); + if (candidate.length < 12) return null; + + return candidate.slice(0, 1400); +} + function shouldKeepCameraAsIs(originalPrompt: string): boolean { return !/(角度|视角|机位|镜头|构图|俯拍|仰拍|侧拍|旋转|翻转|远景|近景|特写)/i.test( originalPrompt @@ -462,12 +508,15 @@ function enforceImageEditStability(params: { }) { const keepBackground = shouldKeepBackgroundAsIs(params.originalPrompt, params.subIntent); const keepCamera = shouldKeepCameraAsIs(params.originalPrompt); + const sceneLikePrompt = isSceneLikeEditPrompt(params.originalPrompt); const stabilityRules = [ "只修改用户明确要求的内容,其他元素保持不变", keepCamera ? "保持原图拍摄角度、主体朝向、构图和透视关系不变" : "", keepBackground - ? "保持原图背景颜色与明暗不变;若原图是白底,继续保持纯白背景(#FFFFFF)" + ? sceneLikePrompt + ? "保持原图背景颜色与明暗不变,禁止删除墙面/地面/家具背景,禁止将场景误改成纯白底" + : "保持原图背景颜色与明暗不变" : "", "保持主体形状比例、材质纹理和光影一致,禁止出现黑底/灰底污染", ].filter(Boolean); @@ -475,10 +524,19 @@ function enforceImageEditStability(params: { const mergedNegativePrompt = [ params.negativePrompt || "", keepCamera ? "角度变化,构图漂移,主体旋转" : "", - keepBackground ? "背景变黑,背景变灰,背景误改,白底丢失" : "", + keepBackground + ? sceneLikePrompt + ? "背景变黑,背景变灰,背景误改,墙面消失,地面消失,场景白底化" + : "背景变黑,背景变灰,背景误改" + : "", "主体变形,比例错误,材质改变,边缘脏污", ] .filter(Boolean) + .join(",") + .split(",") + .map((item) => item.trim()) + .filter(Boolean) + .filter((item, index, list) => list.indexOf(item) === index) .join(","); const promptWithStability = `${params.optimizedPrompt.trim()}\n\n保真约束:${stabilityRules.join(";")}。`; @@ -651,6 +709,30 @@ export async function optimizePromptWithLLM(params: { }; } + const extractedPrompt = extractOptimizedPromptFromNonJson(responseText); + if (extractedPrompt) { + console.log("[Prompt Optimizer LLM] Parse failed, using non-JSON optimized text fallback"); + const normalizedPrompt = ensureNanoBananaPromptStructure(extractedPrompt, intent); + const stabilized = + intent === "image_edit" + ? enforceImageEditStability({ + optimizedPrompt: normalizedPrompt, + originalPrompt, + subIntent, + negativePrompt: "模糊,低质量,变形,失真,背景误改,主体变形", + }) + : { + optimizedPrompt: normalizedPrompt, + negativePrompt: "模糊,低质量,变形,失真", + }; + return { + originalPrompt, + optimizedPrompt: stabilized.optimizedPrompt, + negativePrompt: stabilized.negativePrompt, + friendlyMessage: intent === "image_edit" ? FRIENDLY_MESSAGES[subIntent || ""]?.template : undefined, + }; + } + // 解析失败,回退到模板优化 console.log( "[Prompt Optimizer LLM] Parse failed, falling back to template. raw=", @@ -700,6 +782,25 @@ export function optimizePrompt(params: { }; } + if (shouldForcePreciseEditFromEnhance({ originalPrompt, subIntent })) { + const optimizedPrompt = buildPreciseEditPromptFromUserIntent(originalPrompt); + const stabilized = enforceImageEditStability({ + optimizedPrompt, + originalPrompt, + subIntent, + negativePrompt: + "背景误改,墙面消失,地面消失,场景白底化,构图漂移,主体变形,比例错误,材质改变", + }); + const result: OptimizeResult = { + originalPrompt, + optimizedPrompt: stabilized.optimizedPrompt, + negativePrompt: stabilized.negativePrompt, + friendlyMessage: "收到,我按你的对象替换/位置调整要求精确执行。", + }; + console.log("[Prompt Optimizer] Output (enhance->precise-edit override):", result); + return result; + } + const template = EDIT_TEMPLATES[subIntent] as any; if (!template) { console.log("[Prompt Optimizer] No template for subIntent:", subIntent);