From 60989cd44d021054ec82fa456abd6bd291a30bc8 Mon Sep 17 00:00:00 2001 From: Eddy Date: Sat, 2 May 2026 22:50:27 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20KB-Hints=20Filter-Pipeline=20=E2=80=94?= =?UTF-8?q?=20generische=20Eintr=C3=A4ge=20rausfiltern=20[appimage]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kategorien wie setup, access, claude-md, skill, slash-command, hook werden aus Hints ausgeschlossen. Bei erkanntem Projekt werden Einträge mit passendem Tag bevorzugt (Fallback auf alle wenn Projekt-Filter leer). Co-Authored-By: Claude Opus 4.6 --- src-tauri/src/knowledge.rs | 52 ++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src-tauri/src/knowledge.rs b/src-tauri/src/knowledge.rs index 5d5ff3d..edfb750 100644 --- a/src-tauri/src/knowledge.rs +++ b/src-tauri/src/knowledge.rs @@ -620,23 +620,59 @@ async fn search_knowledge_filtered(search_query: &str, limit: usize, project: &O return Ok(String::new()); } - // Relevanz-Schwelle: Ergebnisse mit zu niedrigem Score rausfiltern. - // MySQL FULLTEXT NATURAL LANGUAGE MODE gibt Scores > 0 zurück, - // aber generische Einzel-Wort-Treffer haben oft Score < 2. + // === Filter-Pipeline: generische Referenz-Einträge raus === + + // 1. Kategorien die als Hints keinen Wert haben (Referenzdaten, Config-Backups) + const EXCLUDED_CATEGORIES: &[&str] = &[ + "setup", "access", "claude-md", "skill", "slash-command", "hook", + ]; + + // 2. Relevanz-Schwelle let min_relevance = 1.5; - let relevant: Vec<_> = results.into_iter() - .filter(|(_, _, _, _, _, _, relevance)| *relevance >= min_relevance) + + // 3. Basis-Filter: Relevanz + Kategorie + let base_filtered: Vec<_> = results.into_iter() + .filter(|(_, category, _, _, _, _, relevance)| { + if *relevance < min_relevance { return false; } + if EXCLUDED_CATEGORIES.contains(&category.as_str()) { return false; } + true + }) .collect(); - if relevant.is_empty() { - println!("🔍 Keine Hints über Relevanz-Schwelle ({:.1})", min_relevance); + if base_filtered.is_empty() { + println!("🔍 Keine Hints über Relevanz-Schwelle ({:.1}) nach Kategorie-Filter", min_relevance); return Ok(String::new()); } + // 4. Projekt-Filter: wenn Projekt erkannt, bevorzuge Einträge mit passendem Tag. + // Fallback auf base_filtered wenn Projekt-Filter alles wegfiltert. + let filtered_results = if let Some(ref proj) = project { + let proj_lower = proj.to_lowercase(); + let proj_filtered: Vec<_> = base_filtered.iter() + .filter(|(_, _, _, _, tags, _, _)| { + if let Some(ref t) = tags { + t.to_lowercase().contains(&proj_lower) + } else { + false + } + }) + .cloned() + .collect(); + if proj_filtered.is_empty() { + println!("🔍 Projekt-Filter '{}' ergab 0 Treffer, Fallback auf {} Basis-Treffer", proj, base_filtered.len()); + base_filtered + } else { + println!("🔍 Projekt-Filter '{}': {} von {} Treffern", proj, proj_filtered.len(), base_filtered.len()); + proj_filtered + } + } else { + base_filtered + }; + // Bereits gezeigte IDs filtern let filtered: Vec<_> = { let topic = SESSION_TOPIC.lock().unwrap(); - relevant.into_iter() + filtered_results.into_iter() .filter(|(id, _, _, _, _, _, _)| !topic.shown_ids.contains(id)) .take(limit) .collect()