fix: retry FAL scale adjust with guide prompts
This commit is contained in:
parent
d519ac3dde
commit
471eb3f650
@ -1099,23 +1099,92 @@ function buildFalScaleAdjustMockupPrompt(
|
||||
const heightFactor =
|
||||
region.rect.height > 0 ? targetRect.height / region.rect.height : 1;
|
||||
|
||||
return `区域 ${region.index}:原主体约在 x=${region.pixelRect.left}, y=${region.pixelRect.top}, w=${region.pixelRect.width}, h=${region.pixelRect.height};目标主体约在 x=${targetPixelRect.left}, y=${targetPixelRect.top}, w=${targetPixelRect.width}, h=${targetPixelRect.height};目标视觉占位约为原主体宽度 ${widthFactor.toFixed(2)} 倍、高度 ${heightFactor.toFixed(2)} 倍。必须保持主体自身宽高比和透视,不要拉伸或压扁。`;
|
||||
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 [
|
||||
"这是一项室内家用场景里的家具/物体局部比例调整任务。输入图片1是一张粗略目标效果草图,不是最终结果,也不是标注图。",
|
||||
`最终输出必须是一张真实、干净、自然的单张照片,并保持原始画幅 ${sourceSize.width} x ${sourceSize.height} px。`,
|
||||
"输入图片1用半透明软占位表达目标主体的最终大小和位置;请把它作为布局意图来理解,但不要直接复制其中的模糊、拼接边缘、软边、矩形块或局部贴片痕迹。",
|
||||
"核心目标:只调整被选中的家具/物体主体比例和位置;不要恢复成原来的大尺寸,也不要返回几乎未修改的原图。",
|
||||
"请用 AI 自然重建原主体移除后露出的背景,让地毯、地板、窗户、墙面、桌面、阴影、遮挡和透视连续自然。",
|
||||
"请保留目标主体的真实材质、结构、轮廓、透视和光照;主体不能透明、幽灵化、变形、被裁切,不能变成说明图或标注元素。",
|
||||
"非目标区域必须保持原室内照片逻辑:画幅边界、窗框、沙发、植物、墙面、地毯整体纹理、光线、色温和镜头透视不要整体移动、裁切、放大、缩小或重排。",
|
||||
"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(
|
||||
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.`;
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
return [
|
||||
"This is a local furniture scale adjustment edit in an indoor home photo.",
|
||||
"Input image 1 is a soft target-layout draft derived from the original photo. It already places the selected furniture at the intended final size and center.",
|
||||
`Recreate input image 1 as one clean realistic final photo with the same frame and pixel size as the original source: ${sourceSize.width} x ${sourceSize.height} px.`,
|
||||
"Use the draft only as geometry and scene guidance. Remove all blur, soft edges, rectangular patch borders, pasted texture, seams, color mismatch, and rough-composite artifacts.",
|
||||
"The selected furniture size and center shown in the draft is mandatory. Do not restore the furniture to its old size and do not average toward the old footprint.",
|
||||
"Synthesize the selected furniture naturally at the target size and center, preserving realistic material, perspective, light, shadow, and occlusion.",
|
||||
"Naturally reconstruct the exposed surrounding background, preserving floor, rug, wall, shadow, perspective, and object continuity.",
|
||||
"",
|
||||
"Region requirements:",
|
||||
regionLines,
|
||||
"",
|
||||
"If the result contains any visible guide overlay, blur patch, hard rectangle, seam, annotation, or unchanged old-size furniture, regenerate.",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function buildFalScaleAdjustSimpleGuideOnlyPrompt(
|
||||
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 `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");
|
||||
|
||||
return [
|
||||
"Input image 1 is a rough preview of an indoor room after a local furniture size edit.",
|
||||
"Create one clean realistic photo from this preview. Keep the same camera frame, room layout, lighting, wall, floor, windows, and background objects.",
|
||||
"The selected furniture in the preview already shows the desired final size and center. Keep that smaller/larger size in the final photo.",
|
||||
"Remove all preview artifacts: blur, translucent haze, rectangular patch borders, seams, pasted edges, annotations, and color mismatch.",
|
||||
regionLines,
|
||||
"Do not return the old furniture size. Do not zoom, crop, or redesign the whole photo.",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
@ -1349,6 +1418,22 @@ export async function POST(request: NextRequest) {
|
||||
{ width: sourceWidth, height: sourceHeight }
|
||||
)
|
||||
: buildLocalEditPrompt(regions);
|
||||
const falScaleAdjustGuideOnlyPrompt =
|
||||
isScaleAdjustOperation && useFalScaleAdjustMockup
|
||||
? buildFalScaleAdjustGuideOnlyPrompt(regions, scalePercent, {
|
||||
width: sourceWidth,
|
||||
height: sourceHeight,
|
||||
})
|
||||
: "";
|
||||
const falScaleAdjustSimpleGuideOnlyPrompt =
|
||||
isScaleAdjustOperation && useFalScaleAdjustMockup
|
||||
? buildFalScaleAdjustSimpleGuideOnlyPrompt(regions, scalePercent, {
|
||||
width: sourceWidth,
|
||||
height: sourceHeight,
|
||||
})
|
||||
: "";
|
||||
const falScaleAdjustNegativePrompt =
|
||||
"visible annotation, guide overlay, translucent overlay, text label, arrows, boxes, rectangle border, UI marks, pasted patch, seam, hard rectangular edge, color mismatch, whole image zoom, whole image crop, whole image pan, whole image redesign, unchanged target furniture, stretched furniture, squashed furniture";
|
||||
const manualRegionReferenceImageUrls = regions.flatMap((region) =>
|
||||
region.referenceImages.map((reference) => reference.url)
|
||||
);
|
||||
@ -1357,7 +1442,7 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
const referenceImages = isScaleAdjustOperation
|
||||
? useFalScaleAdjustMockup
|
||||
? [annotatedUpload.url]
|
||||
? [annotatedUpload.url, sourceImageUrl]
|
||||
: [
|
||||
sourceImageUrl,
|
||||
annotatedUpload.url,
|
||||
@ -1368,6 +1453,29 @@ export async function POST(request: NextRequest) {
|
||||
const scaleAdjustCompositeRegions = isScaleAdjustOperation
|
||||
? buildScaleAdjustCompositeRegions(regions, scalePercent)
|
||||
: [];
|
||||
const scaleAdjustVerificationConfig = isScaleAdjustOperation
|
||||
? {
|
||||
protectedRegions: scaleAdjustCompositeRegions,
|
||||
rejectFailedCandidates: useFalScaleAdjustMockup ? true : undefined,
|
||||
sourceImageUrl,
|
||||
regions: regions.map((region) => region.rect),
|
||||
...(typeof scalePercent === "number"
|
||||
? { scalePercent: scalePercent as ScaleAdjustPercent }
|
||||
: {}),
|
||||
...(hasScaleAdjustTargetRects
|
||||
? {
|
||||
targetRegions: regions
|
||||
.map((region) => region.targetRect)
|
||||
.filter(
|
||||
(
|
||||
rect
|
||||
): rect is NonNullable<NormalizedLocalEditRegion["targetRect"]> =>
|
||||
Boolean(rect)
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const imageRequest: CanvasGenerateImageRequest = {
|
||||
aspectRatio: resolvedAspectRatio,
|
||||
@ -1379,11 +1487,10 @@ export async function POST(request: NextRequest) {
|
||||
annotatedReferenceSentToModel: isScaleAdjustOperation,
|
||||
annotatedReferenceType: isScaleAdjustOperation
|
||||
? useFalScaleAdjustMockup
|
||||
? "scale-adjust-fal-rough-target-mockup"
|
||||
? "scale-adjust-fal-soft-target-guide-plus-source"
|
||||
: "scale-adjust-neutral-coordinate-guide-map"
|
||||
: "source-overlay",
|
||||
cleanSourceReferenceIndex:
|
||||
isScaleAdjustOperation && useFalScaleAdjustMockup ? null : 1,
|
||||
cleanSourceReferenceIndex: useFalScaleAdjustMockup ? 2 : 1,
|
||||
configuredDetailModelId: configuredDetailModel || null,
|
||||
detailFixedModelApplied: Boolean(detailFixedModel),
|
||||
detailFixedModelId: detailFixedModel || null,
|
||||
@ -1408,7 +1515,7 @@ export async function POST(request: NextRequest) {
|
||||
.length,
|
||||
scaleAdjustPromptStrategy: isScaleAdjustOperation
|
||||
? useFalScaleAdjustMockup
|
||||
? "fal-rough-target-mockup-only-v17"
|
||||
? "fal-guide-plus-source-soft-target-guide-v20"
|
||||
: "locked-plate-neutral-coordinate-guide-map-pixel-anchors-v8"
|
||||
: undefined,
|
||||
scaleAdjustPostCompositeApplied: false,
|
||||
@ -1419,12 +1526,10 @@ export async function POST(request: NextRequest) {
|
||||
},
|
||||
displayPrompt,
|
||||
falSafetyTolerance: useFalScaleAdjustMockup ? "6" : undefined,
|
||||
falSystemPrompt: useFalScaleAdjustMockup
|
||||
? buildFalScaleAdjustSystemPrompt()
|
||||
: undefined,
|
||||
falThinkingLevel: useFalScaleAdjustMockup ? "high" : undefined,
|
||||
falSystemPrompt: undefined,
|
||||
falThinkingLevel: undefined,
|
||||
allowFailover: useFalScaleAdjustMockup ? false : undefined,
|
||||
imageCount: useFalScaleAdjustMockup ? 4 : 1,
|
||||
imageCount: useFalScaleAdjustMockup ? 6 : 1,
|
||||
imageSize:
|
||||
typeof body.imageSize === "string" && body.imageSize.trim()
|
||||
? body.imageSize.trim()
|
||||
@ -1432,33 +1537,50 @@ export async function POST(request: NextRequest) {
|
||||
model: resolvedModel || undefined,
|
||||
negativePrompt:
|
||||
isScaleAdjustOperation
|
||||
? "彩色框、蓝色边框、绿色边框、红色边框、橙色边框、矩形框、箭头、连线、角点、编号圆点、提示词气泡、标注文字、UI 控件、半透明色块、蓝色色块、色条、灰底坐标图、选区边框、白边、画幅压扁、画面拉伸、整张图缩放、全图放大、全图裁切、全图平移、整体重绘、删除文字、清理文字、改写文字、文字模糊、Logo消失、主体拉伸、主体压扁、主体变窄、主体变高但变窄、横向挤压、纵向拉伸、透视变形、矩形贴片、硬边、拼接线、补丁感、局部裁切、色差边缘、背景断裂、背景错位、窗框错位、文字错位、地毯纹理错位、非主体背景重绘、主体未缩放、整块框选区域缩放"
|
||||
? useFalScaleAdjustMockup
|
||||
? falScaleAdjustNegativePrompt
|
||||
: "彩色框、蓝色边框、绿色边框、红色边框、橙色边框、矩形框、箭头、连线、角点、编号圆点、提示词气泡、标注文字、UI 控件、半透明色块、蓝色色块、色条、灰底坐标图、选区边框、白边、画幅压扁、画面拉伸、整张图缩放、全图放大、全图裁切、全图平移、整体重绘、删除文字、清理文字、改写文字、文字模糊、Logo消失、主体拉伸、主体压扁、主体变窄、主体变高但变窄、横向挤压、纵向拉伸、透视变形、矩形贴片、硬边、拼接线、补丁感、局部裁切、色差边缘、背景断裂、背景错位、窗框错位、文字错位、地毯纹理错位、非主体背景重绘、主体未缩放、整块框选区域缩放"
|
||||
: "彩色框、蓝色边框、绿色边框、红色边框、橙色边框、矩形框、编号圆点、提示词气泡、标注文字、UI 控件、半透明色块、选区边框、白边、画幅压扁、画面拉伸、主体截断、动物截断、缺头、缺尾巴、缺四肢、贴边裁切、矩形贴片、硬边、拼接线、补丁感、色差边缘、背景错位、地面纹理断裂、椅脚错位",
|
||||
prompt,
|
||||
promptExtend: false,
|
||||
referenceImages,
|
||||
scaleAdjustVerification: isScaleAdjustOperation
|
||||
? {
|
||||
protectedRegions: scaleAdjustCompositeRegions,
|
||||
sourceImageUrl,
|
||||
regions: regions.map((region) => region.rect),
|
||||
...(typeof scalePercent === "number"
|
||||
? { scalePercent: scalePercent as ScaleAdjustPercent }
|
||||
: {}),
|
||||
...(hasScaleAdjustTargetRects
|
||||
? {
|
||||
targetRegions: regions
|
||||
.map((region) => region.targetRect)
|
||||
.filter(
|
||||
(
|
||||
rect
|
||||
): rect is NonNullable<NormalizedLocalEditRegion["targetRect"]> =>
|
||||
Boolean(rect)
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
retryVariants: useFalScaleAdjustMockup
|
||||
? [
|
||||
{
|
||||
debugMeta: {
|
||||
annotatedReferenceType: "scale-adjust-fal-soft-target-guide-only",
|
||||
cleanSourceReferenceIndex: null,
|
||||
regionReferenceImageCount: 1,
|
||||
scaleAdjustPromptStrategy: "fal-guide-only-clean-target-v20",
|
||||
},
|
||||
falSafetyTolerance: "6",
|
||||
imageCount: 6,
|
||||
label: "fal-guide-only-clean-target-v20",
|
||||
negativePrompt: falScaleAdjustNegativePrompt,
|
||||
prompt: falScaleAdjustGuideOnlyPrompt,
|
||||
promptExtend: false,
|
||||
referenceImages: [annotatedUpload.url],
|
||||
scaleAdjustVerification: scaleAdjustVerificationConfig,
|
||||
},
|
||||
{
|
||||
debugMeta: {
|
||||
annotatedReferenceType: "scale-adjust-fal-soft-target-guide-only",
|
||||
cleanSourceReferenceIndex: null,
|
||||
regionReferenceImageCount: 1,
|
||||
scaleAdjustPromptStrategy: "fal-guide-only-simple-clean-target-v20",
|
||||
},
|
||||
falSafetyTolerance: "6",
|
||||
imageCount: 6,
|
||||
label: "fal-guide-only-simple-clean-target-v20",
|
||||
negativePrompt: falScaleAdjustNegativePrompt,
|
||||
prompt: falScaleAdjustSimpleGuideOnlyPrompt,
|
||||
promptExtend: false,
|
||||
referenceImages: [annotatedUpload.url],
|
||||
scaleAdjustVerification: scaleAdjustVerificationConfig,
|
||||
},
|
||||
]
|
||||
: undefined,
|
||||
scaleAdjustVerification: scaleAdjustVerificationConfig,
|
||||
localEditComposite: isScaleAdjustOperation
|
||||
? undefined
|
||||
: {
|
||||
|
||||
@ -53,12 +53,28 @@ export interface CanvasLocalEditCompositeConfig {
|
||||
|
||||
export interface CanvasScaleAdjustVerificationConfig {
|
||||
protectedRegions?: CanvasLocalEditCompositeRegion[];
|
||||
rejectFailedCandidates?: boolean;
|
||||
sourceImageUrl: string;
|
||||
regions: CanvasLocalEditCompositeRegion[];
|
||||
targetRegions?: CanvasLocalEditCompositeRegion[];
|
||||
scalePercent?: number;
|
||||
}
|
||||
|
||||
export interface CanvasGenerateImageRetryVariant {
|
||||
debugMeta?: Record<string, unknown>;
|
||||
falSafetyTolerance?: string | number;
|
||||
falSystemPrompt?: string;
|
||||
falThinkingLevel?: "minimal" | "high";
|
||||
imageCount?: number;
|
||||
label?: string;
|
||||
negativePrompt?: string;
|
||||
prompt?: string;
|
||||
promptExtend?: boolean;
|
||||
referenceImage?: string;
|
||||
referenceImages?: string[];
|
||||
scaleAdjustVerification?: CanvasScaleAdjustVerificationConfig;
|
||||
}
|
||||
|
||||
export interface CanvasGenerateImageRequest {
|
||||
prompt: string;
|
||||
displayPrompt?: string;
|
||||
@ -79,6 +95,8 @@ export interface CanvasGenerateImageRequest {
|
||||
debugMeta?: Record<string, unknown>;
|
||||
localEditComposite?: CanvasLocalEditCompositeConfig;
|
||||
scaleAdjustVerification?: CanvasScaleAdjustVerificationConfig;
|
||||
retryVariants?: CanvasGenerateImageRetryVariant[];
|
||||
internalRetryVariantIndex?: number;
|
||||
allowFailover?: boolean;
|
||||
internalFailoverTriedModelRefs?: string[];
|
||||
onQueueStatusChange?: (
|
||||
@ -370,6 +388,7 @@ function normalizeScaleAdjustVerificationConfig(
|
||||
? {
|
||||
sourceImageUrl,
|
||||
regions,
|
||||
rejectFailedCandidates: value.rejectFailedCandidates === true,
|
||||
...(targetRegions.length > 0 ? { targetRegions } : {}),
|
||||
...(typeof scalePercent === "number" ? { scalePercent } : {}),
|
||||
...(protectedRegions.length > 0 ? { protectedRegions } : {}),
|
||||
@ -1142,6 +1161,19 @@ async function applyScaleAdjustVerificationToImages(params: {
|
||||
score: Number(scoreEvaluation(selected).toFixed(2)),
|
||||
});
|
||||
|
||||
if (
|
||||
verification.rejectFailedCandidates &&
|
||||
(!selected.changedInside || selected.outsideChanged)
|
||||
) {
|
||||
throw new ScaleAdjustOutputRejectedError({
|
||||
reason: selected.outsideChanged
|
||||
? "outside-frame-changed"
|
||||
: "no-effective-scale-change",
|
||||
diffScores: selected.diffScores,
|
||||
outsideDiffScores: selected.outsideDiffScores,
|
||||
});
|
||||
}
|
||||
|
||||
return [selected.cleanedImage || selected.image];
|
||||
}
|
||||
|
||||
@ -1853,7 +1885,7 @@ export async function generateCanvasImage(
|
||||
const imageSize = normalizedImageParams.imageSize;
|
||||
const imageCount =
|
||||
scaleAdjustVerification && provider.type === "fal-image"
|
||||
? Math.max(1, Math.min(4, requestedImageCount))
|
||||
? Math.max(1, Math.min(6, requestedImageCount))
|
||||
: normalizedImageParams.imageCount;
|
||||
if (imageSize !== requestedImageSize || imageCount !== requestedImageCount) {
|
||||
console.info("[Canvas Generate Image] Normalized model image params:", {
|
||||
@ -2289,6 +2321,47 @@ export async function generateCanvasImage(
|
||||
await slot.release();
|
||||
}
|
||||
|
||||
const retryVariants = Array.isArray(request.retryVariants)
|
||||
? request.retryVariants
|
||||
: [];
|
||||
const nextRetryVariantIndex =
|
||||
typeof request.internalRetryVariantIndex === "number"
|
||||
? request.internalRetryVariantIndex + 1
|
||||
: 0;
|
||||
const retryVariant = retryVariants[nextRetryVariantIndex];
|
||||
if (retryVariant) {
|
||||
const {
|
||||
debugMeta: retryVariantDebugMeta,
|
||||
label: retryVariantLabel,
|
||||
...retryOverrides
|
||||
} = retryVariant;
|
||||
const retryDebugMeta = {
|
||||
...debugMeta,
|
||||
...(retryVariantDebugMeta || {}),
|
||||
retryFromError:
|
||||
caughtError instanceof Error ? caughtError.message : String(caughtError),
|
||||
retryVariantIndex: nextRetryVariantIndex,
|
||||
retryVariantLabel: retryVariantLabel || `variant-${nextRetryVariantIndex + 1}`,
|
||||
};
|
||||
console.warn("[Canvas Generate Image] Retrying with prompt/reference variant:", {
|
||||
...retryDebugMeta,
|
||||
debugLabel,
|
||||
retryVariantIndex: nextRetryVariantIndex,
|
||||
retryVariantLabel: retryVariantLabel || null,
|
||||
selectedModelRef: selectedModel.model.id,
|
||||
selectedModelId: selectedModel.model.modelId,
|
||||
error: caughtError instanceof Error ? caughtError.message : String(caughtError),
|
||||
});
|
||||
|
||||
return await generateCanvasImage({
|
||||
...request,
|
||||
...retryOverrides,
|
||||
debugMeta: retryDebugMeta,
|
||||
internalRetryVariantIndex: nextRetryVariantIndex,
|
||||
retryVariants,
|
||||
});
|
||||
}
|
||||
|
||||
const scaleAdjustRejected =
|
||||
caughtError instanceof ScaleAdjustOutputRejectedError;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user