修复连续生图保真:锁定视角背景并禁用编辑扩写
This commit is contained in:
parent
ef8326fd33
commit
20c9f6d821
@ -200,7 +200,10 @@ function hasUserCustomizedImageParams(params?: PostRequestBody["imageParams"]):
|
||||
const customizedImageSize =
|
||||
typeof params.imageSize === "string" && params.imageSize.trim() && params.imageSize.toUpperCase() !== "2K";
|
||||
const customizedImageCount = typeof params.imageCount === "number" && params.imageCount !== 1;
|
||||
const customizedAdvanced = Boolean(params.size || params.seed !== undefined || params.n || params.negativePrompt);
|
||||
const customizedPromptExtend = typeof params.promptExtend === "boolean";
|
||||
const customizedAdvanced = Boolean(
|
||||
params.size || params.seed !== undefined || params.n || params.negativePrompt || customizedPromptExtend
|
||||
);
|
||||
return customizedAspectRatio || customizedImageSize || customizedImageCount || customizedAdvanced;
|
||||
}
|
||||
|
||||
@ -236,6 +239,9 @@ function mergeImageParamsWithAgentRecommendation(params: {
|
||||
|
||||
if (intent === "image_edit") {
|
||||
merged.imageCount = 1;
|
||||
if (typeof base.promptExtend !== "boolean") {
|
||||
merged.promptExtend = false;
|
||||
}
|
||||
}
|
||||
|
||||
return Object.keys(merged).length > 0 ? merged : undefined;
|
||||
|
||||
@ -111,6 +111,10 @@ function sanitizeRecommendedImageParams(
|
||||
safe.promptExtend = params.promptExtend;
|
||||
}
|
||||
|
||||
if (intent === "image_edit") {
|
||||
safe.promptExtend = false;
|
||||
}
|
||||
|
||||
return Object.keys(safe).length > 0 ? safe : undefined;
|
||||
}
|
||||
|
||||
@ -121,7 +125,7 @@ function heuristicImageParams(
|
||||
const normalized = text.toLowerCase();
|
||||
const params: AgentRecommendedImageParams = {
|
||||
imageSize: "2K",
|
||||
promptExtend: true,
|
||||
promptExtend: analysis.intent === "image_edit" ? false : true,
|
||||
};
|
||||
|
||||
if (analysis.intent === "image_edit") {
|
||||
|
||||
@ -316,6 +316,56 @@ function sanitizeSuggestedParams(input?: {
|
||||
return Object.keys(output).length > 0 ? output : undefined;
|
||||
}
|
||||
|
||||
function shouldKeepBackgroundAsIs(originalPrompt: string, subIntent?: string): boolean {
|
||||
if (subIntent === "replace_background" || subIntent === "remove_background") {
|
||||
return false;
|
||||
}
|
||||
return !/(换背景|改背景|替换背景|背景改成|背景换成|白底|黑底|透明背景|场景换成|背景变成)/i.test(
|
||||
originalPrompt
|
||||
);
|
||||
}
|
||||
|
||||
function shouldKeepCameraAsIs(originalPrompt: string): boolean {
|
||||
return !/(角度|视角|机位|镜头|构图|俯拍|仰拍|侧拍|旋转|翻转|远景|近景|特写)/i.test(
|
||||
originalPrompt
|
||||
);
|
||||
}
|
||||
|
||||
function enforceImageEditStability(params: {
|
||||
optimizedPrompt: string;
|
||||
originalPrompt: string;
|
||||
subIntent?: string;
|
||||
negativePrompt?: string;
|
||||
}) {
|
||||
const keepBackground = shouldKeepBackgroundAsIs(params.originalPrompt, params.subIntent);
|
||||
const keepCamera = shouldKeepCameraAsIs(params.originalPrompt);
|
||||
|
||||
const stabilityRules = [
|
||||
"只修改用户明确要求的内容,其他元素保持不变",
|
||||
keepCamera ? "保持原图拍摄角度、主体朝向、构图和透视关系不变" : "",
|
||||
keepBackground
|
||||
? "保持原图背景颜色与明暗不变;若原图是白底,继续保持纯白背景(#FFFFFF)"
|
||||
: "",
|
||||
"保持主体形状比例、材质纹理和光影一致,禁止出现黑底/灰底污染",
|
||||
].filter(Boolean);
|
||||
|
||||
const mergedNegativePrompt = [
|
||||
params.negativePrompt || "",
|
||||
keepCamera ? "角度变化,构图漂移,主体旋转" : "",
|
||||
keepBackground ? "背景变黑,背景变灰,背景误改,白底丢失" : "",
|
||||
"主体变形,比例错误,材质改变,边缘脏污",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(",");
|
||||
|
||||
const promptWithStability = `${params.optimizedPrompt.trim()}\n\n保真约束:${stabilityRules.join(";")}。`;
|
||||
|
||||
return {
|
||||
optimizedPrompt: promptWithStability,
|
||||
negativePrompt: mergedNegativePrompt,
|
||||
};
|
||||
}
|
||||
|
||||
function fallbackImageGenPrompt(originalPrompt: string): OptimizeResult {
|
||||
const normalized = originalPrompt.replace(/\s+/g, " ").trim();
|
||||
const optimizedPrompt = [
|
||||
@ -439,10 +489,22 @@ export async function optimizePromptWithLLM(params: {
|
||||
const parsedResult = parseOptimizerJson(responseText);
|
||||
if (parsedResult) {
|
||||
console.log("[Prompt Optimizer LLM] Result parsed");
|
||||
const stabilized =
|
||||
intent === "image_edit"
|
||||
? enforceImageEditStability({
|
||||
optimizedPrompt: parsedResult.optimizedPrompt || originalPrompt,
|
||||
originalPrompt,
|
||||
subIntent,
|
||||
negativePrompt: parsedResult.negativePrompt || "模糊,低质量,变形,失真",
|
||||
})
|
||||
: {
|
||||
optimizedPrompt: parsedResult.optimizedPrompt || originalPrompt,
|
||||
negativePrompt: parsedResult.negativePrompt || "模糊,低质量,变形,失真",
|
||||
};
|
||||
return {
|
||||
originalPrompt,
|
||||
optimizedPrompt: parsedResult.optimizedPrompt || originalPrompt,
|
||||
negativePrompt: parsedResult.negativePrompt || "模糊,低质量,变形,失真",
|
||||
optimizedPrompt: stabilized.optimizedPrompt,
|
||||
negativePrompt: stabilized.negativePrompt,
|
||||
recommendedImageParams: sanitizeSuggestedParams(parsedResult.suggestedParams),
|
||||
friendlyMessage: intent === "image_edit" ? FRIENDLY_MESSAGES[subIntent || ""]?.template : undefined,
|
||||
};
|
||||
@ -574,6 +636,17 @@ export function optimizePrompt(params: {
|
||||
friendlyMessage: friendlyMessage || `好的,我来帮你处理这张图片~`,
|
||||
};
|
||||
|
||||
if (intent === "image_edit") {
|
||||
const stabilized = enforceImageEditStability({
|
||||
optimizedPrompt: result.optimizedPrompt,
|
||||
originalPrompt,
|
||||
subIntent,
|
||||
negativePrompt: result.negativePrompt,
|
||||
});
|
||||
result.optimizedPrompt = stabilized.optimizedPrompt;
|
||||
result.negativePrompt = stabilized.negativePrompt;
|
||||
}
|
||||
|
||||
console.log("[Prompt Optimizer] Output:", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -23,6 +23,35 @@ export interface AnalysisResult {
|
||||
conversationalReply?: string; // 🆕 自然对话回复
|
||||
}
|
||||
|
||||
function normalizeIntentForImageContext(
|
||||
result: AnalysisResult,
|
||||
text: string,
|
||||
hasImage: boolean
|
||||
): AnalysisResult {
|
||||
if (!hasImage || result.intent !== "image_gen") {
|
||||
return result;
|
||||
}
|
||||
|
||||
const normalizedText = text.toLowerCase();
|
||||
const explicitGenerate =
|
||||
/重新生成|再来一张|生成新图|新建图片|创作一张|参考.*生成|按这个风格生成|以这张图为灵感生成/.test(
|
||||
normalizedText
|
||||
);
|
||||
const editSignal =
|
||||
/改|调整|优化|去掉|换成|改成|保留|继续|再.*一点|修|抠|替换|增强|清晰|重绘/.test(normalizedText);
|
||||
|
||||
if (explicitGenerate && !editSignal) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return {
|
||||
...result,
|
||||
intent: "image_edit",
|
||||
subIntent: result.subIntent,
|
||||
confidence: Math.max(result.confidence, 0.78),
|
||||
};
|
||||
}
|
||||
|
||||
// 系统提示词 - 针对图片编辑场景优化,生成自然对话
|
||||
const ANALYZER_SYSTEM_PROMPT = `你是一个友好的AI图片编辑助手。用户会给你发送图片和编辑请求,你需要:
|
||||
1. 理解用户想要对图片做什么
|
||||
@ -319,7 +348,7 @@ ${historyText}
|
||||
if (jsonMatch) {
|
||||
try {
|
||||
const result = JSON.parse(jsonMatch[0]) as AnalysisResult;
|
||||
return result;
|
||||
return normalizeIntentForImageContext(result, text, hasImage);
|
||||
} catch (e) {
|
||||
console.error("[Smart Analyzer] Failed to parse LLM response:", e);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user