fix(agent): prevent scene edit prompts from collapsing to white background
This commit is contained in:
parent
3d7f0c5485
commit
b5e001dfc8
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user