/* Homepage — search entry + corpus snapshot. * Stats block is wired through window.searchApi.getStats() so it lines * up with the documented GET /stats response shape and swaps to the * real backend by setting window.SEARCH_API_BASE. */ const StatsCard = () => { const [stats, setStats] = React.useState(null); const [error, setError] = React.useState(null); React.useEffect(() => { let cancelled = false; window.searchApi.getStats() .then((s) => { if (!cancelled) setStats(s); }) .catch((e) => { if (!cancelled) setError(e); }); return () => { cancelled = true; }; }, []); return (
Corpus snapshot
{error && (
stats unavailable
)} {!error && (
Cases {stats ? stats.cases.toLocaleString() : "—"} Opinions {stats ? stats.opinions.toLocaleString() : "—"} Chunks indexed {stats ? stats.chunks_indexed.toLocaleString() : "—"} Court {stats ? stats.court : "—"} Source {stats ? stats.source : "—"} Vector dim {stats?.vector_dimension != null ? stats.vector_dimension.toLocaleString() : "—"} Embedding {stats ? stats.embedding_model : "—"}
)}
GET /stats  ·  {stats ? stats.retrieval_modes.join(" · ") : "fts · vector · hybrid"}
); }; const modeLabel = (mode) => mode === "fts" ? "keyword" : mode === "vector" ? "semantic" : "hybrid"; const ExampleQueries = ({ onPick }) => (
Try a query
); const Homepage = ({ onSearch }) => { const [query, setQuery] = React.useState(""); const [mode, setMode] = React.useState("hybrid"); const submit = (q, m) => { const finalQ = (q ?? query).trim(); if (!finalQ) return; onSearch(finalQ, m ?? mode); }; return (
{/* Single inner content wrapper — aligns hero, search bar, and lower row */}
U.S. Supreme Court · CourtListener

A small, traceable casebase for searching legal opinions.

Keyword, semantic, and hybrid retrieval over chunked opinion text. Every result links back to its case, opinion, chunk, and character offsets.

submit()} autoFocus />
/ to focus  ·  to search
GET /search?mode={mode}
{/* Examples + corpus stats — share the same 720px inner width */}
submit(q, m)} />
{/* About — static, no fake numbers */}
About this prototype

Search runs against a normalized SCOTUS slice from CourtListener: cases → opinions → chunks. Keyword search is SQLite FTS5, semantic search is FAISS over OpenAI embeddings, hybrid fuses the two with reciprocal rank fusion. Each result returns its chunk, opinion, and case identifiers so you can trace any match back to the source text.

); }; window.Homepage = Homepage;