aditya0103's picture
Tasks 5-7: eval harness, FastAPI backend, Paper & Ink UI- src/eval/ — precision/recall/F1 harness with type-aware comparators,micro/macro F1, CSV + markdown reports, --model benchmark flag- src/api/ — FastAPI backend with /extract, /schemas, /health,request-ID middleware, typed error envelope, injectable extractor- ui/ — Vite + React + TS + Tailwind + Motion + React Three FiberPaper & Ink editorial UI with 3D paper hero, dark/light mode,confidence inkwell, wax-stamp metrics, kinetic typography- 95 passing tests (up from 54); UI is a separate npm workspace
557ab38
Raw
History Blame Contribute Delete
2.46 kB
/**
* MetricsStrip — cost, latency, tokens, and model, styled like the marginalia
* on an accountant's ledger. Each is a small block with an eyebrow label and
* a display-font number, separated by thin ruled dividers.
*
* The cost gets a wax-stamp treatment — a small angled disc behind the number.
*/
import type { ExtractionMetrics } from "@/types";
interface Props {
metrics: ExtractionMetrics;
}
export function MetricsStrip({ metrics }: Props) {
return (
<div className="grid grid-cols-2 gap-6 border-t border-b border-[var(--rule)] py-6 sm:grid-cols-4">
<Cell label="Cost / doc" value={formatCost(metrics.cost_usd)} stamp />
<Cell label="Latency" value={formatLatency(metrics.latency_ms)} />
<Cell
label="Tokens"
value={`${metrics.input_tokens.toLocaleString()} + ${metrics.output_tokens.toLocaleString()}`}
small
/>
<Cell label="Model" value={metrics.model} small mono />
</div>
);
}
/* ------------------------------------------------------------------------ */
function Cell({
label,
value,
small,
mono,
stamp,
}: {
label: string;
value: string;
small?: boolean;
mono?: boolean;
stamp?: boolean;
}) {
return (
<div className="relative">
<p className="eyebrow mb-2">{label}</p>
<p
className={
(mono ? "font-mono " : "font-display ") +
"relative inline-block leading-none text-[var(--ink-strong)] " +
(small ? "text-[18px] pt-1" : "text-[34px]")
}
>
{stamp && <StampBg />}
<span className="relative">{value}</span>
</p>
</div>
);
}
function StampBg() {
return (
<svg
aria-hidden
className="pointer-events-none absolute -left-3 -top-3 h-14 w-14 -rotate-6 opacity-70"
viewBox="0 0 60 60"
fill="none"
>
<circle
cx="30"
cy="30"
r="26"
stroke="var(--accent)"
strokeWidth="1.2"
strokeDasharray="3 3"
/>
<circle cx="30" cy="30" r="22" stroke="var(--accent)" strokeWidth="0.8" />
</svg>
);
}
/* -- formatters ----------------------------------------------------------- */
function formatCost(usd: number): string {
if (usd < 0.001) return `$${(usd * 1000).toFixed(2)}m`; // in mills
return `$${usd.toFixed(4)}`;
}
function formatLatency(ms: number): string {
if (ms < 1000) return `${Math.round(ms)}ms`;
return `${(ms / 1000).toFixed(2)}s`;
}