import React from 'react'; import type { CodecDetail, RobustnessReport } from '../../services/audioService'; import { Zap, Radio, TrendingDown, Activity } from 'lucide-react'; interface AnomalyMarkersProps { codecDetail: CodecDetail; stabilityReport: RobustnessReport; aiProbability: number; } interface Anomaly { label: string; value: string; description: string; severity: 'ok' | 'warn' | 'alert'; icon: React.ElementType; } const AnomalyMarkers: React.FC = ({ codecDetail, stabilityReport, aiProbability, }) => { const snr = codecDetail?.snr_proxy_db ?? 0; const enf = codecDetail?.enf_strength ?? 0; const ripple = codecDetail?.spectral_ripple_peaks ?? 0; const dc = codecDetail?.dc_offset ?? 0; const stability = stabilityReport?.stability_score ?? 1; const anomalies: Anomaly[] = [ { label: 'SNR Floor', value: `${snr.toFixed(1)} dB`, description: snr > 60 ? 'Suspiciously clean — real recordings have ambient noise' : snr > 40 ? 'Elevated SNR — may indicate studio-grade TTS' : 'Normal noise floor — consistent with real recording', severity: snr > 60 ? 'alert' : snr > 40 ? 'warn' : 'ok', icon: Activity, }, { label: 'ENF Signature', value: enf > 1.2 ? `${enf.toFixed(2)}× peak` : 'Absent', description: enf > 1.2 ? 'Electrical network frequency detected — supports real recording origin' : 'No mains hum — common in TTS/synthetic audio', severity: enf > 1.2 ? 'ok' : 'warn', icon: Radio, }, { label: 'Spectral Ripple', value: `${ripple} peak${ripple !== 1 ? 's' : ''}`, description: ripple > 3 ? 'Periodic spectral ripple — consistent with resampling artifacts' : ripple > 1 ? 'Mild spectral irregularity detected' : 'No significant resampling artifacts', severity: ripple > 3 ? 'alert' : ripple > 1 ? 'warn' : 'ok', icon: TrendingDown, }, { label: 'Stress Stability', value: `${(stability * 100).toFixed(0)}%`, description: stability >= 0.80 ? 'Detection is stable under compression & telephony simulation' : stability >= 0.60 ? 'Moderate instability — result may shift with different formats' : 'Unstable detection — AI artifacts are compression-sensitive', severity: stability >= 0.80 ? 'ok' : stability >= 0.60 ? 'warn' : 'alert', icon: Zap, }, ]; const SEV_STYLES = { ok: { bg: 'var(--accent-green-transparent)', border: 'var(--accent-green-border)', color: 'var(--accent-green)', dot: 'var(--accent-green)' }, warn: { bg: 'var(--accent-yellow-transparent)', border: 'var(--accent-yellow-border)', color: 'var(--accent-yellow)', dot: '#eab308' }, alert: { bg: 'var(--accent-red-transparent)', border: 'var(--accent-red-border)', color: 'var(--accent-red)', dot: '#ef4444' }, }; return (
Codec & Physical Anomalies
65 ? 'var(--accent-red-transparent)' : 'var(--accent-green-transparent)', color: aiProbability > 65 ? 'var(--accent-red)' : 'var(--accent-green)', }} > {anomalies.filter(a => a.severity === 'alert').length} anomalies
{anomalies.map((a) => { const s = SEV_STYLES[a.severity]; return (
{a.label} {a.value}

{a.description}

); })}
{/* Stability scores bar */} {stabilityReport?.scores && (

Robustness Passes

{Object.entries(stabilityReport.scores).map(([key, val]) => { const pct = Math.round(val * 100); return (
{key}
70 ? 'var(--accent-red)' : 'var(--accent-green)' }} > {pct}%
); })}
)}
); }; export default AnomalyMarkers;