Continue local search from conversation context #321
@@ -511,6 +511,7 @@ func main() {
|
||||
var effectiveTaskMessage = interactiondomain.StripAssistantVocative(utterance.Content)
|
||||
var previousTask *interaction.HumanUtterance
|
||||
var conversationHistory []interaction.HumanUtterance
|
||||
var conversationOnlyHistory []interaction.HumanUtterance
|
||||
if request.ConversationID != "" {
|
||||
var historyErr error
|
||||
conversationHistory, historyErr = interactionRepository.Utterances(r.Context(), conversation.ID)
|
||||
@@ -518,6 +519,7 @@ func main() {
|
||||
log.Printf("interaction conversation history unavailable: %v", historyErr)
|
||||
}
|
||||
}
|
||||
conversationOnlyHistory = append(conversationOnlyHistory, conversationHistory...)
|
||||
// Keep durable user context available even when the web client carries a
|
||||
// conversation ID; a new or rotated conversation must not erase learned
|
||||
// preferences.
|
||||
@@ -528,6 +530,9 @@ func main() {
|
||||
log.Printf("interaction principal history loaded: %d utterances", len(recentUserHistory))
|
||||
}
|
||||
conversationHistory = append(conversationHistory, recentUserHistory...)
|
||||
if continuation := interactiondomain.ContinueLocalSearch(effectiveTaskMessage, conversationOnlyHistory); continuation != "" {
|
||||
effectiveTaskMessage = continuation
|
||||
}
|
||||
if request.ConversationID != "" && interactiondomain.IsRetryRequest(utterance.Content) {
|
||||
if len(conversationHistory) > 0 {
|
||||
for index := len(conversationHistory) - 1; index >= 0; index-- {
|
||||
|
||||
@@ -85,6 +85,16 @@ func TestLocalSearchClarification(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestContinueLocalSearch(t *testing.T) {
|
||||
history := []interaction.HumanUtterance{{Content: "Найди ближайший ресторан"}}
|
||||
if got := ContinueLocalSearch("в Сочи", history); got != "Найди ближайший ресторан в Сочи" {
|
||||
t.Fatalf("unexpected continuation: %q", got)
|
||||
}
|
||||
if got := ContinueLocalSearch("в Сочи", nil); got != "" {
|
||||
t.Fatalf("location must not create a goal without conversation context: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTravelSearchClarification(t *testing.T) {
|
||||
if got := TravelSearchClarification("Найди билеты", nil); got == "" {
|
||||
t.Fatal("underspecified travel request must ask for missing route and date")
|
||||
|
||||
@@ -65,6 +65,24 @@ func LocalSearchClarification(message string) string {
|
||||
return "В каком городе или районе искать ресторан?"
|
||||
}
|
||||
|
||||
// ContinueLocalSearch turns a location-only follow-up into the previous local
|
||||
// search request, but only when that request is present in this conversation.
|
||||
func ContinueLocalSearch(message string, history []interaction.HumanUtterance) string {
|
||||
current := strings.TrimSpace(StripAssistantVocative(message))
|
||||
tokens := semanticTokens(current)
|
||||
if len(tokens) == 0 || len(tokens) > 3 || (tokens[0] != "в" && tokens[0] != "на" && tokens[0] != "около") {
|
||||
return ""
|
||||
}
|
||||
for index := len(history) - 1; index >= 0; index-- {
|
||||
previous := strings.TrimSpace(StripAssistantVocative(history[index].Content))
|
||||
previousTokens := semanticTokens(previous)
|
||||
if containsStemInTokens(previousTokens, "ресторан", "кафе") && containsStemInTokens(previousTokens, "ближ", "рядом") {
|
||||
return strings.TrimSpace(previous + " " + current)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// TravelSearchClarification keeps an incomplete travel request in dialogue
|
||||
// instead of reducing it to an unrelated generic web search.
|
||||
func TravelSearchClarification(message string, history []interaction.HumanUtterance) string {
|
||||
|
||||
Reference in New Issue
Block a user