Your Name 0edd9872ea
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: add BLTCY Flux image providers
2026-04-18 10:29:30 +08:00

154 lines
4.3 KiB
TypeScript

import { and, eq } from "drizzle-orm";
import { NextResponse } from "next/server";
import {
BLTCY_BFL_BASE_URL,
BLTCY_BFL_MODEL_PRESETS,
} 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 BLTCY_BFL_BASE = BLTCY_BFL_BASE_URL.replace(TRAILING_SLASHES_REGEX, "");
function isBltcyBflBaseUrl(value?: string | null) {
const normalized = String(value || "")
.trim()
.replace(TRAILING_SLASHES_REGEX, "");
return (
normalized === BLTCY_BFL_BASE ||
normalized === `${BLTCY_BFL_BASE}/bfl` ||
normalized === `${BLTCY_BFL_BASE}/bfl/v1`
);
}
export async function GET() {
try {
await requireAdmin();
return NextResponse.json({
presets: BLTCY_BFL_MODEL_PRESETS,
counts: {
imageEdit: BLTCY_BFL_MODEL_PRESETS.length,
total: BLTCY_BFL_MODEL_PRESETS.length,
},
});
} catch (error: any) {
console.error("[BLTCY BFL Models API] GET error:", error);
return NextResponse.json(
{ error: error.message || "Failed to fetch BLTCY BFL 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 !== "bfl-image" ||
!isBltcyBflBaseUrl(provider.baseUrl)
) {
return NextResponse.json(
{ error: "Provider must be a 柏拉图 BFL 图片 provider" },
{ status: 400 }
);
}
const presetsToAdd = modelIds
? BLTCY_BFL_MODEL_PRESETS.filter((preset) =>
modelIds.includes(preset.modelId)
)
: BLTCY_BFL_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 BFL 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_BFL_MODEL_PRESETS.length,
},
});
} catch (error: any) {
console.error("[BLTCY BFL Models API] POST error:", error);
return NextResponse.json(
{ error: error.message || "Failed to add BLTCY BFL models" },
{ status: 500 }
);
}
}