diff --git a/ui/litellm-dashboard/eslint-suppressions.json b/ui/litellm-dashboard/eslint-suppressions.json index 09d0032e6c9..d486c9e4852 100644 --- a/ui/litellm-dashboard/eslint-suppressions.json +++ b/ui/litellm-dashboard/eslint-suppressions.json @@ -215,21 +215,11 @@ "count": 1 } }, - "src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "src/app/(dashboard)/cost-optimization/_components/PromptCompressionTab.tsx": { "no-restricted-imports": { "count": 1 } }, - "src/app/(dashboard)/cost-optimization/_components/UsageTab.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "src/app/(dashboard)/cost-tracking/_components/add_margin_form.tsx": { "local/filename-pascal-case": { "count": 1 diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.tsx index 3bab6afee57..11bd0cc109e 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.tsx @@ -1,9 +1,10 @@ "use client"; import React from "react"; -import { PiggyBank } from "lucide-react"; -import { Alert, Tabs } from "antd"; +import { Info, PiggyBank } from "lucide-react"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { useVisitedTabs } from "@/hooks/useVisitedTabs"; import UsageTab from "./UsageTab"; import PromptCompressionTab from "./PromptCompressionTab"; import AutorouterTab from "./AutorouterTab"; @@ -18,29 +19,7 @@ interface CostOptimizationViewProps { const CostOptimizationView: React.FC = ({ accessToken, userId, userRole }) => { const activity = useDailyActivityRange(accessToken, userId, userRole); - - const items = [ - { - key: "usage", - label: "Usage", - children: , - }, - { - key: "compression", - label: "Prompt Compression", - children: , - }, - { - key: "autorouter", - label: "Autorouter", - children: , - }, - { - key: "caching", - label: "Prompt Caching", - children: , - }, - ]; + const { onTabChange, hasVisited } = useVisitedTabs("usage"); return (
@@ -54,26 +33,53 @@ const CostOptimizationView: React.FC = ({ accessToken

- +
+ +
+

This is an experimental dashboard

+

Have feedback? Join the discussion{" "} here - - } - /> +

+
+
- + + + + Usage + + + Prompt Compression + + + Autorouter + + + Prompt Caching + + + + + + + + + + + + + + + + ); }; diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/UsageTab.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/UsageTab.tsx index 6e2da4456d3..d68ec552156 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/UsageTab.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/UsageTab.tsx @@ -1,11 +1,12 @@ "use client"; import React, { useEffect, useMemo, useState } from "react"; -import { Collapse } from "antd"; +import { ChevronRight } from "lucide-react"; import { AreaChart, BarChart, DonutChart, DEFAULT_COLOR_CYCLE } from "@/components/shared/charts"; import AdvancedDatePicker from "@/components/shared/advanced_date_picker"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; import { getToolSpend, ToolSpendResponse } from "@/components/networking"; import { SpendMetrics } from "@/components/UsagePage/types"; import { formatNumberWithCommas } from "@/utils/dataUtils"; @@ -35,38 +36,35 @@ const cachingOf = (m: SpendMetrics): number => m.prompt_caching_savings_spend ?? const savedTokensOf = (m: SpendMetrics): number => m.compression_saved_tokens ?? 0; const MethodologyNote = () => ( - How savings are calculated, - children: ( -
-

- Savings are computed for each request when it is logged, using the provider's reported usage and the - model's pricing, then summed into a daily rollup. Totals below are read from that rollup over the - selected date range, so the numbers never require a scan of raw request logs. -

-

- Compression savings are the tokens Headroom removed before the call, priced at the model's input - rate: compression_saved_tokens * input_cost_per_token -

-

- Prompt caching savings are the tokens the provider served from cache (Anthropic{" "} - cache_read_input_tokens, or OpenAI-style prompt_tokens_details.cached_tokens), - priced at the discount between the normal input rate and the cache-read rate:{" "} - cache_read_input_tokens * max(input_cost_per_token - cache_read_input_token_cost, 0) -

-

- Total saved is the sum of both drivers. Models without a separate cache-read price in the pricing map - contribute zero caching savings rather than erroring. -

-
- ), - }, - ]} - /> + + + + How savings are calculated + + +
+

+ Savings are computed for each request when it is logged, using the provider's reported usage and the + model's pricing, then summed into a daily rollup. Totals below are read from that rollup over the + selected date range, so the numbers never require a scan of raw request logs. +

+

+ Compression savings are the tokens Headroom removed before the call, priced at the model's input rate:{" "} + compression_saved_tokens * input_cost_per_token +

+

+ Prompt caching savings are the tokens the provider served from cache (Anthropic{" "} + cache_read_input_tokens, or OpenAI-style prompt_tokens_details.cached_tokens), + priced at the discount between the normal input rate and the cache-read rate:{" "} + cache_read_input_tokens * max(input_cost_per_token - cache_read_input_token_cost, 0) +

+

+ Total saved is the sum of both drivers. Models without a separate cache-read price in the pricing map + contribute zero caching savings rather than erroring. +

+
+
+
); const SummaryCard = ({ label, value, hint }: { label: string; value: string; hint?: string }) => (