Files
glpi-neural-brain/internal/graph/filter.go
groot b3bd3d5ffd
All checks were successful
release-tag / release-image (push) Successful in 2m24s
BugFix
2026-08-05 11:58:25 +02:00

68 lines
1.8 KiB
Go

package graph
import (
"fmt"
"net/url"
"strings"
"github.com/local/glpi-neural-brain/internal/model"
)
// NodeFilter limits knowledge-bearing nodes by the exact value stored in the
// KB document's source field. Values are compared case-sensitively after
// trimming surrounding whitespace. An empty Sources list means unrestricted.
// No category, origin, URI or taxonomy fallback participates in matching.
type NodeFilter struct {
Sources []string
}
func (f NodeFilter) Matches(node model.Node) bool {
if len(f.Sources) == 0 {
return true
}
source := strings.TrimSpace(NodeSource(node))
for _, wanted := range f.Sources {
wanted = strings.TrimSpace(wanted)
if wanted == "" {
continue
}
if source == wanted {
return true
}
}
return false
}
// NodeSource returns only the explicit source metadata copied from the KB
// file's top-level source field (or assigned explicitly to generated research
// evidence). Technical origins such as glpi-kb are deliberately ignored.
func NodeSource(node model.Node) string {
return metadataText(node.Metadata, "source")
}
// SourceFromURL derives the explicit source value used for learned web
// evidence. It is kept separate from NodeSource so ordinary nodes never fall
// back to their URI implicitly.
func SourceFromURL(raw string) string {
parsed, err := url.Parse(strings.TrimSpace(raw))
if err != nil {
return ""
}
return strings.ToLower(strings.TrimSpace(parsed.Hostname()))
}
func metadataText(metadata map[string]any, key string) string {
if metadata == nil {
return ""
}
value, ok := metadata[key]
if !ok || value == nil {
return ""
}
text := strings.TrimSpace(fmt.Sprint(value))
if text == "" || strings.EqualFold(text, "<nil>") || strings.EqualFold(text, "null") {
return ""
}
return text
}