Presidentlin commited on
Commit
f23b928
·
1 Parent(s): f39f6c2
src/App.tsx CHANGED
@@ -1,8 +1,6 @@
1
  import React, { useState, useEffect, useMemo } from "react";
2
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
3
  import { Input } from "@/components/ui/input";
4
- import { Switch } from "@/components/ui/switch";
5
-
6
  import { mockData } from "@/lib/data";
7
 
8
  import { ComparisonSelector } from "@/components/ComparisonSelector";
@@ -42,12 +40,9 @@ const App: React.FC = () => {
42
  const [selectedModels, setSelectedModels] = useState<string[]>([]);
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;
@@ -65,74 +60,70 @@ const App: React.FC = () => {
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;
92
 
93
  return data
94
  .filter((p) => !selectedProviders.length || selectedProviders.includes(p.provider))
95
  .map((p) => ({
96
  ...p,
97
  models: p.models.filter((m) => {
98
- if (linkProviderModel && !selectedModels.length) return selectedProviders.includes(p.provider);
99
- if (!linkProviderModel && !selectedModels.length) return !selectedProviders.length || selectedProviders.includes(p.provider);
100
  return selectedModels.includes(m.name);
101
  }),
102
  }))
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(() => {
@@ -159,21 +150,49 @@ const filteredBenchmarkedModels = useMemo(() => {
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
 
@@ -262,17 +281,11 @@ const filteredBenchmarkedModels = useMemo(() => {
262
  </div>
263
  </div>
264
 
265
- {/* Provider–Model Toggle */}
266
- <div className="flex items-center space-x-2 mb-6">
267
- <Switch id="linkProviderModel" checked={linkProviderModel} onCheckedChange={setLinkProviderModel} />
268
- <label htmlFor="linkProviderModel" className="text-sm">Link Provider and Model</label>
269
- </div>
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}
@@ -283,8 +296,7 @@ const filteredBenchmarkedModels = useMemo(() => {
283
  tokenCalculation={tokenCalculation}
284
  requestSort={requestSort}
285
  sortConfig={sortConfig}
286
- linkProviderModel={linkProviderModel}
287
- />
288
 
289
 
290
  {/* Benchmark Table */}
@@ -299,10 +311,6 @@ const filteredBenchmarkedModels = useMemo(() => {
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}
@@ -320,8 +328,6 @@ const filteredBenchmarkedModels = useMemo(() => {
320
  selectedModels={selectedBenchmarkModels}
321
  onProviderChange={setSelectedBenchmarkProviders}
322
  onModelChange={setSelectedBenchmarkModels}
323
- linkProviderModel={linkBenchmarkProviderModel}
324
- onLinkToggle={setLinkBenchmarkProviderModel}
325
  />
326
 
327
 
 
1
  import React, { useState, useEffect, useMemo } from "react";
2
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
3
  import { Input } from "@/components/ui/input";
 
 
4
  import { mockData } from "@/lib/data";
5
 
6
  import { ComparisonSelector } from "@/components/ComparisonSelector";
 
40
  const [selectedModels, setSelectedModels] = useState<string[]>([]);
41
  const [expandedProviders, setExpandedProviders] = useState<string[]>([]);
42
  const [tokenCalculation, setTokenCalculation] = useState<string>("million");
 
43
  const [benchmarkComparisonMetrics, setBenchmarkComparisonMetrics] = useState<string[]>([]);
44
  const [selectedBenchmarkProviders, setSelectedBenchmarkProviders] = useState<string[]>([]);
45
  const [selectedBenchmarkModels, setSelectedBenchmarkModels] = useState<string[]>([]);
 
 
46
 
47
  const [sortConfig, setSortConfig] = useState<{
48
  key: keyof FlattenedModel;
 
60
  }, []);
61
 
62
 
63
+ const flattenDataFromPricing = (data: Provider[]): FlattenedModel[] =>
64
+ data.flatMap((provider) =>
65
+ provider.models.map((model) => ({
66
+ provider: provider.provider,
67
+ uri: provider.uri,
68
+ ...model,
69
+ benchmark: {},
70
+ }))
71
+ );
72
 
73
+ const flattenDataFromBenchmarks = (): FlattenedModel[] =>
74
+ benchmarkData.map((b) => ({
75
+ provider: b.provider ?? "Unknown",
76
+ uri: b.source, // placeholder or use an optional `b.link` if available
77
+ name: b.model,
78
+ inputPrice: b.inputPrice,
79
+ outputPrice: b.outputPrice,
80
+ benchmark: b.benchmark ?? {},
81
+ }));
82
 
83
 
84
 
85
  const filteredData = useMemo(() => {
86
+ if (!selectedProviders.length && !selectedModels.length) return data;
87
 
88
  return data
89
  .filter((p) => !selectedProviders.length || selectedProviders.includes(p.provider))
90
  .map((p) => ({
91
  ...p,
92
  models: p.models.filter((m) => {
93
+ if (!selectedModels.length) return selectedProviders.includes(p.provider);
94
+ if (!selectedModels.length) return !selectedProviders.length || selectedProviders.includes(p.provider);
95
  return selectedModels.includes(m.name);
96
  }),
97
  }))
98
  .filter((p) => p.models.length > 0);
99
+ }, [data, selectedProviders, selectedModels]);
100
 
101
+ const benchmarkedModels = useMemo(() => {
102
+ return flattenDataFromBenchmarks();
103
+ }, []);
104
 
105
 
106
 
107
+ const filteredBenchmarkedModels = useMemo(() => {
108
+ return benchmarkedModels.filter((model) => {
109
+ const providerMatch =
110
+ selectedBenchmarkProviders.length === 0 || selectedBenchmarkProviders.includes(model.provider);
111
+ const modelMatch =
112
+ selectedBenchmarkModels.length === 0 || selectedBenchmarkModels.includes(model.name);
113
 
114
+ // When not linking, allow filtering by either
115
+ if (selectedBenchmarkProviders.length > 0 && selectedBenchmarkModels.length > 0) {
116
+ return providerMatch || modelMatch;
117
+ }
118
 
119
+ return providerMatch && modelMatch; // this handles the case where one or both are empty
120
+ });
121
+ }, [
122
+ benchmarkedModels,
123
+ selectedBenchmarkProviders,
124
+ selectedBenchmarkModels,
125
 
126
+ ]);
 
 
 
 
 
 
 
127
 
128
 
129
  const sortedBenchmarkedModels = useMemo(() => {
 
150
  });
151
  }, [filteredBenchmarkedModels, benchmarkSortConfig]);
152
 
153
+ const pricingProviders = useMemo(() => {
154
+ const grouped: Record<string, FlattenedModel[]> = {};
155
+
156
+ flattenDataFromPricing(data).forEach((model) => {
157
+ const key = model.provider;
158
+ if (!grouped[key]) grouped[key] = [];
159
+ grouped[key].push(model);
160
+ });
161
+
162
+ return Object.entries(grouped).map(([provider, models]) => ({
163
+ provider,
164
+ uri: models[0]?.uri ?? "#",
165
+ models: models.map(({ name, inputPrice, outputPrice }) => ({
166
+ name,
167
+ inputPrice,
168
+ outputPrice,
169
+ })),
170
+ }));
171
+ }, [data]);
172
+
173
 
174
  const benchmarkProviders = useMemo(() => {
175
+ const grouped: Record<string, FlattenedModel[]> = {};
176
+
177
+ benchmarkedModels.forEach((model) => {
178
+ const key = model.provider;
179
+ if (!grouped[key]) grouped[key] = [];
180
+ grouped[key].push(model);
181
+ });
182
+
183
+ return Object.entries(grouped).map(([provider, models]) => ({
184
+ provider,
185
+ uri: models[0]?.uri ?? "#",
186
+ models: models.map(({ name, inputPrice, outputPrice }) => ({
187
+ name,
188
+ inputPrice,
189
+ outputPrice,
190
+ })),
191
+ }));
192
+ }, [benchmarkedModels]);
193
+
194
+
195
 
 
 
 
 
 
 
 
 
 
196
 
197
 
198
 
 
281
  </div>
282
  </div>
283
 
 
 
 
 
 
 
284
  {/* Pricing Table */}
285
  <h2 className="text-lg font-semibold mb-2">Pricing Table</h2>
286
+ <PricingTable
287
  data={sortedFlattenedData}
288
+ providers={pricingProviders}
289
  selectedProviders={selectedProviders}
290
  selectedModels={selectedModels}
291
  onProviderChange={setSelectedProviders}
 
296
  tokenCalculation={tokenCalculation}
297
  requestSort={requestSort}
298
  sortConfig={sortConfig}
299
+ />
 
300
 
301
 
302
  {/* Benchmark Table */}
 
311
  }
312
  />
313
 
 
 
 
 
314
  <h2 className="text-lg font-semibold mt-12 mb-2">Benchmark Table</h2>
315
  <BenchmarkTable
316
  data={sortedBenchmarkedModels}
 
328
  selectedModels={selectedBenchmarkModels}
329
  onProviderChange={setSelectedBenchmarkProviders}
330
  onModelChange={setSelectedBenchmarkModels}
 
 
331
  />
332
 
333
 
src/components/BenchmarkTable.tsx CHANGED
@@ -8,7 +8,6 @@ import {
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 {
@@ -24,10 +23,9 @@ interface BenchmarkTableProps {
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,
@@ -38,8 +36,7 @@ export const BenchmarkTable: React.FC<BenchmarkTableProps> = ({
38
  selectedModels,
39
  onProviderChange,
40
  onModelChange,
41
- linkProviderModel,
42
- onLinkToggle,
43
  }) => {
44
  const benchmarkMetrics = React.useMemo(() => {
45
  if (!comparisonMetrics || comparisonMetrics.length === 0) return [];
@@ -67,12 +64,14 @@ export const BenchmarkTable: React.FC<BenchmarkTableProps> = ({
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
  <>
@@ -93,16 +92,7 @@ export const BenchmarkTable: React.FC<BenchmarkTableProps> = ({
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>
 
8
  TableCell,
9
  } from "@/components/ui/table";
10
  import { MultiSelect } from "@/components/ui/multi-select";
 
11
  import { Provider, FlattenedModel } from "@/App";
12
 
13
  interface BenchmarkTableProps {
 
23
  selectedModels: string[];
24
  onProviderChange: (values: string[]) => void;
25
  onModelChange: (values: string[]) => void;
 
 
26
  }
27
 
28
+
29
  export const BenchmarkTable: React.FC<BenchmarkTableProps> = ({
30
  data,
31
  comparisonMetrics,
 
36
  selectedModels,
37
  onProviderChange,
38
  onModelChange,
39
+
 
40
  }) => {
41
  const benchmarkMetrics = React.useMemo(() => {
42
  if (!comparisonMetrics || comparisonMetrics.length === 0) return [];
 
64
  }))
65
  );
66
 
67
+ const filtered = flat.filter((m) =>
68
+ !selectedProviders.length || selectedProviders.includes(m.provider)
69
+ );
70
+
71
 
72
  return Array.from(new Map(filtered.map((m) => [m.value, m])).values());
73
+ }, [allProviders, selectedProviders]);
74
+
75
 
76
  return (
77
  <>
 
92
  onValueChange={onModelChange}
93
  />
94
  </div>
95
+
 
 
 
 
 
 
 
 
 
96
  </div>
97
 
98
  <Table>
src/components/PricingTable.tsx CHANGED
@@ -26,7 +26,7 @@ interface PricingTableProps {
26
  key: keyof FlattenedModel;
27
  direction: string;
28
  } | null;
29
- linkProviderModel: boolean;
30
  }
31
 
32
  export const PricingTable: React.FC<PricingTableProps> = ({
@@ -42,7 +42,7 @@ export const PricingTable: React.FC<PricingTableProps> = ({
42
  tokenCalculation,
43
  requestSort,
44
  sortConfig,
45
- linkProviderModel,
46
  }) => {
47
  const calculatePrice = (price: number, tokens: number): number => {
48
  let multiplier = 1;
@@ -66,9 +66,10 @@ export const PricingTable: React.FC<PricingTableProps> = ({
66
  }))
67
  );
68
 
69
- const filtered = linkProviderModel
70
- ? flatModels.filter((m) => selectedProviders.includes(m.provider))
71
- : flatModels;
 
72
 
73
  // Remove duplicates
74
  return Array.from(new Map(filtered.map((m) => [m.value, m])).values());
 
26
  key: keyof FlattenedModel;
27
  direction: string;
28
  } | null;
29
+
30
  }
31
 
32
  export const PricingTable: React.FC<PricingTableProps> = ({
 
42
  tokenCalculation,
43
  requestSort,
44
  sortConfig,
45
+
46
  }) => {
47
  const calculatePrice = (price: number, tokens: number): number => {
48
  let multiplier = 1;
 
66
  }))
67
  );
68
 
69
+ const filtered = flatModels.filter((m) =>
70
+ !selectedProviders.length || selectedProviders.includes(m.provider)
71
+ );
72
+
73
 
74
  // Remove duplicates
75
  return Array.from(new Map(filtered.map((m) => [m.value, m])).values());