| import { NextResponse } from "next/server"; |
| import { |
| getProviderConnections, |
| createProviderConnection, |
| getProviderNodeById, |
| getProviderNodes, |
| getProxyPoolById, |
| } from "@/models"; |
| import { APIKEY_PROVIDERS } from "@/shared/constants/config"; |
| import { AI_PROVIDERS, FREE_TIER_PROVIDERS, WEB_COOKIE_PROVIDERS, isOpenAICompatibleProvider, isAnthropicCompatibleProvider, isCustomEmbeddingProvider } from "@/shared/constants/providers"; |
| import { normalizeProviderId, normalizeProviderSpecificData } from "@/lib/providerNormalization"; |
|
|
| export const dynamic = "force-dynamic"; |
|
|
| function normalizeProxyConfig(body = {}) { |
| const enabled = body?.connectionProxyEnabled === true; |
| const url = typeof body?.connectionProxyUrl === "string" ? body.connectionProxyUrl.trim() : ""; |
| const noProxy = typeof body?.connectionNoProxy === "string" ? body.connectionNoProxy.trim() : ""; |
|
|
| if (enabled && !url) { |
| return { error: "Connection proxy URL is required when connection proxy is enabled" }; |
| } |
|
|
| return { |
| connectionProxyEnabled: enabled, |
| connectionProxyUrl: url, |
| connectionNoProxy: noProxy, |
| }; |
| } |
|
|
| async function normalizeProxyPoolId(proxyPoolId) { |
| if (proxyPoolId === undefined || proxyPoolId === null || proxyPoolId === "" || proxyPoolId === "__none__") { |
| return { proxyPoolId: null }; |
| } |
|
|
| const normalizedId = String(proxyPoolId).trim(); |
| if (!normalizedId) { |
| return { proxyPoolId: null }; |
| } |
|
|
| const proxyPool = await getProxyPoolById(normalizedId); |
| if (!proxyPool) { |
| return { error: "Proxy pool not found" }; |
| } |
|
|
| return { proxyPoolId: normalizedId }; |
| } |
|
|
| |
| export async function GET() { |
| try { |
| const connections = await getProviderConnections(); |
|
|
| |
| let nodeNameMap = {}; |
| try { |
| const nodes = await getProviderNodes(); |
| for (const node of nodes) { |
| if (node.id && node.name) nodeNameMap[node.id] = node.name; |
| } |
| } catch { } |
|
|
| |
| const safeConnections = connections.map(c => { |
| const isCompatible = isOpenAICompatibleProvider(c.provider) || isAnthropicCompatibleProvider(c.provider); |
| const name = isCompatible |
| ? (c.name || nodeNameMap[c.provider] || c.providerSpecificData?.nodeName || c.provider) |
| : c.name; |
| return { |
| ...c, |
| name, |
| apiKey: undefined, |
| accessToken: undefined, |
| refreshToken: undefined, |
| idToken: undefined, |
| }; |
| }); |
|
|
| return NextResponse.json({ connections: safeConnections }); |
| } catch (error) { |
| console.log("Error fetching providers:", error); |
| return NextResponse.json({ error: "Failed to fetch providers" }, { status: 500 }); |
| } |
| } |
|
|
| |
| export async function POST(request) { |
| try { |
| const body = await request.json(); |
| const provider = normalizeProviderId(body.provider); |
| const { apiKey, name, displayName, priority, globalPriority, defaultModel, testStatus } = body; |
| const proxyConfig = normalizeProxyConfig(body); |
| if (proxyConfig.error) { |
| return NextResponse.json({ error: proxyConfig.error }, { status: 400 }); |
| } |
|
|
| const proxyPoolResult = await normalizeProxyPoolId(body.proxyPoolId); |
| if (proxyPoolResult.error) { |
| return NextResponse.json({ error: proxyPoolResult.error }, { status: 400 }); |
| } |
| const proxyPoolId = proxyPoolResult.proxyPoolId; |
|
|
| |
| const isWebCookieProvider = !!WEB_COOKIE_PROVIDERS[provider]; |
| const isValidProvider = APIKEY_PROVIDERS[provider] || |
| FREE_TIER_PROVIDERS[provider] || |
| isWebCookieProvider || |
| isOpenAICompatibleProvider(provider) || |
| isAnthropicCompatibleProvider(provider) || |
| isCustomEmbeddingProvider(provider); |
|
|
| if (!provider || !isValidProvider) { |
| return NextResponse.json({ error: "Invalid provider" }, { status: 400 }); |
| } |
| if (!apiKey && provider !== "ollama-local") { |
| return NextResponse.json({ error: `${isWebCookieProvider ? "Cookie value" : "API Key"} is required` }, { status: 400 }); |
| } |
| const connectionName = name || displayName || AI_PROVIDERS[provider]?.name; |
| if (!connectionName) { |
| return NextResponse.json({ error: "Name is required" }, { status: 400 }); |
| } |
|
|
| let providerSpecificData = normalizeProviderSpecificData(provider, body, body.providerSpecificData); |
|
|
| |
| |
| |
| if (isOpenAICompatibleProvider(provider)) { |
| const node = await getProviderNodeById(provider); |
| if (!node) { |
| return NextResponse.json({ error: "OpenAI Compatible node not found" }, { status: 404 }); |
| } |
| const existingConnections = await getProviderConnections({ provider }); |
| if (existingConnections.length > 0) { |
| return NextResponse.json({ error: "Only one connection is allowed for this OpenAI Compatible node" }, { status: 400 }); |
| } |
| providerSpecificData = { |
| prefix: node.prefix, |
| apiType: node.apiType, |
| baseUrl: node.baseUrl, |
| nodeName: node.name, |
| }; |
| } else if (isAnthropicCompatibleProvider(provider)) { |
| const node = await getProviderNodeById(provider); |
| if (!node) { |
| return NextResponse.json({ error: "Anthropic Compatible node not found" }, { status: 404 }); |
| } |
| const existingConnections = await getProviderConnections({ provider }); |
| if (existingConnections.length > 0) { |
| return NextResponse.json({ error: "Only one connection is allowed for this Anthropic Compatible node" }, { status: 400 }); |
| } |
| providerSpecificData = { |
| prefix: node.prefix, |
| baseUrl: node.baseUrl, |
| nodeName: node.name, |
| }; |
| } else if (isCustomEmbeddingProvider(provider)) { |
| const node = await getProviderNodeById(provider); |
| if (!node) { |
| return NextResponse.json({ error: "Custom Embedding node not found" }, { status: 404 }); |
| } |
| const existingConnections = await getProviderConnections({ provider }); |
| if (existingConnections.length > 0) { |
| return NextResponse.json({ error: "Only one connection is allowed for this Custom Embedding node" }, { status: 400 }); |
| } |
| providerSpecificData = { |
| prefix: node.prefix, |
| baseUrl: node.baseUrl, |
| nodeName: node.name, |
| }; |
| } |
|
|
| const mergedProviderSpecificData = { |
| ...(providerSpecificData || {}), |
| connectionProxyEnabled: proxyConfig.connectionProxyEnabled, |
| connectionProxyUrl: proxyConfig.connectionProxyUrl, |
| connectionNoProxy: proxyConfig.connectionNoProxy, |
| }; |
|
|
| if (proxyPoolId !== null) { |
| mergedProviderSpecificData.proxyPoolId = proxyPoolId; |
| } |
|
|
| const newConnection = await createProviderConnection({ |
| provider, |
| authType: isWebCookieProvider ? "cookie" : "apikey", |
| name: connectionName, |
| apiKey: apiKey || "", |
| priority: priority || 1, |
| globalPriority: globalPriority || null, |
| defaultModel: defaultModel || null, |
| providerSpecificData: mergedProviderSpecificData, |
| isActive: true, |
| testStatus: testStatus || "unknown", |
| }); |
|
|
| |
| const result = { ...newConnection }; |
| delete result.apiKey; |
|
|
| return NextResponse.json({ connection: result }, { status: 201 }); |
| } catch (error) { |
| console.log("Error creating provider:", error); |
| return NextResponse.json({ error: "Failed to create provider" }, { status: 500 }); |
| } |
| } |
|
|