feat: LLM router with chat intent and Cyrillic wake-word support
- Add LLMRouter: grammar-constrained LFM call for intent classification after stage-0, before classifier cascade. Errors fall through gracefully. - Add IntentChat: conversational intent with no store side-effect, routed through LLM -> phraser chat endpoint. - Extract slots for Chat: no structured slots, full utterance is payload. - Extend stage-0 grammars to fire through Cyrillic wake-word spellings (Мэйвен/Мейвен/Майвен/etc.) produced by Russian STT model. - StripWakeToken helper strips leading wake in any script so time/date grammars still match when wake is present. - Add classifier examples for chat utterances (EN + RU). - Wire LLMRouter into Router.Config; optional, nil-safe.
This commit is contained in:
@@ -23,7 +23,30 @@ type Grammar struct {
|
||||
// is matched against the act allowlist. A non-match returns ok=false so the
|
||||
// cascade falls through to the classifier (a wakeword prefix alone doesn't
|
||||
// guarantee a known command — "maven, i'm tired" is a fact, not an act).
|
||||
var wakeWordAct = regexp.MustCompile(`(?i)^\s*maven[,: ]+(.+)$`)
|
||||
var wakeWordAct = regexp.MustCompile(`(?i)^\s*(?:maven|мэйвен|мейвен|майвен|мавена?|мэвен)[,:.!\s]+(.+)$`)
|
||||
|
||||
// wakeToken matches a leading wake-word token in any script the STT commonly
|
||||
// produces for "Maven" — Latin "maven" or a Cyrillic phonetic rendering. The
|
||||
// STT is a Russian model, so it transcribes the spoken wake word phonetically
|
||||
// almost every time; matching only the Latin spelling meant stage-0 grammars
|
||||
// (time/date/reminder) silently missed nearly every wake-worded utterance and
|
||||
// fell through to the classifier, which misroutes time queries into the
|
||||
// reminder intent (dense time-vocab centroid, see SystemTimeDateGrammars).
|
||||
var wakeToken = regexp.MustCompile(`(?i)^\s*(?:maven|мэйвен|мейвен|майвен|мавена?|мэвен)[,:.!\s]*`)
|
||||
|
||||
// StripWakeToken removes a leading wake-word token (any script/spelling seen
|
||||
// in wakeToken) and reports whether one was found.
|
||||
func StripWakeToken(u string) (string, bool) {
|
||||
loc := wakeToken.FindStringIndex(u)
|
||||
if loc == nil {
|
||||
return u, false
|
||||
}
|
||||
rest := strings.TrimSpace(u[loc[1]:])
|
||||
if rest == "" {
|
||||
return u, false
|
||||
}
|
||||
return rest, true
|
||||
}
|
||||
|
||||
// DefaultGrammars — the wake-word act fast path. The ActMatcher is the same
|
||||
// allowlist stage-2 act extraction uses (single source of truth for the fn
|
||||
@@ -106,12 +129,12 @@ func SystemTimeDateGrammars() []Grammar {
|
||||
},
|
||||
{
|
||||
Name: "clock-query",
|
||||
Pattern: regexp.MustCompile(`(?i)^\s*который\s+(сейчас\s+)?час(\s+у\s+нас|\s+в\s+\w+)?\s*\??\s*$`),
|
||||
Pattern: regexp.MustCompile(`(?i)^\s*который\s+(сейчас\s+)?час(\s+у\s+нас|\s+в\s+\w+)?\s*[?!.]?\s*$`),
|
||||
Build: timeDateBuild,
|
||||
},
|
||||
{
|
||||
Name: "date-query",
|
||||
Pattern: regexp.MustCompile(`(?i)^\s*(?:какой\s+сегодня\s+(?:день|день\s+недели|число)|какое\s+сегодня\s+число)\s*\??\s*$`),
|
||||
Pattern: regexp.MustCompile(`(?i)^\s*(?:какой\s+сегодня\s+(?:день|день\s+недели|число)|какое\s+сегодня\s+число)\s*[?!.]?\s*$`),
|
||||
Build: timeDateBuild,
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user