From 79751743f2adf1fe9cff50843a8f152f2aac7140 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 9 Jun 2026 18:44:03 +0800 Subject: [PATCH] fix(external-image): hide model details in API-facing generation errors --- app/api/external/image/generate/route.ts | 25 +++++++++++++++--- lib/external-image-api/service.ts | 33 ++++++++++++++++++++---- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/app/api/external/image/generate/route.ts b/app/api/external/image/generate/route.ts index af24466f3..9e624631c 100644 --- a/app/api/external/image/generate/route.ts +++ b/app/api/external/image/generate/route.ts @@ -8,6 +8,7 @@ import { authenticateExternalImageApiRequest, buildExternalImageApiModelCandidates, buildExternalImageApiKeyFingerprint, + ExternalImageApiGenerationError, ensureHostedReferenceImageUrls, generateImagesWithFailover, getRequesterIp, @@ -405,6 +406,17 @@ export async function POST(request: Request) { }); } catch (error) { console.error("[External Image API] Generate failed:", error); + const shouldHideModelInfo = error instanceof ExternalImageApiGenerationError; + const internalError = shouldHideModelInfo + ? error.internalMessage + : error instanceof Error + ? error.message + : "图片生成失败"; + const publicError = shouldHideModelInfo + ? error.userMessage + : error instanceof Error + ? error.message + : "图片生成失败"; if (error instanceof z.ZodError) { return NextResponse.json( @@ -421,9 +433,16 @@ export async function POST(request: Request) { .update(externalImageApiRequestLog) .set({ status: "failed", - errorMessage: error instanceof Error ? error.message : "图片生成失败", + errorMessage: internalError, responsePayload: { - error: error instanceof Error ? error.message : "图片生成失败", + error: shouldHideModelInfo + ? { + message: error.userMessage, + attempts: error.attempts, + internalError, + } + : internalError, + attempts: shouldHideModelInfo ? error.attempts : undefined, }, durationMs: Date.now() - startedAt, completedAt: new Date(), @@ -449,7 +468,7 @@ export async function POST(request: Request) { return NextResponse.json( { success: false, - error: error instanceof Error ? error.message : "图片生成失败", + error: publicError, }, { status: 500 }, ); diff --git a/lib/external-image-api/service.ts b/lib/external-image-api/service.ts index 426bb7dc2..2f3569adf 100644 --- a/lib/external-image-api/service.ts +++ b/lib/external-image-api/service.ts @@ -24,6 +24,30 @@ type ExternalImageApiGenerateAttempt = { error?: string; }; +export class ExternalImageApiGenerationError extends Error { + readonly attempts: ExternalImageApiGenerateAttempt[]; + readonly userMessage: string; + + constructor( + attempts: ExternalImageApiGenerateAttempt[], + userMessage = "图片生成失败,请稍后重试", + ) { + const summary = attempts + .filter((attempt) => !attempt.success) + .map((attempt) => attempt.displayName || attempt.modelRuntimeId) + .join("; "); + + super(summary || "所有候选模型均调用失败"); + this.name = "ExternalImageApiGenerationError"; + this.attempts = attempts; + this.userMessage = userMessage; + } + + get internalMessage() { + return this.message; + } +} + type ExternalImageApiGeneratedImage = { id: number; originalUrl: string; @@ -759,11 +783,10 @@ export async function generateImagesWithFailover(params: { } } - const summary = attempts - .filter((item) => !item.success) - .map((item) => `${item.displayName}: ${item.error || "图片生成失败"}`) - .join(";"); - throw new Error(summary || "所有候选生图模型均调用失败"); + throw new ExternalImageApiGenerationError( + attempts, + "外部生图服务暂无可用模型返回,请稍后重试", + ); } export async function ensureHostedReferenceImageUrls(imageUrls: string[]) {