AI分析功能:LLM Key 改为数据库管理,支持管理员后台配置
This commit is contained in:
86
web/backend/internal/handlers/llm_config.go
Normal file
86
web/backend/internal/handlers/llm_config.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"trade/web/internal/store"
|
||||
)
|
||||
|
||||
type llmConfigReq struct {
|
||||
BaseURL string `json:"base_url"`
|
||||
APIKey string `json:"api_key"`
|
||||
Model string `json:"model"`
|
||||
}
|
||||
|
||||
type llmConfigResp struct {
|
||||
BaseURL string `json:"base_url"`
|
||||
APIKey string `json:"api_key"` // 脱敏:仅显示首尾
|
||||
Model string `json:"model"`
|
||||
HasAPIKey bool `json:"has_api_key"` // 前端据此判断是否已配置
|
||||
}
|
||||
|
||||
// maskKey 将 sk-abc123xyz 脱敏为 sk-a...xyz。
|
||||
func maskKey(key string) string {
|
||||
if len(key) <= 8 {
|
||||
return strings.Repeat("*", len(key))
|
||||
}
|
||||
return key[:4] + "..." + key[len(key)-4:]
|
||||
}
|
||||
|
||||
// GetLLMConfig 返回当前 LLM 配置(API Key 脱敏)。
|
||||
func (d *Deps) GetLLMConfig(w http.ResponseWriter, r *http.Request) {
|
||||
cfg, err := d.Futures.GetLLMConfig()
|
||||
if err != nil {
|
||||
writeErr(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
resp := llmConfigResp{
|
||||
BaseURL: cfg.BaseURL,
|
||||
Model: cfg.Model,
|
||||
HasAPIKey: cfg.APIKey != "",
|
||||
}
|
||||
if cfg.APIKey != "" {
|
||||
resp.APIKey = maskKey(cfg.APIKey)
|
||||
}
|
||||
writeJSON(w, http.StatusOK, resp)
|
||||
}
|
||||
|
||||
// SaveLLMConfig 保存 LLM 配置。api_key 为脱敏占位时保留原值。
|
||||
func (d *Deps) SaveLLMConfig(w http.ResponseWriter, r *http.Request) {
|
||||
var req llmConfigReq
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeErr(w, http.StatusBadRequest, "invalid json")
|
||||
return
|
||||
}
|
||||
req.BaseURL = strings.TrimSpace(req.BaseURL)
|
||||
req.Model = strings.TrimSpace(req.Model)
|
||||
if req.BaseURL == "" {
|
||||
req.BaseURL = "https://api.deepseek.com/v1"
|
||||
}
|
||||
if req.Model == "" {
|
||||
req.Model = "deepseek-chat"
|
||||
}
|
||||
|
||||
// 如果前端传的是脱敏值(含 ...),说明未修改 Key,保留旧值
|
||||
if strings.Contains(req.APIKey, "...") {
|
||||
old, err := d.Futures.GetLLMConfig()
|
||||
if err != nil {
|
||||
writeErr(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
req.APIKey = old.APIKey
|
||||
}
|
||||
|
||||
cfg := &store.LLMConfig{
|
||||
BaseURL: req.BaseURL,
|
||||
APIKey: req.APIKey,
|
||||
Model: req.Model,
|
||||
}
|
||||
if err := d.Futures.SaveLLMConfig(cfg); err != nil {
|
||||
writeErr(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
||||
}
|
||||
Reference in New Issue
Block a user