fix: prioritize external api img2img providers
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-05-18 17:08:04 +08:00
parent 7a2bd3c71b
commit 57a1e25921
2 changed files with 51 additions and 8 deletions

View File

@ -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",

View File

@ -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),
};
}