From fb11a4becd0dbb2922ffe76ae8ee9f5a1b63f804 Mon Sep 17 00:00:00 2001 From: 134 Date: Sat, 4 Jul 2026 15:38:51 +0800 Subject: [PATCH] fix: stabilize snapgen reference downloads --- lib/ai/providers/snapgen-image.ts | 63 +++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/lib/ai/providers/snapgen-image.ts b/lib/ai/providers/snapgen-image.ts index 3c55318b3..c07ed33cb 100644 --- a/lib/ai/providers/snapgen-image.ts +++ b/lib/ai/providers/snapgen-image.ts @@ -45,6 +45,9 @@ type SnapgenApiFormat = const DEFAULT_OUTPUT_FORMAT = "png"; const POLL_INTERVAL_MS = 2000; const POLL_MAX_ATTEMPTS = 240; +const REFERENCE_ASPECT_DOWNLOAD_TIMEOUT_MS = 30_000; +const REFERENCE_FILE_DOWNLOAD_TIMEOUT_MS = 90_000; +const REFERENCE_FILE_DOWNLOAD_RETRIES = 2; function joinApiPath(baseURL: string, path: string) { const cleanBase = baseURL.replace(/\/+$/, ""); @@ -182,7 +185,10 @@ async function inferImageDimensionsFromUrl( if (!/^https?:\/\//i.test(imageUrl)) return null; const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), 20_000); + const timeout = setTimeout( + () => controller.abort(), + REFERENCE_ASPECT_DOWNLOAD_TIMEOUT_MS + ); try { const response = await fetch(imageUrl, { cache: "no-store", @@ -663,23 +669,48 @@ async function downloadAndUploadImage(imageUrl: string): Promise } async function downloadReferenceImageFile(imageUrl: string, index: number) { - const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), 20_000); - try { - const response = await fetch(imageUrl, { signal: controller.signal }); - if (!response.ok) { - throw new Error(`Failed to download reference image: ${response.status}`); + let lastError: unknown = null; + + for (let attempt = 1; attempt <= REFERENCE_FILE_DOWNLOAD_RETRIES + 1; attempt += 1) { + const controller = new AbortController(); + const timeout = setTimeout( + () => controller.abort(), + REFERENCE_FILE_DOWNLOAD_TIMEOUT_MS + ); + + try { + const response = await fetch(imageUrl, { signal: controller.signal }); + if (!response.ok) { + throw new Error(`Failed to download reference image: ${response.status}`); + } + const mimeType = response.headers.get("content-type") || "image/png"; + const buffer = Buffer.from(await response.arrayBuffer()); + const extension = detectImageExtension(imageUrl, mimeType); + return { + blob: new Blob([new Uint8Array(buffer)], { type: mimeType }), + filename: `snapgen-reference-${index + 1}.${extension}`, + }; + } catch (error) { + lastError = error; + if (attempt <= REFERENCE_FILE_DOWNLOAD_RETRIES) { + console.warn("[SnapGen Image] Retrying reference image download:", { + attempt, + imageIndex: index + 1, + error: error instanceof Error ? error.message : String(error), + }); + await new Promise((resolve) => setTimeout(resolve, attempt * 1500)); + continue; + } + } finally { + clearTimeout(timeout); } - const mimeType = response.headers.get("content-type") || "image/png"; - const buffer = Buffer.from(await response.arrayBuffer()); - const extension = detectImageExtension(imageUrl, mimeType); - return { - blob: new Blob([new Uint8Array(buffer)], { type: mimeType }), - filename: `snapgen-reference-${index + 1}.${extension}`, - }; - } finally { - clearTimeout(timeout); } + + const message = + lastError instanceof Error ? lastError.message : String(lastError || "unknown"); + throw new Error( + `SnapGen 参考图下载失败(第 ${index + 1} 张,已重试 ${REFERENCE_FILE_DOWNLOAD_RETRIES} 次):${message}` + ); } function buildHeaders(apiKey: string) {