fix(ai): filter out noise from AI intelligence display
Critical fixes to show only actionable insights: 1. Skip stopped VMs/containers from anomaly detection - '0.0x baseline' for stopped resources is expected, not an anomaly - Only check anomalies for status='running' 2. Filter correlations by confidence (>=70%) - Low confidence correlations are likely coincidental - Only show high-confidence, actionable dependencies This reduces noise and surfaces genuinely useful intelligence.
This commit is contained in:
parent
98f3d0d48f
commit
367d22e937
2 changed files with 22 additions and 4 deletions
|
|
@ -211,12 +211,16 @@ export const AIOverviewTable: Component<{ showWhenEmpty?: boolean }> = (props) =
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Correlations - sorted by confidence, limited unless expanded
|
// Correlations - only show high-confidence (>=70%) to avoid noise
|
||||||
const sortedCorrelations = [...correlations()].sort((a, b) => b.confidence - a.confidence);
|
// Low confidence correlations are likely coincidental and not actionable
|
||||||
|
const MIN_CORRELATION_CONFIDENCE = 0.70;
|
||||||
|
const highConfidenceCorrelations = correlations().filter(c => c.confidence >= MIN_CORRELATION_CONFIDENCE);
|
||||||
|
const sortedCorrelations = [...highConfidenceCorrelations].sort((a, b) => b.confidence - a.confidence);
|
||||||
const visibleCorrelations = showAllDependencies()
|
const visibleCorrelations = showAllDependencies()
|
||||||
? sortedCorrelations
|
? sortedCorrelations
|
||||||
: sortedCorrelations.slice(0, DEPENDENCY_LIMIT);
|
: sortedCorrelations.slice(0, DEPENDENCY_LIMIT);
|
||||||
|
|
||||||
|
|
||||||
for (const corr of visibleCorrelations) {
|
for (const corr of visibleCorrelations) {
|
||||||
rows.push({
|
rows.push({
|
||||||
id: `corr-${corr.source_id}-${corr.target_id}`,
|
id: `corr-${corr.source_id}-${corr.target_id}`,
|
||||||
|
|
@ -560,9 +564,11 @@ export const AIOverviewTable: Component<{ showWhenEmpty?: boolean }> = (props) =
|
||||||
|
|
||||||
// Calculate hidden items per section
|
// Calculate hidden items per section
|
||||||
const hiddenDependencies = () => {
|
const hiddenDependencies = () => {
|
||||||
const total = correlations().length;
|
// Only count high-confidence correlations (>=70%)
|
||||||
return showAllDependencies() ? 0 : Math.max(0, total - DEPENDENCY_LIMIT);
|
const highConfidence = correlations().filter(c => c.confidence >= 0.70);
|
||||||
|
return showAllDependencies() ? 0 : Math.max(0, highConfidence.length - DEPENDENCY_LIMIT);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hiddenActions = () => {
|
const hiddenActions = () => {
|
||||||
const actionable = remediations().filter(rem => {
|
const actionable = remediations().filter(rem => {
|
||||||
const cmd = rem.action.trim().replace(/^\[[^\]]+\]\s*/, '');
|
const cmd = rem.action.trim().replace(/^\[[^\]]+\]\s*/, '');
|
||||||
|
|
|
||||||
|
|
@ -604,6 +604,11 @@ func (h *AISettingsHandler) HandleGetAnomalies(w http.ResponseWriter, r *http.Re
|
||||||
continue // Skip templates
|
continue // Skip templates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip VMs that aren't running - stopped VMs with 0% usage is expected, not an anomaly
|
||||||
|
if vm.Status != "running" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Skip if we don't have baselines for this resource
|
// Skip if we don't have baselines for this resource
|
||||||
if _, ok := resourceMetrics[vm.ID]; !ok {
|
if _, ok := resourceMetrics[vm.ID]; !ok {
|
||||||
if resourceID == "" {
|
if resourceID == "" {
|
||||||
|
|
@ -613,6 +618,7 @@ func (h *AISettingsHandler) HandleGetAnomalies(w http.ResponseWriter, r *http.Re
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
metrics := map[string]float64{
|
metrics := map[string]float64{
|
||||||
"cpu": vm.CPU * 100, // CPU is already 0-1, convert to percentage
|
"cpu": vm.CPU * 100, // CPU is already 0-1, convert to percentage
|
||||||
|
|
@ -648,6 +654,11 @@ func (h *AISettingsHandler) HandleGetAnomalies(w http.ResponseWriter, r *http.Re
|
||||||
continue // Skip templates
|
continue // Skip templates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip containers that aren't running - stopped containers with 0% usage is expected, not an anomaly
|
||||||
|
if ct.Status != "running" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Skip if we don't have baselines for this resource
|
// Skip if we don't have baselines for this resource
|
||||||
if _, ok := resourceMetrics[ct.ID]; !ok {
|
if _, ok := resourceMetrics[ct.ID]; !ok {
|
||||||
if resourceID == "" {
|
if resourceID == "" {
|
||||||
|
|
@ -657,6 +668,7 @@ func (h *AISettingsHandler) HandleGetAnomalies(w http.ResponseWriter, r *http.Re
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
metrics := map[string]float64{
|
metrics := map[string]float64{
|
||||||
"cpu": ct.CPU * 100, // CPU is already 0-1, convert to percentage
|
"cpu": ct.CPU * 100, // CPU is already 0-1, convert to percentage
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue