diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index e8e01602097..ed7237141e0 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -208,6 +208,7 @@ class UpdateUserRequest(GenerateRequestBase): spend: Optional[float] = None metadata: Optional[dict] = None user_role: Optional[str] = None + max_budget: Optional[float] = None class KeyManagementSystem(enum.Enum): diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 7679d873264..1a5417d7c20 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -554,7 +554,6 @@ async def user_api_key_auth( db=custom_db_client, ) ) - if ( route.startswith("/key/") or route.startswith("/user/") @@ -589,6 +588,11 @@ async def user_api_key_auth( status_code=status.HTTP_403_FORBIDDEN, detail="user not allowed to access this key's info", ) + elif route == "/user/update": + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="only proxy admin can update user settings. Tried calling `/user/update`", + ) elif route == "/model/info": # /model/info just shows models user has access to pass diff --git a/ui/litellm-dashboard/src/components/user_dashboard.tsx b/ui/litellm-dashboard/src/components/user_dashboard.tsx index f8054751eb6..a3af0580374 100644 --- a/ui/litellm-dashboard/src/components/user_dashboard.tsx +++ b/ui/litellm-dashboard/src/components/user_dashboard.tsx @@ -4,6 +4,7 @@ import { userInfoCall } from "./networking"; import { Grid, Col, Card, Text } from "@tremor/react"; import CreateKey from "./create_key_button"; import ViewKeyTable from "./view_key_table"; +import ViewUserSpend from "./view_user_spend"; import EnterProxyUrl from "./enter_proxy_url"; import Navbar from "./navbar"; import { useSearchParams } from "next/navigation"; @@ -14,6 +15,7 @@ const proxyBaseUrl = "http://localhost:4000" // http://localhost:4000 const UserDashboard = () => { const [data, setData] = useState(null); // Keep the initialization of state here + const [userSpendData, setUserSpendData] = useState(null); // Assuming useSearchParams() hook exists and works in your setup const searchParams = useSearchParams(); const userID = searchParams.get("userID"); @@ -71,6 +73,8 @@ const UserDashboard = () => { accessToken, userID ); + console.log("Response:", response); + setUserSpendData(response["user_info"]) setData(response["keys"]); // Assuming this is the correct path to your data } catch (error) { console.error("There was an error fetching the data", error); @@ -104,6 +108,10 @@ const UserDashboard = () => { /> + = ({ userID, userSpendData }) => { + console.log("User SpendData:", userSpendData); + const spend = userSpendData?.spend; + const maxBudget = userSpendData?.max_budget || null; + const displayMaxBudget = maxBudget !== null ? `$${maxBudget} limit` : "No limit"; + const displayText = `$${spend} / ${displayMaxBudget}`; + + return ( + <> + + + ${spend} + + + / {displayMaxBudget} + + + + ) +} + +export default ViewUserSpend; +