Spaces:
Sleeping
Sleeping
| import React from 'react'; | |
| import { formatNumber, getProgressBarStyle } from '../utils/formatters'; | |
| const MlModelCard = ({ riskAssessment, modelMeta, onRefresh, onShowHelp, loading }) => { | |
| const mlScore = riskAssessment?.evidence?.onnxScore; | |
| const heuristicScore = riskAssessment?.evidence?.heuristicRisk; | |
| // Calculate model confidence based on agreement between ML and heuristic scores | |
| const calculateConfidence = () => { | |
| if (mlScore === null || mlScore === undefined || heuristicScore === null || heuristicScore === undefined) { | |
| return 0; | |
| } | |
| const difference = Math.abs(mlScore - heuristicScore); | |
| if (difference < 0.2) return 0.9; // High confidence if scores agree | |
| if (difference < 0.4) return 0.6; // Medium confidence | |
| return 0.3; // Low confidence | |
| }; | |
| const confidence = calculateConfidence(); | |
| // Determine model status | |
| const getModelStatus = () => { | |
| if (!modelMeta) return 'Loading...'; | |
| if (modelMeta.modelPresent && modelMeta.oneClassSvmPresent) { | |
| return 'Level 2 Active (Isolation Forest + One-Class SVM)'; | |
| } else if (modelMeta.modelPresent) { | |
| return 'Level 2 Partial (Isolation Forest only)'; | |
| } else { | |
| return 'Level 1 Only (Heuristics)'; | |
| } | |
| }; | |
| return ( | |
| <div className="card"> | |
| <h3> | |
| ML Model (Level 2) | |
| <button className="help-btn" onClick={onShowHelp} title="Help">?</button> | |
| </h3> | |
| <div className="content"> | |
| {/* ML Anomaly Score */} | |
| <div style={{ marginBottom: '16px' }}> | |
| <div className="muted" style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}> | |
| <span>ML Anomaly Score</span> | |
| <span>{mlScore !== null && mlScore !== undefined ? formatNumber(mlScore, 3) : '–'}</span> | |
| </div> | |
| <div className="bar"> | |
| <div | |
| style={{ | |
| ...getProgressBarStyle(mlScore || 0, 'ml-score'), | |
| height: '100%', | |
| borderRadius: '999px', | |
| }} | |
| /> | |
| </div> | |
| </div> | |
| {/* Model Confidence */} | |
| <div style={{ marginBottom: '16px' }}> | |
| <div className="muted" style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}> | |
| <span>Model Confidence</span> | |
| <span>{formatNumber(confidence, 2)}</span> | |
| </div> | |
| <div className="bar"> | |
| <div | |
| style={{ | |
| ...getProgressBarStyle(confidence, 'confidence'), | |
| height: '100%', | |
| borderRadius: '999px', | |
| }} | |
| /> | |
| </div> | |
| </div> | |
| {/* Model Status */} | |
| <div className="muted" style={{ fontSize: '12px', marginBottom: '12px' }}> | |
| Model Status: <span style={{ fontWeight: '500' }}>{getModelStatus()}</span> | |
| </div> | |
| {/* Refresh Button */} | |
| <div> | |
| <button | |
| className="btn btn-secondary" | |
| onClick={onRefresh} | |
| disabled={loading} | |
| style={{ | |
| width: '100%', | |
| opacity: loading ? 0.6 : 1, | |
| cursor: loading ? 'not-allowed' : 'pointer' | |
| }} | |
| > | |
| {loading ? ( | |
| <> | |
| <span className="spinner" /> | |
| Refreshing... | |
| </> | |
| ) : ( | |
| 'Refresh Model' | |
| )} | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default MlModelCard; | |