diff --git a/app/api/canvas/local-edit/route.ts b/app/api/canvas/local-edit/route.ts index b9175152a..84c395c12 100644 --- a/app/api/canvas/local-edit/route.ts +++ b/app/api/canvas/local-edit/route.ts @@ -2047,21 +2047,28 @@ function buildScaleAdjustPatchPrompt( patchReference: ScaleAdjustPatchReference, sourceSize: { width: number; height: number }, cropReferences: ScaleAdjustCropReference[] = [], - options: { targetDraftPrimary?: boolean } = {} + options: { includeSourceReference?: boolean; targetDraftPrimary?: boolean } = {} ) { const targetDraftPrimary = options.targetDraftPrimary === true; - const sourceInputIndex = targetDraftPrimary ? 2 : 1; + const includeSourceReference = options.includeSourceReference !== false; + const sourceInputIndex = targetDraftPrimary && includeSourceReference ? 2 : 1; const draftInputIndex = targetDraftPrimary ? 1 : 2; + const cropReferenceStartIndex = + targetDraftPrimary && !includeSourceReference ? 2 : 3; const firstInputRole = targetDraftPrimary - ? "Input image 1 is the rough edited target-layout crop. It is the hard layout target: the selected furniture size and center in the final output must match this draft, but the rough wash, ghosted old footprint, placeholder shadow, blur, and patch artifacts must be cleaned." + ? includeSourceReference + ? "Input image 1 is the rough edited target-layout crop. It is the hard layout target: the selected furniture size and center in the final output must match this draft, but the rough wash, ghosted old footprint, placeholder shadow, blur, and patch artifacts must be cleaned." + : "Input image 1 is the rough edited target-layout crop and the only crop base. It is the hard layout target: the selected furniture size and center in the final output must match this draft. Clean away the rough wash, ghosted old footprint, placeholder shadow, blur, and patch artifacts." : "Input image 1 is the exact crop from the original photo and is the locked crop base."; const secondInputRole = targetDraftPrimary - ? "Input image 2 is the original clean crop. Use it only for stable crop framing, background texture, lighting, perspective, and furniture identity. Do not restore the selected furniture to its old larger size from this image." + ? includeSourceReference + ? "Input image 2 is the original clean crop. Use it only for stable crop framing, background texture, lighting, perspective, and furniture identity. Do not restore the selected furniture to its old larger size from this image." + : "" : "Input image 2 is a rough target-layout draft of the same crop. It is the hard layout target for the selected furniture size and position. Use it to understand the final footprint and newly visible background area, then remove any rough seams, washed areas, placeholder shadows, blur, or patch artifacts from that draft."; const cropLines = cropReferences .map( (reference, index) => - `Input image ${index + 3}: clean identity crop for Region ${reference.regionIndex}; use it only to recognize the target furniture shape and materials.` + `Input image ${index + cropReferenceStartIndex}: clean identity crop for Region ${reference.regionIndex}; use it only to recognize the target furniture shape and materials, not its old size.` ) .join("\n"); const regionLines = regions @@ -2093,7 +2100,7 @@ function buildScaleAdjustPatchPrompt( : "move the same furniture to the final footprint"; const cropNote = cropIndex >= 0 - ? ` Input image ${cropIndex + 3} is the clean identity reference for this exact furniture.` + ? ` Input image ${cropIndex + cropReferenceStartIndex} is the clean identity reference for this exact furniture.` : ""; return `Region ${region.index}: current search area inside input image ${sourceInputIndex} crop is x=${sourceInPatch.left}, y=${sourceInPatch.top}, w=${sourceInPatch.width}, h=${sourceInPatch.height}; final visual footprint inside input image ${draftInputIndex} / output crop is x=${targetInPatch.left}, y=${targetInPatch.top}, w=${targetInPatch.width}, h=${targetInPatch.height}; requested scale width=${widthFactor.toFixed(2)}, height=${heightFactor.toFixed(2)}. User request: ${region.prompt || action}. Main action: ${action}. The final object must be much closer to the final footprint than to the current search area.${cropNote}`; }) @@ -2111,7 +2118,9 @@ function buildScaleAdjustPatchPrompt( "Hard failure condition: if the selected furniture remains near its original old size, the answer is wrong. The output must visibly reduce the furniture footprint to the target draft footprint.", "Do not output boxes, lines, labels, coordinate marks, UI marks, text, arrows, overlays, rough layout artifacts, rectangular patch edges, or a full-room image.", targetDraftPrimary - ? "中文硬约束:输入图1是目标大小/位置草稿,必须按它的小尺寸家具布局输出;输入图2只是原始质感和背景参考,绝对不要把家具恢复成输入图2里的旧大尺寸。只输出同一裁切范围的干净局部照片,去掉草稿中的泛白、残影和拼接感。" + ? includeSourceReference + ? "中文硬约束:输入图1是目标大小/位置草稿,必须按它的小尺寸家具布局输出;输入图2只是原始质感和背景参考,绝对不要把家具恢复成输入图2里的旧大尺寸。只输出同一裁切范围的干净局部照片,去掉草稿中的泛白、残影和拼接感。" + : "中文硬约束:输入图1是唯一的裁切底图和目标大小/位置草稿,必须按它的小尺寸家具布局输出;后续家具识别图只看材质形状,不看旧尺寸。只输出同一裁切范围的干净局部照片,去掉草稿中的泛白、残影和拼接感。" : "中文硬约束:只输出输入图1同一裁切范围的干净局部照片;输入图2是目标大小/位置草稿,必须按它的小尺寸家具布局输出,不是要保留旧尺寸。目标家具必须相对原图产生明显比例变化,非目标背景和裁切边缘要稳定自然。", "", "Region instructions:", @@ -2403,6 +2412,7 @@ export async function POST(request: NextRequest) { }) : []; const useScaleAdjustPatchTargetDraftPrimary = Boolean(scaleAdjustPatchReference); + const includeScaleAdjustPatchSourceReference = false; const prompt = isScaleAdjustOperation ? scaleAdjustPatchReference ? buildScaleAdjustPatchPrompt( @@ -2411,7 +2421,10 @@ export async function POST(request: NextRequest) { scaleAdjustPatchReference, { width: sourceWidth, height: sourceHeight }, scaleAdjustCropReferences, - { targetDraftPrimary: useScaleAdjustPatchTargetDraftPrimary } + { + includeSourceReference: includeScaleAdjustPatchSourceReference, + targetDraftPrimary: useScaleAdjustPatchTargetDraftPrimary, + } ) : useProviderTextOnlyCoordinatePrompt ? buildScaleAdjustTextOnlyPrompt( @@ -2460,7 +2473,9 @@ export async function POST(request: NextRequest) { ? useScaleAdjustPatchTargetDraftPrimary ? [ scaleAdjustPatchReference.targetDraftUrl, - scaleAdjustPatchReference.sourceCropUrl, + ...(includeScaleAdjustPatchSourceReference + ? [scaleAdjustPatchReference.sourceCropUrl] + : []), ...scaleAdjustCropReferenceImageUrls, ...manualRegionReferenceImageUrls, ] @@ -2549,7 +2564,13 @@ export async function POST(request: NextRequest) { ? resolvedScaleAdjustModelEntry?.provider?.type || null : null, cleanSourceReferenceIndex: - scaleAdjustPatchReference && useScaleAdjustPatchTargetDraftPrimary ? 2 : 1, + scaleAdjustPatchReference && + useScaleAdjustPatchTargetDraftPrimary && + !includeScaleAdjustPatchSourceReference + ? null + : scaleAdjustPatchReference && useScaleAdjustPatchTargetDraftPrimary + ? 2 + : 1, configuredDetailModelId: configuredDetailModel || null, detailFixedModelApplied: Boolean(detailFixedModel), detailFixedModelId: detailFixedModel || null, @@ -2560,7 +2581,9 @@ export async function POST(request: NextRequest) { scaleAdjustPatchWorkflowApplied: Boolean(scaleAdjustPatchReference), scaleAdjustPatchReferenceOrder: scaleAdjustPatchReference && useScaleAdjustPatchTargetDraftPrimary - ? "target-draft-source-identity" + ? includeScaleAdjustPatchSourceReference + ? "target-draft-source-identity" + : "target-draft-identity" : scaleAdjustPatchReference ? "source-target-draft-identity" : null,