
    h                    f   d Z ddlZddlZddlZddlZddlmZmZ ddlmZm	Z	m
Z
mZmZmZ ddlZddlmZmZmZmZmZmZ ddlZddlmZ ddl ddlmZ dd	lmZ dd
lmZ ddlm Z  ddl!m"Z"m#Z# ddl$m%Z% ddl&m'Z' ddl(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/ ddl0m1Z1m2Z2m3Z3m4Z4 e5rddl6m7Z7  e       Z8de9de:de9fdZ;dee<   deddfdZ=de<de
e<   ddde>fdZ?	 	 	 dde<de<de>dee<   dee@   d eAd!   fd"ZBdeee
e<   e
eC   f      fd#ZDde<dee<   de>d$ee
e<   e
eC   f   ddf
d%ZEe8j                  d&d'g ee      geG(      e% ee      fde:de>fd)              ZHe8j                  d*d'gd+ ee      g,       ee      fde>fd-       ZJd.eee
eK   e
eL   f      de<deeeKeMf      fd/ZNd0edee<   fd1ZOe8j                  d2d'g ee      g3      e% ej                  dd45       ee      fd0edee<   de>fd6              ZQd7 ZRd8ee
eS      d9eee
eK   e
eL   f      fd:ZTde9deeUeVf   de9fd;ZW	 dd<eUde>d=ee<   de	e<ef   fd>ZXe8j                  d?d'g ee      g3      e% ee      fdeUde>fd@              ZY	 ddAe
eU   de>d=ee<   de2fdBZZe8j                  dCd'g ee      ge2(      e% ee       eddDE      fde1de>d=ee<   fdF              Z[	 ddGee
e<      fdHZ\dIee<   dJe<dee	e<e<f      fdKZ]e8j                  dLd'g ee      ge3(       ej                  ddM5       ej                  ddN5       ej                  ddO5       ej                  ddP5       ej                  ddQ5       ej                  dRdRdST       ej                  dUdRdVdWX       ej                  ddY5       ej                  dZd[5      f	d\ee<   dGee<   d]ee<   dee<   d^ee<   d_e^d`e^dIee<   dJe<fda       Z_e8j                  dbd'g ee      g3      e% ee       eddDE      fde`de>d=ee<   fdc              Zade<dde<d ebfdeZce8j                  dfd'g ee      gd+dgdhe
ed   iii       ej                  dd45       ej                  ddj5       ej                  dRdkdRl       ej                  dmdWdRdVn       ee      fdee<   dee<   d_e^d`e^de>f
do       Zedpe/dqe,de/fdrZfdse)dqe,dte	e<e	e<ef   f   due	e<e	e<ef   f   dve	e<e	e<ef   f   de)fdwZge8j                  dxdyd'g ee      ge.(       ej                  ddz5       ej                  dd{5       ej                  dd|5       ej                  dd}5       ej                  dRdkdRl       ej                  dmd~dRdn       ee      fdee<   dee<   dhee<   dee<   d_e^d`e^de>de.fd       Zhy)z
Internal User Management Endpoints


These are members of a Team on LiteLLM

/user/new
/user/update
/user/delete
/user/info
/user/list
    N)datetimetimezone)AnyDictListOptionalUnioncast)	APIRouterDependsHeaderHTTPExceptionRequeststatus)verbose_proxy_logger)*)user_api_key_auth)UserManagementEventHooks)get_daily_activity)_user_has_admin_view)generate_key_helper_fnprepare_metadata_fields)management_endpoint_wrapper)handle_exception_on_proxy)BreakdownMetricsKeyMetadataKeyMetricWithMetadataLiteLLM_DailyUserSpendMetricWithMetadataSpendAnalyticsPaginatedResponseSpendMetrics)BulkUpdateUserRequestBulkUpdateUserResponseUserListResponseUserUpdateResult)PrismaClient	data_jsondatareturnc                 h   d| v r%| d    t        t        j                               | d<   | j                  dd      }|du rd| d<   t        j
                  r|j                  t        j                  j                  k7  r|j                  t        j                  k7  rlt        j
                  j                         D ]K  \  }}|dk(  r|| vs| |   || |<   |dk(  s!t        | |   t              s5t        | |         d	k(  sG|| |<   M |j                  |j                  t        j                  j                  k(  rht        j                  $| j!                  d
      t        j                  | d
<   t        j"                  $| j!                  d      t        j"                  | d<   | j                  dd        | S )Nuser_idauto_create_keyTFuser
table_nameavailable_teamsmodelsr   
max_budgetbudget_durationteams)struuiduuid4poplitellmdefault_internal_user_params	user_roleLitellmUserRolesPROXY_ADMINvalueitems
isinstancelistlenINTERNAL_USERmax_internal_user_budgetgetinternal_user_budget_duration)r'   r(   r,   keyr=   s        v/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/proxy/management_endpoints/internal_user_endpoints.py _update_internal_new_user_paramsrH   ;   s   I)I"6">"4::<0	)mm$5t<O% 	, ++*66<<<NN.:::!>>DDFJC''I%3)?!&	#xy~t4	#'1,!&	# G 	"NN.<<BBB ,,8l+3&-&F&FIl# 11=/08+2+P+PI'(MM'4     
user_emailprisma_clientc                    K   | rn|t        d      |j                  j                  j                  d| j	                         ddi       d{   }|t        ddd	|j                   d
i      yy7 %w)a<  
    Helper function to check if a user email already exists in the database.

    Args:
        user_email (Optional[str]): Email to check
        prisma_client (Any): Database client instance

    Raises:
        Exception: If database is not connected
        HTTPException: If user with email already exists
    NDatabase not connectedrJ   insensitive)equalsmodewhere  errorzUser with email z already existsstatus_codedetail)	Exceptiondblitellm_usertable
find_firststripr   rJ   )rJ   rK   existing_users      rG   _check_duplicate_user_emailr^   k   s       455+..@@KKJ,<,<,>!VW L 
 
 $/0H0H/IY  % 
s   AA6A4&A6r+   organizationsr&   user_api_key_dictc                    K   ddl m} g }|D ]N  }|j                   |t        |t	        | t
        j                        g      t        ddd      |	             P t        j                  |d
di d{    y7 w)z%
    Add a user to organizations
    r   )organization_member_add)r+   role)organization_idmemberhttp	/user/newtypepathscope)r(   http_requestr`   return_exceptionsTN)
9litellm.proxy.management_endpoints.organization_endpointsrb   appendOrganizationMemberAddRequest	OrgMemberr;   rB   r   asynciogather)r+   r_   rK   r`   rb   tasksrd   s          rG   _add_user_to_organizationsrv      s      E(#1$3!$+!1!?!? %#);? #4	
 )$ ..%
84
888s   A4A>6A<7A>team_idmax_budget_in_teamr:   )r-   adminc           
      $  K   ddl m} 	  |t        |t        | ||      |      |       d {    y 7 # t        $ r}|j
                  dk(  rHdt        |      v sdt        |      v r.t        j                  d	j                  t        |                   n2t        j                  d
j                  t        |                   Y d }~y Y d }~y d }~wt        $ r}dt        |      v sdt        |      v r.t        j                  d	j                  t        |                   nat        |t              rJt        j                  |j                  v r.t        j                  d	j                  t        |                   n|Y d }~y Y d }~y d }~ww xY ww)Nr   )team_member_add)r+   rc   rJ   )rw   re   rx   )r(   r`   rS   zalready existszdoesn't existzglitellm.proxy.management_endpoints.internal_user_endpoints.new_user(): User already exists in team - {}z]litellm.proxy.management_endpoints.internal_user_endpoints.new_user(): Exception occured - {})1litellm.proxy.management_endpoints.team_endpointsr{   TeamMemberAddRequestMemberr   rV   r4   r   debugformatrX   r?   ProxyExceptionProxyErrorTypesteam_member_already_in_teamri   )r+   rw   r`   rJ   rx   r:   r{   es           rG   _add_user_to_teamr      sx     R-%#")
 $6 0
 	
 	
  ==CA&/SV*C &&y  A  AF !&&ovvF   s1v%CF)B &&y  A  AF q.);;qvvE &&y  A  AF GsK   F%7 57 F7 	F BC
FFB$F>
FFFc                  ~   t         j                  y t         j                  j                  d      } | t        d | D              r| S t        d | D              rJ| D cg c]>  }t	        |j                  d      |j                  d      |j                  dd            @ c}S t        j                  d	|        y c c}w )
Nr3   c              3   <   K   | ]  }t        |t                y wN)r?   r4   .0teams     rG   	<genexpr>z,check_if_default_team_set.<locals>.<genexpr>   s     7z$$7   c              3   <   K   | ]  }t        |t                y wr   )r?   dictr   s     rG   r   z,check_if_default_team_set.<locals>.<genexpr>   s     :DD$':r   rw   rx   r:   r-   )rw   rx   r:   z5Invalid team type in default internal user params: %s)r8   r9   rD   allNewUserRequestTeamr   rT   )r3   r   s     rG   check_if_default_team_setr      s    ++30044W=E777L:E:: "  # HHY/'+xx0D'E"hh{F;  !&&G s   AB:r3   c           
      D  K   g }|D ]v  }d}t        |t              r|}n@t        |t              r|j                  }|j                  }nt        dt        |             |j                  t        | ||||             x t        j                  |ddi d {    y 7 w)Nr-   zInvalid team type: )r+   rw   rJ   r`   r:   rn   T)r?   r4   r   rw   r:   
ValueErrorri   rp   r   rs   rt   )	r+   rJ   r`   r3   rK   ru   r   r:   rw   s	            rG   add_new_user_to_default_teamr      s      E.4	dC G01llGI24:,?@@%"3#	
 & ..%
84
888s   BB BB rg   zInternal User management)tagsdependenciesresponse_modelc                 
  K   	 ddl m}m} |%t        dt        j
                  j                        |%t        dt        j
                  j                        t        | j                  |       d{    |j                  j                  j                          d{   }|r|j                  |      rt        dd	      | j                         }t        ||       }| j                  }|
t!               }t#        t$        t&        t(              |j+                  d
d            }t-        dddi| d{   }|j/                  dd      }	|	At1        t#        t(        |j/                  d            |	|| j                  dd       d{    nA|?t3        t#        t(        |j/                  d            | j                  |||       d{    t#        t$        t(           |j/                  dd            }
||
t5        |
|||       d{    ddg}i }|j7                         D ]0  \  }}|t8        j:                  j=                         v s'||vs,|||<   2 |j/                  dd      |d<   t9        di |}t?        j@                  tC        jD                  | ||             |S 7 77 7 y7 (7 7 # tF        $ r=}tI        jJ                  djM                  t)        |                   tO        |      d}~ww xY ww)a  
    Use this to create a new INTERNAL user with a budget.
    Internal Users can access LiteLLM Admin UI to make keys, request access to models.
    This creates a new user and generates a new api key for the new user. The new api key is returned.

    Returns user id, budget + new key.

    Parameters:
    - user_id: Optional[str] - Specify a user id. If not set, a unique id will be generated.
    - user_alias: Optional[str] - A descriptive name for you to know who this user id refers to.
    - teams: Optional[list] - specify a list of team id's a user belongs to.
    - user_email: Optional[str] - Specify a user email.
    - send_invite_email: Optional[bool] - Specify if an invite email should be sent.
    - user_role: Optional[str] - Specify a user role - "proxy_admin", "proxy_admin_viewer", "internal_user", "internal_user_viewer", "team", "customer". Info about each role here: `https://github.com/BerriAI/litellm/litellm/proxy/_types.py#L20`
    - max_budget: Optional[float] - Specify max budget for a given user.
    - budget_duration: Optional[str] - Budget is reset at the end of specified duration. If not set, budget is never reset. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d"), months ("1mo").
    - models: Optional[list] - Model_name's a user is allowed to call. (if empty, key is allowed to call all models). Set to ['no-default-models'] to block all model access. Restricting user to only team-based model access.
    - tpm_limit: Optional[int] - Specify tpm limit for a given user (Tokens per minute)
    - rpm_limit: Optional[int] - Specify rpm limit for a given user (Requests per minute)
    - auto_create_key: bool - Default=True. Flag used for returning a key as part of the /user/new response
    - aliases: Optional[dict] - Model aliases for the user - [Docs](https://litellm.vercel.app/docs/proxy/virtual_keys#model-aliases)
    - config: Optional[dict] - [DEPRECATED PARAM] User-specific config.
    - allowed_cache_controls: Optional[list] - List of allowed cache control values. Example - ["no-cache", "no-store"]. See all values - https://docs.litellm.ai/docs/proxy/caching#turn-on--off-caching-per-request-
    - blocked: Optional[bool] - [Not Implemented Yet] Whether the user is blocked.
    - guardrails: Optional[List[str]] - [Not Implemented Yet] List of active guardrails for the user
    - permissions: Optional[dict] - [Not Implemented Yet] User-specific permissions, eg. turning off pii masking.
    - metadata: Optional[dict] - Metadata for user, store information for user. Example metadata = {"team": "core-infra", "app": "app2", "email": "ishaan@berri.ai" }
    - max_parallel_requests: Optional[int] - Rate limit a user based on the number of parallel requests. Raises 429 error, if user's parallel requests > x.
    - soft_budget: Optional[float] - Get alerts when user crosses given budget, doesn't block requests.
    - model_max_budget: Optional[dict] - Model-specific max budget for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-budgets-to-keys)
    - model_rpm_limit: Optional[float] - Model-specific rpm limit for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-limits-to-keys)
    - model_tpm_limit: Optional[float] - Model-specific tpm limit for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-limits-to-keys)
    - spend: Optional[float] - Amount spent by user. Default is 0. Will be updated by proxy whenever user is used. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d"), months ("1mo").
    - team_id: Optional[str] - [DEPRECATED PARAM] The team id of the user. Default is None. 
    - duration: Optional[str] - Duration for the key auto-created on `/user/new`. Default is None.
    - key_alias: Optional[str] - Alias for the key auto-created on `/user/new`. Default is None.
    - sso_user_id: Optional[str] - The id of the user in the SSO provider.
    - object_permission: Optional[LiteLLM_ObjectPermissionBase] - internal user-specific object permission. Example - {"vector_stores": ["vector_store_1", "vector_store_2"]}. IF null or {} then no object permission.
    - organizations: List[str] - List of organization id's the user is a member of
    Returns:
    - key: (str) The generated api key for the user
    - expires: (datetime) Datetime object for when key expires.
    - user_id: (str) Unique user id - used for tracking spend across multiple keys for same user id.
    - max_budget: (float|None) Max budget for given user.

    Usage Example 

    ```shell
     curl -X POST "http://localhost:4000/user/new"      -H "Content-Type: application/json"      -H "Authorization: Bearer sk-1234"      -d '{
         "username": "new_user",
         "email": "new_user@example.com"
     }'
    ```
    r   )_license_checkrK   NrS   rU     )total_usersi  zOLicense is over limit. Please contact support@berri.ai to upgrade your license.r_   request_typer-   rw   r+   )r+   rw   r`   rJ   rx   r:   )r+   rJ   r`   r3   rK   )r+   r_   rK   r`   tokentoken_id rF   )r(   responser`   z!/user/new: Exception occured - {} )(litellm.proxy.proxy_serverr   rK   r   CommonProxyErrorsdb_not_connected_errorr=   r^   rJ   rY   rZ   countis_over_limitjsonrH   r3   r   r
   r   r   r4   r7   r   rD   r   r   rv   r>   NewUserResponsemodel_fieldskeysrs   create_taskr   async_user_created_hookrX   r   	exceptionr   r   )r(   r`   r   rK   r   r'   r3   organization_idsr   _team_idr+   special_keysresponse_dictrF   r=   new_user_responser   s                    rG   new_userr     s    H_+L (9(P(P(V(V   (??EE 
 *$//=III *,,>>DDFF>77K7Ph 
 IIK	4YE	

=-/ET#Y!E
 0QVQyQQ ==D1#S(,,y"9: "3??#'    .S(,,y"9:??"3+   x}hll9d&CD'G,?,.+"3	    ,"..*JCo227799c>U%*c" +  (||GR8e+<m<
 	$<<*"3	
 ! Y 	J G  R@  +&&/66s1v>	
 (**	+s   LA/J: 3J*4+J: J- BJ: 7J08AJ: J3AJ: J6AJ: J8A J: J: AJ: )L*J: -J: 0J: 3J: 6J: 8J: :	L 8K;;L  Lz/user/available_rolesF)r   include_in_schemar   c                    K   i }t         D ]i  }|t         j                  t         j                  t         j                  t         j                  fv sD|j
                  |j                  d||j                  <   k |S w)z
    Endpoint used by Admin UI to show all available roles to assign a user
    return {
        "proxy_admin": {
            "description": "Proxy Admin role",
            "ui_label": "Admin"
        }
    }
    )descriptionui_label)r;   r<   PROXY_ADMIN_VIEW_ONLYrB   INTERNAL_USER_VIEW_ONLYr   r   r=   )r`   _data_to_returnrc   s      rG   ui_get_available_roler     sr     & O ((22**44	
 
  $// MM+ODJJ' ! s   AA9*A9	team_listc                 >    | y | D ]  }|j                   |k(  s|c S  y r   )rw   )r   rw   r   s      rG   get_team_from_listr     s-     <<7"K  rI   requestc                     d}t        | j                  j                        }d|v r7ddl}ddlm} |j                  d|      }|r ||j                  d            }|}|S )z*
    Get the user id from the request
    Nzuser_id=r   )unquotezuser_id=([^&]*)   )r4   urlqueryreurllib.parser   searchgroup)r   r+   query_stringr   r   matchraw_user_ids          rG   get_user_id_from_requestr     s[    
 "Gw{{(()L\!(		,l;!%++a.1K!GNrI   
/user/info)r   r   z!User ID in the request parameters)defaultr   c                   K   ddl m} 	 |d|v rt        |       }|t        d      |/|j                  t
        j                  k(  rt                d{   S ||j                  }||j                  |       d{   }nd}g }g }ddl
m}  |t        d	d
d      ||       d{   }|4t        |t              r$|}|D ]  }	|j                  |	j                           d}
|||j                  |j"                  dd       d{   }
|
t        |
t              r|
D ]=  }	|	j                   |vs|j                  |	       |j                  |	j                          ? n|j                  ||j                  |j                         d{   }|&|j                  |j"                  dd       d{   }
|
Rt        |
t              rB|
D ]=  }	|	j                   |vs|j                  |	       |j                  |	j                          ? |j                  |dd       d{   }||d}|D ]  }|t%        |dd      z  } d|i}t'        ||      }|j)                  d        t        |t*              r|j-                         n|}t/        ||||      }|S 7 P7 )7 7 7 7 7 # t        $ r=}t1        j2                  dj5                  t7        |                   t9        |      d}~ww xY ww)aA  
    [10/07/2024]
    Note: To get all users (+pagination), use `/user/list` endpoint.


    Use this to get user information. (user row + all user key info)

    Example request
    ```
    curl -X GET 'http://localhost:4000/user/info?user_id=krrish7%40berri.ai'     --header 'Authorization: Bearer sk-1234'
    ```
    r   rK   N )r   Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keys)r+   )	list_teamrf   r   rh   rk   )rm   r+   r`   r   find_all)team_id_listr.   
query_typerF   )r+   r.   r   spendr   	all_teamsc                 $    t        | dd      xs dS N
team_aliasr   getattrxs    rG   <lambda>zuser_info.<locals>.<lambda>  s    gar&B&Hb&HrI   rF   r+   	user_infor   r3   z>litellm.proxy.proxy_server.user_info(): Exception occured - {})r   rK   r   rX   r:   r;   r<   _get_user_info_for_proxy_adminr+   get_datar|   r   r   r?   r@   rp   rw   r3   r   _process_keys_for_user_infosort	BaseModel
model_dumpUserInfoResponser   r   r   r4   r   )r   r+   r`   rK   r   r   r   r   teams_1r   teams_2caller_user_infor   r   kreturned_keys
_user_inforesponse_datar   s                      rG   r   r     sL    6 9k+ C7N.w?G  T  O!++/?/K/KK7999_'//G +44W4EEII 	O! %|< /
 
 :gt#<I##DLL1   "& )22&__J 3  G "z'4'@#D||<7!((.$++DLL9 $ %%1go%2%;%;)11 &< &    + - 6 6!1!7!7%) !7 !  "z'4'@#D||<7!((.$++DLL9 $ #++! , 
 
 !1EGQ//  %(I 4QIJ&0I&FI  "I 	 )zY
 k : F
  

0  +&&LSSA	

 (**+s   LAJ8 J%J8 L%J8 ?J( ,J8 ,J+-AJ8 J.*J8 8AJ8 J1'J8 <J4=)J8 'AJ8 ,J6-A7J8 $L%J8 (J8 +J8 .J8 1J8 4J8 6J8 8	K>8K99K>>Lc                    K   ddl m}  d}| t        d      | j                  j	                  |       d{   }t        j                  d|       |d   d   xs g }g }|D ]2  }|j                  d      g |d<   |j                  t        di |       4 |d   d	   xs g }|D cg c]  }t        di | }}|j                  d
        t        ||      }t        dd||      S 7 c c}w w)a1  
    Admin UI Endpoint - Returns All Teams and Keys when Proxy Admin is querying

    - get all teams in LiteLLM_TeamTable
    - get all keys in LiteLLM_VerificationToken table

    Why separate helper for proxy admin ?
        - To get Faster UI load times, get all teams and virtual keys in 1 query
    r   r   z
        SELECT 
            (SELECT json_agg(t.*) FROM "LiteLLM_TeamTable" t) as teams,
            (SELECT json_agg(k.*) FROM "LiteLLM_VerificationToken" k WHERE k.team_id != 'litellm-dashboard' OR k.team_id IS NULL) as keys
    Nr   zresults_keys: %sr   r0   r3   c                 $    t        | dd      xs dS r   r   r   s    rG   r   z0_get_user_info_for_proxy_admin.<locals>.<lambda>  s    WQb%A%GR%GrI   r   r   r   r   )r   rK   rX   rY   	query_rawr   r   rD   rp   LiteLLM_VerificationTokenLiteLLM_TeamTabler   r   r   )	rK   	sql_queryresults_keys_in_db
keys_in_dbrF   _teams_in_dbr   r   s	            rG   r   r     s     9I
  P
 	
 "$$..y99G17;
6*0bKJ778$CM3:c:;  !G,2L:FG$%--GLGHI/Z<XM	 # : Hs"   4C0C)A/C0&C+82C0+C0r   r   c                 ~   ddl m}m} g }| 	 |S | D ]  }|j                  |k(  r|j	                  dd      du r'	 |j                         }d|v r8|d   3|d   dk7  r+t        ||d         }|t        |d	d       }||d	<   nd |d	<   nd
|d	<   |j                  |        |S # t        $ r |j                         }Y qw xY w)Nr   )general_settingslitellm_master_key_hashdisable_master_key_returnFTrw   zlitellm-dashboard)r   rw   r   None)r   r   r   r   rD   r   rX   r   r   r   rp   )	r   r   r   r   r   rF   _key	team_infor   s	            rG   r   r     s     UM|> ; C		44$(()DeL " ^^-
 T!O/O'::.'i	 (!(L$!GJ)3D&)-D&%+\"  &9 : '  "xxz"s   B  B<;B<c                    i }| j                         D ]  \  }}|	|g i fvs|t        vs|||<    d}|j                  t        j                  k(  rd}d|v rddlm}  ||d         |d<   d|vr%|r#t        j                  t        j                  |d<   d|vr:|r8t        j                  (t        j                  |d<   ddlm}  ||d         |d<   |S )	NFTr2   r   )get_budget_reset_time)r2   budget_reset_atr1   )
r>   )LiteLLM_ManagementEndpoint_MetadataFieldsr:   r;   rB   )litellm.proxy.common_utils.timezone_utilsr  r8   rC   rE   )r'   r(   non_default_valuesr   vis_internal_userr  s          rG   _update_internal_user_paramsr    s    !1M
 BB$%q! " ~~)777..S0E./@A1
,- --!A!A!M/6/O/O|, 	!33 E E Q55 01 X4I 23D E501 rI   user_requestlitellm_changed_byc                 2  K   ddl m}m} |t        d      | j                  s| j
                  st        d      | j                  d      }t        ||       }d}| j                  r;|j                  j                  j                  d	| j                  i
       d{   }nF| j
                  r:|j                  j                  j                  d| j
                  i
       d{   }|t        di |j                  d      }|t        t        t        |di       xs i       ni }t!        | ||xs i       }d}	| j                  rNt#        | j                        dkD  r6| j                  |d	<   |j%                  | j                  |d       d{   }	n| j
                  r|j'                  d| j
                  idd       d{   }
|
r\t)        |
t*              rLt#        |
      dkD  r>|
D ]8  }|j                  |d	<   |j%                  |j                  |d       d{   }	 nL nJt-        t/        j0                               |d	<   | j
                  |d<   |j3                  |d       d{   }	|		 |j                  j                  j                  d	|	d	   i
       d{   }|rt        di |j                  d      }t5        j6                  t9        j:                  |j                  d|xs |j                  |||r|j=                  d      nd|j=                  d                   |	tE        dddi      |	S 7 7 c7 7 7 07 7 # t        $ r4}t?        j@                  d|	jC                  d	       d|        Y d}~^d}~ww xY ww)z
    Helper function to update a single user.
    Used by both user_update and bulk_user_update endpoints.

    Returns the updated user data or raises an exception on failure.
    r   litellm_proxy_admin_namerK   NzNot connected to DB!z-Either user_id or user_email must be providedTexclude_unsetr'   r(   r+   rQ   rJ   exclude_nonemetadata)r(   r
  existing_metadatar-   )r+   r(   r.   r   )key_valr.   r   )r(   r.   updatedr+   actionr  r`   r  before_valueafter_valuez$Failed to create audit log for user : rS   rT   zFailed to update userrU   r   )#r   r  rK   rX   r+   rJ   r   r   r  rY   rZ   r[   LiteLLM_UserTabler
   r   r   r   rA   update_datar   r?   r@   r4   r5   r6   insert_datars   r   r   create_internal_user_audit_logmodel_dump_jsonr   warningrD   r   )r  r`   r  r  rK   r'   r
  existing_user_rowr  r   existing_user_rowsr]   updated_user_rowuser_row_typedaudit_errors                  rG   _update_single_user_helperr,    s     S.// (?(?HII #--D-AI 6,
 .2"/"2"2"D"D"O"Ol223 #P #
 
 
	 	 "/"2"2"D"D"O"O!8!89 #P #
 
 $- 
***=
 ( 	T7,j"=CD  1-+1r *.HL$8$8 9A =(4(<(<9%&22 ((# 3 
 

 
	 	 #0#9#9!<#:#:;! $: $
 
 -t4&'!+!30=0E0E"9-!.!:!:)11+% "; " 
  "4 -0

,=y)/;/F/F|,*66'F 7  H
 	%2%5%5%G%G%R%R (9"56 &S &    !2 "&11t1D"
 ##,KK . 6 6(+= ,5,44*;1I  1 .==4=P!%$2$B$BPT$B$U* 45
 	
 OO

4

 4  	 ((6x||I7N6OrR]Q^_ 	s   BNMAN$M%B,NM
4NMAN M!AN.M/N6.M $M%BM 1NN
NNNNM 	N *N
NNNz/user/updatec                   K   	 t        j                  d|        t        | |       d{   }|S 7 # t        $ r}t        j                  dj                  t        |                   t        j                  t        j                                t        |t              rYt        t        |ddt        |       d      t        j                  t        |dd	      t        |d
t        j                               t        |t              r|t        dt        |      z   t        j                  t        |dd	      t        j                         d}~ww xY ww)a  
    Example curl 

    ```
    curl --location 'http://0.0.0.0:4000/user/update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "user_id": "test-litellm-user-4",
        "user_role": "proxy_admin_viewer"
    }'
    ```
    
    Parameters:
        - user_id: Optional[str] - Specify a user id. If not set, a unique id will be generated.
        - user_email: Optional[str] - Specify a user email.
        - password: Optional[str] - Specify a user password.
        - user_alias: Optional[str] - A descriptive name for you to know who this user id refers to.
        - teams: Optional[list] - specify a list of team id's a user belongs to.
        - send_invite_email: Optional[bool] - Specify if an invite email should be sent.
        - user_role: Optional[str] - Specify a user role - "proxy_admin", "proxy_admin_viewer", "internal_user", "internal_user_viewer", "team", "customer". Info about each role here: `https://github.com/BerriAI/litellm/litellm/proxy/_types.py#L20`
        - max_budget: Optional[float] - Specify max budget for a given user.
        - budget_duration: Optional[str] - Budget is reset at the end of specified duration. If not set, budget is never reset. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d"), months ("1mo").
        - models: Optional[list] - Model_name's a user is allowed to call. (if empty, key is allowed to call all models)
        - tpm_limit: Optional[int] - Specify tpm limit for a given user (Tokens per minute)
        - rpm_limit: Optional[int] - Specify rpm limit for a given user (Requests per minute)
        - auto_create_key: bool - Default=True. Flag used for returning a key as part of the /user/new response
        - aliases: Optional[dict] - Model aliases for the user - [Docs](https://litellm.vercel.app/docs/proxy/virtual_keys#model-aliases)
        - config: Optional[dict] - [DEPRECATED PARAM] User-specific config.
        - allowed_cache_controls: Optional[list] - List of allowed cache control values. Example - ["no-cache", "no-store"]. See all values - https://docs.litellm.ai/docs/proxy/caching#turn-on--off-caching-per-request-
        - blocked: Optional[bool] - [Not Implemented Yet] Whether the user is blocked.
        - guardrails: Optional[List[str]] - [Not Implemented Yet] List of active guardrails for the user
        - permissions: Optional[dict] - [Not Implemented Yet] User-specific permissions, eg. turning off pii masking.
        - metadata: Optional[dict] - Metadata for user, store information for user. Example metadata = {"team": "core-infra", "app": "app2", "email": "ishaan@berri.ai" }
        - max_parallel_requests: Optional[int] - Rate limit a user based on the number of parallel requests. Raises 429 error, if user's parallel requests > x.
        - soft_budget: Optional[float] - Get alerts when user crosses given budget, doesn't block requests.
        - model_max_budget: Optional[dict] - Model-specific max budget for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-budgets-to-keys)
        - model_rpm_limit: Optional[float] - Model-specific rpm limit for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-limits-to-keys)
        - model_tpm_limit: Optional[float] - Model-specific tpm limit for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-limits-to-keys)
        - spend: Optional[float] - Amount spent by user. Default is 0. Will be updated by proxy whenever user is used. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d"), months ("1mo").
        - team_id: Optional[str] - [DEPRECATED PARAM] The team id of the user. Default is None. 
        - duration: Optional[str] - [NOT IMPLEMENTED].
        - key_alias: Optional[str] - [NOT IMPLEMENTED].
        - object_permission: Optional[LiteLLM_ObjectPermissionBase] - internal user-specific object permission. Example - {"vector_stores": ["vector_store_1", "vector_store_2"]}. IF null or {} then no object permission.
    
    z /user/update: Received data = %s)r  r`   Nz@litellm.proxy.proxy_server.user_update(): Exception occured - {}rW   zAuthentication Error()paramr  rV   )messageri   r/  codezAuthentication Error, )r   r   r,  rX   r   r   r4   	traceback
format_excr?   r   r   r   r   
auth_errorr   HTTP_400_BAD_REQUEST)r(   r`   r   r   s       rG   user_updater6    s+    p
""#EtL3/
 
 	

  
&&NUUA	

 	""9#7#7#9:a' 8/DSVHA-NO$//a&1Qv/J/JK	  >*G,s1v5 ++!Wf-,,	
 	
!
s1   E&3 13 E3 
EDEEEusers_to_updatec           
        K   g }d}d}	 | D ]c  }	 t        |||       d {   }|j                  t        |r|j                  d      n|j                  |j
                  d|             |dz  }e t        |t        |       ||      S 7 h# t        $ r}t        j                  d|j                  xs |j
                   d|        t        |      }	t        j                  d|j                  xs |j
                   d|	        |j                  t        |j                  |j
                  d	|	
             |dz  }Y d }~7d }~ww xY w# t        $ r5}t        j                  d|        t        ddt        |      i      d }~ww xY ww)Nr   )r  r`   r  r+   Tr+   rJ   successupdated_userr   zFailed to update user r   F)r+   rJ   r:  rT   r   total_requestedsuccessful_updatesfailed_updateszFailed to update users: r   rT   rU   )r,  rp   r%   rD   r+   rJ   rX   r   r   r4   rT   r#   rA   r   )
r7  r`   r  r   r>  r?  r  r   r   error_messages
             rG   bulk_update_processed_usersrA    s    
 ')GN2G+L&$!;!-&7'9"  $  ( %LL3!-!5!5#/#:#: $%-	 #a'") ,R &01)	
 	
O&  $$..,\-A-A-\\E\E\,]]_`a_bc !$A$**,\-A-A-\\E\E\,]]_`m_no $ , 4 4#/#:#: %+	 !#%$4  G&&)A!'EFWc!f4EFFGsc   FE BB
AB0E 	F
B	EB(E=E EE 	F	0FF		Fz/user/bulk_updatezThe litellm-changed-by header enables tracking of actions performed by authorized users on behalf of other users, providing an audit trail for accountability)r   c                   K   ddl m}m} |t        dddi      g }| j                  r| j
                  r|j                  j                  j                  dd	i
       d{   }|st        dddi      d}t        |      |kD  rt        ddd| dt        |       di      | j
                  j                  d      }t        || j
                        }	|	j                  dd       |	j                  dd       d}
d}g }	 |j                  j                  j                  i |	       d{    |D ]G  }|j                  t        |j                   |j"                  dd|j                   i|	             |
dz  }
I 	 t%        j&                  t)        j*                  |j                   xs dd|xs |j                   ||dt        |       dt-        j.                  |	                   |
dkD  r@t;        |t        |      |
|      S | j<                  r| j<                  }nt        ddd i      |st        dddi      d}t        |      |kD  rt        ddd| dt        |       di      t?        tA        tB        tD           |      ||!       d{   S 7 :7 p# t0        $ r"}t3        j4                  d|        Y d}~d}~ww xY w# t0        $ rf}t3        j6                  d|        |D ]>  }| j
                  j9                         }|j                   |_        |j                  |       @ Y d}~Nd}~ww xY w7 w)"a  
    Bulk update multiple users at once.
    
    This endpoint allows updating multiple users in a single request. Each user update
    is processed independently - if some updates fail, others will still succeed.
    
    Parameters:
    - users: Optional[List[UpdateUserRequest]] - List of specific user update requests
    - all_users: Optional[bool] - Set to true to update all users in the system
    - user_updates: Optional[UpdateUserRequest] - Updates to apply when all_users=True
    
    Returns:
    - results: List of individual update results
    - total_requested: Total number of users requested for update
    - successful_updates: Number of successful updates
    - failed_updates: Number of failed updates
    
    Example request for specific users:
    ```bash
    curl --location 'http://0.0.0.0:4000/user/bulk_update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "users": [
            {
                "user_id": "user1",
                "user_role": "internal_user",
                "max_budget": 100.0
            },
            {
                "user_email": "user2@example.com", 
                "user_role": "internal_user_viewer",
                "max_budget": 50.0
            }
        ]
    }'
    ```
    
    Example request for all users:
    ```bash
    curl --location 'http://0.0.0.0:4000/user/bulk_update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "all_users": true,
        "user_updates": {
            "user_role": "internal_user",
            "max_budget": 50.0
        }
    }'
    ```
    r   r  Nr   rT   rM   rU   
created_atdesc)orderrS   zNo users found to updatezMaximum z% users can be updated at once. Found z users.Tr  r  r+   rJ   rR   r(   r9  r   r   r  zUpdated z usersr  z!Failed to create bulk audit log: zFailed to perform bulk update: r<  zkMust specify either 'users' for individual updates or 'all_users=True' with 'user_updates' for bulk updates)r7  r`   r  )#r   r  rK   r   	all_usersuser_updatesrY   rZ   	find_manyrA   r   r  r7   update_manyrp   r%   r+   rJ   rs   r   r   r$  r   dumpsrX   r   r&  r   
model_copyr#   usersrA  r
   r   UpdateUserRequest)r(   r`   r  r  rK   r7  all_users_in_dbMAX_BATCH_SIZEr'   r
  r>  r?  r   r-   r+  r   user_update_requests                    rG   bulk_user_updaterR  <  s    F S56
 	
 	  ~~$++ - 0 0 B B L L( !M !
 
 !;<  .0x'77\]`ap]q\rryz  ++66T6J	9d&7&7

 	y$/|T2*,+	<""44@@1 A   
 ($ $#'?? $&/%TAS%T	 #a'" (##,KK 1 9 9 ?R(+= ,5,44*;1I'/O0D/EV%L$(JJ/A$B	2 !) #O 4#5-	  
**  G
 	
 78
 	
 N
?n,8N#33XY\]lYmXnnuv
 	
 -T"34oF+-  c
H<  $,,7}E 
  	< **-LQC+PQ'&*&7&7&B&B&D#.2ll#+&&':; (	<Ts   A!M#J$B!M*K 0J 1AK A+J# -B+MMM K #	K,K	K 	KK 	M AL;5M;M  Muser_idsc                    K   ddl m} |rt        |      dk(  ri S i }|D ]@  }| j                  j                  j                  |ddidd|iigd       d{   }|||<   B |S 7 w)a  
    Helper function to get the count of keys for each user using Prisma's count method.

    Args:
        prisma_client: The Prisma client instance
        user_ids: List of user IDs to get key counts for

    Returns:
        Dictionary mapping user_id to key count
    r   )UI_SESSION_TOKEN_TEAM_IDrw   Nnot)r+   ORrQ   )litellm.constantsrU  rA   rY   litellm_verificationtokenr   )rK   rS  rU  resultr+   r   s         rG   get_user_key_countsr[    s      ;s8})	F #&&@@FF"%(@ AB G 
 
  w  M
s   AA&A$A&sort_by
sort_orderc                     i }| y g d}| |vr!t        ddddj                  |       i      |j                         dvrt        dddi      |j                         || <   |S )	N)r+   rJ   rC  r   
user_aliasr:   rS   rT   z%Invalid sort column. Must be one of: z, rU   )ascrD  z+Invalid sort order. Must be 'asc' or 'desc')r   joinlower)r\  r]  order_byvalid_columnss       rG   _validate_sort_paramsre  +  s      "HM m#@=AY@Z[
 	
 0JK
 	

 #((*HWOrI   z
/user/listzFilter users by rolezGet list of users by user_idsz Get list of users by sso_user_idz#Filter users by partial email matchzFilter users by team idr   zPage number)r   ger      d   zNumber of items per page)r   rf  ler   zGColumn to sort by (e.g. 'user_id', 'user_email', 'created_at', 'spend')r`  zSort order ('asc' or 'desc')rc   sso_user_idsr   page	page_sizec	                   K   ddl m}	 |	t        ddd|	 i      |dz
  |z  }
i }| r| |d	<   |rTt        |t              rD|j                  d
      D cg c]#  }|j                         s|j                         % }}d|i|d<   |t        |t              r|dd|d<   |t        |t              rd|i|d<   |Tt        |t              rD|j                  d
      D cg c]#  }|j                         s|j                         % }}d|i|d<   |j                         D ci c]  \  }}|	|| }}}|t        |t              rt        ||      nd}|	j                  j                  j                  ||
||r|nddi       d{   }|	j                  j                  j                  |       d{   }|-t        |	|D cg c]  }|j                   c}       d{   }ni }t        j                   d|        | |z   }g }|N|D ]H  }|j#                  t%        di |j'                         d|j)                  |j                  d      i       J ng }|||||dS c c}w c c}w c c}}w 7 7 c c}w 7 w)a  
    Get a paginated list of users with filtering and sorting options.

    Parameters:
        role: Optional[str]
            Filter users by role. Can be one of:
            - proxy_admin
            - proxy_admin_viewer
            - internal_user
            - internal_user_viewer
        user_ids: Optional[str]
            Get list of users by user_ids. Comma separated list of user_ids.
        sso_ids: Optional[str]
            Get list of users by sso_ids. Comma separated list of sso_ids.
        user_email: Optional[str]
            Filter users by partial email match
        team: Optional[str]
            Filter users by team id. Will match if user has this team in their teams array.
        page: int
            The page number to return
        page_size: int
            The number of items per page
        sort_by: Optional[str]
            Column to sort by (e.g. 'user_id', 'user_email', 'created_at', 'spend')
        sort_order: Optional[str]
            Sort order ('asc' or 'desc')
    r   r   Nr   rT   zNo db connected. prisma client=rU   r   r:   ,inr+   rN   containsrP   rJ   hasr3   sso_user_idrC  rD  rR   skiptakerE  rQ   zTotal count of users: 	key_count)rM  totalrk  rl  total_pagesr   )r   rK   r   r?   r4   splitr\   r>   re  rY   rZ   rI  r   r[  r+   r   r   rp   LiteLLM_UserTableWithKeyCountr   rD   )rc   rS  rj  rJ   r   rk  rl  r\  r]  rK   ru  where_conditionsuiduser_id_listsidsso_id_listr   r  rc  rM  total_countr-   user_key_countsry  	user_lists                            rG   	get_usersr  O  s    z 9>}oNO
 	
 1H	!D (*(,%Jx-/7~~c/BRciik		RR,'
# *Z"="!*
&
 JtS14%
! J|S$A.:.@.@.EUssyy{UU++
'
 *:)?)?)ASAQ]1SS :gs#; 	gz2   ""44>> H|V&< ?  E &((::@@GW@XXK  3U;TDLL;!
 
 !7}EF !LI-.K 68ID- oo'3B3F3Ft||UV3W  	 " M S" V T Y
 <
s{   AI?I$)I$;A!I?I)2I)I? 
I.+I.0AI?I4-I?3I64I?I8

I?!I="BI?6I?8I?z/user/deletec                   K   ddl m} ddlm}m}m} |t        dddi      | j                  t        d	dd
i      | j                  D ]+  }|j                  j                  j                  d|i       d{   }|t        ddd| i      t        j                  du r|j                  d      }	t        j                   |t!        t#        t%        j&                               t)        j*                  t,        j.                        |xs |j0                  xs ||j2                  t4        j6                  |dd|		                   |j                  j8                  j;                  dd|j<                  ii       d{   }
g }|
D ]  } |t?        di |jA                         tC        |jD                  |j0                  |jF                              \  }}|sT|D cg c]  }|jA                          }}t        jH                  |      |_%        |jM                  |        |D ]I  }|j                  j8                  jO                  d|jD                  id|jJ                  i       d{    K . |j                  jP                  jS                  dd| j                  ii       d{    |j                  jT                  jS                  dd| j                  ii       d{    |j                  jV                  jS                  dd| j                  ii       d{    |j                  jX                  jS                  dd| j                  ii       d{    |j                  j                  jS                  dd| j                  ii       d{   }|S 7 .7 )c c}w 7 C7 7 7 7 W7 w)a{  
    delete user and associated user keys

    ```
    curl --location 'http://0.0.0.0:4000/user/delete' 
    --header 'Authorization: Bearer sk-1234' 
    --header 'Content-Type: application/json' 
    --data-raw '{
        "user_ids": ["45e3e396-ee08-4a61-a88e-16b3ce7e0849"]
    }'
    ```

    Parameters:
    - user_ids: List[str] - The list of user id's to be deleted.
    r   )_cleanup_members_with_roles)create_audit_log_for_updater  rK   Nr   rT   No db connectedrU   rS   zNo user id passed inr+   rQ   i  zUser not found, passed user_id=Tr  deletedz{})	id
updated_at
changed_bychanged_by_api_keyr.   	object_idr  updated_valuesr  )request_datarw   ro  )rw   r+   rJ   )existing_team_rowr(   members_with_rolesrF  r   )-r|   r  r   r  r  rK   r   rS  rY   rZ   find_uniquer8   store_audit_logsr   rs   r   LiteLLM_AuditLogsr4   r5   r6   r   nowr   utcr+   api_keyLitellmTableNamesUSER_TABLE_NAMElitellm_teamtablerI  r3   r   r   TeamMemberDeleteRequestrw   rJ   rK  r  rp   updaterY  delete_manylitellm_invitationlinklitellm_organizationmembershiplitellm_teammembership)r(   r`   r  r  r  r  rK   r+   user_row	_user_rowfetch_all_teamsteams_to_updater   is_member_in_teamnew_team_membersm_db_new_team_membersdeleted_userss                     rG   delete_userr    s    @  W>O4PQQ}}W>T4UVV ==&));;GGg& H 
 
 #B7)!LM  ''4/$MMtM<	##/%6"4::<0'/||HLL'A'9 (8088(87/@/H/H'8'H'H&-#,+/)2&& !. 0 0 B B L LtX^^45 !M !
 
 #D2M"3"Hdoo6G"H, LL$,,'223// !,<4'(ALLN4$ 4 +/**5I*J'&&t, $$ $D""44;; $,,/*D,C,CD <    $u !D 


4
4
@
@4/0 A   
 


1
1
=
=4/0 >   
 


9
9
E
E4/0 F   
 


1
1
=
=4/0 >   
 (**<<HH4/0 I  M s
F
4



s   A8O:N(;DON+AOO#N.:A6O0N31A O1N62;O-N9.;O)N;*;O%N=&;O!N?"O+O.O6O9O;O=O?Ord   c                 r  K   ddl m} |t        d      	 |j                  j                  j                  d|i       d{   }|t        d|       |j                  j                  j                  | ||d	       d{   }|S 7 H7 # t        $ r}t        d
t        |             d}~ww xY ww)a  
    Helper function to add an internal user to an organization

    Adds the user to LiteLLM_OrganizationMembership table

    - Checks if organization_id exists

    Raises:
    - Exception if database not connected
    - Exception if user_id or organization_id not found
    r   r   NrM   rd   rQ   z/Organization not found, passed organization_id=)r+   rd   r:   )r(   z$Failed to add user to organization: )	r   rK   rX   rY   litellm_organizationtabler  r  creater4   )r+   rd   r:   rK   organization_rownew_membershipr   s          rG   !add_internal_user_to_organizationr  z  s       9011I!.!1!1!K!K!W!W$o6 "X "
 
 #A/ARS 
  -//NNUU"#2&  V  
 
 %

  I>s1vhGHHIsM   B7+B BAB BB 
B7B B 	B4B//B44B7z/user/filter/ui   model)r   r   r   	responsesz$User email in the request parameterszPage number for pagination)r   r   rf  2   )r   r   rf  ri  c           	        K   ddl m} |t        dddi      	 |dz
  |z  }i }| r| d	d
|d<   |r|d	d
|d<   |j                  j                  j                  |||ddi       d{   }|sg S |D 	cg c]  }	t        di |	j                          c}	S 7 /c c}	w # t        $ r?}
t        j                  dt        |
              t        ddt        |
             d}
~
ww xY ww)a
  
    [PROXY-ADMIN ONLY]Filter users based on partial match of user_id or email with pagination.

    Args:
        user_id (Optional[str]): Partial user ID to search for
        user_email (Optional[str]): Partial email to search for
        page (int): Page number for pagination (starts at 1)
        page_size (int): Number of items per page (max 100)
        user_api_key_dict (UserAPIKeyAuth): User authentication information

    Returns:
        List[LiteLLM_SpendLogs]: Paginated list of matching user records
    r   r   Nr   rT   r  rU   r   rN   rp  r+   rJ   rC  rD  rt  zError searching users: r   )r   rK   r   rY   rZ   rI  LiteLLM_UserTableFilteredr   rX   r   r   r4   )r+   rJ   rk  rl  r`   rK   ru  r|  rM  r-   r   s              rG   ui_view_usersr    s&    J 9W>O4PQQ$XqI% #%+Y'
 &%.\*  ""44>>&#V,	 ?   	 IKPQ4)>DOO,=>QQ R X&&)@Q'IJ6McRSfX4VWWXsY   C)AB 'B(B /C)0B 4 BB C)B B 	C&':C!!C&&C)group_metricsrecordc                 N   | xj                   |j                   z  c_         | xj                  |j                  z  c_        | xj                  |j                  z  c_        | xj                  |j                  z  c_        | xj                  |j                  z  c_        | xj
                  |j                  |j                  z   z  c_        | xj                  |j                  z  c_        | xj                  |j                  z  c_        | xj                  |j                  z  c_        | S r   )	r   prompt_tokenscompletion_tokenscache_read_input_tokenscache_creation_input_tokenstotal_tokensapi_requestssuccessful_requestsfailed_requests)r  r  s     rG   update_metricsr    s     6<<'6#7#77##v'?'??#))V-K-KK)--1S1SS-&"6"69Q9Q"QQ&"5"55%%)C)CC%!!V%;%;;!rI   	breakdownmodel_metadataprovider_metadataapi_key_metadatac           	         |j                   r|j                   | j                  vrFt        t               |j	                  |j                   i             | j                  |j                   <   t        | j                  |j                      j                  |      | j                  |j                      _        |j                  xs d}|| j                  vr2t        t               |j	                  |i             | j                  |<   t        | j                  |   j                  |      | j                  |   _        |j                  | j                  vr`t        t               t        |j	                  |j                  i       j	                  dd                  | j                  |j                  <   t        | j                  |j                     j                  |      | j                  |j                     _        | S )zXUpdates breakdown metrics for a single record using the existing update_metrics function)metricsr  unknown	key_aliasN)r  )r  r0   r   r!   rD   r  r  custom_llm_provider	providersr  api_keysr   r   )r  r  r  r  r  providers         rG   update_breakdown_metricsr    s    ||<<y///-?$'++LL".IV\\* 2@V\\*22F2
	&.
 ))6YHy***(: N&**")
	H% -;H%--v-I!)
 ~~Y///-B N *..v~~rBFF.
	6>>* 2@6>>*22F2Iv~~&. rI   z/user/daily/activityzBudget & Spend TrackingzStart date in YYYY-MM-DD formatzEnd date in YYYY-MM-DD formatzFilter by specific modelzFilter by specific API keyzItems per pagei  
start_dateend_dater  c                   K   ddl m} |'t        ddt        j                  j
                  i      | |t        t        j                  ddi      	 d}t        |      s|j                  }t        |dd	|d| |||||
       d{   S 7 # t        $ r[}	t        j                  dj                  t        |	                   t        t        j                   ddt        |	       i      d}	~	ww xY ww)ad  
    [BETA] This is a beta endpoint. It will change.

    Meant to optimize querying spend data for analytics for a user.

    Returns:
    (by date)
    - spend
    - prompt_tokens
    - completion_tokens
    - cache_read_input_tokens
    - cache_creation_input_tokens
    - total_tokens
    - api_requests
    - breakdown by model, api_key, provider
    r   r   Nr   rT   rU   z&Please provide start_date and end_datelitellm_dailyuserspendr+   )rK   r.   entity_id_field	entity_identity_metadata_fieldr  r  r  r  rk  rl  z./spend/daily/analytics: Exception occured - {}zFailed to fetch analytics: )r   rK   r   r   r   r=   r   r5  r   r+   r   rX   r   r   r   r4   HTTP_500_INTERNAL_SERVER_ERROR)
r  r  r  r  rk  rl  r`   rK   r  r   s
             rG   get_user_daily_activityr  <  s    ^ 9.EEKKL
 	

 X-33EF
 	


#'	#$56)11I''/%"&!
 
 	
 
  
&&<CCCFK	
 ==:3q6(CD
 	
	
s=   AC42B BB 
C4B 	C1AC,,C11C4)NNr-   r   )i__doc__rs   r   r2  r5   r   r   typingr   r   r   r   r	   r
   fastapir   r   r   r   r   r   r8   litellm._loggingr   litellm.proxy._types$litellm.proxy.auth.user_api_key_authr   /litellm.proxy.hooks.user_management_event_hooksr   8litellm.proxy.management_endpoints.common_daily_activityr   /litellm.proxy.management_endpoints.common_utilsr   ;litellm.proxy.management_endpoints.key_management_endpointsr   r   &litellm.proxy.management_helpers.utilsr   litellm.proxy.utilsr   >litellm.types.proxy.management_endpoints.common_daily_activityr   r   r   r   r   r    r!   @litellm.types.proxy.management_endpoints.internal_user_endpointsr"   r#   r$   r%   TYPE_CHECKINGr   r&   routerr   NewUserRequestrH   r4   r^   UserAPIKeyAuthrv   floatLiteralr   r   r   r   postr   r   rD   r   r   TeamListResponseObjectLiteLLM_TeamMembershipr   r   Queryr   r   r   r   rN   UpdateUserRequestNoUserIDorEmailr  r,  r6  rA  rR  r[  re  intr  DeleteUserRequestr  r;   r  r  r  r  r  r  r   rI   rG   <module>r     sC
       ' 9 9  N N  1 " B T W P O 9    7	- -N -t -`.1	> 9 99 9 " 9 &	 9N !%*.*0777 &7 	7
 !7 '7t8E$s)TBT=U2U,V#W 0999 &9 cD!3445	9
 "9< 
$	%+,-"	    )00A(B\+
\+%\+ \+~ 
$	%+,-	   )00A(B%:
d#45t<R7SSTU

 e%'==>?
g (3- ( 
$	%+,-    +W]]"E )00A(BA+A+c]A+
 &A+ A+H-`'
412
3'd#45t<R7SSTU'T.. !24T!TU.	.h )-F#F%F !F 
#s(^	FR 
$	%+,-  
  )00A(BN

N
%N
 N
h )-<G+,<G%<G !<G 	<G~ 
$	%+,-)	    )00A(B(. t)@
@%@ !@ @J %)"tCy!"J!c]!(+!d38n!H 
$	%+,-#	   ('--"8 ,gmm"A #0'--"D# !."G! ('--"; aA=I"W]]qS.H +W]]] $gmm#A1U
3-U sm	U 3-U U 3-U  !U" #U( c])U0 1UUp 
$	%+,-  
  )00A(B(. t)D
D%D !D DN+I+I+I  +I\ 
$	%+,-gt567   +W]]"E !."H! ; #W]] :qS )00A(BEXc]EX 	EX EX EX &EXEXP)?11"1 d38n,-1 Cc3h/0	1
 3S#X./1 1h 
#%?	@+,-2	   !.5! ,gmm3 )7==. +W]]0 ; #W]] 0Q4 )00A(B/Q
Q

 smQ
 C=Q
 c]Q
" #Q
( )Q
. &/Q
0 %1Q
Q
rI   