diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/uiSettings/useUISettings.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/uiSettings/useUISettings.ts index 823c0067b5c..46a0254d0db 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/hooks/uiSettings/useUISettings.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/uiSettings/useUISettings.ts @@ -1,10 +1,12 @@ import { getUiSettings } from "@/components/networking"; import { useQuery } from "@tanstack/react-query"; import { createQueryKeys } from "../common/queryKeysFactory"; +import useAuthorized from "../useAuthorized"; const uiSettingsKeys = createQueryKeys("uiSettings"); -export const useUISettings = (accessToken: string) => { +export const useUISettings = () => { + const { accessToken } = useAuthorized(); return useQuery>({ queryKey: uiSettingsKeys.list({}), queryFn: async () => await getUiSettings(accessToken), diff --git a/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/ModelsAndEndpointsView.tsx b/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/ModelsAndEndpointsView.tsx index e833686542c..5252afff27d 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/ModelsAndEndpointsView.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/ModelsAndEndpointsView.tsx @@ -17,7 +17,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { Col, Grid, Icon, Tab, TabGroup, TabList, TabPanel, TabPanels, Text } from "@tremor/react"; import type { UploadProps } from "antd"; import { Form, Typography } from "antd"; -import React, { useEffect, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import AddModelTab from "../../../components/add_model/add_model_tab"; import HealthCheckComponent from "../../../components/model_dashboard/HealthCheckComponent"; import ModelGroupAliasSettings from "../../../components/model_group_alias_settings"; @@ -44,28 +44,8 @@ interface GlobalRetryPolicyObject { [retryPolicyKey: string]: number; } -interface GlobalExceptionActivityData { - sum_num_rate_limit_exceptions: number; - daily_data: { date: string; num_rate_limit_exceptions: number }[]; -} - -//["OpenAI", "Azure OpenAI", "Anthropic", "Gemini (Google AI Studio)", "Amazon Bedrock", "OpenAI-Compatible Endpoints (Groq, Together AI, Mistral AI, etc.)"] - -interface ProviderFields { - field_name: string; - field_type: string; - field_description: string; - field_value: string; -} - -interface ProviderSettings { - name: string; - fields: ProviderFields[]; -} - const ModelsAndEndpointsView: React.FC = ({ modelData = { data: [] }, - keys, setModelData, premiumUser, teams, @@ -73,10 +53,8 @@ const ModelsAndEndpointsView: React.FC = ({ const { accessToken, token, userRole, userId: userID } = useAuthorized(); const [addModelForm] = Form.useForm(); const [lastRefreshed, setLastRefreshed] = useState(""); - const [providerModels, setProviderModels] = useState>([]); // Explicitly typing providerModels as a string array + const [providerModels, setProviderModels] = useState>([]); const [selectedProvider, setSelectedProvider] = useState(Providers.Anthropic); - const [availableModelGroups, setAvailableModelGroups] = useState>([]); - const [availableModelAccessGroups, setAvailableModelAccessGroups] = useState>([]); const [selectedModelGroup, setSelectedModelGroup] = useState(null); const [modelGroupRetryPolicy, setModelGroupRetryPolicy] = useState(null); @@ -93,7 +71,114 @@ const ModelsAndEndpointsView: React.FC = ({ const { data: modelCostMapData } = useModelCostMap(); const { data: credentialsResponse } = useCredentials(); const credentialsList = credentialsResponse?.credentials || []; - const { data: uiSettings } = useUISettings(accessToken || ""); + const { data: uiSettings } = useUISettings(); + + const availableModelGroups = useMemo(() => { + if (!modelDataResponse?.data) return []; + const allModelGroups = new Set(); + for (const model of modelDataResponse.data) { + allModelGroups.add(model.model_name); + } + return Array.from(allModelGroups).sort(); + }, [modelDataResponse?.data]); + + const availableModelAccessGroups = useMemo(() => { + if (!modelDataResponse?.data) return []; + const allModelAccessGroups = new Set(); + for (const model of modelDataResponse.data) { + const modelInfo = model.model_info; + if (modelInfo?.access_groups) { + for (const group of modelInfo.access_groups) { + allModelAccessGroups.add(group); + } + } + } + return Array.from(allModelAccessGroups); + }, [modelDataResponse?.data]); + + const allModelsOnProxy = useMemo(() => { + return modelDataResponse?.data?.map((model: any) => model.model_name); + }, [modelDataResponse?.data]); + + const getProviderFromModel = (model: string) => { + if (modelCostMapData !== null && modelCostMapData !== undefined) { + if (typeof modelCostMapData == "object" && model in modelCostMapData) { + return modelCostMapData[model]["litellm_provider"]; + } + } + return "openai"; + }; + + const processedModelData = useMemo(() => { + return modelDataResponse?.data?.map((model: any) => { + return {}; + }); + }, [modelDataResponse?.data]); + + // loop through model data and edit each row + for (let i = 0; i < modelData.data.length; i++) { + let curr_model = modelData.data[i]; + let litellm_model_name = curr_model?.litellm_params?.model; + let custom_llm_provider = curr_model?.litellm_params?.custom_llm_provider; + let model_info = curr_model?.model_info; + + let provider = ""; + let input_cost = "Undefined"; + let output_cost = "Undefined"; + let max_tokens = "Undefined"; + let max_input_tokens = "Undefined"; + let cleanedLitellmParams = {}; + + // Check if litellm_model_name is null or undefined + if (litellm_model_name) { + // Split litellm_model_name based on "/" + let splitModel = litellm_model_name.split("/"); + + // Get the first element in the split + let firstElement = splitModel[0]; + + // If there is only one element, default provider to openai + provider = custom_llm_provider; + if (!provider) { + provider = splitModel.length === 1 ? getProviderFromModel(litellm_model_name) : firstElement; + } + } else { + // litellm_model_name is null or undefined, default provider to openai + provider = "-"; + } + + if (model_info) { + input_cost = model_info?.input_cost_per_token; + output_cost = model_info?.output_cost_per_token; + max_tokens = model_info?.max_tokens; + max_input_tokens = model_info?.max_input_tokens; + } + + if (curr_model?.litellm_params) { + cleanedLitellmParams = Object.fromEntries( + Object.entries(curr_model?.litellm_params).filter(([key]) => key !== "model" && key !== "api_base"), + ); + } + + modelData.data[i].provider = provider; + modelData.data[i].input_cost = input_cost; + modelData.data[i].output_cost = output_cost; + modelData.data[i].litellm_model_name = litellm_model_name; + + // Convert Cost in terms of Cost per 1M tokens + if (modelData.data[i].input_cost) { + modelData.data[i].input_cost = (Number(modelData.data[i].input_cost) * 1000000).toFixed(2); + } + + if (modelData.data[i].output_cost) { + modelData.data[i].output_cost = (Number(modelData.data[i].output_cost) * 1000000).toFixed(2); + } + + modelData.data[i].max_tokens = max_tokens; + modelData.data[i].max_input_tokens = max_input_tokens; + modelData.data[i].api_base = curr_model?.litellm_params?.api_base; + modelData.data[i].cleanedLitellmParams = cleanedLitellmParams; + } const isProxyAdmin = userRole && isProxyAdminRole(userRole); const isInternalUser = userRole && internalUserRoles.includes(userRole); @@ -176,31 +261,6 @@ const ModelsAndEndpointsView: React.FC = ({ const fetchData = async () => { try { setModelData(modelDataResponse); - let all_model_groups: Set = new Set(); - for (let i = 0; i < modelDataResponse.data.length; i++) { - const model = modelDataResponse.data[i]; - all_model_groups.add(model.model_name); - } - let _array_model_groups = Array.from(all_model_groups); - _array_model_groups = _array_model_groups.sort(); - - setAvailableModelGroups(_array_model_groups); - - let all_model_access_groups: Set = new Set(); - for (let i = 0; i < modelDataResponse.data.length; i++) { - const model = modelDataResponse.data[i]; - let model_info: any | null = model.model_info; - if (model_info) { - let access_groups = model_info.access_groups; - if (access_groups) { - for (let j = 0; j < access_groups.length; j++) { - all_model_access_groups.add(access_groups[j]); - } - } - } - } - - setAvailableModelAccessGroups(Array.from(all_model_access_groups)); const routerSettingsInfo = await getCallbacksCall(accessToken, userID, userRole); let router_settings = routerSettingsInfo.router_settings; @@ -228,92 +288,6 @@ const ModelsAndEndpointsView: React.FC = ({ return
Loading...
; } - let all_models_on_proxy: any[] = []; - let all_providers: string[] = []; - - // loop through model data and edit each row - for (let i = 0; i < modelData.data.length; i++) { - let curr_model = modelData.data[i]; - let litellm_model_name = curr_model?.litellm_params?.model; - let custom_llm_provider = curr_model?.litellm_params?.custom_llm_provider; - let model_info = curr_model?.model_info; - - let provider = ""; - let input_cost = "Undefined"; - let output_cost = "Undefined"; - let max_tokens = "Undefined"; - let max_input_tokens = "Undefined"; - let cleanedLitellmParams = {}; - - const getProviderFromModel = (model: string) => { - /** - * Use model map - * - check if model in model map - * - return it's litellm_provider, if so - */ - if (modelCostMapData !== null && modelCostMapData !== undefined) { - if (typeof modelCostMapData == "object" && model in modelCostMapData) { - return modelCostMapData[model]["litellm_provider"]; - } - } - return "openai"; - }; - - // Check if litellm_model_name is null or undefined - if (litellm_model_name) { - // Split litellm_model_name based on "/" - let splitModel = litellm_model_name.split("/"); - - // Get the first element in the split - let firstElement = splitModel[0]; - - // If there is only one element, default provider to openai - provider = custom_llm_provider; - if (!provider) { - provider = splitModel.length === 1 ? getProviderFromModel(litellm_model_name) : firstElement; - } - } else { - // litellm_model_name is null or undefined, default provider to openai - provider = "-"; - } - - if (model_info) { - input_cost = model_info?.input_cost_per_token; - output_cost = model_info?.output_cost_per_token; - max_tokens = model_info?.max_tokens; - max_input_tokens = model_info?.max_input_tokens; - } - - if (curr_model?.litellm_params) { - cleanedLitellmParams = Object.fromEntries( - Object.entries(curr_model?.litellm_params).filter(([key]) => key !== "model" && key !== "api_base"), - ); - } - - modelData.data[i].provider = provider; - modelData.data[i].input_cost = input_cost; - modelData.data[i].output_cost = output_cost; - modelData.data[i].litellm_model_name = litellm_model_name; - all_providers.push(provider); - - // Convert Cost in terms of Cost per 1M tokens - if (modelData.data[i].input_cost) { - modelData.data[i].input_cost = (Number(modelData.data[i].input_cost) * 1000000).toFixed(2); - } - - if (modelData.data[i].output_cost) { - modelData.data[i].output_cost = (Number(modelData.data[i].output_cost) * 1000000).toFixed(2); - } - - modelData.data[i].max_tokens = max_tokens; - modelData.data[i].max_input_tokens = max_input_tokens; - modelData.data[i].api_base = curr_model?.litellm_params?.api_base; - modelData.data[i].cleanedLitellmParams = cleanedLitellmParams; - - all_models_on_proxy.push(curr_model.model_name); - } - // when users click request access show pop up to allow them to request access - if (userRole && userRole == "Admin Viewer") { const { Title, Paragraph } = Typography; return ( @@ -350,7 +324,7 @@ const ModelsAndEndpointsView: React.FC = ({ accessToken={accessToken} is_team_admin={userRole === "Admin"} is_proxy_admin={userRole === "Proxy Admin"} - userModels={all_models_on_proxy} + userModels={allModelsOnProxy} editTeam={false} onUpdate={handleRefreshClick} premiumUser={premiumUser} @@ -385,24 +359,6 @@ const ModelsAndEndpointsView: React.FC = ({ userID={userID} userRole={userRole} onModelUpdate={(updatedModel) => { - // Handle model deletion - if (updatedModel.deleted) { - const updatedModelData = { - ...modelData, - data: modelData.data.filter((model: any) => model.model_info.id !== updatedModel.model_info.id), - }; - setModelData(updatedModelData); - } else { - // Update the model in the modelData.data array - const updatedModelData = { - ...modelData, - data: modelData.data.map((model: any) => - model.model_info.id === updatedModel.model_info.id ? updatedModel : model, - ), - }; - setModelData(updatedModelData); - } - // Invalidate cache and trigger a refresh to update UI queryClient.invalidateQueries({ queryKey: ["models", "list"] }); handleRefreshClick(); }} @@ -478,7 +434,7 @@ const ModelsAndEndpointsView: React.FC = ({