diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 27a05ca21..4bb8dee7f 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -7552,7 +7552,7 @@ async def model_metrics( FROM "LiteLLM_SpendLogs" WHERE - "startTime" >= NOW() - INTERVAL '30 days' + "startTime" BETWEEN $2::timestamp AND $3::timestamp AND "model" = $1 AND "cache_hit" != 'True' GROUP BY api_base, @@ -7653,6 +7653,8 @@ FROM WHERE "model" = $2 AND "cache_hit" != 'True' + AND "startTime" >= $3::timestamp + AND "startTime" <= $4::timestamp GROUP BY api_base ORDER BY @@ -7660,7 +7662,7 @@ ORDER BY """ db_response = await prisma_client.db.query_raw( - sql_query, alerting_threshold, _selected_model_group + sql_query, alerting_threshold, _selected_model_group, startTime, endTime ) if db_response is not None: diff --git a/ui/litellm-dashboard/src/components/model_dashboard.tsx b/ui/litellm-dashboard/src/components/model_dashboard.tsx index f50447381..b223e9128 100644 --- a/ui/litellm-dashboard/src/components/model_dashboard.tsx +++ b/ui/litellm-dashboard/src/components/model_dashboard.tsx @@ -16,8 +16,8 @@ import { AccordionHeader, AccordionBody, } from "@tremor/react"; -import { TabPanel, TabPanels, TabGroup, TabList, Tab, TextInput, Icon } from "@tremor/react"; -import { Select, SelectItem, MultiSelect, MultiSelectItem } from "@tremor/react"; +import { TabPanel, TabPanels, TabGroup, TabList, Tab, TextInput, Icon, DateRangePicker } from "@tremor/react"; +import { Select, SelectItem, MultiSelect, MultiSelectItem, DateRangePickerValue } from "@tremor/react"; import { modelInfoCall, userGetRequesedtModelsCall, modelCreateCall, Model, modelCostMap, modelDeleteCall, healthCheckCall, modelUpdateCall, modelMetricsCall, modelExceptionsCall, modelMetricsSlowResponsesCall } from "./networking"; import { BarChart, AreaChart } from "@tremor/react"; import { @@ -206,6 +206,10 @@ const ModelDashboard: React.FC = ({ const [allExceptions, setAllExceptions] = useState([]); const [failureTableData, setFailureTableData] = useState([]); const [slowResponsesData, setSlowResponsesData] = useState([]); + const [dateValue, setDateValue] = useState({ + from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), + to: new Date(), + }); const EditModelModal: React.FC = ({ visible, onCancel, model, onSubmit }) => { const [form] = Form.useForm(); @@ -454,11 +458,25 @@ const handleEditSubmit = async (formValues: Record) => { setAvailableModelGroups(_array_model_groups); + console.log("array_model_groups:", _array_model_groups) + let _initial_model_group = "all" + if (_array_model_groups.length > 0) { + // set selectedModelGroup to the last model group + _initial_model_group = _array_model_groups[_array_model_groups.length - 1]; + console.log("_initial_model_group:", _initial_model_group) + setSelectedModelGroup(_initial_model_group); + } + + console.log("selectedModelGroup:", selectedModelGroup) + + const modelMetricsResponse = await modelMetricsCall( accessToken, userID, userRole, - null + _initial_model_group, + dateValue.from?.toISOString(), + dateValue.to?.toISOString() ); console.log("Model metrics response:", modelMetricsResponse); @@ -473,7 +491,9 @@ const handleEditSubmit = async (formValues: Record) => { accessToken, userID, userRole, - null + _initial_model_group, + dateValue.from?.toISOString(), + dateValue.to?.toISOString() ) console.log("Model exceptions response:", modelExceptionsResponse); setModelExceptions(modelExceptionsResponse.data); @@ -484,7 +504,9 @@ const handleEditSubmit = async (formValues: Record) => { accessToken, userID, userRole, - null + _initial_model_group, + dateValue.from?.toISOString(), + dateValue.to?.toISOString() ) console.log("slowResponses:", slowResponses) @@ -492,40 +514,6 @@ const handleEditSubmit = async (formValues: Record) => { setSlowResponsesData(slowResponses); - // let modelMetricsData = modelMetricsResponse.data; - // let successdeploymentToSuccess: Record = {}; - // for (let i = 0; i < modelMetricsData.length; i++) { - // let element = modelMetricsData[i]; - // let _model_name = element.model; - // let _num_requests = element.num_requests; - // successdeploymentToSuccess[_model_name] = _num_requests - // } - // console.log("successdeploymentToSuccess:", successdeploymentToSuccess) - - // let failureTableData = []; - // let _failureData = modelExceptionsResponse.data; - // for (let i = 0; i < _failureData.length; i++) { - // const model = _failureData[i]; - // let _model_name = model.model; - // let total_exceptions = model.total_exceptions; - // let total_Requests = successdeploymentToSuccess[_model_name]; - // if (total_Requests == null) { - // total_Requests = 0 - // } - // let _data = { - // model: _model_name, - // total_exceptions: total_exceptions, - // total_Requests: total_Requests, - // failure_rate: total_Requests / total_exceptions - // } - // failureTableData.push(_data); - // // sort failureTableData by failure_rate - // failureTableData.sort((a, b) => b.failure_rate - a.failure_rate); - - // setFailureTableData(failureTableData); - // console.log("failureTableData:", failureTableData); - // } - } catch (error) { console.error("There was an error fetching the model data", error); } @@ -678,16 +666,17 @@ const handleEditSubmit = async (formValues: Record) => { }; - const updateModelMetrics = async (modelGroup: string | null) => { + const updateModelMetrics = async (modelGroup: string | null, startTime: Date | undefined, endTime: Date | undefined) => { console.log("Updating model metrics for group:", modelGroup); - if (!accessToken || !userID || !userRole) { + if (!accessToken || !userID || !userRole || !startTime || !endTime) { return } + console.log("inside updateModelMetrics - startTime:", startTime, "endTime:", endTime) setSelectedModelGroup(modelGroup); // If you want to store the selected model group in state try { - const modelMetricsResponse = await modelMetricsCall(accessToken, userID, userRole, modelGroup); + const modelMetricsResponse = await modelMetricsCall(accessToken, userID, userRole, modelGroup, startTime.toISOString(), endTime.toISOString()); console.log("Model metrics response:", modelMetricsResponse); // Assuming modelMetricsResponse now contains the metric data for the specified model group @@ -698,7 +687,9 @@ const handleEditSubmit = async (formValues: Record) => { accessToken, userID, userRole, - modelGroup + modelGroup, + startTime.toISOString(), + endTime.toISOString() ) console.log("Model exceptions response:", modelExceptionsResponse); setModelExceptions(modelExceptionsResponse.data); @@ -709,7 +700,9 @@ const handleEditSubmit = async (formValues: Record) => { accessToken, userID, userRole, - modelGroup + modelGroup, + startTime.toISOString(), + endTime.toISOString() ) console.log("slowResponses:", slowResponses) @@ -1118,20 +1111,47 @@ const handleEditSubmit = async (formValues: Record) => { -

View how requests were load balanced within a model group

- + {/*

View how requests were load balanced within a model group

*/} + + + + Select Time Range + { + setDateValue(value); + updateModelMetrics(selectedModelGroup, value.from, value.to); // Call updateModelMetrics with the new date range + }} + /> + + + Select Model Group + + + + + + + + + + + diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 53779c64b..d65482b8f 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -441,6 +441,8 @@ export const modelMetricsCall = async ( userID: String, userRole: String, modelGroup: String | null, + startTime: String | undefined, + endTime: String | undefined ) => { /** * Get all models on proxy @@ -448,7 +450,7 @@ export const modelMetricsCall = async ( try { let url = proxyBaseUrl ? `${proxyBaseUrl}/model/metrics` : `/model/metrics`; if (modelGroup) { - url = `${url}?_selected_model_group=${modelGroup}` + url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}` } // message.info("Requesting model data"); const response = await fetch(url, { @@ -481,6 +483,8 @@ export const modelMetricsSlowResponsesCall = async ( userID: String, userRole: String, modelGroup: String | null, + startTime: String | undefined, + endTime: String | undefined ) => { /** * Get all models on proxy @@ -488,8 +492,9 @@ export const modelMetricsSlowResponsesCall = async ( try { let url = proxyBaseUrl ? `${proxyBaseUrl}/model/metrics/slow_responses` : `/model/metrics/slow_responses`; if (modelGroup) { - url = `${url}?_selected_model_group=${modelGroup}` + url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}` } + // message.info("Requesting model data"); const response = await fetch(url, { method: "GET", @@ -520,14 +525,17 @@ export const modelExceptionsCall = async ( userID: String, userRole: String, modelGroup: String | null, + startTime: String | undefined, + endTime: String | undefined ) => { /** * Get all models on proxy */ try { let url = proxyBaseUrl ? `${proxyBaseUrl}/model/metrics/exceptions` : `/model/metrics/exceptions`; + if (modelGroup) { - url = `${url}?_selected_model_group=${modelGroup}` + url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}` } const response = await fetch(url, { method: "GET",