fix: harden scale adjust product lock uploads
This commit is contained in:
parent
30eef41dc4
commit
17f5485522
@ -3828,57 +3828,66 @@ async function createScaleAdjustPatchReference(params: {
|
||||
});
|
||||
const targetDraftBuffer = targetDraftReference.buffer;
|
||||
const suffix = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
const targetDraftUploadBuffer = await sharp(targetDraftBuffer, { failOn: "none" })
|
||||
.flatten({ background: "#ffffff" })
|
||||
.jpeg({ quality: 90, mozjpeg: true })
|
||||
.toBuffer();
|
||||
const backgroundPlateUploadBuffer = targetDraftReference.backgroundPlateBuffer
|
||||
? await sharp(targetDraftReference.backgroundPlateBuffer, { failOn: "none" })
|
||||
.flatten({ background: "#ffffff" })
|
||||
.jpeg({ quality: 90, mozjpeg: true })
|
||||
.toBuffer()
|
||||
: null;
|
||||
const uploadOptionalScaleAdjustAsset = async (
|
||||
filename: string,
|
||||
buffer: Buffer | null | undefined
|
||||
) => {
|
||||
if (!buffer) return null;
|
||||
try {
|
||||
return await uploadFile(filename, toArrayBuffer(buffer));
|
||||
} catch (error) {
|
||||
console.warn("[Canvas Local Edit] Optional scale adjust asset upload failed:", {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
filename,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (params.fullFrameReferenceOnly && structureLockAppliedRef.value) {
|
||||
const [
|
||||
targetDraftFullUpload,
|
||||
backgroundPlateFullUpload,
|
||||
productLockOverlayUpload,
|
||||
productLockProtectMaskUpload,
|
||||
compositeClipMaskUpload,
|
||||
productLockEditMaskUpload,
|
||||
productLockFalEditMaskUpload,
|
||||
] = await Promise.all([
|
||||
uploadFile(
|
||||
`canvas-scale-adjust-full-target-draft-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftBuffer)
|
||||
),
|
||||
targetDraftReference.backgroundPlateBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-background-plate-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.backgroundPlateBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
const targetDraftFullUpload = await uploadFile(
|
||||
`canvas-scale-adjust-full-target-draft-${suffix}.jpg`,
|
||||
toArrayBuffer(targetDraftUploadBuffer)
|
||||
);
|
||||
const productLockOverlayUpload = await uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-product-lock-overlay-${suffix}.png`,
|
||||
targetDraftReference.productLockOverlayBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-product-lock-overlay-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.productLockOverlayBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
targetDraftReference.productLockProtectMaskBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-product-lock-protect-mask-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.productLockProtectMaskBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
targetDraftReference.compositeClipMaskBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-composite-clip-mask-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.compositeClipMaskBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
targetDraftReference.productLockEditMaskBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-product-lock-edit-mask-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.productLockEditMaskBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
targetDraftReference.productLockFalEditMaskBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-product-lock-fal-edit-mask-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.productLockFalEditMaskBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
]);
|
||||
);
|
||||
const [productLockEditMaskUpload, productLockFalEditMaskUpload] =
|
||||
await Promise.all([
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-product-lock-edit-mask-${suffix}.png`,
|
||||
targetDraftReference.productLockEditMaskBuffer
|
||||
),
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-product-lock-fal-edit-mask-${suffix}.png`,
|
||||
targetDraftReference.productLockFalEditMaskBuffer
|
||||
),
|
||||
]);
|
||||
const [backgroundPlateFullUpload, productLockProtectMaskUpload, compositeClipMaskUpload] =
|
||||
await Promise.all([
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-background-plate-${suffix}.jpg`,
|
||||
backgroundPlateUploadBuffer
|
||||
),
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-product-lock-protect-mask-${suffix}.png`,
|
||||
targetDraftReference.productLockProtectMaskBuffer
|
||||
),
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-composite-clip-mask-${suffix}.png`,
|
||||
targetDraftReference.compositeClipMaskBuffer
|
||||
),
|
||||
]);
|
||||
|
||||
return {
|
||||
backgroundPlateFullUrl: backgroundPlateFullUpload?.url || null,
|
||||
@ -3907,10 +3916,22 @@ async function createScaleAdjustPatchReference(params: {
|
||||
.png({ compressionLevel: 6 })
|
||||
.toBuffer(),
|
||||
]);
|
||||
const [sourceCropUpload, targetDraftUpload, targetDraftFullUpload] =
|
||||
await Promise.all([
|
||||
uploadFile(
|
||||
`canvas-scale-adjust-workspace-source-${suffix}.png`,
|
||||
toArrayBuffer(sourceCropBuffer)
|
||||
),
|
||||
uploadFile(
|
||||
`canvas-scale-adjust-workspace-target-draft-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftCropBuffer)
|
||||
),
|
||||
uploadFile(
|
||||
`canvas-scale-adjust-full-target-draft-${suffix}.jpg`,
|
||||
toArrayBuffer(targetDraftUploadBuffer)
|
||||
),
|
||||
]);
|
||||
const [
|
||||
sourceCropUpload,
|
||||
targetDraftUpload,
|
||||
targetDraftFullUpload,
|
||||
backgroundPlateFullUpload,
|
||||
productLockOverlayUpload,
|
||||
productLockProtectMaskUpload,
|
||||
@ -3918,54 +3939,30 @@ async function createScaleAdjustPatchReference(params: {
|
||||
productLockEditMaskUpload,
|
||||
productLockFalEditMaskUpload,
|
||||
] = await Promise.all([
|
||||
uploadFile(
|
||||
`canvas-scale-adjust-workspace-source-${suffix}.png`,
|
||||
toArrayBuffer(sourceCropBuffer)
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-background-plate-${suffix}.jpg`,
|
||||
backgroundPlateUploadBuffer
|
||||
),
|
||||
uploadFile(
|
||||
`canvas-scale-adjust-workspace-target-draft-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftCropBuffer)
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-product-lock-overlay-${suffix}.png`,
|
||||
targetDraftReference.productLockOverlayBuffer
|
||||
),
|
||||
uploadFile(
|
||||
`canvas-scale-adjust-full-target-draft-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftBuffer)
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-product-lock-protect-mask-${suffix}.png`,
|
||||
targetDraftReference.productLockProtectMaskBuffer
|
||||
),
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-composite-clip-mask-${suffix}.png`,
|
||||
targetDraftReference.compositeClipMaskBuffer
|
||||
),
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-product-lock-edit-mask-${suffix}.png`,
|
||||
targetDraftReference.productLockEditMaskBuffer
|
||||
),
|
||||
uploadOptionalScaleAdjustAsset(
|
||||
`canvas-scale-adjust-product-lock-fal-edit-mask-${suffix}.png`,
|
||||
targetDraftReference.productLockFalEditMaskBuffer
|
||||
),
|
||||
targetDraftReference.backgroundPlateBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-background-plate-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.backgroundPlateBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
targetDraftReference.productLockOverlayBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-product-lock-overlay-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.productLockOverlayBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
targetDraftReference.productLockProtectMaskBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-product-lock-protect-mask-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.productLockProtectMaskBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
targetDraftReference.compositeClipMaskBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-composite-clip-mask-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.compositeClipMaskBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
targetDraftReference.productLockEditMaskBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-product-lock-edit-mask-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.productLockEditMaskBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
targetDraftReference.productLockFalEditMaskBuffer
|
||||
? uploadFile(
|
||||
`canvas-scale-adjust-product-lock-fal-edit-mask-${suffix}.png`,
|
||||
toArrayBuffer(targetDraftReference.productLockFalEditMaskBuffer)
|
||||
)
|
||||
: Promise.resolve(null),
|
||||
]);
|
||||
|
||||
return {
|
||||
@ -5349,14 +5346,18 @@ export async function POST(request: NextRequest) {
|
||||
regions.some((region) =>
|
||||
isScaleAdjustFurnitureProductLikePrompt(region.prompt)
|
||||
);
|
||||
const useScaleAdjustProductLockComposite =
|
||||
const canUseScaleAdjustProductLockMaskEdit =
|
||||
useScaleAdjustFullFrameStructurePatch &&
|
||||
Boolean(scaleAdjustPatchReference?.backgroundPlateFullUrl) &&
|
||||
Boolean(scaleAdjustPatchReference?.productLockOverlayUrl);
|
||||
const useScaleAdjustProductLockMaskEdit =
|
||||
useScaleAdjustProductLockComposite &&
|
||||
isScaleAdjustMaskCapableModel(resolvedScaleAdjustModelEntry) &&
|
||||
Boolean(scaleAdjustPatchReference?.productLockEditMaskUrl);
|
||||
const useScaleAdjustProductLockComposite =
|
||||
useScaleAdjustFullFrameStructurePatch &&
|
||||
Boolean(scaleAdjustPatchReference?.productLockOverlayUrl) &&
|
||||
(Boolean(scaleAdjustPatchReference?.backgroundPlateFullUrl) ||
|
||||
canUseScaleAdjustProductLockMaskEdit);
|
||||
const useScaleAdjustProductLockMaskEdit =
|
||||
useScaleAdjustProductLockComposite &&
|
||||
canUseScaleAdjustProductLockMaskEdit;
|
||||
const useScaleAdjustPatchTargetDraftPrimary = Boolean(scaleAdjustPatchReference);
|
||||
const includeScaleAdjustPatchSourceReference =
|
||||
Boolean(scaleAdjustPatchReference);
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
} from "@/lib/db/queries";
|
||||
import {
|
||||
enqueueStorageMigrationTask,
|
||||
getEnabledS3StorageConfigs,
|
||||
getPreferredAliyunStorageConfig,
|
||||
isAliyunStorageConfig,
|
||||
} from "@/lib/storage/migration-db";
|
||||
@ -491,6 +492,43 @@ async function uploadWithBackupStorageConfig(
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadWithAnyEnabledStorageConfig(
|
||||
filename: string,
|
||||
buffer: ArrayBuffer,
|
||||
skipStorageConfigIds: Array<string | undefined>
|
||||
): Promise<
|
||||
| {
|
||||
uploaded: { url: string; pathname: string; contentType: string };
|
||||
storageConfig?: StorageConfig;
|
||||
}
|
||||
| null
|
||||
> {
|
||||
const skipped = new Set(skipStorageConfigIds.filter(Boolean) as string[]);
|
||||
try {
|
||||
const configs = await getEnabledS3StorageConfigs();
|
||||
for (const storageConfig of configs) {
|
||||
if (skipped.has(storageConfig.id)) continue;
|
||||
const s3Config = toDbS3UploadConfig(storageConfig);
|
||||
if (!s3Config) continue;
|
||||
|
||||
try {
|
||||
logger.debug(
|
||||
`[Upload] Retrying with enabled S3 config: ${storageConfig.name ?? storageConfig.id}`
|
||||
);
|
||||
const uploaded = await uploadToS3(filename, buffer, s3Config);
|
||||
lastKnownGoodDbS3Config = s3Config;
|
||||
return { uploaded, storageConfig };
|
||||
} catch (error) {
|
||||
logger.error("[Upload] Enabled S3 config retry failed:", error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("[Upload] Failed to list enabled S3 configs for retry:", error);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 上传文件到存储服务
|
||||
export async function uploadFile(
|
||||
filename: string,
|
||||
@ -546,6 +584,22 @@ export async function uploadFile(
|
||||
return uploadedFromBackup.uploaded;
|
||||
}
|
||||
|
||||
const uploadedFromEnabledConfig = await uploadWithAnyEnabledStorageConfig(
|
||||
filename,
|
||||
buffer,
|
||||
[primaryStorageConfigId]
|
||||
);
|
||||
if (uploadedFromEnabledConfig) {
|
||||
await maybeEnqueueAliyunMigrationTask({
|
||||
uploaded: uploadedFromEnabledConfig.uploaded,
|
||||
storageConfig: uploadedFromEnabledConfig.storageConfig,
|
||||
migrationConfig,
|
||||
}).catch((enqueueError) => {
|
||||
logger.error("[Upload] Failed to enqueue enabled S3 OSS migration task:", enqueueError);
|
||||
});
|
||||
return uploadedFromEnabledConfig.uploaded;
|
||||
}
|
||||
|
||||
if (lastKnownGoodDbS3Config) {
|
||||
try {
|
||||
logger.debug("[Upload] Retrying with last known good database S3 config");
|
||||
@ -572,6 +626,22 @@ export async function uploadFile(
|
||||
});
|
||||
return uploadedFromBackup.uploaded;
|
||||
}
|
||||
|
||||
const uploadedFromEnabledConfig = await uploadWithAnyEnabledStorageConfig(
|
||||
filename,
|
||||
buffer,
|
||||
[primaryStorageConfigId]
|
||||
);
|
||||
if (uploadedFromEnabledConfig) {
|
||||
await maybeEnqueueAliyunMigrationTask({
|
||||
uploaded: uploadedFromEnabledConfig.uploaded,
|
||||
storageConfig: uploadedFromEnabledConfig.storageConfig,
|
||||
migrationConfig,
|
||||
}).catch((enqueueError) => {
|
||||
logger.error("[Upload] Failed to enqueue enabled S3 OSS migration task:", enqueueError);
|
||||
});
|
||||
return uploadedFromEnabledConfig.uploaded;
|
||||
}
|
||||
}
|
||||
|
||||
const envS3Config = buildEnvS3Config();
|
||||
@ -651,6 +721,22 @@ export async function createStorageUploadSession(): Promise<StorageUploadFunctio
|
||||
return uploadedFromBackup.uploaded;
|
||||
}
|
||||
|
||||
const uploadedFromEnabledConfig = await uploadWithAnyEnabledStorageConfig(
|
||||
filename,
|
||||
buffer,
|
||||
[primaryStorageConfigId]
|
||||
);
|
||||
if (uploadedFromEnabledConfig) {
|
||||
await maybeEnqueueAliyunMigrationTask({
|
||||
uploaded: uploadedFromEnabledConfig.uploaded,
|
||||
storageConfig: uploadedFromEnabledConfig.storageConfig,
|
||||
migrationConfig,
|
||||
}).catch((migrationError) => {
|
||||
logger.error("[Upload] Failed to enqueue enabled S3 OSS migration task:", migrationError);
|
||||
});
|
||||
return uploadedFromEnabledConfig.uploaded;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user