Initial commit: CarrotAssistant backend (Go + Gin + SQLite, OpenAI-compatible agent runtime)
This commit is contained in:
116
internal/server/handlers_models.go
Normal file
116
internal/server/handlers_models.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"code.littlelan.cn/CarrotAssistant/backend/internal/security"
|
||||
"code.littlelan.cn/CarrotAssistant/backend/internal/store"
|
||||
)
|
||||
|
||||
type modelConfigReq struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
BaseURL string `json:"base_url" binding:"required"`
|
||||
APIKey string `json:"api_key"`
|
||||
DefaultModel string `json:"default_model" binding:"required"`
|
||||
SupportsTools *bool `json:"supports_tools"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
}
|
||||
|
||||
// GET /admin/model-configs
|
||||
func (d Deps) handleListModels(c *gin.Context) {
|
||||
var list []store.ModelConfig
|
||||
d.DB.Order("id DESC").Find(&list)
|
||||
c.JSON(http.StatusOK, list)
|
||||
}
|
||||
|
||||
// POST /admin/model-configs
|
||||
func (d Deps) handleCreateModel(c *gin.Context) {
|
||||
var req modelConfigReq
|
||||
if !bind(c, &req) {
|
||||
return
|
||||
}
|
||||
req.BaseURL = strings.TrimRight(strings.TrimSpace(req.BaseURL), "/")
|
||||
enc, err := d.Crypto.Encrypt(req.APIKey)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "加密失败"})
|
||||
return
|
||||
}
|
||||
m := store.ModelConfig{
|
||||
Name: req.Name,
|
||||
BaseURL: req.BaseURL,
|
||||
APIKeyEncrypted: enc,
|
||||
APIKeyPreview: security.GenerateAPIKeyPreview(req.APIKey),
|
||||
DefaultModel: req.DefaultModel,
|
||||
SupportsTools: req.SupportsTools == nil || *req.SupportsTools,
|
||||
MaxTokens: req.MaxTokens,
|
||||
}
|
||||
if err := d.DB.Create(&m).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
||||
c.JSON(http.StatusConflict, gin.H{"error": "名称已存在"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "创建失败"})
|
||||
return
|
||||
}
|
||||
d.audit(c, nil, nil, "model_config.create", map[string]any{"id": m.ID, "name": m.Name})
|
||||
c.JSON(http.StatusOK, m)
|
||||
}
|
||||
|
||||
// PUT /admin/model-configs/:id — api_key is optional on update; an empty
|
||||
// value keeps the existing key, a non-empty value replaces it.
|
||||
func (d Deps) handleUpdateModel(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var m store.ModelConfig
|
||||
if err := d.DB.First(&m, "id = ?", id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "未找到"})
|
||||
return
|
||||
}
|
||||
var req modelConfigReq
|
||||
if !bind(c, &req) {
|
||||
return
|
||||
}
|
||||
req.BaseURL = strings.TrimRight(strings.TrimSpace(req.BaseURL), "/")
|
||||
m.Name = req.Name
|
||||
m.BaseURL = req.BaseURL
|
||||
m.DefaultModel = req.DefaultModel
|
||||
m.MaxTokens = req.MaxTokens
|
||||
if req.SupportsTools != nil {
|
||||
m.SupportsTools = *req.SupportsTools
|
||||
}
|
||||
if strings.TrimSpace(req.APIKey) != "" {
|
||||
enc, err := d.Crypto.Encrypt(req.APIKey)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "加密失败"})
|
||||
return
|
||||
}
|
||||
m.APIKeyEncrypted = enc
|
||||
m.APIKeyPreview = security.GenerateAPIKeyPreview(req.APIKey)
|
||||
}
|
||||
if err := d.DB.Save(&m).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存失败"})
|
||||
return
|
||||
}
|
||||
d.audit(c, nil, nil, "model_config.update", map[string]any{"id": m.ID})
|
||||
c.JSON(http.StatusOK, m)
|
||||
}
|
||||
|
||||
// DELETE /admin/model-configs/:id
|
||||
func (d Deps) handleDeleteModel(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
res := d.DB.Delete(&store.ModelConfig{}, "id = ?", id)
|
||||
if res.Error != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "删除失败"})
|
||||
return
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "未找到"})
|
||||
return
|
||||
}
|
||||
d.audit(c, nil, nil, "model_config.delete", map[string]any{"id": id})
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
Reference in New Issue
Block a user