import { and, eq } from "drizzle-orm"; import { NextResponse } from "next/server"; import { BLTCY_IMAGE_MODEL_PRESETS, BLTCY_IMAGE_OPENAI_BASE_URL, } from "@/lib/ai/bltcy-image-models"; import { db } from "@/lib/db"; import { getAiProviderById } from "@/lib/db/queries"; import { type AiModel, aiModel } from "@/lib/db/schema"; import { requireAdmin } from "@/lib/middleware/admin"; const TRAILING_SLASHES_REGEX = /\/+$/; const TRAILING_V1_REGEX = /\/v1$/i; const BLTCY_IMAGE_BASE_URL = BLTCY_IMAGE_OPENAI_BASE_URL.replace( TRAILING_SLASHES_REGEX, "" ); const BLTCY_IMAGE_BASE_URL_WITHOUT_V1 = BLTCY_IMAGE_OPENAI_BASE_URL.replace( TRAILING_V1_REGEX, "" ); function isBltcyImageBaseUrl(value?: string | null) { const normalized = String(value || "") .trim() .replace(TRAILING_SLASHES_REGEX, ""); return ( normalized === BLTCY_IMAGE_BASE_URL || normalized === BLTCY_IMAGE_BASE_URL_WITHOUT_V1 ); } export async function GET() { try { await requireAdmin(); return NextResponse.json({ presets: BLTCY_IMAGE_MODEL_PRESETS, counts: { imageEdit: BLTCY_IMAGE_MODEL_PRESETS.length, total: BLTCY_IMAGE_MODEL_PRESETS.length, }, }); } catch (error: any) { console.error("[BLTCY Image Models API] GET error:", error); return NextResponse.json( { error: error.message || "Failed to fetch BLTCY image model presets" }, { status: 500 } ); } } export async function POST(request: Request) { try { await requireAdmin(); const body = await request.json(); const providerId = String(body?.providerId || "").trim(); const modelIds = Array.isArray(body?.modelIds) ? body.modelIds .map((item: unknown) => String(item || "").trim()) .filter(Boolean) : null; if (!providerId) { return NextResponse.json( { error: "Provider ID is required" }, { status: 400 } ); } const provider = await getAiProviderById({ id: providerId }); if ( !provider || provider.type !== "openai-image" || !isBltcyImageBaseUrl(provider.baseUrl) ) { return NextResponse.json( { error: "Provider must be a 柏拉图 OpenAI 图片兼容 provider" }, { status: 400 } ); } const presetsToAdd = modelIds ? BLTCY_IMAGE_MODEL_PRESETS.filter((preset) => modelIds.includes(preset.modelId) ) : BLTCY_IMAGE_MODEL_PRESETS; const addedModels: AiModel[] = []; const errors: { modelId: string; error: string }[] = []; for (const preset of presetsToAdd) { try { const existing = await db.query.aiModel.findFirst({ where: and( eq(aiModel.providerId, providerId), 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, isHidden: false, isDefault: false, sortOrder: preset.sortOrder, capabilities: preset.capabilities || null, defaultParams: preset.defaultParams || null, imageGenConfig: preset.imageGenConfig || null, isSubModel: false, parentModelId: null, }) .returning(); addedModels.push(newModel); } catch (error: any) { console.error( `[BLTCY Image Models API] Failed to add ${preset.modelId}:`, error ); errors.push({ modelId: preset.modelId, error: error.message || "Insert failed", }); } } return NextResponse.json({ success: true, addedCount: addedModels.length, addedModels, errors: errors.length > 0 ? errors : undefined, counts: { requested: presetsToAdd.length, total: BLTCY_IMAGE_MODEL_PRESETS.length, }, }); } catch (error: any) { console.error("[BLTCY Image Models API] POST error:", error); return NextResponse.json( { error: error.message || "Failed to add BLTCY image models" }, { status: 500 } ); } }