package handler import ( "net/http" "strings" "github.com/gin-gonic/gin" "github.com/sundynix/sundynix-gateway/internal/store" "github.com/sundynix/sundynix-shared/secrets" ) // 每用户 JARVIS 设置的用户级存取(非 admin):名字 / 人设 / 自带豆包配置。 // 桌面端「JARVIS 设置」面板用它读写。api_key 密文入库、脱敏回显。 // GetMyJarvis: GET /api/v1/me/jarvis —— 当前用户的 JARVIS 设置。 func (h *Handler) GetMyJarvis(c *gin.Context) { j := h.db.GetUserJarvis(c.Request.Context(), userID(c)) if j == nil { c.JSON(http.StatusOK, gin.H{"name": "", "persona": "", "asr_resource_id": "", "tts_resource_id": "", "tts_voice_type": "", "api_key": "", "has_own_voice": false}) return } apiKey := "" if j.APIKey != "" { if plain, err := secrets.Decrypt(j.APIKey); err == nil { apiKey = mask(plain) } } c.JSON(http.StatusOK, gin.H{ "name": j.Name, "persona": j.Persona, "asr_resource_id": j.ASRResourceID, "tts_resource_id": j.TTSResourceID, "tts_voice_type": j.TTSVoiceType, "api_key": apiKey, // 是否自带一套完整豆包配置(齐全才会覆盖系统;否则只是名字/人设生效、语音仍走系统)。 "has_own_voice": j.APIKey != "" && j.ASRResourceID != "" && j.TTSResourceID != "" && j.TTSVoiceType != "", }) } // SaveMyJarvis: PUT /api/v1/me/jarvis —— 保存当前用户的 JARVIS 设置。api_key 留空/掩码=沿用已存。 func (h *Handler) SaveMyJarvis(c *gin.Context) { var b struct { Name string `json:"name"` Persona string `json:"persona"` APIKey string `json:"api_key"` ASRResourceID string `json:"asr_resource_id"` TTSResourceID string `json:"tts_resource_id"` TTSVoiceType string `json:"tts_voice_type"` } if err := c.ShouldBindJSON(&b); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"}) return } ctx := c.Request.Context() uid := userID(c) // api_key:空或掩码占位 → 沿用已存密文;否则加密新值。 key := strings.TrimSpace(b.APIKey) enc := "" if key == "" || strings.Contains(key, "•") { if cur := h.db.GetUserJarvis(ctx, uid); cur != nil { enc = cur.APIKey } } else { e, err := secrets.Encrypt(key) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "密钥加密失败:" + err.Error()}) return } enc = e } j := &store.UserJarvis{ UserID: uid, Name: strings.TrimSpace(b.Name), Persona: strings.TrimSpace(b.Persona), APIKey: enc, ASRResourceID: strings.TrimSpace(b.ASRResourceID), TTSResourceID: strings.TrimSpace(b.TTSResourceID), TTSVoiceType: strings.TrimSpace(b.TTSVoiceType), } if err := h.db.SaveUserJarvis(ctx, j); err != nil { c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"status": "ok"}) }