diff --git a/app/(admin)/settings/admin-settings-client.tsx b/app/(admin)/settings/admin-settings-client.tsx index dcb885758..3f109da89 100644 --- a/app/(admin)/settings/admin-settings-client.tsx +++ b/app/(admin)/settings/admin-settings-client.tsx @@ -158,7 +158,7 @@ type ToolConfig = { type AiProvider = { id: string; name: string; - type: "alibaba" | "openai" | "custom" | "local" | "gemini" | "huanke-gemini" | "qianwen-video" | "doubao-video" | "ruxa-video" | "volcano-vision" | "volcano-video" | "alibaba-image" | "ruxa-image" | "fal-image" | "openai-image" | "midjourney" | "fal-video" | "zhipu" | "tripo-3d" | "runway" | "volcano-multimodal"; + type: "alibaba" | "openai" | "custom" | "local" | "gemini" | "huanke-gemini" | "qianwen-video" | "doubao-video" | "ruxa-video" | "volcano-vision" | "volcano-video" | "alibaba-image" | "bfl-image" | "ruxa-image" | "fal-image" | "openai-image" | "midjourney" | "fal-video" | "zhipu" | "tripo-3d" | "runway" | "volcano-multimodal"; baseUrl: string; apiKey: string; isEnabled: boolean; @@ -464,6 +464,7 @@ const AVAILABLE_TOOLS = [ const PROVIDER_TYPES = [ { value: "alibaba", label: "阿里云通义千问" }, { value: "alibaba-image", label: "阿里生图模型" }, // 🆕 千问图片生成/编辑 + { value: "bfl-image", label: "BFL FLUX.2 图片编辑" }, { value: "ruxa-image", label: "RUXA生图" }, { value: "fal-image", label: "FAL 生图模型" }, { value: "openai-image", label: "OpenAI 图片兼容" }, @@ -489,6 +490,7 @@ const PROVIDER_DEFAULT_BASE_URL: Record = { alibaba: "https://dashscope.aliyuncs.com/compatible-mode/v1", "alibaba-image": "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation", + "bfl-image": "https://api.bfl.ai", "ruxa-image": "https://api.ruxa.ai", "fal-image": "https://fal.run", "openai-image": "https://api.openai.com/v1", @@ -1475,7 +1477,7 @@ export function AdminSettingsClient() { const [providerForm, setProviderForm] = useState({ id: "", name: "", - type: "openai" as "alibaba" | "openai" | "custom" | "local" | "gemini" | "huanke-gemini" | "qianwen-video" | "doubao-video" | "ruxa-video" | "volcano-vision" | "volcano-video" | "alibaba-image" | "ruxa-image" | "fal-image" | "openai-image" | "midjourney" | "fal-video" | "zhipu" | "tripo-3d" | "runway" | "volcano-multimodal", + type: "openai" as "alibaba" | "openai" | "custom" | "local" | "gemini" | "huanke-gemini" | "qianwen-video" | "doubao-video" | "ruxa-video" | "volcano-vision" | "volcano-video" | "alibaba-image" | "bfl-image" | "ruxa-image" | "fal-image" | "openai-image" | "midjourney" | "fal-video" | "zhipu" | "tripo-3d" | "runway" | "volcano-multimodal", baseUrl: "", apiKey: "", isEnabled: true, @@ -4012,6 +4014,7 @@ export function AdminSettingsClient() { "ruxa-video": "bg-violet-500", "alibaba": "bg-blue-500", "alibaba-image": "bg-amber-500", + "bfl-image": "bg-cyan-600", "ruxa-image": "bg-emerald-500", "fal-image": "bg-sky-500", "openai-image": "bg-green-600", diff --git a/app/api/admin/ai-providers/route.ts b/app/api/admin/ai-providers/route.ts index 53b67b613..0ade5f1aa 100644 --- a/app/api/admin/ai-providers/route.ts +++ b/app/api/admin/ai-providers/route.ts @@ -22,6 +22,7 @@ const providerTypes = [ "volcano-vision", "volcano-video", "alibaba-image", + "bfl-image", "ruxa-image", "fal-image", "openai-image", @@ -58,6 +59,7 @@ const DOUBAO_VIDEO_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"; const RUXA_VIDEO_BASE_URL = "https://api.ruxa.ai"; const RUXA_IMAGE_BASE_URL = "https://api.ruxa.ai"; const OPENAI_IMAGE_BASE_URL = "https://api.openai.com/v1"; +const BFL_IMAGE_BASE_URL = "https://api.bfl.ai"; const MIDJOURNEY_BASE_URL = "https://your-midjourney-api.example.com"; const TRIPO_3D_BASE_URL = "https://api.tripo3d.ai/v2/openapi"; const RUNWAY_BASE_URL = "https://api.dev.runwayml.com"; @@ -196,6 +198,8 @@ export async function POST(request: Request) { ? data.baseUrl || DOUBAO_VIDEO_BASE_URL : data.type === "ruxa-video" ? data.baseUrl || RUXA_VIDEO_BASE_URL + : data.type === "bfl-image" + ? data.baseUrl || BFL_IMAGE_BASE_URL : data.type === "ruxa-image" ? data.baseUrl || RUXA_IMAGE_BASE_URL : data.type === "openai-image" diff --git a/lib/ai/provider-defaults.ts b/lib/ai/provider-defaults.ts index 84f788296..65b030c8f 100644 --- a/lib/ai/provider-defaults.ts +++ b/lib/ai/provider-defaults.ts @@ -14,6 +14,7 @@ const PROVIDER_DEFAULT_BASE_URL: Partial> = { "ruxa-image": "https://api.ruxa.ai", "fal-image": "https://fal.run", "openai-image": "https://api.openai.com/v1", + "bfl-image": "https://api.bfl.ai", midjourney: "https://your-midjourney-api.example.com", "fal-video": "https://fal.run", "tripo-3d": "https://api.tripo3d.ai/v2/openapi", diff --git a/lib/db/queries.ts b/lib/db/queries.ts index 59c47b553..712315553 100644 --- a/lib/db/queries.ts +++ b/lib/db/queries.ts @@ -3386,7 +3386,7 @@ export async function createAiProvider({ updatedBy, }: { name: string; - type: "alibaba" | "openai" | "custom" | "local" | "gemini" | "huanke-gemini" | "qianwen-video" | "doubao-video" | "ruxa-video" | "volcano-vision" | "volcano-video" | "alibaba-image" | "ruxa-image" | "fal-image" | "openai-image" | "midjourney" | "fal-video" | "zhipu" | "tripo-3d" | "runway"; + type: "alibaba" | "openai" | "custom" | "local" | "gemini" | "huanke-gemini" | "qianwen-video" | "doubao-video" | "ruxa-video" | "volcano-vision" | "volcano-video" | "alibaba-image" | "bfl-image" | "ruxa-image" | "fal-image" | "openai-image" | "midjourney" | "fal-video" | "zhipu" | "tripo-3d" | "runway"; baseUrl: string; apiKey: string; isEnabled?: boolean; @@ -3424,7 +3424,7 @@ export async function updateAiProvider({ }: { id: string; name?: string; - type?: "alibaba" | "openai" | "custom" | "local" | "gemini" | "huanke-gemini" | "qianwen-video" | "doubao-video" | "ruxa-video" | "volcano-vision" | "volcano-video" | "alibaba-image" | "ruxa-image" | "fal-image" | "openai-image" | "midjourney" | "fal-video" | "zhipu" | "tripo-3d" | "runway"; + type?: "alibaba" | "openai" | "custom" | "local" | "gemini" | "huanke-gemini" | "qianwen-video" | "doubao-video" | "ruxa-video" | "volcano-vision" | "volcano-video" | "alibaba-image" | "bfl-image" | "ruxa-image" | "fal-image" | "openai-image" | "midjourney" | "fal-video" | "zhipu" | "tripo-3d" | "runway"; baseUrl?: string; apiKey?: string; isEnabled?: boolean; diff --git a/lib/db/schema.ts b/lib/db/schema.ts index 9c2a4c573..1bb4099ec 100644 --- a/lib/db/schema.ts +++ b/lib/db/schema.ts @@ -259,7 +259,7 @@ export type ToolConfig = InferSelectModel; export const aiProvider = pgTable("AiProvider", { id: uuid("id").primaryKey().notNull().defaultRandom(), name: varchar("name", { length: 128 }).notNull(), // 提供商名称,如 "阿里云通义千问" - type: varchar("type", { enum: ["alibaba", "openai", "custom", "local", "gemini", "huanke-gemini", "qianwen-video", "doubao-video", "ruxa-video", "volcano-vision", "volcano-video", "alibaba-image", "ruxa-image", "fal-image", "openai-image", "midjourney", "fal-video", "zhipu", "tripo-3d", "runway"] }) + type: varchar("type", { enum: ["alibaba", "openai", "custom", "local", "gemini", "huanke-gemini", "qianwen-video", "doubao-video", "ruxa-video", "volcano-vision", "volcano-video", "alibaba-image", "ruxa-image", "fal-image", "openai-image", "midjourney", "fal-video", "zhipu", "tripo-3d", "runway", "bfl-image"] }) .notNull() .default("custom"), // 提供商类型 baseUrl: text("baseUrl").notNull(), // API 基础 URL