import "server-only"; import { createOpenAI } from "@ai-sdk/openai"; import type { LanguageModel } from "ai"; import { getLanguageModelById } from "@/lib/ai/dynamic-provider"; import { isImageGenerationModelDescriptor, isVideoModelDescriptor, } from "@/lib/ai/model-classification"; import { isAiModelMultimodal } from "@/lib/db/ai-model-flags"; import { getDefaultAiModel, getEnabledAiModelsWithProvider, getSystemSetting, } from "@/lib/db/queries"; import { normalizeProductPlanningAiModelConfig, PRODUCT_PLANNING_AI_MODEL_CONFIG_KEY, toProductPlanningOpenAIBaseUrl, } from "./model-config"; type ProductPlanningModelResolution = | { model: LanguageModel; source: "dedicated" | "default"; error?: undefined; } | { model: null; source: "dedicated" | "default"; error: string; }; async function resolveDedicatedProductPlanningModel(): Promise { const setting = await getSystemSetting({ key: PRODUCT_PLANNING_AI_MODEL_CONFIG_KEY, }).catch(() => null); const config = normalizeProductPlanningAiModelConfig(setting?.value); if (!config.enabled) { return null; } if (!config.apiKey.trim()) { return { model: null, source: "dedicated", error: "商品策划专用 AI 模型已启用,但未配置 API Key,请前往系统设置填写", }; } const provider = createOpenAI({ apiKey: config.apiKey.trim(), baseURL: toProductPlanningOpenAIBaseUrl(config.baseUrl), }); return { model: provider.chat(config.modelId.trim()), source: "dedicated", }; } async function resolveDefaultTextModel(): Promise { const [defaultModel, enabledModels] = await Promise.all([ getDefaultAiModel().catch(() => undefined), getEnabledAiModelsWithProvider(false), ]); const candidates = enabledModels.filter(({ model, provider }) => { const isVideoModel = isVideoModelDescriptor({ providerType: provider.type, modelId: model.modelId, capabilities: model.capabilities, supportsImageGen: model.supportsImageGen, }); return !isVideoModel && !model.supportsImageGen; }); const selected = (defaultModel ? candidates.find(({ model }) => model.id === defaultModel.id) : undefined) || candidates[0]; if (!selected) { return { model: null, source: "default", error: "当前站点没有可用的文本分析模型", }; } const model = await getLanguageModelById(selected.model.id); if (!model) { return { model: null, source: "default", error: "当前站点没有可用的文本分析模型", }; } return { model, source: "default", }; } async function resolveDefaultVisionModel(): Promise { const [defaultModel, enabledModels] = await Promise.all([ getDefaultAiModel().catch(() => undefined), getEnabledAiModelsWithProvider(false), ]); const candidates = enabledModels.filter(({ model, provider }) => { const isVideoModel = isVideoModelDescriptor({ providerType: provider.type, modelId: model.modelId, capabilities: model.capabilities, supportsImageGen: model.supportsImageGen, }); const isImageModel = isImageGenerationModelDescriptor({ providerType: provider.type, modelId: model.modelId, capabilities: model.capabilities, supportsImageGen: model.supportsImageGen, }); return ( !isVideoModel && !isImageModel && (Boolean(model.supportsVision) || isAiModelMultimodal({ capabilities: model.capabilities, defaultParams: model.defaultParams, })) && !model.supportsImageGen ); }); const selected = (defaultModel ? candidates.find(({ model }) => model.id === defaultModel.id) : undefined) || candidates[0]; if (!selected) { return { model: null, source: "default", error: "当前站点没有可用的图片分析模型", }; } const model = await getLanguageModelById(selected.model.id); if (!model) { return { model: null, source: "default", error: "当前站点没有可用的图片分析模型", }; } return { model, source: "default", }; } export async function resolveProductPlanningTextModel() { const dedicated = await resolveDedicatedProductPlanningModel(); if (dedicated) { return dedicated; } return resolveDefaultTextModel(); } export async function resolveProductPlanningVisionModel() { const dedicated = await resolveDedicatedProductPlanningModel(); if (dedicated) { return dedicated; } return resolveDefaultVisionModel(); }