UAIDE / src /components /AssessmentPanels.jsx
ATS-27
Refreshed backend assets and scripts via Git LFS
adad1d3
Raw
History Blame Contribute Delete
4.07 kB
import { BrainCircuit, ShieldAlert, ShieldCheck, Scale, Sparkles } from 'lucide-react';
import styles from './AssessmentPanels.module.css';
function SectionCard({ title, icon: Icon, tone = 'neutral', subtitle, children }) {
return (
<section className={`${styles.card} ${styles[`tone_${tone}`]}`}>
<div className={styles.header}>
<div className={styles.titleWrap}>
<div className={styles.iconWrap}><Icon size={16} /></div>
<div>
<h3 className={styles.title}>{title}</h3>
{subtitle ? <p className={styles.subtitle}>{subtitle}</p> : null}
</div>
</div>
</div>
<div className={styles.body}>{children}</div>
</section>
);
}
function Row({ label, value, mono = false, strong = false }) {
return (
<div className={styles.row}>
<span className={styles.label}>{label}</span>
<span className={`${styles.value} ${mono ? styles.mono : ''} ${strong ? styles.strong : ''}`}>{value}</span>
</div>
);
}
export default function AssessmentPanels({ result }) {
const ethical = result.ethical;
const neurosymbolic = result.neurosymbolic;
if (!ethical && !neurosymbolic) return null;
const ethicalTone = ethical ? (ethical.is_ethical ? 'positive' : 'critical') : 'neutral';
const nsTone = neurosymbolic?.decision === 'SYMBOLIC_SUPPORTS_AI' ? 'critical' : 'neutral';
return (
<div className={styles.grid}>
{neurosymbolic && (
<SectionCard
title="Neurosymbolic Analysis"
icon={BrainCircuit}
tone={nsTone}
subtitle="Symbolic rules layered over the model output for transparent forensic reasoning"
>
<Row label="Decision" value={neurosymbolic.decision?.replaceAll('_', ' ')} strong />
<Row label="Symbolic Score" value={`${((neurosymbolic.symbolic_score || 0) * 100).toFixed(1)}%`} />
{neurosymbolic.features && (
<>
<Row label="Residual Std" value={(neurosymbolic.features.residual_std || 0).toFixed(4)} mono />
<Row label="HF Ratio" value={(neurosymbolic.features.hf_ratio || 0).toFixed(4)} mono />
<Row label="LBP Entropy" value={(neurosymbolic.features.lbp_entropy || 0).toFixed(4)} mono />
</>
)}
<div className={styles.ruleBlock}>
<div className={styles.ruleTitle}><Sparkles size={14} />Triggered Rules</div>
{neurosymbolic.fired_rules?.length ? neurosymbolic.fired_rules.map((rule) => (
<div key={rule.rule} className={styles.ruleItem}>
<div className={styles.ruleHead}>
<span className={styles.ruleCode}>{rule.rule}</span>
<span className={styles.ruleWeight}>+{Number(rule.weight || 0).toFixed(2)}</span>
</div>
<p className={styles.ruleReason}>{rule.reason}</p>
</div>
)) : <p className={styles.empty}>No symbolic rules fired.</p>}
</div>
</SectionCard>
)}
{ethical && (
<SectionCard
title="Ethical Assessment"
icon={ethical.is_ethical ? ShieldCheck : ShieldAlert}
tone={ethicalTone}
subtitle="Risk-oriented interpretation layer for sensitive or harmful synthetic content"
>
<Row label="Status" value={ethical.status || 'UNKNOWN'} strong />
<Row label="Risk Score" value={`${((ethical.riskScore || 0) * 100).toFixed(1)}%`} />
<Row label="Simple Verdict" value={ethical.simpleStatus || 'Unavailable'} />
<div className={styles.flagBlock}>
<div className={styles.ruleTitle}><Scale size={14} />Flags</div>
<div className={styles.flagList}>
{ethical.flags?.length ? ethical.flags.map((flag) => (
<span key={flag} className={styles.flag}>{flag.replaceAll('_', ' ')}</span>
)) : <p className={styles.empty}>No ethical flags raised.</p>}
</div>
</div>
</SectionCard>
)}
</div>
);
}