fix: retry weak scale adjust edits with stronger prompt

This commit is contained in:
134 2026-07-02 11:33:39 +08:00
parent 0ec99e8ffb
commit c0ddd420ba
2 changed files with 95 additions and 9 deletions

View File

@ -1186,6 +1186,55 @@ function buildScaleAdjustCoordinatePrompt(
].join("\n");
}
function buildScaleAdjustCoordinateRetryPrompt(params: {
basePrompt: string;
regions: NormalizedLocalEditRegion[];
scalePercent: ScaleAdjustPercent | null | undefined;
sourceSize: { width: number; height: number };
}) {
const forceLines = params.regions
.map((region) => {
const targetRect = getScaleAdjustTargetRect(region, params.scalePercent);
const targetPixelRect =
region.targetPixelRect ||
rectToPixels(targetRect, params.sourceSize.width, params.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;
const sourceRight = region.pixelRect.left + region.pixelRect.width;
const sourceBottom = region.pixelRect.top + region.pixelRect.height;
const targetRight = targetPixelRect.left + targetPixelRect.width;
const targetBottom = targetPixelRect.top + targetPixelRect.height;
const direction =
widthFactor < 0.92 || heightFactor < 0.92
? "缩小"
: widthFactor > 1.08 || heightFactor > 1.08
? "放大"
: "移动/贴合目标框";
return [
`区域 ${region.index} 强制重试目标:${direction}目标家具。`,
`OLD 源框 px: left=${region.pixelRect.left}, top=${region.pixelRect.top}, right=${sourceRight}, bottom=${sourceBottom}, width=${region.pixelRect.width}, height=${region.pixelRect.height}。`,
`TARGET 最终占位 px: left=${targetPixelRect.left}, top=${targetPixelRect.top}, right=${targetRight}, bottom=${targetBottom}, width=${targetPixelRect.width}, height=${targetPixelRect.height}。`,
`目标家具最终视觉尺寸必须接近 OLD 的 ${widthFactor.toFixed(2)}x 宽、${heightFactor.toFixed(2)}x 高;必须让轮廓明显离开 OLD 原边缘,并更接近 TARGET 边缘。`,
].join(" ");
})
.join("\n");
return [
"IMPORTANT RETRY / 重要重试:上一张候选图被系统判定为 no-effective-scale-change,也就是目标家具几乎没有发生有效比例变化。",
"这次不要保守保持原尺寸。必须执行可见的主体比例调整;如果最终看起来像原图,只是局部轻微修补,就是失败。",
"Do not return an unchanged image. Do not keep the furniture in the OLD footprint. The furniture silhouette must move/resize clearly toward TARGET while the camera frame and non-target room stay locked.",
"缩小时:OLD 中超出 TARGET 的旧家具外轮廓必须消失,并补成自然背景/地面/地毯/墙面/阴影;不要让旧尺寸家具仍然贴着 OLD 源框边缘。",
"放大时:同一件家具必须明显占据更大的 TARGET 占位,但保持原透视、材质和宽高比,不要只拉伸单轴,也不要整图放大。",
"",
forceLines,
"",
"下面是完整原始任务,请在遵守以上强制重试目标的前提下执行:",
params.basePrompt,
].join("\n");
}
function buildScaleAdjustCoordinateSystemPrompt() {
return [
"You are an image editing model for local furniture scale adjustment.",
@ -1417,6 +1466,15 @@ export async function POST(request: NextRequest) {
{ width: sourceWidth, height: sourceHeight }
)
: buildLocalEditPrompt(regions);
const scaleAdjustCoordinateRetryPrompt =
isScaleAdjustOperation && useScaleAdjustCoordinateGuide
? buildScaleAdjustCoordinateRetryPrompt({
basePrompt: prompt,
regions,
scalePercent,
sourceSize: { width: sourceWidth, height: sourceHeight },
})
: "";
const scaleAdjustCoordinateNegativePrompt =
"visible annotation, guide overlay, translucent overlay, text label, arrows, boxes, rectangle border, UI marks, pasted patch, seam, hard rectangular edge, color mismatch, different-resolution area, whole image zoom, whole image crop, whole image pan, whole image redesign, unchanged target furniture, stretched furniture, squashed furniture, duplicate furniture, second copy, extra legs, extra rails, side panels, shelves, cabinets, lattice panels";
const manualRegionReferenceImageUrls = regions.flatMap((region) =>
@ -1517,6 +1575,10 @@ export async function POST(request: NextRequest) {
? "same-name-locked-source-neutral-coordinate-map-v30-bilingual-fal-last"
: "locked-plate-neutral-coordinate-guide-map-pixel-anchors-v8"
: undefined,
scaleAdjustRetryPromptStrategy:
isScaleAdjustOperation && scaleAdjustCoordinateRetryPrompt
? "force-visible-scale-change-on-guard-reject-v1"
: undefined,
scaleAdjustPostCompositeApplied: false,
scaleAdjustUsesFullFrameOutput: isScaleAdjustOperation,
sourceHeight,
@ -1545,6 +1607,19 @@ export async function POST(request: NextRequest) {
prompt,
promptExtend: false,
referenceImages,
retryVariants: scaleAdjustCoordinateRetryPrompt
? [
{
debugMeta: {
scaleAdjustRetryPromptStrategy:
"force-visible-scale-change-on-guard-reject-v1",
},
label: "force-visible-scale-change",
prompt: scaleAdjustCoordinateRetryPrompt,
retryOnScaleAdjustRejectionOnly: true,
},
]
: undefined,
scaleAdjustVerification: scaleAdjustVerificationConfig,
localEditComposite: isScaleAdjustOperation
? undefined

View File

@ -76,6 +76,7 @@ export interface CanvasGenerateImageRetryVariant {
promptExtend?: boolean;
referenceImage?: string;
referenceImages?: string[];
retryOnScaleAdjustRejectionOnly?: boolean;
scaleAdjustVerification?: CanvasScaleAdjustVerificationConfig;
}
@ -2543,15 +2544,28 @@ export async function generateCanvasImage(
const retryVariants = Array.isArray(request.retryVariants)
? request.retryVariants
: [];
const scaleAdjustRejection =
caughtError instanceof ScaleAdjustOutputRejectedError ? caughtError : null;
const scaleAdjustRejected = Boolean(scaleAdjustRejection);
const nextRetryVariantIndex =
typeof request.internalRetryVariantIndex === "number"
? request.internalRetryVariantIndex + 1
: 0;
const retryVariant = retryVariants[nextRetryVariantIndex];
let retryVariantIndex = nextRetryVariantIndex;
let retryVariant = retryVariants[retryVariantIndex];
while (
retryVariant &&
retryVariant.retryOnScaleAdjustRejectionOnly &&
!scaleAdjustRejected
) {
retryVariantIndex += 1;
retryVariant = retryVariants[retryVariantIndex];
}
if (retryVariant) {
const {
debugMeta: retryVariantDebugMeta,
label: retryVariantLabel,
retryOnScaleAdjustRejectionOnly,
...retryOverrides
} = retryVariant;
const retryDebugMeta = {
@ -2559,13 +2573,14 @@ export async function generateCanvasImage(
...(retryVariantDebugMeta || {}),
retryFromError:
caughtError instanceof Error ? caughtError.message : String(caughtError),
retryVariantIndex: nextRetryVariantIndex,
retryVariantLabel: retryVariantLabel || `variant-${nextRetryVariantIndex + 1}`,
retryScaleAdjustRejected: scaleAdjustRejected,
retryVariantIndex,
retryVariantLabel: retryVariantLabel || `variant-${retryVariantIndex + 1}`,
};
console.warn("[Canvas Generate Image] Retrying with prompt/reference variant:", {
...retryDebugMeta,
debugLabel,
retryVariantIndex: nextRetryVariantIndex,
retryVariantIndex,
retryVariantLabel: retryVariantLabel || null,
selectedModelRef: selectedModel.model.id,
selectedModelId: selectedModel.model.modelId,
@ -2576,15 +2591,11 @@ export async function generateCanvasImage(
...request,
...retryOverrides,
debugMeta: retryDebugMeta,
internalRetryVariantIndex: nextRetryVariantIndex,
internalRetryVariantIndex: retryVariantIndex,
retryVariants,
});
}
const scaleAdjustRejection =
caughtError instanceof ScaleAdjustOutputRejectedError ? caughtError : null;
const scaleAdjustRejected = Boolean(scaleAdjustRejection);
if (scaleAdjustRejected) {
console.info("[Canvas Generate Image] Skip model health failure for scale adjust rejection:", {
debugLabel,