mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
Merge pull request #121 from Chiron-Brahm/fix/custom-models-selector-118
fix(ui): 修复自定义模型无法在模型选择器中显示的问题
This commit is contained in:
@@ -108,38 +108,6 @@ const ALIAS_CONFIG_MAPPING: Record<string, string> = {
|
||||
gemini_api_key: "gemini",
|
||||
};
|
||||
|
||||
// 根据 API 类型获取对应的模型 provider_id 列表
|
||||
const getModelProviderIds = (apiType: ApiType, provider?: string): string[] => {
|
||||
// Antigravity 使用自己的模型列表(别名配置)
|
||||
if (provider?.toLowerCase() === "antigravity") {
|
||||
return ["antigravity"];
|
||||
}
|
||||
|
||||
// Codex 使用自己的模型列表(别名配置)
|
||||
if (provider?.toLowerCase() === "codex") {
|
||||
return ["codex"];
|
||||
}
|
||||
|
||||
// Gemini 使用别名配置
|
||||
if (
|
||||
provider?.toLowerCase() === "gemini" ||
|
||||
provider?.toLowerCase() === "gemini_api_key"
|
||||
) {
|
||||
return ["gemini"];
|
||||
}
|
||||
|
||||
switch (apiType) {
|
||||
case "gemini":
|
||||
return ["gemini"]; // 使用别名配置
|
||||
case "anthropic":
|
||||
return ["anthropic"];
|
||||
case "openai":
|
||||
return ["openai", "azure", "deepseek", "alibaba"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
// 可用的 Provider 信息(合并 OAuth 凭证池和 API Key Provider)
|
||||
interface AvailableProvider {
|
||||
id: string;
|
||||
@@ -308,31 +276,95 @@ export function ApiServerPage() {
|
||||
} else {
|
||||
// 非别名 Provider,使用模型注册表
|
||||
// 首先检查是否是自定义 API Key Provider
|
||||
// 如果是,使用其 type 字段来确定 API 类型
|
||||
let effectiveProvider = provider;
|
||||
// 如果是,优先使用其 custom_models 字段
|
||||
let customModels: string[] | undefined;
|
||||
let registryId = provider; // 默认使用 provider ID 作为 registryId
|
||||
let fallbackRegistryId: string | undefined;
|
||||
|
||||
if (providers) {
|
||||
const customProvider = providers.find((p) => p.id === provider);
|
||||
if (customProvider) {
|
||||
// 使用自定义 Provider 的 type 字段
|
||||
effectiveProvider = customProvider.type;
|
||||
// 获取自定义模型列表
|
||||
customModels = customProvider.custom_models;
|
||||
// 使用 provider.id 作为 registryId(适用于系统预设的 Provider,如 deepseek, moonshot)
|
||||
// 如果模型注册表中没有该 id 的模型,则回退到使用 type 映射
|
||||
registryId = customProvider.id;
|
||||
// 根据 type 获取回退的 registryId
|
||||
const typeToRegistryMap: Record<string, string> = {
|
||||
openai: "openai",
|
||||
anthropic: "anthropic",
|
||||
"anthropic-compatible": "anthropic",
|
||||
gemini: "gemini",
|
||||
"azure-openai": "openai",
|
||||
vertexai: "google",
|
||||
ollama: "ollama",
|
||||
};
|
||||
fallbackRegistryId =
|
||||
typeToRegistryMap[customProvider.type.toLowerCase()] ||
|
||||
customProvider.type.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
// 根据 Provider 的 API 类型过滤模型
|
||||
const apiType = getProviderApiType(effectiveProvider);
|
||||
const providerIds = getModelProviderIds(apiType, provider);
|
||||
// 收集所有模型
|
||||
let allModels: EnhancedModelMetadata[] = [];
|
||||
const existingIds = new Set<string>();
|
||||
|
||||
if (providerIds.length > 0) {
|
||||
// 获取所有匹配 provider_id 的模型
|
||||
const modelPromises = providerIds.map((id) =>
|
||||
getModelsForProvider(id),
|
||||
// 1. 首先添加自定义模型(排在最前面)
|
||||
if (customModels && customModels.length > 0) {
|
||||
const customModelList = customModels.map(
|
||||
(modelName): EnhancedModelMetadata => ({
|
||||
id: modelName,
|
||||
display_name: modelName,
|
||||
provider_id: provider,
|
||||
provider_name: provider,
|
||||
family: null,
|
||||
tier: "pro" as const,
|
||||
capabilities: {
|
||||
vision: false,
|
||||
tools: true,
|
||||
streaming: true,
|
||||
json_mode: true,
|
||||
function_calling: true,
|
||||
reasoning: modelName.includes("thinking"),
|
||||
},
|
||||
pricing: null,
|
||||
limits: {
|
||||
context_length: null,
|
||||
max_output_tokens: null,
|
||||
requests_per_minute: null,
|
||||
tokens_per_minute: null,
|
||||
},
|
||||
status: "active" as const,
|
||||
release_date: null,
|
||||
is_latest: false,
|
||||
description: `自定义模型: ${modelName}`,
|
||||
source: "custom" as const,
|
||||
created_at: Date.now() / 1000,
|
||||
updated_at: Date.now() / 1000,
|
||||
}),
|
||||
);
|
||||
const modelArrays = await Promise.all(modelPromises);
|
||||
models = modelArrays.flat();
|
||||
} else {
|
||||
// 未知类型,显示所有模型
|
||||
models = await getModelRegistry();
|
||||
allModels = [...customModelList];
|
||||
customModels.forEach((id) => existingIds.add(id));
|
||||
}
|
||||
|
||||
// 2. 添加模型注册表中的模型
|
||||
// 优先使用 registryId,如果没有模型则回退到 fallbackRegistryId
|
||||
let registryModels = await getModelsForProvider(registryId);
|
||||
if (
|
||||
registryModels.length === 0 &&
|
||||
fallbackRegistryId &&
|
||||
fallbackRegistryId !== registryId
|
||||
) {
|
||||
registryModels = await getModelsForProvider(fallbackRegistryId);
|
||||
}
|
||||
|
||||
// 过滤掉已存在的模型
|
||||
const newModels = registryModels.filter(
|
||||
(m) => !existingIds.has(m.id),
|
||||
);
|
||||
allModels = [...allModels, ...newModels];
|
||||
|
||||
models = allModels;
|
||||
}
|
||||
} else {
|
||||
models = await getModelRegistry();
|
||||
|
||||
@@ -34,6 +34,8 @@ export interface ConfiguredProvider {
|
||||
credentialType?: string;
|
||||
/** Provider ID(用于 API Key Provider) */
|
||||
providerId?: string;
|
||||
/** 自定义模型列表(用于 API Key Provider) */
|
||||
customModels?: string[];
|
||||
}
|
||||
|
||||
export interface UseConfiguredProvidersResult {
|
||||
@@ -127,6 +129,7 @@ export function useConfiguredProviders(): UseConfiguredProvidersResult {
|
||||
type: provider.type,
|
||||
credentialType: `${provider.type}_key`,
|
||||
providerId: provider.id,
|
||||
customModels: provider.custom_models,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -62,6 +62,48 @@ function sortModels(models: EnhancedModelMetadata[]): EnhancedModelMetadata[] {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将自定义模型列表转换为 EnhancedModelMetadata 格式
|
||||
*/
|
||||
function convertCustomModelsToMetadata(
|
||||
models: string[],
|
||||
providerId: string,
|
||||
providerName: string,
|
||||
): EnhancedModelMetadata[] {
|
||||
return models.map((modelName): EnhancedModelMetadata => {
|
||||
return {
|
||||
id: modelName,
|
||||
display_name: modelName,
|
||||
provider_id: providerId,
|
||||
provider_name: providerName,
|
||||
family: null,
|
||||
tier: "pro" as const,
|
||||
capabilities: {
|
||||
vision: false,
|
||||
tools: true,
|
||||
streaming: true,
|
||||
json_mode: true,
|
||||
function_calling: true,
|
||||
reasoning: modelName.includes("thinking"),
|
||||
},
|
||||
pricing: null,
|
||||
limits: {
|
||||
context_length: null,
|
||||
max_output_tokens: null,
|
||||
requests_per_minute: null,
|
||||
tokens_per_minute: null,
|
||||
},
|
||||
status: "active" as const,
|
||||
release_date: null,
|
||||
is_latest: false,
|
||||
description: `自定义模型: ${modelName}`,
|
||||
source: "custom" as const,
|
||||
created_at: Date.now() / 1000,
|
||||
updated_at: Date.now() / 1000,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将别名配置中的模型转换为 EnhancedModelMetadata 格式
|
||||
*/
|
||||
@@ -155,42 +197,69 @@ export function useProviderModels(
|
||||
return { modelIds: [], models: [] };
|
||||
}
|
||||
|
||||
// 对于别名 Provider,使用别名配置中的模型列表
|
||||
if (isAliasProvider(selectedProvider.key) && aliasConfig) {
|
||||
const modelIds = aliasConfig.models;
|
||||
// 收集所有模型
|
||||
let allModels: EnhancedModelMetadata[] = [];
|
||||
let allModelIds: string[] = [];
|
||||
|
||||
if (returnFullMetadata) {
|
||||
const models = convertAliasModelsToMetadata(
|
||||
modelIds,
|
||||
aliasConfig,
|
||||
selectedProvider.key,
|
||||
selectedProvider.label,
|
||||
);
|
||||
return { modelIds, models };
|
||||
}
|
||||
|
||||
return { modelIds, models: [] };
|
||||
// 1. 首先添加自定义模型(排在最前面)
|
||||
if (
|
||||
selectedProvider.customModels &&
|
||||
selectedProvider.customModels.length > 0
|
||||
) {
|
||||
const customModels = convertCustomModelsToMetadata(
|
||||
selectedProvider.customModels,
|
||||
selectedProvider.key,
|
||||
selectedProvider.label,
|
||||
);
|
||||
allModels = [...customModels];
|
||||
allModelIds = [...selectedProvider.customModels];
|
||||
}
|
||||
|
||||
// 从模型注册表获取模型
|
||||
let models = registryModels.filter(
|
||||
// 2. 对于别名 Provider,添加别名配置中的模型
|
||||
if (isAliasProvider(selectedProvider.key) && aliasConfig) {
|
||||
const aliasModels = convertAliasModelsToMetadata(
|
||||
aliasConfig.models,
|
||||
aliasConfig,
|
||||
selectedProvider.key,
|
||||
selectedProvider.label,
|
||||
);
|
||||
// 过滤掉已存在的模型(避免重复)
|
||||
const newAliasModels = aliasModels.filter(
|
||||
(m) => !allModelIds.includes(m.id),
|
||||
);
|
||||
allModels = [...allModels, ...newAliasModels];
|
||||
allModelIds = [...allModelIds, ...newAliasModels.map((m) => m.id)];
|
||||
}
|
||||
|
||||
// 3. 从模型注册表获取模型
|
||||
let registryFilteredModels = registryModels.filter(
|
||||
(m) => m.provider_id === selectedProvider.registryId,
|
||||
);
|
||||
|
||||
// 如果没有找到模型,尝试使用 fallbackRegistryId
|
||||
if (models.length === 0 && selectedProvider.fallbackRegistryId) {
|
||||
models = registryModels.filter(
|
||||
if (
|
||||
registryFilteredModels.length === 0 &&
|
||||
selectedProvider.fallbackRegistryId
|
||||
) {
|
||||
registryFilteredModels = registryModels.filter(
|
||||
(m) => m.provider_id === selectedProvider.fallbackRegistryId,
|
||||
);
|
||||
}
|
||||
|
||||
// 排序
|
||||
const sortedModels = sortModels(models);
|
||||
const modelIds = sortedModels.map((m) => m.id);
|
||||
// 过滤掉已存在的模型(避免重复)
|
||||
const newRegistryModels = registryFilteredModels.filter(
|
||||
(m) => !allModelIds.includes(m.id),
|
||||
);
|
||||
|
||||
// 排序注册表模型
|
||||
const sortedRegistryModels = sortModels(newRegistryModels);
|
||||
|
||||
allModels = [...allModels, ...sortedRegistryModels];
|
||||
allModelIds = [...allModelIds, ...sortedRegistryModels.map((m) => m.id)];
|
||||
|
||||
return {
|
||||
modelIds,
|
||||
models: returnFullMetadata ? sortedModels : [],
|
||||
modelIds: allModelIds,
|
||||
models: returnFullMetadata ? allModels : [],
|
||||
};
|
||||
}, [selectedProvider, registryModels, aliasConfig, returnFullMetadata]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user