feat(companion): add personality, relationship, and mood engines
This commit is contained in:
107
internal/companion/personality.go
Normal file
107
internal/companion/personality.go
Normal file
@@ -0,0 +1,107 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user