sdaduanbilei 9e279a0627 fix
2026-03-05 17:34:49 +08:00

128 lines
2.9 KiB
Go

package user
import (
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
"gopkg.in/yaml.v3"
)
type Config struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
Provider string `yaml:"provider"`
Model string `yaml:"model"`
APIKeyEnv string `yaml:"api_key_env"`
AvatarColor string `yaml:"avatar_color"`
Preferences Preferences `yaml:"preferences"`
}
type Preferences struct {
Language string `yaml:"language"`
Tone string `yaml:"tone"`
}
type User struct {
Config Config
Profile string // content from PROFILE.md
Dir string // users/<name>/
}
const DefaultUser = "default"
func Load(dir string) (*User, error) {
userDir := filepath.Join(dir, DefaultUser)
userMD, err := os.ReadFile(filepath.Join(userDir, "USER.md"))
if err != nil {
return nil, fmt.Errorf("read USER.md: %w", err)
}
cfg, err := parseFrontmatter(userMD)
if err != nil {
return nil, fmt.Errorf("parse USER.md: %w", err)
}
profile, _ := os.ReadFile(filepath.Join(userDir, "PROFILE.md"))
if cfg.Provider == "" {
cfg.Provider = "deepseek"
}
if cfg.APIKeyEnv == "" {
cfg.APIKeyEnv = "DEEPSEEK_API_KEY"
}
if cfg.AvatarColor == "" {
cfg.AvatarColor = "#5865F2"
}
return &User{Config: cfg, Profile: string(profile), Dir: userDir}, nil
}
func parseFrontmatter(data []byte) (Config, error) {
var cfg Config
if !bytes.HasPrefix(data, []byte("---")) {
return cfg, fmt.Errorf("missing frontmatter")
}
parts := bytes.SplitN(data, []byte("---"), 3)
if len(parts) < 3 {
return cfg, fmt.Errorf("invalid frontmatter")
}
return cfg, yaml.Unmarshal(parts[1], &cfg)
}
func (u *User) SaveProfile(content string) error {
return os.WriteFile(filepath.Join(u.Dir, "PROFILE.md"), []byte(content), 0644)
}
func (u *User) SaveConfig(cfg Config) error {
u.Config = cfg
var buf bytes.Buffer
buf.WriteString("---\n")
enc := yaml.NewEncoder(&buf)
enc.Encode(cfg)
buf.WriteString("---\n")
return os.WriteFile(filepath.Join(u.Dir, "USER.md"), buf.Bytes(), 0644)
}
func (u *User) BuildUserXML() string {
var xml strings.Builder
xml.WriteString("<user_info>\n")
xml.WriteString(fmt.Sprintf(" <name>%s</name>\n", u.Config.Name))
xml.WriteString(fmt.Sprintf(" <description>%s</description>\n", u.Config.Description))
if u.Profile != "" {
xml.WriteString(" <profile>\n")
xml.WriteString(u.Profile)
xml.WriteString(" </profile>\n")
}
xml.WriteString("</user_info>")
return xml.String()
}
func (u *User) GetProvider() string {
return u.Config.Provider
}
func (u *User) GetModel() string {
return u.Config.Model
}
func (u *User) GetAPIKeyEnv() string {
return u.Config.APIKeyEnv
}
func (u *User) GetName() string {
return u.Config.Name
}
func (u *User) GetAvatarColor() string {
return u.Config.AvatarColor
}
func Exists(dir string) bool {
_, err := os.Stat(filepath.Join(dir, DefaultUser, "USER.md"))
return err == nil
}