// Analyzing state — terminal-style processing log. // No fake AI probability values: streams plausible log lines while the real // backend works, then shows a heartbeat until livePayload arrives. const { useState: useStateAna, useEffect: useEffectAna, useRef: useRefAna } = React; function AnalyzingScreen({ payload, file, onDone, onCancel }){ const [lines, setLines] = useStateAna([]); const [elapsed, setElapsed] = useStateAna(0); const [scriptDone, setScriptDone] = useStateAna(false); const logRef = useRefAna(null); // Elapsed clock useEffectAna(() => { const t0 = performance.now(); const tick = setInterval(() => setElapsed((performance.now() - t0)/1000), 100); return () => clearInterval(tick); }, []); // Streaming log useEffectAna(() => { const sizeKB = (file.sizeBytes/1024).toFixed(1); const ext = (file.name.split('.').pop() || 'bin').toLowerCase(); const script = [ ['boot', `truedetect v0.4.2 — engine cold-start`], ['boot', `loading verdict tiers, layer weights, ensemble config`], ['recv', `received: ${file.name} · ${sizeKB} KB · ${ext}`], ['parse', `detecting file type: ${ext}`], ['parse', `extracting raw text + metadata`], ['parse', `tokenizing sentences (spaCy en_core_web_sm)`], ['parse', `splitting paragraphs`], ['queue', `dispatching 10 layers in parallel (ThreadPoolExecutor)`], ['L1', `perplexity: scoring sentences via gpt2 (sample cap=150)`], ['L2', `burstiness: computing sentence-length Gini + std`], ['L3', `stylometrics: ttr, ai-phrase density, hedging, passive ratio`], ['L4', `semantic: paragraph embeddings via all-MiniLM-L6-v2`], ['L5', `unicode: scanning for invisible chars + homoglyphs`], ['L6', `metadata: scanning creator, producer, timestamps`], ['L7', `fonts: extracting per-glyph font data`], ['L8', `ensemble: chunking → roberta x2 inference`], ['L9', `hallucination: extracting claims via remote LLM`], ['L10', `revisions: parsing %%EOF count / docx track changes`], ['fuse', `combining weighted scores → verdict tier + confidence`], ['synth', `synthesizing narrative + conflict notes`], ['pdf', `rendering report → weasyprint → pdf`], ]; let i = 0; const interval = setInterval(() => { if (i >= script.length){ clearInterval(interval); setScriptDone(true); onDone(); return; } const [tag, msg] = script[i++]; setLines(L => [...L, { t: performance.now(), tag, msg }]); }, 280); return () => clearInterval(interval); }, [file.name, file.sizeBytes, onDone]); // Auto-scroll log to bottom useEffectAna(() => { if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight; }, [lines.length]); const tagColor = (tag) => { if (tag === 'boot' || tag === 'recv') return 'var(--text-muted)'; if (tag === 'parse' || tag === 'queue') return 'var(--blue)'; if (tag === 'fuse' || tag === 'synth') return 'var(--amber)'; if (tag === 'pdf') return 'var(--green)'; return 'var(--text)'; // L1..L10 }; return (