Fix TS strict mode: remove unused imports, fix Tooltip formatter types in CostAnalysis"
Browse files
web/src/components/tabs/CostAnalysis.tsx
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
|
| 3 |
import { useState, useMemo } from "react";
|
| 4 |
import {
|
| 5 |
-
|
| 6 |
Tooltip, ResponsiveContainer, Legend,
|
| 7 |
AreaChart, Area,
|
| 8 |
} from "recharts";
|
|
@@ -25,7 +25,7 @@ export function CostAnalysis() {
|
|
| 25 |
const graphragCostPerQ = (2200 / 1000) * model.inputPer1k + (200 / 1000) * model.outputPer1k;
|
| 26 |
|
| 27 |
const cumulativeData = useMemo(() => {
|
| 28 |
-
const points = [];
|
| 29 |
const step = Math.max(Math.floor(numQueries / 50), 1);
|
| 30 |
for (let q = 0; q <= numQueries; q += step) {
|
| 31 |
points.push({
|
|
@@ -41,31 +41,22 @@ export function CostAnalysis() {
|
|
| 41 |
<div>
|
| 42 |
{/* Controls */}
|
| 43 |
<div className="card mb-6">
|
| 44 |
-
<div className="display-sm mb-4">Cost & Token Projections</div>
|
| 45 |
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
| 46 |
<div>
|
| 47 |
<label className="caption">Number of Queries</label>
|
| 48 |
-
<input
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
max={100000}
|
| 52 |
-
step={100}
|
| 53 |
-
value={numQueries}
|
| 54 |
-
onChange={(e) => setNumQueries(+e.target.value)}
|
| 55 |
-
className="w-full mt-2 accent-[#FF6B00]"
|
| 56 |
-
/>
|
| 57 |
<div className="body-sm font-mono mt-1">{numQueries.toLocaleString()}</div>
|
| 58 |
</div>
|
| 59 |
<div>
|
| 60 |
<label className="caption">LLM Model</label>
|
| 61 |
<div className="flex flex-wrap gap-2 mt-2">
|
| 62 |
{MODELS.map((m, i) => (
|
| 63 |
-
<button
|
| 64 |
-
key={m.id}
|
| 65 |
className={i === modelIdx ? "badge-orange" : "badge-outline cursor-pointer"}
|
| 66 |
-
onClick={() => setModelIdx(i)}
|
| 67 |
-
style={{ fontSize: "0.75rem" }}
|
| 68 |
-
>
|
| 69 |
{m.label}
|
| 70 |
</button>
|
| 71 |
))}
|
|
@@ -86,9 +77,9 @@ export function CostAnalysis() {
|
|
| 86 |
{[
|
| 87 |
{ label: "Cost/Query (Baseline)", value: "$" + baselineCostPerQ.toFixed(6), color: "#0072CE" },
|
| 88 |
{ label: "Cost/Query (GraphRAG)", value: "$" + graphragCostPerQ.toFixed(6), color: "#FF6B00" },
|
| 89 |
-
{ label: `Total (${(numQueries / 1000).toFixed(0)}K)`, value: "$" + (baselineCostPerQ * numQueries).toFixed(2),
|
| 90 |
-
{ label: `Total (${(numQueries / 1000).toFixed(0)}K)`, value: "$" + (graphragCostPerQ * numQueries).toFixed(2),
|
| 91 |
-
{ label: "Annual (1K qpd)", value: "$" + (graphragCostPerQ * 1000 * 365).toFixed(0),
|
| 92 |
].map((m, i) => (
|
| 93 |
<div key={i} className="card-cream" style={{ padding: "16px", textAlign: "center" }}>
|
| 94 |
<div className="metric-value-sm" style={{ color: m.color, fontSize: "1.125rem" }}>{m.value}</div>
|
|
@@ -99,9 +90,7 @@ export function CostAnalysis() {
|
|
| 99 |
|
| 100 |
{/* Cumulative Cost Chart */}
|
| 101 |
<div className="card mb-6">
|
| 102 |
-
<div className="title-md mb-4">
|
| 103 |
-
Cumulative Cost — {model.label}
|
| 104 |
-
</div>
|
| 105 |
<ResponsiveContainer width="100%" height={380}>
|
| 106 |
<AreaChart data={cumulativeData} margin={{ top: 10, right: 30, left: 10, bottom: 0 }}>
|
| 107 |
<defs>
|
|
@@ -115,16 +104,11 @@ export function CostAnalysis() {
|
|
| 115 |
</linearGradient>
|
| 116 |
</defs>
|
| 117 |
<CartesianGrid strokeDasharray="3 3" stroke="#002B49" strokeOpacity={0.06} />
|
| 118 |
-
<XAxis
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
tickFormatter={(v
|
| 122 |
-
/>
|
| 123 |
-
<YAxis tick={{ fill: "#6c6a64", fontSize: 11 }} tickFormatter={(v: number) => `$${v}`} />
|
| 124 |
-
<Tooltip
|
| 125 |
-
contentStyle={{ background: "#faf9f5", border: "1px solid #e6dfd8", borderRadius: "8px" }}
|
| 126 |
-
formatter={(v: number) => [`$${v.toFixed(4)}`, undefined]}
|
| 127 |
-
/>
|
| 128 |
<Legend />
|
| 129 |
<Area type="monotone" dataKey="Baseline" stroke="#0072CE" strokeWidth={2.5} fill="url(#baselineGrad)" />
|
| 130 |
<Area type="monotone" dataKey="GraphRAG" stroke="#FF6B00" strokeWidth={2.5} fill="url(#graphragGrad)" />
|
|
@@ -141,7 +125,8 @@ export function CostAnalysis() {
|
|
| 141 |
The Adaptive Router eliminates this overhead for simple queries by routing them to Baseline RAG —
|
| 142 |
achieving the best of both worlds.
|
| 143 |
</p>
|
| 144 |
-
<button className="btn btn-on-dark mt-4"
|
|
|
|
| 145 |
Try Adaptive Routing →
|
| 146 |
</button>
|
| 147 |
</div>
|
|
|
|
| 2 |
|
| 3 |
import { useState, useMemo } from "react";
|
| 4 |
import {
|
| 5 |
+
XAxis, YAxis, CartesianGrid,
|
| 6 |
Tooltip, ResponsiveContainer, Legend,
|
| 7 |
AreaChart, Area,
|
| 8 |
} from "recharts";
|
|
|
|
| 25 |
const graphragCostPerQ = (2200 / 1000) * model.inputPer1k + (200 / 1000) * model.outputPer1k;
|
| 26 |
|
| 27 |
const cumulativeData = useMemo(() => {
|
| 28 |
+
const points: { queries: number; Baseline: number; GraphRAG: number }[] = [];
|
| 29 |
const step = Math.max(Math.floor(numQueries / 50), 1);
|
| 30 |
for (let q = 0; q <= numQueries; q += step) {
|
| 31 |
points.push({
|
|
|
|
| 41 |
<div>
|
| 42 |
{/* Controls */}
|
| 43 |
<div className="card mb-6">
|
| 44 |
+
<div className="display-sm mb-4">Cost & Token Projections</div>
|
| 45 |
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
| 46 |
<div>
|
| 47 |
<label className="caption">Number of Queries</label>
|
| 48 |
+
<input type="range" min={100} max={100000} step={100}
|
| 49 |
+
value={numQueries} onChange={(e) => setNumQueries(+e.target.value)}
|
| 50 |
+
className="w-full mt-2 accent-[#FF6B00]" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
<div className="body-sm font-mono mt-1">{numQueries.toLocaleString()}</div>
|
| 52 |
</div>
|
| 53 |
<div>
|
| 54 |
<label className="caption">LLM Model</label>
|
| 55 |
<div className="flex flex-wrap gap-2 mt-2">
|
| 56 |
{MODELS.map((m, i) => (
|
| 57 |
+
<button key={m.id}
|
|
|
|
| 58 |
className={i === modelIdx ? "badge-orange" : "badge-outline cursor-pointer"}
|
| 59 |
+
onClick={() => setModelIdx(i)} style={{ fontSize: "0.75rem" }}>
|
|
|
|
|
|
|
| 60 |
{m.label}
|
| 61 |
</button>
|
| 62 |
))}
|
|
|
|
| 77 |
{[
|
| 78 |
{ label: "Cost/Query (Baseline)", value: "$" + baselineCostPerQ.toFixed(6), color: "#0072CE" },
|
| 79 |
{ label: "Cost/Query (GraphRAG)", value: "$" + graphragCostPerQ.toFixed(6), color: "#FF6B00" },
|
| 80 |
+
{ label: `Total (${(numQueries / 1000).toFixed(0)}K)`, value: "$" + (baselineCostPerQ * numQueries).toFixed(2), color: "#0072CE" },
|
| 81 |
+
{ label: `Total (${(numQueries / 1000).toFixed(0)}K)`, value: "$" + (graphragCostPerQ * numQueries).toFixed(2), color: "#FF6B00" },
|
| 82 |
+
{ label: "Annual (1K qpd)", value: "$" + (graphragCostPerQ * 1000 * 365).toFixed(0), color: "#cc785c" },
|
| 83 |
].map((m, i) => (
|
| 84 |
<div key={i} className="card-cream" style={{ padding: "16px", textAlign: "center" }}>
|
| 85 |
<div className="metric-value-sm" style={{ color: m.color, fontSize: "1.125rem" }}>{m.value}</div>
|
|
|
|
| 90 |
|
| 91 |
{/* Cumulative Cost Chart */}
|
| 92 |
<div className="card mb-6">
|
| 93 |
+
<div className="title-md mb-4">Cumulative Cost — {model.label}</div>
|
|
|
|
|
|
|
| 94 |
<ResponsiveContainer width="100%" height={380}>
|
| 95 |
<AreaChart data={cumulativeData} margin={{ top: 10, right: 30, left: 10, bottom: 0 }}>
|
| 96 |
<defs>
|
|
|
|
| 104 |
</linearGradient>
|
| 105 |
</defs>
|
| 106 |
<CartesianGrid strokeDasharray="3 3" stroke="#002B49" strokeOpacity={0.06} />
|
| 107 |
+
<XAxis dataKey="queries" tick={{ fill: "#6c6a64", fontSize: 11 }}
|
| 108 |
+
tickFormatter={(v) => (Number(v) >= 1000 ? `${Number(v) / 1000}K` : String(v))} />
|
| 109 |
+
<YAxis tick={{ fill: "#6c6a64", fontSize: 11 }}
|
| 110 |
+
tickFormatter={(v) => `$${v}`} />
|
| 111 |
+
<Tooltip contentStyle={{ background: "#faf9f5", border: "1px solid #e6dfd8", borderRadius: "8px" }} />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
<Legend />
|
| 113 |
<Area type="monotone" dataKey="Baseline" stroke="#0072CE" strokeWidth={2.5} fill="url(#baselineGrad)" />
|
| 114 |
<Area type="monotone" dataKey="GraphRAG" stroke="#FF6B00" strokeWidth={2.5} fill="url(#graphragGrad)" />
|
|
|
|
| 125 |
The Adaptive Router eliminates this overhead for simple queries by routing them to Baseline RAG —
|
| 126 |
achieving the best of both worlds.
|
| 127 |
</p>
|
| 128 |
+
<button className="btn btn-on-dark mt-4"
|
| 129 |
+
onClick={() => document.getElementById("live")?.scrollIntoView({ behavior: "smooth" })}>
|
| 130 |
Try Adaptive Routing →
|
| 131 |
</button>
|
| 132 |
</div>
|