
    h                       d dl Z d dlZd dlZd dlZd dl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 d dlmZ d dlmZmZmZmZmZmZmZmZmZ d dlmZ d dlmZmZmZmZm Z m!Z! d dl"m#Z# 	 d dl$Z$d d
l&m'Z'm(Z( d dl)Z)d dl*Z)d dl+Z)d dl)m,Z,m-Z-m.Z.m/Z/m0Z0 d dl1m2Z2 d dl3m4Z4m5Z5 d dl6m7Z7m8Z8 d dl9m:Z: d dl;m<Z< d dl=m>Z> d dl?m@Z@ d dlAmBZB d dl+mCZC d dlDmEZE d dlFmGZG d dlHmIZI d dlmJZJmKZKmLZLmMZMmNZN d dlOmPZP d dlQmRZRmSZS d dlTmUZU d dlVmWZW d dlXmYZY d dlZm[Z[m\Z\ d dl]m^Z^ d d l_m`Z` d d!lambZb d d"lcmdZd d d#lemfZf d d$lgmhZh d d%limjZjmkZkmlZl erd d&lmmnZo eeoef   ZnneZnd' Zpd( Zq G d) d*      Zr G d+ d,      Zsd- Ztd.eud/eufd0Zv G d1 d2      Zwd3exd4e7d5ewfd6Zy	 	 	 dcd7eex   d8eex   d9eex   fd:Zzd;exfd<Z{d;exd/exfd=Z| G d> d?      Z}d@ewdAeeI   dBesfdCZ~dDedEedBesfdFZdGedHee   fdIZdGedHee   d/ee   fdJZdcdKZdL Zd.eudMee0   d/eufdNZd.eudOed/eufdPZdDed/exfdQZd/eex   fdRZd/eex   fdSZdDed/efdTZdU ZdVeex   dMee0   d/efdWZdXexdYexd/exfdZZddd[exdYeex   d/exfd\Zd/eex   fd]Zd/exfd^Zd_exfd`Zdaexd/efdbZy# e%$ r	  e%d	      w xY w)e    N)datetime	timedelta)MIMEMultipart)MIMEText)	TYPE_CHECKINGAnyDictListLiteralOptionalUnioncastoverload)MAX_TEAM_LIST_LIMIT)DB_CONNECTION_ERROR_TYPESCommonProxyErrorsProxyErrorTypesProxyExceptionSpendLogsMetadataSpendLogsPayloadGuardrailEventHookszEbackoff is not installed. Please install it via 'pip install backoff')HTTPExceptionstatus)EmbeddingResponseImageResponseModelResponseModelResponseStreamRouter)verbose_proxy_logger)ServiceLoggingServiceTypes)	DualCache
RedisCache)RejectedRequestError)CustomGuardrail)CustomLogger)SlackAlerting)_add_langfuse_trace_id_to_alert)Logging)
safe_dumps)safe_json_loads)HTTPHandler)	AlertTypeCallInfoLiteLLM_VerificationTokenViewMemberUserAPIKeyAuth)RouteChecks)create_missing_viewsshould_create_missing_views)DBSpendUpdateWriter)log_db_metrics)PrismaWrapper)PROXY_HOOKSget_proxy_hook)_PROXY_CacheControlCheck)_PROXY_MaxBudgetLimiter)!_PROXY_MaxParallelRequestsHandler)LiteLLMProxyRequestSetup)str_to_bool)DEFAULT_ALERT_TYPES)	CallTypesLLMResponseTypesLoggedLiteLLMParams)Spanc                     ddl }t        j                  dj                  |  |j                                      t
        j                  rt        d|         yy)a  
    Prints the given `print_statement` to the console if `litellm.set_verbose` is True.
    Also logs the `print_statement` at the debug level using `verbose_proxy_logger`.

    :param print_statement: The statement to be printed and logged.
    :type print_statement: Any
    r   Nz{}
{}zLiteLLM Proxy: )	tracebackr    debugformat
format_exclitellmset_verboseprint)print_statementrF   s     O/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/proxy/utils.pyprint_verboserO   e   sJ     x@T	@T@T@VWX012     c                     t         j                  du r| S d}d}t        | t              rd| v rd| d   v r| d   j	                  d      }t        j                  |       }t        | t              r|d| v r|| d   d<   |S )z
    Safe Deep Copy

    The LiteLLM Request has some object that can-not be pickled / deep copied

    Use this function to safely deep copy the LiteLLM Request
    TNmetadatalitellm_parent_otel_span)rJ   safe_memory_mode
isinstancedictpopcopydeepcopy)datarS   new_datas      rN   safe_deep_copyr\   t   s     4'.2#$"<Z@P"P'+J'7';';<V'W$}}T"H $":"F;SD78OrP   c            	           e Zd ZdefdZ	 ddeedf   dedefdZ		 ddeedf   deddfdZ
	 dd	edeedf   deddfd
Z	 	 ddedee   defdZ	 ddedeedf   defdZ	 ddeddfdZ	 ddedefdZy)InternalUsageCache
dual_cachec                     || _         y Nr_   )selfr_   s     rN   __init__zInternalUsageCache.__init__   s	    %/rP   rS   N
local_onlyreturnc                 ^   K    | j                   j                  d|||d| d {   S 7 w)N)keyre   parent_otel_span )r_   async_get_cache)rc   rh   rS   re   kwargss        rN   rk   z"InternalUsageCache.async_get_cache   sC      5T__44 
!5
 	
 
 	
 
   $-+-c                 `   K    | j                   j                  d||||d| d {   S 7 w)N)rh   valuere   rS   rj   )r_   async_set_cacherc   rh   ro   rS   re   rl   s         rN   rp   z"InternalUsageCache.async_set_cache   sF      5T__44 
!%=	

 
 
 	
 
   %.,.
cache_listc                 ^   K    | j                   j                  d|||d| d {   S 7 w)N)rs   re   rS   rj   )r_   async_set_cache_pipeline)rc   rs   rS   re   rl   s        rN   async_batch_set_cachez(InternalUsageCache.async_batch_set_cache   sC      >T__== 
!!%=
 	
 
 	
 
rm   keysri   c                 Z   K   | j                   j                  |||       d {   S 7 w)N)rw   ri   re   )r_   async_batch_get_cache)rc   rw   ri   re   s       rN   ry   z(InternalUsageCache.async_batch_get_cache   s7      __::-! ; 
 
 	
 
s   "+)+ro   c                 `   K    | j                   j                  d||||d| d {   S 7 w)N)rh   ro   re   ri   rj   )r_   async_increment_cacherq   s         rN   r{   z(InternalUsageCache.async_increment_cache   sF      ;T__:: 
!5	

 
 
 	
 
rr   c                 B     | j                   j                  d|||d|S )N)rh   ro   re   rj   )r_   	set_cache)rc   rh   ro   re   rl   s        rN   r}   zInternalUsageCache.set_cache   s5     )t(( 
!
 	
 	
rP   c                 @     | j                   j                  d||d|S )N)rh   re   rj   )r_   	get_cache)rc   rh   re   rl   s       rN   r   zInternalUsageCache.get_cache   s2     )t(( 
!
 
 	
rP   F)NF)__name__
__module____qualname__r#   rd   r   rD   boolr   rk   rp   r
   rv   listr   ry   floatr{   r}   r   rj   rP   rN   r^   r^      sC   09 0 !	
 #(d
"3
 	
 

& !
 #(d
"3	

 
 

( !	

 #(d
"3
 	
 

" ,0 	



 #4.

 	

" !
 
 #(d
"3	

 
( !	
 	
 

" !

 


 


rP   r^   c                      e Zd ZdZ	 d?dedefdZdee   dee	   fdZ
	 	 	 	 	 	 d@d	ee   d
ee   dee	   deee      dee   dee   fdZdAdee   fdZdedee   fdZdAdee   fdZdeded   fdZd Zededdded   ddfd       Zedededed   defd       Zdedee   ded   dee   fd Zdededed!   fd"Zd#ed$efd%Zd&ed'   d(efd)Z	 dAd*ed+ed,   d-ed.ee   fd/Z	 dBd0edefd1Z 	 	 	 dCd.ed2e!ded3ee"   d4ee   d5ee   fd6Z#	 	 dDd2e!d3ee"   d4ee   defd7Z$	 	 dDd.eded4ee   d2ee!   fd8Z%ded9e&defd:Z'	 dAded9e(e)e*e+e,f   ded;ee   fd<Z-ded.efd=Z.dAdee   fd>Z/y)EProxyLoggingz
    Logging/Custom Handlers for proxy.

    Implemented mainly to:
    - log successful/failed db read/writes
    - support the max parallel request integration
    user_api_key_cachepremium_userc                     i | _         || j                   d<   t        t        d            | _        t	        | j                        | _        t               | _        t               | _	        d | _
        d| _        t        | _        d | _        t        | j                  | j                  | j                  j                         | _        || _        t'               | _        t+               | _        i | _        d| _        d| _        y )Nr      )default_in_memory_ttlrb   i,  )alerting_thresholdalertinginternal_usage_cacheF)call_detailsr^   r#   r   r=   max_parallel_request_limiterr<   max_budget_limiterr;   cache_control_checkr   r   r@   alert_typesalert_to_webhook_urlr(   r_   slack_alerting_instancer   r!   service_logging_objr6   db_spend_update_writerproxy_hook_mappingdaily_report_startedhanging_requests_check_started)rc   r   r   s      rN   rd   zProxyLogging.__init__   s     #%2D./8J q99
! -N%%-
) #:";#;#= (,),,?48!6C#66]]!%!:!:!E!E7
$
 )#1#3 &9&;#;= +0!49+rP   
llm_routerredis_usage_cachec                 N   | j                   j                  |       | j                  |       | j                  |       | j                   Zd| j                   j                  v rB| j                  s6t        j                  | j                   j                  |             d| _        | j                   st        j                  | j                   j                  v rL| j                  s?t        j                  | j                   j                  j                                d| _
        yyyy)z0Initialize logging and alerting on proxy startupr   )redis_cacheNdaily_reportsT)r   update_values_init_litellm_callbacksr   r   asynciocreate_task_run_scheduled_daily_reportr.   llm_requests_hangingr   hanging_request_checkcheck_for_hanging_requests)rc   r   r   s      rN   startup_eventzProxyLogging.startup_event"  s    	$$22j2I 	) 	 	
 	$$! 	% 	

 ((44#?#?#K#KK--,,HH) I 
 )-D% ((4..++77877,,BB]]_ 37D/ 88 5rP   Nr   r   r   r   alerting_argsr   c                    d}|	|| _         d}|	|| _        d}|	|| _        d}|	|| _        d}|du r| j                  j                  | j                   | j                  | j                  || j                         | j                   d| j                   v rd| j                  v sd| j                  v sd| j                  v r)t        j                  j                  | j                         t        j                  j                  | j                  j                         |R|| j                  j                  _        || j                  j                  _        || j                  j                   _        y y )NFT)r   r   r   r   r   slackr   outage_alertsregion_outage_alerts)r   r   r   r   r   r   rJ   logging_callback_manageradd_litellm_callbackadd_litellm_success_callback!response_taking_too_long_callbackr   r_   r   r   redis_update_bufferpod_lock_manager)rc   r   r   r   r   r   r   updated_slack_alertings           rN   r   zProxyLogging.update_valuesK  sh    (-$DM%)")&8D#%)""*D%)"+(<D%%)"!T)((66#'#:#: ,,+%)%>%> 7  }}(W-E $t'7'77&$*:*::-1A1AA44II$JfJfg00MM00RR "?JD%%00<JUD'';;GGRD''88D #rP   c           	      >   ddl m} t        D ]  }t        |      }ddl}|j                  |      j                  }i }d|v r| j                  |d<   d|v r||d<   t        t         |di |      }t        j                  j                  |       || j                  |<    y)z6
        Add proxy hooks to litellm.callbacks
        r   prisma_clientNr   r   rj   )litellm.proxy.proxy_serverr   r9   r:   inspectgetfullargspecargsr   r   r'   rJ   r   r   r   )	rc   r   r   hook
proxy_hookr   expected_argspassed_in_argsproxy_hook_objs	            rN   _add_proxy_hookszProxyLogging._add_proxy_hooks}  s     	=D'-J#22:>CCM-/N%69=9R9R56-/2?/!,
0L^0LMN,,AA.Q,:D##D)  rP   r   rf   c                 8    | j                   j                  |      S )z>
        Get a proxy hook from the proxy_hook_mapping
        )r   get)rc   r   s     rN   r:   zProxyLogging.get_proxy_hook  s     &&**400rP   c                 "   | j                  |       t        j                  j                  | j                         t        j
                  D ]~  }t        |t              rCt        j                  j                  j                  || j                  j                  |      }|W|t        j                  vrt        j                  j                  |       |t        j                  vrt        j                  j!                  |       |t        j"                  vrt        j                  j%                  |       |t        j&                  vrt        j                  j)                  |       |t        j*                  vrt        j                  j-                  |       |t        j.                  vs`t        j.                  j                  |        t1        t        j                        dkD  s8t1        t        j                        dkD  st1        t        j"                        dkD  rot3        t5        t        j                  t        j                  z   t        j"                  z               }t        j                  j                  j7                  |       y y )N)r   r   r   )callback_list)r   rJ   r   r   r   	callbacksrU   strlitellm_core_utilslitellm_logging$_init_custom_logger_compatible_classr   r_   input_callbackappendsuccess_callbackr   failure_callbackadd_litellm_failure_callback_async_success_callback"add_litellm_async_success_callback_async_failure_callback"add_litellm_async_failure_callbackservice_callbacklenr   setset_callbacks)rc   r   callbackr   s       rN   r   z$ProxyLogging._init_litellm_callbacks  s   j)((==d>V>VW))H(C("55EEjj)-)B)B)M)M) k 
 #w555&&--h7w77700MMhWw77700MMhWw>>>00SST\]w>>>00SST\]w777((//9) *. &&'!+7++,q07++,q0 **../../M &&66DD+ E  1rP   litellm_call_idr   )successfailc                    K   | j                   y | j                  }|dz  }| j                  j                  dj	                  |      |d|d        d {    y 7 w)Nd   zrequest_status:{}T)rh   ro   re   ttlrS   )r   r   r   rp   rH   )rc   r   r   r   s       rN   update_request_statusz"ProxyLogging.update_request_status  sm      ==  %)$;$; 	c!''77#**?;"%) 8 
 	
 	
s   AAAAc                    K   t        |t              r|t        |t              r|S t        |t              r2|dv rt	        ||j                  dd      d|      t        dd|i      |S w)N)
completiontext_completionmodel )messager   llm_providerrequest_data  errorstatus_codedetail)rU   	ExceptionrV   r   r%   r   r   )rc   responserZ   	call_types       rN   process_pre_call_hook_responsez+ProxyLogging.process_pre_call_hook_response  st     h	*Nh%Oh$==*$((7B/!#!%	  $Wh<OPPs   A)A+user_api_key_dictrZ   r   )r   r   
embeddingsimage_generation
moderationaudio_transcriptionpass_through_endpointrerankc                    K   y wra   rj   rc   r   rZ   r   s       rN   pre_call_hookzProxyLogging.pre_call_hook         	   c                    K   y wra   rj   r   s       rN   r   zProxyLogging.pre_call_hook  r   r   c                   K   t        j                  d       | j                  |       |y	 t        j                  D ]b  }d}t        |t              r*t        j                  j                  j                  |      }n|}|t        |t              rpddlm} |j                  ||j                        durz|j                  || j                   d   ||	       d{   }|| j#                  |||
       d{   }|t        |t$              sdt'        |j(                        v s|j(                  j                  t$        j                  k7  s|j                  || j                   d   ||	       d{   }|G| j#                  |||
       d{   }e |S 7 7 7 -7 # t*        $ r}|d}~ww xY ww)z
        Allows users to modify/reject the incoming request to the proxy, without having to deal with parsing Request body.

        Covers:
        1. /chat/completions
        2. /embeddings
        3. /image/generation
        z#Inside Proxy Logging Pre-call hook!rZ   Nr   r   rZ   
event_typeTr   )r   cacherZ   r   )r   rZ   r   async_pre_call_hook)r    rG   #_init_response_taking_too_long_taskrJ   r   rU   r   r   r   "get_custom_logger_compatible_classr&   litellm.types.guardrailsr   should_run_guardrailpre_callr  r   r   r'   vars	__class__r   )	rc   r   rZ   r   r   	_callbackr   r   es	            rN   r   zProxyLogging.pre_call_hook  s    . 	""#HI00d0;<3	#-- 	h, ' : : J J m m !I !)I(Z	?-SL "66!%2E2N2N 7   $$
 !%.%B%B*;"//0DE!"+	 &C &  H  +%)%H%H%-DI &I &  
 )"9l;-i6I6I1JJ!++??#778 &/%B%B*;"//0DE!"+	 &C &  H  +%)%H%H%-DI &I &  Y .` K;    
  	G	s   +GB/F. F&F. %F. <F(=F. F. F. .'F. %F. <F*=F. F. F,F. %G&F. (F. *F. ,F. .	F>7F99F>>G)r   	responsesr   r   r   r   c                 Z  K   t         j                  D ]~  }	 t        |t              rk|j                  t        |d      r|j                  dk(  r( yddlm} |j                  ||j                        durc|j                  |||       d{     |S 7 # t        $ r}|d}~ww xY ww)	zD
        Runs the CustomGuardrail's async_moderation_hook()
        Nmoderation_checkr  r   r   r  T)rZ   r   r   )rJ   r   rU   r&   
event_hookhasattrr  r	  r   r
  during_callasync_moderation_hookr   )rc   rZ   r   r   r   r   r  s          rN   during_call_hookzProxyLogging.during_call_hook`  s        ))Hh8  **2w "48 $44
B" Q %99%)6I6U6U :  $((
 %"88!*;"+ 9   1 *> 
  sR   B+7BB+%B5B+6BBBB+B	B(!B##B((B+error_messagefailing_modelc                    K   | j                   y | j                  r&| j                  j                  ||       d {    y y 7 w)N)r  r  )r   r   failed_tracking_alert)rc   r  r  s      rN   r  z"ProxyLogging.failed_tracking_alert  sR     
 == ''..DD++ E    (s   :AAAtype)token_budgetuser_budgetsoft_budgetteam_budgetproxy_budgetprojected_limit_exceeded	user_infoc                 t   K   | j                   y | j                  j                  ||       d {    y 7 w)N)r  r#  )r   r   budget_alerts)rc   r  r#  s      rN   r%  zProxyLogging.budget_alerts  s>      == **88 9 
 	
 	
s   .868r   level)LowMediumHigh
alert_typer   c           
        K   | j                   yddlm}  |j                         j                  d      }t	        j
                  dd      }d| d| d| }|	|d	| d
z  }i }	i }
|ft        |       d{   }|||	d<   |dj                  |      z  }d|v r3|d   j                  dd      t        |d   d   t              r|d   d   }
| j                   D ]  }|dk(  r+ | j                  j                  d|||d|
d|	 d{    3|dk(  s9t        j                  j                  *t        j                  j                  j!                  |       }t#        d       y7 7 ^w)a  
        Alerting based on thresholds: - https://github.com/BerriAI/litellm/issues/1298

        - Responses taking too long
        - Requests are hanging
        - Calls are failing
        - DB Read/Writes are failing
        - Proxy Close to max budget
        - Key Close to max budget

        Parameters:
            level: str - Low|Medium|High - if calls might fail (Medium) or are failing (High); Currently, no alerts would be 'Low'.
            message: str - what is the alert about
        Nr   )r   z%H:%M:%SPROXY_BASE_URLzLevel: `z`
Timestamp: `z`

Message: z

Proxy URL: ``r   u   🪢 Langfuse Traceu   

🪢 Langfuse Trace: {}rR   alerting_metadatar   )r   r&  r*  r#  r/  sentryz#Missing SENTRY_DSN from environmentrj   )r   r   nowstrftimeosgetenvr)   rH   r   rU   rV   r   
send_alertrJ   utilssentry_sdk_instancecapture_messager   )rc   r   r&  r*  r   r   current_time_proxy_base_urlformatted_messageextra_kwargsr/  _urlclients                rN   alerting_handlerzProxyLogging.alerting_handler  s    * == % $x||~..z:))$4d;ug_\N.	R 	 &#3O3DA!FF#8lSSD6:23!%B%I%I$%OO!l* ,001DdKW|J78KLdS$0$<=P$Q!mmF =d22== #)"&7 #   8#==44@MM55EEFWX#$IJJ $ Ts,   A5E(7E$8BE(E&
E(AE(&E(durationc                   K   t         j                  | j                  vryt        |t              rmt        |j
                  t              r|j
                  }nQt        |j
                  t              r t        j                  |j
                        }nt        |      }nt        |      }t        |t              r||dd z  }t        j                  | j                  d| dt         j                  i              t        | d      r5| j                  j                  t         j"                  |||       d{    t$        j&                  j(                  r!t$        j&                  j)                  |       yy7 @w)	z]
        Log failed db read/writes

        Currently only logs exceptions to sentry
        N  zDB read/write call failed: r)  r   r&  r*  r   r   )servicer@  r   r   )r   )r.   db_exceptionsr   rU   r   r   r   rV   jsondumpsr   r   r?  r  r   async_service_failure_hookr"   DBrJ   r6  capture_exception)rc   original_exceptionr@  r   traceback_strr  s         rN   failure_handlerzProxyLogging.failure_handler  sG     ""$*:*::(-8,33S9 2 9 9.55t< $

+=+D+D E #$6 7 23MmS)]5D11M!!5m_E$22	 " 	
 4./**EE$!##	 F    ==**MM++2D+E +s   D3E85E66AE8rK  
error_typerouterL  c           	      f  K   | j                  |j                  dd      d       d{    t        j                  | j                  v rjt        |t              sZ	 t        |dd      }t        |      }|||z  }t        j                  | j                  d| dd	t        j                  |
             | j                  |||j                        r| j                  ||||       d{    t        j                   D ]{  }		 d}
t        |	t              r*t        j"                  j$                  j'                  |	      }
n|	}
|
8t        |
t(              r(t        j                  |
j+                  ||||             } y7 U7 # t,        $ r"}t/        j0                  d|        Y d}~d}~ww xY ww)a  
        Allows users to raise custom exceptions/log when a call fails, without having to deal with parsing Request body.

        Covers:
        1. /chat/completions
        2. /embeddings
        3. /image/generation

        Args:
            - request_data: dict - The request data.
            - original_exception: Exception - The original exception.
            - user_api_key_dict: UserAPIKeyAuth - The user api key dict.
            - error_type: Optional[ProxyErrorTypes] - The error type.
            - route: Optional[str] - The route.
            - traceback_str: Optional[str] - The traceback string, sometimes upstream endpoints might need to send the upstream traceback. In which case we use this
        r   r   r   )r   r   Nlitellm_debug_infozLLM API call failed: `r-  r)  rC  )rK  rN  rO  )r   r   rO  rK  )r   r   rK  rL  z0[Non-Blocking] Error in post_call_failure_hook: )r   r   r.   llm_exceptionsr   rU   r   getattrr   r   r   r?  _is_proxy_only_llm_api_errorrequest_route _handle_logging_proxy_only_errorrJ   r   r   r   r  r'   async_post_call_failure_hookr   r    	exception)rc   r   rK  r   rN  rO  rL  rQ  exception_strr   r  r  s               rN   post_call_failure_hookz#ProxyLogging.post_call_failure_hook  s    6 (((,,->CF ) 
 	
 	
 ##t'7'77
A

 "));=QSW!X 23M!-!33%%4]O1E (77!-	 &  ,,1!#11 - 

 77)"3#5	 8     ))H48	h, ' : : J J m m !I !)I(Z	<-P''!>>)5.?/A*7	 ?  *, 	y	
>2  $..FqcJ sM   'F1E>C F1*F+F1A8F;F1F1	F.F)$F1)F..F1c                     |yt        j                  |      duryt        |t              xs |t        j
                  k(  S )a  
        Return True if the error is a Proxy Only LLM API Error

        Prevents double logging of LLM API exceptions

        e.g should only return True for:
            - Authentication Errors from user_api_key_auth
            - HTTP HTTPException (rate limit errors)
        FT)r3   is_llm_api_routerU   r   r   
auth_error)rc   rK  rN  rO  s       rN   rT  z)ProxyLogging._is_proxy_only_llm_api_errorw  sE    . =''.d:,m< 
/444	
rP   c                 t  K   |j                  dd      }|ddl}t        |j                               |d<   t	        j
                  |      }t        j                  j                  d|xs dt        j                  j                         t        j                         d|\  }}d|vri |d<   |d   j                  |       |i }	i }
t        j                  j                         }|j!                         D ]   \  }}||v r||
|<   |d	k7  s|d
k7  s||	|<   " |j#                  |j                  d	d      |j                  d
d      |	|
       d}d|v rGt%        |d   t&              r4|d   }||j(                  d<   t*        j,                  j.                  |_        nd|v rGt%        |d   t              r4|d   }||j(                  d<   t*        j2                  j.                  |_        nJd|v rFt%        |d   t&              r3|d   }||j(                  d<   t*        j4                  j.                  |_        |j7                  |d       |j9                  |t;        j<                                d{    t?        j@                  |jB                  |t;        j<                         f      jE                          yy7 Iw)z
        Handle logging for proxy only errors by calling `litellm_logging_obj.async_failure_handler`

        Is triggered when self._is_proxy_only_error() returns True
        litellm_logging_objNr   r   )r   IGNORE_THIS)original_function	rules_obj
start_timerR   r   userr   )r   rd  optional_paramslitellm_paramsmessagespromptinput)ri  api_key)rX  traceback_exception)targetr   rj   )#r   uuidr   uuid4r>   'get_sanitized_user_information_from_keyrJ   r6  function_setupRulesr   r1  updaterC   __annotations__rw   itemsupdate_environment_variablesrU   r   model_call_detailsrA   acompletionro   r   atext_completion
aembeddingr  async_failure_handlerrF   rI   	threadingThreadrM  start)rc   r   r   rO  rK  r_  rm  user_api_key_logged_metadatarZ   _optional_params_litellm_paramslitellm_param_keyskvri  s                  rN   rV  z-ProxyLogging._handle_logging_proxy_only_error  s     2>1A1A!42
 &.1$**,.?L*+(PP&7 ) )0(D(D )"'"8=!----/#<<>) 	)% -+-Z($++,HI*! O!4!D!D!I!I!K$**,1**)*OA&'\a6k*+$Q'	 -  <<"&&w3!%%fb1 0.	 =  -/E\)jZ($/ %Z0EJ#66zB090E0E0K0K#-\)jh9OQT.U$X.CH#66x@090J0J0P0P#-L(ZW8Mt-T$W-BG#66w?090D0D0J0J#-(( )  &;;,$-$8$8$: <   
 *::&((* egg +Ps    D
J8J8EJ8,J6-A
J8r   c                   K   t         j                  D ]  }	 d}t        |t              r*t         j                  j
                  j                  |      }n|}|t        |t              rCddlm	} |j                  ||j                        durz|j                  |||       d{    n,t        |t              r|j                  |||       d{     |S 7 57 
# t        $ r}|d}~ww xY ww)z
        Allow user to modify outgoing data

        Covers:
        1. /chat/completions
        2. /embeddings
        3. /image/generation
        4. /files
        Nr   r   r  T)r   rZ   r   )rJ   r   rU   r   r   r   r  r&   r	  r   r
  	post_callasync_post_call_success_hookr'   r   )rc   rZ   r   r   r   r  r   r  s           rN   post_call_success_hookz#ProxyLogging.post_call_success_hook  s       ))H'48	h, ' : : J J m m !I !)I( "(O<P %99%)6I6S6S :  $((
 %&CC.?!%%- D    $I|<'DD.?!%%- E   E *R !
  sY   C1A5CC1C$C%,CCCC1CC	C.'C))C..C1
str_so_farc                   K   ddl m} d}t        |t        t        f      rt        j                  |      }|t
        j                  D ]  }	 d}t        |t              r3ddl	m
}	 t        ||      }
|j                  |
|	j                        durIt        |t              r*t
        j                  j                   j#                  |      }n|}|Zt        |t$              rJ|||z   }n|}|j'                  ||	       d{   }t        |t              r|j)                  d
      r|c S  |S 7 -# t*        $ r}|d}~ww xY ww)zy
        Allow user to modify outgoing streaming data -> per chunk

        Covers:
        1. /chat/completions
        r   r   N)response_objr   )rZ   r   r  T)r   r   zdata: )r   r   rU   r   r   rJ   get_response_stringr   r&   r	  r   '_check_and_merge_model_level_guardrailsr
  r  r   r   r   r  r'   async_post_call_streaming_hook
startswithr   )rc   rZ   r   r   r  r   response_strr   r  r   modified_datacomplete_responsepotential_error_responser  s                 rN   r  z+ProxyLogging.async_post_call_streaming_hook*  sa     	:&*h0C DE"66HML##--)8<I!(O<P )P!%*)
 %99%2+>+H+H :  $(	( %!(C0$+$>$>$N$N$q$q$%	 %-	 ,I|1T%10:\0I-0<-"+"J"J2C): #K #  1 &4c6AA(K#;;Q .V  ! GsJ   A
EAD0EA.D0 D.&D0'E.D00	E 9D;;E  Ec                 `   t         j                  D ]  }d}t        |t              r*t         j                  j
                  j                  |      }n|}|Dt        |t              sUt        |t              r"|j                  |t        j                        s|j                  |||      } |S )z
        Allow user to modify outgoing streaming data -> Given a whole response iterator.
        This hook is best used when you need to modify multiple chunks of the response at once.

        Covers:
        1. /chat/completions
        Nr  )r   r   r   )rJ   r   rU   r   r   r   r  r'   r&   r
  r   r  'async_post_call_streaming_iterator_hook)rc   r   r   r   r   r  s         rN   r  z4ProxyLogging.async_post_call_streaming_iterator_hookl  s      ))H04I(C(#66FFii	 %	$I|)L!33%2E2O2O 4   )PP*;!)%1  Q  H *& rP   c                     | j                   rG| j                   j                  0t        j                  | j                   j	                  |             yyy)z
        Initialize the response taking too long task if user is using slack alerting

        Only run task if user is using slack alerting

        This handles checking for if a request is hanging for too long
        Nr.  )r   r   r   r   response_taking_too_long)rc   rZ   s     rN   r  z0ProxyLogging._init_response_taking_too_long_task  sP     ((,,55A,,EESWEX B )rP   r   )NNNNNNra   )r   NNN)NN)0r   r   r   __doc__r#   r   rd   r   r   r$   r   r
   r   r.   rV   r   r   r   r'   r:   r   r   r   r   r   r2   r   r  r  r/   r%  r?  rM  r   r   rZ  rT  rV  rB   r  r   r   r   r   r   r  r  r  rj   rP   rN   r   r      s     # :% :  :D'7V$'7 $J/'7V $(.2,015(,/30S4.0S %UO0S j)	0S
 d9o.0S  ~0S 'tn0Sd;8F+; ;*13 18L+A 1'(62B 'R
"
,34E,F
,$ )  	
	 
 " )  	
	 
 "Q)Q tnQ 	
	Q 
$Qf// */ #
	/b 
(

 
2 (,?K?K ./?K 	?K
 tn?KD RT(F,1(F>A(F^ 15#'+WW &W *	W
 _-W }W  }Wx 15#	
%
 _-
 }	

 

H  $26VV *V }	V
 %Y/Vp99 #9 *	9D %)@@ ,m=PP
@ *@ SM@D  *  	 D rP   r   c                 &    t        d| d           y )Nz!Backing off... this was attempt #tries)rO   )detailss    rN   
on_backoffr    s    5gg6F5GHIrP   rZ   rf   c                     t        j                  |       }|j                         D ]/  \  }}t        |t              s	 t        j                  |      ||<   1 |S # t        $ r d||<   Y Dw xY wNzfailed-to-serialize-jsonrX   rY   rt  rU   rV   rF  rG  r   )rZ   db_datar  r  s       rN   jsonify_objectr    se    mmD!G1a8!ZZ]
   N  87
8   AA+*A+c            #          e Zd ZU g Zeed<   	 dKdededee	   fdZ
deeef   ded	   fd
ZdefdZdedefdZ ej&                  ej(                  edde      d        Ze ej&                  ej(                  edde      dede	ded   fd              Z ej&                  ej(                  edde      e	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dLdeeeef      dee   dee   dee   dee   dee   deed      d ed!   d"ee   d#ee   d$ee   d%ee   d&ee   dee   d'eee      fd(              Zd)efd*Z ej&                  ej(                  edde      deded+   fd,       Z  ej&                  ej(                  edde      di dddd-dddf	dee   ded.ee   dee   dee   d ed/   deed0      d1ee   d2ee   fd3       Z! ej&                  ej(                  edde      	 	 	 	 dMd4ee   dee   deed5      dee   fd6       Z" ej&                  ej(                  edde      d7        Z# ej&                  ej(                  edde      d8        Z$d9 Z%defd:Z&dNd;Z'd<ee(   dee(   fd=Z)d>ee   dee   fd?Z*	 	 	 	 	 	 	 dOd@edAedBedCedDee   d<ee(   d>ee   dEee   dFee   fdGZ+	 	 	 	 dPd@ee   d%ed$edHee   fdIZ,dJ Z-y)QPrismaClientspend_log_transactionsNdatabase_urlproxy_logging_objhttp_clientc                    || _         t        t        j                  d            | _        t        j                  d       	 ddlm} |2t         ||      | j                  | j                  nd      | _        n/t         |       | j                  | j                  nd      | _        t        j                  d	       y # t        $ r t        d      w xY w)
NIAM_TOKEN_DB_AUTHzCreating Prisma Client..r   )PrismazUnable to find Prisma binaries.)httpF)original_prismaiam_token_db_authzSuccess - Created Prisma Client)r  r?   r3  r4  r  r    rG   prismar  r   r8   db)rc   r  r  r  r  s        rN   rd   zPrismaClient.__init__  s     "31<II)*2
 	""#=>	?% "# &K 8 --9 **DG $ & --9 **DG 	""#DE)  	?=>>	?s   C   Cpayloadrf   )r   failurec                    	 |j                  di       }t        |t              r$t        t        t        j                  |            }n|}|j                  d      dk(  rdS dS # t
        j                  t        f$ r Y yw xY w)a  
        Determine if a request was successful or failed based on payload metadata.

        Args:
            payload (Union[dict, SpendLogsPayload]): Request payload containing metadata

        Returns:
            Literal["success", "failure"]: Request status
        rR   r   r  r   )	r   rU   r   r   r	   rF  loadsJSONDecodeErrorAttributeError)rc   r  payload_metadatapayload_metadata_jsons       rN   get_request_statuszPrismaClient.get_request_status  s    	DKKKBE *C0HL$**%56I% )9%
 ),,X6)C   $$n5 		s   AA"  A" "A>=A>tokenc                 h    t        j                  |j                               j                         }|S ra   hashlibsha256encode	hexdigest)rc   r  hashed_tokens      rN   
hash_tokenzPrismaClient.hash_token  s%    ~~elln5??ArP   rZ   c                     t        j                  |      }|j                         D ]/  \  }}t        |t              s	 t        j                  |      ||<   1 |S # t        $ r d||<   Y Dw xY wr  r  )rc   rZ   r  r  r  s        rN   r  zPrismaClient.jsonify_object  se    --%MMODAq!T"<!%AGAJ $  ! <!;GAJ<r     
   )	max_triesmax_timer  c                 H  K   	 g d}d}dj                  d |D              }t        j                  dd      }| j                  j	                  d| d| d	       d
{   }t        |      }|d   d   |k(  rt        j                  d       y
|d   d   r[||d   d   vrQ| j                          d
{    | j                  j                  d       d
{    t        j                  d       y
t        | j                         d
{   }|rt        | j                         d
{    y
|d   d   rt        |d   d         n	t               }t        |      }	|	|z
  }
t        j                  dj                  |
             	 y
7 ,7 7 7 7 g# t        $ r  w xY ww)a|  
        Checks if the LiteLLM_VerificationTokenView and MonthlyGlobalSpend exists in the user's db.

        LiteLLM_VerificationTokenView: This view is used for getting the token + team data in user_api_key_auth

        MonthlyGlobalSpend: This view is used for the admin view to see global spend for this month

        If the view doesn't exist, one will be created.
        )r0   MonthlyGlobalSpendLast30dKeysBySpendLast30dModelsBySpendMonthlyGlobalSpendPerKeyMonthlyGlobalSpendPerUserPerKeyLast30dTopEndUsersSpendDailyTagSpendr0   z, c              3   (   K   | ]
  }d | d   yw)'Nrj   ).0views     rN   	<genexpr>z1PrismaClient.check_view_exists.<locals>.<genexpr>2  s     *R4QtfA;*Rs   DATABASE_SCHEMApublicz
                WITH existing_views AS (
                    SELECT viewname
                    FROM pg_views
                    WHERE schemaname = 'z,' AND viewname IN (
                        z
                    )
                )
                SELECT
                    (SELECT COUNT(*) FROM existing_views) AS view_count,
                    ARRAY_AGG(viewname) AS view_names
                FROM existing_views
                Nr   
view_countzAll necessary views exist!
view_namesa"  
                            CREATE VIEW "LiteLLM_VerificationTokenView" AS
                            SELECT
                            v.*,
                            t.spend AS team_spend,
                            t.max_budget AS team_max_budget,
                            t.tpm_limit AS team_tpm_limit,
                            t.rpm_limit AS team_rpm_limit
                            FROM "LiteLLM_VerificationToken" v
                            LEFT JOIN "LiteLLM_TeamTable" t ON v.team_id = t.team_id;
                        z,LiteLLM_VerificationTokenView Created in DB!)r  z

[93mNot all views exist in db, needed for UI 'Usage' tab. Missing={}.
Run 'create_views.py' from https://github.com/BerriAI/litellm/tree/main/db_scripts to create missing views.[0m
)joinr3  r4  r  	query_rawr   r    infohealth_checkexecute_rawr5   r4   r   warningrH   r   )rc   expected_viewsrequired_viewexpected_views_str	pg_schemaretexpected_total_viewsshould_create_viewsret_view_names_setexpected_views_setmissing_viewss              rN   check_view_existszPrismaClient.check_view_exists  s    *K		N <M!%*R>*R!R		"3X>I))) *3 4+, - C $'~#6 1vl#';;$))*FG q6,'MQAU,U++---''--
   )--F2 	+ 1Ltww0W*W'*2dgg>>>& 	 :=Q9MCA| 45SVSX + .1-@*(:=O(O,44 b  i  i - 	}, .$ +X>"  		s   F"AF F	/F F"%F 3F4"F FF 0F"1F 
FF *F+F /F"0AF F"	F F F F F FF"r      rh   ro   
table_name)usersrw   configspendc           	      n  K   t        j                          }	 |dk(  r2| j                  j                  j                  ||i       d{   }|S |dk(  r2| j                  j                  j                  ||i       d{   }|S |dk(  r2| j                  j
                  j                  ||i       d{   }|S |dk(  r0| j                  j                  j                  ||i       d{   }S 7 7 v7 A7 # t        $ r}ddl}dt        |       }t        j                  |       |d	j                  t        |            z   }|d
z    |j                         z   }	t        j                          }
|
|z
  }t        j                   | j"                  j%                  |||	d             |d}~ww xY ww)z4
        Generic implementation of get data
        r  whereNrw   r  r  r   z2LiteLLM Prisma Client Exception get_generic_data: z
Exception Type: {}
get_generic_data)rK  r@  rL  r   )timer  litellm_usertable
find_firstlitellm_verificationtokenlitellm_configlr   rF   r   r    r   rH   r  rI   r   r   r  rM  )rc   rh   ro   r  rc  r   r  rF   	error_msgerror_tracebackend_time	_durations               rN   r  zPrismaClient.get_generic_datat  s    " YY[
$	W$!%!:!:!E!E, "F "  O v%!%!B!B!M!M, "N "  O x'!%!7!7!B!B, "C "  O	 w&!%!5!5, "6 "  O  	LSQRVHUI &&y1!$:$A$A$q'$JJI'$.1E1E1E1GGOyy{H :-I&&66'(&"10	 7  G%	s   F50C< C4	C< F50C< ?C6 C< F50C< 6C87C< <F5=0C< -C:.C< 3F54C< 6C< 8C< :C< <	F2B(F--F22F5user_iduser_id_listteam_idteam_id_listkey_val)	rd  rh   r  r  enduserbudgetteamuser_notificationcombined_view
query_type)find_uniquefind_allexpiresreset_atoffsetlimitri   budget_id_listc           	        K   t               }t        j                         }d }	 d }||	||dk(  r|4t        |t              r$t	        |      }t        j                  d|        |dk(  r||t        ddd| i      | j                  j                  j                  d	|id
di       d {   }|I|j                  t        |j                  t              r|j                  j                         |_        nt        t        j                  d|       |dk(  r|| j                  j                  j!                  d|id
di       d {   }|Zt#        |      dkD  rK|D ]<  }t        |j                  t              s|j                  j                         |_        > n|dk(  r|| j                  j                  j!                  d|id
di       d {   }|t#        |      dkD  r|D ]<  }t        |j                  t              s|j                  j                         |_        > ny|dk(  r|	|
| j                  j                  j!                  dd idd|	iigd|
id       d {   }|2t#        |      dkD  r#|D ]<  }t        |j                  t              s|j                  j                         |_        > n|dk(  ri }|i |d	<   t        |t              rt	        |      }|g|d	   d<   nyt        |t$              rig }|D ]Z  }t        |t              sJ |j'                  d      r$| j)                  |      }|j+                  |       J|j+                  |       \ ||d	   d<   | j                  j                  j!                  ddi|d
di       d {   }||S t        t        j                  d      ||	|^|dk(  rX|dk(  r9|d|i}| j                  j,                  j                  |ddi       d {   }|S |dk(  r2|0| j                  j,                  j!                  |       d {   }|S |dk(  r6|
4| j                  j,                  j!                  dd|
ii       d {   }|S |dk(  r6|4| j                  j,                  j!                  dd|ii       d {   }|S |dk(  rf|	=| j                  j,                  j!                  ddid dd idd|	iigi!       d {   }|S d"}| j                  j/                  |||       d {   }|S |dk(  rt        j                  d#       |z|dk(  r8| j                  j0                  j                  |d   |d$   i       d {   }|S |dk(  r6| j                  j0                  j!                  |d   |d$   i       d {   }|S | j                  j0                  j!                  d%di&       d {   }|S |d'k(  rJ|
H|dk(  rs| j                  j2                  j!                  d d(dd id)d*d iigidd|
iigi       d {   }|S |d+k(  r<|:|dk(  r#| j                  j4                  j!                  d,d|ii       d {   }|S |d-k(  r)|dk(  r5| j                  j6                  j                  d|id.di       d {   }|S |dk(  r6|
4| j                  j6                  j!                  dd|
ii       d {   }|S |dk(  r9|7| j                  j6                  j!                  d/d0|iid
di       d {   }|S |dk(  r6|4| j                  j6                  j!                  dd|ii       d {   }|S |dk(  r4|2| j                  j6                  j!                  t8        1       d {   }|S |d2k(  rj|dk(  r2| j                  j:                  j                  d|i       d {   }|S |dk(  r,| j                  j:                  j!                          d {   }|S |d3k(  rJ|4t        |t              r$t	        |      }t        j                  d|        |dk(  r|t        ddd| i      d4| d5}| j                  j=                  |6       d {   }||d7   g |d7<   |d8   d9|d8<   d }|d:   E|d   @	 |d:   D ]7  }|j?                  d      |d   |j?                  d      k(  s-tA        dAi |}9 ||d;<   tC        dAi |d<t        j                         i}|j                  9t        |j                  t              r|j                  j                         |_        |S y y y y 7 7 27 7 7 7 y7 E7 7 7 7 n7 7 7 7 c7 %7 7 7 u7 =7 7 7 7 # tD        $ r}dd l#}d=| }|t        |      z   }tI        |       |d>z    |jJ                         z   } t        j                  |        t        j                         }!|!|z
  }"tM        jN                  | jP                  jS                  ||"d?| @             |d }~ww xY ww)BNrh   r  z%PrismaClient: find_unique for token: r	  r   r   zNo token passed in. Token=r   r  litellm_budget_tableT)r  includezQAuthentication Error: invalid user key - user key does not exist in db. User Key=r
  r  r   r   r  gtlt)ORbudget_reset_atr  insk-r  desc)orderr  r  z=Authentication Error: invalid user key - token does not existrd  organization_membershipsr  r  )r  r  a  
                        SELECT
                            u.*,
                            json_agg(v.key_alias) AS key_aliases
                        FROM
                            "LiteLLM_UserTable" u
                        LEFT JOIN "LiteLLM_VerificationToken" v ON u.user_id = v.user_id
                        GROUP BY
                            u.user_id
                        ORDER BY u.spend DESC
                        LIMIT $1
                        OFFSET $2
                        z-PrismaClient: get_data: table_name == 'spend'ro   	startTimer  r  ANDNOTbudget_durationr  	budget_idr  litellm_model_tablemembershas)taker  r  a  
                        SELECT 
                            v.*,
                            t.spend AS team_spend, 
                            t.max_budget AS team_max_budget, 
                            t.tpm_limit AS team_tpm_limit,
                            t.rpm_limit AS team_rpm_limit,
                            t.models AS team_models,
                            t.metadata AS team_metadata,
                            t.blocked AS team_blocked,
                            t.team_alias AS team_alias,
                            t.metadata AS team_metadata,
                            t.members_with_roles AS team_members_with_roles,
                            t.organization_id as org_id,
                            tm.spend AS team_member_spend,
                            m.aliases AS team_model_aliases,
                            -- Added comma to separate b.* columns
                            b.max_budget AS litellm_budget_table_max_budget,
                            b.tpm_limit AS litellm_budget_table_tpm_limit,
                            b.rpm_limit AS litellm_budget_table_rpm_limit,
                            b.model_max_budget as litellm_budget_table_model_max_budget,
                            b.soft_budget as litellm_budget_table_soft_budget
                        FROM "LiteLLM_VerificationToken" AS v
                        LEFT JOIN "LiteLLM_TeamTable" AS t ON v.team_id = t.team_id
                        LEFT JOIN "LiteLLM_TeamMembership" AS tm ON v.team_id = tm.team_id AND tm.user_id = v.user_id
                        LEFT JOIN "LiteLLM_ModelTable" m ON t.model_id = m.id
                        LEFT JOIN "LiteLLM_BudgetTable" AS b ON v.budget_id = b.budget_id
                        WHERE v.token = 'z'
                    queryteam_modelsteam_blockedFteam_members_with_rolesteam_memberlast_refreshed_atzHLiteLLM Prisma Client Exception: Error with `get_data`. Args passed in: r  get_datarK  r@  r   rL  rj   )*localsr  rU   r   _hash_token_if_neededr    rG   r   r  r  r	  r  r   	isoformatr   HTTP_401_UNAUTHORIZED	find_manyr   r   r  r  r   r  r  litellm_spendlogslitellm_budgettablelitellm_endusertablelitellm_teamtabler   litellm_usernotificationsquery_firstr   r1   r0   r   rF   rO   rI   r   r   r  rM  )#rc   r  r  r  r   r  r  r  r  r  r  r  r  ri   r  r  args_passed_inrc  r  r   rwhere_filterhashed_tokenst	new_token	sql_queryr,  tmr  rF   prisma_query_infor  r  r  r  s#                                      rN   r.  zPrismaClient.get_data  sc    P  YY[
&*W	 H!j&8&:+> $!%-'<5'I,22CL>R .<3K}+(+$+/I%-Q#R  &*WW%F%F%R%R&5!7 > &S &  H  +#++7J$,,h= 08/?/?/I/I/KH, ,(.(D(D%vw|v}#~   :-'2E%)WW%F%F%P%P('2!7 > &Q &  H  +H0A!)A)!))X>,-II,?,?,A	 "*  :-'2E%)WW%F%F%P%P('2!7 > &Q &  H  +H0A!)A)!))X>,-II,?,?,A	 "* *,+ ,%)WW%F%F%P%P "+D 1!*T7O <# 15h/? &Q &  H  +H0A!)A)!))X>,-II,?,?,A	 "*  :-)+L(02W-%eS1$9$FE;@'L1$7't4,.M%*'1!S'9 9'9#$<<#604a0HI$1$8$8$C$1$8$8$; &+ ;HL1$7%)WW%F%F%P%P&/*!7 > &Q &  H
 '#O ($*$@$@^  %**<&:+?.#,g"6%)WW%>%>%J%J%!;T B &K &  H\  S  :-'2E%)WW%>%>%H%H% &I &  HP  K  :-(2F%)WW%>%>%H%H-h/? &I &  HH  ?  :-,2J%)WW%>%>%H%H(4*>? &I &  H<  7  :-*)-)B)B)L)L#*F"3 $%.$5%.w$@'"# *M * $2  %	 *.):):9eV)T#Tw&$**C &!]2)-)B)B)N)N '0@# *O * $ $O $z1)-)B)B)L)L '0@# *M * $
 $O%)WW%>%>%H%H*F3 &I &  H $Ox'H,@+%)WW%@%@%J%J $)):D(A).1BD0I(J,&!" "3T84D E#
 &K &  H $Oy(^-G+%)WW%A%A%K%K*T>,BC &L &  H $Ov%.%)WW%>%>%J%J('2!6 = &K &  H2  +  :-(2F%)WW%>%>%H%H-h/? &I &  H(    :-'2E%)WW%>%>%H%H%w'7 "8 >	 &I &  H    :-,2J%)WW%>%>%H%H(4*>? &I &  H  	  :-,2F%)WW%>%>%H%H0 &I &  H  22.%)WW%F%F%R%R('2 &S &  H
    :-%)WW%F%F%P%P%RRH.$!%-'<5'I,22CL>R .}+(+$+/I%-Q#R 
%*6 +0 17!I< &*WW%8%8y%8%IIH+#M2:68H]3#N3;7<H^48<$%>?K ( 3 ?  '//H&I#%66)#4#@X$-F"%'VVI%6F7 39,2,K	 'J
 3>/#@ $&$:>))+$ $++7J$,,h= 08/?/?/I/I/KH,#O_ / /S ,# ,A "   < (    
$0 $U$$  "  
       S^  JV  	"jkyjz {)CF2I)$'$.1E1E1E1GGO &&7yy{H :-I&&66'(&("1	 7  G'	s  !i8Bg 2f3B"g f5g Ag $f
%5g A"g =f>5g 4C>g 2f3g :i8;Ag fg  i8!0g fg i84g fg i84g fg i8=g fg i8"g 4f"5g :i8;Ag f%g i86g 
f(g i8+g <f+=g i8Ag f.g i8:g f1g i89g f4g i84g f7g i87g f:g i84g  f=g i84g ;g <g i85g 7g8g =i8>,g *g+g 0i81A;g ,g	-A g .g A9g ?i8g g 
g g g g g g g g "g %g (g +g .g 1g 4g 7g :g =g  g g g 	g 	i5Bi00i55i8r  c                     | j                  |      }|j                  dd       .t        |d   t              rt	        j
                  |d         |d<   |S )Nr  members_with_roles)r  r   rU   r   rF  rG  )rc   r  s     rN   jsonify_team_objectz PrismaClient.jsonify_team_object0  s[    %%7%3;;+T2>:()4D
 -1JJw?S7T,UG()rP   )rd  rh   r  r  r  r  c           	        K   t        j                          }	 t        j                  d|       |dk(  r|d   }| j                  |      }| j	                  |      }||d<   t        d       | j                  j                  j                  d|ii |i ddd	i
       d{   }t        j                  d       |S |dk(  rc| j	                  |      }	 | j                  j                  j                  d|d   ii |i d       d{   }t        j                  d       |S |dk(  rb| j                  |      }| j                  j                  j                  d|d   ii |i d       d{   }
t        j                  d       |
S |dk(  r	 g }|j!                         D ]^  \  }}|}t#        j$                  |      }| j                  j&                  j                  d|i||dd|id      }|j)                  |       ` t+        j,                  |  d{    t        j                  d        y|d!k(  rb| j	                  |      }| j                  j.                  j                  d"|d"   ii |i d       d{   }t        j                  d#       |S |d$k(  rb| j	                  |      }| j                  j0                  j                  d"|d"   ii |i d       d{   }t        j                  d%       |S y7 c7 # t        $ r*}	dt        |	      v rt        ddd|d    di      |	d}	~	ww xY w7 7 )7 7 `# t        $ r}	d&dl}d't        |	       }t        |       |d(z    |j4                         z   }t        j                          }||z
  }t+        j6                  | j8                  j;                  |	|d)|*             |	d}	~	ww xY ww)+zN
        Add a key to the database. If it already exists, do nothing.
        zPrismaClient: insert_data: %srh   r  r  r  z:PrismaClient: Before upsert into litellm_verificationtokencreaterr  r  T)r  rZ   r  NzData Inserted into Keys Tablerd  r  r  rZ   z\Foreign key constraint failed on the field: `LiteLLM_UserTable_organization_id_fkey (index)`r   r   z/Foreign Key Constraint failed. Organization ID=organization_idzM does not exist in LiteLLM_OrganizationTable. Create via `/organization/new`.r   zData Inserted into User Tabler  r  r   zData Inserted into Team Tabler  
param_name)rM  param_valuerN  zData Inserted into Config Tabler  
request_idzData Inserted into Spend Tabler  z&Data Inserted into Model Request Tabler   z0LiteLLM Prisma Client Exception in insert_data: r  insert_datar/  )r  r    rG   r  r  rO   r  r  upsertr  r  r   r   r   rF  r8  rt  rF  rG  r  r   r   gatherr5  r9  rF   rI   r   r  rM  )rc   rZ   r  rc  r  r  r  new_verification_tokennew_user_rowr  new_team_rowtasksr  r  updated_dataupdated_table_rownew_spend_rownew_user_notification_rowrF   r  r  r  r  s                          rN   rP  zPrismaClient.insert_data9  sq    " YY[
z	 &&'FMU"W#U;--4-8#/ P 04ww/P/P/W/W #.W+"$ 4T: 0X 	0 	*& %))*IJ--v%--4-8)-)B)B)I)I($y/:&1k&( *J * $L& %))*IJ##v%2242@%)WW%>%>%E%E$d9o6"-W+"$ &F &   %))*IJ##x'  JJLDAq#$L#'::l#;L(,(>(>(E(E+Q/56|&T'4l&C )F )% LL!23 ) nne,,,$))*KLw&--4-8&*gg&?&?&F&F'l);<"-W+"$ 'G ' ! %))*JK$$22--4-8'';;BB+T,-?@&1k&( C   * %))*RS00 3e	*$ ! vq6" ,(+ '+Z[bct[uZv  wD  *E$  G  > -!  	J3q6(SI)$'$.1E1E1E1GGOyy{H :-I&&66'(&+"1	 7  G!	s   OBM	  L!M	 ;O<M	 4L	 L	L	 M	 #O$AM	 /L?0M	 
OBM	 MM	 3O4AM	 ?M M	 OAM	 &M'M	 OM	 L	 		L<%L77L<<M	 M	 M	 M	 		OBOOOrr  	data_list)rr  update_many)rd  rh   r  r  r  r  r  update_key_valuesupdate_key_values_custom_queryc
           	      4  K   t        j                  d|        t        j                         }
	 | j                  |      }|| j                  |      }|t	        d|        t        |      }||d<   | j                  j                  j                  d|ii |       d{   }t        j                  dd	| z   d
z          i }|	 |j                         }||dS ||v|dk(  rq|dk(  rl	 ||d   }||	|	}n|}| j                  j                  j                  d|ii |i |d       d{   }t        j                  dd| z   d
z          ||dS |||dk(  r|dk(  r	 ||d   }||}d|vr|||d<   d|v r.t        |d   t               rt#        j$                  |d         |d<   d|v r.t        |d   t               rt#        j$                  |d         |d<   | j                  j&                  j                  d|ii |i |d       d{   }t        j                  dd| z   d
z          ||dS ||dk(  r|dk(  r|t        |t               r	 | j                  j)                         }t+        |      D ]  \  }}|j,                  j/                  d      r!| j1                  |j,                        |_        	 | j                  |j                  d            }|j                  j                  d|j,                  ii |        |j3                          d{    t	        d       y||dk(  r|dk(  r|t        |t               r	 | j                  j)                         }t+        |      D ]X  \  }}	 | j                  |j                  d            }|j                  j                  d|j4                  ii |i |d       Z |j3                          d{    t        j                  d       y||dk(  r|dk(  r|t        |t               r	 | j                  j)                         }|D ]U  }	 | j                  |j                  d            }|j6                  j                  d|j4                  ii |i |d       W |j3                          d{    t        j                  d       y||d k(  r|dk(  r|t        |t               r	 | j                  j)                         }|D ]U  }	 | j                  |j                  d            }|j8                  j                  d!|j:                  ii |i |d       W |j3                          d{    t        j                  d"       y||dk(  r|dk(  r|t        |t               r| j                  j)                         }t+        |      D ]X  \  }}	 | j=                  |j                  d      #      }|j&                  j                  d|j>                  ii |i |d       Z |j3                          d{    t        j                  d$       yyyyyy7 # t        $ r |j                         }Y w xY w7 I7 h# t        $ r& | j                  |j                  d            }Y w xY w7 # t        $ r$ | j                  |j                               }Y =w xY w7 # t        $ r$ | j                  |j                               }Y w xY w7 n# t        $ r$ | j                  |j                               }Y !w xY w7 # t        $ r& | j                  |j                  d            }Y w xY w7 I# t        $ r}d%dl }d&tC        |       }t	        |       |d'z    |jD                         z   }t        j                         }||
z
  }tG        jH                  | jJ                  jM                  ||d(|)             |d}~ww xY ww)*z&
        Update existing data
        z'PrismaClient: update_data, table_name: r  Nztoken: r  r  rJ  z[91mz DB Token Table update succeeded z[0m)r  rZ   rd  rr  r  rH  z!DB User Table - update succeeded )r  rZ   r  r   rE  z!DB Team Table - update succeeded )r   rZ   rh   r\  r  T)exclude_nonez([91mDB Token Table update succeeded[0mz-[91mDB User Table Batch update succeeded[0mr  z1[91mDB End User Table Batch update succeeded[0mr  r"  z/[91mDB Budget Table Batch update succeeded[0mrL  z-[91mDB Team Table Batch update succeeded[0mr   z/LiteLLM Prisma Client Exception - update_data: r  update_datar/  )'r    rG   r  r  rO   r1  r  r  rr  
model_dumpr   rV   r  rQ  r  rU   r   rF  rG  r8  batch_	enumerater  r  r  commitr  r7  r6  r"  rF  r   rF   r   rI   r   r   r  rM  )rc   r  rZ   r[  r  r   r  r  r]  r^  rc  r  r   _dataupdate_user_rowupdate_team_rowbatcheridxr?  	data_jsonrd  r  r  r  r  rF   r  r  r  r  s                                 rN   ra  zPrismaClient.update_data  s`	    0 	""5j\B	
 YY[
J	))t)4G ,$($7$7=N$7$O! w/0-E:#( !%!B!B!I!I"E*$G "J "  %**8
CD 
 !'0 ( 3 3 5 "'66#*zV/C(* ?%i0G$,5A,J),3)(,(A(A(H(H$g."-W+#/# )I ) # %))9/9JKL 
 $+ODD#*zV/C(* ?%i0G$,(/%G+0C)0GI&'72z0148 59JJ 455G01 (+<<%&:;TB ?Cjj)*>??%&:; )-(A(A(H(H$g."-W+#/# )I ) # %))9/9JKL 
 $+ODD&%'-/)y$/ ''..*'	2FCww))%0"&///"@X$($7$7!"4!@ %8 %	
 55<<&0*	] =  3 nn&&&N &&(-/)y$/ ''..*!*9!5ICJ$($7$7!%d!C %8 %	
 --44($,,7&3m'"+' 5  "6  nn&&&$))S &)+-/)y$/ ''..*(GM$($7$7!(!3!3!3!F %8 %	
 0077('//:&3m'"+' 8   )  nn&&&$))W &(*-/)y$/ ''..*'FL$($7$7!'!2!2!2!E %8 %	
 //66*F,<,<=&3m'"+' 7  (  nn&&&$))U &&(-/)y$/ ''..*!*9!5IC$($<$<$(OOO$F %= %	 --44($,,7&3m'"+' 5  "6$ nn&&&$))S/ 0 * 0 ) 'e % 0 (0$#R#D % X$($7$7QVVQUV=V$7$W	X '( % J$($7$7TYY[$7$I	J '( % M$($7$7W\\^$7$L	M '( % L$($7$7V[[]$7$K	L '$ % $($7$7!%!= %8 %	 '
  	I#a&RI)$'$.1E1E1E1GGOyy{H :-I&&66'(&+"1	 7  G!	s  -`A5^ %Y&&^ Y ^ !`"A^ 4Y=5&^ `B<^ Z &^ ?` B^ "Z)A ^ )Z5*^ 9`:A
^ "Z8'A^ ,[(-^ `>^ "[+(A^ -\.^ `>^ "\)A^ .]/^ `	A	^ "]5A^ :^;^ `^ Y:6^ 9Y::^  ^ +Z2.^ 1Z22^ 8)[%!^ $[%%^ +)\^ \^ )]^ 
]^ +^ <^ ?^  ^ 	`B```tokens)rd  rh   r  r  r  c           	        K   t        j                          }	 |t        |t              rg }|D ]I  }t        |t              r$|j	                  d      r| j                  |      }n|}|j                  |       K i }	|ddd|iid|igi}	ndd|ii}	| j                  j                  j                  |	       d{   }
t        j                  d	|
       d
|
iS |dk(  rH|Ft        |t              r6| j                  j                  j                  dd|ii       d{    d|iS |dk(  rG|Dt        |t              r3| j                  j                  j                  dd|ii       d{    yyyy7 7 W7 # t        $ r}ddl}dt        |       }t        |       |dz    |j                          z   }t        j                          }||z
  }t#        j$                  | j&                  j)                  ||d|             |d}~ww xY ww)za
        Allow user to delete a key(s)

        Ensure user owns that key, unless admin.
        Nr  r  r  r  r  r  r  zdeleted_tokens: %sdeleted_keysr  r   deleted_teamsrh   r   z/LiteLLM Prisma Client Exception - delete_data: r  delete_datar/  )r  rU   r
   r   r  r  r   r  r  delete_manyr    rG   r8  r   rF   rO   rI   r   r   r  rM  )rc   rl  r  r  r  rc  r>  r  r  filter_querydeleted_tokensr  rF   r  r  r  r  s                    rN   rp  zPrismaClient.delete_data  sT    & YY[
9	!j&> "#E!%-%2B2B52I'+U'C',!((6 $ &(&4*? @9gBVW$L %,dM-B#CL'+ww'H'H'T'T& (U ( " %**+?P&77f$ ,|T2 gg//;;$t\&:; <    (66e# ,|T2 gg77CC$t\&:; D    3 - $!"  	I#a&RI)$'$.1E1E1E1GGOyy{H :-I&&66'(&+"1	 7  G!	sz   HB"E9 :E3;E9 HAE9 E5E9 %H&AE9 *E7+E9 /H3E9 5E9 7E9 9	HBHHHc           	      0  K   t        j                          }	 t        j                  d       | j                  j	                         du r8t        j                  d       | j                  j                          d {    y y 7 # t        $ r}dd l}dt        |       }t        |       |dz    |j                         z   }t        j                          }||z
  }t        j                  | j                  j                  ||d|             |d }~ww xY ww)	Nz:PrismaClient: connect() called Attempting to Connect to DBFz;PrismaClient: DB not connected, Attempting to Connect to DBr   z+LiteLLM Prisma Client Exception connect(): r  connectr/  )r  r    rG   r  is_connectedru  r   rF   r   rO   rI   r   r   r  rM  rc   rc  r  rF   r  r  r  r  s           rN   ru  zPrismaClient.connectA	  s     YY[
	 &&L ww##%.$**Q ggoo'''	 / ( 	Ec!fXNI)$'$.1E1E1E1GGOyy{H :-I&&66'(&'"1	 7  G!	s<   DA#B ;B<B  DB 	DBDDDc           	        K   t        j                          }	 | j                  j                          d {    y 7 # t        $ r}dd l}dt        |       }t        |       |dz    |j                         z   }t        j                          }||z
  }t        j                  | j                  j                  ||d|             |d }~ww xY ww)Nr   .LiteLLM Prisma Client Exception disconnect(): r  
disconnectr/  )r  r  rz  r   rF   r   rO   rI   r   r   r  rM  rw  s           rN   rz  zPrismaClient.disconnectf	  s      YY[
	''$$&&& 	HQQI)$'$.1E1E1E1GGOyy{H :-I&&66'(&*"1	 7  G!	s2   C= ;= C= 	CBCCCc           	        K   t        j                          }	 d}| j                  j                  |       d{   }|S 7 # t        $ r}ddl}dt        |       }t        |       |dz    |j                         z   }t        j                          }||z
  }	t        j                  | j                  j                  ||	d|             |d}~ww xY ww)z=
        Health check endpoint for the prisma client
        zSELECT 1Nr   ry  r  r  r/  )r  r  r  r   rF   r   rO   rI   r   r   r  rM  )
rc   rc  rA  r   r  rF   r  r  r  r  s
             rN   r  zPrismaClient.health_check	  s      YY[
	"I "WW..y99HO : 	HQQI)$'$.1E1E1E1GGOyy{H :-I&&66'(&,"1	 7  G!	s6   C A ?A CA 	C
BCCCc                    K   	 d}| j                   j                  |       d {   }|d   d   S 7 # t        $ r"}t        j                  d|        Y d }~yd }~ww xY ww)Nz
            SELECT reltuples::BIGINT
            FROM pg_class
            WHERE oid = '"LiteLLM_SpendLogs"'::regclass;
            r'  r   	reltuplesz+Error getting LiteLLM_SpendLogs row count: )r  r  r   r    r   )rc   rA  resultr  s       rN   _get_spend_logs_row_countz&PrismaClient._get_spend_logs_row_count	  sn     	I
  77,,9,==F!9[)) > 	 &&=aSA 		s6   A"!4 24 A"4 	AAA"AA"c                 r   K   ddl m} | j                          d{   }|j                  d|       y7 w)z
        Set the `LiteLLM_SpendLogs`row count in proxy state.

        This is used later to determine if we should run expensive UI Usage queries.
        r   )proxy_stateNspend_logs_row_count)variable_namero   )r   r  r  set_proxy_state_variable)rc   r  _num_spend_logs_rowss      rN   (_set_spend_logs_row_count_in_proxy_statez5PrismaClient._set_spend_logs_row_count_in_proxy_state	  s<      	;%)%C%C%EE,,0& 	- 	
  Fs   757response_time_msc                     |y	 t        |      }||k(  r|t        d      t        d      fvr|S dS # t        t        f$ r t        j                  d|        Y yw xY w)z&Validate and clean response time valueNinfz-infz Invalid response_time_ms value: )r   
ValueError	TypeErrorr    r  )rc   r  ro   s      rN   _validate_response_timez$PrismaClient._validate_response_time	  s     #	*+E E>eE%L%-3P&P  
 I& 	 ((23C2DE 		s   )1 1 'AAr  c                     t        |t              sy	 t        t        |            S # t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)zClean and validate details JSONNzFailed to clean details JSON: )rU   rV   r,   r+   r   r    r  )rc   r  r  s      rN   _clean_detailszPrismaClient._clean_details	  sM    '4(	":g#677 	 ((+I!)MN	s   ' 	AAA
model_namer   healthy_countunhealthy_countr  
checked_bymodel_idc
                 l  K   	 t        |      t        |      t        |      t        |      d}
|rt        |      dd nd| j                  |      | j                  |      |rt        |      nd|	rt        |	      ndd}|
j	                  |j                         D ci c]  \  }}|	|| c}}       t        j                  d|
        | j                  j                  j                  |
       d{   S c c}}w 7 
# t        $ r%}t        j                  d| d|        Y d}~yd}~ww xY ww)	z$Save health check result to database)r  r   r  r  Ni  )r  r  r  r  r  zSaving health check data: r  z+Error saving health check result for model : )r   intr  r  rr  rt  r    rG   r  litellm_healthchecktablerI  r   r   )rc   r  r   r  r  r  r  r  r  r  health_check_dataoptional_fieldsr  r  r  s                  rN   save_health_check_resultz%PrismaClient.save_health_check_result	  s1    	 "*of+!$]!3#&#7	! >K]!3DS!9PT$($@$@AQ$R..w71;c*o-5CM4O $$"1"7"7"9K$!QQ]AK !&&)CDUCV'WX99@@FW@XXX	 L Y 	 &&=j\A3O 		sT   D4BD 
C;
(C;
-A	D 6D7D :D4;D 	D1D,'D4,D11D4status_filterc                    K   	 i }|r||d<   |r||d<   | j                   j                  j                  |ddi||       d{   }|S 7 # t        $ r$}t	        j
                  d|        g cY d}~S d}~ww xY ww)zB
        Get health check history with optional filtering
        r  r   
checked_atr  )r  r  r&  skipNz$Error getting health check history: )r  r  r4  r   r    r   )rc   r  r  r  r  where_clauseresultsr  s           rN   get_health_check_historyz%PrismaClient.get_health_check_history	
  s     	L-7\*)6X& GG<<FF"#V,	 G  G N  	 &&)MaS'QRI	sF   A;>A A	A A;	A 	A8A3-A8.A;3A88A;c                 P  K   	 | j                   j                  j                  ddi       d{   }i }|D ]   }|j                  |vs|||j                  <   " t	        |j                               S 7 D# t        $ r$}t        j                  d|        g cY d}~S d}~ww xY ww)z<
        Get the latest health check for each model
        r  r  r  Nz(Error getting all latest health checks: )	r  r  r4  r  r   valuesr   r    r   )rc   
all_checkslatest_checkscheckr  s        rN   get_all_latest_health_checksz)PrismaClient.get_all_latest_health_checks%
  s     	#ww??II#V,  J   J
 M###=86;M%"2"23 $ ,,.//  	 &&)QRSQT'UVI	sJ   B&+A6 A4A6 
)A6 3B&4A6 6	B#?BB#B&B##B&ra   )NNNNNNNr	  NNNNNNN)NNNN)rf   N)r   r   NNNNN)Nr   r   N).r   r   r   r  r
   rs  r   r   r   r   rd   r   rV   r   r   r  r  r  backoffon_exceptionexpor   r  r  r7   r  r   r   r  rD   r.  rF  rP  ra  rp  ru  rz  r  r  r  r   r  r  r  r  r  rj   rP   rN   r  r    s   #%D% &*	"F"F ("F c]	"FH!T#334!	%	&!F 
4 
D 
 WZZx W.. . >?	. .` W  -1!%'+!%'+"& 9F&*'+ $ +/48.2=zc4i()z #z tn	z
 #z tnz $z !

z* 56+z, (#-z. 8$/z0 1z2 
3z8 #4.9z: $L1;z< !c+=z zx4  WEE I
EEP W  $$(!%!%7? ,09=_}_ _ D>	_
 #_ #_ 34_ QR
_ $D>_ )1__D	 W "&'+RV!%FF tnF W%MNO	F
 #FFR W< W,< 
 (	%&htn $   '+,0"&$("&++ + 	+
 +  }+ #5/+ $+ SM+ 3-+^ %)'+SM  	
  }8rP   r  r  r  r  c                 8  K   |  d}|j                  |      }|{|j                  |        d{   }|_t        d| dt        |              t	        |d      r9t        t        |d            r$|j                         }|j                  ||d	       y7 fw)
zE
    Check if a user_id exists in cache,
    if not retrieve it.
    _user_api_key_user_id)rh   N)r  z
User Row: z	, type = model_dump_jsoniX  )rh   ro   r   )	r   r.  rO   r  r  callablerS  r  r}   )r  r  r  	cache_keyr   user_rowcache_values          rN   _cache_user_rowr  >
  s     
 )01I9-HW55Jxj	$x.9IJKx!23"349 '668!#     6s   /BBA'Breceiver_emailsubjecthtmlc                   K   t        j                  d      }t        t        j                  dd            }t        j                  d      }t        j                  d      }t        j                  dd      }|t        d      | t        d	|        |t        d
|       |t        d|       t	               }||d<   | |d<   ||d<   t        j                  d||        |t        d      |j                  t        |d             	 t        j                  ||      5 }	t        j                  dd      dk7  r|	j                          |r|r|	j                  ||       |	j                  |||        ddd       y# 1 sw Y   yxY w# t        $ r+}
t        j                  dt!        |
      z          Y d}
~
yd}
~
ww xY ww)zl
    smtp_host,
    smtp_port,
    smtp_username,
    smtp_password,
    sender_name,
    sender_email,
    	SMTP_HOST	SMTP_PORT587SMTP_USERNAMESMTP_PASSWORDSMTP_SENDER_EMAILNz4Trying to use SMTP, but SMTP_SENDER_EMAIL is not setz+No receiver email provided for SMTP email. z$No subject provided for SMTP email. z&No HTML body provided for SMTP email. FromToSubjectzsending email from %s to %sz,Trying to use SMTP, but SMTP_HOST is not setr  )hostportSMTP_TLSTrueFalse)rd  password)msg	from_addrto_addrsz*An error occurred while sending the email:)r3  r4  r  r  r   r    rG   attachr   smtplibSMTPstarttlsloginsend_messager   rX  r   )r  r  r  	smtp_host	smtp_portsmtp_usernamesmtp_passwordsender_emailemail_messageserverr  s              rN   
send_emailr  S
  s     		+&IBIIk512IIIo.MIIo.M990$7LOPPF~FVWXX?yIJJ|A$HII "OM(M&(M$&M)%|^ GHH $/0
\\
 	 yyV,7! &*   !&'   	 	 	*  
&&83q6A	
 	

sU   D
GF $AF9F GFF 
GF 	G!F=8G=GGr  c                 j    dd l } |j                  | j                               j                         }|S )Nr   r  )r  r  r  s      rN   r  r  
  s,     "7>>%,,.1;;=LrP   c                 @    | j                  d      rt        |       S | S )z`
    Hash the token if it's a string and starts with "sk-"

    Else return the token as is
    r  r  )r  r  r  s    rN   r1  r1  
  s"     &&rP   c                   v    e Zd Zededededeee	f   fd       Z
edededee   defd       Zedefd	       Zy
)ProxyUpdateSpendn_retry_timesr   r  end_user_list_transactionsc                   K   t        | dz         D ]  }t        j                         }	 |j                  j                  t	        d            4 d {   }|j                         4 d {   }|j                         D ]@  \  }}	t        j                  	 |j                  j                  d|i||	dddd	|	iid
       B d d d       d {    d d d       d {     y  y 7 7 }7 # 1 d {  7  sw Y   ,xY w7 ## 1 d {  7  sw Y    y xY w# t        $ r?}
|| k\  rt        |
||       t        j                  d|z         d {  7   Y d }
~
Md }
~
wt        $ r}
t        |
||       Y d }
~
md }
~
ww xY ww)Nr   <   )seconds)timeoutr  F)r  r  blockedr  	incrementrH  rJ  r  rc  r  r  )ranger  r  txr   rc  rt  rJ   max_end_user_budgetr7  rQ  r   $_raise_failed_update_spend_exceptionr   sleepr   )r  r   r  r  irc  transactionri  end_user_idresponse_costr  s              rN   update_end_user_spendz&ProxyUpdateSpend.update_end_user_spend
  s     }q()AJ"(++..%b1 /    *113  w 8==?')&::F $#88??'0+&> 4?1>38/&
 07m8T.U&" @ 
 @	  , 3 *       , , *%8
FW mmAqD))) 4JBS s   &F*DC(DD,C*
-D0AC.DC,DDD D$F(D*D,D.D 4C75D <DDD	DD	DFD	F$.EEEFF*E>8F>FFdb_writer_clientc           	        K   d}d}|j                   d | }t        j                         }	 t        | dz         D ]  }	 t        j                  dd       }	t        |      dkD  r|	||	j                  d      s|	dz  }	t        j                  dj                  |	             |j                  |	dz   t        j                  |      d	d
i       d {   }
|
j                  dk(  r|j                   t        |      d  |_         nt        dt        |      |      D ]{  }||||z    }|D cg c]  }|j                  i |       }}|j                  j                   j#                  |d       d {    t        j                  dt        |       d       } |j                   t        |      d  |_         t        j                  t        |       dt        |j                                  y  y 7 c c}w 7 # t$        $ r/ |d}|| k\  r t'        j(                  d|z         d {  7   Y w xY w# t*        $ r5}|j                   t        |      d  |_         t-        |||       Y d }~y d }~ww xY ww)Nr   rB  r   SPEND_LOGS_URLr   /zbase_url: {}zspend/updatezContent-Typezapplication/json)urlrZ   headers   T)rZ   skip_duplicateszFlushed z logs to the DB.z% logs processed. Remaining in queue: r  r  )r  r  r  r3  r4  r   endswithr    rG   rH   postrF  rG  r   r  r  r5  create_manyr   r   r  r   r  )r  r   r  r  
BATCH_SIZEMAX_LOGS_PER_INTERVALlogs_to_processrc  r  base_urlr   jbatchentrybatch_with_datesr  s                   rN   update_spend_logsz"ProxyUpdateSpend.update_spend_logs
  s     
 	 (>>?U@UVYY[
8	=1,-/.!yy)94@HO,q0$0,8'005$OH,22>3H3H3RS)9)>)> (> 9!%O!<%35G$H *? * $
 $//36 - D D$'$8$:!" *@ "'q#o*>
!KA$3AJ$GE .30$) !. < <YY G0, 0 #0"2"2"D"D"P"P%5t #Q #   166"*3u:,6F G "L *@@_AUAWX &< -22"?344YZ]^k  _C  _C  [D  ZE  F U .$0 1 .yM)!--1---.  	3@3W3WO$&4M0 1
>O 		s   (I3H2 BG7G-AG7'G0,G7-G5.A;G7)H2 *I3+H2 ,I3-G70G77.H/%H(&H/+H2 .H//H2 2	I0;+I+&I3+I00I3rf   c                  8    ddl m}  | j                  d      du ryy)z
        returns True if should not update spend in db
        Skips writing spend logs and updates to key, team, user spend to DB
        r   general_settingsdisable_spend_updatesTF)r   r  r   r  s    rN   r  z&ProxyUpdateSpend.disable_spend_updates'  s"     	@ 78D@rP   N)r   r   r   staticmethodr  r  r   r	   r   r   r  r   r-   r  r   r  rj   rP   rN   r  r  
  s    **#* (* %)e$4	* *X EE#E #;/E (	E EN 	4 	 	rP   r  r   r  r  c                 F  K   d}|j                   j                  | ||       d{    t        j                  dj	                  t        | j                                     t        | j                        dkD  r"t        j                  || ||       d{    yy7 v7 w)z
    Batch write updates to db.

    Triggered every minute.

    Requires:
    user_id_list: dict,
    keys_list: list,
    team_list: list,
    spend_logs: list,
    r  )r   r  r  NzSpend Logs transactions: {}r   )r  r   r  r  )	r   #db_update_spend_transaction_handlerr    rG   rH   r   r  r  r  )r   r  r  r  s       rN   update_spendr	  4  s       M

2
2
V
V##+ W    %,,S1U1U-VW =//01400''/-	 1 
 	
 	
 5	
s"   $B!BA/B!BB!B!r  rc  c                     ddl }dt        |        }|dz    |j                         z   }t        j                         }||z
  }t	        j
                  |j                  | |d|             | )z
    Raise an exception for failed update spend logs

    - Calls proxy_logging_obj.failure_handler to log the error
    - Ensures error messages says "Non-Blocking"
    r   NzC[Non-Blocking]LiteLLM Prisma Client Exception - update spend logs: r  r	  r/  )rF   r   rI   r  r   r   rM  )r  rc  r  rF   r  r  r  r  s           rN   r  r  Y  s      NcRSfXV   $&)=)=)=)??Oyy{H:%I)) $)	 	* 	
 GrP   current_spendsoft_budget_limitc                    ddl m} |y|j                         }|j                  dk(  r% ||j                  dz   dd      t        d      z
  }n. ||j                  |j                  dz   d      t        d      z
  }||z
  j                  }|j                  dk(  r| }n| |j                  dz
  z  }| ||z  z   }||kD  rt        d       yy)	Nr   )dateF   r   daysz*Projected spend exceeds soft budget limit!T)	r   r  todaymonthyearr   r  dayrO   )r  r  r  r  	end_monthremaining_daysdaily_spend_estimateprojected_spends           rN   _is_projected_spend_over_limitr  u  s      JJLE {{baA.1BB	U[[1_a89!;LL	%'--N yyA~,,		A> $';n'LMO**BCrP   c                 X   dd l }|y |j                  j                         } |j                  |j                  |j                  dz   d       |j
                  d      z
  }||z
  j                  }| |j                  dz
  z  }||z  }||kD  r||z  }| |j
                  |      z   }	||	fS y )Nr   r   r  )r   r  r  r  r  r   r  r  )
r  r  r   r  r  r  daily_spendr  approx_dayslimit_exceed_dates
             rN   _get_projected_spend_over_limitr    s      MM!Eejj%++/1=@R@R@RA I  %'--N		AK "N2O**'+5!$6H$6$6K$HH  111rP   c           	      x    | ||y d|v r/|j                  d      }|d   }||vrt        d|  d| d| d      y )Nmodelsr   zInvalid model for team r  z.  Valid models for team are: r  )rW   r   )r   team_configr   valid_modelsmodel_in_requests        rN   _is_valid_team_configsr%    sm    +-1E;"x0'0</)'"5E4FFdeqdrrtu  rP   c                 :    t        | j                         dz        S )Ng    eA)r  	timestamp)dts    rN   _to_nsr)    s    r||~#$$rP   r   c                    || S | j                  d      xs i }|j                  d      xs i }|j                  dd      }|| S |j                  |      }|| S |j                  j                  d      }|| S t        | |      S )aM  
    Check if the model has guardrails defined and merge them with existing guardrails in the request data.

    Args:
        data: The request data dict
        llm_router: The LLM router instance to get deployment info from

    Returns:
        Modified data dict with merged guardrails (if any model-level guardrails exist)
    NrR   
model_infoid)r  
guardrails)r   get_deploymentrf  _merge_guardrails_with_existing)rZ   r   rR   r+  r  
deploymentmodel_level_guardrailss          rN   r  r    s      xx
#)rHl+1rJ~~dD)H **H*=J'66::<H% +41GHHrP   r1  c                     | j                         }|j                  di       }|j                  dg       }t        |t              s|r|gng }t        |t              s|r|gng }t	        t        ||z               |d<   |S )a  
    Merge model-level guardrails with any existing guardrails in the request data.

    Args:
        data: The request data dict
        model_level_guardrails: Guardrails defined at the model level

    Returns:
        Modified data dict with merged guardrails in metadata
    rR   r-  )rX   
setdefaultr   rU   r   r   )rZ   r1  r  rR   existing_guardrailss        rN   r/  r/    s     IIKM''
B7H",,|R8 )407J23PR ,d3(>#$B 	
 "#&9<R&R"STH\rP   c                    d}t        | t              rt        | j                  t              r| j                  }|S t        | j                  t              r!t        j                  | j                        }|S t        | d      rHt        | dd       }t        |t              r|}|S t        |t              r"t        j                  |      }|S t        |       }|S t        |       }|S )Nr   r   )	rU   r   r   r   rV   rF  rG  r  rS  )r  r  _errors      rN   get_error_message_strr7  
  s    M!]#ahh$HHM  $' JJqxx0M  Q	"Q	40F&#& &  FD) $

6 2
   FM  ArP   c                  x    t        j                  d      x} r| S t        t        j                  d            du ryy)z
    Get the Redoc URL from the environment variables.

    - If REDOC_URL is set, return it.
    - If NO_REDOC is True, return None.
    - Otherwise, default to "/redoc".
    	REDOC_URLNO_REDOCTNz/redocr3  r4  r?   )	redoc_urls    rN   _get_redoc_urlr=    s:     IIk**y*299Z()T1rP   c                  x    t        j                  d      x} r| S t        t        j                  d            du ryy)z
    Get the docs (Swagger UI) URL from the environment variables.

    - If DOCS_URL is set, return it.
    - If NO_DOCS is True, return None.
    - Otherwise, default to "/".
    DOCS_URLNO_DOCSTNr  r;  )docs_urls    rN   _get_docs_urlrB  /  s9     99Z((x(299Y'(D0rP   c           
         ddl m} t        j                  d|         t	        | t
              rUt        t        | ddt        |        d      t        j                  t        | dd      t        | d	|j                        
      S t	        | t              r| S t        dt        |       z   t        j                  t        | dd      |j                  
      S )zg
    Returns an Exception as ProxyException, this ensures all exceptions are OpenAI API compatible
    r   )r   zException: r   zerror()paramNoner   )r   r  rE  codezInternal Server Error, )fastapir   r    rX  rU   r   r   rS  r   r   internal_server_errorHTTP_500_INTERNAL_SERVER_ERROR)r  r   s     rN   handle_exception_on_proxyrK  @  s     ""[#45!]#Ax6#a&);< 66!Wf-M6+P+PQ	
 	
 
A~	&)CF222a&)22	 rP   c                  h    ddl m}  | s*t        dddt        j                  j
                   i      y)zC
    Raises an HTTPException if the user is not a premium user
    r   r   i  r   z=This feature is only available for LiteLLM Enterprise users. r   N)r   r   r   r   not_premium_userro   rM  s    rN   _premium_user_checkrO  Y  sN     8XYjY{Y{  ZB  ZB  YC  D
 	
 rP   r   c                 @    | |y|j                         }d}| |v rd}|S )zD
    Returns True if the model is in the llm_router model names
    FT)get_model_names)r   r   model_names
is_in_lists       rN   is_known_modelrT  h  s7     }
*,,.KJ
rP   	base_pathrO  c                 r    | j                  d      } |j                  d      }| s	|rd| S dS |s| S |  d| S )Nr  )rstriplstrip)rU  rO  s     rN   
join_pathsrY  w  sV      %ILLE #5'{,,  [%!!rP   request_base_urlc                     t               }||}n| }t               }|)|dk7  rt        ||      }t        ||      S t        ||      S t        ||      S )Nr   )get_proxy_base_urlget_server_root_pathrY  )rZ  rO  server_base_urlr  server_root_pathintermediate_urls         rN   get_custom_urlra    sh    (*O""#+-r!)(4DE.66h..($455rP   c                  ,    t        j                  d      S )z@
    Get the proxy base url from the environment variables.
    r,  r3  r4  rj   rP   rN   r\  r\    s     99%&&rP   c                  .    t        j                  dd      S )z
    Get the server root path from the environment variables.

    - If SERVER_ROOT_PATH is set, return it.
    - Otherwise, default to "/".
    SERVER_ROOT_PATHr  rc  rj   rP   rN   r]  r]    s     99'--rP   r   c                 P    ddl m} |t        t        j                  d| i      |S )Nr   r   r   r   )r   r   r   r   rJ  )r   r   s     rN   get_prisma_client_or_throwrg    s1    8==W%
 	
 rP   rh   c                     ddl }t        | t              sydt        |       cxk  rdk  r)n y|j	                  d|       ry|j	                  d|       ryy)	z
    Validates API key format:
    - sk- keys: must match ^sk-[A-Za-z0-9_-]+$
    - hashed keys: must match ^[a-fA-F0-9]{64}$
    - Length between 20 and 100 characters
    r   NFr  r   z^sk-[A-Za-z0-9_-]+$Tz^[a-fA-F0-9]{64}$)rerU   r   r   match)rh   ri  s     rN   is_valid_api_keyrk    sS     c3CH
 	 88*C088(#.rP   r  ra   )r   rX   r  rF  r3  r  r{  r  rF   r   r   email.mime.multipartr   email.mime.textr   typingr   r   r	   r
   r   r   r   r   r   litellm.constantsr   litellm.proxy._typesr   r   r   r   r   r   r	  r   r  ImportErrorrH  r   r   rJ   litellm.litellm_core_utils*litellm.litellm_core_utils.litellm_loggingr   r   r   r   r   litellm._loggingr    litellm._service_loggerr!   r"   litellm.caching.cachingr#   r$   litellm.exceptionsr%   %litellm.integrations.custom_guardrailr&   "litellm.integrations.custom_loggerr'   1litellm.integrations.SlackAlerting.slack_alertingr(   (litellm.integrations.SlackAlerting.utilsr)   r*   *litellm.litellm_core_utils.safe_json_dumpsr+   *litellm.litellm_core_utils.safe_json_loadsr,   'litellm.llms.custom_httpx.httpx_handlerr-   r.   r/   r0   r1   r2   litellm.proxy.auth.route_checksr3   litellm.proxy.db.create_viewsr4   r5   'litellm.proxy.db.db_spend_update_writerr6   litellm.proxy.db.log_db_metricsr7   litellm.proxy.db.prisma_clientr8   litellm.proxy.hooksr9   r:   'litellm.proxy.hooks.cache_control_checkr;   &litellm.proxy.hooks.max_budget_limiterr<   ,litellm.proxy.hooks.parallel_request_limiterr=   $litellm.proxy.litellm_pre_call_utilsr>   litellm.secret_managers.mainr?   )litellm.types.integrations.slack_alertingr@   litellm.types.utilsrA   rB   rC   opentelemetry.tracerD   _SpanrO   r\   r^   r   r  rV   r  r  r   r  r  r  r1  r  r	  r   r   r  r  tupler  r%  r)  r  r/  r7  r=  rB  rK  rO  r   rT  rY  ra  r\  r]  rg  rk  rj   rP   rN   <module>r     s       	     ( . $
 
 
 2  9 *  ! 1  2 @ 9 3 A ; K T > A F ?  8 H : 8 ; L J J 4 I P P1DD36d
 d
Pf fXJ

 
$ 
C CR,3 y l , %)!F
SMF
c]F
 3-F
Rc 	 	 	@ @F"
"
{+"
 $"
J#8D8-5e_D-5e_e_:%#I
#I$V,#I	#IL$  PT <Y 3 ( "x} " ~ 2
(3- Xf5E $ "# "c "c ""6S 6# 6# 6('HSM '.c . # $ ed  
O s   ,I7 7J