108 lines
3.0 KiB
Go
108 lines
3.0 KiB
Go
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
|
|
}
|