Commit
·
f39f6c2
1
Parent(s):
f54e377
- src/App.tsx +157 -47
- src/components/BenchmarkComparisonSelector.tsx +32 -0
- src/components/BenchmarkTable.tsx +169 -79
- src/lib/benchmarks/google.ts +36 -30
- src/lib/benchmarks/types.ts +4 -1
- src/lib/benchmarks/xai.ts +31 -25
src/App.tsx
CHANGED
@@ -7,8 +7,10 @@ import { mockData } from "@/lib/data";
|
|
7 |
|
8 |
import { ComparisonSelector } from "@/components/ComparisonSelector";
|
9 |
import { PricingTable } from "@/components/PricingTable";
|
10 |
-
|
11 |
import { BenchmarkTable } from "./components/BenchmarkTable";
|
|
|
|
|
12 |
|
13 |
|
14 |
export interface FlattenedModel extends Model {
|
@@ -41,33 +43,49 @@ const App: React.FC = () => {
|
|
41 |
const [expandedProviders, setExpandedProviders] = useState<string[]>([]);
|
42 |
const [tokenCalculation, setTokenCalculation] = useState<string>("million");
|
43 |
const [linkProviderModel, setLinkProviderModel] = useState<boolean>(false);
|
44 |
-
const [
|
|
|
|
|
|
|
|
|
45 |
|
46 |
const [sortConfig, setSortConfig] = useState<{
|
47 |
key: keyof FlattenedModel;
|
48 |
direction: string;
|
49 |
} | null>(null);
|
50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
useEffect(() => {
|
52 |
setData(mockData);
|
53 |
}, []);
|
54 |
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
provider.
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
|
72 |
const filteredData = useMemo(() => {
|
73 |
if (!selectedProviders.length && !selectedModels.length && !linkProviderModel) return data;
|
@@ -85,26 +103,82 @@ const App: React.FC = () => {
|
|
85 |
.filter((p) => p.models.length > 0);
|
86 |
}, [data, selectedProviders, selectedModels, linkProviderModel]);
|
87 |
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
(model) => model.benchmark && Object.keys(model.benchmark).length > 0
|
92 |
-
);
|
93 |
-
}, [data]);
|
94 |
|
95 |
-
const sortedBenchmarkedModels = useMemo(() => {
|
96 |
-
if (!benchmarkSortKey) return benchmarkedModels;
|
97 |
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
});
|
103 |
-
}, [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
|
105 |
|
106 |
const sortedFlattenedData = useMemo(() => {
|
107 |
-
const flattened =
|
108 |
if (!sortConfig) return flattened;
|
109 |
|
110 |
return [...flattened].sort((a, b) => {
|
@@ -131,21 +205,7 @@ const App: React.FC = () => {
|
|
131 |
);
|
132 |
};
|
133 |
|
134 |
-
const getModelsForSelectedProviders = () => {
|
135 |
-
const allModels = data.flatMap((provider) =>
|
136 |
-
provider.models.map((model) => ({
|
137 |
-
label: model.name,
|
138 |
-
value: model.name,
|
139 |
-
provider: provider.provider,
|
140 |
-
}))
|
141 |
-
);
|
142 |
-
|
143 |
-
const filtered = linkProviderModel
|
144 |
-
? allModels.filter((m) => selectedProviders.includes(m.provider))
|
145 |
-
: allModels;
|
146 |
|
147 |
-
return Array.from(new Map(filtered.map((m) => [m.value, m])).values());
|
148 |
-
};
|
149 |
|
150 |
return (
|
151 |
<Card className="w-full max-w-6xl mx-auto">
|
@@ -210,11 +270,61 @@ const App: React.FC = () => {
|
|
210 |
|
211 |
{/* Pricing Table */}
|
212 |
<h2 className="text-lg font-semibold mb-2">Pricing Table</h2>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
213 |
|
214 |
|
215 |
{/* Benchmark Table */}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
<h2 className="text-lg font-semibold mt-12 mb-2">Benchmark Table</h2>
|
217 |
-
<BenchmarkTable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
</CardContent>
|
219 |
</Card>
|
220 |
);
|
|
|
7 |
|
8 |
import { ComparisonSelector } from "@/components/ComparisonSelector";
|
9 |
import { PricingTable } from "@/components/PricingTable";
|
10 |
+
|
11 |
import { BenchmarkTable } from "./components/BenchmarkTable";
|
12 |
+
import { benchmarkData } from "./lib/benchmarks/ index";
|
13 |
+
import { BenchmarkComparisonSelector } from "./components/BenchmarkComparisonSelector";
|
14 |
|
15 |
|
16 |
export interface FlattenedModel extends Model {
|
|
|
43 |
const [expandedProviders, setExpandedProviders] = useState<string[]>([]);
|
44 |
const [tokenCalculation, setTokenCalculation] = useState<string>("million");
|
45 |
const [linkProviderModel, setLinkProviderModel] = useState<boolean>(false);
|
46 |
+
const [benchmarkComparisonMetrics, setBenchmarkComparisonMetrics] = useState<string[]>([]);
|
47 |
+
const [selectedBenchmarkProviders, setSelectedBenchmarkProviders] = useState<string[]>([]);
|
48 |
+
const [selectedBenchmarkModels, setSelectedBenchmarkModels] = useState<string[]>([]);
|
49 |
+
const [linkBenchmarkProviderModel, setLinkBenchmarkProviderModel] = useState<boolean>(false);
|
50 |
+
|
51 |
|
52 |
const [sortConfig, setSortConfig] = useState<{
|
53 |
key: keyof FlattenedModel;
|
54 |
direction: string;
|
55 |
} | null>(null);
|
56 |
|
57 |
+
const [benchmarkSortConfig, setBenchmarkSortConfig] = useState<{
|
58 |
+
key: string;
|
59 |
+
direction: "ascending" | "descending";
|
60 |
+
} | null>(null);
|
61 |
+
|
62 |
+
|
63 |
useEffect(() => {
|
64 |
setData(mockData);
|
65 |
}, []);
|
66 |
|
67 |
+
|
68 |
+
const flattenDataFromPricing = (data: Provider[]): FlattenedModel[] =>
|
69 |
+
data.flatMap((provider) =>
|
70 |
+
provider.models.map((model) => ({
|
71 |
+
provider: provider.provider,
|
72 |
+
uri: provider.uri,
|
73 |
+
...model,
|
74 |
+
benchmark: {},
|
75 |
+
}))
|
76 |
+
);
|
77 |
+
|
78 |
+
const flattenDataFromBenchmarks = (): FlattenedModel[] =>
|
79 |
+
benchmarkData.map((b) => ({
|
80 |
+
provider: b.provider ?? "Unknown",
|
81 |
+
uri: b.source, // placeholder or use an optional `b.link` if available
|
82 |
+
name: b.model,
|
83 |
+
inputPrice: b.inputPrice,
|
84 |
+
outputPrice: b.outputPrice,
|
85 |
+
benchmark: b.benchmark ?? {},
|
86 |
+
}));
|
87 |
+
|
88 |
+
|
89 |
|
90 |
const filteredData = useMemo(() => {
|
91 |
if (!selectedProviders.length && !selectedModels.length && !linkProviderModel) return data;
|
|
|
103 |
.filter((p) => p.models.length > 0);
|
104 |
}, [data, selectedProviders, selectedModels, linkProviderModel]);
|
105 |
|
106 |
+
const benchmarkedModels = useMemo(() => {
|
107 |
+
return flattenDataFromBenchmarks();
|
108 |
+
}, []);
|
|
|
|
|
|
|
109 |
|
|
|
|
|
110 |
|
111 |
+
|
112 |
+
const filteredBenchmarkedModels = useMemo(() => {
|
113 |
+
return benchmarkedModels.filter((model) => {
|
114 |
+
const providerMatch =
|
115 |
+
selectedBenchmarkProviders.length === 0 || selectedBenchmarkProviders.includes(model.provider);
|
116 |
+
const modelMatch =
|
117 |
+
selectedBenchmarkModels.length === 0 || selectedBenchmarkModels.includes(model.name);
|
118 |
+
|
119 |
+
if (linkBenchmarkProviderModel) {
|
120 |
+
return providerMatch && modelMatch;
|
121 |
+
}
|
122 |
+
|
123 |
+
// When not linking, allow filtering by either
|
124 |
+
if (selectedBenchmarkProviders.length > 0 && selectedBenchmarkModels.length > 0) {
|
125 |
+
return providerMatch || modelMatch;
|
126 |
+
}
|
127 |
+
|
128 |
+
return providerMatch && modelMatch; // this handles the case where one or both are empty
|
129 |
});
|
130 |
+
}, [
|
131 |
+
benchmarkedModels,
|
132 |
+
selectedBenchmarkProviders,
|
133 |
+
selectedBenchmarkModels,
|
134 |
+
linkBenchmarkProviderModel,
|
135 |
+
]);
|
136 |
+
|
137 |
+
|
138 |
+
const sortedBenchmarkedModels = useMemo(() => {
|
139 |
+
if (!benchmarkSortConfig) return filteredBenchmarkedModels;
|
140 |
+
|
141 |
+
return [...benchmarkedModels].sort((a, b) => {
|
142 |
+
const key = benchmarkSortConfig.key;
|
143 |
+
const aVal = key === "provider" || key === "name"
|
144 |
+
? (a as any)[key]?.toLowerCase?.() ?? ""
|
145 |
+
: a.benchmark?.[key] ?? -Infinity;
|
146 |
+
const bVal = key === "provider" || key === "name"
|
147 |
+
? (b as any)[key]?.toLowerCase?.() ?? ""
|
148 |
+
: b.benchmark?.[key] ?? -Infinity;
|
149 |
+
|
150 |
+
if (typeof aVal === "string" && typeof bVal === "string") {
|
151 |
+
return benchmarkSortConfig.direction === "ascending"
|
152 |
+
? aVal.localeCompare(bVal)
|
153 |
+
: bVal.localeCompare(aVal);
|
154 |
+
}
|
155 |
+
|
156 |
+
return benchmarkSortConfig.direction === "ascending"
|
157 |
+
? aVal - bVal
|
158 |
+
: bVal - aVal;
|
159 |
+
});
|
160 |
+
}, [filteredBenchmarkedModels, benchmarkSortConfig]);
|
161 |
+
|
162 |
+
|
163 |
+
const benchmarkProviders = useMemo(() => {
|
164 |
+
const modelsInBenchmark = new Set(
|
165 |
+
benchmarkedModels.map((m) => `${m.provider}:${m.name}`)
|
166 |
+
);
|
167 |
+
|
168 |
+
return data
|
169 |
+
.map((provider) => ({
|
170 |
+
...provider,
|
171 |
+
models: provider.models.filter((model) =>
|
172 |
+
modelsInBenchmark.has(`${provider.provider}:${model.name}`)
|
173 |
+
),
|
174 |
+
}))
|
175 |
+
.filter((p) => p.models.length > 0);
|
176 |
+
}, [data, benchmarkedModels]);
|
177 |
+
|
178 |
|
179 |
|
180 |
const sortedFlattenedData = useMemo(() => {
|
181 |
+
const flattened = flattenDataFromPricing(filteredData);
|
182 |
if (!sortConfig) return flattened;
|
183 |
|
184 |
return [...flattened].sort((a, b) => {
|
|
|
205 |
);
|
206 |
};
|
207 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
|
|
|
|
|
209 |
|
210 |
return (
|
211 |
<Card className="w-full max-w-6xl mx-auto">
|
|
|
270 |
|
271 |
{/* Pricing Table */}
|
272 |
<h2 className="text-lg font-semibold mb-2">Pricing Table</h2>
|
273 |
+
<PricingTable
|
274 |
+
data={sortedFlattenedData}
|
275 |
+
providers={data}
|
276 |
+
selectedProviders={selectedProviders}
|
277 |
+
selectedModels={selectedModels}
|
278 |
+
onProviderChange={setSelectedProviders}
|
279 |
+
onModelChange={setSelectedModels}
|
280 |
+
comparisonModels={comparisonModels}
|
281 |
+
inputTokens={inputTokens}
|
282 |
+
outputTokens={outputTokens}
|
283 |
+
tokenCalculation={tokenCalculation}
|
284 |
+
requestSort={requestSort}
|
285 |
+
sortConfig={sortConfig}
|
286 |
+
linkProviderModel={linkProviderModel}
|
287 |
+
/>
|
288 |
|
289 |
|
290 |
{/* Benchmark Table */}
|
291 |
+
<h3 className="text-lg font-semibold mt-12 mb-2">Select Benchmark Metrics to Compare</h3>
|
292 |
+
<BenchmarkComparisonSelector
|
293 |
+
allMetrics={Array.from(new Set(benchmarkedModels.flatMap((m) => Object.keys(m.benchmark ?? {})))).sort()}
|
294 |
+
selected={benchmarkComparisonMetrics}
|
295 |
+
onChange={(metric, checked) =>
|
296 |
+
setBenchmarkComparisonMetrics((prev) =>
|
297 |
+
checked ? [...prev, metric] : prev.filter((m) => m !== metric)
|
298 |
+
)
|
299 |
+
}
|
300 |
+
/>
|
301 |
+
|
302 |
+
|
303 |
+
|
304 |
+
|
305 |
+
|
306 |
<h2 className="text-lg font-semibold mt-12 mb-2">Benchmark Table</h2>
|
307 |
+
<BenchmarkTable
|
308 |
+
data={sortedBenchmarkedModels}
|
309 |
+
comparisonMetrics={benchmarkComparisonMetrics}
|
310 |
+
requestSort={(key) => {
|
311 |
+
setBenchmarkSortConfig((prev) =>
|
312 |
+
prev?.key === key
|
313 |
+
? { key, direction: prev.direction === "ascending" ? "descending" : "ascending" }
|
314 |
+
: { key, direction: "descending" }
|
315 |
+
);
|
316 |
+
}}
|
317 |
+
sortConfig={benchmarkSortConfig}
|
318 |
+
allProviders={benchmarkProviders}
|
319 |
+
selectedProviders={selectedBenchmarkProviders}
|
320 |
+
selectedModels={selectedBenchmarkModels}
|
321 |
+
onProviderChange={setSelectedBenchmarkProviders}
|
322 |
+
onModelChange={setSelectedBenchmarkModels}
|
323 |
+
linkProviderModel={linkBenchmarkProviderModel}
|
324 |
+
onLinkToggle={setLinkBenchmarkProviderModel}
|
325 |
+
/>
|
326 |
+
|
327 |
+
|
328 |
</CardContent>
|
329 |
</Card>
|
330 |
);
|
src/components/BenchmarkComparisonSelector.tsx
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// components/BenchmarkComparisonSelector.tsx
|
2 |
+
import React from "react";
|
3 |
+
import { Checkbox } from "@/components/ui/checkbox";
|
4 |
+
|
5 |
+
interface Props {
|
6 |
+
allMetrics: string[];
|
7 |
+
selected: string[];
|
8 |
+
onChange: (metric: string, checked: boolean) => void;
|
9 |
+
}
|
10 |
+
|
11 |
+
export const BenchmarkComparisonSelector: React.FC<Props> = ({
|
12 |
+
allMetrics,
|
13 |
+
selected,
|
14 |
+
onChange,
|
15 |
+
}) => {
|
16 |
+
return (
|
17 |
+
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2 mb-4">
|
18 |
+
{allMetrics.map((metric) => (
|
19 |
+
<div key={metric} className="flex items-center space-x-2">
|
20 |
+
<Checkbox
|
21 |
+
id={metric}
|
22 |
+
checked={selected.includes(metric)}
|
23 |
+
onCheckedChange={(checked) => onChange(metric, !!checked)}
|
24 |
+
/>
|
25 |
+
<label htmlFor={metric} className="text-sm">
|
26 |
+
{metric.replace(/_/g, " ").toUpperCase()}
|
27 |
+
</label>
|
28 |
+
</div>
|
29 |
+
))}
|
30 |
+
</div>
|
31 |
+
);
|
32 |
+
};
|
src/components/BenchmarkTable.tsx
CHANGED
@@ -1,93 +1,183 @@
|
|
1 |
import * as React from "react";
|
2 |
import {
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
} from "@/components/ui/table";
|
10 |
import { MultiSelect } from "@/components/ui/multi-select";
|
11 |
-
import {
|
|
|
12 |
|
13 |
interface BenchmarkTableProps {
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
}
|
16 |
|
17 |
-
export const BenchmarkTable: React.FC<BenchmarkTableProps> = ({
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
-
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
setVisibleMetrics(benchmarkMetrics);
|
33 |
-
}
|
34 |
-
}, [benchmarkMetrics]);
|
35 |
|
36 |
-
|
37 |
-
|
38 |
-
if (value === undefined) return "";
|
39 |
-
if (value >= 85) return "bg-green-100";
|
40 |
-
if (value >= 60) return "bg-yellow-100";
|
41 |
-
return "bg-red-100";
|
42 |
-
};
|
43 |
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
};
|
|
|
1 |
import * as React from "react";
|
2 |
import {
|
3 |
+
Table,
|
4 |
+
TableHeader,
|
5 |
+
TableBody,
|
6 |
+
TableRow,
|
7 |
+
TableHead,
|
8 |
+
TableCell,
|
9 |
} from "@/components/ui/table";
|
10 |
import { MultiSelect } from "@/components/ui/multi-select";
|
11 |
+
import { Switch } from "@/components/ui/switch";
|
12 |
+
import { Provider, FlattenedModel } from "@/App";
|
13 |
|
14 |
interface BenchmarkTableProps {
|
15 |
+
data: FlattenedModel[];
|
16 |
+
comparisonMetrics?: string[];
|
17 |
+
requestSort: (key: string) => void;
|
18 |
+
sortConfig: {
|
19 |
+
key: string;
|
20 |
+
direction: "ascending" | "descending";
|
21 |
+
} | null;
|
22 |
+
allProviders: Provider[];
|
23 |
+
selectedProviders: string[];
|
24 |
+
selectedModels: string[];
|
25 |
+
onProviderChange: (values: string[]) => void;
|
26 |
+
onModelChange: (values: string[]) => void;
|
27 |
+
linkProviderModel: boolean;
|
28 |
+
onLinkToggle: (checked: boolean) => void;
|
29 |
}
|
30 |
|
31 |
+
export const BenchmarkTable: React.FC<BenchmarkTableProps> = ({
|
32 |
+
data,
|
33 |
+
comparisonMetrics,
|
34 |
+
requestSort,
|
35 |
+
sortConfig,
|
36 |
+
allProviders,
|
37 |
+
selectedProviders,
|
38 |
+
selectedModels,
|
39 |
+
onProviderChange,
|
40 |
+
onModelChange,
|
41 |
+
linkProviderModel,
|
42 |
+
onLinkToggle,
|
43 |
+
}) => {
|
44 |
+
const benchmarkMetrics = React.useMemo(() => {
|
45 |
+
if (!comparisonMetrics || comparisonMetrics.length === 0) return [];
|
46 |
+
return comparisonMetrics;
|
47 |
+
}, [comparisonMetrics]);
|
48 |
+
|
49 |
+
const getCellStyle = (value?: number) => {
|
50 |
+
if (value === undefined) return "";
|
51 |
+
if (value >= 85) return "bg-green-100";
|
52 |
+
if (value >= 60) return "bg-yellow-100";
|
53 |
+
return "bg-red-100";
|
54 |
+
};
|
55 |
+
|
56 |
+
const renderSortIndicator = (key: string) => {
|
57 |
+
if (sortConfig?.key !== key) return null;
|
58 |
+
return sortConfig.direction === "ascending" ? " ▲" : " ▼";
|
59 |
+
};
|
60 |
|
61 |
+
const modelOptions = React.useMemo(() => {
|
62 |
+
const flat = allProviders.flatMap((provider) =>
|
63 |
+
provider.models.map((model) => ({
|
64 |
+
label: model.name,
|
65 |
+
value: model.name,
|
66 |
+
provider: provider.provider,
|
67 |
+
}))
|
68 |
+
);
|
69 |
|
70 |
+
const filtered = linkProviderModel
|
71 |
+
? flat.filter((m) => selectedProviders.includes(m.provider))
|
72 |
+
: flat;
|
|
|
|
|
|
|
73 |
|
74 |
+
return Array.from(new Map(filtered.map((m) => [m.value, m])).values());
|
75 |
+
}, [allProviders, selectedProviders, linkProviderModel]);
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
+
return (
|
78 |
+
<>
|
79 |
+
<div className="flex items-center space-x-4 mb-4">
|
80 |
+
<div className="flex-1">
|
81 |
+
<label className="text-sm font-medium block mb-1">Providers</label>
|
82 |
+
<MultiSelect
|
83 |
+
options={allProviders.map((p) => ({ label: p.provider, value: p.provider }))}
|
84 |
+
defaultValue={selectedProviders}
|
85 |
+
onValueChange={onProviderChange}
|
86 |
+
/>
|
87 |
+
</div>
|
88 |
+
<div className="flex-1">
|
89 |
+
<label className="text-sm font-medium block mb-1">Models</label>
|
90 |
+
<MultiSelect
|
91 |
+
options={modelOptions.map(({ label, value }) => ({ label, value }))}
|
92 |
+
defaultValue={selectedModels}
|
93 |
+
onValueChange={onModelChange}
|
94 |
+
/>
|
95 |
+
</div>
|
96 |
+
<div className="flex items-center pt-6 space-x-2">
|
97 |
+
<Switch
|
98 |
+
id="linkBenchmarkProviderModel"
|
99 |
+
checked={linkProviderModel}
|
100 |
+
onCheckedChange={onLinkToggle}
|
101 |
+
/>
|
102 |
+
<label htmlFor="linkBenchmarkProviderModel" className="text-sm">
|
103 |
+
Link Provider and Model
|
104 |
+
</label>
|
105 |
+
</div>
|
106 |
+
</div>
|
107 |
|
108 |
+
<Table>
|
109 |
+
<TableHeader>
|
110 |
+
<TableRow>
|
111 |
+
<TableHead>
|
112 |
+
<button
|
113 |
+
onClick={() => requestSort("provider")}
|
114 |
+
className="font-medium underline underline-offset-2"
|
115 |
+
>
|
116 |
+
Provider{renderSortIndicator("provider")}
|
117 |
+
</button>
|
118 |
+
</TableHead>
|
119 |
+
<TableHead>
|
120 |
+
<button
|
121 |
+
onClick={() => requestSort("name")}
|
122 |
+
className="font-medium underline underline-offset-2"
|
123 |
+
>
|
124 |
+
Model{renderSortIndicator("name")}
|
125 |
+
</button>
|
126 |
+
</TableHead>
|
127 |
+
<TableHead>
|
128 |
+
<button
|
129 |
+
onClick={() => requestSort("inputPrice")}
|
130 |
+
className="font-medium underline underline-offset-2"
|
131 |
+
>
|
132 |
+
Input Price (USD){renderSortIndicator("inputPrice")}
|
133 |
+
</button>
|
134 |
+
</TableHead>
|
135 |
+
<TableHead>
|
136 |
+
<button
|
137 |
+
onClick={() => requestSort("outputPrice")}
|
138 |
+
className="font-medium underline underline-offset-2"
|
139 |
+
>
|
140 |
+
Output Price (USD){renderSortIndicator("outputPrice")}
|
141 |
+
</button>
|
142 |
+
</TableHead>
|
143 |
+
|
144 |
+
{benchmarkMetrics.map((metric) => (
|
145 |
+
<TableHead key={metric}>
|
146 |
+
<button
|
147 |
+
onClick={() => requestSort(metric)}
|
148 |
+
className="font-medium underline underline-offset-2"
|
149 |
+
>
|
150 |
+
{metric.replace(/_/g, " ").toUpperCase()}
|
151 |
+
{renderSortIndicator(metric)}
|
152 |
+
</button>
|
153 |
+
</TableHead>
|
154 |
+
))}
|
155 |
+
</TableRow>
|
156 |
+
</TableHeader>
|
157 |
+
<TableBody>
|
158 |
+
{data.map((model) => (
|
159 |
+
<TableRow key={`${model.provider}-${model.name}`}>
|
160 |
+
<TableCell>
|
161 |
+
<a href={model.uri} className="underline">
|
162 |
+
{model.provider}
|
163 |
+
</a>
|
164 |
+
</TableCell>
|
165 |
+
<TableCell>{model.name}</TableCell>
|
166 |
+
<TableCell>${model.inputPrice.toFixed(2)}</TableCell>
|
167 |
+
<TableCell>${model.outputPrice.toFixed(2)}</TableCell>
|
168 |
+
|
169 |
+
{benchmarkMetrics.map((metric) => {
|
170 |
+
const score = model.benchmark?.[metric];
|
171 |
+
return (
|
172 |
+
<TableCell key={metric} className={getCellStyle(score)}>
|
173 |
+
{score !== undefined ? `${score.toFixed(1)}%` : "-"}
|
174 |
+
</TableCell>
|
175 |
+
);
|
176 |
+
})}
|
177 |
+
</TableRow>
|
178 |
+
))}
|
179 |
+
</TableBody>
|
180 |
+
</Table>
|
181 |
+
</>
|
182 |
+
);
|
183 |
};
|
src/lib/benchmarks/google.ts
CHANGED
@@ -2,36 +2,42 @@ import { Benchmark } from "./types";
|
|
2 |
|
3 |
|
4 |
export const googleBenchmarks: Benchmark[] = [
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
18 |
},
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
|
|
|
|
|
|
34 |
},
|
35 |
-
source: "Google Gemini site",
|
36 |
-
},
|
37 |
];
|
|
|
2 |
|
3 |
|
4 |
export const googleBenchmarks: Benchmark[] = [
|
5 |
+
{
|
6 |
+
model: "Gemini Diffusion",
|
7 |
+
provider: "Google",
|
8 |
+
inputPrice: 0,
|
9 |
+
outputPrice: 0,
|
10 |
+
benchmark: {
|
11 |
+
livecodebench_v6: 30.9,
|
12 |
+
bigcodebench: 45.4,
|
13 |
+
lbpp_v2: 56.8,
|
14 |
+
swe_bench_verified: 22.9,
|
15 |
+
humaneval: 89.6,
|
16 |
+
mbpp: 76.0,
|
17 |
+
gpqa_diamond: 40.4,
|
18 |
+
aime_2025: 23.3,
|
19 |
+
bigbench_extra_hard: 15.0,
|
20 |
+
global_mmlu_lite: 69.1,
|
21 |
+
},
|
22 |
+
source: "https://deepmind.google/models/gemini-diffusion/",
|
23 |
},
|
24 |
+
{
|
25 |
+
model: "Gemini 2.0 Flash-Lite",
|
26 |
+
provider: "Google",
|
27 |
+
inputPrice: 0.10,
|
28 |
+
outputPrice: 0.40,
|
29 |
+
benchmark: {
|
30 |
+
livecodebench_v6: 28.5,
|
31 |
+
bigcodebench: 45.8,
|
32 |
+
lbpp_v2: 56.0,
|
33 |
+
swe_bench_verified: 28.5,
|
34 |
+
humaneval: 90.2,
|
35 |
+
mbpp: 75.8,
|
36 |
+
gpqa_diamond: 56.5,
|
37 |
+
aime_2025: 20.0,
|
38 |
+
bigbench_extra_hard: 21.0,
|
39 |
+
global_mmlu_lite: 79.0,
|
40 |
+
},
|
41 |
+
source: "https://deepmind.google/models/gemini-diffusion/",
|
42 |
},
|
|
|
|
|
43 |
];
|
src/lib/benchmarks/types.ts
CHANGED
@@ -20,7 +20,10 @@ export type BenchmarkMetric =
|
|
20 |
|
21 |
export interface Benchmark {
|
22 |
model: string;
|
|
|
23 |
benchmark: Partial<Record<BenchmarkMetric, number>>;
|
24 |
-
|
|
|
|
|
25 |
version?: string;
|
26 |
}
|
|
|
20 |
|
21 |
export interface Benchmark {
|
22 |
model: string;
|
23 |
+
provider: string;
|
24 |
benchmark: Partial<Record<BenchmarkMetric, number>>;
|
25 |
+
inputPrice: number;
|
26 |
+
outputPrice: number;
|
27 |
+
source: string;
|
28 |
version?: string;
|
29 |
}
|
src/lib/benchmarks/xai.ts
CHANGED
@@ -2,32 +2,38 @@ import { Benchmark } from "./types";
|
|
2 |
|
3 |
|
4 |
export const xaiBenchmarks: Benchmark[] = [
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
16 |
},
|
17 |
-
source: "x.ai blog",
|
18 |
-
},
|
19 |
{
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
30 |
},
|
31 |
-
source: "x.ai blog",
|
32 |
-
},
|
33 |
];
|
|
|
2 |
|
3 |
|
4 |
export const xaiBenchmarks: Benchmark[] = [
|
5 |
+
{
|
6 |
+
model: "Grok 3 Beta",
|
7 |
+
provider: "Xai",
|
8 |
+
inputPrice: 3.00,
|
9 |
+
outputPrice: 15.00,
|
10 |
+
benchmark: {
|
11 |
+
aime_24: 52.2,
|
12 |
+
gpqa: 75.4,
|
13 |
+
lcb: 57.0,
|
14 |
+
mmlu_pro: 79.9,
|
15 |
+
loft: 83.3,
|
16 |
+
simpleqa: 43.6,
|
17 |
+
mmmu: 73.2,
|
18 |
+
egoschema: 74.5,
|
19 |
+
},
|
20 |
+
source: "https://x.ai/news/grok-3",
|
21 |
},
|
|
|
|
|
22 |
{
|
23 |
+
model: "Grok 3 mini Beta",
|
24 |
+
provider: "Xai",
|
25 |
+
inputPrice: 0.30,
|
26 |
+
outputPrice: 0.50,
|
27 |
+
benchmark: {
|
28 |
+
aime_24: 39.7,
|
29 |
+
gpqa: 66.2,
|
30 |
+
lcb: 41.5,
|
31 |
+
mmlu_pro: 78.9,
|
32 |
+
loft: 83.1,
|
33 |
+
simpleqa: 21.7,
|
34 |
+
mmmu: 69.4,
|
35 |
+
egoschema: 74.3,
|
36 |
+
},
|
37 |
+
source: "https://x.ai/news/grok-3",
|
38 |
},
|
|
|
|
|
39 |
];
|