diff --git a/src/routes/admin.js b/src/routes/admin.js index be522c8d..78fc9767 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -4281,6 +4281,48 @@ router.put( } ) +// 重置 Gemini OAuth 账户限流状态 +router.post('/gemini-accounts/:id/reset-rate-limit', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params + + await geminiAccountService.updateAccount(id, { + rateLimitedAt: '', + rateLimitStatus: '', + status: 'active', + errorMessage: '' + }) + + logger.info(`🔄 Admin manually reset rate limit for Gemini account ${id}`) + + res.json({ + success: true, + message: 'Rate limit reset successfully' + }) + } catch (error) { + logger.error('Failed to reset Gemini account rate limit:', error) + res.status(500).json({ + success: false, + error: error.message + }) + } +}) + +// 重置 Gemini OAuth 账户状态(清除所有异常状态) +router.post('/gemini-accounts/:id/reset-status', authenticateAdmin, async (req, res) => { + try { + const { id } = req.params + + const result = await geminiAccountService.resetAccountStatus(id) + + logger.success(`✅ Admin reset status for Gemini account: ${id}`) + return res.json({ success: true, data: result }) + } catch (error) { + logger.error('❌ Failed to reset Gemini account status:', error) + return res.status(500).json({ error: 'Failed to reset status', message: error.message }) + } +}) + // 📊 账户使用统计 // 获取所有账户的使用统计 diff --git a/src/routes/standardGeminiRoutes.js b/src/routes/standardGeminiRoutes.js index 9e78c62b..c6b0681c 100644 --- a/src/routes/standardGeminiRoutes.js +++ b/src/routes/standardGeminiRoutes.js @@ -402,20 +402,20 @@ async function handleStandardGenerateContent(req, res) { stack: error.stack }) - // 处理速率限制 - if (error.response?.status === 429 && accountId) { - logger.warn(`⚠️ Gemini account ${accountId} rate limited (Standard API), marking as limited`) - try { - const rateLimitAccountType = isApiAccount ? 'gemini-api' : 'gemini' - await unifiedGeminiScheduler.markAccountRateLimited( - accountId, // 账户 ID - rateLimitAccountType, - sessionHash - ) - } catch (limitError) { - logger.warn('Failed to mark account as rate limited in scheduler:', limitError) - } - } + // 处理速率限制 暂时去掉此处的标记限流的处理 + // if (error.response?.status === 429 && accountId) { + // logger.warn(`⚠️ Gemini account ${accountId} rate limited (Standard API), marking as limited`) + // try { + // const rateLimitAccountType = isApiAccount ? 'gemini-api' : 'gemini' + // await unifiedGeminiScheduler.markAccountRateLimited( + // accountId, // 账户 ID + // rateLimitAccountType, + // sessionHash + // ) + // } catch (limitError) { + // logger.warn('Failed to mark account as rate limited in scheduler:', limitError) + // } + // } res.status(500).json({ error: { diff --git a/src/services/geminiAccountService.js b/src/services/geminiAccountService.js index d24368d3..a23d81b3 100644 --- a/src/services/geminiAccountService.js +++ b/src/services/geminiAccountService.js @@ -1616,6 +1616,50 @@ async function updateTempProjectId(accountId, tempProjectId) { } } +// 重置账户状态(清除所有异常状态) +async function resetAccountStatus(accountId) { + const account = await getAccount(accountId) + if (!account) { + throw new Error('Account not found') + } + + const updates = { + // 根据是否有有效的 refreshToken 来设置 status + status: account.refreshToken ? 'active' : 'created', + // 恢复可调度状态 + schedulable: 'true', + // 清除错误相关字段 + errorMessage: '', + rateLimitedAt: '', + rateLimitStatus: '' + } + + await updateAccount(accountId, updates) + logger.info(`✅ Reset all error status for Gemini account ${accountId}`) + + // 发送 Webhook 通知 + try { + const webhookNotifier = require('../utils/webhookNotifier') + await webhookNotifier.sendAccountAnomalyNotification({ + accountId, + accountName: account.name || accountId, + platform: 'gemini', + status: 'recovered', + errorCode: 'STATUS_RESET', + reason: 'Account status manually reset', + timestamp: new Date().toISOString() + }) + logger.info(`📢 Webhook notification sent for Gemini account ${account.name} status reset`) + } catch (webhookError) { + logger.error('Failed to send status reset webhook notification:', webhookError) + } + + return { + success: true, + message: 'Account status reset successfully' + } +} + module.exports = { generateAuthUrl, pollAuthorizationStatus, @@ -1646,6 +1690,7 @@ module.exports = { generateContent, generateContentStream, updateTempProjectId, + resetAccountStatus, OAUTH_CLIENT_ID, OAUTH_SCOPES } diff --git a/web/admin-spa/src/views/AccountsView.vue b/web/admin-spa/src/views/AccountsView.vue index ad50e515..17e751da 100644 --- a/web/admin-spa/src/views/AccountsView.vue +++ b/web/admin-spa/src/views/AccountsView.vue @@ -3054,6 +3054,8 @@ const resetAccountStatus = async (account) => { endpoint = `/admin/droid-accounts/${account.id}/reset-status` } else if (account.platform === 'gemini-api') { endpoint = `/admin/gemini-api-accounts/${account.id}/reset-status` + } else if (account.platform === 'gemini') { + endpoint = `/admin/gemini-accounts/${account.id}/reset-status` } else { showToast('不支持的账户类型', 'error') account.isResetting = false