diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 1edc85ef3..266c89352 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -11615,6 +11615,7 @@ async def model_metrics( _selected_model_group: Optional[str] = "gpt-4-32k", startTime: Optional[datetime] = None, endTime: Optional[datetime] = None, + api_key: Optional[str] = None, ): global prisma_client, llm_router if prisma_client is None: @@ -11627,6 +11628,9 @@ async def model_metrics( startTime = startTime or datetime.now() - timedelta(days=30) endTime = endTime or datetime.now() + if api_key is None or api_key == "undefined": + api_key = "null" + sql_query = """ SELECT api_base, @@ -11639,6 +11643,12 @@ async def model_metrics( WHERE "startTime" BETWEEN $2::timestamp AND $3::timestamp AND "model_group" = $1 AND "cache_hit" != 'True' + AND ( + CASE + WHEN $4 != 'null' THEN "api_key" = $4 + ELSE TRUE + END + ) GROUP BY api_base, model_group, @@ -11651,7 +11661,7 @@ async def model_metrics( """ _all_api_bases = set() db_response = await prisma_client.db.query_raw( - sql_query, _selected_model_group, startTime, endTime + sql_query, _selected_model_group, startTime, endTime, api_key ) _daily_entries: dict = {} # {"Jun 23": {"model1": 0.002, "model2": 0.003}} @@ -11710,6 +11720,7 @@ async def model_metrics_slow_responses( _selected_model_group: Optional[str] = "gpt-4-32k", startTime: Optional[datetime] = None, endTime: Optional[datetime] = None, + api_key: Optional[str] = None, ): global prisma_client, llm_router, proxy_logging_obj if prisma_client is None: @@ -11719,6 +11730,9 @@ async def model_metrics_slow_responses( param="None", code=status.HTTP_500_INTERNAL_SERVER_ERROR, ) + if api_key is None or api_key == "undefined": + api_key = "null" + startTime = startTime or datetime.now() - timedelta(days=30) endTime = endTime or datetime.now() @@ -11742,6 +11756,12 @@ WHERE AND "cache_hit" != 'True' AND "startTime" >= $3::timestamp AND "startTime" <= $4::timestamp + AND ( + CASE + WHEN $5 != 'null' THEN "api_key" = $5 + ELSE TRUE + END + ) GROUP BY api_base ORDER BY @@ -11749,7 +11769,12 @@ ORDER BY """ db_response = await prisma_client.db.query_raw( - sql_query, alerting_threshold, _selected_model_group, startTime, endTime + sql_query, + alerting_threshold, + _selected_model_group, + startTime, + endTime, + api_key, ) if db_response is not None: @@ -11773,6 +11798,7 @@ async def model_metrics_exceptions( _selected_model_group: Optional[str] = None, startTime: Optional[datetime] = None, endTime: Optional[datetime] = None, + api_key: Optional[str] = None, ): global prisma_client, llm_router if prisma_client is None: @@ -11786,6 +11812,9 @@ async def model_metrics_exceptions( startTime = startTime or datetime.now() - timedelta(days=30) endTime = endTime or datetime.now() + if api_key is None or api_key == "undefined": + api_key = "null" + """ """ sql_query = """ @@ -11795,7 +11824,10 @@ async def model_metrics_exceptions( exception_type, COUNT(*) AS num_rate_limit_exceptions FROM "LiteLLM_ErrorLogs" - WHERE "startTime" >= $1::timestamp AND "endTime" <= $2::timestamp AND model_group = $3 + WHERE + "startTime" >= $1::timestamp + AND "endTime" <= $2::timestamp + AND model_group = $3 GROUP BY combined_model_api_base, exception_type ) SELECT @@ -11808,7 +11840,7 @@ async def model_metrics_exceptions( LIMIT 200; """ db_response = await prisma_client.db.query_raw( - sql_query, startTime, endTime, _selected_model_group + sql_query, startTime, endTime, _selected_model_group, api_key ) response: List[dict] = [] exception_types = set() diff --git a/ui/litellm-dashboard/src/app/page.tsx b/ui/litellm-dashboard/src/app/page.tsx index 9c56abdf7..c218a8aad 100644 --- a/ui/litellm-dashboard/src/app/page.tsx +++ b/ui/litellm-dashboard/src/app/page.tsx @@ -138,6 +138,7 @@ const CreateKeyPage = () => { userID={userID} userRole={userRole} token={token} + keys={keys} accessToken={accessToken} modelData={modelData} setModelData={setModelData} diff --git a/ui/litellm-dashboard/src/components/model_dashboard.tsx b/ui/litellm-dashboard/src/components/model_dashboard.tsx index 1504e251a..ea23f660a 100644 --- a/ui/litellm-dashboard/src/components/model_dashboard.tsx +++ b/ui/litellm-dashboard/src/components/model_dashboard.tsx @@ -56,6 +56,7 @@ import { BarChart, AreaChart } from "@tremor/react"; import { Button as Button2, Modal, + Popover, Form, Input, Select as Select2, @@ -80,6 +81,7 @@ import { RefreshIcon, CheckCircleIcon, XCircleIcon, + FilterIcon, } from "@heroicons/react/outline"; import DeleteModelButton from "./delete_model_button"; const { Title: Title2, Link } = Typography; @@ -96,6 +98,7 @@ interface ModelDashboardProps { userRole: string | null; userID: string | null; modelData: any; + keys: any[] | null; setModelData: any; premiumUser: boolean; } @@ -260,6 +263,7 @@ const ModelDashboard: React.FC = ({ userRole, userID, modelData = { data: [] }, + keys, setModelData, premiumUser, }) => { @@ -313,6 +317,17 @@ const ModelDashboard: React.FC = ({ const [globalExceptionData, setGlobalExceptionData] = useState({} as GlobalExceptionActivityData); const [globalExceptionPerDeployment, setGlobalExceptionPerDeployment] = useState([]); + const [showAdvancedFilters, setShowAdvancedFilters] = useState(false); + const [selectedAPIKey, setSelectedAPIKey] = useState(null); + + useEffect(() => { + updateModelMetrics( + selectedModelGroup, + dateValue.from, + dateValue.to + ); + }, [selectedAPIKey]); + function formatCreatedAt(createdAt: string | null) { if (createdAt) { const date = new Date(createdAt); @@ -612,7 +627,8 @@ const ModelDashboard: React.FC = ({ userRole, _initial_model_group, dateValue.from?.toISOString(), - dateValue.to?.toISOString() + dateValue.to?.toISOString(), + selectedAPIKey?.token ); console.log("Model metrics response:", modelMetricsResponse); @@ -640,7 +656,8 @@ const ModelDashboard: React.FC = ({ userRole, _initial_model_group, dateValue.from?.toISOString(), - dateValue.to?.toISOString() + dateValue.to?.toISOString(), + selectedAPIKey?.token ); console.log("Model exceptions response:", modelExceptionsResponse); setModelExceptions(modelExceptionsResponse.data); @@ -652,7 +669,8 @@ const ModelDashboard: React.FC = ({ userRole, _initial_model_group, dateValue.from?.toISOString(), - dateValue.to?.toISOString() + dateValue.to?.toISOString(), + selectedAPIKey?.token ); const dailyExceptions = await adminGlobalActivityExceptions( @@ -874,7 +892,7 @@ const ModelDashboard: React.FC = ({ const updateModelMetrics = async ( modelGroup: string | null, startTime: Date | undefined, - endTime: Date | undefined + endTime: Date | undefined, ) => { console.log("Updating model metrics for group:", modelGroup); if (!accessToken || !userID || !userRole || !startTime || !endTime) { @@ -888,6 +906,11 @@ const ModelDashboard: React.FC = ({ ); setSelectedModelGroup(modelGroup); // If you want to store the selected model group in state + let selected_token = selectedAPIKey?.token; + if (selected_token === undefined) { + selected_token = null; + } + try { const modelMetricsResponse = await modelMetricsCall( accessToken, @@ -895,7 +918,8 @@ const ModelDashboard: React.FC = ({ userRole, modelGroup, startTime.toISOString(), - endTime.toISOString() + endTime.toISOString(), + selected_token ); console.log("Model metrics response:", modelMetricsResponse); @@ -922,7 +946,8 @@ const ModelDashboard: React.FC = ({ userRole, modelGroup, startTime.toISOString(), - endTime.toISOString() + endTime.toISOString(), + selected_token ); console.log("Model exceptions response:", modelExceptionsResponse); setModelExceptions(modelExceptionsResponse.data); @@ -934,7 +959,8 @@ const ModelDashboard: React.FC = ({ userRole, modelGroup, startTime.toISOString(), - endTime.toISOString() + endTime.toISOString(), + selected_token ); console.log("slowResponses:", slowResponses); @@ -969,6 +995,51 @@ const ModelDashboard: React.FC = ({ } }; + + const FilterByContent = ( +
+ Select API Key Name + + + + + + +
+ + ); + const customTooltip = (props: any) => { const { payload, active } = props; if (!active || !payload) return null; @@ -1722,9 +1793,7 @@ const ModelDashboard: React.FC = ({ - {/*

View how requests were load balanced within a model group

*/} - - + Select Time Range = ({ Select Model Group - + + + + + + + + @@ -2035,7 +2123,7 @@ const ModelDashboard: React.FC = ({
- + ); }; diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index b7660ee0e..601f2c432 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -726,7 +726,8 @@ export const modelMetricsCall = async ( userRole: String, modelGroup: String | null, startTime: String | undefined, - endTime: String | undefined + endTime: String | undefined, + apiKey: String | null, ) => { /** * Get all models on proxy @@ -734,7 +735,7 @@ export const modelMetricsCall = async ( try { let url = proxyBaseUrl ? `${proxyBaseUrl}/model/metrics` : `/model/metrics`; if (modelGroup) { - url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}`; + url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}&api_key=${apiKey}`; } // message.info("Requesting model data"); const response = await fetch(url, { @@ -805,7 +806,8 @@ export const modelMetricsSlowResponsesCall = async ( userRole: String, modelGroup: String | null, startTime: String | undefined, - endTime: String | undefined + endTime: String | undefined, + apiKey: String | null ) => { /** * Get all models on proxy @@ -815,7 +817,7 @@ export const modelMetricsSlowResponsesCall = async ( ? `${proxyBaseUrl}/model/metrics/slow_responses` : `/model/metrics/slow_responses`; if (modelGroup) { - url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}`; + url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}&api_key=${apiKey}`; } // message.info("Requesting model data"); @@ -848,7 +850,8 @@ export const modelExceptionsCall = async ( userRole: String, modelGroup: String | null, startTime: String | undefined, - endTime: String | undefined + endTime: String | undefined, + apiKey: String | null ) => { /** * Get all models on proxy @@ -859,7 +862,7 @@ export const modelExceptionsCall = async ( : `/model/metrics/exceptions`; if (modelGroup) { - url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}`; + url = `${url}?_selected_model_group=${modelGroup}&startTime=${startTime}&endTime=${endTime}&api_key=${apiKey}`; } const response = await fetch(url, { method: "GET", diff --git a/ui/litellm-dashboard/ui_colors.json b/ui/litellm-dashboard/ui_colors.json index a67d9835a..4a6ffbf34 100644 --- a/ui/litellm-dashboard/ui_colors.json +++ b/ui/litellm-dashboard/ui_colors.json @@ -1,7 +1,6 @@ { "brand": { "DEFAULT": "#6366f1", - "faint": "#6c6fed", "muted": "#8688ef", "subtle": "#8e91eb", "emphasis": "#5558eb",