Allow research source recovery to complete #390
@@ -214,11 +214,17 @@ func TestDecomposeUsesRememberedAliasesAcrossWordings(t *testing.T) {
|
||||
func TestTaskLexiconFromHistoryFeedsSearchQueryWithoutCoreAlias(t *testing.T) {
|
||||
history := []interaction.HumanUtterance{{Content: "запомни: WB — это Wildberries, источник для поиска"}}
|
||||
lexicon := TaskLexiconFromHistory(history)
|
||||
if got := SearchQueryWithLexicon("найди на WB бренд marka-wear", lexicon); got != "найди на WB бренд marka-wear wildberries" {
|
||||
if got := SearchQueryWithLexicon("найди на WB бренд marka-wear", lexicon); got != "на WB бренд marka-wear wildberries" {
|
||||
t.Fatalf("learned source was not applied to search: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchQueryWithoutLearnedSourceOmitsImperative(t *testing.T) {
|
||||
if got := SearchQueryWithLexicon("найди на WB бренд marka-wear", TaskLexicon{}); got != "на WB бренд marka-wear" {
|
||||
t.Fatalf("search imperative leaked into external query: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecomposeCreativeRequestDoesNotInventResearch(t *testing.T) {
|
||||
lexicon := TaskLexicon{ObjectAliases: []TaskLexiconEntry{{Alias: "медвед", Value: "IMAGE"}}}
|
||||
got := DecomposeTaskWithLexicon("нарисуй бурого медведя", lexicon)
|
||||
|
||||
@@ -72,19 +72,38 @@ func TaskLexiconFromHistory(history []interaction.HumanUtterance) TaskLexicon {
|
||||
return lexicon
|
||||
}
|
||||
|
||||
// SearchQueryWithLexicon keeps a learned source in the external query without
|
||||
// turning its alias into core vocabulary.
|
||||
// SearchQueryWithLexicon prepares a search-engine query without turning a
|
||||
// learned source alias into core vocabulary. The imperative that expresses the
|
||||
// user's intent is deliberately omitted: search engines must receive the
|
||||
// subject of the request, not mistake a Russian command such as "найди" for a
|
||||
// brand or site name.
|
||||
func SearchQueryWithLexicon(message string, lexicon TaskLexicon) string {
|
||||
decomposition := DecomposeTaskWithLexicon(message, lexicon)
|
||||
if decomposition.Intent == TaskIntentSearch && decomposition.Source != "" {
|
||||
if decomposition.Target != "" {
|
||||
return decomposition.Target + " " + decomposition.Source
|
||||
}
|
||||
return strings.TrimSpace(message) + " " + decomposition.Source
|
||||
return searchQueryWithoutImperative(message) + " " + decomposition.Source
|
||||
}
|
||||
if decomposition.Intent == TaskIntentSearch {
|
||||
return searchQueryWithoutImperative(message)
|
||||
}
|
||||
return strings.TrimSpace(message)
|
||||
}
|
||||
|
||||
func searchQueryWithoutImperative(message string) string {
|
||||
cleaned := strings.TrimSpace(message)
|
||||
fields := strings.Fields(cleaned)
|
||||
if len(fields) < 2 {
|
||||
return cleaned
|
||||
}
|
||||
first := strings.Trim(strings.ToLower(fields[0]), ".,!?:;")
|
||||
if !containsStem(first, "найд", "поищ", "подбер", "проверь") {
|
||||
return cleaned
|
||||
}
|
||||
return strings.TrimSpace(strings.TrimPrefix(cleaned, fields[0]))
|
||||
}
|
||||
|
||||
// DecomposeTaskWithLexicon performs a cheap semantic pass. The lexicon is
|
||||
// intentionally an input: a remembered alias may be revalidated or replaced
|
||||
// without changing the parser or shipping a new hard-coded branch.
|
||||
|
||||
Reference in New Issue
Block a user