Neues UI
release-tag / release-image (push) Successful in 1m31s

This commit is contained in:
2026-07-28 18:55:55 +02:00
parent de813aad3c
commit 51995f9275
7 changed files with 575 additions and 164 deletions
+78
View File
@@ -193,6 +193,7 @@ func (s *Service) Process(ctx context.Context, id int64) error {
return err
}
if len(hits) > 0 {
run.KnowledgeCandidates = auditKnowledgeCandidates(hits, s.cfg.KnowledgeMinScore, 5)
run.KnowledgeTopID = hits[0].Doc.ID
run.KnowledgeTopTitle = hits[0].Doc.Title
run.KnowledgeScore = hits[0].Score
@@ -218,6 +219,7 @@ func (s *Service) Process(ctx context.Context, id int64) error {
run.ContextIssues = len(contextData.ServiceIssues)
run.ContextDevices = len(contextData.UserDevices)
run.ContextWarnings = append([]string(nil), contextData.Warnings...)
run.ContextDetails = auditContextDetails(contextData, 5)
if contextData.Incomplete {
s.metrics.ContextErrors.Add(1)
}
@@ -367,6 +369,82 @@ func (s *Service) Process(ctx context.Context, id int64) error {
finish(nil)
return nil
}
func auditKnowledgeCandidates(hits []model.KnowledgeHit, globalMin float64, limit int) []model.KnowledgeCandidateAudit {
if limit <= 0 || limit > len(hits) {
limit = len(hits)
}
out := make([]model.KnowledgeCandidateAudit, 0, limit)
for _, h := range hits[:limit] {
required := globalMin
if h.Doc.MinScore > required {
required = h.Doc.MinScore
}
out = append(out, model.KnowledgeCandidateAudit{
ID: h.Doc.ID, Title: h.Doc.Title, Source: h.Doc.Source, Score: h.Score,
SemanticScore: h.SemanticScore, TitleScore: h.TitleScore, KeywordScore: h.KeywordScore,
CategoryScore: h.CategoryScore, RequiredScore: required, AutoReply: h.Doc.AutoReply,
BestChunkExcerpt: h.BestChunkExcerpt, BestQueryExcerpt: h.BestQueryExcerpt,
QueryChunkCount: h.QueryChunkCount, DocumentChunkCount: h.DocumentChunkCount,
})
}
return out
}
func auditContextDetails(c model.ContextSnapshot, limit int) []model.ContextAuditItem {
if limit <= 0 {
limit = 5
}
out := make([]model.ContextAuditItem, 0, limit*4)
for i, x := range c.Changes {
if i >= limit {
break
}
out = append(out, model.ContextAuditItem{Kind: "change", ID: x.ID, Name: x.Name, Relevance: x.Relevance, Detail: strings.TrimSpace(x.PlannedBegin + " – " + x.PlannedEnd)})
}
for i, x := range c.MajorIncidents {
if i >= limit {
break
}
out = append(out, model.ContextAuditItem{Kind: "incident", ID: x.ID, Name: x.Name, Relevance: x.Relevance, Status: fmt.Sprint(x.StatusID), Detail: auditExcerpt(x.Content, 320)})
}
for i, x := range c.ServiceIssues {
if i >= limit {
break
}
name := x.MonitorName
if name == "" {
name = x.IncidentTitle
}
out = append(out, model.ContextAuditItem{Kind: "uptime", ID: x.MonitorID, Name: name, Relevance: x.Relevance, Status: x.Status, Detail: auditExcerpt(x.Message, 320)})
}
for i, x := range c.UserDevices {
if i >= limit {
break
}
name := x.Name
if name == "" {
name = fmt.Sprintf("%s #%d", x.ItemType, x.ID)
}
parts := make([]string, 0, 3)
for _, v := range []string{x.Serial, x.InventoryNumber, x.Location} {
if strings.TrimSpace(v) != "" {
parts = append(parts, strings.TrimSpace(v))
}
}
detail := strings.Join(parts, " · ")
out = append(out, model.ContextAuditItem{Kind: "device", ID: x.ID, Name: name, Status: x.Status, Detail: detail})
}
return out
}
func auditExcerpt(v string, max int) string {
v = strings.Join(strings.Fields(v), " ")
if max <= 0 || len(v) <= max {
return v
}
return strings.TrimSpace(v[:max]) + "…"
}
func (s *Service) getCategories(ctx context.Context) ([]model.Category, error) {
s.catMu.RLock()
if len(s.categories) > 0 && time.Since(s.catAt) < 10*time.Minute {