Akash4911's picture
Production Deploy: Improved robustness and logging
66b6851
// @ts-nocheck
import { useState, useMemo } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
ShieldAlert,
Search,
Trash2,
Download,
Brain,
Fingerprint,
Zap,
BarChart3,
Info,
CheckCircle2,
FileSearch,
Activity,
ChevronRight
} from 'lucide-react';
import Sidebar from '../../components/layout/Sidebar';
import { scanTextSync } from '../../services/textService';
import type { TextResult } from '../../services/textService';
import {
BarChart,
Bar,
XAxis,
Tooltip,
ResponsiveContainer,
Cell
} from 'recharts';
const ForensicLab = () => {
const [text, setText] = useState("");
const [result, setResult] = useState<TextResult | null>(null);
const [isScanning, setIsScanning] = useState(false);
const [mode, setMode] = useState<"quick" | "deep" | "forensic">("deep");
const handleScan = async () => {
if (!text || text.length < 20) {
alert("Minimum 20 characters required for forensic analysis.");
return;
}
setIsScanning(true);
setResult(null);
try {
const data = await scanTextSync(text);
setResult(data);
} catch (error) {
console.error("Forensic scan failed:", error);
alert("Analysis engine failure. Check backend logs.");
} finally {
setIsScanning(false);
}
};
const getLabelColor = (label: string, score: number | null) => {
if (label === 'too_short') return 'transparent';
const s = (score || 0) / 100;
// Proper Heatmap Logic: Clearer, more distinct highlighting
if (label === 'AI') {
return `rgba(239, 68, 68, ${0.4 + s * 0.4})`; // Red
}
if (label === 'LIKELY_AI') {
return `rgba(249, 115, 22, ${0.3 + s * 0.4})`; // Orange
}
if (label === 'UNCERTAIN') {
return `rgba(234, 179, 8, ${0.3 + s * 0.3})`; // Yellow/Amber
}
if (label === 'HUMAN') {
return `rgba(34, 197, 94, ${0.2 + (1 - s) * 0.2})`; // Green
}
return 'transparent';
};
const getBorderColor = (label: string) => {
if (label === 'AI') return 'border-[var(--accent-red)]/40';
if (label === 'LIKELY_AI') return 'border-orange-500/30';
if (label === 'UNCERTAIN') return 'border-[var(--accent-purple)]/30';
if (label === 'HUMAN') return 'border-[var(--accent-green)]/30';
return 'border-transparent';
};
const signalData = useMemo(() => {
if (!result) return [];
return [
{ name: 'CLF1 (ChatGPT)', score: result.signals.clf1 * 100, color: '#00E5CC' },
{ name: 'CLF2 (OpenAI)', score: (result.signals.clf2 || 0) * 100, color: 'var(--accent-purple)' },
{ name: 'Embedding', score: result.signals.embedding * 100, color: '#6366f1' },
{ name: 'GPT2 Stats', score: result.signals.gpt2_entropy * 100, color: 'var(--accent-red)' },
{ name: 'Stylometric', score: result.signals.stylometric * 100, color: 'var(--text-active)' },
{ name: 'Consistency', score: (result.signals.consistency || 0) * 100, color: '#06b6d4' },
{ name: 'Repetition', score: (result.signals.repetition || 0) * 100, color: '#f97316' },
{ name: 'Entropy', score: (result.signals.entropy_var || 0) * 100, color: '#ec4899' },
];
}, [result]);
return (
<div className="flex h-screen overflow-hidden text-[var(--text-primary)] font-sans" style={{ background: 'var(--bg-primary)' }}>
<Sidebar activeTab="Text Lab" />
<div className="flex-1 flex flex-col min-w-0">
{/* Header */}
<header className="h-16 border-b bg-[var(--panel-bg)] backdrop-blur-xl flex items-center justify-between px-8 z-50" style={{ borderColor: 'var(--panel-border)' }}>
<div className="flex items-center space-x-4">
<div className="flex items-center text-xs font-mono text-[var(--text-muted)]">
<span className="hover:text-[var(--accent-purple)] transition-colors cursor-pointer">FORENSICS</span>
<ChevronRight className="w-3 h-3 mx-2" />
<span className="text-[var(--accent-purple)]">TEXT INTELLIGENCE LAB</span>
</div>
<div className="h-4 w-px bg-[var(--panel-border)]" />
<div className="flex bg-[var(--bg-secondary)] p-1 rounded-lg border border-[var(--panel-border)]">
{(['quick', 'deep', 'forensic'] as const).map((m) => (
<button
key={m}
onClick={() => setMode(m)}
className={`px-3 py-1 text-[10px] font-bold uppercase tracking-wider rounded-md transition-all ${
mode === m ? 'bg-[var(--accent-purple)] text-white shadow-lg shadow-purple-500/20' : 'text-[var(--text-muted)] hover:text-[var(--text-secondary)]'
}`}
>
{m}
</button>
))}
</div>
</div>
<div className="flex items-center space-x-4">
<div className="flex items-center px-3 py-1.5 bg-[var(--accent-green-transparent)] border border-[var(--accent-green-border)] rounded-full">
<div className="w-1.5 h-1.5 rounded-full bg-[var(--accent-green)] animate-pulse mr-2" />
<span className="text-[10px] font-mono text-[var(--accent-green)] tracking-tighter uppercase">V7.0-ALPHA-READY</span>
</div>
<button className="flex items-center px-4 py-2 bg-[var(--btn-secondary-bg)] border border-[var(--panel-border)] rounded-lg hover:bg-[var(--btn-secondary-hover)] transition-all font-mono text-[10px] uppercase tracking-widest text-[var(--text-primary)]">
<Download className="w-3 h-3 mr-2" />
REPORT.PDF
</button>
</div>
</header>
<main className="flex-1 flex overflow-hidden">
{/* Main Input/Result Area */}
<div className="flex-1 flex flex-col p-6 space-y-6 overflow-hidden">
<div className="flex-1 flex flex-col min-h-0 space-y-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<FileSearch className="w-5 h-5 text-[var(--accent-purple)]" />
<h2 className="text-sm font-bold uppercase tracking-widest text-[var(--text-heading)]">Investigation Chamber</h2>
</div>
<div className="flex items-center text-[10px] font-mono text-[var(--text-muted)]">
<Activity className="w-3 h-3 mr-1 text-[var(--accent-green)] opacity-50" />
REAL-TIME PATTERN MATCHING ENABLED
</div>
</div>
<div className="flex-1 rounded-2xl overflow-hidden relative shadow-2xl" style={{ background: 'var(--bg-secondary)', border: '1px solid var(--panel-border)' }}>
{!result && !isScanning && (
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Paste technical document, essay, or raw text for deep forensic analysis..."
className="w-full h-full bg-transparent p-8 text-lg font-light leading-relaxed outline-none resize-none placeholder:text-[var(--text-muted)] text-[var(--text-primary)]"
/>
)}
<AnimatePresence>
{isScanning && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 z-50 flex flex-col items-center justify-center bg-[var(--bg-primary)]/80 backdrop-blur-md"
>
<div className="relative">
<div className="w-24 h-24 border-2 border-[var(--accent-purple)]/20 rounded-full animate-ping absolute inset-0" />
<div className="w-24 h-24 border-t-2 border-[var(--accent-purple)] rounded-full animate-spin" />
<Brain className="w-8 h-8 text-[var(--accent-purple)] absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" />
</div>
<h3 className="mt-8 font-mono text-xs uppercase tracking-[0.4em] text-[var(--accent-purple)] animate-pulse">Running Neural Inference</h3>
<p className="mt-2 text-[10px] font-mono text-[var(--text-muted)]">ENGINE V7.0 • DEBERTA • MINI-LM • GPT2-E</p>
</motion.div>
)}
</AnimatePresence>
{result && (
<div className="w-full h-full p-8 overflow-y-auto custom-scrollbar">
<div className="prose prose-invert max-w-none">
<p className="text-lg leading-[1.8] font-light text-[var(--text-primary)]">
{result.sentence_highlights.map((h, i) => (
<motion.span
initial={{ backgroundColor: 'transparent', borderBottomColor: 'transparent' }}
animate={{
backgroundColor: getLabelColor(h.label, h.ai_score),
borderBottomColor: h.label === 'too_short' ? 'transparent' : 'inherit'
}}
key={i}
className={`inline px-1 py-1 mx-0.5 rounded-md border-b-2 ${getBorderColor(h.label)} transition-all duration-700 cursor-help group relative`}
>
{h.sentence}
{h.ai_score !== null && (
<span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 invisible group-hover:visible w-56 p-4 bg-[var(--bg-secondary)] border border-[var(--panel-border)] rounded-2xl shadow-2xl z-[100] text-[10px] pointer-events-none backdrop-blur-xl">
<div className="flex items-center justify-between mb-2">
<span className="font-bold text-[var(--text-muted)] uppercase tracking-tighter">FORENSIC SIGNAL</span>
<span className={h.ai_score > 70 ? 'text-[var(--accent-red)] font-black' : h.ai_score > 40 ? 'text-[var(--accent-yellow)]' : 'text-[var(--accent-green)]'}>
{h.ai_score}% AI
</span>
</div>
<div className="h-1.5 bg-[var(--border-subtle)] rounded-full overflow-hidden">
<div className={`h-full transition-all duration-1000 ${
h.label === 'AI' ? 'bg-gradient-to-r from-red-500 to-red-600' :
h.label === 'LIKELY_AI' ? 'bg-gradient-to-r from-orange-400 to-orange-500' :
h.label === 'UNCERTAIN' ? 'bg-gradient-to-r from-yellow-400 to-amber-500' :
'bg-gradient-to-r from-emerald-400 to-green-500'
}`} style={{ width: `${h.ai_score || 0}%` }} />
</div>
<div className="mt-3 flex items-center justify-between font-mono text-[9px] text-[var(--text-muted)] uppercase">
<span>VERDICT: {h.label.replace('_', ' ')}</span>
<div className="flex space-x-1">
<div className={`w-1.5 h-1.5 rounded-full ${h.label === 'AI' ? 'bg-red-500 shadow-[0_0_5px_red]' : 'bg-transparent'}`} />
<div className={`w-1.5 h-1.5 rounded-full ${h.label === 'LIKELY_AI' ? 'bg-orange-500' : 'bg-transparent'}`} />
<div className={`w-1.5 h-1.5 rounded-full ${h.label === 'UNCERTAIN' ? 'bg-yellow-500' : 'bg-transparent'}`} />
<div className={`w-1.5 h-1.5 rounded-full ${h.label === 'HUMAN' ? 'bg-green-500' : 'bg-transparent'}`} />
</div>
</div>
</span>
)}
</motion.span>
))}
</p>
</div>
</div>
)}
</div>
<div className="flex items-center space-x-4">
<button
disabled={isScanning}
onClick={handleScan}
className={`flex-1 group h-14 flex items-center justify-center space-x-3 rounded-2xl transition-all font-bold uppercase tracking-[0.2em] text-sm ${
isScanning
? 'bg-[var(--btn-secondary-bg)] text-[var(--text-muted)] cursor-not-allowed'
: 'bg-gradient-to-r from-[var(--accent-purple)] to-indigo-600 hover:opacity-90 text-white shadow-xl shadow-purple-500/20 active:scale-[0.98]'
}`}
>
{isScanning ? (
'PROCESSING ENGINE...'
) : (
<>
<Zap className="w-4 h-4 group-hover:animate-pulse" />
<span>{result ? 'INITIATE NEW SCAN' : 'RUN FORENSIC ANALYSIS'}</span>
</>
)}
</button>
<button
onClick={() => { setText(""); setResult(null); }}
className="w-14 h-14 bg-[var(--btn-secondary-bg)] border border-[var(--panel-border)] rounded-2xl flex items-center justify-center hover:bg-[var(--accent-red-transparent)] hover:border-[var(--accent-red-border)] hover:text-[var(--accent-red)] transition-all active:scale-95 text-[var(--text-muted)]"
>
<Trash2 className="w-5 h-5" />
</button>
</div>
</div>
</div>
{/* Right Sidebar - Analytics */}
<aside className="w-[400px] border-l overflow-y-auto custom-scrollbar flex flex-col" style={{ background: 'var(--panel-bg)', borderColor: 'var(--panel-border)' }}>
<div className="p-8 space-y-8">
{/* Verdict Section */}
<section className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-[var(--text-muted)]">Forensic Verdict</h3>
{result && (
<div className="flex items-center text-[10px] font-mono text-[var(--accent-purple)] bg-[var(--accent-purple-transparent)] px-2 py-0.5 rounded border border-[var(--accent-purple-border)]">
ID: {result.engine_version.split('-')[0]}
</div>
)}
</div>
<div className="rounded-3xl p-8 flex flex-col items-center relative overflow-hidden group" style={{ background: 'var(--bg-secondary)', border: '1px solid var(--panel-border)' }}>
<div className="absolute inset-0 bg-gradient-to-br from-[var(--accent-purple)]/5 to-transparent pointer-events-none" />
<div className="relative w-40 h-40 flex items-center justify-center">
<svg className="w-full h-full -rotate-90 pointer-events-none">
<circle cx="80" cy="80" r="70" className="fill-none stroke-[var(--border-subtle)] stroke-[8]" />
<motion.circle
cx="80" cy="80" r="70"
initial={{ strokeDasharray: "0, 440" }}
animate={{ strokeDasharray: `${(result ? result.confidence : 0) * 4.4}, 440` }}
transition={{ duration: 1.5, ease: "easeOut" }}
className={`fill-none stroke-[8] stroke-linecap-round ${
!result ? 'stroke-[var(--text-muted)]' :
result.threat_level === 'CRITICAL' ? 'stroke-[var(--accent-red)] shadow-[0_0_15px_rgba(239,68,68,0.5)]' :
result.threat_level === 'HIGH' ? 'stroke-[var(--accent-yellow)]' : 'stroke-[var(--accent-purple)]'
}`}
/>
</svg>
<div className="absolute inset-0 flex flex-col items-center justify-center">
<AnimatePresence mode="wait">
<motion.span
key={result ? result.confidence : 'no'}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
className="text-4xl font-black text-[var(--text-heading)]"
>
{result ? Math.round(result.confidence) : '00'}<span className="text-xl text-[var(--text-muted)]">%</span>
</motion.span>
</AnimatePresence>
<span className="text-[10px] font-mono text-[var(--text-muted)] uppercase tracking-widest mt-1">AI PROBABILITY</span>
</div>
</div>
<div className="mt-8 text-center space-y-2">
<div className={`text-xl font-black uppercase tracking-tighter ${
!result ? 'text-[var(--text-muted)]' :
result.threat_level === 'CRITICAL' ? 'text-[var(--accent-red)]' :
result.verdict.includes('HUMAN') ? 'text-[var(--accent-green)]' : 'text-[var(--text-heading)]'
}`}>
{result ? result.verdict : 'PENDING INPUT'}
</div>
{result && (
<div className="flex flex-col items-center space-y-1">
<div className="flex items-center space-x-2 text-[10px] font-mono">
<span className="text-[var(--text-muted)] uppercase tracking-widest">CONFIDENCE:</span>
<span className={`font-bold ${
result.confidence_level === 'HIGH' ? 'text-[var(--accent-green)]' :
result.confidence_level === 'MEDIUM' ? 'text-[var(--accent-yellow)]' : 'text-[var(--accent-red)]'
}`}>{result.confidence_level}</span>
</div>
<div className="flex items-center space-x-2 text-[10px] font-mono">
<span className="text-[var(--text-muted)] uppercase tracking-widest">RISK LEVEL:</span>
<span className={result.threat_level === 'CRITICAL' ? 'text-[var(--accent-red)]' : 'text-[var(--text-secondary)]'}>{result.threat_level}</span>
</div>
<div className="flex items-center space-x-2 text-[10px] font-mono">
<span className="text-[var(--text-muted)] uppercase tracking-widest">AGREEMENT:</span>
<span className="text-[var(--text-secondary)]">{result.agreement_score}/4 SIGNALS</span>
</div>
</div>
)}
</div>
</div>
</section>
{/* Signal Breakdown Section */}
<section className="space-y-4">
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-[var(--text-muted)]">Signal Breakdown</h3>
<div className="rounded-3xl p-6" style={{ background: 'var(--bg-secondary)', border: '1px solid var(--panel-border)' }}>
<div className="h-56 w-full">
{result ? (
<ResponsiveContainer width="100%" height="100%">
<BarChart data={signalData} margin={{ top: 20, right: 0, left: -25, bottom: 0 }}>
<XAxis
dataKey="name"
axisLine={false}
tickLine={false}
tick={{ fill: 'var(--text-muted)', fontSize: 10, fontWeight: 700 }}
/>
<Tooltip
cursor={{ fill: 'var(--border-subtle)' }}
content={({ active, payload }) => {
if (active && payload && payload.length) {
return (
<div className="bg-[var(--bg-secondary)] border border-[var(--panel-border)] p-3 rounded-xl shadow-2xl">
<p className="text-[10px] font-bold text-[var(--text-muted)] uppercase mb-1">{payload[0].payload.name}</p>
<p className="text-lg font-black text-[var(--text-heading)]">{Math.round(payload[0].value as number)}%</p>
</div>
);
}
return null;
}}
/>
<Bar dataKey="score" radius={[6, 6, 6, 6]} barSize={32}>
{signalData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} fillOpacity={0.8} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
) : (
<div className="h-full flex flex-col items-center justify-center text-[var(--text-muted)] opacity-20 space-y-4">
<BarChart3 className="w-12 h-12" />
<span className="text-[10px] font-mono uppercase tracking-[0.2em]">WAITING FOR SCAN DATA</span>
</div>
)}
</div>
</div>
</section>
{/* Forensic Reasons */}
<section className="space-y-4">
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-[var(--text-muted)]">Forensic Explanation</h3>
<div className="space-y-2">
{result && result.reasons ? (
result.reasons.map((reason, i) => (
<motion.div
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: i * 0.1 }}
key={i}
className="flex items-start space-x-3 p-4 rounded-2xl group border hover:border-[#00E5CC]/30 transition-colors"
style={{ background: 'var(--bg-secondary)', border: '1px solid var(--panel-border)' }}
>
<div className="mt-0.5">
<CheckCircle2 className="w-4 h-4" style={{ color: '#00E5CC' }} />
</div>
<div>
<div className="text-[11px] font-bold text-[var(--text-primary)]">{reason}</div>
</div>
</motion.div>
))
) : (
<div className="p-8 border border-[var(--panel-border)] border-dashed rounded-3xl flex flex-col items-center justify-center text-[var(--text-muted)] opacity-20">
<Info className="w-8 h-8 mb-2" />
<span className="text-[10px] font-mono uppercase">NO ANOMALIES DETECTED</span>
</div>
)}
</div>
</section>
{/* Indicators */}
<section className="space-y-4">
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-[var(--text-muted)]">Key Indicators</h3>
<div className="flex flex-wrap gap-2">
{result && result.indicators.map((indicator, i) => (
<span key={i} className="px-3 py-1 bg-[var(--bg-secondary)] border border-[var(--panel-border)] rounded-full text-[9px] font-bold text-[var(--text-secondary)] uppercase">
{indicator}
</span>
))}
</div>
</section>
{/* Stability Score */}
{result && (
<section className="space-y-4">
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-[var(--text-muted)]">Engine Stability</h3>
<div className="rounded-3xl p-6" style={{ background: 'var(--bg-secondary)', border: '1px solid var(--panel-border)' }}>
<div className="flex justify-between items-center mb-4">
<div className="flex items-center space-x-2">
<Activity className="w-4 h-4 text-[var(--accent-green)]" />
<span className="text-[10px] font-bold text-[var(--text-secondary)] uppercase tracking-wider">Detection Stability</span>
</div>
<span className="text-sm font-black text-[var(--accent-green)]">{Math.round(result.stability_score * 100)}%</span>
</div>
<div className="h-1.5 bg-[var(--border-subtle)] rounded-full overflow-hidden">
<motion.div
initial={{ width: 0 }}
animate={{ width: `${result.stability_score * 100}%` }}
className="h-full bg-[var(--accent-green)]"
/>
</div>
</div>
</section>
)}
{/* Linguistic Fingerprint Section */}
{result && result.stylometric_details && (
<section className="space-y-4">
<h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-[var(--text-muted)]">Linguistic Fingerprint</h3>
<div className="grid grid-cols-2 gap-3">
{[
{ label: 'Burstiness', value: result.stylometric_details.burstiness_cv, icon: Activity, color: 'text-[#00E5CC]' },
{ label: 'Vocab Diversity', value: result.stylometric_details.ttr, icon: Fingerprint, color: 'text-[var(--accent-purple)]' },
{ label: 'AI Phrases', value: result.stylometric_details.ai_phrases, icon: Search, color: 'text-[var(--accent-yellow)]' },
{ label: 'Passive Voice', value: result.stylometric_details.passives, icon: ShieldAlert, color: 'text-indigo-400' }
].map((item, i) => (
<div key={i} className="rounded-2xl p-4 flex flex-col space-y-2" style={{ background: 'var(--bg-secondary)', border: '1px solid var(--panel-border)' }}>
<div className="flex items-center space-x-2">
<item.icon className={`w-3 h-3 ${item.color}`} />
<span className="text-[9px] font-bold text-[var(--text-muted)] uppercase">{item.label}</span>
</div>
<div className="text-lg font-black text-[var(--text-heading)]">
{typeof item.value === 'number' && item.value < 1 ? Math.round(item.value * 100) + '%' : item.value}
</div>
</div>
))}
</div>
</section>
)}
</div>
<div className="mt-auto p-8 border-t" style={{ background: 'var(--panel-bg)', borderColor: 'var(--panel-border)' }}>
<div className="flex items-center space-x-3 text-[var(--text-muted)] mb-4">
<Brain className="w-5 h-5 text-[var(--accent-purple)]" />
<div>
<div className="text-[10px] font-black uppercase tracking-widest text-[var(--text-secondary)]">FAKESHIELD V7 FORENSIC JUDGE</div>
<div className="text-[8px] font-mono tracking-tighter uppercase">NEURAL LOGIC • STYLOGRAPHY • ENTROPY</div>
</div>
</div>
<p className="text-[10px] leading-relaxed text-[var(--text-muted)] italic">
{result
? `Forensic analysis complete. System identifies the text as ${result.verdict.toLowerCase()} with ${result.confidence_level.toLowerCase()} confidence markers based on ${result.agreement_score} cross-engine signals.`
: "Awaiting forensic target for comprehensive linguistic analysis. Neural models pre-loaded and stabilized."
}
</p>
</div>
</aside>
</main>
</div>
<style>{`
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: transparent;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: var(--panel-border);
border-radius: 10px;
}
`}</style>
</div>
);
};
export default ForensicLab;