fix: avoid blank detail replacement outputs

This commit is contained in:
Your Name 2026-06-02 21:27:37 +08:00
parent 1a97f56169
commit e126355b26
3 changed files with 20 additions and 7 deletions

View File

@ -187,6 +187,7 @@ export async function normalizeReplacementResultImage(params: {
generatedThumbnailUrl?: string;
referenceImageUrl: string;
referenceGeometry?: ReplacementReferenceGeometry | null;
scenePlan?: ReplacementScenePlan | null;
uploadPrefix: string;
}): Promise<{
originalUrl: string;
@ -235,13 +236,23 @@ export async function normalizeReplacementResultImage(params: {
const shouldCropTallComposite =
Boolean(targetAspectRatio && generatedAspectRatio) &&
Number(generatedAspectRatio) < Number(targetAspectRatio) * 0.78;
const shouldPreserveFullGeneratedCanvas =
params.scenePlan?.whiteBackgroundLikely === true ||
params.scenePlan?.textPolicy === "lock" ||
params.scenePlan?.generationRoute === "copy_locked_regenerate" ||
params.scenePlan?.generationRoute === "layout_preserve_replace";
const resizeFit = shouldCropTallComposite
? "cover"
: shouldPreserveFullGeneratedCanvas
? "contain"
: "cover";
const normalizedBuffer =
targetWidth && targetHeight
? await imagePipeline
.resize(targetWidth, targetHeight, {
// Wide outputs need containment to avoid cropping edge text; overly tall outputs
// usually mean the model stacked two page variants, so crop to the top page.
fit: shouldCropTallComposite ? "cover" : "contain",
// Layout-locked copy pages keep containment to protect edge text. Scene pages
// fill the target frame so a wrong model aspect does not become a white panel.
fit: resizeFit,
position: shouldCropTallComposite ? "top" : "centre",
background: { r: 255, g: 255, b: 255, alpha: 1 },
withoutEnlargement: false,

View File

@ -3530,6 +3530,7 @@ export async function POST(request: Request) {
generatedThumbnailUrl: firstImage.thumbnailUrl,
referenceImageUrl: reference.imageUrl,
referenceGeometry,
scenePlan: replacementExecutionPlan.scenePlan,
uploadPrefix: "agent-detail-replacement",
});
finalImage = {
@ -4333,6 +4334,7 @@ export async function POST(request: Request) {
generatedThumbnailUrl: firstImage.thumbnailUrl,
referenceImageUrl: reference.imageUrl,
referenceGeometry,
scenePlan: replacementExecutionPlan.scenePlan,
uploadPrefix: isDetailReplacementPreset
? "agent-detail-replacement"
: "agent-sku-replacement",

View File

@ -6685,7 +6685,7 @@ export function AgentGenerationWorkspaceDarkV2({
)}
onClick={() => setActiveDetailReferenceCardId(card.id)}
>
<div className="relative aspect-[790/1300] overflow-hidden bg-white/95">
<div className="relative min-h-[220px] overflow-hidden bg-white/95">
<div className="absolute right-3 top-3 z-10 flex flex-col items-end gap-2">
<button
type="button"
@ -6718,7 +6718,7 @@ export function AgentGenerationWorkspaceDarkV2({
<AgentPreviewImage
src={card.imageUrl}
alt={card.label}
className="h-full w-full object-contain"
className="block h-auto w-full"
previewWidth={720}
previewQuality={76}
onError={(event) =>
@ -6808,11 +6808,11 @@ export function AgentGenerationWorkspaceDarkV2({
)}
>
{hasResult ? (
<div className="relative aspect-[790/1300] overflow-hidden bg-white/95">
<div className="relative min-h-[220px] overflow-hidden bg-white/95">
<AgentPreviewImage
src={card.resultUrl!}
alt={`结果图 ${card.index + 1}`}
className="h-full w-full cursor-zoom-in object-contain"
className="block h-auto w-full cursor-zoom-in"
previewWidth={720}
previewQuality={78}
onError={(event) =>