Files
sundynix-agentix/sundynix-gateway/internal/store/user_jarvis.go
T
Blizzard 99ce07c1b0 feat(voice): 每用户 JARVIS——自定义名字/人设 + 自带豆包配置回落 + 语音不串主记忆
把 JARVIS 做成每用户独立:名字(你叫JARVIS别人叫星期五)、人设(与主偏好记忆分开)、
可自带豆包配置(齐全则用用户的,否则回落系统)。

- store/user_jarvis.go: sundynix_user_jarvis(user_id唯一;name/persona/火山creds,APIKey密文)
  + Get/Save(upsert) + AutoMigrate 注册
- voice_config.go resolveJarvis(uid): 火山配置用户优先系统兜底 + 取名字/人设
- voice_task.go: voiceSystemPrompt(name,persona)——简短是硬基线,名字/语气由用户定;
  buildVoiceGraph 带 name+persona;voice.go 会话升级时按用户解析
- dispatcher compose_compiler: 语音任务(useVoice)不拉主偏好记忆,改用用户 persona(保留短期历史)
- jarvis.go + 路由: GET/PUT /api/v1/me/jarvis(用户级,api_key 脱敏/留空沿用)

真机验证:设 name=星期五+干净人设→语音答"我是星期五…"(自称新名、无糙话、4.4s),
has_own_voice=false 用系统豆包。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 14:06:32 +08:00

50 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package store
import (
"context"
"gorm.io/gorm/clause"
)
// UserJarvis 是**每用户**的 JARVIS 语音助手配置(客户端配、用户级)。
// 与系统级语音配置(Setting voice_config)、与主偏好记忆(user_profile) 都分开:
// - Name/Persona:这个用户的助手叫什么、什么语气人设(persona 独立于主偏好记忆,互不污染)。
// - APIKey/…ResourceID/VoiceType:用户自带的豆包(火山)配置;齐全则语音走用户的,否则回落系统。
// APIKey 密文入库(AES-256-GCM,同 LLMModel/微信配置)。表名 sundynix_user_jarvis。
type UserJarvis struct {
BaseModel
UserID string `gorm:"size:32;uniqueIndex"` // 雪花 user.id,每用户唯一一条
Name string `gorm:"size:32"` // 助手名(空=用系统默认 "JARVIS"
Persona string `gorm:"size:1024"` // 语气/人设(空=用系统默认)
APIKey string `gorm:"size:255"` // 用户自带火山 API Key(密文;空=用系统)
ASRResourceID string `gorm:"size:64"`
TTSResourceID string `gorm:"size:64"`
TTSVoiceType string `gorm:"size:64"`
}
func (UserJarvis) TableName() string { return "sundynix_user_jarvis" }
// GetUserJarvis 取某用户的 JARVIS 配置;不存在返回 nil(调用方回落系统默认)。
func (p *Postgres) GetUserJarvis(ctx context.Context, uid string) *UserJarvis {
if p.db == nil || uid == "" {
return nil
}
var j UserJarvis
if err := p.db.WithContext(ctx).Where("user_id = ?", uid).First(&j).Error; err != nil {
return nil
}
return &j
}
// SaveUserJarvis 幂等写某用户的 JARVIS 配置(按 user_id 唯一,重复即覆盖)。
// APIKey 传空串表示"沿用已存"(由 handler 决定是否覆盖),此处只负责按传入值落库。
func (p *Postgres) SaveUserJarvis(ctx context.Context, j *UserJarvis) error {
if p.db == nil {
return errStoreDisabled
}
return p.db.WithContext(ctx).Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "user_id"}},
DoUpdates: clause.AssignmentColumns([]string{"name", "persona", "api_key", "asr_resource_id", "tts_resource_id", "tts_voice_type", "updated_at"}),
}).Create(j).Error
}