mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-04 16:13:47 +00:00
- 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
70 lines
1.3 KiB
Go
70 lines
1.3 KiB
Go
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)
|
||
}
|