Files
goclaw/internal/knowledgegraph/similarity.go
T
viettranx 21b6c454ca feat: merge pipeline, per-user credentials, unified picker, group contacts
- Enable merge UI for linking channel contacts to tenant_users
- Contact → tenant_user resolution with cached lookup (60s TTL)
- MCP per-user credentials via user-keyed connection pool
- Secure CLI per-user credentials with AES-256-GCM encryption
- Unified UserPickerCombobox searching contacts + tenant_users
- Group contact collection with chat title in all channels
- Group permission inheritance via wildcard user_id="*"
- Fix heartbeat using wrong userID in group chats
- Filter internal senders from contact collection
- Add contact_type column (user/group) to channel_contacts
- SQLite schema v2 migration for desktop edition
2026-03-29 22:33:17 +07:00

70 lines
1.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package knowledgegraph
import "strings"
// JaroWinkler computes the Jaro-Winkler similarity between two strings (0.0–1.0).
// Higher values indicate greater similarity. Case-insensitive comparison.
func JaroWinkler(a, b string) float64 {
a = strings.ToLower(a)
b = strings.ToLower(b)
if a == b {
return 1.0
}
if len(a) == 0 || len(b) == 0 {
return 0.0
}
// Jaro similarity
matchDist := max(max(len(a), len(b))/2-1, 0)
aMatched := make([]bool, len(a))
bMatched := make([]bool, len(b))
var matches, transpositions float64
for i := range a {
lo := max(0, i-matchDist)
hi := min(len(b), i+matchDist+1)
for j := lo; j < hi; j++ {
if bMatched[j] || a[i] != b[j] {
continue
}
aMatched[i] = true
bMatched[j] = true
matches++
break
}
}
if matches == 0 {
return 0.0
}
k := 0
for i := range a {
if !aMatched[i] {
continue
}
for !bMatched[k] {
k++
}
if a[i] != b[k] {
transpositions++
}
k++
}
jaro := (matches/float64(len(a)) + matches/float64(len(b)) + (matches-transpositions/2)/matches) / 3.0
// Winkler prefix bonus (up to 4 chars, scaling factor 0.1)
prefix := 0
for i := 0; i < min(4, min(len(a), len(b))); i++ {
if a[i] == b[i] {
prefix++
} else {
break
}
}
return jaro + float64(prefix)*0.1*(1-jaro)
}