fix: remove FAL scale adjust mockup guide

This commit is contained in:
134 2026-06-29 17:03:43 +08:00
parent 12c93e1154
commit 164d9f97e7

View File

@ -97,15 +97,6 @@ const MAX_REFERENCE_IMAGES_PER_REGION = 3;
const MAX_SCALE_ADJUST_CROP_REFERENCES = 4;
const SCALE_ADJUST_CROP_PADDING_RATIO = 0.18;
const SCALE_ADJUST_CROP_MAX_EDGE = 1536;
const SCALE_ADJUST_FAL_MOCKUP_PADDING_RATIO = 0.02;
const SCALE_ADJUST_FAL_MOCKUP_BLUR_PX = 42;
const SCALE_ADJUST_FAL_MOCKUP_WORKSPACE_FEATHER_RATIO = 0.095;
const SCALE_ADJUST_FAL_MOCKUP_WORKSPACE_INSET_RATIO = 0.19;
const SCALE_ADJUST_FAL_MOCKUP_SUBJECT_BLUR_PX = 0.65;
const SCALE_ADJUST_FAL_MOCKUP_SUBJECT_FEATHER_RATIO = 0.16;
const SCALE_ADJUST_FAL_MOCKUP_SUBJECT_INSET_RATIO = 0.25;
const SCALE_ADJUST_FAL_MOCKUP_SUBJECT_OPACITY = 0.72;
const SCALE_ADJUST_FAL_MOCKUP_WORKSPACE_OPACITY = 0.07;
const MIN_REGION_EDGE_PX = 24;
const SCALE_ADJUST_OPERATION = "scale-adjust";
type LocalEditOperation = "local-edit" | typeof SCALE_ADJUST_OPERATION;
@ -551,186 +542,6 @@ function buildScaleAdjustCompositeRegions(
});
}
function expandPixelBox(params: {
amount: number;
box: NormalizedLocalEditRegion["pixelRect"];
height: number;
width: number;
}) {
const { amount, box, height, width } = params;
const left = clamp(box.left - amount, 0, Math.max(0, width - 1));
const top = clamp(box.top - amount, 0, Math.max(0, height - 1));
const right = clamp(box.left + box.width + amount, left + 1, width);
const bottom = clamp(box.top + box.height + amount, top + 1, height);
return {
left,
top,
width: Math.max(1, right - left),
height: Math.max(1, bottom - top),
};
}
async function createFeatherAlphaMask(params: {
width: number;
height: number;
feather: number;
inset: number;
opacity?: number;
}) {
const { width, height } = params;
const feather = Math.max(1, Math.round(params.feather));
const maxInset = Math.max(1, Math.floor(Math.min(width, height) * 0.42));
const inset = clamp(Math.round(params.inset), 1, maxInset);
const innerWidth = Math.max(1, width - inset * 2);
const innerHeight = Math.max(1, height - inset * 2);
const alpha = clamp(
Math.round((params.opacity ?? 1) * 255),
0,
255
);
const svg = Buffer.from(`
<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="soft"><feGaussianBlur stdDeviation="${feather}" /></filter>
</defs>
<rect x="${inset}" y="${inset}" width="${innerWidth}" height="${innerHeight}" fill="rgb(${alpha},${alpha},${alpha})" filter="url(#soft)" />
</svg>
`);
return sharp(svg, { failOn: "none" })
.resize(width, height, { fit: "fill" })
.removeAlpha()
.greyscale()
.png({ compressionLevel: 6 })
.toBuffer();
}
async function addFeatherAlpha(params: {
buffer: Buffer;
width: number;
height: number;
feather: number;
inset: number;
opacity?: number;
}) {
const mask = await createFeatherAlphaMask({
feather: params.feather,
height: params.height,
inset: params.inset,
opacity: params.opacity,
width: params.width,
});
return sharp(params.buffer, { failOn: "none" })
.resize(params.width, params.height, { fit: "fill" })
.removeAlpha()
.joinChannel(mask)
.png({ compressionLevel: 6 })
.toBuffer();
}
async function buildScaleAdjustFalTargetMockup(params: {
sourceBuffer: Buffer;
sourceHeight: number;
sourceWidth: number;
regions: NormalizedLocalEditRegion[];
scalePercent?: ScaleAdjustPercent | null;
}) {
const { sourceBuffer, sourceHeight, sourceWidth, regions, scalePercent } = params;
const minSide = Math.max(1, Math.min(sourceWidth, sourceHeight));
const composites: sharp.OverlayOptions[] = [];
for (const region of regions) {
const targetRect = getScaleAdjustTargetRect(region, scalePercent);
const targetPixelRect =
region.targetPixelRect || rectToPixels(targetRect, sourceWidth, sourceHeight);
const workspaceRect = getScaleAdjustWorkspaceRect(
region.rect,
targetRect,
scalePercent
);
const workspacePixelRect = expandPixelBox({
amount: Math.round(minSide * SCALE_ADJUST_FAL_MOCKUP_PADDING_RATIO),
box: rectToPixels(workspaceRect, sourceWidth, sourceHeight),
height: sourceHeight,
width: sourceWidth,
});
const blurredWorkspace = await sharp(sourceBuffer, { failOn: "none" })
.extract(workspacePixelRect)
.blur(SCALE_ADJUST_FAL_MOCKUP_BLUR_PX)
.modulate({ brightness: 1.05, saturation: 0.78 })
.png({ compressionLevel: 6 })
.toBuffer();
const workspaceFeather = Math.max(
52,
Math.round(minSide * SCALE_ADJUST_FAL_MOCKUP_WORKSPACE_FEATHER_RATIO)
);
const featheredWorkspace = await addFeatherAlpha({
buffer: blurredWorkspace,
feather: workspaceFeather,
height: workspacePixelRect.height,
inset: Math.max(
92,
Math.round(minSide * SCALE_ADJUST_FAL_MOCKUP_WORKSPACE_INSET_RATIO)
),
opacity: SCALE_ADJUST_FAL_MOCKUP_WORKSPACE_OPACITY,
width: workspacePixelRect.width,
});
const subjectCrop = await sharp(sourceBuffer, { failOn: "none" })
.extract(region.pixelRect)
.resize(targetPixelRect.width, targetPixelRect.height, {
fit: "cover",
position: "center",
})
.blur(SCALE_ADJUST_FAL_MOCKUP_SUBJECT_BLUR_PX)
.modulate({ brightness: 1.01, saturation: 0.94 })
.png({ compressionLevel: 6 })
.toBuffer();
const subjectFeather = Math.max(
24,
Math.round(
Math.min(targetPixelRect.width, targetPixelRect.height) *
SCALE_ADJUST_FAL_MOCKUP_SUBJECT_FEATHER_RATIO
)
);
const featheredSubject = await addFeatherAlpha({
buffer: subjectCrop,
feather: subjectFeather,
height: targetPixelRect.height,
inset: Math.max(
34,
Math.round(
Math.min(targetPixelRect.width, targetPixelRect.height) *
SCALE_ADJUST_FAL_MOCKUP_SUBJECT_INSET_RATIO
)
),
opacity: SCALE_ADJUST_FAL_MOCKUP_SUBJECT_OPACITY,
width: targetPixelRect.width,
});
composites.push(
{
input: featheredWorkspace,
left: workspacePixelRect.left,
top: workspacePixelRect.top,
},
{
input: featheredSubject,
left: targetPixelRect.left,
top: targetPixelRect.top,
}
);
}
return sharp(sourceBuffer, { failOn: "none" })
.composite(composites)
.png({ compressionLevel: 6 })
.toBuffer();
}
function expandPixelRectForCrop(params: {
height: number;
pixelRect: NormalizedLocalEditRegion["pixelRect"];
@ -1102,46 +913,7 @@ function buildScaleAdjustPrompt(
].join("\n");
}
function buildFalScaleAdjustMockupPrompt(
regions: NormalizedLocalEditRegion[],
scalePercent: ScaleAdjustPercent | null | undefined,
sourceSize: { width: number; height: number }
) {
const regionLines = regions
.map((region) => {
const targetRect = getScaleAdjustTargetRect(region, scalePercent);
const targetPixelRect =
region.targetPixelRect ||
rectToPixels(targetRect, sourceSize.width, sourceSize.height);
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 `Region ${region.index}: original subject box approximately x=${region.pixelRect.left}, y=${region.pixelRect.top}, w=${region.pixelRect.width}, h=${region.pixelRect.height}; target visual box approximately x=${targetPixelRect.left}, y=${targetPixelRect.top}, w=${targetPixelRect.width}, h=${targetPixelRect.height}; target footprint is about ${widthFactor.toFixed(2)}x width and ${heightFactor.toFixed(2)}x height of the original. Preserve the subject's own aspect ratio and perspective.`;
})
.join("\n");
return [
"This is a local furniture scale adjustment edit in an indoor home photo.",
"Input image 1 is a soft semi-transparent target-layout guide.",
"Input image 2 is the clean original photo that must be edited.",
`The final output must be one clean realistic photo with the same frame and pixel size as the source: ${sourceSize.width} x ${sourceSize.height} px.`,
"Use image 2 for the real scene, material, lighting, background, and camera perspective. Use image 1 only to understand the selected furniture's intended final size and center.",
"The selected furniture size and center shown in image 1 is the final geometry instruction. It overrides the old furniture size and old footprint in image 2; do not average between the two.",
"Do not directly copy blur, soft edges, rectangular patch borders, seams, pasted texture, or any rough-composite artifacts from image 1.",
"Only resize and, if needed, move the selected furniture subject. Remove the old furniture footprint first, then synthesize the same furniture at the target guide size and center. Do not resize, crop, pan, or regenerate the entire canvas.",
"Naturally reconstruct the exposed surrounding background, preserving floor, rug, wall, tabletop, shadow, perspective, and occlusion continuity.",
"Keep all non-target regions stable: windows, wall lines, rugs, sofas, plants, lamps, text, logos, background furniture, lighting, color temperature, and camera perspective must not move or be redesigned.",
"",
"Region requirements:",
regionLines,
"",
"Before returning, self-check: if the target furniture remains close to its old size/old footprint, if the whole photo is zoomed/cropped/redesigned, or if any guide overlay, blur patch, hard rectangle, seam, annotation, or pasted edge is visible, regenerate a seamless realistic photo.",
].join("\n");
}
function buildFalScaleAdjustGuideOnlyPrompt(
function buildFalScaleAdjustCoordinatePrompt(
regions: NormalizedLocalEditRegion[],
scalePercent: ScaleAdjustPercent | null | undefined,
cropReferences: ScaleAdjustCropReference[] = [],
@ -1157,85 +929,45 @@ function buildFalScaleAdjustGuideOnlyPrompt(
region.rect.width > 0 ? targetRect.width / region.rect.width : 1;
const heightFactor =
region.rect.height > 0 ? targetRect.height / region.rect.height : 1;
const cropIndex = cropReferences.findIndex(
(reference) => reference.regionIndex === region.index
);
const cropNote =
cropIndex >= 0
? ` Input image ${cropIndex + 3} is this region's clean crop reference for subject identity and proportions only.`
: "";
return `Region ${region.index}: original subject box approximately x=${region.pixelRect.left}, y=${region.pixelRect.top}, w=${region.pixelRect.width}, h=${region.pixelRect.height}; target visual box approximately x=${targetPixelRect.left}, y=${targetPixelRect.top}, w=${targetPixelRect.width}, h=${targetPixelRect.height}; target footprint is about ${widthFactor.toFixed(2)}x width and ${heightFactor.toFixed(2)}x height of the original.`;
return `Region ${region.index}: old subject search box in input image 1 is x=${region.pixelRect.left}, y=${region.pixelRect.top}, w=${region.pixelRect.width}, h=${region.pixelRect.height}; final target visual box is x=${targetPixelRect.left}, y=${targetPixelRect.top}, w=${targetPixelRect.width}, h=${targetPixelRect.height}; target footprint is about ${widthFactor.toFixed(2)}x width and ${heightFactor.toFixed(2)}x height of the old search box.${cropNote}`;
})
.join("\n");
const cropLines = cropReferences
.map(
(reference, index) =>
`Input image ${index + 2} is a clean crop reference for region ${reference.regionIndex}. Use it only to preserve the selected furniture identity, visible structure, proportions, and top objects; do not paste the crop into the final photo.`
`Input image ${index + 3}: clean crop reference for region ${reference.regionIndex}. Use it only to identify the selected furniture, its visible structure, proportions, material, and top objects. Never paste this crop into the output.`
)
.join("\n");
return [
"This is a local furniture scale adjustment edit in an indoor home photo.",
"Input image 1 is a very soft target-layout guide derived from the original photo after a local furniture size edit.",
"This is a local furniture scale-adjustment edit. It is not full-image resizing, not a collage, and not a patch-copy task.",
`Return one seamless realistic final photo with exactly the same camera frame and pixel size as input image 1: ${sourceSize.width} x ${sourceSize.height} px.`,
"Input image 1 is the clean original photo and must be treated as the locked background plate.",
"Input image 2 is a neutral coordinate instruction map with the same pixel size as input image 1. It is not a photo, not a texture source, not a layer, and not output content.",
"In input image 2, the lighter old/source outline only marks where to find the selected subject in input image 1. The darker target outline marks the desired final visual size and center.",
cropLines,
`Create one clean realistic final photo with the same camera frame and pixel size as the original source: ${sourceSize.width} x ${sourceSize.height} px.`,
"The selected furniture ghost in the guide already shows the desired final size and center. Keep the furniture at that size and center in the final photo.",
"The guide is not a layer, patch, sticker, crop, or pasted block to copy. It is only a geometry hint.",
"Do not preserve or copy any rectangular area from input image 1. No straight patch boundary may remain around the furniture.",
cropLines
? "Use the crop reference only to preserve the target furniture's exact identity and structure. Do not invent duplicate parts, extra legs, rails, side panels, shelves, cabinets, a second copy, or a different furniture design."
: "Preserve the target furniture's exact identity and structure. Do not invent duplicate parts, extra legs, rails, side panels, shelves, cabinets, a second copy, or a different furniture design.",
"Redraw the furniture and scene as one coherent photo with consistent sharpness, exposure, color, perspective, and texture across the entire canvas.",
"Remove all guide artifacts completely: haze, translucent rectangle, blur, hard patch border, seams, pasted edges, different-resolution crop, annotations, and color mismatch.",
"There must be no visible rectangular area around the furniture. Do not preserve any straight crop boundary from the guide.",
"Naturally reconstruct the exposed surrounding background, preserving floor, rug, wall, tabletop, shadows, perspective, and object continuity.",
"",
"Task:",
"Identify the main independently adjustable furniture subject inside the old/source box in input image 1. Resize and, if needed, move only that furniture subject so its final visible footprint matches the target box size and center.",
"If the target box is smaller than the old/source box, the furniture must become clearly smaller. Remove the old larger footprint and naturally reconstruct the newly exposed rug, floor, wall base, shadows, cushion edges, and background continuity.",
"Preserve the selected furniture identity and structure from the original/crop reference: same tabletop, same objects on top, same material, same rectangular leg-frame design. Do not invent duplicate furniture, extra legs, side panels, shelves, cabinets, or a second copy.",
"",
"Region requirements:",
regionLines,
"",
"Do not return the old furniture size. Do not zoom, crop, pan, resize, or redesign the whole photo.",
"Return only a seamless realistic edited photo.",
].join("\n");
}
function buildFalScaleAdjustSimpleGuideOnlyPrompt(
regions: NormalizedLocalEditRegion[],
scalePercent: ScaleAdjustPercent | null | undefined,
cropReferences: ScaleAdjustCropReference[] = [],
sourceSize: { width: number; height: number }
) {
const regionLines = regions
.map((region) => {
const targetRect = getScaleAdjustTargetRect(region, scalePercent);
const targetPixelRect =
region.targetPixelRect ||
rectToPixels(targetRect, sourceSize.width, sourceSize.height);
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 `Selected furniture region ${region.index}: target box x=${targetPixelRect.left}, y=${targetPixelRect.top}, w=${targetPixelRect.width}, h=${targetPixelRect.height}; about ${widthFactor.toFixed(2)}x width and ${heightFactor.toFixed(2)}x height of the original.`;
})
.join("\n");
const cropLines = cropReferences
.map(
(reference, index) =>
`Input image ${index + 2} is a clean crop reference for selected furniture region ${reference.regionIndex}; use it only to preserve identity, visible structure, proportions, and top objects.`
)
.join("\n");
return [
"Input image 1 is a very soft target-layout guide from the original photo after a local furniture size edit.",
cropLines,
`Create one clean realistic final photo with the same camera frame and pixel size: ${sourceSize.width} x ${sourceSize.height} px.`,
"The selected furniture ghost in the guide already shows the desired final size and center. Keep the furniture at that size and center in the final photo.",
"The guide is not a layer, patch, sticker, crop, or pasted block to copy. It is only a geometry hint.",
"Do not preserve or copy any rectangular area from input image 1. No straight patch boundary may remain around the furniture.",
cropLines
? "Use the crop reference only for furniture identity and structure. Do not paste it into the output, and do not invent duplicate parts, extra legs, rails, side panels, shelves, cabinets, a second copy, or a different furniture design."
: "Preserve the furniture identity and structure. Do not invent duplicate parts, extra legs, rails, side panels, shelves, cabinets, a second copy, or a different furniture design.",
"Redraw the furniture and scene as one coherent photo with consistent sharpness, exposure, color, perspective, and texture across the entire canvas.",
"Remove all guide artifacts completely: haze, translucent rectangle, blur, hard patch border, seams, pasted edges, different-resolution crop, annotations, and color mismatch.",
"There must be no visible rectangular area around the furniture. Do not preserve any straight crop boundary from the guide.",
"Naturally reconstruct the exposed surrounding background, preserving floor, rug, wall, tabletop, shadows, perspective, and object continuity.",
regionLines,
"Do not return the old furniture size. Do not zoom, crop, pan, resize, or redesign the whole photo.",
"Return only a seamless realistic edited photo.",
"Hard restrictions:",
"Do not copy, scale, move, or paste any rectangular area from input image 1, input image 2, or any crop reference.",
"Do not output guide marks, outlines, labels, haze, rectangular patch boundaries, seams, different-resolution blocks, color mismatch, or pasted edges.",
"Do not zoom, crop, pan, resize, reframe, or redesign the full canvas. Non-target background, camera perspective, lighting, color temperature, window blinds, wall, floor, rug, and cushion positions must remain coherent.",
"Return only the clean edited photo.",
].join("\n");
}
@ -1407,41 +1139,32 @@ export async function POST(request: NextRequest) {
const resolvedScaleAdjustModelEntry = isScaleAdjustOperation
? findModelSelectionEntry(scaleAdjustModelCandidates, resolvedModel || "")
: null;
const useFalScaleAdjustMockup =
const useFalScaleAdjustCoordinateGuide =
isScaleAdjustOperation && isFalImageModelEntry(resolvedScaleAdjustModelEntry);
const annotatedBuffer =
useFalScaleAdjustMockup
? await buildScaleAdjustFalTargetMockup({
regions,
scalePercent,
sourceBuffer,
sourceHeight,
sourceWidth,
})
: await sharp(sourceBuffer, { failOn: "none" })
.composite([
{
input: isScaleAdjustOperation
? buildScaleAdjustAnnotationSvg({
height: sourceHeight,
regions,
scalePercent,
width: sourceWidth,
})
: buildAnnotationSvg({
height: sourceHeight,
hidePromptText: false,
regions,
width: sourceWidth,
}),
left: 0,
top: 0,
},
])
.png({ compressionLevel: 6 })
.toBuffer();
const annotatedFilename = `${useFalScaleAdjustMockup ? "canvas-scale-adjust-fal-target-mockup" : isScaleAdjustOperation ? "canvas-scale-adjust-guide" : "canvas-local-edit"}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.png`;
const annotatedBuffer = await sharp(sourceBuffer, { failOn: "none" })
.composite([
{
input: isScaleAdjustOperation
? buildScaleAdjustAnnotationSvg({
height: sourceHeight,
regions,
scalePercent,
width: sourceWidth,
})
: buildAnnotationSvg({
height: sourceHeight,
hidePromptText: false,
regions,
width: sourceWidth,
}),
left: 0,
top: 0,
},
])
.png({ compressionLevel: 6 })
.toBuffer();
const annotatedFilename = `${isScaleAdjustOperation ? "canvas-scale-adjust-guide" : "canvas-local-edit"}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.png`;
const annotatedUpload = await uploadFile(
annotatedFilename,
toArrayBuffer(annotatedBuffer)
@ -1455,8 +1178,8 @@ export async function POST(request: NextRequest) {
})
: [];
const prompt = isScaleAdjustOperation
? useFalScaleAdjustMockup
? buildFalScaleAdjustSimpleGuideOnlyPrompt(
? useFalScaleAdjustCoordinateGuide
? buildFalScaleAdjustCoordinatePrompt(
regions,
scalePercent,
scaleAdjustCropReferences,
@ -1481,25 +1204,23 @@ export async function POST(request: NextRequest) {
(reference) => reference.url
);
const referenceImages = isScaleAdjustOperation
? useFalScaleAdjustMockup
? [annotatedUpload.url, ...scaleAdjustCropReferenceImageUrls]
: [
sourceImageUrl,
annotatedUpload.url,
...scaleAdjustCropReferenceImageUrls,
...manualRegionReferenceImageUrls,
]
? [
sourceImageUrl,
annotatedUpload.url,
...scaleAdjustCropReferenceImageUrls,
...manualRegionReferenceImageUrls,
]
: [sourceImageUrl, ...manualRegionReferenceImageUrls];
const scaleAdjustCompositeRegions = isScaleAdjustOperation
? buildScaleAdjustCompositeRegions(regions, scalePercent)
: [];
const scaleAdjustVerificationConfig = isScaleAdjustOperation
? {
allowOutsideChangedWhenChangedInside: useFalScaleAdjustMockup
allowOutsideChangedWhenChangedInside: useFalScaleAdjustCoordinateGuide
? true
: undefined,
protectedRegions: scaleAdjustCompositeRegions,
rejectFailedCandidates: useFalScaleAdjustMockup ? true : undefined,
rejectFailedCandidates: useFalScaleAdjustCoordinateGuide ? true : undefined,
sourceImageUrl,
regions: regions.map((region) => region.rect),
...(typeof scalePercent === "number"
@ -1529,22 +1250,22 @@ export async function POST(request: NextRequest) {
annotatedReferenceUrl: annotatedUpload.url,
annotatedReferenceSentToModel: isScaleAdjustOperation,
annotatedReferenceType: isScaleAdjustOperation
? useFalScaleAdjustMockup
? "scale-adjust-fal-soft-target-guide-plus-crop"
? useFalScaleAdjustCoordinateGuide
? "scale-adjust-fal-coordinate-guide-plus-crop"
: "scale-adjust-neutral-coordinate-guide-map"
: "source-overlay",
cleanSourceReferenceIndex: useFalScaleAdjustMockup ? null : 1,
cleanSourceReferenceIndex: 1,
configuredDetailModelId: configuredDetailModel || null,
detailFixedModelApplied: Boolean(detailFixedModel),
detailFixedModelId: detailFixedModel || null,
displayPrompt,
falScaleAdjustMockupApplied: useFalScaleAdjustMockup,
operation,
requestedModel: requestedModel || null,
resolvedAspectRatio,
resolvedModel: resolvedModel || null,
resolvedScaleAdjustProviderType:
resolvedScaleAdjustModelEntry?.provider?.type || null,
falScaleAdjustCoordinateGuideApplied: useFalScaleAdjustCoordinateGuide,
manualRegionReferenceImageCount: manualRegionReferenceImageUrls.length,
regionReferenceImageCount:
referenceImages.length,
@ -1557,8 +1278,8 @@ export async function POST(request: NextRequest) {
scaleAdjustTargetRegionCount: regions.filter((region) => region.targetRect)
.length,
scaleAdjustPromptStrategy: isScaleAdjustOperation
? useFalScaleAdjustMockup
? "fal-faint-guide-crop-clean-target-single-v22b"
? useFalScaleAdjustCoordinateGuide
? "fal-locked-source-coordinate-crop-single-v23"
: "locked-plate-neutral-coordinate-guide-map-pixel-anchors-v8"
: undefined,
scaleAdjustPostCompositeApplied: false,
@ -1568,10 +1289,10 @@ export async function POST(request: NextRequest) {
sourceWidth,
},
displayPrompt,
falSafetyTolerance: useFalScaleAdjustMockup ? "6" : undefined,
falSafetyTolerance: useFalScaleAdjustCoordinateGuide ? "6" : undefined,
falSystemPrompt: undefined,
falThinkingLevel: undefined,
allowFailover: useFalScaleAdjustMockup ? false : undefined,
allowFailover: useFalScaleAdjustCoordinateGuide ? false : undefined,
imageCount: 1,
imageSize:
typeof body.imageSize === "string" && body.imageSize.trim()
@ -1580,7 +1301,7 @@ export async function POST(request: NextRequest) {
model: resolvedModel || undefined,
negativePrompt:
isScaleAdjustOperation
? useFalScaleAdjustMockup
? useFalScaleAdjustCoordinateGuide
? falScaleAdjustNegativePrompt
: "彩色框、蓝色边框、绿色边框、红色边框、橙色边框、矩形框、箭头、连线、角点、编号圆点、提示词气泡、标注文字、UI 控件、半透明色块、蓝色色块、色条、灰底坐标图、选区边框、白边、画幅压扁、画面拉伸、整张图缩放、全图放大、全图裁切、全图平移、整体重绘、删除文字、清理文字、改写文字、文字模糊、Logo消失、主体拉伸、主体压扁、主体变窄、主体变高但变窄、横向挤压、纵向拉伸、透视变形、矩形贴片、硬边、拼接线、补丁感、局部裁切、色差边缘、背景断裂、背景错位、窗框错位、文字错位、地毯纹理错位、非主体背景重绘、主体未缩放、整块框选区域缩放"
: "彩色框、蓝色边框、绿色边框、红色边框、橙色边框、矩形框、编号圆点、提示词气泡、标注文字、UI 控件、半透明色块、选区边框、白边、画幅压扁、画面拉伸、主体截断、动物截断、缺头、缺尾巴、缺四肢、贴边裁切、矩形贴片、硬边、拼接线、补丁感、色差边缘、背景错位、地面纹理断裂、椅脚错位",