Humanize web research replies #347

Merged
m merged 1 commits from codex/household-scenario-audit into main 2026-08-25 10:38:48 +00:00
2 changed files with 29 additions and 2 deletions
+22 -2
View File
@@ -1671,7 +1671,7 @@ func renderResearchReply(query string, result epistemics.ResearchResult, researc
if finding.State != epistemics.FindingSupported || strings.TrimSpace(finding.Excerpt.Text) == "" || strings.TrimSpace(finding.Source.Locator) == "" {
continue
}
excerpt := strings.TrimSpace(finding.Excerpt.Text)
excerpt := humanResearchExcerpt(query, finding.Excerpt.Text)
limit := 180
if index > 0 {
limit = 100
@@ -1687,7 +1687,7 @@ func renderResearchReply(query string, result epistemics.ResearchResult, researc
if len(lines) == 0 {
return "Проверяемых данных пока не найдено. Могу повторить поиск или уточнить, что именно проверить.", false
}
reply := strings.Join(lines, "\n")
reply := "Нашёл проверяемые данные:\n\n" + strings.Join(lines, "\n\n")
lowerQuery := strings.ToLower(query)
if (strings.Contains(lowerQuery, "цен") || strings.Contains(lowerQuery, "стоим")) && !containsPriceEvidence(reply) {
reply = "Актуальная цена в найденных фрагментах не указана, поэтому не буду придумывать сумму. Вот страницы, где её можно проверить:\n" + reply
@@ -1695,6 +1695,26 @@ func renderResearchReply(query string, result epistemics.ResearchResult, researc
return reply, true
}
func humanResearchExcerpt(query, raw string) string {
text := strings.Join(strings.Fields(strings.TrimSpace(raw)), " ")
if text == "" {
return text
}
parts := strings.Split(text, " — ")
if len(parts) < 2 {
return text
}
lowerQuery := strings.ToLower(query)
for index := len(parts) - 1; index >= 0; index-- {
candidate := strings.TrimSpace(parts[index])
lower := strings.ToLower(candidate)
if len([]rune(candidate)) >= 24 && (strings.Contains(lower, "сейчас") || strings.Contains(lower, "температур") || strings.Contains(lower, "цена") || strings.Contains(lower, "стоим") || strings.Contains(lower, "рейс") || strings.Contains(lower, "вылет") || strings.Contains(lowerQuery, "найди")) {
return candidate
}
}
return text
}
func containsPriceEvidence(value string) bool {
pricePattern := regexp.MustCompile(`(?i)(\d[\d\s.,]{2,})(?:\s*(?:₽|руб\.?|р\.?|usd|\$|€))`)
return pricePattern.MatchString(value)
+7
View File
@@ -15,6 +15,13 @@ import (
interactiondomain "git.cin.su/m/Assistant/modules/interaction/domain"
)
func TestHumanResearchExcerptRemovesSearchResultHeading(t *testing.T) {
got := humanResearchExcerpt("погода в Санкт-Петербурге", "Погода в Санкт-Петербурге — Прогноз погоды — Сейчас пасмурно, температура +14°")
if got != "Сейчас пасмурно, температура +14°" || strings.Contains(got, "Прогноз погоды") {
t.Fatalf("human research excerpt = %q", got)
}
}
func TestBearerTokenRequiresBearerScheme(t *testing.T) {
request := httptest.NewRequest("GET", "/", nil)
request.Header.Set("Authorization", "Basic value")