56051e58c0
Baseline types: LegacyRouter interface (satisfied by *router.Router), LegacyCase with PrerouteConsumed flag for command-prohibition detection, LegacyReport with fast-path/residual/router-residual/pre-route breakdowns, ContrastFamilyReport for per-transform-family scoring. Test helpers: buildSeededClassifier (hash embedder seeded from models/seeds/*.txt), actVerbList, seed file loading. TestContrastFamiliesShareSplitGroup verifies that all contrastive variants of one base seed share exactly one SplitGroup, preventing train/eval leakage across the contrast family split.
88 lines
2.0 KiB
Go
88 lines
2.0 KiB
Go
package semantic
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/kami/maven/internal/router"
|
|
)
|
|
|
|
const seedDir = "../../../models/seeds"
|
|
|
|
var seedIntents = []router.Intent{
|
|
router.IntentAct, router.IntentReminder, router.IntentFact,
|
|
router.IntentNote, router.IntentQuery, router.IntentChat, router.IntentSystem,
|
|
}
|
|
|
|
func actVerbList() []string {
|
|
return []string{
|
|
"перезапусти", "перезагрузи", "выключи", "включи", "останови", "запусти",
|
|
"закрой", "открой", "сделай", "поставь",
|
|
"restart", "reboot", "stop", "start", "turn off", "turn on", "open", "close",
|
|
}
|
|
}
|
|
|
|
func buildSeededClassifier(t *testing.T, emb router.Embedder) *router.Classifier {
|
|
t.Helper()
|
|
cls := router.NewClassifier(emb)
|
|
ctx := context.Background()
|
|
seeds := seedsWithIntent(t)
|
|
texts := make([]string, 0, len(seeds))
|
|
for text := range seeds {
|
|
texts = append(texts, text)
|
|
}
|
|
sort.Strings(texts)
|
|
for _, text := range texts {
|
|
if err := cls.AddExample(ctx, seeds[text], text); err != nil {
|
|
t.Fatalf("seed %q: %v", text, err)
|
|
}
|
|
}
|
|
return cls
|
|
}
|
|
|
|
func seedsWithIntent(t *testing.T) map[string]router.Intent {
|
|
t.Helper()
|
|
files := readSeedFiles(t)
|
|
out := map[string]router.Intent{}
|
|
for _, intent := range seedIntents {
|
|
for _, l := range files[intent] {
|
|
if _, dup := out[l]; dup {
|
|
continue
|
|
}
|
|
out[l] = intent
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func readSeedFiles(t *testing.T) map[router.Intent][]string {
|
|
t.Helper()
|
|
out := map[router.Intent][]string{}
|
|
for _, intent := range seedIntents {
|
|
path := filepath.Join(seedDir, string(intent)+".txt")
|
|
fh, err := os.Open(path)
|
|
if err != nil {
|
|
t.Fatalf("open %s: %v", path, err)
|
|
}
|
|
sc := bufio.NewScanner(fh)
|
|
for sc.Scan() {
|
|
line := strings.TrimSpace(sc.Text())
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
out[intent] = append(out[intent], line)
|
|
}
|
|
err = sc.Err()
|
|
fh.Close()
|
|
if err != nil {
|
|
t.Fatalf("read %s: %v", path, err)
|
|
}
|
|
}
|
|
return out
|
|
}
|