Route local place searches to relevant evidence
CI / test (pull_request) Successful in 1m19s
CI / test (push) Successful in 47s

This commit is contained in:
m
2026-08-26 10:40:15 +03:00
parent f329224d12
commit 4e54ace76b
4 changed files with 58 additions and 1 deletions
+19
View File
@@ -1863,6 +1863,9 @@ func researchFindingMatchesIntent(query string, finding epistemics.ResearchFindi
if distanceResearchQuery(query) && !containsDistanceEvidence(finding.Excerpt.Text) {
return false
}
if localPlaceSearchQuery(query) && !containsLocalPlaceEvidence(finding.Excerpt.Text) {
return false
}
if !nearestFlightQuery(query) {
return true
}
@@ -1892,6 +1895,22 @@ func researchFindingMatchesIntent(query string, finding epistemics.ResearchFindi
return true
}
func localPlaceSearchQuery(query string) bool {
lower := strings.ToLower(query)
return (strings.Contains(lower, "ресторан") || strings.Contains(lower, "кафе")) &&
(strings.Contains(lower, "адрес") || strings.Contains(lower, "отзыв") || strings.Contains(lower, "меню"))
}
func containsLocalPlaceEvidence(value string) bool {
lower := strings.ToLower(value)
for _, term := range []string{"ресторан", "кафе", "адрес", "меню", "отзыв", "кухн"} {
if strings.Contains(lower, term) {
return true
}
}
return false
}
func distanceResearchQuery(query string) bool {
lower := strings.ToLower(query)
return strings.Contains(lower, "расстоян") || strings.Contains(lower, "километр")
+12
View File
@@ -106,6 +106,18 @@ func TestResearchReplyRejectsGenericLandingPageForConcreteIdentifier(t *testing.
}
}
func TestLocalPlaceReplyRejectsDictionaryFinding(t *testing.T) {
result := epistemics.ResearchResult{Findings: []epistemics.ResearchFinding{{
State: epistemics.FindingSupported,
Source: epistemics.Source{Locator: "https://dictionary.example", Title: "Ближайший — словарь"},
Excerpt: epistemics.SourceExcerpt{Text: "Ближайший — значение слова и пример употребления."},
}}}
reply, backed := renderResearchReply("места ресторан в Сочи адрес отзывы меню", result, nil)
if backed || !strings.Contains(reply, "Проверяемых данных") {
t.Fatalf("dictionary finding was presented as local place result: %q", reply)
}
}
func TestResearchReplyKeepsFindingContainingConcreteIdentifier(t *testing.T) {
result := epistemics.ResearchResult{Findings: []epistemics.ResearchFinding{{
State: epistemics.FindingSupported,
@@ -189,6 +189,13 @@ func TestTravelResearchQueryUsesKnownOriginForDistance(t *testing.T) {
}
}
func TestTravelResearchQueryCompilesLocalPlaceSearchWithoutSearchImperative(t *testing.T) {
query := TravelResearchQuery("найди ближайший ресторан в Сочи", nil, time.Time{})
if strings.Contains(query, "найди") || strings.Contains(query, "ближайший") || !strings.Contains(query, "сочи") || !strings.Contains(query, "адрес") {
t.Fatalf("local place query was not compiled semantically: %q", query)
}
}
func TestTravelRouteWithKnownOriginDoesNotAskForTicketDate(t *testing.T) {
history := []interaction.HumanUtterance{{Content: "я сейчас в Москве"}}
if got := TravelSearchClarification("как можно добраться до Сочи?", history); got != "" {
+20 -1
View File
@@ -46,7 +46,9 @@ func normalizedTravelSearchText(message string) string {
func TravelResearchQuery(message string, history []interaction.HumanUtterance, now time.Time) string {
query := TravelSearchQuery(message, now)
tokens := semanticTokens(StripAssistantVocative(message))
if containsStemInTokens(tokens, "расстоян", "километр") {
if localPlaceSearchRequest(tokens) {
return localPlaceResearchQuery(tokens)
} else if containsStemInTokens(tokens, "расстоян", "километр") {
origin := travelContextOrigin(history)
destination := travelContextDestinationFromTokens(tokens)
if origin != "" && destination != "" {
@@ -86,6 +88,23 @@ func TravelResearchQuery(message string, history []interaction.HumanUtterance, n
return query
}
// localPlaceSearchRequest recognizes a proximity search as a local-search
// capability, keeping it separate from travel-route compilation.
func localPlaceSearchRequest(tokens []string) bool {
return containsStemInTokens(tokens, "ресторан", "кафе") && containsStemInTokens(tokens, "ближ", "рядом")
}
func localPlaceResearchQuery(tokens []string) string {
parts := make([]string, 0, len(tokens))
for _, token := range tokens {
if containsStem(token, "найд", "покаж", "ближ", "рядом") {
continue
}
parts = append(parts, token)
}
return "места " + strings.Join(parts, " ") + " адрес отзывы меню"
}
// trainScheduleResearchQuery formulates an observed schedule request from the
// user's route and remembered origin. It contains no city, provider or answer
// catalogue: actual departure data remains evidence from the selected source.