|
|
|
|
@@ -223,6 +223,7 @@ func (h *Handler) PatchGeminiKey(c *gin.Context) {
|
|
|
|
|
value.APIKey = strings.TrimSpace(value.APIKey)
|
|
|
|
|
value.BaseURL = strings.TrimSpace(value.BaseURL)
|
|
|
|
|
value.ProxyURL = strings.TrimSpace(value.ProxyURL)
|
|
|
|
|
value.ExcludedModels = config.NormalizeExcludedModels(value.ExcludedModels)
|
|
|
|
|
if value.APIKey == "" {
|
|
|
|
|
// Treat empty API key as delete.
|
|
|
|
|
if body.Index != nil && *body.Index >= 0 && *body.Index < len(h.cfg.GeminiKey) {
|
|
|
|
|
@@ -504,6 +505,91 @@ func (h *Handler) DeleteOpenAICompat(c *gin.Context) {
|
|
|
|
|
c.JSON(400, gin.H{"error": "missing name or index"})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// oauth-excluded-models: map[string][]string
|
|
|
|
|
func (h *Handler) GetOAuthExcludedModels(c *gin.Context) {
|
|
|
|
|
c.JSON(200, gin.H{"oauth-excluded-models": config.NormalizeOAuthExcludedModels(h.cfg.OAuthExcludedModels)})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *Handler) PutOAuthExcludedModels(c *gin.Context) {
|
|
|
|
|
data, err := c.GetRawData()
|
|
|
|
|
if err != nil {
|
|
|
|
|
c.JSON(400, gin.H{"error": "failed to read body"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var entries map[string][]string
|
|
|
|
|
if err = json.Unmarshal(data, &entries); err != nil {
|
|
|
|
|
var wrapper struct {
|
|
|
|
|
Items map[string][]string `json:"items"`
|
|
|
|
|
}
|
|
|
|
|
if err2 := json.Unmarshal(data, &wrapper); err2 != nil {
|
|
|
|
|
c.JSON(400, gin.H{"error": "invalid body"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
entries = wrapper.Items
|
|
|
|
|
}
|
|
|
|
|
h.cfg.OAuthExcludedModels = config.NormalizeOAuthExcludedModels(entries)
|
|
|
|
|
h.persist(c)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *Handler) PatchOAuthExcludedModels(c *gin.Context) {
|
|
|
|
|
var body struct {
|
|
|
|
|
Provider *string `json:"provider"`
|
|
|
|
|
Models []string `json:"models"`
|
|
|
|
|
}
|
|
|
|
|
if err := c.ShouldBindJSON(&body); err != nil || body.Provider == nil {
|
|
|
|
|
c.JSON(400, gin.H{"error": "invalid body"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
provider := strings.ToLower(strings.TrimSpace(*body.Provider))
|
|
|
|
|
if provider == "" {
|
|
|
|
|
c.JSON(400, gin.H{"error": "invalid provider"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
normalized := config.NormalizeExcludedModels(body.Models)
|
|
|
|
|
if len(normalized) == 0 {
|
|
|
|
|
if h.cfg.OAuthExcludedModels == nil {
|
|
|
|
|
c.JSON(404, gin.H{"error": "provider not found"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if _, ok := h.cfg.OAuthExcludedModels[provider]; !ok {
|
|
|
|
|
c.JSON(404, gin.H{"error": "provider not found"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
delete(h.cfg.OAuthExcludedModels, provider)
|
|
|
|
|
if len(h.cfg.OAuthExcludedModels) == 0 {
|
|
|
|
|
h.cfg.OAuthExcludedModels = nil
|
|
|
|
|
}
|
|
|
|
|
h.persist(c)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if h.cfg.OAuthExcludedModels == nil {
|
|
|
|
|
h.cfg.OAuthExcludedModels = make(map[string][]string)
|
|
|
|
|
}
|
|
|
|
|
h.cfg.OAuthExcludedModels[provider] = normalized
|
|
|
|
|
h.persist(c)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *Handler) DeleteOAuthExcludedModels(c *gin.Context) {
|
|
|
|
|
provider := strings.ToLower(strings.TrimSpace(c.Query("provider")))
|
|
|
|
|
if provider == "" {
|
|
|
|
|
c.JSON(400, gin.H{"error": "missing provider"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if h.cfg.OAuthExcludedModels == nil {
|
|
|
|
|
c.JSON(404, gin.H{"error": "provider not found"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if _, ok := h.cfg.OAuthExcludedModels[provider]; !ok {
|
|
|
|
|
c.JSON(404, gin.H{"error": "provider not found"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
delete(h.cfg.OAuthExcludedModels, provider)
|
|
|
|
|
if len(h.cfg.OAuthExcludedModels) == 0 {
|
|
|
|
|
h.cfg.OAuthExcludedModels = nil
|
|
|
|
|
}
|
|
|
|
|
h.persist(c)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// codex-api-key: []CodexKey
|
|
|
|
|
func (h *Handler) GetCodexKeys(c *gin.Context) {
|
|
|
|
|
c.JSON(200, gin.H{"codex-api-key": h.cfg.CodexKey})
|
|
|
|
|
@@ -533,6 +619,7 @@ func (h *Handler) PutCodexKeys(c *gin.Context) {
|
|
|
|
|
entry.BaseURL = strings.TrimSpace(entry.BaseURL)
|
|
|
|
|
entry.ProxyURL = strings.TrimSpace(entry.ProxyURL)
|
|
|
|
|
entry.Headers = config.NormalizeHeaders(entry.Headers)
|
|
|
|
|
entry.ExcludedModels = config.NormalizeExcludedModels(entry.ExcludedModels)
|
|
|
|
|
if entry.BaseURL == "" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
@@ -557,6 +644,7 @@ func (h *Handler) PatchCodexKey(c *gin.Context) {
|
|
|
|
|
value.BaseURL = strings.TrimSpace(value.BaseURL)
|
|
|
|
|
value.ProxyURL = strings.TrimSpace(value.ProxyURL)
|
|
|
|
|
value.Headers = config.NormalizeHeaders(value.Headers)
|
|
|
|
|
value.ExcludedModels = config.NormalizeExcludedModels(value.ExcludedModels)
|
|
|
|
|
// If base-url becomes empty, delete instead of update
|
|
|
|
|
if value.BaseURL == "" {
|
|
|
|
|
if body.Index != nil && *body.Index >= 0 && *body.Index < len(h.cfg.CodexKey) {
|
|
|
|
|
@@ -694,6 +782,7 @@ func normalizeClaudeKey(entry *config.ClaudeKey) {
|
|
|
|
|
entry.BaseURL = strings.TrimSpace(entry.BaseURL)
|
|
|
|
|
entry.ProxyURL = strings.TrimSpace(entry.ProxyURL)
|
|
|
|
|
entry.Headers = config.NormalizeHeaders(entry.Headers)
|
|
|
|
|
entry.ExcludedModels = config.NormalizeExcludedModels(entry.ExcludedModels)
|
|
|
|
|
if len(entry.Models) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|