mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
fix: 添加 OpenAI 兼容路由对 Claude Console 账户的支持
This commit is contained in:
@@ -8,6 +8,7 @@ const router = express.Router()
|
|||||||
const logger = require('../utils/logger')
|
const logger = require('../utils/logger')
|
||||||
const { authenticateApiKey } = require('../middleware/auth')
|
const { authenticateApiKey } = require('../middleware/auth')
|
||||||
const claudeRelayService = require('../services/claudeRelayService')
|
const claudeRelayService = require('../services/claudeRelayService')
|
||||||
|
const claudeConsoleRelayService = require('../services/claudeConsoleRelayService')
|
||||||
const openaiToClaude = require('../services/openaiToClaude')
|
const openaiToClaude = require('../services/openaiToClaude')
|
||||||
const apiKeyService = require('../services/apiKeyService')
|
const apiKeyService = require('../services/apiKeyService')
|
||||||
const unifiedClaudeScheduler = require('../services/unifiedClaudeScheduler')
|
const unifiedClaudeScheduler = require('../services/unifiedClaudeScheduler')
|
||||||
@@ -235,7 +236,7 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
|||||||
}
|
}
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
const { accountId } = accountSelection
|
const { accountId, accountType } = accountSelection
|
||||||
|
|
||||||
// 获取该账号存储的 Claude Code headers
|
// 获取该账号存储的 Claude Code headers
|
||||||
const claudeCodeHeaders = await claudeCodeHeadersService.getAccountHeaders(accountId)
|
const claudeCodeHeaders = await claudeCodeHeadersService.getAccountHeaders(accountId)
|
||||||
@@ -265,13 +266,9 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 使用转换后的响应流 (使用 OAuth-only beta header,添加 Claude Code 必需的 headers)
|
// 使用转换后的响应流 (根据账户类型选择转发服务)
|
||||||
await claudeRelayService.relayStreamRequestWithUsageCapture(
|
// 创建 usage 回调函数
|
||||||
claudeRequest,
|
const usageCallback = (usage) => {
|
||||||
apiKeyData,
|
|
||||||
res,
|
|
||||||
claudeCodeHeaders,
|
|
||||||
(usage) => {
|
|
||||||
// 记录使用统计
|
// 记录使用统计
|
||||||
if (usage && usage.input_tokens !== undefined && usage.output_tokens !== undefined) {
|
if (usage && usage.input_tokens !== undefined && usage.output_tokens !== undefined) {
|
||||||
const model = usage.model || claudeRequest.model
|
const model = usage.model || claudeRequest.model
|
||||||
@@ -288,7 +285,8 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
|||||||
apiKeyData.id,
|
apiKeyData.id,
|
||||||
usage, // 直接传递整个 usage 对象,包含可能的 cache_creation 详细数据
|
usage, // 直接传递整个 usage 对象,包含可能的 cache_creation 详细数据
|
||||||
model,
|
model,
|
||||||
accountId
|
accountId,
|
||||||
|
accountType
|
||||||
)
|
)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error('❌ Failed to record usage:', error)
|
logger.error('❌ Failed to record usage:', error)
|
||||||
@@ -303,27 +301,62 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
|||||||
cacheReadTokens
|
cacheReadTokens
|
||||||
},
|
},
|
||||||
model,
|
model,
|
||||||
'openai-claude-stream'
|
`openai-${accountType}-stream`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
// 流转换器
|
|
||||||
(() => {
|
// 创建流转换器
|
||||||
// 为每个请求创建独立的会话ID
|
|
||||||
const sessionId = `chatcmpl-${Math.random().toString(36).substring(2, 15)}${Math.random().toString(36).substring(2, 15)}`
|
const sessionId = `chatcmpl-${Math.random().toString(36).substring(2, 15)}${Math.random().toString(36).substring(2, 15)}`
|
||||||
return (chunk) => openaiToClaude.convertStreamChunk(chunk, req.body.model, sessionId)
|
const streamTransformer = (chunk) =>
|
||||||
})(),
|
openaiToClaude.convertStreamChunk(chunk, req.body.model, sessionId)
|
||||||
|
|
||||||
|
// 根据账户类型选择转发服务
|
||||||
|
if (accountType === 'claude-console') {
|
||||||
|
// Claude Console 账户使用 Console 转发服务
|
||||||
|
await claudeConsoleRelayService.relayStreamRequestWithUsageCapture(
|
||||||
|
claudeRequest,
|
||||||
|
apiKeyData,
|
||||||
|
res,
|
||||||
|
claudeCodeHeaders,
|
||||||
|
usageCallback,
|
||||||
|
accountId,
|
||||||
|
streamTransformer
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Claude Official 账户使用标准转发服务
|
||||||
|
await claudeRelayService.relayStreamRequestWithUsageCapture(
|
||||||
|
claudeRequest,
|
||||||
|
apiKeyData,
|
||||||
|
res,
|
||||||
|
claudeCodeHeaders,
|
||||||
|
usageCallback,
|
||||||
|
streamTransformer,
|
||||||
{
|
{
|
||||||
betaHeader:
|
betaHeader:
|
||||||
'oauth-2025-04-20,claude-code-20250219,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14'
|
'oauth-2025-04-20,claude-code-20250219,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 非流式请求
|
// 非流式请求
|
||||||
logger.info(`📄 Processing OpenAI non-stream request for model: ${req.body.model}`)
|
logger.info(`📄 Processing OpenAI non-stream request for model: ${req.body.model}`)
|
||||||
|
|
||||||
// 发送请求到 Claude (使用 OAuth-only beta header,添加 Claude Code 必需的 headers)
|
// 根据账户类型选择转发服务
|
||||||
const claudeResponse = await claudeRelayService.relayRequest(
|
let claudeResponse
|
||||||
|
if (accountType === 'claude-console') {
|
||||||
|
// Claude Console 账户使用 Console 转发服务
|
||||||
|
claudeResponse = await claudeConsoleRelayService.relayRequest(
|
||||||
|
claudeRequest,
|
||||||
|
apiKeyData,
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
claudeCodeHeaders,
|
||||||
|
accountId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Claude Official 账户使用标准转发服务
|
||||||
|
claudeResponse = await claudeRelayService.relayRequest(
|
||||||
claudeRequest,
|
claudeRequest,
|
||||||
apiKeyData,
|
apiKeyData,
|
||||||
req,
|
req,
|
||||||
@@ -331,6 +364,7 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
|||||||
claudeCodeHeaders,
|
claudeCodeHeaders,
|
||||||
{ betaHeader: 'oauth-2025-04-20' }
|
{ betaHeader: 'oauth-2025-04-20' }
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 解析 Claude 响应
|
// 解析 Claude 响应
|
||||||
let claudeData
|
let claudeData
|
||||||
@@ -376,7 +410,8 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
|||||||
apiKeyData.id,
|
apiKeyData.id,
|
||||||
usage, // 直接传递整个 usage 对象,包含可能的 cache_creation 详细数据
|
usage, // 直接传递整个 usage 对象,包含可能的 cache_creation 详细数据
|
||||||
claudeRequest.model,
|
claudeRequest.model,
|
||||||
accountId
|
accountId,
|
||||||
|
accountType
|
||||||
)
|
)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error('❌ Failed to record usage:', error)
|
logger.error('❌ Failed to record usage:', error)
|
||||||
@@ -391,7 +426,7 @@ async function handleChatCompletion(req, res, apiKeyData) {
|
|||||||
cacheReadTokens
|
cacheReadTokens
|
||||||
},
|
},
|
||||||
claudeRequest.model,
|
claudeRequest.model,
|
||||||
'openai-claude-non-stream'
|
`openai-${accountType}-non-stream`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user