diff --git a/app/api/canvas/local-edit/route.ts b/app/api/canvas/local-edit/route.ts index 0e13e4003..b24303720 100644 --- a/app/api/canvas/local-edit/route.ts +++ b/app/api/canvas/local-edit/route.ts @@ -399,6 +399,7 @@ function compareScaleAdjustProviderCandidates( function resolveScaleAdjustPreferredModelId(params: { configuredModelId: string; honorRequestedModelBeforeGpt?: boolean; + preferMaskCapableGpt?: boolean; requestedModelId: string; models: AiModelWithProviderForSelection[]; }) { @@ -428,6 +429,14 @@ function resolveScaleAdjustPreferredModelId(params: { params.requestedModelId || params.configuredModelId ) ); + if (params.preferMaskCapableGpt) { + const maskCapableGptImage2 = gptImage2Candidates.filter( + isScaleAdjustMaskCapableModel + ); + if (maskCapableGptImage2[0]) { + return maskCapableGptImage2[0].model.id; + } + } if (gptImage2Candidates[0]) { return gptImage2Candidates[0].model.id; } @@ -652,6 +661,20 @@ function hasScaleAdjustEnlargeTarget( }); } +function hasScaleAdjustShrinkTarget( + regions: NormalizedLocalEditRegion[], + scalePercent?: ScaleAdjustPercent | null +) { + return regions.some((region) => { + const targetRect = getScaleAdjustTargetRect(region, scalePercent); + const widthFactor = + region.rect.width > 0 ? targetRect.width / region.rect.width : 1; + const heightFactor = + region.rect.height > 0 ? targetRect.height / region.rect.height : 1; + return widthFactor < 0.92 || heightFactor < 0.92; + }); +} + function hasScaleAdjustStructureTarget( regions: NormalizedLocalEditRegion[], scalePercent?: ScaleAdjustPercent | null @@ -2584,6 +2607,7 @@ async function buildScaleAdjustVisualLayoutGuideBuffer(params: { } const shouldUseShrinkCutoutDraft = + process.env.CANVAS_SCALE_ADJUST_ENABLE_RMBG_SHRINK_CUTOUT === "1" && !structureLockedDraft && sourceRaw && userId && @@ -3739,6 +3763,14 @@ export async function POST(request: NextRequest) { const isScaleAdjustOperation = operation === SCALE_ADJUST_OPERATION && (hasScaleAdjustTargetRects || scalePercent !== null); + const hasScaleAdjustEnlarge = isScaleAdjustOperation + ? hasScaleAdjustEnlargeTarget(regions, scalePercent) + : false; + const hasScaleAdjustShrink = isScaleAdjustOperation + ? hasScaleAdjustShrinkTarget(regions, scalePercent) + : false; + const preferScaleAdjustMaskCapableModel = + hasScaleAdjustShrink && !hasScaleAdjustEnlarge; const displayPrompt = buildLocalEditDisplayPrompt({ operation, scalePercent }); const resolvedAspectRatio = resolveLocalEditAspectRatio( body.aspectRatio, @@ -3756,10 +3788,8 @@ export async function POST(request: NextRequest) { const detailFixedModel = isScaleAdjustOperation ? resolveScaleAdjustPreferredModelId({ configuredModelId: configuredDetailModel, - honorRequestedModelBeforeGpt: hasScaleAdjustEnlargeTarget( - regions, - scalePercent - ), + honorRequestedModelBeforeGpt: hasScaleAdjustEnlarge, + preferMaskCapableGpt: preferScaleAdjustMaskCapableModel, requestedModelId: requestedModel || "", models: scaleAdjustModelCandidates, }) @@ -3800,7 +3830,9 @@ export async function POST(request: NextRequest) { useScaleAdjustCoordinatePrompt && !useScaleAdjustVisualLayoutGuide; const useScaleAdjustStructureLockedPatchWorkflow = isScaleAdjustOperation && - hasScaleAdjustStructureTarget(regions, scalePercent); + hasScaleAdjustStructureTarget(regions, scalePercent) && + (!preferScaleAdjustMaskCapableModel || + !isScaleAdjustMaskCapableModel(resolvedScaleAdjustModelEntry)); const useScaleAdjustEditMask = isScaleAdjustOperation && !useScaleAdjustStructureLockedPatchWorkflow && @@ -4159,6 +4191,8 @@ export async function POST(request: NextRequest) { ? scaleAdjustPatchReference.structureLockedDraft ? "ai-patch-workspace-structure-locked-draft-v85-one-shot" : "ai-patch-workspace-draft-v73-rmbg-cutout-soft-wipe-one-shot" + : useScaleAdjustEditMask + ? "mask-edit-gpt-image-2-scale-shrink-v74-one-shot" : useFalScaleAdjustCoordinatePrompt ? "fal-safe-marked-photo-box-guide-no-old-crop-v44-one-shot" : useScaleAdjustVisualLayoutGuide