/** * Global help: the (?) button in the app bar. Opens a dialog with tabs: * How it works — the pipeline story * Glossary — searchable glossary * Pages — what each page does (from pageGuides) * Tips — keyboard / nav tips * Docs — links into hf-space/docs/ * About — current version and release notes */ import { useMemo, useState } from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Dialog from '@mui/material/Dialog'; import DialogContent from '@mui/material/DialogContent'; import IconButton from '@mui/material/IconButton'; import InputAdornment from '@mui/material/InputAdornment'; import Link from '@mui/material/Link'; import Tab from '@mui/material/Tab'; import Tabs from '@mui/material/Tabs'; import TextField from '@mui/material/TextField'; import Tooltip from '@mui/material/Tooltip'; import Typography from '@mui/material/Typography'; import { ArrowRight, CircleHelp, MessageCircle, Search, X } from 'lucide-react'; import { GLOSSARY, GLOSSARY_CATEGORIES, type GlossaryEntry } from '../../content/glossary'; import { PAGE_GUIDE_LIST } from '../../help/pageGuides'; import { useLabelEval, type PageId } from '../../context/LabelEvalContext'; import { AboutPanel } from './AboutDialog'; import { APP_VERSION } from '../../content/releases'; // ---------------------------------------------------------------- how it works const PIPELINE_STAGES: Array<{ name: string; page: PageId; text: string }> = [ { name: '1 · Input', page: 'datasets', text: 'Datasets are ingested and versioned (Datasets). Raw frames flow into auto-labeling (Label Generation), which produces candidate labels at machine speed.', }, { name: '2 · Evaluation engines', page: 'evaluation', text: 'Every candidate label is measured from multiple angles: geometry vs reference GT where it exists, GT-free structural validation (Quality Engine), camera–LiDAR consistency, anomaly ensembles (Rare Events), grader consensus, tracking quality, and model-version regression (Regression).', }, { name: '3 · Quality gate', page: 'triage', text: 'The quality policy turns measurements into pass/fail gate lines: min IoU, max position/orientation error, min point support, min confidence, min consensus, anomaly threshold, tracking requirements.', }, { name: '4 · Triage', page: 'triage', text: 'Gate results deterministically route each label: all-pass → AUTO_GRADED; failures → FLAGGED with explicit failure reasons; hopeless → REJECTED. Every decision records its policy ID for audit.', }, { name: '5 · Human review (HITL)', page: 'review', text: 'Flagged labels and statistically-sampled labels reach human reviewers with full evidence (camera / LiDAR / BEV / temporal). Verdicts: verify, correct, or reject. Review of a stratified sample also puts confidence intervals on the automated headline metrics.', }, { name: '6 · Flywheel', page: 'training', text: 'Verified labels become training datasets; new models train on them; every new model is evaluated back through the platform (Command Center evaluation runs, promote / do-not-promote decisions). Better labels → better models → better labels.', }, ]; function HowItWorks({ goTo }: { goTo: (p: PageId) => void }) { return ( Sensorflow Studio evaluates machine-generated perception labels at scale. The core loop: measure every label, gate it against a versioned quality policy, route the uncertain minority to humans, and feed verified results back into training. Aggregates lead, individual annotations are drill-down. {PIPELINE_STAGES.map((s) => ( {s.name} {s.text} goTo(s.page)} title="Open related page" aria-label={`Open ${s.page}`} sx={{ color: '#5c6873' }}> ))} ); } // ---------------------------------------------------------------- glossary browser function GlossaryBrowser() { const [query, setQuery] = useState(''); const grouped = useMemo(() => { const q = query.trim().toLowerCase(); const entries = Object.values(GLOSSARY).filter( (e) => !q || e.term.toLowerCase().includes(q) || e.short.toLowerCase().includes(q) || e.detail.toLowerCase().includes(q) ); const byCat = new Map(); for (const cat of GLOSSARY_CATEGORIES) byCat.set(cat, []); for (const e of entries) byCat.get(e.category)?.push(e); return [...byCat.entries()].filter(([, list]) => list.length > 0); }, [query]); return ( setQuery(e.target.value)} sx={{ mb: 2 }} InputProps={{ startAdornment: ( ), }} /> {grouped.length === 0 ? ( No terms match “{query}”. ) : null} {grouped.map(([cat, entries]) => ( {cat} {entries.map((e) => ( {e.term} {e.short} {e.detail} {e.caveat ? ( Caveat: {e.caveat} ) : null} ))} ))} ); } // ---------------------------------------------------------------- page index function PageIndex({ goTo }: { goTo: (p: PageId) => void }) { return ( {PAGE_GUIDE_LIST.map((g) => ( goTo(g.pageId)} sx={{ display: 'flex', gap: 1.5, p: 1.25, mb: 0.75, bgcolor: '#141a20', border: '1px solid #232a31', borderRadius: 1, cursor: 'pointer', alignItems: 'center', '&:hover': { borderColor: '#4fc3f7' }, }} > {g.title} {g.summary} ))} ); } // ---------------------------------------------------------------- tips const NAV_TIPS = [ { title: 'Hash URLs', text: 'Every page is addressable as #/page or #/page/entityId. Browser back/forward and shareable deep links work.', }, { title: 'Left drawer', text: 'Platform / Studio / Engines / Safety / Legacy sections list every major screen. Badges on Overview and Human Review show live alert and queue counts.', }, { title: 'About this page', text: 'Under each page title, expand “About this page” for purpose, how to read the UI, actions, and data flow. Open state is remembered per page.', }, { title: 'Tooltips & glossary', text: 'Hover dotted terms and (i) icons for definitions. The Glossary tab searches the full term bank.', }, { title: 'Help chatbot', text: 'The floating chat bubble answers questions from the local FAQ + page-guide index (CPU-friendly). Ollama is optional enrichment when available.', }, { title: 'Active dataset chip', text: 'The AppBar chip shows the dataset other pages follow. Change it on Datasets.', }, { title: 'Version & About', text: 'The AppBar vX.Y.Z chip (and the matching chip at the bottom of the nav drawer) opens About: current version, links, and release notes. Help → About shows the same catalog.', }, ]; function TipsPanel() { return ( {NAV_TIPS.map((t) => ( {t.title} {t.text} ))} ); } // ---------------------------------------------------------------- docs const DOC_LINKS: Array<{ label: string; path: string; note: string }> = [ { label: 'Platform inventory', path: 'docs/PLATFORM_INVENTORY.md', note: 'What ships where in the Space.' }, { label: 'Population-scale roadmap', path: 'docs/POPULATION_SCALE_ROADMAP.md', note: 'Megaeval aggregate-first design.' }, { label: 'Hardening audit', path: 'docs/hardening/audit.md', note: 'Production-readiness findings.' }, { label: 'ROTR architecture', path: 'docs/architecture/rotr-architecture.md', note: 'Right-of-the-road control plane.' }, { label: 'Studio 2.0 review', path: 'docs/architecture/studio2-review.md', note: 'Governance / release gate.' }, { label: 'Next-gen ADR', path: 'docs/architecture/nextgen-adr.md', note: 'Closed-loop lab decisions.' }, { label: 'Vitis HIL PRD', path: 'docs/prd/vitis-hil-regression.md', note: 'Hardware acceleration demos.' }, { label: 'Retro final report', path: 'docs/retro/final-report.md', note: 'Retrospective analyzer.' }, ]; function DocsPanel() { return ( In-repo guides under hf-space/docs/. On Hugging Face Spaces these are packaged with the backend; locally open them in the repo. The Production Readiness page also surfaces the hardening audit live. {DOC_LINKS.map((d) => ( {d.label} {d.note} {d.path} ))} Also see{' '} Production Readiness {' '} for the live audit browser. ); } // ---------------------------------------------------------------- dialog shell type HelpTab = 'how' | 'glossary' | 'pages' | 'tips' | 'docs' | 'about'; export default function HelpMenu({ onOpenChat }: { onOpenChat?: () => void }) { const { navigate } = useLabelEval(); const [open, setOpen] = useState(false); const [tab, setTab] = useState('how'); const goTo = (p: PageId) => { setOpen(false); navigate(p); }; return ( <> setOpen(true)} sx={{ ml: 1, color: '#8a949e' }} aria-label="Open help"> setOpen(false)} maxWidth="md" fullWidth PaperProps={{ sx: { bgcolor: '#12171d', border: '1px solid #232a31', height: '82vh' } }} > Sensorflow Studio Help v{APP_VERSION} {onOpenChat ? ( ) : null} setOpen(false)} aria-label="Close help"> setTab(v)} variant="scrollable" scrollButtons="auto" sx={{ px: 2, minHeight: 36, '& .MuiTab-root': { minHeight: 36, fontSize: 12.5 } }} > {tab === 'how' ? : null} {tab === 'glossary' ? : null} {tab === 'pages' ? : null} {tab === 'tips' ? : null} {tab === 'docs' ? : null} {tab === 'about' ? : null} ); }