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:
shaw
2025-09-10 15:41:52 +08:00
parent 1c3b74f45b
commit 08946c67ea
17 changed files with 3061 additions and 238 deletions

View File

@@ -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} (账户不存在)`
}