package router import "time" // Habit queries — "что я обычно делаю по вторникам?" (Vikunja #254). // // Deterministic matching, like the calendar and plan matchers: the LLM router // classifies the intent, but WHICH weekday was asked about is a lookup, not a // generation. A model that answers "по вторникам" for a question about Thursday // gives a confidently wrong account of the owner's own life. // HabitQuery — a parsed "what do I usually do" question. Weekday is set only // when the utterance names one; otherwise the answer covers the whole week. // Weekend is set for "по выходным", which names two days rather than one. type HabitQuery struct { Weekday time.Weekday HasWeekday bool Weekend bool } // habitMarkers — the words that make a question about habit rather than about // today. Without one of these, "что я делаю" is a question about right now, and // the recall path owns it. var habitMarkers = []string{ "обычно", "обычное", "чаще", "постоянно", "привычки", "привычка", "привычках", "регулярно", "каждый", "каждую", "каждое", "usually", "habits", "habit", "typically", "normally", } // weekdayWords — every form of a weekday name maven needs to recognise, // including the "по …ам" plural the question is usually phrased in. var weekdayWords = map[string]time.Weekday{ "понедельник": time.Monday, "понедельникам": time.Monday, "вторник": time.Tuesday, "вторникам": time.Tuesday, "среда": time.Wednesday, "среду": time.Wednesday, "средам": time.Wednesday, "четверг": time.Thursday, "четвергам": time.Thursday, "пятница": time.Friday, "пятницу": time.Friday, "пятницам": time.Friday, "суббота": time.Saturday, "субботу": time.Saturday, "субботам": time.Saturday, "воскресенье": time.Sunday, "воскресеньям": time.Sunday, "воскресенья": time.Sunday, "воскресенью": time.Sunday, "воскресеньем": time.Sunday, "воскресеньях": time.Sunday, "monday": time.Monday, "mondays": time.Monday, "tuesday": time.Tuesday, "tuesdays": time.Tuesday, "wednesday": time.Wednesday, "wednesdays": time.Wednesday, "thursday": time.Thursday, "thursdays": time.Thursday, "friday": time.Friday, "fridays": time.Friday, "saturday": time.Saturday, "saturdays": time.Saturday, "sunday": time.Sunday, "sundays": time.Sunday, } // weekendWords — the weekend as one unit. "что я обычно делаю по выходным?" // has a habit marker and names days, but no weekday name is in it, so it used // to fall through to the whole-week profile and answer about Tuesdays too. var weekendWords = map[string]bool{ "выходным": true, "выходные": true, "выходных": true, "выходной": true, "weekend": true, "weekends": true, } // ParseHabitQuery reports whether an utterance asks what the owner usually // does, and on which weekday if it names one. // // A habit marker is required. "что я делаю в среду?" without one is a question // about this coming Wednesday — the calendar's job — and answering it with a // statistical average would be answering a different question. func ParseHabitQuery(text string) (HabitQuery, bool) { toks := planTokens(text) marked := false for _, t := range toks { for _, m := range habitMarkers { if t == m { marked = true break } } } if !marked { return HabitQuery{}, false } for _, t := range toks { if wd, ok := weekdayWords[t]; ok { return HabitQuery{Weekday: wd, HasWeekday: true}, true } if weekendWords[t] { return HabitQuery{Weekend: true}, true } } return HabitQuery{}, true }