diff --git a/src/services/account/openaiResponsesAccountService.js b/src/services/account/openaiResponsesAccountService.js index e16c7129..dc1517e0 100644 --- a/src/services/account/openaiResponsesAccountService.js +++ b/src/services/account/openaiResponsesAccountService.js @@ -51,7 +51,8 @@ class OpenAIResponsesAccountService { dailyQuota = 0, // 每日额度限制(美元),0表示不限制 quotaResetTime = '00:00', // 额度重置时间(HH:mm格式) rateLimitDuration = 60, // 限流时间(分钟) - disableAutoProtection = false // 是否关闭自动防护(429/401/400/529 不自动禁用) + disableAutoProtection = false, // 是否关闭自动防护(429/401/400/529 不自动禁用) + providerEndpoint = 'responses' // Provider 端点类型:responses | completions | auto } = options // 验证必填字段 @@ -96,7 +97,8 @@ class OpenAIResponsesAccountService { lastResetDate: redis.getDateStringInTimezone(), quotaResetTime, quotaStoppedAt: '', - disableAutoProtection: disableAutoProtection.toString() // 关闭自动防护 + disableAutoProtection: disableAutoProtection.toString(), // 关闭自动防护 + providerEndpoint // Provider 端点类型:responses(默认) | completions | auto } // 保存到 Redis diff --git a/src/services/relay/openaiResponsesRelayService.js b/src/services/relay/openaiResponsesRelayService.js index 1cb06e13..f1a6f8fc 100644 --- a/src/services/relay/openaiResponsesRelayService.js +++ b/src/services/relay/openaiResponsesRelayService.js @@ -91,8 +91,22 @@ class OpenAIResponsesRelayService { req.once('close', handleClientDisconnect) res.once('close', handleClientDisconnect) - // 构建目标 URL - const targetUrl = `${fullAccount.baseApi}${req.path}` + // 构建目标 URL(根据 providerEndpoint 配置决定端点路径) + const providerEndpoint = fullAccount.providerEndpoint || 'responses' + let targetPath = req.path + if (providerEndpoint === 'responses' && targetPath.includes('/completions')) { + // Provider 仅支持 Responses 端点,将 completions 路径归一化 + targetPath = '/v1/responses' + logger.info(`📝 Normalized path (${req.path}) → /v1/responses (providerEndpoint=responses)`) + } else if (providerEndpoint === 'completions' && targetPath.includes('/responses')) { + // Provider 仅支持 Completions 端点,将 responses 路径归一化 + targetPath = '/v1/chat/completions' + logger.info( + `📝 Normalized path (${req.path}) → /v1/chat/completions (providerEndpoint=completions)` + ) + } + // providerEndpoint === 'auto' 时保持原始路径不变 + const targetUrl = `${fullAccount.baseApi}${targetPath}` logger.info(`🎯 Forwarding to: ${targetUrl}`) // 构建请求头 - 使用统一的 headerFilter 移除 CDN headers diff --git a/web/admin-spa/src/components/accounts/AccountForm.vue b/web/admin-spa/src/components/accounts/AccountForm.vue index ce2eb71e..dddcf150 100644 --- a/web/admin-spa/src/components/accounts/AccountForm.vue +++ b/web/admin-spa/src/components/accounts/AccountForm.vue @@ -1692,6 +1692,24 @@
++ 指定 Provider 支持的端点类型。Responses 会将所有请求路由到 /v1/responses;Chat + Completions 路由到 /v1/chat/completions;自动则保持客户端请求的原始路径 +
++ 指定 Provider 支持的端点类型。Responses 路由到 /v1/responses;Chat Completions + 路由到 /v1/chat/completions;自动则保持原始路径 +
+