Fix canvas scale adjust local edit build

This commit is contained in:
134 2026-07-09 12:00:42 +08:00
parent accaaad8f1
commit c9ed662809

View File

@ -199,6 +199,32 @@ function inferClosestAspectRatio(width: number, height: number) {
return closest;
}
function inferScaleAdjustPatchAspectRatio(width: number, height: number) {
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
return "1:1";
}
const sourceRatio = width / height;
const providerSafeRatios = [
"1:1",
"2:3",
"3:2",
"3:4",
"4:3",
"9:16",
"16:9",
] as const;
let closest: (typeof providerSafeRatios)[number] = "1:1";
let closestDiff = Number.POSITIVE_INFINITY;
for (const candidate of providerSafeRatios) {
const diff = Math.abs(parseAspectRatioValue(candidate) - sourceRatio);
if (diff < closestDiff) {
closest = candidate;
closestDiff = diff;
}
}
return closest;
}
function resolveLocalEditAspectRatio(input: unknown, sourceWidth: number, sourceHeight: number) {
const requested = String(input || "").trim();
if (
@ -339,7 +365,26 @@ function isScaleAdjustFalNanoBananaEditModel(
const label = `${entry.model.displayName || ""} ${entry.model.modelId || ""}`
.toLowerCase()
.replace(/\s+/g, " ");
return label.includes("/edit") || /\bedit\b/.test(label);
const capabilities =
entry.model.capabilities && typeof entry.model.capabilities === "object"
? (entry.model.capabilities as Record<string, unknown>)
: {};
const defaultParams =
entry.model.defaultParams && typeof entry.model.defaultParams === "object"
? (entry.model.defaultParams as Record<string, unknown>)
: {};
const editEndpoint =
typeof capabilities.editEndpoint === "string"
? capabilities.editEndpoint
: typeof defaultParams.editEndpoint === "string"
? defaultParams.editEndpoint
: "";
return (
label.includes("/edit") ||
/\bedit\b/.test(label) ||
capabilities.autoRouteEditEndpoint === true ||
editEndpoint.toLowerCase().includes("/edit")
);
}
function isScaleAdjustHealthyModel(
@ -761,6 +806,51 @@ function expandRectWithMargins(
};
}
function expandRectToProviderAspectLimit(
rect: NormalizedLocalEditRegion["rect"],
sourceWidth: number,
sourceHeight: number,
maxAspectRatio = 3
) {
if (
!Number.isFinite(sourceWidth) ||
!Number.isFinite(sourceHeight) ||
sourceWidth <= 0 ||
sourceHeight <= 0 ||
maxAspectRatio <= 1
) {
return rect;
}
const pixelWidth = rect.width * sourceWidth;
const pixelHeight = rect.height * sourceHeight;
if (pixelWidth <= 0 || pixelHeight <= 0) return rect;
const ratio = pixelWidth / pixelHeight;
let nextWidth = rect.width;
let nextHeight = rect.height;
if (ratio > maxAspectRatio) {
nextHeight = Math.min(1, pixelWidth / maxAspectRatio / sourceHeight);
} else if (ratio < 1 / maxAspectRatio) {
nextWidth = Math.min(1, (pixelHeight / maxAspectRatio) / sourceWidth);
} else {
return rect;
}
const centerX = rect.x + rect.width / 2;
const centerY = rect.y + rect.height / 2;
const x = clamp(centerX - nextWidth / 2, 0, Math.max(0, 1 - nextWidth));
const y = clamp(centerY - nextHeight / 2, 0, Math.max(0, 1 - nextHeight));
return {
x,
y,
width: nextWidth,
height: nextHeight,
};
}
function getRectUnion(
leftRect: NormalizedLocalEditRegion["rect"],
rightRect: NormalizedLocalEditRegion["rect"]
@ -938,6 +1028,40 @@ function getScaleAdjustPatchWorkspaceRect(
return workspaceRects.reduce((combined, rect) => getRectUnion(combined, rect));
}
function shouldUseScaleAdjustEdgeLockedFullFrameReference(params: {
regions: NormalizedLocalEditRegion[];
scalePercent?: ScaleAdjustPercent | null;
sourceHeight: number;
sourceWidth: number;
}) {
const { regions, scalePercent, sourceHeight, sourceWidth } = params;
if (!regions.length || !hasScaleAdjustShrinkTarget(regions, scalePercent)) {
return false;
}
if (!regions.some((region) => isScaleAdjustFurnitureProductLikePrompt(region.prompt))) {
return false;
}
const workspaceRect = expandRectToProviderAspectLimit(
getScaleAdjustPatchWorkspaceRect(regions, scalePercent),
sourceWidth,
sourceHeight
);
const pixelWidth = workspaceRect.width * sourceWidth;
const pixelHeight = workspaceRect.height * sourceHeight;
if (pixelWidth <= 0 || pixelHeight <= 0) return false;
const ratio = pixelWidth / pixelHeight;
const touchesCanvasEdge =
workspaceRect.x <= 0.002 ||
workspaceRect.y <= 0.002 ||
workspaceRect.x + workspaceRect.width >= 0.998 ||
workspaceRect.y + workspaceRect.height >= 0.998;
const nearProviderAspectLimit = ratio <= 0.42 || ratio >= 2.4;
return touchesCanvasEdge && nearProviderAspectLimit;
}
function expandPixelRectForCrop(params: {
height: number;
pixelRect: NormalizedLocalEditRegion["pixelRect"];
@ -1336,6 +1460,13 @@ function isScaleAdjustPersonLikePrompt(prompt: string) {
);
}
function isScaleAdjustFurnitureProductLikePrompt(prompt: string) {
const text = normalizeScaleAdjustModelText(prompt);
return /furniture|product|commodity|goods|object|item|subject|sofa|couch|chair|table|desk|cabinet|shelf|bed|bench|lamp|basket|rack|stool|drawer|wardrobe|主物体|主体|物体|商品|产品|家具|沙发|椅|桌|柜|架|床|凳|灯|篮|抽屉|衣柜/.test(
text
);
}
function hasScaleAdjustPersonPixelSignal(params: {
box: { left: number; top: number; width: number; height: number };
raw: Buffer;
@ -2781,7 +2912,11 @@ async function createScaleAdjustPatchReference(params: {
sourceWidth,
userId,
} = params;
const workspaceRect = getScaleAdjustPatchWorkspaceRect(regions, scalePercent);
const workspaceRect = expandRectToProviderAspectLimit(
getScaleAdjustPatchWorkspaceRect(regions, scalePercent),
sourceWidth,
sourceHeight
);
const workspacePixelRect = rectToPixels(workspaceRect, sourceWidth, sourceHeight);
const shouldUseStructureLockedDraft = hasScaleAdjustStructureTarget(
regions,
@ -3890,7 +4025,7 @@ export async function POST(request: NextRequest) {
const useFalScaleAdjustCoordinatePrompt =
useScaleAdjustCoordinatePrompt &&
resolvedScaleAdjustModelEntry?.provider?.type === "fal-image" &&
!useScaleAdjustFullFrameFalEdit;
getScaleAdjustModelFamily(resolvedScaleAdjustModelEntry) === "nano-banana-2";
const useScaleAdjustVisualLayoutGuide =
useScaleAdjustCoordinatePrompt &&
!useFalScaleAdjustCoordinatePrompt &&
@ -4152,7 +4287,7 @@ export async function POST(request: NextRequest) {
const imageRequest: CanvasGenerateImageRequest = {
allowFailover: isScaleAdjustOperation ? false : undefined,
aspectRatio: scaleAdjustPatchReference
? inferClosestAspectRatio(
? inferScaleAdjustPatchAspectRatio(
scaleAdjustPatchReference.workspacePixelRect.width,
scaleAdjustPatchReference.workspacePixelRect.height
)