From 0e4448a7312ed0de8d54c2e259054541145be086 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Mon, 5 Jan 2026 19:41:54 +0530 Subject: [PATCH] fix - multi model selector --- .../pricing_calculator/index.tsx | 95 ++++- .../pricing_calculator/model_entry_row.tsx | 107 ++++++ .../pricing_calculator/multi_cost_results.tsx | 363 ++++++++++++++++++ .../multi_export_dropdown.tsx | 77 ++++ .../pricing_calculator/multi_export_utils.ts | 302 +++++++++++++++ .../pricing_calculator/types.ts | 23 ++ .../use_multi_cost_estimate.ts | 193 ++++++++++ 7 files changed, 1144 insertions(+), 16 deletions(-) create mode 100644 ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/model_entry_row.tsx create mode 100644 ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx create mode 100644 ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_export_dropdown.tsx create mode 100644 ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_export_utils.ts create mode 100644 ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/use_multi_cost_estimate.ts 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 fff6475e8a2..d0f50cbe875 100644 --- a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/index.tsx +++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/index.tsx @@ -1,31 +1,94 @@ -import React, { useCallback } from "react"; -import PricingForm from "./pricing_form"; -import CostResults from "./cost_results"; -import { useCostEstimate } from "./use_cost_estimate"; -import { PricingCalculatorProps, PricingFormValues } from "./types"; +import React, { useState, useCallback } from "react"; +import { Button, Text } from "@tremor/react"; +import { 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"; + +const generateId = () => `entry-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + +const createDefaultEntry = (): ModelEntry => ({ + id: generateId(), + model: "", + input_tokens: 1000, + output_tokens: 500, + num_requests_per_day: undefined, + num_requests_per_month: undefined, +}); const PricingCalculator: React.FC = ({ accessToken, models, }) => { - const { loading, result, debouncedFetch } = useCostEstimate(accessToken); + const [entries, setEntries] = useState([createDefaultEntry()]); + const { debouncedFetchForEntry, removeEntry, getMultiModelResult } = + useMultiCostEstimate(accessToken); - const handleValuesChange = useCallback( - (_changedValues: Partial, allValues: PricingFormValues) => { - if (allValues.model) { - debouncedFetch(allValues); - } + const handleEntryChange = useCallback( + (id: string, field: keyof ModelEntry, value: string | number | undefined) => { + setEntries((prev) => { + const updated = prev.map((entry) => + entry.id === id ? { ...entry, [field]: value } : entry + ); + const changedEntry = updated.find((e) => e.id === id); + if (changedEntry && changedEntry.model) { + debouncedFetchForEntry(changedEntry); + } + return updated; + }); }, - [debouncedFetch] + [debouncedFetchForEntry] ); + const handleAddEntry = useCallback(() => { + setEntries((prev) => [...prev, createDefaultEntry()]); + }, []); + + const handleRemoveEntry = useCallback( + (id: string) => { + setEntries((prev) => prev.filter((entry) => entry.id !== id)); + removeEntry(id); + }, + [removeEntry] + ); + + // Note: Fetching is triggered by handleEntryChange when model is selected + + const multiModelResult = getMultiModelResult(entries); + return ( -
- - +
+
+ + Add models to estimate costs. Each model can have its own token counts and request volumes. + + +
+ +
+ {entries.map((entry) => ( + 1} + /> + ))} +
+ +
); }; export default PricingCalculator; - diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/model_entry_row.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/model_entry_row.tsx new file mode 100644 index 00000000000..340d7763ddc --- /dev/null +++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/model_entry_row.tsx @@ -0,0 +1,107 @@ +import React from "react"; +import { Select, InputNumber, Button, Tooltip } from "antd"; +import { DeleteOutlined } from "@ant-design/icons"; +import { ModelEntry } from "./types"; + +interface ModelEntryRowProps { + entry: ModelEntry; + models: string[]; + onChange: (id: string, field: keyof ModelEntry, value: string | number | undefined) => void; + onRemove: (id: string) => void; + canRemove: boolean; +} + +const ModelEntryRow: React.FC = ({ + entry, + models, + onChange, + onRemove, + canRemove, +}) => { + return ( +
+
+
+ +