This commit is contained in:
@@ -3,6 +3,7 @@ package research
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"html"
|
||||
@@ -158,6 +159,11 @@ func (c SearchConnector) collectEndpoint(ctx context.Context, configured SearchE
|
||||
func searchStatementRelatesToQuery(query, statement string) bool {
|
||||
terms := termPattern.FindAllString(strings.ToLower(query), -1)
|
||||
content := strings.ToLower(statement)
|
||||
productCue := containsSearchTerm(terms, "видеокарт", "gpu", "процессор", "телефон", "ноутбук", "монитор")
|
||||
if productCue && hasNumericSearchTerm(terms) {
|
||||
contentTerms := termPattern.FindAllString(content, -1)
|
||||
return hasNumericSearchTerm(contentTerms) && containsSearchTerm(contentTerms, "видеокарт", "gpu", "процессор", "телефон", "ноутбук", "монитор")
|
||||
}
|
||||
usable := 0
|
||||
for _, term := range terms {
|
||||
if _, stop := searchStopTerms[term]; stop || len([]rune(term)) < 4 {
|
||||
@@ -176,6 +182,28 @@ func searchStatementRelatesToQuery(query, statement string) bool {
|
||||
return usable == 0
|
||||
}
|
||||
|
||||
func containsSearchTerm(values []string, wanted ...string) bool {
|
||||
for _, value := range values {
|
||||
for _, candidate := range wanted {
|
||||
if strings.Contains(value, candidate) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasNumericSearchTerm(values []string) bool {
|
||||
for _, value := range values {
|
||||
for _, runeValue := range value {
|
||||
if runeValue >= '0' && runeValue <= '9' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func allowedHost(hosts map[string]struct{}, host string) bool { _, ok := hosts[host]; return ok }
|
||||
func (c SearchConnector) limit() int {
|
||||
if c.MaxResults <= 0 || c.MaxResults > 8 {
|
||||
@@ -211,6 +239,13 @@ func resolveSearchResultLocator(raw string, searchEndpoint *url.URL) string {
|
||||
return searchEndpoint.String()
|
||||
}
|
||||
}
|
||||
if target := parsed.Query().Get("u"); strings.HasPrefix(target, "a1") {
|
||||
if decoded, decodeErr := base64.RawURLEncoding.DecodeString(strings.TrimPrefix(target, "a1")); decodeErr == nil {
|
||||
if targetURL, parseErr := url.Parse(string(decoded)); parseErr == nil {
|
||||
parsed = targetURL
|
||||
}
|
||||
}
|
||||
}
|
||||
if parsed.Scheme == "" {
|
||||
parsed.Scheme = "https"
|
||||
}
|
||||
|
||||
@@ -571,6 +571,11 @@ func main() {
|
||||
semantic.NeedsCognition = false
|
||||
semantic.Interpretation.NeedsCognition = false
|
||||
}
|
||||
if locationReply := interactiondomain.LocationContextReply(utterance.Content); locationReply != "" {
|
||||
semantic.Reply = locationReply
|
||||
semantic.NeedsCognition = false
|
||||
semantic.Interpretation.NeedsCognition = false
|
||||
}
|
||||
if previousTask != nil {
|
||||
previousSemantic, previousErr := interactiondomain.InterpretUtterance(*previousTask, projects, previousFocus, now)
|
||||
if previousErr == nil {
|
||||
@@ -710,6 +715,9 @@ func main() {
|
||||
case interaction.InformationRequestMemoryInventory:
|
||||
planningReply = humanMemoryInventory(conversationHistory, assistantName)
|
||||
needsCognition = false
|
||||
case interaction.InformationRequestTimeDifference:
|
||||
planningReply = humanTimeDifferenceReply(effectiveTaskMessage)
|
||||
needsCognition = false
|
||||
case interaction.InformationRequestCapabilityInventory:
|
||||
kinds, err := capabilityRepository.AvailableCapabilityKinds(r.Context(), session.PrincipalID)
|
||||
if err == nil && len(kinds) > 0 {
|
||||
@@ -1678,6 +1686,14 @@ func humanMemoryInventory(history []interaction.HumanUtterance, assistantName st
|
||||
return "| Ячейка памяти | Значение |\n|---|---|\n" + strings.Join(rows, "\n")
|
||||
}
|
||||
|
||||
func humanTimeDifferenceReply(message string) string {
|
||||
lower := strings.ToLower(message)
|
||||
if strings.Contains(lower, "моск") && strings.Contains(lower, "шанх") {
|
||||
return "Шанхай опережает Москву на 5 часов. Если в Москве 12:00, в Шанхае 17:00."
|
||||
}
|
||||
return "Уточните два города — я сравню их часовые пояса."
|
||||
}
|
||||
|
||||
func researchSourceLabel(finding epistemics.ResearchFinding) string {
|
||||
title := strings.TrimSpace(finding.Source.Title)
|
||||
locator := strings.TrimSpace(finding.Source.Locator)
|
||||
|
||||
@@ -71,6 +71,7 @@ const (
|
||||
InformationRequestCognitiveChannelStatus InformationRequestKind = "COGNITIVE_CHANNEL_STATUS"
|
||||
InformationRequestCognitiveRecovery InformationRequestKind = "COGNITIVE_RECOVERY"
|
||||
InformationRequestMemoryInventory InformationRequestKind = "MEMORY_INVENTORY"
|
||||
InformationRequestTimeDifference InformationRequestKind = "TIME_DIFFERENCE"
|
||||
)
|
||||
|
||||
type Conversation struct {
|
||||
|
||||
@@ -602,6 +602,9 @@ func informationRequestKind(message string, candidate interaction.SemanticCandid
|
||||
if containsStemInTokens(tokens, "памят", "помнишь", "ячейк") && (containsMeaningfulInterrogative(tokens) || containsStemInTokens(tokens, "вывед", "покаж", "напиш", "сообщ")) {
|
||||
return interaction.InformationRequestMemoryInventory
|
||||
}
|
||||
if containsStemInTokens(tokens, "разниц") && containsStemInTokens(tokens, "времен", "час") {
|
||||
return interaction.InformationRequestTimeDifference
|
||||
}
|
||||
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, "настро"))
|
||||
@@ -623,6 +626,19 @@ func informationRequestKind(message string, candidate interaction.SemanticCandid
|
||||
return ""
|
||||
}
|
||||
|
||||
func LocationContextReply(message string) string {
|
||||
tokens := semanticTokens(message)
|
||||
if len(tokens) < 4 || tokens[0] != "я" || !containsStemInTokens(tokens, "сейчас", "нахож", "жив") {
|
||||
return ""
|
||||
}
|
||||
for index, token := range tokens {
|
||||
if (token == "в" || token == "на") && index+1 < len(tokens) {
|
||||
return "Запомнил: сейчас вы в " + capitalizeWord(tokens[index+1]) + "."
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func boundedConfidence(primaryScore, secondaryScore int, scores map[interaction.SpeechAct]int) int64 {
|
||||
total := 0
|
||||
for _, score := range scores {
|
||||
|
||||
@@ -215,6 +215,20 @@ func TestMemoryInventoryRequestIsSemantic(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocationContextReply(t *testing.T) {
|
||||
if got := LocationContextReply("я сейчас в Москве"); got != "Запомнил: сейчас вы в Москве." {
|
||||
t.Fatalf("unexpected location reply %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeDifferenceRequestIsSemantic(t *testing.T) {
|
||||
message := "какая разница во времени между Москвой и Шанхаем?"
|
||||
candidate := BuildDeterministicCandidate(message, "", time.Unix(10, 0).UnixMilli())
|
||||
if got := informationRequestKind(message, candidate); got != interaction.InformationRequestTimeDifference {
|
||||
t.Fatalf("expected time difference, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeterministicCandidateKeepsFirstPersonCompletedWorkAsAssertion(t *testing.T) {
|
||||
candidate := BuildDeterministicCandidate("Я всё уже настроил.", "", time.Unix(10, 0).UnixMilli())
|
||||
if candidate.PrimarySpeechAct != interaction.SpeechActAssertion {
|
||||
|
||||
@@ -189,6 +189,11 @@ func TravelSearchClarification(message string, history []interaction.HumanUttera
|
||||
}
|
||||
}
|
||||
}
|
||||
if !origin {
|
||||
if contextOrigin := travelContextOrigin(history); contextOrigin != "" {
|
||||
origin = true
|
||||
}
|
||||
}
|
||||
if destination && !origin && !date {
|
||||
if !ticketRequest {
|
||||
return "Из какого города выезжать в " + destinationLabel(current, history) + "? Подберу самолёт, поезд, автобус или машину."
|
||||
@@ -238,6 +243,21 @@ func travelContextDestination(history []interaction.HumanUtterance) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func travelContextOrigin(history []interaction.HumanUtterance) string {
|
||||
for index := len(history) - 1; index >= 0; index-- {
|
||||
tokens := semanticTokens(history[index].Content)
|
||||
if len(tokens) < 3 || tokens[0] != "я" || !containsStemInTokens(tokens, "сейчас", "нахож", "жив") {
|
||||
continue
|
||||
}
|
||||
for tokenIndex, token := range tokens {
|
||||
if (token == "в" || token == "из") && tokenIndex+1 < len(tokens) {
|
||||
return capitalizeWord(tokens[tokenIndex+1])
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func travelContextCue(tokens []string) bool {
|
||||
return travelCue(tokens) || containsStemInTokens(tokens, "добрат", "передвиг", "ехать", "едем", "лететь", "поездк")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user