/** * 火山引擎视频模型快速配置API * 用于批量添加预设模型 */ import { NextResponse } from 'next/server'; import { auth } from '@/app/(auth)/auth'; import { db } from '@/lib/db'; import { aiModel } from '@/lib/db/schema'; import { VOLCANO_VIDEO_MODEL_PRESETS } from '@/lib/ai/volcano-video-models'; import { eq } from 'drizzle-orm'; /** * 获取火山引擎视频模型预设列表 */ export async function GET(request: Request) { try { const session = await auth(); if (!session?.user || session.user.type !== 'admin') { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } return NextResponse.json({ presets: VOLCANO_VIDEO_MODEL_PRESETS, }); } catch (error: any) { console.error('[Volcano Video Models API] GET error:', error); return NextResponse.json( { error: error.message || 'Failed to fetch model presets' }, { status: 500 } ); } } /** * 批量添加火山引擎视频模型 * POST body: { * providerId: string, * modelIds?: string[], // 可选:只添加指定的模型ID * models?: Array<{modelId, displayName, description}> // 可选:自定义模型配置 * } */ export async function POST(request: Request) { try { const session = await auth(); if (!session?.user || session.user.type !== 'admin') { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const body = await request.json(); const { providerId, modelIds, models: customModels } = body; if (!providerId) { return NextResponse.json( { error: 'Provider ID is required' }, { status: 400 } ); } // 🆕 如果提供了自定义模型配置(通常只有主模型),需要补充所有子模型 let modelsToAdd; if (customModels && Array.isArray(customModels)) { // 检查是否只传了主模型 const hasMasterOnly = customModels.length === 1 && customModels[0].modelId === 'volcano-video-master'; if (hasMasterOnly) { // 🎯 只传了主模型,需要补充所有子模型 const masterModelConfig = customModels[0]; const masterPreset = VOLCANO_VIDEO_MODEL_PRESETS.find(p => p.modelId === 'volcano-video-master'); // 获取主模型 const masterModel = { ...masterPreset, displayName: masterModelConfig.displayName || masterPreset?.displayName || '火山引擎视频', description: masterModelConfig.description || masterPreset?.description || '', }; // 获取所有子模型(使用预设配置) const subModels = VOLCANO_VIDEO_MODEL_PRESETS.filter(p => p.isSubModel); // 组合:主模型 + 所有子模型 modelsToAdd = [masterModel, ...subModels]; console.log(`[Volcano Video Models] ℹ️ 添加主模型和 ${subModels.length} 个子模型`); } else { // 使用自定义配置,但需要从预设中获取完整的capabilities和defaultParams modelsToAdd = customModels.map(customModel => { let preset = VOLCANO_VIDEO_MODEL_PRESETS.find(p => p.modelId === customModel.modelId); if (!preset) { const baseModelId = customModel.modelId.split('-').slice(0, 4).join('-'); preset = VOLCANO_VIDEO_MODEL_PRESETS.find(p => p.modelId.startsWith(baseModelId)); if (preset) { console.log(`[Volcano Video Models] ⚠️ 模型ID "${customModel.modelId}" 未找到精确匹配,使用相似配置: ${preset.modelId}`); } else { console.warn(`[Volcano Video Models] ⚠️ 模型ID "${customModel.modelId}" 未找到预设配置,将使用默认配置`); preset = VOLCANO_VIDEO_MODEL_PRESETS[0]; } } return { ...preset, modelId: customModel.modelId, displayName: customModel.displayName || preset?.displayName || customModel.modelId, description: customModel.description || preset?.description || '', }; }).filter(Boolean); } } else { // 使用预设模型,可以通过modelIds过滤 const selectedModelIds = modelIds || VOLCANO_VIDEO_MODEL_PRESETS.map(p => p.modelId); modelsToAdd = VOLCANO_VIDEO_MODEL_PRESETS.filter(p => selectedModelIds.includes(p.modelId)); } const addedModels = []; const errors = []; for (const preset of modelsToAdd) { if (!preset) { errors.push({ modelId: 'unknown', error: 'Invalid model configuration' }); continue; } try { // 检查模型是否已存在 const existing = await db.query.aiModel.findFirst({ where: eq(aiModel.modelId, preset.modelId), }); if (existing) { errors.push({ modelId: preset.modelId, error: 'Model already exists' }); continue; } // 添加模型 const [newModel] = await db.insert(aiModel).values({ providerId, modelId: preset.modelId, displayName: preset.displayName, description: preset.description, supportsVision: preset.supportsVision, supportsImageGen: preset.supportsImageGen, isEnabled: true, isDefault: false, sortOrder: preset.sortOrder, capabilities: preset.capabilities, defaultParams: preset.defaultParams, isSubModel: preset.isSubModel || false, // 🆕 保存子模型标记 parentModelId: preset.parentModelId ? null : null, // 🆕 父模型ID(第一次添加时为null,稍后通过UPDATE关联) }).returning(); addedModels.push(newModel); console.log(`[Volcano Video Models API] ✅ Added model: ${preset.displayName}`); } catch (error: any) { console.error(`[Volcano Video Models API] ❌ Failed to add ${preset.modelId}:`, error); errors.push({ modelId: preset.modelId, error: error.message }); } } // 🆕 更新子模型的parentModelId,关联到主模型 try { // ✅ 查找主模型(isSubModel=false的那个),支持自定义modelId const masterModel = addedModels.find(m => !m.isSubModel); if (masterModel) { // ✅ 查找所有子模型(isSubModel=true) const subModels = addedModels.filter(m => m.isSubModel); if (subModels.length > 0) { for (const subModel of subModels) { await db.update(aiModel) .set({ parentModelId: masterModel.id }) .where(eq(aiModel.id, subModel.id)); } console.log(`[Volcano Video Models API] ✅ 已关联 ${subModels.length} 个子模型到主模型 (${masterModel.displayName})`); } } else { console.warn('[Volcano Video Models API] ⚠️ 未找到主模型,跳过子模型关联'); } } catch (updateError) { console.error('[Volcano Video Models API] ⚠️ 更新parentModelId失败:', updateError); // 不影响主流程,仅记录错误 } return NextResponse.json({ success: true, addedCount: addedModels.length, addedModels, errors: errors.length > 0 ? errors : undefined, }); } catch (error: any) { console.error('[Volcano Video Models API] POST error:', error); return NextResponse.json( { error: error.message || 'Failed to add models' }, { status: 500 } ); } }