package router import "strings" // transientStems — the states a thing is in for an afternoon. Compared as // prefixes because Russian inflects the ending: "медленн" covers "медленная", // "медленный" and "медленно" without listing them. var transientStems = []string{ "медленн", "тормоз", "лаг", "завис", "виснет", "глюч", "барахл", "отвал", "падает", "упал", "сдох", "греется", "перегре", "slow", "laggy", "stuck", "frozen", "flaky", "broken", "down", } // brokenVerbs — what "не ..." is denying when the sentence is a complaint. // "не работает", "не грузит", "не открывается". Prefixes again. var brokenVerbs = []string{ "работ", "пашет", "груз", "открыва", "включа", "коннект", "подключ", "work", "load", "connect", "respond", } // selfMarkers — the words that make a sentence about him rather than about a // thing. Their presence turns the test off, because losing a fact he meant to // store is worse than keeping a complaint: "я сломал руку" is durable, and // "интернет не работает" is not. var selfMarkers = []string{"я", "мне", "меня", "мной", "i", "me", "my"} // IsTransientComplaint reports whether text observes a passing state of some // thing rather than recording a fact. // // It exists because "сеть какая-то медленная" and "интернет не работает" were // written to the fact store as `self` rows at confidence 1.00 (Vikunja #481), // where recall reads them back later as if they were still true. A complaint // describes a moment; the fact store describes him. // // Deterministic, offline, and shaped exactly like IsQuestionShaped: an // explicit capture verb wins over everything, because "запомни что интернет // не работает" is an instruction and not a passing remark. A first-person // marker also turns it off — the test is meant to catch a sentence about a // thing, and it errs toward storing. func IsTransientComplaint(text string) bool { t := strings.TrimSpace(text) if t == "" { return false } toks := planTokens(strings.ToLower(t)) for _, v := range captureVerbs { if hasTok(toks, v) { return false } } for _, m := range selfMarkers { if hasTok(toks, m) { return false } } for _, tok := range toks { for _, stem := range transientStems { if strings.HasPrefix(tok, stem) { return true } } } // "не" plus a verb of working, in either order of the two tokens that // follow it — "не работает" and "не очень работает" both deny the same // thing. for i, tok := range toks { if tok != "не" && tok != "not" && tok != "isn" { continue } for j := i + 1; j < len(toks) && j <= i+2; j++ { for _, v := range brokenVerbs { if strings.HasPrefix(toks[j], v) { return true } } } } return false }