feat: 添加账号时支持同步上游模型

新增 POST /admin/accounts/models/sync-upstream-preview 端点,
允许在创建账号流程中直接使用凭证同步上游支持的模型,
无需先保存账号获取 ID。

- 后端: 新增 SyncUpstreamModelsPreview handler
- 前端: 新增 syncUpstreamModelsPreview API 函数
- 前端: ModelWhitelistSelector 支持 syncCredentials prop
- 前端: CreateAccountModal 传递凭证给 ModelWhitelistSelector
This commit is contained in:
benjamin
2026-05-30 12:19:38 +08:00
parent f18451e56f
commit 57d9e15e04
5 changed files with 109 additions and 8 deletions
@@ -2131,6 +2131,56 @@ func (h *AccountHandler) SyncUpstreamModels(c *gin.Context) {
response.Success(c, gin.H{"models": models})
}
// SyncUpstreamModelsPreview handles syncing live supported models using provided credentials (no account ID needed).
// POST /api/v1/admin/accounts/models/sync-upstream-preview
func (h *AccountHandler) SyncUpstreamModelsPreview(c *gin.Context) {
var req struct {
Platform string `json:"platform" binding:"required"`
Type string `json:"type" binding:"required"`
BaseURL string `json:"base_url"`
APIKey string `json:"api_key" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request: "+err.Error())
return
}
tempAccount := &service.Account{
Platform: req.Platform,
Type: req.Type,
Credentials: map[string]any{
"api_key": req.APIKey,
"base_url": req.BaseURL,
},
}
if h.accountTestService == nil {
response.InternalError(c, "Account test service is not configured")
return
}
models, err := h.accountTestService.FetchUpstreamSupportedModels(c.Request.Context(), tempAccount)
if err != nil {
var syncErr *service.UpstreamModelSyncError
if errors.As(err, &syncErr) {
switch syncErr.Kind {
case service.UpstreamModelSyncErrorConfiguration, service.UpstreamModelSyncErrorUnsupported:
response.BadRequest(c, syncErr.SafeMessage())
default:
slog.Warn("sync_upstream_models_preview_failed", "platform", req.Platform, "kind", syncErr.Kind)
response.Error(c, http.StatusBadGateway, syncErr.SafeMessage())
}
return
}
slog.Warn("sync_upstream_models_preview_failed", "platform", req.Platform)
response.Error(c, http.StatusBadGateway, "Failed to sync upstream models from upstream")
return
}
response.Success(c, gin.H{"models": models})
}
// SetPrivacy handles setting privacy for a single OpenAI/Antigravity OAuth account
// POST /api/v1/admin/accounts/:id/set-privacy
func (h *AccountHandler) SetPrivacy(c *gin.Context) {
+1
View File
@@ -302,6 +302,7 @@ func registerAccountRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
accounts.GET("/:id/temp-unschedulable", h.Admin.Account.GetTempUnschedulable)
accounts.DELETE("/:id/temp-unschedulable", h.Admin.Account.ClearTempUnschedulable)
accounts.POST("/:id/schedulable", h.Admin.Account.SetSchedulable)
accounts.POST("/models/sync-upstream-preview", h.Admin.Account.SyncUpstreamModelsPreview)
accounts.GET("/:id/models", h.Admin.Account.GetAvailableModels)
accounts.POST("/:id/models/sync-upstream", h.Admin.Account.SyncUpstreamModels)
accounts.POST("/batch", h.Admin.Account.BatchCreate)