
    h                     .   d 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	m
Z
mZmZmZmZmZmZ ddlZddlmZ ddlmZ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"m#Z#m$Z$ dd	l%m&Z& dd
l'm(Z( ddl)m*Z* ddl+m,Z, e	r	ddl-m.Z.m/Z/ ne
Z.e
Z/ G d d      Z0y)z
Module responsible for

1. Writing spend increments to either in memory list of transactions or to redis
2. Reading increments from redis or in memory list of transactions and committing them to db
    N)datetime	timedelta)TYPE_CHECKINGAnyDictLiteralOptionalUnioncastoverload)verbose_proxy_logger)	DualCache
RedisCache)DB_SPEND_UPDATE_JOB_NAME)DB_CONNECTION_ERROR_TYPESBaseDailySpendTransactionDailyTagSpendTransactionDailyTeamSpendTransactionDailyUserSpendTransactionDBSpendUpdateTransactionsLitellm_EntityTypeLiteLLM_UserTableSpendLogsMetadataSpendLogsPayloadSpendUpdateQueueItem)DailySpendUpdateQueue)PodLockManager)RedisUpdateBuffer)SpendUpdateQueue)PrismaClientProxyLoggingc                      e Zd ZdZ	 d:dee   fdZdee   dee   dee   dee   d	ee   d
ee   dee	e
j                  eef      dee   dee   dee   fdZdee   dee   dee   fdZ	 d:dee   dee   dee   dedee   dee   fdZdee   dee   dee   dee   fdZdee   d	ee   dee   fdZd ej0                  d      fde	eef   dee   dee   dee   fdZdededefdZdededefd Zdededefd!Zdededed"e fd#Z!e"e#dededed$e$ee%f   d%e&d&   d'ed(ed)eddfd*              Z'e"e#dededed$e$ee(f   d%e&d+   d'ed(ed)eddfd,              Z'e"e#dededed$e$ee)f   d%e&d-   d'ed(ed)eddfd.              Z'e#dededed$e	e$ee%f   e$ee(f   e$ee)f   f   d%e&d/   d'ed(ed)eddfd0       Z'e#dededed$e$ee%f   fd1       Z*e#dededed$e$ee(f   fd2       Z+e#dededed$e$ee)f   fd3       Z,	 d;de	eef   ded4e&d5   dee-   fd6Z.	 d:de	eef   dee   fd7Z/	 d:dedee   ddfd8Z0	 d:dedee   ddfd9Z1y)<DBSpendUpdateWriterz
    Module responsible for

    1. Writing spend increments to either in memory list of transactions or to redis
    2. Reading increments from redis or in memory list of transactions and committing them to db
    Nredis_cachec                     || _         t        | j                         | _        t               | _        t               | _        t               | _        t               | _	        t               | _
        y )N)r$   )r$   r   redis_update_bufferr   pod_lock_managerr   spend_update_queuer   daily_spend_update_queuedaily_team_spend_update_queuedaily_tag_spend_update_queue)selfr$   s     c/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/proxy/db/db_spend_update_writer.py__init__zDBSpendUpdateWriter.__init__7   sV     '#4AQAQ#R  . 0"2"4(=(?%-B-D*,A,C)    tokenuser_idend_user_idteam_idorg_idkwargscompletion_response
start_timeend_timeresponse_costc           
        K   ddl m}m}m}m} ddlm}m} 	 t        j                  d|
 d| d| d|        |j                         du ry |+t        |t              r|j                  d	      r
 ||
      }n|}ddlm}  |||||	      }|
xs d|d<   t        |d   t               r|d   j#                         |d<   t        |d   t               r|d   j#                         |d<   t%        j&                  | j)                  |
|||||             t%        j&                  | j+                  |
||             t%        j&                  | j-                  |
|||             t%        j&                  | j/                  |
||             |du r| j1                  ||       d {    nt        j2                  d       t%        j&                  | j5                  ||             t%        j&                  | j7                  ||             t%        j&                  | j9                  ||             t        j                  d       y 7 # t:        $ r- t        j                  dt=        j>                                 Y y w xY ww)Nr   )disable_spend_logslitellm_proxy_budget_nameprisma_clientuser_api_key_cache)ProxyUpdateSpend
hash_tokenz&Enters prisma db call, response_cost: z	, token: z; user_id: z; team_id: Tzsk-)r0   )get_logging_payload)r5   response_objr7   r8   g        spend	startTimeendTime)r9   r1   r=   r>   r<   r2   )r9   hashed_tokenr=   )r9   r3   r1   r=   )r9   r4   r=   F)payloadr=   zwdisable_spend_logs=True. Skipping writing spend logs to db. Other spend updates - Key/User/Team table will still occur.zRuns spend update on all tablesz Error updating Prisma database: ) litellm.proxy.proxy_serverr;   r<   r=   r>   litellm.proxy.utilsr?   r@   r   debugdisable_spend_updates
isinstancestr
startswith1litellm.proxy.spend_tracking.spend_tracking_utilsrA   r   	isoformatasynciocreate_task_update_user_db_update_key_db_update_team_db_update_org_db_insert_spend_log_to_dbinfo3add_spend_log_transaction_to_daily_user_transaction3add_spend_log_transaction_to_daily_team_transaction2add_spend_log_transaction_to_daily_tag_transaction	Exception	traceback
format_exc)r,   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r;   r<   r=   r>   r?   r@   rF   rA   rG   s                       r-   update_databasez#DBSpendUpdateWriter.update_databaseC   s    	
 	
 	E`	 &&8yQVPWWbcjbkkvw~v  A  5574? Zs%;@P@PQV@W)6$ *0%!	G  -3GG'+.9'.{';'E'E'G$'),h7%,Y%7%A%A%C	"$$"/#"/'9.G + % 	 ##"/!-"/ $  $$"/##"/	 %  ##"/!"/ $  "U*22#"/ 3   
 %)) N HH#"/ I  HH#"/ I  GG#"/ H  !&&'HI=>  	 &&293G3G3I2JK	sH   J 3I J EI "I#B!I J I 3I=:J <I==J rF   r=   c                    K   	 ||y | j                   j                  t        t        j                  ||             d {    y 7 # t
        $ r(}t        j                  dt        |              |d }~ww xY ww)Nentity_type	entity_idr9   updatez'Update Key DB Call failed to execute - )	r(   
add_updater   r   KEYr\   r   	exceptionrM   )r,   r9   rF   r=   es        r-   rT   z"DBSpendUpdateWriter._update_key_db   s     	#}'<))44+ 2 6 6*"/ 5     	 **9#a&B G		sD   A>A
 A>9A
 AA
 A>A
 
	A;#A66A;;A>r>   r<   c           	        K   |j                  |       d{   }|t        |t              rt        d	i |}	 ||g}t        j
                  dkD  r|j                  |       |D ]C  }	|	| j                  j                  t        t        j                  |	|             d{    E |?| j                  j                  t        t        j                  ||             d{    yyy7 7 K7 # t        $ rC}
t        j                  ddt!        |
       dt#        j$                          z          Y d}
~
yd}
~
ww xY ww)
zi
        - Update that user's row
        - Update litellm-proxy-budget row (global proxy spend)
        )keyNr   ra   rd   z[91mz&Update User DB call failed to execute 
 )async_get_cacherL   dictr   litellm
max_budgetappendr(   rf   r   r   USEREND_USERr\   r   rX   rM   r]   r^   )r,   r9   r1   r=   r>   r<   r2   existing_user_objuser_ids_idri   s              r-   rS   z#DBSpendUpdateWriter._update_user_db   s^     #5"D"D"D"QQ(Z8I4-P 1 F4E F	(#9&&*OO$=>#C"55@@#7,>,C,C*-.;$ A    $ *11<<3(:(C(C&1*7  =    +# )	 R  	 %%:3q6("YEYEYE[D\]^ 	sc   EC/!E0C5 ,9C5 %C1&AC5 'C3(C5 ,E1C5 3C5 5	E>9D<7E<EEc                 
  K   	 ||t        j                  d       y | j                  j                  t	        t
        j                  ||             d {    	 |Gd| d| }| j                  j                  t	        t
        j                  ||             d {    y y 7 O7 # t        $ r Y y w xY w# t        $ r=}t        j                  dt        |       dt        j                                 |d }~ww xY ww)NzZtrack_cost_callback: team_id is None or prisma_client is None. Not tracking spend for teamra   rd   z	team_id::z::user_id::z#Update Team DB failed to execute - rl   )r   rJ   r(   rf   r   r   TEAMTEAM_MEMBERr\   rX   rM   r]   r^   )r,   r9   r3   r1   r=   team_member_keyri   s          r-   rU   z#DBSpendUpdateWriter._update_team_db  s!    !	-"7$**p ))44+ 2 7 7%"/ 5   &(1'+gY&OO11<<3(:(F(F&5*7  =    '   	 %%5c!fXR	@T@T@V?WX G		s{   DB: D9B: B'B: AB+  B)!B+ %D'B: )B+ +	B74B: 5D6B77B: :	D 8C;;D  Dc                 T  K   	 ||t        j                  d       y | j                  j                  t	        t
        j                  ||             d {    y 7 # t        $ r=}t        j                  dt        |       dt        j                                 |d }~ww xY ww)NzXtrack_cost_callback: org_id is None or prisma_client is None. Not tracking spend for orgra   rd   z"Update Org DB failed to execute - rl   )r   rJ   r(   rf   r   r   ORGANIZATIONr\   rX   rM   r]   r^   )r,   r9   r4   r=   ri   s        r-   rV   z"DBSpendUpdateWriter._update_org_db.  s     	~!6$**n ))44+ 2 ? ?$"/ 5     	 %%4SVHBy?S?S?U>VW G		sD   B(A B(9A AA B(A 	B%(8B  B%%B(SPEND_LOGS_URLrG   spend_logs_urlreturnc                 >  K   t        j                  dj                  |j                  d      |j                  d                   |||j                  j                  |       |S ||j                  j                  |       |S t        j                  d       |S w)Nz3Writing spend log to db - request_id: {}, spend: {}
request_idrC   9prisma_client is None. Skipping writing spend logs to db.)r   rX   formatgetspend_log_transactionsrr   rJ   )r,   rG   r=   r   s       r-   rW   z+DBSpendUpdateWriter._insert_spend_log_to_dbH  s      	!!AHHL)7;;w+?	

 $)C0077@  &0077@ 	 !&&K s   BBn_retry_timesproxy_logging_objc                    K   t        j                         r| j                  |||       d{    y| j                  |||       d{    y7 "7 w)a=  
        Handles commiting update spend transactions to db

        `UPDATES` can lead to deadlocks, hence we handle them separately

        Args:
            prisma_client: PrismaClient object
            n_retry_times: int, number of retry times
            proxy_logging_obj: ProxyLogging object

        How this works:
        - Check `general_settings.use_redis_transaction_buffer`
            - If enabled, write in-memory transactions to Redis
            - Check if this Pod should read from the DB
        else:
            - Regular flow of this method
        )r=   r   r   N)r   %_should_commit_spend_updates_to_redis&_commit_spend_updates_to_db_with_redis0_commit_spend_updates_to_db_without_redis_buffer)r,   r=   r   r   s       r-   #db_update_spend_transaction_handlerz7DBSpendUpdateWriter.db_update_spend_transaction_handler^  sn     . BBD==++"3 >    GG++"3 H   s!   ,AAAAAAc                   K   | j                   j                  | j                  | j                  | j                  | j
                         d{    | j                  j                  t               d{   rOt        j                  d       	 | j                   j                          d{   }|| j                  ||||       d{    | j                   j                          d{   }|!t        j                  ||||       d{    | j                   j!                          d{   }|!t        j#                  ||||       d{    | j                   j%                          d{   }|!t        j'                  ||||       d{    | j                  j-                  t               d{    yy7 ~7 Y7 #7 7 7 7 7 7 e7 D# t(        $ r"}t        j*                  d|        Y d}~hd}~ww xY w7 L# | j                  j-                  t               d{  7   w xY ww)a  
        Handler to commit spend updates to Redis and attempt to acquire lock to commit to db

        This is a v2 scalable approach to first commit spend updates to redis, then commit to db

        This minimizes DB Deadlocks since
            - All pods only need to write their spend updates to redis
            - Only 1 pod will commit to db at a time (based on if it can acquire the lock over writing to DB)
        )r(   r)   r*   r+   N)
cronjob_idzacquired lock for spend updatesr=   r   r   db_spend_update_transactionsr   r=   r   daily_spend_transactionsz Error committing spend updates: )r&   &store_in_memory_spend_updates_in_redisr(   r)   r*   r+   r'   acquire_lockr   r   rJ   -get_all_update_transactions_from_redis_buffer_commit_spend_updates_to_db9get_all_daily_spend_update_transactions_from_redis_bufferr#   update_daily_user_spend>get_all_daily_team_spend_update_transactions_from_redis_bufferupdate_daily_team_spend=get_all_daily_tag_spend_update_transactions_from_redis_bufferupdate_daily_tag_spendr\   errorrelease_lock)	r,   r=   r   r   r   daily_spend_update_transactions$daily_team_spend_update_transactions#daily_tag_spend_update_transactionsri   s	            r-   r   z:DBSpendUpdateWriter._commit_spend_updates_to_db_with_redis  s     &&MM#66%)%B%B*.*L*L)-)J)J	 N 
 	
 	
 &&33/ 4 
 
 
 !&&'HI022``bb - 0;::&3&3*;5Q	 ;    22llnn 0 3>-EE&3&3*;1P	 F    22qqss 5 8C-EE&3&3*;1U	 F    22pprr 4 7B-DD&3&3*;1T	 E    ++887 9   g
	

 c o t s  S$**-MaS+QRRSd++887 9   s  AIG'I5G6IG# .G/G# G!G# /G0"G# G!G# 4G5"G# G!G# 9G:"G# G!G# !#IHIIG# G# G# G# G# G# G# !G# #	H,H	H 	HH I$H>7H:8H>>Ic                   K   | j                   j                          d{   }| j                  ||||       d{    t        t        t
        t        f   | j                  j                          d{         }t        j                  ||||       d{    t        t        t
        t        f   | j                  j                          d{         }t        j                  ||||       d{    t        t        t
        t        f   | j                  j                          d{         }t        j!                  ||||       d{    y7 =7 #7 7 7 7 o7 87 w)a4  
        Commits all the spend `UPDATE` transactions to the Database

        This is the regular flow of committing to db without using a redis buffer

        Note: This flow causes Deadlocks in production (1K RPS+). Use self._commit_spend_updates_to_db_with_redis() instead if you expect 1K+ RPS.
        Nr   r   )r(   5flush_and_get_aggregated_db_spend_update_transactionsr   r   r   rM   r   r)   8flush_and_get_aggregated_daily_spend_update_transactionsr#   r   r   r*   r   r   r+   r   )r,   r=   r   r   r   r   r   r   s           r-   r   zDDBSpendUpdateWriter._commit_spend_updates_to_db_without_redis_buffer  s    " ))__aa 	% ..''/)E	 / 
 	
 	
 +///0//hhjj+
'
 "99''/%D	 : 
 	
 	
 04//044mmoo0
,
 "99''/%I	 : 
 	
 	
 /3../33llnn/
+
 "88''/%H	 9 
 	
 	
Y b	
 k	
 p	
 o	
s   E/EE/E 8E/6E#
7$E/E%8E/E'
$E/9E):8E/2E+
3$E/E-E/ E/#E/%E/'E/)E/+E/-E/r   c           
      n  K   ddl m}m} |d   }t        j                  dj                  |             |t        |j                               dkD  rt        |dz         D ]  }t        j                         }		 |j                  j                  t        d      	      4 d{   }
|
j                         4 d{   }|j                         D ](  \  }}|j                  j!                  d
|idd|ii       * ddd      d{    ddd      d{     n |d   }t        j                  dj                  |             |9t        |j                               dkD  r|j+                  ||||       d{    |d   }t        j                  dj                  |             |t        |j                               dkD  rt        |dz         D ]  }t        j                         }		 |j                  j                  t        d      	      4 d{   }
|
j                         4 d{   }|j                         D ](  \  }}|j,                  j!                  d|idd|ii       * ddd      d{    ddd      d{     n |d   }t        j                  dj                  |             |t        |j                               dkD  rt        |dz         D ]  }t        j                         }		 |j                  j                  t        d      	      4 d{   }
|
j                         4 d{   }|j                         D ]M  \  }}t        j                  dj                  ||             |j.                  j!                  d|idd|ii       O ddd      d{    ddd      d{     n |d   }t        j                  dj                  |             |t        |j                               dkD  rt        |dz         D ]  }t        j                         }		 |j                  j                  t        d      	      4 d{   }
|
j                         4 d{   }|j                         D ]Q  \  }}|j1                  d      d   }|j1                  d      d   }|j2                  j!                  ||ddd|ii       S ddd      d{    ddd      d{     n |d   }t        j                  d j                  |             |t        |j                               dkD  rt        |dz         D ]  }t        j                         }		 |j                  j                  t        d      	      4 d{   }
|
j                         4 d{   }|j                         D ](  \  }}|j4                  j!                  d!|idd|ii       * ddd      d{    ddd      d{     y yyy7 7 i7 !# 1 d{  7  sw Y   2xY w7 *# 1 d{  7  sw Y   ;xY w# t"        $ r<}||k\  r |||	|       t%        j&                  d|z         d{  7   Y d}~9d}~wt(        $ r} |||	|       Y d}~Vd}~ww xY w7 A7 7 7 J# 1 d{  7  sw Y   [xY w7 S# 1 d{  7  sw Y   dxY w# t"        $ r<}||k\  r |||	|       t%        j&                  d|z         d{  7   Y d}~bd}~wt(        $ r} |||	|       Y d}~d}~ww xY w7 17 7 # 1 d{  7  sw Y   xY w7 # 1 d{  7  sw Y   xY w# t"        $ r<}||k\  r |||	|       t%        j&                  d|z         d{  7   Y d}~d}~wt(        $ r} |||	|       Y d}~d}~ww xY w7 7 7 # 1 d{  7  sw Y   xY w7 # 1 d{  7  sw Y   (xY w# t"        $ r<}||k\  r |||	|       t%        j&                  d|z         d{  7   Y d}~Od}~wt(        $ r} |||	|       Y d}~ld}~ww xY w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%        j&                  d|z         d{  7   Y d}~d}~wt(        $ r} |||	|       Y d}~d}~ww xY ww)"zN
        Commits all the spend `UPDATE` transactions to the Database

        r   )r?   $_raise_failed_update_spend_exceptionuser_list_transactionszUser Spend transactions: {}N   <   )seconds)timeoutr1   rC   	incrementwheredatari   r7   r      end_user_list_transactionszEnd-User Spend transactions: {})r   r=   r   r   key_list_transactionszKEY Spend transactions: {}r0   team_list_transactionszTeam Spend transactions: {}z#Updating spend for team id={} by {}r3   team_member_list_transactionsz&Team Membership Spend transactions: {}z::   )r3   r1   org_list_transactionszOrg Spend transactions: {}organization_id)rI   r?   r   r   rJ   r   lenkeysrangetimedbtxr   batch_itemslitellm_usertableupdate_manyr   rQ   sleepr\   update_end_user_spendlitellm_verificationtokenlitellm_teamtablesplitlitellm_teammembershiplitellm_organizationtable)r,   r=   r   r   r   r?   r   r   ir7   transactionbatcherr1   r9   ri   r   r   r0   r   r3   r   rk   r   r4   s                           r-   r   z/DBSpendUpdateWriter._commit_spend_updates_to_db  sf	    	
 ">>V!W"")001GH	
 #.*//12Q6=1,-!YY[
,//22 )" 5  3   " "$#.#5#5#7 " "7 "8!=!=!?! ' - ' 9 9 E E+4g*>*1K3O)P !F !" "@	" "" "  .B &B(&
" 	""-445OP	
 '2.3356:"88++"3+E	 9    !==T U""(//0EF	
 !,5J5O5O5Q1RUV1V=1,-!YY[
,//22 )" 5  3   " "$#.#5#5#7 " "7 "7!<!<!>! % - ' A A M M+2E*:*1K3O)P !N !" "?	" "" "  .B ">>V!W"")001GH	
 #.*//12Q6=1,-!YY[
!,//22 )" 5  3   " "$#.#5#5#7 " "7 "8!=!=!?! ' - 4 : :$I$P$P(/%&!"
 !( 9 9 E E+4g*>*1K3O)P !F !" "@	" "" "" ) .L )E+)
% 	""4;;-	
 *516689A==1,-!YY[
 ,//22 )" 5  3   " "$#.#5#5#7 " "7 "?!D!D!F! # - +.))D/!*<*-))D/!*< ' > > J J6='*R*1K3O)P !K !" "G	" "" "  ' .J !==T U""(//0EF	
 !,5J5O5O5Q1RUV1V=1,-!YY[
,//22 )" 5  3   " "$#.#5#5#7 " "7 "7!<!<!>! & - ' A A M M+<f*E*1K3O)P !N !" "?	" "" "  . 2W,q"" " " " "" " " " 1 
.]*<'1.? "--1---  8
FW  "" " " " "" " " " 1 
.]*<'1.? "--1---  8
FW """ " " " "" " " "$ 1 
.]*<'1.? "--1---  8
FW *"" " " " "" " " "" 1 
.]*<'1.? "--1---  8
FW "" " " " "" " " " 0 
.]*<'1.? "--1---  8
FW s]  A5d58*Y"X!#Y&Y;X$
<Y?<X*;YX'YYY YA"d5=Z>>A0d5/*[9[[9[#2[
3[#6<[
2[#=[>[#[9[ [9A0d5*^-].^1^ ]!
^ 
A!]'+^ 6]$7^ ;^]=^A0d5<*`3&_;'`3*`?_>
 `A%`(`3`4`8`3``3A/d58*c"b#c&b:;b
<b:?<b!;b:bb:cb7cd5!Y$Y'Y*X=0X31X=8Y YY		Y
Y	Y	Z;"+ZZZd5Z;%Z60d56Z;;d5[9[#[#
[[[[# [9#[6	)[,*[6	1[99	]+\9-\0.\93d59]]d5]d5^!^ $^ ']:-]0.]:5^ =^ ^	^	^	^	_8+_
__d5_8"_3-d53_88d5;`3>```
````3`0	#`&$`0	+`33	b<+a3'a*(a3-d53b?b
d5bd5cb:b:!b4'b*(b4/b:7c:c	 cc	cd5c	d2+ddd
d5d2d-'d5-d22d5r   rb   userentity_id_field
table_nameunique_constraint_namec                    K   y wNrm   r   r=   r   r   rb   r   r   r   s           r-   _update_daily_spendz'DBSpendUpdateWriter._update_daily_spend        	   teamc                    K   y wr   rm   r   s           r-   r   z'DBSpendUpdateWriter._update_daily_spend  r   r   tagc                    K   y wr   rm   r   s           r-   r   z'DBSpendUpdateWriter._update_daily_spend(  r   r   )r   r   r   c                 $  K   ddl m} t        j                  d|j	                          dt        |              d}	t        j                         }
	 t        | dz         D ]u  }	 t        t        |j                               d|	       }t        |      dk(  rt        j                  d| d	        y|j                  j                         4 d{   }|j                         D ]w  \  }}|j                  |      }|||d
|d
   d|d   d|d   d|j                  d      xs dd|j                  d      xs dii}t        ||      }||d
|d
   d|d   d|j                  d      d|j                  d      d|j                  d      d|j                  d      d|d   d|d   d|d   d|d   d|d   d|d   i}d|v r|j                  dd      |d<   d|v r|j                  dd      |d<   d|d   id|d   id|d   id|d   id|d   id|d   id}d|v rd|j                  dd      i|d<   d|v rd|j                  dd      i|d<   |j                  |||d       z ddd      d{    t        j                   dt        |       d| dt        j                         |
z
  d d!       |j#                         D ]  }|j%                  |d         y y7 	7 p# 1 d{  7  sw Y   xY w# t&        $ r<}|| k\  r |||
|"       t)        j*                  d#|z         d{  7   Y d}~d}~ww xY w# t,        $ rH}d$t/               v r'j#                         D ]  }|j%                  |d         |||
|"       Y d}~yd}~ww xY ww)%z^
        Generic function to update daily spend for any entity type (user, team, tag)
        r   )r   zDaily z Spend transactions: d   r   Nz)No new transactions to process for daily z spend updatedateapi_keymodelcustom_llm_provider mcp_namespaced_tool_namemodel_groupprompt_tokenscompletion_tokensrC   api_requestssuccessful_requestsfailed_requestscache_read_input_tokenscache_creation_input_tokensr   )r   r   rC   r   r   r   )createre   r   z
Processed z daily z transactions in z.2fsr   r   transactions_to_process)rI   r   r   rJ   
capitalizer   r   r   ro   listr   r   r   r   getattrupsertrX   r   popr   rQ   r   r\   locals)r   r=   r   r   rb   r   r   r   r   
BATCH_SIZEr7   r   r   r   _r   rc   where_clausetablecommon_dataupdate_datark   ri   s                          r-   r   z'DBSpendUpdateWriter._update_daily_spend7  s    $ 	M""[++-..CCH`DaCbc	
 
YY[
J	=1,-@..25;;=>{
K/+ 23q8,22G}Tab ,//668 b bG.E.K.K.MNA{(3(HI !7$3Y$*K,?$-{9/E$+[-A$9;??(=<& <* (*$>(BA& A* (*9",L$ %,GZ$@E !0 &F(; );y+A ')A -{}/M :KOO$>=" !6{$98" !0_1M 3[AT5U 'W)= .N0K 5{$98" !2;?P3Q'+K.  9KG$/OO4Mq$Q !,,E F  =K$/OO4QST$U !,,I J %0_1M2" %0=P1Q6" +6{77K)L$/^1L1" %0=R1S8" %0=N1O4"+K(  9KG$/(A12&J",E F
  =K$/(Eq2&N",I J "LL&2.9.9&" ) w /Nb bH )--$S)@%A$B'+Vghlhqhqhs  wA  iA  BE  hF  FG  H
  7;;=044S$?  > q .b b b b b\ 1 .M)<'1.?
 "--1---.  	(FH42779C,00d; :0
>O 		s   ANL< %AK41L< 2N3K4KK4FK!K4,K-A)K4L< NL< NK4K4K1	%K(&K1	-K44	L9=+L4(L+)L4.L< 4L99L< <	N>NNNNc           
      Z   K   t         j                  | |||dddd       d{    y7 w)zk
        Batch job to update LiteLLM_DailyUserSpend table using in-memory daily_spend_transactions
        r   r1   litellm_dailyuserspendGuser_id_date_api_key_model_custom_llm_provider_mcp_namespaced_tool_namer   Nr#   r   r   s       r-   r   z+DBSpendUpdateWriter.update_daily_user_spend  =      "55''/%=%/#l 6 	
 		
 		
   !+)+c           
      Z   K   t         j                  | |||dddd       d{    y7 w)zk
        Batch job to update LiteLLM_DailyTeamSpend table using in-memory daily_spend_transactions
        r   r3   litellm_dailyteamspendGteam_id_date_api_key_model_custom_llm_provider_mcp_namespaced_tool_namer   Nr   r   s       r-   r   z+DBSpendUpdateWriter.update_daily_team_spend  r   r   c           
      Z   K   t         j                  | |||dddd       d{    y7 w)zj
        Batch job to update LiteLLM_DailyTagSpend table using in-memory daily_spend_transactions
        r   litellm_dailytagspendCtag_date_api_key_model_custom_llm_provider_mcp_namespaced_tool_namer   Nr   r   s       r-   r   z*DBSpendUpdateWriter.update_daily_tag_spend  s=      "55''/%=!.#h 6 	
 		
 		
r   type)r   r   request_tagsc                   K   ddg}|dk(  rdg|}n$|dk(  rdg|}n|dk(  rdg|}nt        d|       t        fd|D              st        j                  d	| d
       y ddg}t	        fd|D              st        j                  d| d
       y dv rn"dv rdvsdvrt        j                  d       y |j                        }t        j                  d|        t        j                  d         }|j                  di       xs i }	t        d   t              r(d   j                         }
|
j                  d      d   }nHt        d   t              rd   j                  d      d   }nt        j                  dd    d       y 	 t        |d   j                  dd       j                  dd       j                  dd       j                  dd       d   d   d   d|dk(  rdnd|dk7  rdnd|	j                  dd      xs d|	j                  dd      xs d       }|S # t         $ r}|d }~ww xY ww)!NrD   r   r   r   r3   r  zInvalid type: c              3   &   K   | ]  }|v  
 y wr   rm   .0rk   rG   s     r-   	<genexpr>z]DBSpendUpdateWriter._common_add_spend_log_transaction_to_daily_transaction.<locals>.<genexpr>+  s     ;c3'>;   zMissing expected keys: z9, in payload, skipping from daily_user_spend_transactionsr   r   c              3   &   K   | ]  }|v  
 y wr   rm   r  s     r-   r  z]DBSpendUpdateWriter._common_add_spend_log_transaction_to_daily_transaction.<locals>.<genexpr>2  s     ?c3'>?r  zMissing any expected keys: r   r   zbMissing custom_llm_provider or model_group in payload, skipping from daily_user_spend_transactionszLogged request status: metadatausage_objectTr   zInvalid start time: z-, skipping from daily_user_spend_transactionsr   r   rC   r   successr   r   )r   r   r   r   r   r   r   r   rC   r   r   r   r   r   )
ValueErrorallr   rJ   anyget_request_statusrX   jsonloadsr   rL   r   rP   r   rM   r   r\   )r,   rG   r=   r  common_expected_keysexpected_keysany_expected_keysrequest_status	_metadata	usage_objr7   r   daily_transactionri   s    `            r-   6_common_add_spend_log_transaction_to_daily_transactionzJDBSpendUpdateWriter._common_add_spend_log_transaction_to_daily_transaction  s     !,Y76>#;&:;MV^&>)=>M^#+C.BCM~dV455;];; &&)-8qr $&@A?->?? &&-.?-@@yz '72!0M4P &&t &99'B!!$;N;K"LM'+zz'*2E'F	MM."5;	gk*H5 -779J##C(+D,c2;'--c215D &&&w{';&<<ij 	 9	*kk'40#KKt<)05OQU)V$+KK0Et$L%o6")*=">g&)79)DA!%3y%@a(16OQR(S ),5MM11- - %!( %$ 	G	s+   FI	BH6 5I	6	I?III	c           
      *  K   |t        j                  d       y| j                  ||d       d{   }|y|d    d|d    d|d    d|d    d|d    	}t        dd	|d   i|}| j                  j                  ||i
       d{    y7 ]7 w)z
        Add a spend log transaction to the `daily_spend_update_queue`

        Key = @@unique([user_id, date, api_key, model, custom_llm_provider])    )

        If key exists, update the transaction with the new spend and usage
        Nr   r   r   r   r   r   r   r1   rd   rm   )r   rJ   r!  r   r)   rf   r,   rG   r=   base_daily_transactiondaily_transaction_keyr   s         r-   rY   zGDBSpendUpdateWriter.add_spend_log_transaction_to_daily_user_transactionh  s       &&K  MM  	
 ")#*6?"315KF5S4TTUV]^gVhUiijkrszk{j||}  F  G\  ]  ~^  !_5 
FO
'=
 ++66)+<= 7 
 	
 	
	
s"   /BBAB	B
BBc           
      `  K   |t        j                  d       y | j                  ||d       d {   }|y |d   t        j                  d       y |d    d|d    d|d    d|d    d|d	    	}t        dd|d   i|}| j                  j                  ||i
       d {    y 7 x7 w)Nr   r   r3   z>team_id is None for request. Skipping incrementing team spend.r   r   r   r   r   rd   rm   )r   rJ   r!  r   r*   rf   r#  s         r-   rZ   zGDBSpendUpdateWriter.add_spend_log_transaction_to_daily_team_transaction  s,    
   &&K  MM  	
 ")9% &&P #*9#5"6a8Nv8V7WWXY`ajYkXllmnuv}n~m  @A  BI  J_  B`  Aa  !b5 
I&
*@
 00;;)+<= < 
 	
 	
! 	
s"   /B.B*A2B.$B,%B.,B.c                   K   |t        j                  d       y | j                  ||d       d {   }|y |d   t        j                  d       y g }t        |d   t              rt        j                  |d         }n*t        |d   t              r|d   }nt        d|d          |D ]Q  }| d|d    d|d    d|d    d|d	    	}t        dd
|i|}| j                  j                  ||i       d {    S y 7 7 	w)Nr   r  zBrequest_tags is None for request. Skipping incrementing tag spend.zInvalid request_tags: r   r   r   r   r   r   rd   rm   )r   rJ   r!  rL   rM   r  r  r   r  r   r+   rf   )r,   rG   r=   r$  r  r   r%  r   s           r-   r[   zFDBSpendUpdateWriter.add_spend_log_transaction_to_daily_tag_transaction  sz    
   &&K  MM  	
 ")>"* &&T gn-s3::gn&=>L/6">2L5gn6M5NOPPC'*e1-CF-K,LAgV_N`Maabcjkrcsbttuv}  T  wU  vV  %W! 8 !!1! 33>>-/@A ?     '2s"   /DDC	D;D<DDr   )r   )2__name__
__module____qualname____doc__r	   r   r.   rM   ro   r
   rp   ModelResponser   r\   r   floatr_   r    rT   r   rS   rU   rV   osgetenvr   rW   intr!   r   r   r   r   r   r   staticmethodr   r   r   r   r   r   r   r   r   r   r!  rY   rZ   r[   rm   r/   r-   r#   r#   /   s    -1
Dj)
Dw }w #	w
 c]w #w w w &eG,A,A3	,Q&RSw X&w 8$w  wr sm  -	< &*// #/  -	/
 &/ $,C=/ c]/b(( #( #	(
  -(T   -	: 15(1		2B(C	t--.  - !	
 
,	,### # (	#JL#L L (	L\B
#B
 B
 (	B
Hs#s s (	s
 '@sn 

#
 (
 #'s,E'E"F	

 V_
 
 
 !$
 

  
 

#
 (
 #'s,E'E"F	

 V_
 
 
 !$
 

  
 

#
 (
 #'s,D'D"E	

 U^
 
 
 !$
 

  
 cc#c (c #(//0//0../1#
	c 23c c c !$c 
c cJ 

#
 (
 #'s,E'E"F	
 
( 

#
 (
 #'s,E'E"F	
 
( 

#
 (
 #'s,D'D"E	
 
0 9?	Jt--.J $J 45	J
 
+	,J^ 15 
t--. 
  - 
J 15
!
  -
 
	
F 15'!'  -' 
	'r/   r#   )1r+  rQ   r  r.  r   r]   r   r   typingr   r   r   r   r	   r
   r   r   rp   litellm._loggingr   litellm.cachingr   r   litellm.constantsr   litellm.proxy._typesr   r   r   r   r   r   r   r   r   r   r   >litellm.proxy.db.db_transaction_queue.daily_spend_update_queuer   6litellm.proxy.db.db_transaction_queue.pod_lock_managerr   9litellm.proxy.db.db_transaction_queue.redis_update_bufferr   8litellm.proxy.db.db_transaction_queue.spend_update_queuer   rI   r    r!   r#   rm   r/   r-   <module>r;     sw      	   ( U U U  1 1 6    R W U>>LLb br/   