feat: OAuth 导入导出、提供商筛选、Gemini 图像生成支持与流式处理增强

- OAuth: 支持通过 Refresh Token 导入账号(文件拖拽/粘贴),OAuth Key 可导出为 JSON
- OAuth: 所有 OAuth 端点添加 require_admin 鉴权
- 提供商管理: 新增状态/API格式/模型三级筛选,后端返回 global_model_ids
- Gemini: 新增图像生成模型适配(finalize_provider_request 钩子 + envelope 跳过不兼容字段)
- 流式处理: buffer 残留数据 flush 与 token 兜底估算
- 上游元数据: 提取 merge_upstream_metadata,配额耗尽模型保留与深度合并
- Antigravity 配额: 无 quotaInfo 时视为耗尽,移除 Other 兜底分组
- README: 新增升级备份与回滚指南
This commit is contained in:
fawney19
2026-02-06 21:52:22 +08:00
parent 62dae22a2c
commit 8b6a5d3824
23 changed files with 1129 additions and 101 deletions

View File

@@ -30,6 +30,7 @@ from src.models.endpoint_models import (
EndpointAPIKeyUpdate,
)
from src.services.cache.provider_cache import ProviderCacheService
from src.services.model.upstream_fetcher import merge_upstream_metadata
from src.utils.auth_utils import require_admin
router = APIRouter(tags=["Provider Keys"])
@@ -467,6 +468,29 @@ class AdminRevealEndpointKeyAdapter(AdminApiAdapter):
"无法解密认证配置,可能是加密密钥已更改。请重新添加该密钥。"
)
# OAuth 类型:返回 access_token + refresh_token
if auth_type == "oauth":
try:
decrypted_key = crypto_service.decrypt(key.api_key)
except Exception as e:
logger.error(f"解密 Key 失败: ID={self.key_id}, Error={e}")
raise InvalidRequestException(
"无法解密 API Key可能是加密密钥已更改。请重新添加该密钥。"
)
result: dict[str, Any] = {"auth_type": "oauth", "api_key": decrypted_key}
encrypted_auth_config = getattr(key, "auth_config", None)
if encrypted_auth_config:
try:
decrypted_config = crypto_service.decrypt(encrypted_auth_config)
auth_config = json.loads(decrypted_config)
refresh_token = auth_config.get("refresh_token")
if refresh_token:
result["refresh_token"] = refresh_token
except Exception as e:
logger.error(f"解密 auth_config 失败: ID={self.key_id}, Error={e}")
logger.info(f"[REVEAL] 查看 OAuth Key: ID={self.key_id}, Name={key.name}")
return result
# API Key 类型返回 api_key
try:
decrypted_key = crypto_service.decrypt(key.api_key)
@@ -1178,13 +1202,9 @@ class AdminRefreshProviderQuotaAdapter(AdminApiAdapter):
if key.id in metadata_updates:
updates = metadata_updates[key.id]
if isinstance(updates, dict):
# NOTE: upstream_metadata is a plain JSON column (not MutableDict),
# so in-place mutation won't be persisted reliably. Always assign
# a new dict object to mark the column as dirty.
current = key.upstream_metadata
merged: dict = dict(current) if isinstance(current, dict) else {}
merged.update(updates)
key.upstream_metadata = merged
key.upstream_metadata = merge_upstream_metadata(
key.upstream_metadata, updates
)
db.add(key)
# 提交数据库更改