From 69aefb8a94a78c7a59d6aa7be2a84003da1db8eb Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Mon, 5 Jan 2026 19:45:29 +0530 Subject: [PATCH] v2 of report --- .../pricing_calculator/index.tsx | 158 ++++++-- .../pricing_calculator/model_entry_row.tsx | 107 ------ .../pricing_calculator/multi_cost_results.tsx | 345 ++++++++---------- .../pricing_calculator/multi_export_utils.ts | 37 +- .../pricing_calculator/types.ts | 3 + .../use_multi_cost_estimate.ts | 13 + 6 files changed, 326 insertions(+), 337 deletions(-) delete mode 100644 ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/model_entry_row.tsx diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/index.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/index.tsx index d0f50cbe875..17eb48b2eec 100644 --- a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/index.tsx +++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/index.tsx @@ -1,8 +1,7 @@ import React, { useState, useCallback } from "react"; -import { Button, Text } from "@tremor/react"; -import { PlusOutlined } from "@ant-design/icons"; +import { Table, Select, InputNumber, Button } from "antd"; +import { DeleteOutlined, PlusOutlined } from "@ant-design/icons"; import { PricingCalculatorProps, ModelEntry } from "./types"; -import ModelEntryRow from "./model_entry_row"; import MultiCostResults from "./multi_cost_results"; import { useMultiCostEstimate } from "./use_multi_cost_estimate"; @@ -53,38 +52,135 @@ const PricingCalculator: React.FC = ({ [removeEntry] ); - // Note: Fetching is triggered by handleEntryChange when model is selected - const multiModelResult = getMultiModelResult(entries); + const columns = [ + { + title: "Model", + dataIndex: "model", + key: "model", + width: "30%", + render: (_: string, record: ModelEntry) => ( + onChange(entry.id, "model", value)} - optionFilterProp="label" - filterOption={(input, option) => - String(option?.label ?? "").toLowerCase().includes(input.toLowerCase()) - } - options={models.map((model) => ({ - value: model, - label: model, - }))} - style={{ width: "100%" }} - size="small" - /> - -
- - onChange(entry.id, "input_tokens", value ?? 0)} - style={{ width: "100%" }} - size="small" - formatter={(value) => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",")} - /> -
-
- - onChange(entry.id, "output_tokens", value ?? 0)} - style={{ width: "100%" }} - size="small" - formatter={(value) => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",")} - /> -
-
- - onChange(entry.id, "num_requests_per_day", value ?? undefined)} - style={{ width: "100%" }} - size="small" - placeholder="Optional" - formatter={(value) => value ? `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : ""} - /> -
-
- - onChange(entry.id, "num_requests_per_month", value ?? undefined)} - style={{ width: "100%" }} - size="small" - placeholder="Optional" - formatter={(value) => value ? `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : ""} - /> -
- -
- -
- - ); -}; - -export default ModelEntryRow; - diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx index 3618dfc626c..754d061ead7 100644 --- a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx +++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { Text, Button } from "@tremor/react"; import { Card, Statistic, Row, Col, Divider, Spin, Table, Tag } from "antd"; -import { DollarOutlined, LoadingOutlined, DownOutlined, RightOutlined } from "@ant-design/icons"; +import { LoadingOutlined, DownOutlined, RightOutlined } from "@ant-design/icons"; import { CostEstimateResponse } from "../types"; import { formatNumberWithCommas } from "@/utils/dataUtils"; import { MultiModelResult } from "./types"; @@ -29,7 +29,7 @@ const SingleModelBreakdown: React.FC<{ loading: boolean; }> = ({ result, loading }) => { return ( -
+
{loading && (
} size="small" /> @@ -37,136 +37,82 @@ const SingleModelBreakdown: React.FC<{
)} - - - - } - /> - - - - - - - - - 0 ? "#faad14" : undefined, - }} - /> - - - +
+
+ Total/Request + {formatCost(result.cost_per_request)} +
+
+ Input Cost + {formatCost(result.input_cost_per_request)} +
+
+ Output Cost + {formatCost(result.output_cost_per_request)} +
+
+ Margin/Fee + 0 ? "text-amber-600" : ""}`}> + {formatCost(result.margin_cost_per_request)} + +
+
{result.daily_cost !== null && ( - - - - } - /> - - - - - - - - - 0 ? "#faad14" : undefined, - }} - /> - - - +
+
+ Daily Total ({formatRequests(result.num_requests_per_day)} req) + {formatCost(result.daily_cost)} +
+
+ Daily Input + {formatCost(result.daily_input_cost)} +
+
+ Daily Output + {formatCost(result.daily_output_cost)} +
+
+ Daily Margin + 0 ? "text-amber-600" : ""}`}> + {formatCost(result.daily_margin_cost)} + +
+
)} {result.monthly_cost !== null && ( - - - - } - /> - - - - - - - - - 0 ? "#faad14" : undefined, - }} - /> - - - +
+
+ Monthly Total ({formatRequests(result.num_requests_per_month)} req) + {formatCost(result.monthly_cost)} +
+
+ Monthly Input + {formatCost(result.monthly_input_cost)} +
+
+ Monthly Output + {formatCost(result.monthly_output_cost)} +
+
+ Monthly Margin + 0 ? "text-amber-600" : ""}`}> + {formatCost(result.monthly_margin_cost)} + +
+
)} {(result.input_cost_per_token || result.output_cost_per_token) && ( -
- Token Pricing: +
+ Token Pricing: {" "} {result.input_cost_per_token && ( - Input: ${formatNumberWithCommas(result.input_cost_per_token * 1_000_000, 2)}/1M + Input ${formatNumberWithCommas(result.input_cost_per_token * 1_000_000, 2)}/1M )} {result.input_cost_per_token && result.output_cost_per_token && " | "} {result.output_cost_per_token && ( - Output: ${formatNumberWithCommas(result.output_cost_per_token * 1_000_000, 2)}/1M + Output ${formatNumberWithCommas(result.output_cost_per_token * 1_000_000, 2)}/1M )}
)} @@ -184,7 +130,7 @@ const MultiCostResults: React.FC = ({ multiResult }) => { if (!hasAnyResult && !isAnyLoading) { return ( -
+
Select models above to see cost estimates @@ -194,7 +140,7 @@ const MultiCostResults: React.FC = ({ multiResult }) => { if (!hasAnyResult && isAnyLoading) { return ( -
+
} /> Calculating costs...
@@ -213,16 +159,18 @@ const MultiCostResults: React.FC = ({ multiResult }) => { }); }; + const hasMargin = multiResult.totals.margin_per_request > 0; + const summaryColumns = [ { title: "Model", dataIndex: "model", key: "model", render: (text: string, record: { id: string; provider?: string | null }) => ( -
- {text} +
+ {text} {record.provider && ( - + {record.provider} )} @@ -233,29 +181,44 @@ const MultiCostResults: React.FC = ({ multiResult }) => { title: "Per Request", dataIndex: "cost_per_request", key: "cost_per_request", - render: (value: number) => formatCost(value), + align: "right" as const, + render: (value: number) => {formatCost(value)}, + }, + { + title: "Margin", + dataIndex: "margin_cost_per_request", + key: "margin_cost_per_request", + align: "right" as const, + render: (value: number) => ( + 0 ? "text-amber-600" : "text-gray-400"}`}> + {formatCost(value)} + + ), }, { title: "Daily", dataIndex: "daily_cost", key: "daily_cost", - render: (value: number | null) => formatCost(value), + align: "right" as const, + render: (value: number | null) => {formatCost(value)}, }, { title: "Monthly", dataIndex: "monthly_cost", key: "monthly_cost", - render: (value: number | null) => formatCost(value), + align: "right" as const, + render: (value: number | null) => {formatCost(value)}, }, { title: "", key: "expand", - width: 50, + width: 40, render: (_: unknown, record: { id: string }) => ( @@ -269,88 +232,95 @@ const MultiCostResults: React.FC = ({ multiResult }) => { model: e.result!.model, provider: e.result!.provider, cost_per_request: e.result!.cost_per_request, + margin_cost_per_request: e.result!.margin_cost_per_request, daily_cost: e.result!.daily_cost, monthly_cost: e.result!.monthly_cost, })); return (
- +
-
- Cost Estimates - - {validEntries.length} model{validEntries.length !== 1 ? "s" : ""} configured - -
+ Cost Estimates
{isAnyLoading && } size="small" />}
- {/* Totals Summary */} - {validEntries.length > 1 && ( - -
- Combined Totals -
- - - } - /> + {/* Combined Totals - Always show when there are results */} + + + + Total Per Request} + value={formatCost(multiResult.totals.cost_per_request)} + valueStyle={{ color: "#1890ff", fontSize: "18px", fontFamily: "monospace" }} + /> + + + Total Daily} + value={formatCost(multiResult.totals.daily_cost)} + valueStyle={{ color: "#52c41a", fontSize: "18px", fontFamily: "monospace" }} + /> + + + Total Monthly} + value={formatCost(multiResult.totals.monthly_cost)} + valueStyle={{ color: "#722ed1", fontSize: "18px", fontFamily: "monospace" }} + /> + + + {hasMargin && ( + + +
Margin/Request
+
{formatCost(multiResult.totals.margin_per_request)}
- - } - /> + +
Daily Margin
+
{formatCost(multiResult.totals.daily_margin)}
- - } - /> + +
Monthly Margin
+
{formatCost(multiResult.totals.monthly_margin)}
-
- )} + )} +
- {/* Per-Model Summary Table */} - { - const entry = validEntries.find((e) => e.entry.id === record.id); - if (!entry?.result) return null; - return ( -
- -
- ); - }, - showExpandColumn: false, - }} - /> + {/* Per-Model Table */} + {validEntries.length > 0 && ( +
{ + const entry = validEntries.find((e) => e.entry.id === record.id); + if (!entry?.result) return null; + return ( +
+ +
+ ); + }, + showExpandColumn: false, + }} + /> + )} {/* Error Messages */} {multiResult.entries .filter((e) => e.error) .map((e) => ( -
+
{e.entry.model || "Unknown model"}: {e.error}
@@ -360,4 +330,3 @@ const MultiCostResults: React.FC = ({ multiResult }) => { }; export default MultiCostResults; - diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_export_utils.ts b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_export_utils.ts index 13119051aea..8c7de10f58f 100644 --- a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_export_utils.ts +++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_export_utils.ts @@ -196,7 +196,6 @@ export const exportMultiToPDF = (multiResult: MultiModelResult): void => {

LLM Cost Estimate Report

${modelCount} model${modelCount !== 1 ? "s" : ""} configured

- ${modelCount > 1 ? `

Combined Totals

@@ -213,8 +212,23 @@ export const exportMultiToPDF = (multiResult: MultiModelResult): void => {
${formatCostForExport(multiResult.totals.monthly_cost)}
+ ${multiResult.totals.margin_per_request > 0 ? ` +
+
+
Margin/Request
+
${formatCostForExport(multiResult.totals.margin_per_request)}
+
+
+
Daily Margin
+
${formatCostForExport(multiResult.totals.daily_margin)}
+
+
+
Monthly Margin
+
${formatCostForExport(multiResult.totals.monthly_margin)}
+
+
+ ` : ""}
- ` : ""}

Model Breakdown

${validEntries.map((e) => generateModelSection(e.result!)).join("")} @@ -243,15 +257,16 @@ export const exportMultiToCSV = (multiResult: MultiModelResult): void => { ]; // Summary section - if (validEntries.length > 1) { - rows.push( - ["COMBINED TOTALS"], - ["Total Per Request", multiResult.totals.cost_per_request.toString()], - ["Total Daily", multiResult.totals.daily_cost?.toString() || "-"], - ["Total Monthly", multiResult.totals.monthly_cost?.toString() || "-"], - [""] - ); - } + rows.push( + ["COMBINED TOTALS"], + ["Total Per Request", multiResult.totals.cost_per_request.toString()], + ["Total Daily", multiResult.totals.daily_cost?.toString() || "-"], + ["Total Monthly", multiResult.totals.monthly_cost?.toString() || "-"], + ["Margin Per Request", multiResult.totals.margin_per_request.toString()], + ["Daily Margin", multiResult.totals.daily_margin?.toString() || "-"], + ["Monthly Margin", multiResult.totals.monthly_margin?.toString() || "-"], + [""] + ); // Summary table header rows.push([ diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/types.ts b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/types.ts index 29f22b10ea9..726b12ce36c 100644 --- a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/types.ts +++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/types.ts @@ -31,6 +31,9 @@ export interface MultiModelResult { cost_per_request: number; daily_cost: number | null; monthly_cost: number | null; + margin_per_request: number; + daily_margin: number | null; + monthly_margin: number | null; }; } diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/use_multi_cost_estimate.ts b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/use_multi_cost_estimate.ts index 75de9ac2111..ed1794879f3 100644 --- a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/use_multi_cost_estimate.ts +++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/use_multi_cost_estimate.ts @@ -159,16 +159,26 @@ export function useMultiCostEstimate(accessToken: string | null) { let totalCostPerRequest = 0; let totalDailyCost: number | null = null; let totalMonthlyCost: number | null = null; + let totalMarginPerRequest = 0; + let totalDailyMargin: number | null = null; + let totalMonthlyMargin: number | null = null; for (const r of results) { if (r.result) { totalCostPerRequest += r.result.cost_per_request; + totalMarginPerRequest += r.result.margin_cost_per_request; if (r.result.daily_cost !== null) { totalDailyCost = (totalDailyCost ?? 0) + r.result.daily_cost; } + if (r.result.daily_margin_cost !== null) { + totalDailyMargin = (totalDailyMargin ?? 0) + r.result.daily_margin_cost; + } if (r.result.monthly_cost !== null) { totalMonthlyCost = (totalMonthlyCost ?? 0) + r.result.monthly_cost; } + if (r.result.monthly_margin_cost !== null) { + totalMonthlyMargin = (totalMonthlyMargin ?? 0) + r.result.monthly_margin_cost; + } } } @@ -178,6 +188,9 @@ export function useMultiCostEstimate(accessToken: string | null) { cost_per_request: totalCostPerRequest, daily_cost: totalDailyCost, monthly_cost: totalMonthlyCost, + margin_per_request: totalMarginPerRequest, + daily_margin: totalDailyMargin, + monthly_margin: totalMonthlyMargin, }, }; },