mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
feat: 新增 OpenAI-Responses 账户管理功能和独立自动停止标记机制
## 功能新增 - 实现 OpenAI-Responses 账户服务(openaiResponsesAccountService.js) - 支持使用账户内置 API Key 进行请求转发 - 实现每日额度管理和重置机制 - 支持代理配置和优先级设置 - 实现 OpenAI-Responses 中继服务(openaiResponsesRelayService.js) - 处理请求转发和响应流处理 - 自动记录使用统计信息 - 支持流式和非流式响应 - 新增管理界面的 OpenAI-Responses 账户管理功能 - 完整的 CRUD 操作支持 - 实时额度监控和状态管理 - 支持手动重置限流和每日额度 ## 架构改进 - 引入独立的自动停止标记机制,区分不同原因的自动停止 - rateLimitAutoStopped: 限流自动停止 - fiveHourAutoStopped: 5小时限制自动停止 - tempErrorAutoStopped: 临时错误自动停止 - quotaAutoStopped: 额度耗尽自动停止 - 修复手动修改调度状态时自动恢复的问题 - 统一清理逻辑,防止状态冲突 ## 其他优化 - getAccountUsageStats 支持不同账户类型参数 - 统一调度器支持 OpenAI-Responses 账户类型 - WebHook 通知增强,支持新账户类型的事件 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1849,6 +1849,7 @@ const accounts = ref({
|
||||
claude: [],
|
||||
gemini: [],
|
||||
openai: [],
|
||||
openaiResponses: [], // 添加 OpenAI-Responses 账号列表
|
||||
bedrock: [],
|
||||
claudeGroups: [],
|
||||
geminiGroups: [],
|
||||
@@ -2016,15 +2017,23 @@ const paginatedApiKeys = computed(() => {
|
||||
// 加载账户列表
|
||||
const loadAccounts = async () => {
|
||||
try {
|
||||
const [claudeData, claudeConsoleData, geminiData, openaiData, bedrockData, groupsData] =
|
||||
await Promise.all([
|
||||
apiClient.get('/admin/claude-accounts'),
|
||||
apiClient.get('/admin/claude-console-accounts'),
|
||||
apiClient.get('/admin/gemini-accounts'),
|
||||
apiClient.get('/admin/openai-accounts'),
|
||||
apiClient.get('/admin/bedrock-accounts'),
|
||||
apiClient.get('/admin/account-groups')
|
||||
])
|
||||
const [
|
||||
claudeData,
|
||||
claudeConsoleData,
|
||||
geminiData,
|
||||
openaiData,
|
||||
openaiResponsesData,
|
||||
bedrockData,
|
||||
groupsData
|
||||
] = await Promise.all([
|
||||
apiClient.get('/admin/claude-accounts'),
|
||||
apiClient.get('/admin/claude-console-accounts'),
|
||||
apiClient.get('/admin/gemini-accounts'),
|
||||
apiClient.get('/admin/openai-accounts'),
|
||||
apiClient.get('/admin/openai-responses-accounts'), // 加载 OpenAI-Responses 账号
|
||||
apiClient.get('/admin/bedrock-accounts'),
|
||||
apiClient.get('/admin/account-groups')
|
||||
])
|
||||
|
||||
// 合并Claude OAuth账户和Claude Console账户
|
||||
const claudeAccounts = []
|
||||
@@ -2065,6 +2074,13 @@ const loadAccounts = async () => {
|
||||
}))
|
||||
}
|
||||
|
||||
if (openaiResponsesData.success) {
|
||||
accounts.value.openaiResponses = (openaiResponsesData.data || []).map((account) => ({
|
||||
...account,
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
}))
|
||||
}
|
||||
|
||||
if (bedrockData.success) {
|
||||
accounts.value.bedrock = (bedrockData.data || []).map((account) => ({
|
||||
...account,
|
||||
@@ -2209,12 +2225,31 @@ const getBoundAccountName = (accountId) => {
|
||||
return `${geminiAccount.name}`
|
||||
}
|
||||
|
||||
// 处理 responses: 前缀的 OpenAI-Responses 账户
|
||||
if (accountId.startsWith('responses:')) {
|
||||
const realAccountId = accountId.replace('responses:', '')
|
||||
const openaiResponsesAccount = accounts.value.openaiResponses.find(
|
||||
(acc) => acc.id === realAccountId
|
||||
)
|
||||
if (openaiResponsesAccount) {
|
||||
return `${openaiResponsesAccount.name}`
|
||||
}
|
||||
// 如果找不到,返回ID的前8位
|
||||
return `${realAccountId.substring(0, 8)}`
|
||||
}
|
||||
|
||||
// 从OpenAI账户列表中查找
|
||||
const openaiAccount = accounts.value.openai.find((acc) => acc.id === accountId)
|
||||
if (openaiAccount) {
|
||||
return `${openaiAccount.name}`
|
||||
}
|
||||
|
||||
// 从 OpenAI-Responses 账户列表中查找(兼容没有前缀的情况)
|
||||
const openaiResponsesAccount = accounts.value.openaiResponses.find((acc) => acc.id === accountId)
|
||||
if (openaiResponsesAccount) {
|
||||
return `${openaiResponsesAccount.name}`
|
||||
}
|
||||
|
||||
// 从Bedrock账户列表中查找
|
||||
const bedrockAccount = accounts.value.bedrock.find((acc) => acc.id === accountId)
|
||||
if (bedrockAccount) {
|
||||
@@ -2281,8 +2316,17 @@ const getOpenAIBindingInfo = (key) => {
|
||||
if (key.openaiAccountId.startsWith('group:')) {
|
||||
return info
|
||||
}
|
||||
// 检查账户是否存在
|
||||
const account = accounts.value.openai.find((acc) => acc.id === key.openaiAccountId)
|
||||
|
||||
// 处理 responses: 前缀的 OpenAI-Responses 账户
|
||||
let account = null
|
||||
if (key.openaiAccountId.startsWith('responses:')) {
|
||||
const realAccountId = key.openaiAccountId.replace('responses:', '')
|
||||
account = accounts.value.openaiResponses.find((acc) => acc.id === realAccountId)
|
||||
} else {
|
||||
// 查找普通 OpenAI 账户
|
||||
account = accounts.value.openai.find((acc) => acc.id === key.openaiAccountId)
|
||||
}
|
||||
|
||||
if (!account) {
|
||||
return `⚠️ ${info} (账户不存在)`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user