Merge the list read-back seeds (#179)
This commit is contained in:
@@ -95,6 +95,12 @@ func (h *reactiveHandler) removeListItem(ctx context.Context, cap router.ListCap
|
||||
return "", false
|
||||
}
|
||||
|
||||
// listFloor — the keyword test behind topicList, in the shape turnIsAbout takes.
|
||||
func listFloor(u string) bool {
|
||||
_, ok := router.ParseListQuery(u)
|
||||
return ok
|
||||
}
|
||||
|
||||
// queryList — "что в списке покупок?", "что мне купить?".
|
||||
//
|
||||
// A query source, so it sits in querySources and either claims the turn or
|
||||
@@ -102,10 +108,15 @@ func (h *reactiveHandler) removeListItem(ctx context.Context, cap router.ListCap
|
||||
// source is: the notes pass would otherwise answer a list question with
|
||||
// whatever note is nearest.
|
||||
func (h *reactiveHandler) queryList(ctx context.Context, t *queryTurn) (string, bool) {
|
||||
list, ok := router.ParseListQuery(t.dec.Utterance)
|
||||
if !ok || h.dataStore == nil {
|
||||
if h.dataStore == nil {
|
||||
return "", false
|
||||
}
|
||||
// The seeds decide the subject and listQueryPrefixes is the floor behind
|
||||
// them (V-522). Which list he named is a noun lookup either way.
|
||||
if !h.turnIsAbout(ctx, t, topicList, listFloor) {
|
||||
return "", false
|
||||
}
|
||||
list := router.ListNamedIn(t.dec.Utterance)
|
||||
items, err := h.dataStore.ListItems(ctx, list, "")
|
||||
if err != nil {
|
||||
log.Printf("voice: list items: %v", err)
|
||||
|
||||
@@ -58,6 +58,7 @@ const (
|
||||
topicNetwork topicLabel = "network"
|
||||
topicAttend topicLabel = "attention"
|
||||
topicFeed topicLabel = "feeds"
|
||||
topicList topicLabel = "list"
|
||||
topicOther topicLabel = "other"
|
||||
)
|
||||
|
||||
@@ -140,7 +141,25 @@ var topicSeedSets = map[topicLabel][]string{
|
||||
"what is new in the feeds",
|
||||
"any news headlines today",
|
||||
},
|
||||
// Reading a standing list back, and only that. Adding to one and clearing
|
||||
// one stay on the phrase tables in internal/router/list.go — see its header
|
||||
// for why a span and a delete are not seed-shaped work.
|
||||
topicList: {
|
||||
"что в списке покупок",
|
||||
"что мне нужно купить",
|
||||
"прочитай список покупок",
|
||||
"покажи что в списке",
|
||||
"что осталось купить в магазине",
|
||||
"что мне нужно в аптеке",
|
||||
"какой у меня список покупок",
|
||||
"what is on my shopping list",
|
||||
"read me the grocery list",
|
||||
},
|
||||
topicOther: {
|
||||
// A task question is not a list read-back. They collide on "что у меня",
|
||||
// and the list has its own table to lose to as well.
|
||||
"какие у меня задачи",
|
||||
"что у меня в делах",
|
||||
// The bare newness opener, which is a greeting and not a request for
|
||||
// headlines. It sits here on purpose: it is close enough to the feed
|
||||
// seeds that it will not clear topicMargin, and a thin call goes to
|
||||
|
||||
@@ -26,6 +26,7 @@ func TestTopicFloorAnswersWithoutSeeds(t *testing.T) {
|
||||
{"какие устройства в сети?", topicNetwork, isNetworkQuery, true},
|
||||
{"что требует внимания?", topicAttend, isAttentionQuery, true},
|
||||
{"что нового в лентах?", topicFeed, feedFloor, true},
|
||||
{"что в списке покупок?", topicList, listFloor, true},
|
||||
{"почему небо синее", topicWeather, isWeatherQuery, false},
|
||||
{"я дома", topicHome, isHomeQuery, false},
|
||||
{"интернет не работает", topicNetwork, isNetworkQuery, false},
|
||||
@@ -93,6 +94,12 @@ func TestONNXTopics(t *testing.T) {
|
||||
// The greeting. It has to lose to topicOther, or fall thin enough that
|
||||
// ParseFeedQuery — which declines a vague noun with no topic — answers.
|
||||
{"что нового?", topicOther, feedFloor},
|
||||
{"что мне надо купить в магазине", topicList, listFloor},
|
||||
{"прочитай мне список", topicList, listFloor},
|
||||
{"что там в аптеке нужно взять", topicList, listFloor},
|
||||
// A task read-back is not a list read-back, and the two collide on
|
||||
// "что у меня".
|
||||
{"какие у меня сейчас задачи", topicOther, listFloor},
|
||||
}
|
||||
|
||||
h := &reactiveHandler{recall: recallWiring{embedder: emb}}
|
||||
|
||||
@@ -17,6 +17,15 @@ import (
|
||||
// The markers are deliberately explicit. "молоко закончилось" is an
|
||||
// observation about the world and belongs in a note; only an instruction to
|
||||
// put something on a list puts it there.
|
||||
//
|
||||
// The four paths split on 05-08-2026, and the split is by what the caller needs
|
||||
// rather than by language (V-522). Reading a list back needs one bit — is this
|
||||
// about the list — so the seeds decide it, topicList through turnIsAbout, and
|
||||
// listQueryPrefixes below is the offline floor. The other three keep the tables
|
||||
// as the answer. Add and remove need to know WHERE the item starts, and a
|
||||
// cosine over a whole utterance does not say which byte the milk begins at.
|
||||
// Clear DELETES the list, so it stays on exact phrases: a false claim there
|
||||
// loses rows he cannot get back, which is not the trade a margin makes.
|
||||
|
||||
// listTags — the lists he can name, as one dictionary form each. Russian
|
||||
// declines the tag ("список покупок", "в покупки", "в покупках"), and the
|
||||
@@ -186,6 +195,31 @@ func ParseListQuery(text string) (string, bool) {
|
||||
return list, true
|
||||
}
|
||||
|
||||
// ListNamedIn reports which standing list an utterance names, anywhere in it,
|
||||
// defaulting to покупки when it names none.
|
||||
//
|
||||
// takeListTag is not enough for a read-back, because it reads the FRONT of a
|
||||
// remainder a prefix table has already eaten. The seeds claim a read-back
|
||||
// without eating anything (topicList, cmd/mavend/topics.go, V-522), so "что мне
|
||||
// нужно в аптеке" has to be scanned rather than trimmed. A list name is a noun
|
||||
// in the dictionary, so this is a lookup and decides nothing about meaning.
|
||||
func ListNamedIn(text string) string {
|
||||
for _, f := range strings.Fields(strings.ToLower(text)) {
|
||||
head := strings.Trim(f, listTrimCut)
|
||||
for _, s := range listTags {
|
||||
if morph.SameWord(head, s.word) {
|
||||
return s.list
|
||||
}
|
||||
}
|
||||
for _, s := range listTagsEN {
|
||||
if head == s.word {
|
||||
return s.list
|
||||
}
|
||||
}
|
||||
}
|
||||
return "покупки"
|
||||
}
|
||||
|
||||
// ParseListClear reports whether an utterance crosses off a whole list.
|
||||
func ParseListClear(text string) (string, bool) {
|
||||
lower := strings.ToLower(strings.Trim(strings.TrimSpace(text), listTrimCut))
|
||||
|
||||
Reference in New Issue
Block a user