diff --git a/app/(chat)/api/models/route.ts b/app/(chat)/api/models/route.ts index 35f80da1f..2f10d6511 100644 --- a/app/(chat)/api/models/route.ts +++ b/app/(chat)/api/models/route.ts @@ -7,6 +7,19 @@ import { import { ChatSDKError } from "@/lib/errors"; import { isAiModelAgentAuto } from "@/lib/db/ai-model-flags"; +function sortModelsForDisplay( + 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 { @@ -20,12 +33,22 @@ export async function GET() { const modelsWithProvider = await getEnabledAiModelsWithProvider(false); const agentModelWithProvider = await getAgentAiModelWithProvider(); const defaultModel = await getDefaultAiModel(); - const visibleModelsWithProvider = modelsWithProvider.filter( - ({ model }) => !isAiModelAgentAuto(model) + 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 = visibleModelsWithProvider.map(({ model, provider }) => ({ + const models = visibleModelsWithProviderSorted.map(({ model, provider }) => ({ id: model.id, modelId: model.modelId, displayName: model.displayName, @@ -40,6 +63,7 @@ export async function GET() { parentModelId: model.parentModelId, capabilities: model.capabilities, // 🆕 返回子模型的能力配置 imageGenConfig: model.imageGenConfig, + sortOrder: model.sortOrder ?? 0, })); const resolvedDefaultModelId = diff --git a/app/api/admin/ai-models/route.ts b/app/api/admin/ai-models/route.ts index e58f89c93..cdd9d371c 100644 --- a/app/api/admin/ai-models/route.ts +++ b/app/api/admin/ai-models/route.ts @@ -70,6 +70,19 @@ function normalizeModel(model: any) { }; } +function sortModelsForDisplay( + 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"); + }); +} + export async function GET(request: Request) { try { await requireAdmin(); @@ -88,11 +101,11 @@ export async function GET(request: Request) { if (providerId) { const models = await getAiModelsByProviderId({ providerId }); - return Response.json({ models: models.map(normalizeModel) }); + return Response.json({ models: sortModelsForDisplay(models.map(normalizeModel)) }); } const models = await getAllAiModels(); - return Response.json({ models: models.map(normalizeModel) }); + return Response.json({ models: sortModelsForDisplay(models.map(normalizeModel)) }); } catch (error) { if (error instanceof ChatSDKError) { return error.toResponse(); diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index 4af9599fa..0e7d80b5c 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -1345,6 +1345,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF avatarUrl: modelsData?.agentModel?.avatarUrl || null, providerType: "auto", supportsImageGen: true, + imageGenConfig: undefined, }; // 所有可选模型(Agent模式 + 可视化模型)