Your Name 53ddb7e585
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
Initial commit - clean repository
2025-12-17 20:15:18 +08:00

206 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 火山引擎视频模型快速配置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 }
);
}
}