4c40a183cf
- Add events table (migration #4): stores normalized (action, object, ts) triples extracted from facts, indexed for recurrence detection. - Add proposed_routines table: stores inferred recurring patterns with proposed/accepted/dismissed status and optional linked reminder. - Add pattern package: Extractor normalizes fact text into (action, object) pairs with TTS normalization; Detector groups events to find recurring patterns and proposes routines. - Add internal/ttsnorm: text normalization pipeline for Russian/English (lowercase, punctuation strip, number normalization, stopword removal). - Add chat seed file for LLM phraser.
57 lines
1.7 KiB
Go
57 lines
1.7 KiB
Go
package pattern
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestExtractSimpleAction(t *testing.T) {
|
|
now := time.Now().UTC()
|
|
|
|
tests := []struct {
|
|
name string
|
|
key string
|
|
value string
|
|
wantAction string
|
|
wantObject string
|
|
wantNil bool
|
|
}{
|
|
{"refill english", "water_fountain", "refilled", "refill", "water_fountain", false},
|
|
{"refill russian", "cat_water", "налил", "refill", "cat_water", false},
|
|
{"fed cat", "cat_food", "fed", "feed", "cat_food", false},
|
|
{"clean litter", "litter_box", "почистил", "clean", "litter_box", false},
|
|
{"walked dog", "dog_walk", "walked", "walk", "dog_walk", false},
|
|
{"took medicine", "medicine", "took", "take", "medicine", false},
|
|
{"watered plants", "plants", "watered", "water", "plants", false},
|
|
{"json value skipped", "weight", `{"kg": 82}`, "", "", true},
|
|
{"empty value skipped", "something", "", "", "", true},
|
|
{"unrecognized action", "door", "opened", "", "", true},
|
|
{"case insensitive", "WATER_FOUNTAIN", "REFILLED", "refill", "water_fountain", false},
|
|
{"whitespace trimmed", " cat_bed ", " cleaned ", "clean", "cat_bed", false},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ev := Extract(42, tc.key, tc.value, now)
|
|
if tc.wantNil {
|
|
if ev != nil {
|
|
t.Fatalf("want nil, got %+v", ev)
|
|
}
|
|
return
|
|
}
|
|
if ev == nil {
|
|
t.Fatal("want event, got nil")
|
|
}
|
|
if ev.Action != tc.wantAction {
|
|
t.Fatalf("action: want %q, got %q", tc.wantAction, ev.Action)
|
|
}
|
|
if ev.Object != tc.wantObject {
|
|
t.Fatalf("object: want %q, got %q", tc.wantObject, ev.Object)
|
|
}
|
|
if ev.FactID != 42 {
|
|
t.Fatalf("fact_id: want 42, got %d", ev.FactID)
|
|
}
|
|
})
|
|
}
|
|
}
|