package companion import ( "fmt" "log/slog" "sync" "git.db123.ir/db123/divacode/internal/storage" "git.db123.ir/db123/divacode/pkg/personality" ) type PersonalityEngine struct { mu sync.Mutex db *storage.DB def map[personality.Trait]personality.TraitValue } func NewPersonalityEngine(db *storage.DB) *PersonalityEngine { e := &PersonalityEngine{ db: db, def: map[personality.Trait]personality.TraitValue{ personality.TraitHumor: {Trait: personality.TraitHumor, Value: 0.5, MinValue: 0.3, MaxValue: 0.7}, personality.TraitCuriosity: {Trait: personality.TraitCuriosity, Value: 0.8, MinValue: 0.7, MaxValue: 0.9}, personality.TraitPlayfulness: {Trait: personality.TraitPlayfulness, Value: 0.5, MinValue: 0.3, MaxValue: 0.7}, personality.TraitFormality: {Trait: personality.TraitFormality, Value: 0.3, MinValue: 0.2, MaxValue: 0.5}, personality.TraitAffection: {Trait: personality.TraitAffection, Value: 0.5, MinValue: 0.3, MaxValue: 0.7}, }, } e.seed() return e } func (e *PersonalityEngine) seed() { for _, tv := range e.def { err := e.db.Exec( "INSERT OR IGNORE INTO personality_traits (id, trait, value, min_value, max_value) VALUES (?, ?, ?, ?, ?)", fmt.Sprintf("trait_%s", tv.Trait), string(tv.Trait), tv.Value, tv.MinValue, tv.MaxValue, ) if err != nil { slog.Warn("seed trait failed", "trait", tv.Trait, "error", err) } } } func (e *PersonalityEngine) Current() []personality.TraitValue { e.mu.Lock() defer e.mu.Unlock() rows, err := e.db.Query("SELECT trait, value, min_value, max_value, updated_at FROM personality_traits") if err != nil { slog.Warn("read traits failed", "error", err) return e.defaults() } defer rows.Close() var traits []personality.TraitValue for rows.Next() { var tv personality.TraitValue var t, updated string if err := rows.Scan(&t, &tv.Value, &tv.MinValue, &tv.MaxValue, &updated); err != nil { continue } tv.Trait = personality.Trait(t) traits = append(traits, tv) } if len(traits) == 0 { return e.defaults() } return traits } func (e *PersonalityEngine) Update(trait personality.Trait, delta float64) error { e.mu.Lock() defer e.mu.Unlock() current := e.get(trait) newVal := current.Value + delta if newVal < current.MinValue { newVal = current.MinValue } if newVal > current.MaxValue { newVal = current.MaxValue } return e.db.Exec( "UPDATE personality_traits SET value = ?, updated_at = datetime('now') WHERE trait = ?", newVal, string(trait), ) } func (e *PersonalityEngine) get(trait personality.Trait) personality.TraitValue { row := e.db.QueryRow("SELECT trait, value, min_value, max_value FROM personality_traits WHERE trait = ?", string(trait)) var tv personality.TraitValue var t string if err := row.Scan(&t, &tv.Value, &tv.MinValue, &tv.MaxValue); err != nil { return e.def[trait] } tv.Trait = personality.Trait(t) return tv } func (e *PersonalityEngine) defaults() []personality.TraitValue { var out []personality.TraitValue for _, tv := range e.def { out = append(out, tv) } return out }