feat: harden search ranking and deduplication

This commit is contained in:
zhaoyilun
2026-07-10 09:39:18 +08:00
parent 1d6dd2f504
commit 6ca6c08b62
13 changed files with 368 additions and 56 deletions

View File

@@ -2,6 +2,7 @@ package tools
import (
"context"
"sort"
"strings"
"isphere-ai-bridge/internal/isphere"
@@ -73,7 +74,7 @@ func groupsFromDisplayEntities(entities []msglib.DisplayEntity) []isphere.Group
return groups
}
func mergeContacts(primary []isphere.Contact, fallback []isphere.Contact, limit int) isphere.SearchContactsResult {
func mergeContacts(primary []isphere.Contact, fallback []isphere.Contact, query string, limit int) isphere.SearchContactsResult {
seen := map[string]bool{}
contacts := make([]isphere.Contact, 0, len(primary)+len(fallback))
for _, contact := range append(primary, fallback...) {
@@ -83,14 +84,15 @@ func mergeContacts(primary []isphere.Contact, fallback []isphere.Contact, limit
}
seen[strings.ToLower(id)] = true
contacts = append(contacts, contact)
if limit > 0 && len(contacts) >= limit {
break
}
}
sortContactsForQuery(contacts, query)
if limit > 0 && len(contacts) > limit {
contacts = contacts[:limit]
}
return isphere.SearchContactsResult{Contacts: contacts}
}
func mergeGroups(primary []isphere.Group, fallback []isphere.Group, limit int) isphere.SearchGroupsResult {
func mergeGroups(primary []isphere.Group, fallback []isphere.Group, query string, limit int) isphere.SearchGroupsResult {
seen := map[string]bool{}
groups := make([]isphere.Group, 0, len(primary)+len(fallback))
for _, group := range append(primary, fallback...) {
@@ -100,9 +102,87 @@ func mergeGroups(primary []isphere.Group, fallback []isphere.Group, limit int) i
}
seen[strings.ToLower(id)] = true
groups = append(groups, group)
if limit > 0 && len(groups) >= limit {
break
}
}
sortGroupsForQuery(groups, query)
if limit > 0 && len(groups) > limit {
groups = groups[:limit]
}
return isphere.SearchGroupsResult{Groups: groups}
}
func sortContactsForQuery(contacts []isphere.Contact, query string) {
queryText := strings.ToLower(strings.TrimSpace(query))
sort.Slice(contacts, func(i, j int) bool {
leftRank := contactRankForQuery(contacts[i], queryText)
rightRank := contactRankForQuery(contacts[j], queryText)
if leftRank != rightRank {
return leftRank < rightRank
}
leftID := strings.ToLower(contacts[i].ContactID)
rightID := strings.ToLower(contacts[j].ContactID)
if leftID != rightID {
return leftID < rightID
}
return contacts[i].ContactID < contacts[j].ContactID
})
}
func contactRankForQuery(contact isphere.Contact, queryText string) int {
if queryText == "" {
return 0
}
values := []string{
strings.ToLower(contact.ContactID),
strings.ToLower(contact.DisplayName),
strings.ToLower(contact.Account),
}
for _, value := range values {
if value == queryText {
return 0
}
}
for _, value := range values {
if strings.HasPrefix(value, queryText) {
return 1
}
}
return 2
}
func sortGroupsForQuery(groups []isphere.Group, query string) {
queryText := strings.ToLower(strings.TrimSpace(query))
sort.Slice(groups, func(i, j int) bool {
leftRank := groupRankForQuery(groups[i], queryText)
rightRank := groupRankForQuery(groups[j], queryText)
if leftRank != rightRank {
return leftRank < rightRank
}
leftID := strings.ToLower(groups[i].GroupID)
rightID := strings.ToLower(groups[j].GroupID)
if leftID != rightID {
return leftID < rightID
}
return groups[i].GroupID < groups[j].GroupID
})
}
func groupRankForQuery(group isphere.Group, queryText string) int {
if queryText == "" {
return 0
}
values := []string{
strings.ToLower(group.GroupID),
strings.ToLower(group.DisplayName),
}
for _, value := range values {
if value == queryText {
return 0
}
}
for _, value := range values {
if strings.HasPrefix(value, queryText) {
return 1
}
}
return 2
}