From 57a1e25921be40f7424187587bbe594f15ca1b29 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 May 2026 17:08:04 +0800 Subject: [PATCH] fix: prioritize external api img2img providers --- lib/ai/model-classification.ts | 1 + lib/external-image-api/service.ts | 58 ++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/lib/ai/model-classification.ts b/lib/ai/model-classification.ts index 58bc1d6c3..99ec9833c 100644 --- a/lib/ai/model-classification.ts +++ b/lib/ai/model-classification.ts @@ -16,6 +16,7 @@ const STATIC_IMAGE_PROVIDER_TYPES = new Set([ "bfl-image", "ruxa-image", "fal-image", + "grsai-gpt-image", "openai-image", "stepfun-image", "midjourney", diff --git a/lib/external-image-api/service.ts b/lib/external-image-api/service.ts index 749e9edc0..92e4c9799 100644 --- a/lib/external-image-api/service.ts +++ b/lib/external-image-api/service.ts @@ -184,6 +184,7 @@ function supportsImageEditForReferenceCount( } const capabilities = toRecord(entry.model.capabilities); + const providerType = normalizeText(entry.provider.type).toLowerCase(); const kind = normalizeText(capabilities?.kind).toLowerCase(); const supportedModes = getSupportedImageModes(entry.model.capabilities); const maxReferenceImages = getMaxReferenceImages(entry.model.capabilities); @@ -191,8 +192,12 @@ function supportsImageEditForReferenceCount( const supportsMultiImageReference = capabilities?.supportsMultiImageReference === true; const runtimeModelId = normalizeText(entry.model.modelId).toLowerCase(); + const providerImpliesReferenceEdit = + providerType === "openai-image" || + providerType === "grsai-gpt-image"; const supportsReferenceEdit = + providerImpliesReferenceEdit || kind === "image-edit" || supportedModes.has("image-edit") || supportedModes.has("reference-images") || @@ -214,14 +219,18 @@ function supportsImageEditForReferenceCount( if (maxReferenceImages !== null) { return referenceImageCount <= maxReferenceImages; } - return supportsMultiImageReference || autoRouteEditEndpoint; + return ( + supportsMultiImageReference || + autoRouteEditEndpoint || + providerImpliesReferenceEdit + ); } return true; } -function isPreferredGptImage2Model(entry: ImageModelEntry) { - const candidates = [ +function getNormalizedModelCandidates(entry: ImageModelEntry) { + return [ entry.model.displayName, entry.model.modelId, entry.model.id, @@ -232,6 +241,10 @@ function isPreferredGptImage2Model(entry: ImageModelEntry) { .replace(/[\s_]+/g, "-"), ) .filter(Boolean); +} + +function isPreferredGptImage2Model(entry: ImageModelEntry) { + const candidates = getNormalizedModelCandidates(entry); return candidates.some( (item) => @@ -241,15 +254,44 @@ function isPreferredGptImage2Model(entry: ImageModelEntry) { ); } +function getExternalImageApiPriority(entry: ImageModelEntry) { + const providerType = normalizeText(entry.provider.type).toLowerCase(); + const candidates = getNormalizedModelCandidates(entry); + const isGptImage2 = isPreferredGptImage2Model(entry); + const isVip = candidates.some((item) => item.includes("vip")); + + if (isGptImage2 && providerType === "openai-image") { + return 400; + } + + if (isGptImage2 && providerType === "grsai-gpt-image") { + return isVip ? 350 : 340; + } + + if (isGptImage2 && providerType === "fal-image") { + return 200; + } + + if (isGptImage2) { + return 100; + } + + return 0; +} + +function isExternalImageApiPreferredProvider(entry: ImageModelEntry) { + return getExternalImageApiPriority(entry) >= 340; +} + function sortExternalImageApiModels( models: ImageModelEntry[], referenceImageCount: number, ) { return [...models].sort((left, right) => { - const leftPreferred = isPreferredGptImage2Model(left) ? 1 : 0; - const rightPreferred = isPreferredGptImage2Model(right) ? 1 : 0; - if (leftPreferred !== rightPreferred) { - return rightPreferred - leftPreferred; + const leftPriority = getExternalImageApiPriority(left); + const rightPriority = getExternalImageApiPriority(right); + if (leftPriority !== rightPriority) { + return rightPriority - leftPriority; } const leftRefSupport = supportsImageEditForReferenceCount( @@ -445,7 +487,7 @@ export function serializeExternalImageApiModel(entry: ImageModelEntry) { capabilities?.supportsMultiImageReference === true || (maxReferenceImages !== null && maxReferenceImages > 1), maxReferenceImages, - preferred: isPreferredGptImage2Model(entry), + preferred: isExternalImageApiPreferredProvider(entry), }; }