Commit 
							
							·
						
						5403286
	
1
								Parent(s):
							
							d4f1866
								
- src/App.tsx +129 -133
 
    	
        src/App.tsx
    CHANGED
    
    | 
         @@ -43,6 +43,7 @@ const App: React.FC = () => { 
     | 
|
| 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;
         
     | 
| 
         @@ -54,12 +55,10 @@ const App: React.FC = () => { 
     | 
|
| 54 | 
         
             
                direction: "ascending" | "descending";
         
     | 
| 55 | 
         
             
              } | null>(null);
         
     | 
| 56 | 
         | 
| 57 | 
         
            -
             
     | 
| 58 | 
         
             
              useEffect(() => {
         
     | 
| 59 | 
         
             
                setData(mockData);
         
     | 
| 60 | 
         
             
              }, []);
         
     | 
| 61 | 
         | 
| 62 | 
         
            -
             
     | 
| 63 | 
         
             
              const flattenDataFromPricing = (data: Provider[]): FlattenedModel[] =>
         
     | 
| 64 | 
         
             
                data.flatMap((provider) =>
         
     | 
| 65 | 
         
             
                  provider.models.map((model) => ({
         
     | 
| 
         @@ -73,15 +72,13 @@ const App: React.FC = () => { 
     | 
|
| 73 | 
         
             
              const flattenDataFromBenchmarks = (): FlattenedModel[] =>
         
     | 
| 74 | 
         
             
                benchmarkData.map((b) => ({
         
     | 
| 75 | 
         
             
                  provider: b.provider ?? "Unknown",
         
     | 
| 76 | 
         
            -
                  uri: b.source, 
     | 
| 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 | 
         | 
| 
         @@ -91,49 +88,33 @@ const App: React.FC = () => { 
     | 
|
| 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 | 
         
            -
             
     | 
| 108 | 
         
            -
             
     | 
| 109 | 
         
            -
             
     | 
| 110 | 
         
            -
                  selectedBenchmarkProviders.length === 0 || selectedBenchmarkProviders.includes(model.provider);
         
     | 
| 111 | 
         
            -
                const modelMatch =
         
     | 
| 112 | 
         
            -
                  selectedBenchmarkModels.length === 0 || selectedBenchmarkModels.includes(model.name);
         
     | 
| 113 | 
         
            -
             
     | 
| 114 | 
         
            -
                return providerMatch && modelMatch;
         
     | 
| 115 | 
         
            -
              });
         
     | 
| 116 | 
         
            -
            }, [
         
     | 
| 117 | 
         
            -
              benchmarkedModels,
         
     | 
| 118 | 
         
            -
              selectedBenchmarkProviders,
         
     | 
| 119 | 
         
            -
              selectedBenchmarkModels,
         
     | 
| 120 | 
         
            -
            ]);
         
     | 
| 121 | 
         
            -
             
     | 
| 122 | 
         | 
| 123 | 
         
             
              const sortedBenchmarkedModels = useMemo(() => {
         
     | 
| 124 | 
         
             
                if (!benchmarkSortConfig) return filteredBenchmarkedModels;
         
     | 
| 125 | 
         | 
| 126 | 
         
             
                return [...filteredBenchmarkedModels].sort((a, b) => {
         
     | 
| 127 | 
         
             
                  const key = benchmarkSortConfig.key;
         
     | 
| 128 | 
         
            -
             
     | 
| 129 | 
         
             
                  const isTopLevelKey = ["provider", "name", "inputPrice", "outputPrice"].includes(key);
         
     | 
| 130 | 
         
            -
             
     | 
| 131 | 
         
            -
                  const  
     | 
| 132 | 
         
            -
                    ? (a as any)[key]
         
     | 
| 133 | 
         
            -
                    : a.benchmark?.[key] ?? -Infinity;
         
     | 
| 134 | 
         
            -
                  const bVal = isTopLevelKey
         
     | 
| 135 | 
         
            -
                    ? (b as any)[key]
         
     | 
| 136 | 
         
            -
                    : b.benchmark?.[key] ?? -Infinity;
         
     | 
| 137 | 
         | 
| 138 | 
         
             
                  if (typeof aVal === "string" && typeof bVal === "string") {
         
     | 
| 139 | 
         
             
                    return benchmarkSortConfig.direction === "ascending"
         
     | 
| 
         @@ -147,7 +128,6 @@ const filteredBenchmarkedModels = useMemo(() => { 
     | 
|
| 147 | 
         
             
                });
         
     | 
| 148 | 
         
             
              }, [filteredBenchmarkedModels, benchmarkSortConfig]);
         
     | 
| 149 | 
         | 
| 150 | 
         
            -
             
     | 
| 151 | 
         
             
              const pricingProviders = useMemo(() => {
         
     | 
| 152 | 
         
             
                const grouped: Record<string, FlattenedModel[]> = {};
         
     | 
| 153 | 
         | 
| 
         @@ -168,7 +148,6 @@ const filteredBenchmarkedModels = useMemo(() => { 
     | 
|
| 168 | 
         
             
                }));
         
     | 
| 169 | 
         
             
              }, [data]);
         
     | 
| 170 | 
         | 
| 171 | 
         
            -
             
     | 
| 172 | 
         
             
              const benchmarkProviders = useMemo(() => {
         
     | 
| 173 | 
         
             
                const grouped: Record<string, FlattenedModel[]> = {};
         
     | 
| 174 | 
         | 
| 
         @@ -189,11 +168,6 @@ const filteredBenchmarkedModels = useMemo(() => { 
     | 
|
| 189 | 
         
             
                }));
         
     | 
| 190 | 
         
             
              }, [benchmarkedModels]);
         
     | 
| 191 | 
         | 
| 192 | 
         
            -
             
     | 
| 193 | 
         
            -
             
     | 
| 194 | 
         
            -
             
     | 
| 195 | 
         
            -
             
     | 
| 196 | 
         
            -
             
     | 
| 197 | 
         
             
              const sortedFlattenedData = useMemo(() => {
         
     | 
| 198 | 
         
             
                const flattened = flattenDataFromPricing(filteredData);
         
     | 
| 199 | 
         
             
                if (!sortConfig) return flattened;
         
     | 
| 
         @@ -222,15 +196,12 @@ const filteredBenchmarkedModels = useMemo(() => { 
     | 
|
| 222 | 
         
             
                );
         
     | 
| 223 | 
         
             
              };
         
     | 
| 224 | 
         | 
| 225 | 
         
            -
             
     | 
| 226 | 
         
            -
             
     | 
| 227 | 
         
             
              return (
         
     | 
| 228 | 
         
             
                <Card className="w-full max-w-6xl mx-auto">
         
     | 
| 229 | 
         
             
                  <CardHeader>
         
     | 
| 230 | 
         
            -
                    <CardTitle>LLM Pricing  
     | 
| 231 | 
         
             
                  </CardHeader>
         
     | 
| 232 | 
         
             
                  <CardContent>
         
     | 
| 233 | 
         
            -
                    {/* Source Link */}
         
     | 
| 234 | 
         
             
                    <p className="italic text-sm text-muted-foreground mb-4">
         
     | 
| 235 | 
         
             
                      <a
         
     | 
| 236 | 
         
             
                        href="https://huggingface.co/spaces/philschmid/llm-pricing"
         
     | 
| 
         @@ -240,97 +211,122 @@ const filteredBenchmarkedModels = useMemo(() => { 
     | 
|
| 240 | 
         
             
                      </a>
         
     | 
| 241 | 
         
             
                    </p>
         
     | 
| 242 | 
         | 
| 243 | 
         
            -
                    {/*  
     | 
| 244 | 
         
            -
                    < 
     | 
| 245 | 
         
            -
             
     | 
| 246 | 
         
            -
             
     | 
| 247 | 
         
            -
             
     | 
| 248 | 
         
            -
             
     | 
| 249 | 
         
            -
             
     | 
| 250 | 
         
            -
             
     | 
| 251 | 
         
            -
             
     | 
| 252 | 
         
            -
             
     | 
| 253 | 
         
            -
                         
     | 
| 254 | 
         
            -
                       
     | 
| 255 | 
         
            -
             
     | 
| 256 | 
         
            -
             
     | 
| 257 | 
         
            -
             
     | 
| 258 | 
         
            -
             
     | 
| 259 | 
         
            -
             
     | 
| 260 | 
         
            -
             
     | 
| 261 | 
         
            -
             
     | 
| 262 | 
         
            -
             
     | 
| 263 | 
         
            -
             
     | 
| 264 | 
         
            -
             
     | 
| 265 | 
         
            -
                        <Input type="number" value={outputTokens} min={1} onChange={(e) => setOutputTokens(Number(e.target.value))} />
         
     | 
| 266 | 
         
            -
                      </div>
         
     | 
| 267 | 
         
            -
                      <div className="flex-1">
         
     | 
| 268 | 
         
            -
                        <label className="block text-sm font-medium">Token Calculation</label>
         
     | 
| 269 | 
         
            -
                        <select
         
     | 
| 270 | 
         
            -
                          value={tokenCalculation}
         
     | 
| 271 | 
         
            -
                          onChange={(e) => setTokenCalculation(e.target.value)}
         
     | 
| 272 | 
         
            -
                          className="mt-1 block w-full pl-3 pr-10 py-2 text-base border rounded-md"
         
     | 
| 273 | 
         
            -
                        >
         
     | 
| 274 | 
         
            -
                          <option value="billion">Billion Tokens</option>
         
     | 
| 275 | 
         
            -
                          <option value="million">Million Tokens</option>
         
     | 
| 276 | 
         
            -
                          <option value="thousand">Thousand Tokens</option>
         
     | 
| 277 | 
         
            -
                          <option value="unit">Unit Tokens</option>
         
     | 
| 278 | 
         
            -
                        </select>
         
     | 
| 279 | 
         
            -
                      </div>
         
     | 
| 280 | 
         
             
                    </div>
         
     | 
| 281 | 
         | 
| 282 | 
         
            -
                    { 
     | 
| 283 | 
         
            -
             
     | 
| 284 | 
         
            -
             
     | 
| 285 | 
         
            -
             
     | 
| 286 | 
         
            -
             
     | 
| 287 | 
         
            -
             
     | 
| 288 | 
         
            -
             
     | 
| 289 | 
         
            -
             
     | 
| 290 | 
         
            -
             
     | 
| 291 | 
         
            -
             
     | 
| 292 | 
         
            -
             
     | 
| 293 | 
         
            -
             
     | 
| 294 | 
         
            -
             
     | 
| 295 | 
         
            -
             
     | 
| 296 | 
         
            -
             
     | 
| 297 | 
         
            -
             
     | 
| 298 | 
         
            -
             
     | 
| 299 | 
         
            -
             
     | 
| 300 | 
         
            -
             
     | 
| 301 | 
         
            -
             
     | 
| 302 | 
         
            -
             
     | 
| 303 | 
         
            -
             
     | 
| 304 | 
         
            -
             
     | 
| 305 | 
         
            -
             
     | 
| 306 | 
         
            -
             
     | 
| 307 | 
         
            -
             
     | 
| 308 | 
         
            -
             
     | 
| 309 | 
         
            -
             
     | 
| 310 | 
         
            -
             
     | 
| 311 | 
         
            -
             
     | 
| 312 | 
         
            -
             
     | 
| 313 | 
         
            -
             
     | 
| 314 | 
         
            -
             
     | 
| 315 | 
         
            -
             
     | 
| 316 | 
         
            -
             
     | 
| 317 | 
         
            -
             
     | 
| 318 | 
         
            -
             
     | 
| 319 | 
         
            -
                         
     | 
| 320 | 
         
            -
             
     | 
| 321 | 
         
            -
             
     | 
| 322 | 
         
            -
             
     | 
| 323 | 
         
            -
             
     | 
| 324 | 
         
            -
             
     | 
| 325 | 
         
            -
             
     | 
| 326 | 
         
            -
             
     | 
| 327 | 
         
            -
             
     | 
| 328 | 
         
            -
             
     | 
| 329 | 
         
            -
             
     | 
| 330 | 
         
            -
             
     | 
| 331 | 
         
            -
             
     | 
| 332 | 
         
            -
             
     | 
| 333 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 334 | 
         
             
                  </CardContent>
         
     | 
| 335 | 
         
             
                </Card>
         
     | 
| 336 | 
         
             
              );
         
     | 
| 
         | 
|
| 43 | 
         
             
              const [benchmarkComparisonMetrics, setBenchmarkComparisonMetrics] = useState<string[]>([]);
         
     | 
| 44 | 
         
             
              const [selectedBenchmarkProviders, setSelectedBenchmarkProviders] = useState<string[]>([]);
         
     | 
| 45 | 
         
             
              const [selectedBenchmarkModels, setSelectedBenchmarkModels] = useState<string[]>([]);
         
     | 
| 46 | 
         
            +
              const [viewMode, setViewMode] = useState<"pricing" | "benchmark">("pricing");
         
     | 
| 47 | 
         | 
| 48 | 
         
             
              const [sortConfig, setSortConfig] = useState<{
         
     | 
| 49 | 
         
             
                key: keyof FlattenedModel;
         
     | 
| 
         | 
|
| 55 | 
         
             
                direction: "ascending" | "descending";
         
     | 
| 56 | 
         
             
              } | null>(null);
         
     | 
| 57 | 
         | 
| 
         | 
|
| 58 | 
         
             
              useEffect(() => {
         
     | 
| 59 | 
         
             
                setData(mockData);
         
     | 
| 60 | 
         
             
              }, []);
         
     | 
| 61 | 
         | 
| 
         | 
|
| 62 | 
         
             
              const flattenDataFromPricing = (data: Provider[]): FlattenedModel[] =>
         
     | 
| 63 | 
         
             
                data.flatMap((provider) =>
         
     | 
| 64 | 
         
             
                  provider.models.map((model) => ({
         
     | 
| 
         | 
|
| 72 | 
         
             
              const flattenDataFromBenchmarks = (): FlattenedModel[] =>
         
     | 
| 73 | 
         
             
                benchmarkData.map((b) => ({
         
     | 
| 74 | 
         
             
                  provider: b.provider ?? "Unknown",
         
     | 
| 75 | 
         
            +
                  uri: b.source,
         
     | 
| 76 | 
         
             
                  name: b.model,
         
     | 
| 77 | 
         
             
                  inputPrice: b.inputPrice,
         
     | 
| 78 | 
         
             
                  outputPrice: b.outputPrice,
         
     | 
| 79 | 
         
             
                  benchmark: b.benchmark ?? {},
         
     | 
| 80 | 
         
             
                }));
         
     | 
| 81 | 
         | 
| 
         | 
|
| 
         | 
|
| 82 | 
         
             
              const filteredData = useMemo(() => {
         
     | 
| 83 | 
         
             
                if (!selectedProviders.length && !selectedModels.length) return data;
         
     | 
| 84 | 
         | 
| 
         | 
|
| 88 | 
         
             
                    ...p,
         
     | 
| 89 | 
         
             
                    models: p.models.filter((m) => {
         
     | 
| 90 | 
         
             
                      if (!selectedModels.length) return selectedProviders.includes(p.provider);
         
     | 
| 
         | 
|
| 91 | 
         
             
                      return selectedModels.includes(m.name);
         
     | 
| 92 | 
         
             
                    }),
         
     | 
| 93 | 
         
             
                  }))
         
     | 
| 94 | 
         
             
                  .filter((p) => p.models.length > 0);
         
     | 
| 95 | 
         
             
              }, [data, selectedProviders, selectedModels]);
         
     | 
| 96 | 
         | 
| 97 | 
         
            +
              const benchmarkedModels = useMemo(() => flattenDataFromBenchmarks(), []);
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 98 | 
         | 
| 99 | 
         
            +
              const filteredBenchmarkedModels = useMemo(() => {
         
     | 
| 100 | 
         
            +
                return benchmarkedModels.filter((model) => {
         
     | 
| 101 | 
         
            +
                  const providerMatch =
         
     | 
| 102 | 
         
            +
                    selectedBenchmarkProviders.length === 0 || selectedBenchmarkProviders.includes(model.provider);
         
     | 
| 103 | 
         
            +
                  const modelMatch =
         
     | 
| 104 | 
         
            +
                    selectedBenchmarkModels.length === 0 || selectedBenchmarkModels.includes(model.name);
         
     | 
| 105 | 
         | 
| 106 | 
         
            +
                  return providerMatch && modelMatch;
         
     | 
| 107 | 
         
            +
                });
         
     | 
| 108 | 
         
            +
              }, [benchmarkedModels, selectedBenchmarkProviders, selectedBenchmarkModels]);
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 109 | 
         | 
| 110 | 
         
             
              const sortedBenchmarkedModels = useMemo(() => {
         
     | 
| 111 | 
         
             
                if (!benchmarkSortConfig) return filteredBenchmarkedModels;
         
     | 
| 112 | 
         | 
| 113 | 
         
             
                return [...filteredBenchmarkedModels].sort((a, b) => {
         
     | 
| 114 | 
         
             
                  const key = benchmarkSortConfig.key;
         
     | 
| 
         | 
|
| 115 | 
         
             
                  const isTopLevelKey = ["provider", "name", "inputPrice", "outputPrice"].includes(key);
         
     | 
| 116 | 
         
            +
                  const aVal = isTopLevelKey ? (a as any)[key] : a.benchmark?.[key] ?? -Infinity;
         
     | 
| 117 | 
         
            +
                  const bVal = isTopLevelKey ? (b as any)[key] : b.benchmark?.[key] ?? -Infinity;
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 118 | 
         | 
| 119 | 
         
             
                  if (typeof aVal === "string" && typeof bVal === "string") {
         
     | 
| 120 | 
         
             
                    return benchmarkSortConfig.direction === "ascending"
         
     | 
| 
         | 
|
| 128 | 
         
             
                });
         
     | 
| 129 | 
         
             
              }, [filteredBenchmarkedModels, benchmarkSortConfig]);
         
     | 
| 130 | 
         | 
| 
         | 
|
| 131 | 
         
             
              const pricingProviders = useMemo(() => {
         
     | 
| 132 | 
         
             
                const grouped: Record<string, FlattenedModel[]> = {};
         
     | 
| 133 | 
         | 
| 
         | 
|
| 148 | 
         
             
                }));
         
     | 
| 149 | 
         
             
              }, [data]);
         
     | 
| 150 | 
         | 
| 
         | 
|
| 151 | 
         
             
              const benchmarkProviders = useMemo(() => {
         
     | 
| 152 | 
         
             
                const grouped: Record<string, FlattenedModel[]> = {};
         
     | 
| 153 | 
         | 
| 
         | 
|
| 168 | 
         
             
                }));
         
     | 
| 169 | 
         
             
              }, [benchmarkedModels]);
         
     | 
| 170 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 171 | 
         
             
              const sortedFlattenedData = useMemo(() => {
         
     | 
| 172 | 
         
             
                const flattened = flattenDataFromPricing(filteredData);
         
     | 
| 173 | 
         
             
                if (!sortConfig) return flattened;
         
     | 
| 
         | 
|
| 196 | 
         
             
                );
         
     | 
| 197 | 
         
             
              };
         
     | 
| 198 | 
         | 
| 
         | 
|
| 
         | 
|
| 199 | 
         
             
              return (
         
     | 
| 200 | 
         
             
                <Card className="w-full max-w-6xl mx-auto">
         
     | 
| 201 | 
         
             
                  <CardHeader>
         
     | 
| 202 | 
         
            +
                    <CardTitle>LLM Pricing & Benchmark Comparison Tool</CardTitle>
         
     | 
| 203 | 
         
             
                  </CardHeader>
         
     | 
| 204 | 
         
             
                  <CardContent>
         
     | 
| 
         | 
|
| 205 | 
         
             
                    <p className="italic text-sm text-muted-foreground mb-4">
         
     | 
| 206 | 
         
             
                      <a
         
     | 
| 207 | 
         
             
                        href="https://huggingface.co/spaces/philschmid/llm-pricing"
         
     | 
| 
         | 
|
| 211 | 
         
             
                      </a>
         
     | 
| 212 | 
         
             
                    </p>
         
     | 
| 213 | 
         | 
| 214 | 
         
            +
                    {/* View Toggle */}
         
     | 
| 215 | 
         
            +
                    <div className="flex justify-center gap-6 mb-6">
         
     | 
| 216 | 
         
            +
                      <label className="flex items-center space-x-2">
         
     | 
| 217 | 
         
            +
                        <input
         
     | 
| 218 | 
         
            +
                          type="radio"
         
     | 
| 219 | 
         
            +
                          name="view"
         
     | 
| 220 | 
         
            +
                          value="pricing"
         
     | 
| 221 | 
         
            +
                          checked={viewMode === "pricing"}
         
     | 
| 222 | 
         
            +
                          onChange={() => setViewMode("pricing")}
         
     | 
| 223 | 
         
            +
                        />
         
     | 
| 224 | 
         
            +
                        <span>Pricing</span>
         
     | 
| 225 | 
         
            +
                      </label>
         
     | 
| 226 | 
         
            +
                      <label className="flex items-center space-x-2">
         
     | 
| 227 | 
         
            +
                        <input
         
     | 
| 228 | 
         
            +
                          type="radio"
         
     | 
| 229 | 
         
            +
                          name="view"
         
     | 
| 230 | 
         
            +
                          value="benchmark"
         
     | 
| 231 | 
         
            +
                          checked={viewMode === "benchmark"}
         
     | 
| 232 | 
         
            +
                          onChange={() => setViewMode("benchmark")}
         
     | 
| 233 | 
         
            +
                        />
         
     | 
| 234 | 
         
            +
                        <span>Benchmark</span>
         
     | 
| 235 | 
         
            +
                      </label>
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 236 | 
         
             
                    </div>
         
     | 
| 237 | 
         | 
| 238 | 
         
            +
                    {viewMode === "pricing" && (
         
     | 
| 239 | 
         
            +
                      <>
         
     | 
| 240 | 
         
            +
                        <h3 className="text-lg font-semibold mb-2">Select Comparison Models</h3>
         
     | 
| 241 | 
         
            +
                        <ComparisonSelector
         
     | 
| 242 | 
         
            +
                          data={data}
         
     | 
| 243 | 
         
            +
                          expanded={expandedProviders}
         
     | 
| 244 | 
         
            +
                          comparisonModels={comparisonModels}
         
     | 
| 245 | 
         
            +
                          onToggleExpand={toggleProviderExpansion}
         
     | 
| 246 | 
         
            +
                          onChangeModel={(modelId, checked) =>
         
     | 
| 247 | 
         
            +
                            setComparisonModels((prev) =>
         
     | 
| 248 | 
         
            +
                              checked ? [...prev, modelId] : prev.filter((m) => m !== modelId)
         
     | 
| 249 | 
         
            +
                            )
         
     | 
| 250 | 
         
            +
                          }
         
     | 
| 251 | 
         
            +
                        />
         
     | 
| 252 | 
         
            +
             
     | 
| 253 | 
         
            +
                        <div className="flex gap-4 mt-6 mb-4">
         
     | 
| 254 | 
         
            +
                          <div className="flex-1">
         
     | 
| 255 | 
         
            +
                            <label className="block text-sm font-medium">Input Tokens ({tokenCalculation})</label>
         
     | 
| 256 | 
         
            +
                            <Input type="number" value={inputTokens} min={1} onChange={(e) => setInputTokens(Number(e.target.value))} />
         
     | 
| 257 | 
         
            +
                          </div>
         
     | 
| 258 | 
         
            +
                          <div className="flex-1">
         
     | 
| 259 | 
         
            +
                            <label className="block text-sm font-medium">Output Tokens ({tokenCalculation})</label>
         
     | 
| 260 | 
         
            +
                            <Input type="number" value={outputTokens} min={1} onChange={(e) => setOutputTokens(Number(e.target.value))} />
         
     | 
| 261 | 
         
            +
                          </div>
         
     | 
| 262 | 
         
            +
                          <div className="flex-1">
         
     | 
| 263 | 
         
            +
                            <label className="block text-sm font-medium">Token Calculation</label>
         
     | 
| 264 | 
         
            +
                            <select
         
     | 
| 265 | 
         
            +
                              value={tokenCalculation}
         
     | 
| 266 | 
         
            +
                              onChange={(e) => setTokenCalculation(e.target.value)}
         
     | 
| 267 | 
         
            +
                              className="mt-1 block w-full pl-3 pr-10 py-2 text-base border rounded-md"
         
     | 
| 268 | 
         
            +
                            >
         
     | 
| 269 | 
         
            +
                              <option value="billion">Billion Tokens</option>
         
     | 
| 270 | 
         
            +
                              <option value="million">Million Tokens</option>
         
     | 
| 271 | 
         
            +
                              <option value="thousand">Thousand Tokens</option>
         
     | 
| 272 | 
         
            +
                              <option value="unit">Unit Tokens</option>
         
     | 
| 273 | 
         
            +
                            </select>
         
     | 
| 274 | 
         
            +
                          </div>
         
     | 
| 275 | 
         
            +
                        </div>
         
     | 
| 276 | 
         
            +
             
     | 
| 277 | 
         
            +
                        <h2 className="text-lg font-semibold mb-2">Pricing Table</h2>
         
     | 
| 278 | 
         
            +
                        <PricingTable
         
     | 
| 279 | 
         
            +
                          data={sortedFlattenedData}
         
     | 
| 280 | 
         
            +
                          providers={pricingProviders}
         
     | 
| 281 | 
         
            +
                          selectedProviders={selectedProviders}
         
     | 
| 282 | 
         
            +
                          selectedModels={selectedModels}
         
     | 
| 283 | 
         
            +
                          onProviderChange={setSelectedProviders}
         
     | 
| 284 | 
         
            +
                          onModelChange={setSelectedModels}
         
     | 
| 285 | 
         
            +
                          comparisonModels={comparisonModels}
         
     | 
| 286 | 
         
            +
                          inputTokens={inputTokens}
         
     | 
| 287 | 
         
            +
                          outputTokens={outputTokens}
         
     | 
| 288 | 
         
            +
                          tokenCalculation={tokenCalculation}
         
     | 
| 289 | 
         
            +
                          requestSort={requestSort}
         
     | 
| 290 | 
         
            +
                          sortConfig={sortConfig}
         
     | 
| 291 | 
         
            +
                        />
         
     | 
| 292 | 
         
            +
                      </>
         
     | 
| 293 | 
         
            +
                    )}
         
     | 
| 294 | 
         
            +
             
     | 
| 295 | 
         
            +
                    {viewMode === "benchmark" && (
         
     | 
| 296 | 
         
            +
                      <>
         
     | 
| 297 | 
         
            +
                        <h3 className="text-lg font-semibold mb-2">Select Benchmark Metrics to Compare</h3>
         
     | 
| 298 | 
         
            +
                        <BenchmarkComparisonSelector
         
     | 
| 299 | 
         
            +
                          allMetrics={benchmarkMetricOrder.filter(
         
     | 
| 300 | 
         
            +
                            (metric) => benchmarkedModels.some((m) => m.benchmark?.[metric] !== undefined)
         
     | 
| 301 | 
         
            +
                          )}
         
     | 
| 302 | 
         
            +
                          selected={benchmarkComparisonMetrics}
         
     | 
| 303 | 
         
            +
                          onChange={(metric, checked) =>
         
     | 
| 304 | 
         
            +
                            setBenchmarkComparisonMetrics((prev) =>
         
     | 
| 305 | 
         
            +
                              checked ? [...prev, metric] : prev.filter((m) => m !== metric)
         
     | 
| 306 | 
         
            +
                            )
         
     | 
| 307 | 
         
            +
                          }
         
     | 
| 308 | 
         
            +
                        />
         
     | 
| 309 | 
         
            +
             
     | 
| 310 | 
         
            +
                        <h2 className="text-lg font-semibold mb-2">Benchmark Table</h2>
         
     | 
| 311 | 
         
            +
                        <BenchmarkTable
         
     | 
| 312 | 
         
            +
                          data={sortedBenchmarkedModels}
         
     | 
| 313 | 
         
            +
                          comparisonMetrics={benchmarkComparisonMetrics}
         
     | 
| 314 | 
         
            +
                          requestSort={(key) => {
         
     | 
| 315 | 
         
            +
                            setBenchmarkSortConfig((prev) =>
         
     | 
| 316 | 
         
            +
                              prev?.key === key
         
     | 
| 317 | 
         
            +
                                ? { key, direction: prev.direction === "ascending" ? "descending" : "ascending" }
         
     | 
| 318 | 
         
            +
                                : { key, direction: "descending" }
         
     | 
| 319 | 
         
            +
                            );
         
     | 
| 320 | 
         
            +
                          }}
         
     | 
| 321 | 
         
            +
                          sortConfig={benchmarkSortConfig}
         
     | 
| 322 | 
         
            +
                          allProviders={benchmarkProviders}
         
     | 
| 323 | 
         
            +
                          selectedProviders={selectedBenchmarkProviders}
         
     | 
| 324 | 
         
            +
                          selectedModels={selectedBenchmarkModels}
         
     | 
| 325 | 
         
            +
                          onProviderChange={setSelectedBenchmarkProviders}
         
     | 
| 326 | 
         
            +
                          onModelChange={setSelectedBenchmarkModels}
         
     | 
| 327 | 
         
            +
                        />
         
     | 
| 328 | 
         
            +
                      </>
         
     | 
| 329 | 
         
            +
                    )}
         
     | 
| 330 | 
         
             
                  </CardContent>
         
     | 
| 331 | 
         
             
                </Card>
         
     | 
| 332 | 
         
             
              );
         
     |