From 432ce90a9a2c3c27f37abfb2bfe0e9681e9ada28 Mon Sep 17 00:00:00 2001 From: ishaan-jaff Date: Thu, 29 Feb 2024 12:30:47 -0800 Subject: [PATCH 1/6] (feat) proxy add pagination on /user/info endpoint --- litellm/proxy/proxy_server.py | 12 +++++++++++- litellm/proxy/utils.py | 6 +++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index ecf1d4ae5..31722fc5c 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -4311,6 +4311,14 @@ async def user_info( default=False, description="set to true to View all users. When using view_all, don't pass user_id", ), + page: int = fastapi.Query( + default=1, + description="Page number for pagination. Only use when view_all is true", + ), + page_size: int = fastapi.Query( + default=10, + description="Number of items per page. Only use when view_all is true", + ), user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), ): """ @@ -4332,8 +4340,10 @@ async def user_info( if user_id is not None: user_info = await prisma_client.get_data(user_id=user_id) elif view_all == True: + offset = (page - 1) * page_size # default is 0 + limit = page_size # default is 10 user_info = await prisma_client.get_data( - table_name="user", query_type="find_all" + table_name="user", query_type="find_all", offset=offset, limit=limit ) return user_info else: diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index ec563bbf3..abe8d7307 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -613,6 +613,10 @@ class PrismaClient: query_type: Literal["find_unique", "find_all"] = "find_unique", expires: Optional[datetime] = None, reset_at: Optional[datetime] = None, + offset: Optional[int] = None, # pagination, what row number to start from + limit: Optional[ + int + ] = None, # pagination, number of rows to getch when find_all==True ): try: response: Any = None @@ -748,7 +752,7 @@ class PrismaClient: ) else: response = await self.db.litellm_usertable.find_many( # type: ignore - order={"spend": "desc"}, + order={"spend": "desc"}, take=limit, skip=offset ) return response elif table_name == "spend": From 68500cb58afd89a6508619a87ead2f470e14e6bb Mon Sep 17 00:00:00 2001 From: ishaan-jaff Date: Thu, 29 Feb 2024 12:37:33 -0800 Subject: [PATCH 2/6] (fix) limit number of users on the users panel --- litellm/proxy/proxy_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 31722fc5c..9b681c368 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -4316,7 +4316,7 @@ async def user_info( description="Page number for pagination. Only use when view_all is true", ), page_size: int = fastapi.Query( - default=10, + default=25, description="Number of items per page. Only use when view_all is true", ), user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), From ed85d2de9529e7c637edefcf5fb394a690eaf921 Mon Sep 17 00:00:00 2001 From: ishaan-jaff Date: Thu, 29 Feb 2024 13:04:41 -0800 Subject: [PATCH 3/6] (docs) /user/info --- docs/my-website/docs/proxy/ui.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/my-website/docs/proxy/ui.md b/docs/my-website/docs/proxy/ui.md index e6a83a033..188a2a2eb 100644 --- a/docs/my-website/docs/proxy/ui.md +++ b/docs/my-website/docs/proxy/ui.md @@ -2,7 +2,7 @@ import Image from '@theme/IdealImage'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -# 🔑 [BETA] Proxy UI +# [BETA] Proxy UI ### **Create + delete keys through a UI** [Let users create their own keys](#setup-ssoauth-for-ui) From 2415dc79272a991ef83c44d8b8a7d1779f726595 Mon Sep 17 00:00:00 2001 From: ishaan-jaff Date: Thu, 29 Feb 2024 13:05:07 -0800 Subject: [PATCH 4/6] (docs) /user/info --- docs/my-website/docs/proxy/virtual_keys.md | 75 ++++++++++++++++++++-- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/docs/my-website/docs/proxy/virtual_keys.md b/docs/my-website/docs/proxy/virtual_keys.md index 83994701c..e350ce9d5 100644 --- a/docs/my-website/docs/proxy/virtual_keys.md +++ b/docs/my-website/docs/proxy/virtual_keys.md @@ -1,4 +1,4 @@ -# Virtual Keys, Users +# 🔑 Virtual Keys, Users Track Spend, Set budgets and create virtual keys for the proxy Grant other's temporary access to your proxy, with keys that expire after a set duration. @@ -343,18 +343,83 @@ A key will be generated for the new user created "key_name": null, "expires": null } - ``` -Request Params: -- keys: List[str] - List of keys to delete + +## /user/info + +### Request + +#### View all Users +If you're trying to view all users, we recommend using pagination with the following args +- `view_all=true` +- `page=0` Optional(int) min = 0, default=0 +- `page_size=25` Optional(int) min = 1, default = 25 +```shell +curl -X GET "http://0.0.0.0:4000/user/info?view_all=true&page=0&page_size=25" -H "Authorization: Bearer sk-1234" +``` + +#### View specific user_id +```shell +curl -X GET "http://0.0.0.0:4000/user/info?user_id=228da235-eef0-4c30-bf53-5d6ac0d278c2" -H "Authorization: Bearer sk-1234" +``` ### Response +View user spend, budget, models, keys and teams ```json { - "deleted_keys": ["sk-kdEXbIqZRwEeEiHwdg7sFA"] + "user_id": "228da235-eef0-4c30-bf53-5d6ac0d278c2", + "user_info": { + "user_id": "228da235-eef0-4c30-bf53-5d6ac0d278c2", + "team_id": null, + "teams": [], + "user_role": "app_user", + "max_budget": null, + "spend": 200000.0, + "user_email": null, + "models": [], + "max_parallel_requests": null, + "tpm_limit": null, + "rpm_limit": null, + "budget_duration": null, + "budget_reset_at": null, + "allowed_cache_controls": [], + "model_spend": { + "chatgpt-v-2": 200000 + }, + "model_max_budget": {} + }, + "keys": [ + { + "token": "16c337f9df00a0e6472627e39a2ed02e67bc9a8a760c983c4e9b8cad7954f3c0", + "key_name": null, + "key_alias": null, + "spend": 200000.0, + "expires": null, + "models": [], + "aliases": {}, + "config": {}, + "user_id": "228da235-eef0-4c30-bf53-5d6ac0d278c2", + "team_id": null, + "permissions": {}, + "max_parallel_requests": null, + "metadata": {}, + "tpm_limit": null, + "rpm_limit": null, + "max_budget": null, + "budget_duration": null, + "budget_reset_at": null, + "allowed_cache_controls": [], + "model_spend": { + "chatgpt-v-2": 200000 + }, + "model_max_budget": {} + } + ], + "teams": [] } + ``` ## Advanced From 1e8478c1d3d67f78292a295fb2ec90d15c6d2cb8 Mon Sep 17 00:00:00 2001 From: ishaan-jaff Date: Thu, 29 Feb 2024 13:05:28 -0800 Subject: [PATCH 5/6] (feat) use pagination on /user/info --- litellm/proxy/proxy_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 9b681c368..e63149384 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -4312,7 +4312,7 @@ async def user_info( description="set to true to View all users. When using view_all, don't pass user_id", ), page: int = fastapi.Query( - default=1, + default=0, description="Page number for pagination. Only use when view_all is true", ), page_size: int = fastapi.Query( @@ -4340,7 +4340,7 @@ async def user_info( if user_id is not None: user_info = await prisma_client.get_data(user_id=user_id) elif view_all == True: - offset = (page - 1) * page_size # default is 0 + offset = (page) * page_size # default is 0 limit = page_size # default is 10 user_info = await prisma_client.get_data( table_name="user", query_type="find_all", offset=offset, limit=limit From 6d30e2684533154ee4388d35e78e8592f6db4519 Mon Sep 17 00:00:00 2001 From: ishaan-jaff Date: Thu, 29 Feb 2024 13:11:07 -0800 Subject: [PATCH 6/6] (fix) make page and page size optional params --- litellm/proxy/proxy_server.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index e63149384..4e1eabc1a 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -4311,11 +4311,11 @@ async def user_info( default=False, description="set to true to View all users. When using view_all, don't pass user_id", ), - page: int = fastapi.Query( + page: Optional[int] = fastapi.Query( default=0, description="Page number for pagination. Only use when view_all is true", ), - page_size: int = fastapi.Query( + page_size: Optional[int] = fastapi.Query( default=25, description="Number of items per page. Only use when view_all is true", ), @@ -4340,6 +4340,10 @@ async def user_info( if user_id is not None: user_info = await prisma_client.get_data(user_id=user_id) elif view_all == True: + if page is None: + page = 0 + if page_size is None: + page_size = 25 offset = (page) * page_size # default is 0 limit = page_size # default is 10 user_info = await prisma_client.get_data(