126 lines
4.8 KiB
TypeScript
126 lines
4.8 KiB
TypeScript
import { auth } from "@/app/(auth)/auth";
|
||
import {
|
||
getAgentAiModelWithProvider,
|
||
getDefaultAiModel,
|
||
getEnabledAiModelsWithProvider,
|
||
getSiteSettings,
|
||
} from "@/lib/db/queries";
|
||
import { ChatSDKError } from "@/lib/errors";
|
||
import { isAiModelAgentAuto } from "@/lib/db/ai-model-flags";
|
||
|
||
function sortModelsForDisplay<T extends { sortOrder?: number | null; displayName?: string | null }>(
|
||
models: T[]
|
||
) {
|
||
return [...models].sort((a, b) => {
|
||
const leftOrder = Number.isFinite(a.sortOrder as number) ? Number(a.sortOrder) : 0;
|
||
const rightOrder = Number.isFinite(b.sortOrder as number) ? Number(b.sortOrder) : 0;
|
||
if (leftOrder !== rightOrder) return leftOrder - rightOrder;
|
||
const leftName = String(a.displayName || "");
|
||
const rightName = String(b.displayName || "");
|
||
return leftName.localeCompare(rightName, "zh-Hans-CN");
|
||
});
|
||
}
|
||
|
||
// 获取前端可用的 AI 模型列表(需要登录但不需要管理员权限)
|
||
export async function GET() {
|
||
try {
|
||
const session = await auth();
|
||
|
||
if (!session?.user) {
|
||
return new ChatSDKError("unauthorized:chat").toResponse();
|
||
}
|
||
|
||
// 只获取主模型(不包括子模型),子模型由后端根据 videoParams.mode 自动选择
|
||
const modelsWithProvider = await getEnabledAiModelsWithProvider(false);
|
||
const agentModelWithProvider = await getAgentAiModelWithProvider();
|
||
const defaultModel = await getDefaultAiModel();
|
||
const siteSettings = await getSiteSettings();
|
||
const visibleModelsWithProvider = sortModelsForDisplay(
|
||
modelsWithProvider
|
||
.filter(({ model }) => !isAiModelAgentAuto(model))
|
||
.map((item) => item.model)
|
||
);
|
||
const visibleModelIdSet = new Set(visibleModelsWithProvider.map((m) => m.id));
|
||
const visibleModelsWithProviderSorted = modelsWithProvider.filter(({ model }) =>
|
||
visibleModelIdSet.has(model.id)
|
||
).sort((a, b) => {
|
||
const left = visibleModelsWithProvider.findIndex((m) => m.id === a.model.id);
|
||
const right = visibleModelsWithProvider.findIndex((m) => m.id === b.model.id);
|
||
return left - right;
|
||
});
|
||
|
||
// 转换为前端需要的格式
|
||
const models = visibleModelsWithProviderSorted.map(({ model, provider }) => ({
|
||
id: model.id,
|
||
modelId: model.modelId,
|
||
displayName: model.displayName,
|
||
avatarUrl: model.avatarUrl,
|
||
description: model.description,
|
||
supportsVision: model.supportsVision,
|
||
supportsImageGen: model.supportsImageGen,
|
||
isDefault: model.isDefault,
|
||
providerName: provider.name,
|
||
providerType: provider.type,
|
||
isSubModel: model.isSubModel,
|
||
parentModelId: model.parentModelId,
|
||
capabilities: model.capabilities, // 🆕 返回子模型的能力配置
|
||
imageGenConfig: model.imageGenConfig,
|
||
sortOrder: model.sortOrder ?? 0,
|
||
}));
|
||
|
||
// Agent 模式在前端展示头像/参数时,优先使用“Agent模式 - 默认生图模型”的配置
|
||
// 避免展示成分析模型(如视觉模型)的头像,导致与管理员设置不一致
|
||
const imageGenModelsWithProvider = visibleModelsWithProviderSorted.filter(
|
||
({ model }) => model.supportsImageGen
|
||
);
|
||
const configuredAutoImageModelId =
|
||
typeof siteSettings?.canvasAutoModeDefaultModelId === "string"
|
||
? siteSettings.canvasAutoModeDefaultModelId.trim()
|
||
: "";
|
||
const configuredAutoImageModel = configuredAutoImageModelId
|
||
? imageGenModelsWithProvider.find(
|
||
({ model }) => model.id === configuredAutoImageModelId
|
||
)
|
||
: undefined;
|
||
const defaultImageGenModel =
|
||
(defaultModel &&
|
||
!isAiModelAgentAuto(defaultModel) &&
|
||
defaultModel.supportsImageGen
|
||
? imageGenModelsWithProvider.find(({ model }) => model.id === defaultModel.id)
|
||
: undefined) || imageGenModelsWithProvider[0];
|
||
const agentDisplayModelWithProvider =
|
||
configuredAutoImageModel ||
|
||
defaultImageGenModel ||
|
||
agentModelWithProvider ||
|
||
null;
|
||
|
||
const resolvedDefaultModelId =
|
||
(defaultModel &&
|
||
!isAiModelAgentAuto(defaultModel) &&
|
||
models.some((model) => model.id === defaultModel.id)
|
||
? defaultModel.id
|
||
: models.find((model) => model.isDefault)?.id) ??
|
||
models[0]?.id ??
|
||
null;
|
||
|
||
return Response.json({
|
||
models,
|
||
defaultModelId: resolvedDefaultModelId,
|
||
agentModel: agentDisplayModelWithProvider
|
||
? {
|
||
id: agentDisplayModelWithProvider.model.id,
|
||
displayName: agentDisplayModelWithProvider.model.displayName,
|
||
avatarUrl: agentDisplayModelWithProvider.model.avatarUrl,
|
||
providerType: agentDisplayModelWithProvider.provider.type,
|
||
imageGenConfig: agentDisplayModelWithProvider.model.imageGenConfig,
|
||
}
|
||
: null,
|
||
});
|
||
} catch (error) {
|
||
if (error instanceof ChatSDKError) {
|
||
return error.toResponse();
|
||
}
|
||
return new ChatSDKError("offline:chat").toResponse();
|
||
}
|
||
}
|