From 05ea65964b1dedaa24b793b997b28e248b268f78 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 29 Dec 2025 01:21:48 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=A0=B9=E6=8D=AE=E5=AE=98?= =?UTF-8?q?=E6=96=B9=E7=A4=BA=E4=BE=8B=E9=87=8D=E5=86=99enhance=20API?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E7=94=A8=E5=BC=82=E6=AD=A5=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=EF=BC=88=E5=88=9B=E5=BB=BA=E4=BB=BB=E5=8A=A1+=E8=BD=AE?= =?UTF-8?q?=E8=AF=A2=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/enhance/route.ts | 215 +++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 110 deletions(-) diff --git a/app/api/enhance/route.ts b/app/api/enhance/route.ts index 266f517..c8a8c06 100644 --- a/app/api/enhance/route.ts +++ b/app/api/enhance/route.ts @@ -82,51 +82,68 @@ async function uploadBase64ToS3(base64Data: string, mimeType: string = "image/jp } /** - * 轮询获取任务结果 + * 轮询获取任务结果(根据官方示例) */ -async function pollTaskResult(apiUrl: string, apiKey: string, taskId: string, maxAttempts: number = 30): Promise { +async function pollTaskResult( + apiUrl: string, + apiKey: string, + taskId: string, + delay: number = 1000, + timeout: number = 30000 +): Promise { const pollUrl = `${apiUrl}/api/tasks/visual/scale/${taskId}`; - for (let attempt = 0; attempt < maxAttempts; attempt++) { - try { - const response = await fetch(pollUrl, { - method: "GET", - headers: { - "X-API-KEY": apiKey, - }, - }); + const getTaskResult = async (): Promise => { + const response = await fetch(pollUrl, { + method: "GET", + headers: { + "X-API-KEY": apiKey, + }, + }); - if (!response.ok) { - throw new Error(`轮询请求失败: ${response.status} ${response.statusText}`); - } - - const result = await response.json(); - - // 检查任务状态 - if (result.status === 200 && result.data) { - if (result.data.state === 1) { - // 任务完成 - return result.data; - } else if (result.data.state === 0) { - // 任务进行中,继续轮询 - await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒 - continue; - } else { - // 任务失败 - throw new Error(`任务失败: state=${result.data.state}`); - } - } else { - throw new Error(`API返回错误: ${result.message || "未知错误"}`); - } - } catch (error) { - if (attempt === maxAttempts - 1) { - throw error; - } - await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒后重试 + if (!response.ok) { + throw new Error(`轮询请求失败: ${response.status} ${response.statusText}`); } - } + + const result = await response.json(); + + if (!result.data) { + throw result; + } + + const { progress, state } = result.data; + + // state < 0 表示失败 + if (state < 0) { + throw result; + } + + // progress >= 100 表示完成 + if (progress >= 100) { + return result; + } + + // 否则继续轮询 + throw null; + }; - throw new Error("轮询超时,任务未在30秒内完成"); + try { + const result = await getTaskResult(); + return result; + } catch (error) { + if (error && typeof error === 'object' && 'data' in error) { + throw new Error(JSON.stringify(error, null, 2)); + } + if (timeout <= 0) { + throw new Error('轮询超时'); + } + await new Promise((resolve) => { + setTimeout(() => { + resolve(undefined); + }, delay); + }); + return pollTaskResult(apiUrl, apiKey, taskId, delay, timeout - delay); + } } /** @@ -218,7 +235,7 @@ export async function POST(request: NextRequest) { ); } - // 3. 调用变清晰API(使用同步模式) + // 3. 调用变清晰API(使用异步模式,根据官方示例) const apiUrl = config.apiUrl.endsWith("/") ? config.apiUrl.slice(0, -1) : config.apiUrl; @@ -235,7 +252,8 @@ export async function POST(request: NextRequest) { filename: "image.jpg", contentType: "image/jpeg", }); - formData.append("sync", "1"); // 同步模式 + // 使用异步模式(sync=0),根据官方示例 + formData.append("sync", "0"); formData.append("type", config.type || "clean"); // 默认通用清晰化 const scaleFactorValue = typeof config.scaleFactor === "number" ? config.scaleFactor : (config.scaleFactor === "auto" ? undefined : Number.parseInt(String(config.scaleFactor))); if (scaleFactorValue) { @@ -249,12 +267,12 @@ export async function POST(request: NextRequest) { }; const startTime = Date.now(); - let response: Response; + let taskId: string; try { - // 添加超时控制(60秒,因为同步模式可能需要更长时间) + // 添加超时控制(30秒) const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 60000); + const timeoutId = setTimeout(() => controller.abort(), 30000); // 将FormData转换为Buffer(form-data包是stream) const formDataBuffer = await new Promise((resolve, reject) => { @@ -267,7 +285,7 @@ export async function POST(request: NextRequest) { // 将Buffer转换为Uint8Array用于fetch(更兼容) const uint8Array = new Uint8Array(formDataBuffer); - response = await fetch(enhanceUrl, { + const createResponse = await fetch(enhanceUrl, { method: "POST", headers, body: uint8Array, @@ -275,6 +293,20 @@ export async function POST(request: NextRequest) { }); clearTimeout(timeoutId); + + if (!createResponse.ok) { + const errorText = await createResponse.text(); + throw new Error(`创建任务失败: ${errorText || createResponse.statusText}`); + } + + const createResult = await createResponse.json(); + + if (!createResult.data || !createResult.data.task_id) { + throw new Error(`API未返回task_id: ${JSON.stringify(createResult)}`); + } + + taskId = createResult.data.task_id; + console.log(`[Enhance] 任务已创建,task_id: ${taskId}`); } catch (fetchError) { const processingTime = (Date.now() - startTime) / 1000; console.error("[Enhance API] 网络请求失败:", { @@ -332,50 +364,34 @@ export async function POST(request: NextRequest) { ); } - const processingTime = (Date.now() - startTime) / 1000; - - if (!response.ok) { - const errorText = await response.text(); - console.error("[Enhance API] 请求失败:", { - status: response.status, - statusText: response.statusText, - error: errorText, - enhanceUrl, - }); + // 4. 轮询获取任务结果(根据官方示例) + console.log(`[Enhance] 开始轮询任务结果,task_id: ${taskId}`); + const taskResult = await pollTaskResult(apiUrl, config.apiKey, taskId); - return NextResponse.json( - { - error: "变清晰API请求失败", - detail: errorText || response.statusText, - }, - { status: response.status } - ); - } - - const result = await response.json(); - - // 4. 处理返回结果 - if (result.status !== 200 || !result.data) { - return NextResponse.json( - { error: "变清晰处理失败", detail: result.message || "未知错误" }, - { status: 500 } - ); - } - - // 检查是否是异步任务(返回task_id) - let enhancedImageBase64: string; - let finalProcessingTime = processingTime; - - if (result.data.task_id && !result.data.image && !result.data.image_base64) { - // 异步模式,需要轮询 - console.log(`[Enhance] 异步任务,task_id: ${result.data.task_id}`); - const taskResult = await pollTaskResult(apiUrl, config.apiKey, result.data.task_id); + const finalProcessingTime = (Date.now() - startTime) / 1000; - if (taskResult.image_base64) { - enhancedImageBase64 = taskResult.image_base64; - } else if (taskResult.image) { + // 5. 处理返回结果 + if (taskResult.status !== 200 || !taskResult.data) { + return NextResponse.json( + { error: "变清晰处理失败", detail: taskResult.message || "未知错误" }, + { status: 500 } + ); + } + + let enhancedImageBase64: string; + + if (taskResult.data.image_base64) { + // 返回的是base64 + enhancedImageBase64 = taskResult.data.image_base64; + } else if (taskResult.data.image) { // 返回的是URL,需要下载 - const imageResponse = await fetch(taskResult.image); + const imageResponse = await fetch(taskResult.data.image); + if (!imageResponse.ok) { + return NextResponse.json( + { error: "变清晰处理失败", detail: "无法下载处理后的图片" }, + { status: 500 } + ); + } const imageBuffer = await imageResponse.arrayBuffer(); enhancedImageBase64 = Buffer.from(imageBuffer).toString("base64"); } else { @@ -384,34 +400,13 @@ export async function POST(request: NextRequest) { { status: 500 } ); } - finalProcessingTime = (Date.now() - startTime) / 1000; - } else if (result.data.image_base64) { - // 同步模式,直接返回base64 - enhancedImageBase64 = result.data.image_base64; - } else if (result.data.image) { - // 返回的是URL,需要下载 - const imageResponse = await fetch(result.data.image); - if (!imageResponse.ok) { + + if (!enhancedImageBase64) { return NextResponse.json( - { error: "变清晰处理失败", detail: "无法下载处理后的图片" }, + { error: "变清晰处理失败", detail: "无法获取处理后的图片" }, { status: 500 } ); } - const imageBuffer = await imageResponse.arrayBuffer(); - enhancedImageBase64 = Buffer.from(imageBuffer).toString("base64"); - } else { - return NextResponse.json( - { error: "变清晰处理失败", detail: "API未返回处理后的图片" }, - { status: 500 } - ); - } - - if (!enhancedImageBase64) { - return NextResponse.json( - { error: "变清晰处理失败", detail: "无法获取处理后的图片" }, - { status: 500 } - ); - } // 5. 上传处理后的图片到S3存储桶 let thumbnailUrl: string;