update: 2026-03-28 20:59

This commit is contained in:
2026-03-28 20:59:52 +08:00
parent e21d58e603
commit 1c81d4e6ea
611 changed files with 27847 additions and 65061 deletions

View File

@@ -0,0 +1,109 @@
package handler
import (
"errors"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"infogenie-backend/config"
"infogenie-backend/internal/database"
"infogenie-backend/internal/model"
)
type AIRuntimeHandler struct{}
func NewAIRuntimeHandler() *AIRuntimeHandler { return &AIRuntimeHandler{} }
func maskAPIKey(k string) (set bool, hint string) {
k = strings.TrimSpace(k)
if k == "" {
return false, ""
}
if len(k) <= 4 {
return true, "****"
}
return true, "****" + k[len(k)-4:]
}
// GetAIRuntime 管理员读取当前 AI 上游配置(密钥脱敏)
func (h *AIRuntimeHandler) GetAIRuntime(c *gin.Context) {
if config.Cfg == nil || strings.TrimSpace(config.Cfg.SiteAdminToken) == "" {
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "admin_not_configured"})
return
}
if !siteAdminTokenOK(c.GetHeader("X-Site-Admin-Token")) {
c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
return
}
var row model.SiteAIRuntime
_ = database.DB.First(&row, 1).Error
keySet, keyHint := maskAPIKey(row.APIKey)
c.JSON(http.StatusOK, gin.H{
"api_base": strings.TrimSpace(row.APIBase),
"api_key_set": keySet,
"api_key_hint": keyHint,
"default_model": strings.TrimSpace(row.DefaultModel),
"default_provider": strings.TrimSpace(row.DefaultProv),
})
}
type putAIRuntimeBody struct {
APIBase string `json:"api_base"`
APIKey string `json:"api_key"`
DefaultModel string `json:"default_model"`
DefaultProvider string `json:"default_provider"`
}
// PutAIRuntime 管理员写入api_key 留空或不传则保留原密钥
func (h *AIRuntimeHandler) PutAIRuntime(c *gin.Context) {
if config.Cfg == nil || strings.TrimSpace(config.Cfg.SiteAdminToken) == "" {
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "admin_not_configured"})
return
}
if !siteAdminTokenOK(c.GetHeader("X-Site-Admin-Token")) {
c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
return
}
var body putAIRuntimeBody
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid_json"})
return
}
var row model.SiteAIRuntime
err := database.DB.First(&row, 1).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
row = model.SiteAIRuntime{ID: 1}
} else {
c.JSON(http.StatusInternalServerError, gin.H{"error": "db_error"})
return
}
}
row.APIBase = strings.TrimSpace(body.APIBase)
if strings.TrimSpace(body.DefaultModel) != "" {
row.DefaultModel = strings.TrimSpace(body.DefaultModel)
}
if strings.TrimSpace(body.DefaultProvider) != "" {
row.DefaultProv = strings.TrimSpace(body.DefaultProvider)
} else if row.DefaultProv == "" {
row.DefaultProv = "deepseek"
}
newKey := strings.TrimSpace(body.APIKey)
if newKey != "" && !strings.Contains(newKey, "****") {
row.APIKey = newKey
}
if err := database.DB.Save(&row).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "db_error"})
return
}
c.JSON(http.StatusOK, gin.H{"ok": true})
}