From b00d0eb9e1bf13a072890b5060b999e5545f0274 Mon Sep 17 00:00:00 2001 From: Feng Yue <2525275@gmail.com> Date: Sun, 31 Aug 2025 01:21:25 +0800 Subject: [PATCH] use proxy if configured in all Gemini API requests --- src/routes/admin.js | 2 +- src/routes/geminiRoutes.js | 61 +++++++++++++++++++++++++------- src/routes/openaiGeminiRoutes.js | 19 ++++++++-- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/routes/admin.js b/src/routes/admin.js index ee65dffd..e00a6ee7 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -2395,7 +2395,7 @@ router.post('/gemini-accounts/generate-auth-url', authenticateAdmin, async (req, state: authState, codeVerifier, redirectUri: finalRedirectUri - } = await geminiAccountService.generateAuthUrl(state, redirectUri) + } = await geminiAccountService.generateAuthUrl(state, redirectUri, proxy) // 创建 OAuth 会话,包含 codeVerifier 和代理配置 const sessionId = authState diff --git a/src/routes/geminiRoutes.js b/src/routes/geminiRoutes.js index 2a1525f2..75f633d0 100644 --- a/src/routes/geminiRoutes.js +++ b/src/routes/geminiRoutes.js @@ -331,7 +331,17 @@ async function handleLoadCodeAssist(req, res) { apiKeyId: req.apiKey?.id || 'unknown' }) - const client = await geminiAccountService.getOauthClient(accessToken, refreshToken) + // 解析账户的代理配置 + let proxyConfig = null + if (account.proxy) { + try { + proxyConfig = typeof account.proxy === 'string' ? JSON.parse(account.proxy) : account.proxy + } catch (e) { + logger.warn('Failed to parse proxy configuration:', e) + } + } + + const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig) // 根据账户配置决定项目ID: // 1. 如果账户有项目ID -> 使用账户的项目ID(强制覆盖) @@ -348,7 +358,11 @@ async function handleLoadCodeAssist(req, res) { logger.info('No project ID in account for loadCodeAssist, removing project parameter') } - const response = await geminiAccountService.loadCodeAssist(client, effectiveProjectId) + const response = await geminiAccountService.loadCodeAssist( + client, + effectiveProjectId, + proxyConfig + ) res.json(response) } catch (error) { @@ -387,7 +401,17 @@ async function handleOnboardUser(req, res) { apiKeyId: req.apiKey?.id || 'unknown' }) - const client = await geminiAccountService.getOauthClient(accessToken, refreshToken) + // 解析账户的代理配置 + let proxyConfig = null + if (account.proxy) { + try { + proxyConfig = typeof account.proxy === 'string' ? JSON.parse(account.proxy) : account.proxy + } catch (e) { + logger.warn('Failed to parse proxy configuration:', e) + } + } + + const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig) // 根据账户配置决定项目ID: // 1. 如果账户有项目ID -> 使用账户的项目ID(强制覆盖) @@ -410,7 +434,8 @@ async function handleOnboardUser(req, res) { client, tierId, effectiveProjectId, // 使用处理后的项目ID - metadata + metadata, + proxyConfig ) res.json(response) @@ -419,7 +444,8 @@ async function handleOnboardUser(req, res) { const response = await geminiAccountService.setupUser( client, effectiveProjectId, // 使用处理后的项目ID - metadata + metadata, + proxyConfig ) res.json(response) @@ -460,7 +486,8 @@ async function handleCountTokens(req, res) { sessionHash, model ) - const { accessToken, refreshToken } = await geminiAccountService.getAccount(accountId) + const account = await geminiAccountService.getAccount(accountId) + const { accessToken, refreshToken } = account const version = req.path.includes('v1beta') ? 'v1beta' : 'v1internal' logger.info(`CountTokens request (${version})`, { @@ -469,8 +496,18 @@ async function handleCountTokens(req, res) { apiKeyId: req.apiKey?.id || 'unknown' }) - const client = await geminiAccountService.getOauthClient(accessToken, refreshToken) - const response = await geminiAccountService.countTokens(client, contents, model) + // 解析账户的代理配置 + let proxyConfig = null + if (account.proxy) { + try { + proxyConfig = typeof account.proxy === 'string' ? JSON.parse(account.proxy) : account.proxy + } catch (e) { + logger.warn('Failed to parse proxy configuration:', e) + } + } + + const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig) + const response = await geminiAccountService.countTokens(client, contents, model, proxyConfig) res.json(response) } catch (error) { @@ -544,8 +581,6 @@ async function handleGenerateContent(req, res) { apiKeyId: req.apiKey?.id || 'unknown' }) - const client = await geminiAccountService.getOauthClient(accessToken, refreshToken) - // 解析账户的代理配置 let proxyConfig = null if (account.proxy) { @@ -556,6 +591,8 @@ async function handleGenerateContent(req, res) { } } + const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig) + const response = await geminiAccountService.generateContent( client, { model, request: actualRequestData }, @@ -680,8 +717,6 @@ async function handleStreamGenerateContent(req, res) { } }) - const client = await geminiAccountService.getOauthClient(accessToken, refreshToken) - // 解析账户的代理配置 let proxyConfig = null if (account.proxy) { @@ -692,6 +727,8 @@ async function handleStreamGenerateContent(req, res) { } } + const client = await geminiAccountService.getOauthClient(accessToken, refreshToken, proxyConfig) + const streamResponse = await geminiAccountService.generateContentStream( client, { model, request: actualRequestData }, diff --git a/src/routes/openaiGeminiRoutes.js b/src/routes/openaiGeminiRoutes.js index 5e304f06..54305401 100644 --- a/src/routes/openaiGeminiRoutes.js +++ b/src/routes/openaiGeminiRoutes.js @@ -311,6 +311,16 @@ router.post('/v1/chat/completions', authenticateApiKey, async (req, res) => { // 标记账户被使用 await geminiAccountService.markAccountUsed(account.id) + // 解析账户的代理配置 + let proxyConfig = null + if (account.proxy) { + try { + proxyConfig = typeof account.proxy === 'string' ? JSON.parse(account.proxy) : account.proxy + } catch (e) { + logger.warn('Failed to parse proxy configuration:', e) + } + } + // 创建中止控制器 abortController = new AbortController() @@ -325,7 +335,8 @@ router.post('/v1/chat/completions', authenticateApiKey, async (req, res) => { // 获取OAuth客户端 const client = await geminiAccountService.getOauthClient( account.accessToken, - account.refreshToken + account.refreshToken, + proxyConfig ) if (actualStream) { // 流式响应 @@ -341,7 +352,8 @@ router.post('/v1/chat/completions', authenticateApiKey, async (req, res) => { null, // user_prompt_id account.projectId, // 使用有权限的项目ID apiKeyData.id, // 使用 API Key ID 作为 session ID - abortController.signal // 传递中止信号 + abortController.signal, // 传递中止信号 + proxyConfig // 传递代理配置 ) // 设置流式响应头 @@ -541,7 +553,8 @@ router.post('/v1/chat/completions', authenticateApiKey, async (req, res) => { { model, request: geminiRequestBody }, null, // user_prompt_id account.projectId, // 使用有权限的项目ID - apiKeyData.id // 使用 API Key ID 作为 session ID + apiKeyData.id, // 使用 API Key ID 作为 session ID + proxyConfig // 传递代理配置 ) // 转换为 OpenAI 格式并返回