diff --git a/app/(chat)/api/chat/_lib/detail-replacement.ts b/app/(chat)/api/chat/_lib/detail-replacement.ts index 9f82da663..da5a7de3f 100644 --- a/app/(chat)/api/chat/_lib/detail-replacement.ts +++ b/app/(chat)/api/chat/_lib/detail-replacement.ts @@ -1053,7 +1053,7 @@ function applyDetailReplacementScenePlanGuards( ...next, pageKind: "action_poster", generationRoute: "people_relation_locked", - promptPackPolicy: "forbid", + promptPackPolicy: "soft", textPolicy: next.textPolicy === "free" ? "lock" : next.textPolicy, peoplePolicy: "preserve_relation", useModelImage: params.hasModelImage, @@ -1064,21 +1064,21 @@ function applyDetailReplacementScenePlanGuards( "参考图是带明确人物动作的详情海报,必须按参考图人数、动作、姿态和版式生成类似图。", routeReason: appendUniqueInstruction( next.routeReason, - "命中多人围坐/承重测试等参考动作海报,参考图语义优先,禁止套用前置场景词包。", + "命中多人围坐/承重测试等参考动作海报,参考动作和版式优先,但前置场景词包必须软生效以避免原图复刻。", 240, ), sceneSummary: appendUniqueInstruction( next.sceneSummary, - "按参考图做同版式类似图:保留人物数量、围坐/试坐/承重动作、产品形状、机位和图文关系,只做必要产品/材质/视觉区替换。", + "按参考图做同版式类似图:保留人物数量、围坐/试坐/承重动作、产品形状、机位和图文关系,同时按前置词包重建图片框内背景、空间、软装和灯光。", 320, ), generationPrompt: appendUniqueInstruction( next.generationPrompt, - "本屏是参考动作海报,不使用前置词包;标题/标签中的“多人围坐、聚餐、横向受力测试、单侧承重、重心平稳”等语义是硬约束。必须根据参考图做一张同版式、同动作、同人物关系的类似详情图:多人就保持多人围坐,承重就保持人物坐在产品上的受力姿态;产品主体的形状、外轮廓、长宽比例、桌面圆角、腿部结构和透视角度必须跟参考图一致。禁止生成无关餐厨空间、走动路人、无人空场景或改成另一种产品形状。", + "本屏是参考动作海报,前置场景词包必须软生效:标题/标签中的“多人围坐、聚餐、横向受力测试、单侧承重、重心平稳”等语义是硬约束。必须根据参考图做一张同版式、同动作、同人物关系的类似详情图:多人就保持多人围坐,承重就保持人物坐在产品上的受力姿态;产品主体的形状、外轮廓、长宽比例、桌面圆角、腿部结构和透视角度必须跟参考图一致;同时要按前置词包明显重建图片框内旧背景、空间、软装、灯光和产品场景,不能只复刻原图。禁止生成走动路人、无人空场景或改成另一种产品形状。", ), avoidSummary: appendUniqueInstruction( next.avoidSummary, - "不要让前置厨房/餐厨/软装词包覆盖参考动作,不要把多人改成单人或无人,不要把坐姿/承重动作改成走动人物,不要改变产品形状。", + "不要让前置词包覆盖参考动作,不要把多人改成单人或无人,不要把坐姿/承重动作改成走动人物,不要改变产品形状;也不要只原图复刻或轻微修饰。", 340, ), whiteBackgroundLikely: next.whiteBackgroundLikely || visualProfileSuggestsLightBase, @@ -1557,8 +1557,10 @@ export function buildHeuristicReplacementScenePlan(params: { : "direct_passthrough"; const promptPackPolicy: DetailReplacementPromptPackPolicy = params.shouldReplace && isDetailReplacement && !isProductOnly - ? shouldProtectFallbackWhiteLayout || shouldProtectFallbackReferencePosterAction + ? shouldProtectFallbackWhiteLayout ? "forbid" + : shouldProtectFallbackReferencePosterAction + ? "soft" : fallbackHasPeopleAction ? shouldRebuildFallbackWhiteScene ? "soft" @@ -1611,7 +1613,7 @@ export function buildHeuristicReplacementScenePlan(params: { ? shouldProtectFallbackWhiteLayout ? "兜底命中产品尺寸说明页,按白底抠图和尺寸标注执行,不使用词包。" : shouldProtectFallbackReferencePosterAction - ? "兜底命中参考动作海报,保留人物动作和产品形状,不使用词包。" + ? "兜底命中参考动作海报,保留人物动作和产品形状,同时软吃词包重建背景和产品场景。" : fallbackHasPeopleAction ? "兜底命中人物/动作/使用场景,按人物关系锁定并允许词包重建背景和产品场景。" : shouldProtectFallbackLayout @@ -1635,7 +1637,7 @@ export function buildHeuristicReplacementScenePlan(params: { : shouldProtectFallbackWhiteLayout ? "产品主体抠出在白底或米白底中展示,保留产品尺寸标题、单位、尺寸线、尺寸数字和原版式关系。" : shouldProtectFallbackReferencePosterAction - ? "按参考图动作海报做类似图,保留人物数量、动作、产品形状、机位、标题标签和图文关系,不套用前置词包。" + ? "按参考图动作海报做类似图,保留人物数量、动作、产品形状、机位、标题标签和图文关系,同时按前置词包重建图片框内背景、空间、软装和灯光。" : fallbackHasPeopleAction ? "保留参考图人物数量、动作、互动关系、文字层级和版式骨架,同时按工作流目标重建背景、产品、软装和灯光。" : shouldProtectFallbackLayout @@ -1660,7 +1662,7 @@ export function buildHeuristicReplacementScenePlan(params: { : shouldProtectFallbackWhiteLayout ? "白底产品尺寸说明图,只允许产品抠图和尺寸标注,不引入室内场景。" : shouldProtectFallbackReferencePosterAction - ? "参考图动作海报语义优先,做同动作同版式类似图,不引入前置空间词包。" + ? "参考图动作海报语义优先,做同动作同版式类似图,前置词包只用于改造图片框内背景、空间、软装和灯光。" : fallbackHasPeopleAction ? "人物动作和关系保真,背景、产品场景、软装和灯光按前置词包明显重建。" : shouldProtectFallbackLayout @@ -1687,7 +1689,7 @@ export function buildHeuristicReplacementScenePlan(params: { : isDetailReplacement && shouldProtectFallbackWhiteLayout ? `当前参考图按产品尺寸说明页处理:不使用前置词包;必须把产品主体抠出放在白底/米白底上,保留标题“产品尺寸”、单位 cm、尺寸箭头/尺寸线/数字标注和原版式位置;禁止生成室内场景、人物、椅子、柜体、灯具、花瓶或软装背景;产品形状、桌面比例、腿部结构、圆角和透视必须跟参考图一致。${params.reason}` : isDetailReplacement && shouldProtectFallbackReferencePosterAction - ? `当前参考图按动作海报处理:不使用前置词包;必须根据参考图做同版式类似图,保留标题标签、人物数量、多人围坐/试坐/单侧承重/受力测试等动作、产品外轮廓、长宽比例、桌面圆角、腿部结构、透视角度和机位;禁止生成无关餐厨空间、走动人物、无人空场景或另一种产品形状。${params.reason}` + ? `当前参考图按动作海报处理:必须软吃前置词包;根据参考图做同版式类似图,保留标题标签、人物数量、多人围坐/试坐/单侧承重/受力测试等动作、产品外轮廓、长宽比例、桌面圆角、腿部结构、透视角度和机位;同时按前置词包明显重建图片框内旧背景、空间、软装、灯光和产品场景,禁止走动人物、无人空场景、原图复刻或另一种产品形状。${params.reason}` : isDetailReplacement && fallbackHasPeopleAction ? `当前参考图按人物/动作详情页处理:必须保留参考图中的人物数量、动作、朝向、互动关系和出镜比例,同时使用前置工作流词包明显重建图片框内旧背景、产品、空间、软装和灯光;禁止生成白底单品图或无人物空场景,保留文字区、版式骨架、机位和信息层级。${params.reason}` : isDetailReplacement && shouldProtectFallbackLayout @@ -2188,7 +2190,7 @@ export async function analyzeReplacementExecutionPlan(params: { ? `像素初筛:nearWhite=${referenceVisualProfile.nearWhitePixelRatio.toFixed(2)}, lightLowSaturation=${referenceVisualProfile.lightLowSaturationPixelRatio.toFixed(2)}, topLight=${referenceVisualProfile.topLightLowSaturationPixelRatio.toFixed(2)}, borderLight=${referenceVisualProfile.borderLightLowSaturationPixelRatio.toFixed(2)}, dark=${referenceVisualProfile.darkPixelRatio.toFixed(2)}, likelyWhiteLayout=${referenceVisualProfile.likelyWhiteLayout ? "true" : "false"}, likelyWhiteScene=${referenceVisualProfile.likelyWhiteScene ? "true" : "false"}。${referenceVisualProfile.reason}` : "", referenceVisualProfile?.likelyWhiteLayout - ? "像素初筛已经命中白底/浅色说明页候选:请继续读取画面文字和图像语义。若存在标题、标签、参数、尺寸、卖点、图标、白底图片区、圆角图片区、人物动作海报或明显留白排版,generationRoute 必须是 layout_preserve_replace、copy_locked_regenerate 或 people_relation_locked,promptPackPolicy 必须 forbid;人物动作只能按参考图保留,不允许套用厨房、客厅、灯光、软装等场景词包。" + ? "像素初筛已经命中白底/浅色说明页候选:请继续读取画面文字和图像语义。若存在标题、标签、参数、尺寸、卖点、图标、白底图片区、圆角图片区或明显留白排版,generationRoute 必须是 layout_preserve_replace 或 copy_locked_regenerate,promptPackPolicy 必须 forbid;但如果这是多人围坐、聚餐、试坐、承重、受力测试等人物动作海报,generationRoute 必须是 people_relation_locked,promptPackPolicy 必须 soft:参考图锁动作和版式,前置词包软改造图片框内背景、空间、软装和灯光。" : "", !referenceVisualProfile?.likelyWhiteLayout && referenceVisualProfile?.likelyWhiteScene ? "像素初筛已经命中白/浅色低饱和真实场景:这不是白底说明页。若画面存在真实空间、人物或产品照片,promptPackPolicy 应为 soft 或 allow,必须使用前置工作流词包重建图片框内产品、空间、软装和灯光,使差异清晰可见;但最终仍保持白/浅色低饱和基调,不要改造成深色厨房、黑墙、复杂吊灯或强软装。" @@ -2213,7 +2215,7 @@ export async function analyzeReplacementExecutionPlan(params: { ? "这张参考图可能是场景图、白底说明图、强文案图、人物关系图或纯版式图。你必须先判断它适合哪一种执行路由,再决定是否允许前置工作流词包参与。文字、标题、卖点标签、UI图标、按钮、分割线、品牌标识、留白和排版必须保留。" : "这张参考图不是要求原样保留的场景照片。原图里的沙发、床、柜体、墙面、地面、窗帘、灯具、摆件、桌面道具、背景家具和环境光氛围,都可以在后续生图阶段按前置工作流风格重建。", isDetailReplacement - ? "重要分流例子:如果标题/标签或画面写着“多人围坐、聚餐、横向受力测试、单侧承重、重心依旧平稳、桌体依然稳固”等动作海报语义,这不是通用 prompt pack 场景图;必须 people_relation_locked + promptPackPolicy=forbid,根据参考图做同版式同动作类似图。" + ? "重要分流例子:如果标题/标签或画面写着“多人围坐、聚餐、横向受力测试、单侧承重、重心依旧平稳、桌体依然稳固”等动作海报语义,这不是纯锁版式页;必须 people_relation_locked + promptPackPolicy=soft。参考图决定人物数量、围坐/试坐/承重动作、产品受力关系和版式,前置词包必须参与重建图片框内背景、空间、软装、灯光和产品场景,避免原图复刻。" : "", isDetailReplacement ? "重要分流例子:如果标题或标注写着“产品尺寸、尺寸、单位 cm、160/180/210、90、75、尺寸线、尺寸箭头”等产品尺寸说明语义,必须 layout_preserve_replace + promptPackPolicy=forbid;后续应生成白底/米白底产品抠图和尺寸标注,不允许生成室内场景、椅子、人物、柜体、灯具或软装背景。" @@ -2232,10 +2234,10 @@ export async function analyzeReplacementExecutionPlan(params: { ? "3. 判断 generationRoute:prompt_pack_scene=通用场景图且可吃词包;layout_preserve_replace=锁定版式/白底/产品说明/材质说明,只做有限替换;copy_locked_regenerate=文案与画面强绑定,必须锁文案;people_relation_locked=多人/模特/互动关系图,必须锁人物关系。详情替换不允许 direct_passthrough。" : "3. 提炼 sceneSummary、cameraSummary、placementSummary、preserveSummary、styleSummary、avoidSummary。", isDetailReplacement - ? "4. 判断 promptPackPolicy:纯白底参数/说明/卖点页、产品尺寸页、强图文绑定页、以及标题/标签已经明确动作的详情海报页必须 forbid;通用空间场景必须 allow;只有没有强文案/海报动作绑定的真实人物生活场景,才可以 people_relation_locked + allow/soft。" + ? "4. 判断 promptPackPolicy:纯白底参数/说明/卖点页、产品尺寸页、强图文绑定页必须 forbid;标题/标签已经明确多人围坐、聚餐、试坐、单侧承重、横向受力测试等动作的详情海报页必须 soft,参考图锁动作和版式,前置词包改造背景/产品场景;通用空间场景必须 allow;普通真实人物生活场景可以 people_relation_locked + allow/soft。" : "", isDetailReplacement - ? "4a. 白底/白场景分流规则:白底参数、规格、卖点、产品尺寸、强文案、图标说明、纯版式页或动作测试海报必须 forbid;白/浅色真实场景页只有在没有这些强绑定文字时才使用 soft/allow 词包重造图片框内产品、空间、软装和灯光。" + ? "4a. 白底/白场景分流规则:白底参数、规格、卖点、产品尺寸、强文案、图标说明、纯版式页必须 forbid;动作测试/多人围坐/聚餐/承重海报必须 soft;白/浅色真实场景页在没有强版式绑定时使用 soft/allow 词包重造图片框内产品、空间、软装和灯光。" : "", isDetailReplacement ? "5. 判断 textPolicy:画面中存在营销标题、卖点、编号、参数、标签且与图匹配时必须 lock 或 preserve,避免后续生图改字、混色或重排。" @@ -2249,7 +2251,7 @@ export async function analyzeReplacementExecutionPlan(params: { isProductOnlyDetailReplacement ? "4. 输出 generationPrompt:这是一段给后续生图模型的本屏生成指令,要求只替换产品主体,保留其余背景、文案、排版、装饰和光影完全不变。" : isDetailReplacement - ? "8. 输出 generationPrompt:这是一段给后续生图模型的本屏生成指令。若 promptPackPolicy=forbid,必须明确“不使用前置词包,参考图语义优先”;若是动作海报,必须写清人物数量、围坐/试坐/承重等动作、产品形状和版式必须照参考图;若是产品尺寸页,必须写清白底抠图、尺寸线、单位和数字标注,不允许室内场景;若 promptPackPolicy=allow/soft 且 peoplePolicy=preserve_relation,才明确“保留人物数量/动作/关系与文字层级,同时使用前置词包重建背景/产品场景”。" + ? "8. 输出 generationPrompt:这是一段给后续生图模型的本屏生成指令。若 promptPackPolicy=forbid,必须明确“不使用前置词包,参考图语义优先”;若是动作海报,必须写清人物数量、围坐/试坐/承重等动作、产品形状和版式必须照参考图,同时写清“前置词包软生效,必须重建图片框内背景/空间/软装/灯光/产品场景,不能原图复刻”;若是产品尺寸页,必须写清白底抠图、尺寸线、单位和数字标注,不允许室内场景;若 promptPackPolicy=allow/soft 且 peoplePolicy=preserve_relation,明确“保留人物数量/动作/关系与文字层级,同时使用前置词包重建背景/产品场景”。" : "4. 输出 generationPrompt:这是一段给后续生图模型的本屏生成指令,描述这一屏需要的场景、机位、主体位置、周边环境重建方向以及必须保留的内容。", isProductOnlyDetailReplacement ? "5. sceneSummary、styleSummary 和 generationPrompt 必须强调‘只替换产品,不动其他内容’,不要引导重建场景。" @@ -2589,7 +2591,7 @@ export function buildAgentReplacementPrompt(params: { "你现在做的是“详情参考图背景/场景图替换”,不是重新设计整张详情图。", "【版式锁层规则】把最后一张参考图当成 PSD 模板:文字、标题、编号、卖点标签、按钮、图标、白底/浅色底、留白、分割线、圆角图片框、图片框裁切边界都属于锁定版式层,不允许移动、缩放、重排或重新设计。", isReferencePosterActionPlan - ? "【参考动作海报硬约束】本屏不使用前置词包;必须按照最后一张参考图做同版式类似图。若标题/标签写多人围坐、聚餐、横向受力测试、单侧承重、重心平稳等,人物数量、相对位置、围坐/试坐/承重动作、产品受力关系、产品外轮廓、桌面长宽比例、圆角、腿部结构和透视角度都必须跟参考图一致。" + ? "【参考动作海报硬约束】本屏必须软吃前置词包,但参考图动作和版式优先。若标题/标签写多人围坐、聚餐、横向受力测试、单侧承重、重心平稳等,人物数量、相对位置、围坐/试坐/承重动作、产品受力关系、产品外轮廓、桌面长宽比例、圆角、腿部结构和透视角度都必须跟参考图一致;同时必须按前置词包明显重建图片框内旧背景、空间、软装、灯光和产品场景,不能只原图复刻。" : "", isDimensionDetailPlan ? "【产品尺寸图硬约束】本屏不使用前置词包;必须是白底/米白底产品抠图尺寸说明页。保留标题“产品尺寸”、单位 cm、尺寸线/箭头/数字标注和原版式位置;产品主体外轮廓、长宽比例、圆角、腿部结构和透视必须跟参考图一致;禁止生成室内场景、椅子、柜体、灯具、花瓶、人物或软装背景。"