Handle memory identity and travel follow-ups
This commit is contained in:
@@ -133,7 +133,7 @@ func PreferredAssistantName(message string) string {
|
||||
continue
|
||||
}
|
||||
for _, candidate := range tokens[index+1:] {
|
||||
if candidate == "тебя" || candidate == "тебе" || candidate == "себя" || candidate == "меня" {
|
||||
if candidate == "тебя" || candidate == "тебе" || candidate == "себя" || candidate == "меня" || candidate == "в" || candidate == "теперь" || candidate == "же" {
|
||||
continue
|
||||
}
|
||||
if candidate == "буду" || candidate == "будет" || candidate == "запомни" || candidate == "помни" || candidate == "ты" || candidate == "это" {
|
||||
@@ -144,12 +144,19 @@ func PreferredAssistantName(message string) string {
|
||||
}
|
||||
runes := []rune(candidate)
|
||||
runes[0] = []rune(strings.ToUpper(string(runes[0])))[0]
|
||||
return string(runes)
|
||||
return normalizeAssistantName(string(runes))
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func normalizeAssistantName(value string) string {
|
||||
if strings.HasSuffix(value, "ю") {
|
||||
return strings.TrimSuffix(value, "ю") + "я"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// IsIdentityInquiry identifies a request about the assistant itself by its
|
||||
// interrogative meaning. Punctuation is optional and wording may vary.
|
||||
func IsIdentityInquiry(message string) bool {
|
||||
@@ -592,6 +599,9 @@ func informationRequestKind(message string, candidate interaction.SemanticCandid
|
||||
if len(tokens) == 0 {
|
||||
return ""
|
||||
}
|
||||
if containsStemInTokens(tokens, "памят", "помнишь", "ячейк") && (containsMeaningfulInterrogative(tokens) || containsStemInTokens(tokens, "вывед", "покаж", "напиш", "сообщ")) {
|
||||
return interaction.InformationRequestMemoryInventory
|
||||
}
|
||||
inquiry := candidate.PrimarySpeechAct == interaction.SpeechActQuestion || candidate.PrimarySpeechAct == interaction.SpeechActRequestToInvestigate || candidate.SecondarySpeechAct == interaction.SpeechActQuestion || candidate.SecondarySpeechAct == interaction.SpeechActRequestToInvestigate
|
||||
cognitiveSubject := containsStemInTokens(tokens, "модел", "ии", "ai", "локальн", "когнитив", "канал")
|
||||
inventoryCue := containsStemInTokens(tokens, "список", "доступ", "подключ", "вариант") || (containsMeaningfulInterrogative(tokens) && containsStemInTokens(tokens, "настро"))
|
||||
|
||||
@@ -198,11 +198,23 @@ func TestNamingPreferenceIsSemanticAndProducesNaturalAcceptance(t *testing.T) {
|
||||
if name := PreferredAssistantName("я назову тебя дед, запомни"); name != "Дед" {
|
||||
t.Fatalf("expected conversational name form to be extracted, got %q", name)
|
||||
}
|
||||
if name := PreferredAssistantName("давай переименуем тебя в фею. теперь тебя зовут фея"); name != "Фея" {
|
||||
t.Fatalf("rename phrase returned %q", name)
|
||||
}
|
||||
if !IsIdentityInquiry("ты кто?") || !IsIdentityInquiry("как тебя зовут") {
|
||||
t.Fatal("identity variants should be recognized")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemoryInventoryRequestIsSemantic(t *testing.T) {
|
||||
for _, message := range []string{"выведи свою память", "напиши что ты помнишь в виде таблицы"} {
|
||||
candidate := BuildDeterministicCandidate(message, "", time.Unix(10, 0).UnixMilli())
|
||||
if got := informationRequestKind(message, candidate); got != interaction.InformationRequestMemoryInventory {
|
||||
t.Fatalf("%q: expected memory inventory, got %q", message, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeterministicCandidateKeepsFirstPersonCompletedWorkAsAssertion(t *testing.T) {
|
||||
candidate := BuildDeterministicCandidate("Я всё уже настроил.", "", time.Unix(10, 0).UnixMilli())
|
||||
if candidate.PrimarySpeechAct != interaction.SpeechActAssertion {
|
||||
|
||||
@@ -103,12 +103,18 @@ func TestContinueTravelOrigin(t *testing.T) {
|
||||
if got := ContinueTravelOrigin("я в Казани", nil); got != "" {
|
||||
t.Fatalf("location must not create a travel task without context: %q", got)
|
||||
}
|
||||
if got := ContinueTravelOrigin("Москва", history); got != "Как можно добраться до Сочи из города Москва" {
|
||||
t.Fatalf("bare city should complete travel origin: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTravelSearchClarification(t *testing.T) {
|
||||
if got := TravelSearchClarification("Найди билеты", nil); got == "" {
|
||||
t.Fatal("underspecified travel request must ask for missing route and date")
|
||||
}
|
||||
if got := TravelSearchClarification("Покажи ближайшие рейсы до Сочи", nil); got != "Из какого города вылетать?" {
|
||||
t.Fatalf("nearest-flight request should default date to now, got %q", got)
|
||||
}
|
||||
if got := TravelSearchClarification("Найди билеты из Москвы в Сочи на 12 сентября", nil); got != "" {
|
||||
t.Fatalf("complete travel request must proceed, got %q", got)
|
||||
}
|
||||
@@ -126,7 +132,7 @@ func TestTravelSearchClarification(t *testing.T) {
|
||||
t.Fatalf("complete general travel route must proceed, got %q", got)
|
||||
}
|
||||
contextHistory := []interaction.HumanUtterance{{Content: "Как можно добраться до Сочи?"}}
|
||||
if got := TravelSearchClarification("Найди билеты, какой ближайший самолёт", contextHistory); got != "Из какого города вылетать в Сочи и на какую дату?" {
|
||||
if got := TravelSearchClarification("Найди билеты, какой ближайший самолёт", contextHistory); got != "Из какого города вылетать в Сочи?" {
|
||||
t.Fatalf("travel destination should be inherited from context, got %q", got)
|
||||
}
|
||||
noisyContext := []interaction.HumanUtterance{
|
||||
|
||||
@@ -97,15 +97,22 @@ func ContinueLocalSearch(message string, history []interaction.HumanUtterance) s
|
||||
// completed for routing and research.
|
||||
func ContinueTravelOrigin(message string, history []interaction.HumanUtterance) string {
|
||||
current := semanticTokens(StripAssistantVocative(message))
|
||||
if len(current) < 3 || len(current) > 6 || current[0] != "я" {
|
||||
if len(current) == 0 || len(current) > 6 {
|
||||
return ""
|
||||
}
|
||||
location := ""
|
||||
for index, token := range current {
|
||||
if (token == "в" || token == "из") && index+1 < len(current) {
|
||||
location = capitalizeWord(current[index+1])
|
||||
break
|
||||
if current[0] == "я" {
|
||||
if len(current) < 3 {
|
||||
return ""
|
||||
}
|
||||
for index, token := range current {
|
||||
if (token == "в" || token == "из") && index+1 < len(current) {
|
||||
location = capitalizeWord(current[index+1])
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if len(current) <= 2 && !isTravelDateWord(current[0]) && len([]rune(current[0])) >= 3 {
|
||||
location = capitalizeWord(current[0])
|
||||
}
|
||||
if location == "" {
|
||||
return ""
|
||||
@@ -124,7 +131,11 @@ func ContinueTravelOrigin(message string, history []interaction.HumanUtterance)
|
||||
return ""
|
||||
}
|
||||
previous := strings.TrimRight(strings.TrimSpace(StripAssistantVocative(latest.Content)), "?!.,;:")
|
||||
return strings.TrimSpace(previous + " из " + location)
|
||||
preposition := " из "
|
||||
if current[0] != "я" {
|
||||
preposition = " из города "
|
||||
}
|
||||
return strings.TrimSpace(previous + preposition + location)
|
||||
}
|
||||
|
||||
// TravelSearchClarification keeps an incomplete travel request in dialogue
|
||||
@@ -149,6 +160,9 @@ func TravelSearchClarification(message string, history []interaction.HumanUttera
|
||||
origin := containsStemInTokens(current, "из", "откуда", "от")
|
||||
destination := containsStemInTokens(current, "в", "куда", "до")
|
||||
date := containsStemInTokens(current, "сегодня", "завтра", "послезавтр", "январ", "феврал", "март", "апрел", "мая", "июн", "июл", "август", "сентябр", "октябр", "ноябр", "декабр")
|
||||
if containsStemInTokens(current, "ближ") {
|
||||
date = true
|
||||
}
|
||||
if !date {
|
||||
for _, token := range current {
|
||||
if hasDigit(token) {
|
||||
@@ -190,6 +204,10 @@ func TravelSearchClarification(message string, history []interaction.HumanUttera
|
||||
return "Уточните маршрут и дату: откуда, куда и на какой день нужны билеты?"
|
||||
}
|
||||
|
||||
func isTravelDateWord(value string) bool {
|
||||
return containsStem(value, "сегодня", "завтра", "послезавтр", "январ", "феврал", "март", "апрел", "мая", "июн", "июл", "август", "сентябр", "октябр", "ноябр", "декабр")
|
||||
}
|
||||
|
||||
func destinationLabel(current []string, history []interaction.HumanUtterance) string {
|
||||
for index, token := range current {
|
||||
if (token == "в" || token == "до") && index+1 < len(current) {
|
||||
|
||||
Reference in New Issue
Block a user