fix: improve scene fusion prompts and failover blacklist
This commit is contained in:
parent
aaf5d3cddb
commit
0213047d2d
@ -50,8 +50,9 @@ const sceneFusionRequestSchema = z.object({
|
||||
|
||||
type SceneFusionMode = "scene-fission" | "multi-product-scene" | "random-bg";
|
||||
|
||||
// 默认提示词(当数据库未配置时使用)- 使用"参考"的表述方式
|
||||
const FALLBACK_PROMPT = "请参考第一张图片中的产品,将其自然地融合到第二张图片的场景中。要求:1)必须保持产品的核心结构、轮廓比例、部件数量、材质颜色和设计细节与第一张图一致;2)允许为了匹配参考场景调整产品角度、朝向、大小和透视,不要把角度变化当成结构改变;3)注意光影和透视关系使融合自然。";
|
||||
// 默认提示词(当数据库未配置时使用)- 强化主体锁定,避免把产品图里的摆件/文字/背景当作产品替入。
|
||||
const FALLBACK_PROMPT =
|
||||
"请参考第一张图片中的主产品主体,将其自然地融合到第二张图片的场景中。要求:1)只提取第一张图的主产品,忽略产品图中的杂志、杯子、摆件、文字、Logo、背景和装饰附件;2)必须保持主产品的核心结构、轮廓比例、部件数量、材质颜色和关键设计细节与第一张图一致;3)允许为了匹配参考场景调整产品角度、朝向、大小和透视,不要把角度变化当成结构改变;4)先移除第二张图里需要被替换的完整目标物,再放入主产品,禁止直接叠加在原目标物上;5)保留第二张图的大部分场景、机位、构图、光影方向和背景关系,使融合自然。";
|
||||
|
||||
const SCENE_FUSION_MODEL_COOLDOWN_MS = 2 * 60 * 1000;
|
||||
const SCENE_FUSION_MAX_ITEMS = 10;
|
||||
@ -64,7 +65,7 @@ const SCENE_FUSION_ECHO_HASH_TIMEOUT_MS = 20_000;
|
||||
const SCENE_FUSION_ECHO_HASH_THRESHOLD = 8;
|
||||
const SCENE_FUSION_REVIEW_TIMEOUT_MS = 25_000;
|
||||
const SCENE_FUSION_STRICT_PROMPT_TAIL =
|
||||
"硬性要求:严禁直接返回第一张参考图(产品图)原图,必须保留第二张图的场景与构图,仅替换目标主体;结果中不得同时完整保留原目标主体与新产品;产品可因场景透视调整角度、朝向和大小,但核心结构、轮廓比例、部件关系、材质颜色不得被改造;若识别不确定,请优先保持第二张图背景不变并完成主体替换。";
|
||||
"硬性要求:严禁直接返回第一张参考图(产品图)原图;严禁把产品图中的杂志、杯子、摆件、文字、Logo、背景或装饰附件当成要替换的产品;必须保留第二张图的场景与构图,仅替换目标主体;替换前必须移除原目标主体,结果中不得同时完整保留原目标主体与新产品,不得把新产品直接叠加在原物体表面;产品可因场景透视调整角度、朝向和大小,但核心结构、轮廓比例、部件关系、材质颜色不得被改造;若识别不确定,请优先保持第二张图背景不变并完成主体替换。";
|
||||
const SCENE_FUSION_RANDOM_BG_PROMPT_TAIL =
|
||||
"硬性要求:背景必须与原图明显不同(颜色、结构、元素至少两项显著变化),禁止保留原背景纹理或直接回传原图;仅保留产品主体并保证主体结构、轮廓比例、部件关系和边缘完整自然,允许为新背景调整朝向、角度和透视。";
|
||||
let sceneFusionRoundRobinCursor = 0;
|
||||
@ -214,6 +215,13 @@ function getSceneFusionCandidatePriority(candidate: SceneFusionModelCandidate):
|
||||
return score;
|
||||
}
|
||||
|
||||
function isSceneFusionReviewRejectError(message: string): boolean {
|
||||
return (
|
||||
message.includes("生成结果未通过替换质检") ||
|
||||
message.includes("生成结果疑似回传产品图")
|
||||
);
|
||||
}
|
||||
|
||||
function buildPreRmbgCandidateUrls(request: Request): string[] {
|
||||
const urls: string[] = [];
|
||||
const requestUrl = new URL(request.url);
|
||||
@ -419,10 +427,12 @@ async function detectProductNameWithAgent(imageUrl: string): Promise<{
|
||||
} | null> {
|
||||
const prompt = [
|
||||
"你是电商图片分析助手。",
|
||||
"请识别图片中最核心、最主要的产品主体名称。",
|
||||
"请识别图片中最核心、最主要、应被用于替换的产品主体名称。",
|
||||
"要求:",
|
||||
"- 名称精简,2-8个字,尽量包含材质/品类(如:皮质沙发、木质餐椅、陶瓷花瓶)",
|
||||
"- 不要返回颜色描述句子,不要返回背景和场景词",
|
||||
"- 如果画面里有杂志、杯子、蜡烛、摆件、文字、Logo、包装、背景或装饰附件,只把它们当作干扰项,不要作为产品主体返回",
|
||||
"- 如果产品图里有多个物体,优先选择占画面最大、最像商品主卖点、可独立售卖的主体",
|
||||
"- 不要返回颜色描述句子,不要返回背景和场景词,不要返回附件名",
|
||||
"仅返回JSON:",
|
||||
'{\"productName\":\"名称\",\"confidence\":0.0}',
|
||||
].join("\n");
|
||||
@ -463,12 +473,14 @@ async function detectTargetNameWithAgent(params: {
|
||||
"你是场景替换识别助手。",
|
||||
`图1是待融合的产品参考图,产品名称提示:${params.productNameHint || "该产品"}`,
|
||||
"图2是待处理的场景图。",
|
||||
"请识别图2里最应该被图1产品替换的目标物体,并给出简短位置描述,帮助后续模型准确定位。",
|
||||
"请识别图2里最应该被图1主产品替换的完整目标物体,并给出简短位置描述,帮助后续模型准确定位。",
|
||||
"要求:",
|
||||
"- 返回“完整物体名”,不要返回局部部件名",
|
||||
"- 名称精简,2-8个字(如:餐椅、沙发、茶几、花瓶)",
|
||||
"- positionHint 用 4-16 个字描述目标大致位置(如:画面中央偏左、前景靠窗处、餐桌区域)",
|
||||
"- replaceCue 用 4-20 个字描述该目标最醒目的识别特征(如:深色办公椅、木质圆餐桌)",
|
||||
"- 不要把产品图里的附件、文字、Logo、装饰物当成目标;目标必须是图2中需要被移除并替换的完整原物体",
|
||||
"- 如果图2里有多个同类物体,优先选择与图1主产品用途/体量最接近、画面中最醒目的那个",
|
||||
"- 如果无法确定,返回最主要主体物体名,并尽量给出位置",
|
||||
"仅返回JSON:",
|
||||
'{\"targetName\":\"名称\",\"positionHint\":\"位置\",\"replaceCue\":\"识别特征\",\"confidence\":0.0}',
|
||||
@ -872,6 +884,7 @@ function buildSceneFusionCandidatePool(
|
||||
if (!entry?.model?.isEnabled) return false;
|
||||
if (!entry?.model?.supportsImageGen) return false;
|
||||
if (entry?.model?.isSubModel) return false;
|
||||
if (entry?.model?.excludeFromFailover) return false;
|
||||
return true;
|
||||
})
|
||||
.map((entry) => ({
|
||||
@ -1393,15 +1406,17 @@ function buildPrompt(
|
||||
|
||||
if (sceneMode === "random-bg") {
|
||||
const subject = productName || "产品";
|
||||
prompt = `请以第一张图片中的${subject}为唯一主体,对第二张图片进行背景重绘。要求:1)必须保持${subject}核心结构、轮廓比例、部件数量、材质颜色和主要设计细节与第一张图一致,不要改造成另一款产品;2)允许调整主体位置、大小、角度、朝向和透视以匹配新背景,不要把角度变化当成结构改变;3)背景需要完整重建并与原图明显不同;4)光影透视自然,输出商业摄影质感。`;
|
||||
prompt = `请以第一张图片中的${subject}为唯一商品主体,对第二张图片进行背景重绘。要求:1)只保留${subject},忽略第一张图中的杂志、杯子、蜡烛、摆件、文字、Logo、包装、背景和装饰附件;2)必须保持${subject}核心结构、轮廓比例、部件数量、材质颜色和主要设计细节与第一张图一致,不要改造成另一款产品;3)允许调整主体位置、大小、角度、朝向和透视以匹配新背景,不要把角度变化当成结构改变;4)背景需要完整重建并与原图明显不同;5)光影透视自然,输出商业摄影质感。`;
|
||||
} else {
|
||||
const subject = productName || "产品";
|
||||
const targetSubject = targetName || "场景主主体";
|
||||
const locationHints = [positionHint, replaceCue].filter(Boolean).join(",");
|
||||
const subjectLock =
|
||||
`主产品锁定:第一张图中只有${subject}是要替换进场景的商品主体,必须忽略杂志、杯子、蜡烛、摆件、文字、Logo、包装、背景和其他装饰附件,不要把这些附件复制到结果图。`;
|
||||
if (targetName) {
|
||||
prompt = `请参考第一张图片中的${subject},仅替换第二张图片中的${targetSubject},不要改成全新场景。要求:1)必须保持${subject}核心结构、轮廓比例、部件数量、材质颜色和主要设计细节与第一张图一致,不要增删关键部件或改造成另一款产品;2)先移除第二张图中原有的${targetSubject},再将${subject}放入其原位置;3)允许调整${subject}的大小、角度、朝向、光影和透视,使其与第二张图自然融合,角度变化本身是允许的;4)结果中不得同时完整保留原${targetSubject}和新的${subject}。`;
|
||||
prompt = `${subjectLock} 请参考第一张图片中的${subject},仅替换第二张图片中的${targetSubject},不要改成全新场景。要求:1)必须保持${subject}核心结构、轮廓比例、部件数量、材质颜色和主要设计细节与第一张图一致,不要增删关键部件或改造成另一款产品;2)先完整移除第二张图中原有的${targetSubject},再将${subject}放入其原位置,禁止在原${targetSubject}表面直接叠加;3)允许调整${subject}的大小、角度、朝向、光影和透视,使其与第二张图自然融合,角度变化本身是允许的;4)保留第二张图的主要背景、机位、透视线、空间关系和光源方向;5)结果中不得同时完整保留原${targetSubject}和新的${subject}。`;
|
||||
} else {
|
||||
prompt = `请参考第一张图片中的${subject},将其自然地融合到第二张图片的场景主主体位置。要求:1)必须保持${subject}核心结构、轮廓比例、部件数量、材质颜色和主要设计细节与第一张图一致,不要改造成另一款产品;2)优先替换第二张图中最主要的同类主体,不要只做风格微调;3)允许为了匹配场景调整${subject}角度、朝向、大小和透视,角度变化不代表结构变化;4)注意光影和透视关系使融合自然。`;
|
||||
prompt = `${subjectLock} 请参考第一张图片中的${subject},将其自然地融合到第二张图片的场景主主体位置。要求:1)必须保持${subject}核心结构、轮廓比例、部件数量、材质颜色和主要设计细节与第一张图一致,不要改造成另一款产品;2)优先替换第二张图中最主要、用途和体量最接近的同类完整主体,不要只做风格微调;3)先移除原主体再放入${subject},禁止叠加原物体;4)允许为了匹配场景调整${subject}角度、朝向、大小和透视,角度变化不代表结构变化;5)保留第二张图主要背景、机位、透视线、空间关系和光源方向,注意光影和透视关系使融合自然。`;
|
||||
}
|
||||
if (locationHints) {
|
||||
prompt = `${prompt} 待替换目标定位:${locationHints}。`;
|
||||
@ -1972,7 +1987,10 @@ async function processSceneWithDiversity(
|
||||
markSceneFusionCandidateFailed(candidate, params.modelCooldown);
|
||||
// Batch processing can fail because of per-image inputs, review gates, or echo checks.
|
||||
// Keep these failures local to this request so they do not auto-disable shared models.
|
||||
console.error("[SceneFusion] Candidate failed, try next:", {
|
||||
const logCandidateFailure = isSceneFusionReviewRejectError(errorMessage)
|
||||
? console.warn
|
||||
: console.error;
|
||||
logCandidateFailure("[SceneFusion] Candidate failed, try next:", {
|
||||
requestId: params.requestId,
|
||||
sceneIndex: params.sceneIndex,
|
||||
attempt: attemptIndex + 1,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user