Ë
    tPêji ã            5       óà!  — U 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 d dl	m
Z
mZ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mZmZmZmZmZ d dlmZ d dlZd dlmZ d dl m!Z! d d	l"­ d d
l"m#Z#m$Z$ d dl%m&Z& d dl'm(Z(m)Z) d dl*m+Z+ d dl,m-Z- d dl.m/Z/ d dl0m1Z1 d dl2m3Z3 e
rd dl4m5Z6 d dl7m8Z8 d dl9m:Z: neZ8 e«       Z;ee<d<   dZ=ee<d<   e! e>e!¬«      fZ?ee<d<    ed«      Z@ G d„ de«      ZA G d„ de«      ZB G d„ d e«      ZC G d!„ d"e«      ZD G d#„ d$e«      ZE G d%„ d&e«      ZF G d'„ d(e«      ZG G d)„ d*e«      ZH G d+„ d,e«      ZI G d-„ d.e«      ZJ G d/„ d0e«      ZK G d1„ d2e«      ZL G d3„ d4e«      ZM G d5„ d6e«      ZN G d7„ d8e«      ZO G d9„ d:e«      ZP G d;„ d<e«      ZQ G d=„ d>e«      ZR G d?„ d@e«      ZS G dA„ dBedC¬D«      ZT G dE„ dFe«      ZUdGe8dHeVdIeWdJee@   fdK„ZXdGe8dHeVdIeWdJee@   dz  fdL„ZY G dM„ dNe«      ZZ G dO„ dPe«      Z[dGe8dJe-dQ   fdR„Z\dGe8dJeZfdS„Z]dGe8dJe[fdT„Z^dGe8dUeeVeWf   dVeeVeVf   dWe_dXedJeeA   fdY„Z`dGe8dZeVdJeBdz  fd[„ZadGe8dUeeVeWf   dJe_fd\„ZbdGe8d]eeVdz     dJeeR   fd^„ZcdGe8d_eVdJeAdz  fd`„ZddGe8daeeV   dJeeA   fdb„Zee;jÍ                  dcddg ee&«      gdC¬e«       ee&«      fdfegfdg„«       Zh�dCdh„Zie;jÍ                  diddg ee&«      gdC¬e«       ejÔ                  ddj¬k«       ee&«      fdleVdz  dfegfdm„«       Zke;jÍ                  dnddg ee&«      gdodpelem   ii¬q«       ejÔ                  ddr¬k«       ejÔ                  dds¬k«      fdteVdz  dueVdz  fdv„«       Zndfegdteduefdw„Zoe;jÍ                  dxddg ee&«      gdodpelem   iidC¬y«       ejÔ                  ddz¬k«       ejÔ                  dd{¬k«       ee&«      fdteVdz  dueVdz  dfegfd|„«       Zpdfegdteduefd}„Zqe;jÍ                  d~ddg ee&«      gdodpelem   iidC¬y«       ejÔ                  ddz¬k«       ejÔ                  dd{¬k«       ee&«      fdteVdz  dueVdz  dfegfd„«       Zre;jÍ                  d€ddg ee&«      gdodpelem   iidC¬y«       ejÔ                  d�¬‚«       ejÔ                  ddz¬k«       ejÔ                  dd{¬k«      fdƒeVdteVdz  dueVdz  fd„„«       Zse;jÍ                  d…ddg ee&«      gdodpelem   iidC¬y«       ejÔ                  d�¬‚«       ejÔ                  ddz¬k«       ejÔ                  dd{¬k«      fdƒeVdteVdz  dueVdz  fd†„«       Zte;jÍ                  d‡ddg ee&«      gdCdodpelem   ii¬ˆ«       ejÔ                  ddz¬k«       ejÔ                  dd{¬k«       ee&«      fdteVdz  dueVdz  dfegfd‰„«       Zue;jÍ                  dŠddg ee&«      gdodpelem   ii¬q«       ejÔ                  ddz¬k«       ejÔ                  dd{¬k«       ejÔ                  d‹dŒ¬k«       ejÔ                  dd�¬k«       ejÔ                  ddŽ¬k«       ejÔ                  dd�¬k«       ejÔ                  dd�¬k«      fdteVdz  dueVdz  d‘ed’   dz  d“eVdz  d”eVdz  d_eVdz  d•eVdz  fd–„«       Zv ewh d—£«      Zxd˜Zyd™eVdJeVfdš„Zzd›Z{dJe8fdœ„Z|dteVdz  dueVdz  dJe}eef   fd�„Z~dfegdžeVdz  dŸeVdz  d eVdJeVf
d¡„Zdfegd¢eVdz  dGe8dJe}eVe}eVd£f   f   fd¤„Z€e;jÍ                  d¥d¦¬§«      	 	 	 �dDdfeeg ee&«      f   dteeVdz   ejÔ                  d¨¬‚«      f   dueeVdz   ejÔ                  d©¬‚«      f   d“eeVdz   ejÔ                  dª¬‚«      f   dJeeeVeWf      f
d«„«       Z�e;jÍ                  d¬d¦¬§«      	 	 	 �dDdfeeg ee&«      f   dteeVdz   ejÔ                  d¨¬‚«      f   dueeVdz   ejÔ                  d©¬‚«      f   d”eeVdz   ejÔ                  d­¬‚«      f   dJeeeVeWf      f
d®„«       Z‚e;jÍ                  d¯d¦¬§«      	 	 	 �dDdfeeg ee&«      f   dteeVdz   ejÔ                  d¨¬‚«      f   dueeVdz   ejÔ                  d©¬‚«      f   d_eeVdz   ejÔ                  d°¬‚«      f   dJeeeVeWf      f
d±„«       Zƒe;jÍ                  d²d¦¬§«      	 	 	 �dDdfeeg ee&«      f   dteeVdz   ejÔ                  d¨¬‚«      f   dueeVdz   ejÔ                  d©¬‚«      f   d¢eeVdz   ejÔ                  d³¬‚«      f   dJeeeVeWf      f
d´„«       Z„e;jÍ                  dµddg ee&«      gdCdodpelem   ii¬ˆ«      d¶„ «       Z…e;jÍ                  d·ddg ee&«      gdodpelem   ii¬q«       ejÔ                  ddr¬k«       ejÔ                  dds¬k«       ejÔ                  dd¸¬k«      fdteVdz  dueVdz  d¹eVdz  fdº„«       Z†dteVdueVfd»„Z‡e;�j                  d¼ddg ee&«      gdod½d¾d¿dÀdÁdÂd½dÃdÄœidÅœiidÆœi¬q«      dÇe‰fdÈ„«       ZŠe;jÍ                  dÉddg ee&«      gdodpe‹eVef   ii¬q«      e;jÍ                  dÊddg ee&«      gdCdodpelem   ii¬ˆ«       ejÔ                  ddË¬k«       ejÔ                  ddÌ¬k«       ejÔ                  ddÍ¬k«       ejÔ                  ddÎ¬k«       ejÔ                  ddÏ¬k«       ejÔ                  ddÐ¬k«       ejÔ                  ddÑ¬k«       ejÔ                  ddr¬k«       ejÔ                  dds¬k«       ejÔ                  dÒdÓdÒ¬Ô«       ejÔ                  dÕdÖdÒd×¬Ø«       ee&«       ejÔ                  ddÙ¬k«       ejÔ                  ddÚ¬k«       ejÔ                  ddÛ¬k«       ejÔ                  ddÜ¬k«       ejÔ                  ddÝ¬k«       ejÔ                  ddÞ¬k«       ejÔ                  ddß¬k«       ejÔ                  ddà¬k«       ejÔ                  ddá¬k«       ejÔ                  dâdã¬k«       ejÔ                  dädå¬k«       ejÔ                  dCdæ¬k«      fdÇed“eVdz  dleVdz  dZeVdz  dçeVdz  d_eVdz  dèeŒdz  déeŒdz  dteVdz  dueVdz  dêe_dëe_dfegdìeVdz  díeVdz  dpeVdz  dîeVdz  dƒeVdz  dïeVdz  dðeVdz  dñeVdz  dòeVdz  dóeVdôeVdz  dõe�f2dö„«       «       ZŽ G d÷„ døe«      Z� ewh dù£«      Z�ee<dú<   dûeVelz  e‹z  dz  dJe�fdü„Z‘dýeeeVeWf      dJdfdþ„Z’dÿeVe‹z  dz  dJeVdz  f�d „Z“�deeVef   �d�ddJe�f�d„Z”e;jÍ                  �dddg ee&«      gdC¬e«       ejÔ                  ddr¬k«       ejÔ                  dds¬k«       ee&«      fdZeVdteVdz  dueVdz  dfegf�d„«       Z•e;jÍ                  �dddg ee&«      gdodpelem   ii¬q«       ejÔ                  ddË¬k«       ejÔ                  ddÌ¬k«       ejÔ                  d�d¬k«       ejÔ                  ddr¬k«       ejÔ                  dds¬k«       ejÔ                  �d	�d
¬k«       ee&«      f�ded“eVdz  dleVdz  dZeVdz  dteVdz  dueVdz  �de�dfegf�d„«       Z–e;�j                  �dddg ee&«      g�¬«      �d„ «       Z—e;�j                  �dddg ee&«      gdC¬e«      �d„ «       Z˜d ee&«      fd“eVdz  dfegf�d„Z™e;jÍ                  �dddg ee&«      gdC¬e«       ejÔ                  d�d¬k«       ee&«      fd“eVdz  dfegf�d„«       Zše;jÍ                  �dddg ee&«      gdC¬e«      �d„ «       Z›�dEdfeg�de_f�d„Zœe;jÍ                  �dddg ee&«      gdC¬e«       ejÔ                  d�d¬k«       ee&«      f�de_dfegf�d„«       Z�e;jÍ                  �dddg ee&«      gdC¬e«      �d „ «       Zže;jÍ                  �d!ddg ee&«      gdC¬e«      �d"„ «       ZŸe;�j                  �d#ddg ee&«      gdC¬e«      �dF�d$e dz  f�d%„«       Z¡�dEdfeg�de_f�d&„Z¢e;jÍ                  �d'ddg ee&«      gdC¬e«       ejÔ                  �d�d(¬k«       ee&«      f�de_dfegf�d)„«       Z£e;jÍ                  �d* ee&«      ge#�¬+«      dJe#f�d,„«       Z¤�dGdGe8f�d-„Z¥	 	 �dGdteVdueVdGe8dz  �d.eVdz  f�d/„Z¦e;jÍ                  �d0ddg ee&«      gdCdodpelem   ii¬ˆ«       ejÔ                  �d1¬‚«       ejÔ                  dÒdÒdÓ�¬2«       ejÔ                  dÕdÒ�d3dÖ�¬4«       ee&«      fdçeVdêe_dëe_dfegf�d5„«       Z§	 	 �dHdG�d6�d$el�d7e_dêe_dëe_�d8e_�d9e��d:e�dJe‹f�d;„Z¨dìeVdz  dJeeVeWf   f�d<„Z©dfegdJe�f�d=„ZªdGe8dfegd_eVdz  dJe�f�d>„Z«dfegdJe�f�d?„Z¬dGe8dfegdZeVdJdf�d@„Z­dGe8dfegdJeleV   f�dA„Z®dGe8dfegdJe}eVd£f   f�dB„Z¯y(I  é    N)ÚMappingÚSequence)ÚdatetimeÚ	timedeltaÚtimezone)
ÚTYPE_CHECKINGÚ	AnnotatedÚAnyÚFinalÚLiteralÚ
NamedTupleÚProtocolÚ	TypedDictÚTypeVarÚcast)Ú	APIRouterÚDependsÚHTTPExceptionÚRequestÚResponseÚstatus)ÚReadOnly)Úverbose_proxy_logger)Ú,LITTELM_INTERNAL_HEALTH_SERVICE_ACCOUNT_NAME)Ú*)ÚProviderBudgetResponseÚProviderBudgetResponseObject)Úuser_api_key_auth)Úget_spend_by_teamÚget_spend_by_team_and_customer)Úhandle_exception_on_proxy)ÚTableActions)ÚSpendLogsRepository)ÚTeamRepository)ÚVerificationTokenRepository)Úmodels©ÚPrismaClient©ÚColdStorageHandlerÚrouteri'  ÚSPEND_LOGS_PAGINATION_COUNT_CAP©ÚtokenÚ_INTERNAL_HEALTH_CHECK_API_KEYSÚ_RowTc                   ó"   — e Zd Zdeeef   fd„Zy)Ú_SupportsModelDumpÚreturnc                  ó   — y ©N© )Úselfs    ú|/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/spend_tracking/spend_management_endpoints.pyÚ
model_dumpz_SupportsModelDump.model_dumpC   s   � ó    N)Ú__name__Ú
__module__Ú__qualname__r   ÚstrÚobjectr9   r6   r:   r8   r2   r2   B   s   „ Ø5˜G C¨ KÑ0Ô5r:   r2   c                   ó.   — e Zd ZU edz  ed<   edz  ed<   y)Ú_SpendLogOwnershipRowNÚuserÚteam_id©r;   r<   r=   r>   Ú__annotations__r6   r:   r8   rA   rA   F   s   … Ø
�‰*ÓØ�4‰ZÔr:   rA   c                   ó,   — e Zd ZU eed<   eed<   eed<   y)Ú_ActivityRowÚdateÚapi_requestsÚtotal_tokensN©r;   r<   r=   r>   rE   Úintr6   r:   r8   rG   rG   K   s   … Ø
ƒIØÓØÔr:   rG   c                   ó6   — e Zd ZU eed<   eed<   eed<   eed<   y)Ú_ActivityModelRowÚmodel_grouprH   rI   rJ   NrK   r6   r:   r8   rN   rN   Q   s   … ØÓØ
ƒIØÓØÔr:   rN   c                   ó,   — e Zd ZU eed<   eed<   eed<   y)Ú_DeploymentExceptionsRowÚapi_baserH   Únum_rate_limit_exceptionsNrK   r6   r:   r8   rQ   rQ   X   s   … ØƒMØ
ƒIØ"Ô"r:   rQ   c                   ó"   — e Zd ZU eed<   eed<   y)Ú_ExceptionsRowrH   rS   NrK   r6   r:   r8   rU   rU   ^   s   … Ø
ƒIØ"Ô"r:   rU   c                   ó"   — e Zd ZU eed<   eed<   y)Ú_ModelIdSpendRowÚmodel_idÚspendN©r;   r<   r=   r>   rE   Úfloatr6   r:   r8   rW   rW   c   s   … ØƒMØ„Lr:   rW   c                   ó   — e Zd ZU eed<   y)Ú_TagNameRowÚindividual_request_tagNrD   r6   r:   r8   r]   r]   h   s   … ØÔr:   r]   c                   ó(   — e Zd ZU edz  ed<   eed<   y)Ú_TeamSpendRowNÚ
team_aliasÚtotal_spendrZ   r6   r:   r8   r`   r`   l   s   … Ø�d‘
ÓØÔr:   r`   c                   ó"   — e Zd ZU eed<   eed<   y)Ú_TagSpendRowr^   rb   NrZ   r6   r:   r8   rd   rd   q   s   … ØÓØÔr:   rd   c                   ó   — e Zd ZU eed<   y)Ú_SpendLogsCountRowÚtotal_countN©r;   r<   r=   rL   rE   r6   r:   r8   rf   rf   v   s   … ØÔr:   rf   c                   ó"   — e Zd ZU eed<   eed<   y)Ú_PgClassRowÚrelnameÚrelkindNrD   r6   r:   r8   rj   rj   z   s   … ØƒLØ„Lr:   rj   c                   ó   — e Zd ZU eed<   y)Ú_TotalSpendRowrb   N)r;   r<   r=   r[   rE   r6   r:   r8   rn   rn      s   … ØÔr:   rn   c                   ó8   — e Zd ZU edz  ed<   edz  ed<   eed<   y)Ú_TeamDailySpendRowNra   Ú
spend_daterb   rZ   r6   r:   r8   rp   rp   ƒ   s   … Ø�d‘
ÓØ�d‘
ÓØÔr:   rp   c                   ó   — e Zd ZU edz  ed<   y)Ú_EndUserRowNÚend_userrD   r6   r:   r8   rs   rs   ‰   s   … Ø�D‰jÔr:   rs   c                   ó,   — e Zd ZU eed<   eed<   eed<   y)Ú_DailyTagSpendRowr^   Ú	log_countrb   N)r;   r<   r=   r>   rE   rL   r[   r6   r:   r8   rv   rv   �   s   … ØÓØƒNØÔr:   rv   c                   ó   — e Zd ZU eed<   y)Ú_SessionCountAggregateÚ
session_idNrh   r6   r:   r8   ry   ry   “   s   … Ø„Or:   ry   c                   ó"   — e Zd ZU eed<   eed<   y)Ú_SessionCountRowrz   Ú_countN)r;   r<   r=   r>   rE   ry   r6   r:   r8   r|   r|   —   s   … ØƒOØ"Ô"r:   r|   c                   óF   — e Zd ZU eed<   eed<   eed<   eed<   ee   ed<   y)Ú_SessionSpendRowrz   Úsession_total_spendÚmcp_tool_call_countÚmcp_tool_call_spendÚsession_cache_hit_countN)r;   r<   r=   r>   rE   r[   rL   r   r6   r:   r8   r   r   œ   s#   … ØƒOØÓØÓØÓØ% c™]Ô*r:   r   c                   ó   — e Zd ZU ee   ed<   y)Ú_SpendSumAggregaterY   N)r;   r<   r=   r   r[   rE   r6   r:   r8   r…   r…   ¤   s   … Ø�E‰?Ôr:   r…   F)Útotalc                   ód   — e Zd ZU ee   ed<   eedz     ed<   ee   ed<   ee   ed<   ee   ed<   y)Ú_SpendGroupByRowÚapi_keyNrB   ÚmodelÚ	startTimeÚ_sum)r;   r<   r=   r   r>   rE   r?   r…   r6   r:   r8   rˆ   rˆ   ¨   s<   … Ø�c‰]ÓØ
�3˜‘:Ñ
ÓØ�C‰=ÓØ˜ÑÓØ
Ð%Ñ
&Ô&r:   rˆ   Úprisma_clientÚ	sql_queryÚargsr3   c              ‡   óX   K  —  | j                   j                  |g|¢­Ž ƒ d{  –—† S 7 Œ­w)zMRun a raw read query and return its rows as the row type the caller declares.N)ÚdbÚ	query_raw©r�   rŽ   r�   s      r8   Ú
_query_rawr”   °   s*   è ø€ à+�×!Ñ!×+Ñ+¨IÐ=¸Ò=×=Ð=Ð=úó   ‚!*£(¤*c              ‡   ó8   K  — t        | |g|¢­Ž ƒ d{  –—† S 7 Œ­w)zI``_query_raw`` for the call sites that guard the result against ``None``.N©r”   r“   s      r8   Ú_query_raw_or_noner˜   µ   s   è ø€ ä˜M¨9Ð<°tÒ<×<Ð<Ð<ús   ‚“”c                   óx   — e Zd ZdZdeeef   dedz  fd„Zdeeef   de	e   fd„Z
deeef   deeef   defd„Zy)	Ú
_TeamTablez9The subset of the Prisma team table API this module uses.Úwherer3   Nc             ƒ   ó   K  — y ­wr5   r6   ©r7   r›   s     r8   Úfind_uniquez_TeamTable.find_unique½   ó   è ø� ùó   ‚c             ƒ   ó   K  — y ­wr5   r6   r�   s     r8   Ú	find_manyz_TeamTable.find_many¿   rŸ   r    Údatac             ƒ   ó   K  — y ­wr5   r6   ©r7   r£   r›   s      r8   Úupdate_manyz_TeamTable.update_manyÁ   rŸ   r    )r;   r<   r=   Ú__doc__r   r>   r?   r2   rž   r   r¢   r[   rL   r¦   r6   r:   r8   rš   rš   º   sd   „ ÙCàa¨'°#°v°+Ñ*>ÐaÐCUÐX\ÑC\Óaàb¨°°V°Ñ(<ÐbÀÐJ\ÑA]Óbàf¨°°e°Ñ)<ÐfÀWÈSÐRXÈ[ÑEYÐfÐ^aÔfr:   rš   c                   ó8   — e Zd ZdZdeeef   deeef   defd„Z	y)Ú_VerificationTokenTablezGThe subset of the Prisma verification token table API this module uses.r£   r›   r3   c             ƒ   ó   K  — y ­wr5   r6   r¥   s      r8   r¦   z#_VerificationTokenTable.update_manyÇ   rŸ   r    N)
r;   r<   r=   r§   r   r>   r[   r?   rL   r¦   r6   r:   r8   r©   r©   Ä   s+   „ ÙQàf¨°°e°Ñ)<ÐfÀWÈSÐRXÈ[ÑEYÐfÐ^aÔfr:   r©   zprisma_models.LiteLLM_SpendLogsc                 ó,   — t        | «      j                  S r5   )r#   Útable©r�   s    r8   Ú_spend_logs_tabler®   Ê   s   € Ü˜}Ó-×3Ñ3Ð3r:   c                 ó,   — t        | «      j                  S r5   )r$   r¬   r­   s    r8   Ú_team_tabler°   Î   s   € Ü˜-Ó(×.Ñ.Ð.r:   c                 ó,   — t        | «      j                  S r5   )r%   r¬   r­   s    r8   Ú_verification_token_tabler²   Ò   s   € Ü& }Ó5×;Ñ;Ð;r:   r›   ÚorderÚtakeÚhttp_responsec              ƒ   óÂ   K  — t        | «      j                  |||¬«      ƒ d{  –—† }t        |«      |k(  r%d|j                  d<   t	        j
                  d|«       |S 7 Œ9­w)zGRead spend log rows as Prisma model instances, capped at ``take`` rows.)r›   r³   r´   NÚtruezx-litellm-spend-logs-truncatedz`/spend/logs result truncated to the %s most recent rows; use /spend/logs/v2 for paginated access)r®   r¢   ÚlenÚheadersr   Úwarning)r�   r›   r³   r´   rµ   Úrowss         r8   Ú_find_spend_logsr¼   Ö   sg   è ø€ ô *¨-Ó8×BÑBÈÐV[ÐbfÐBÓg×g€DÜ
ˆ4ƒy�DÒØBHˆ×ÑÐ>Ñ?Ü×$Ñ$ØnØô	
ð €Kð hús   ‚!A£A¤:AÚ
request_idc              ƒ   óZ   K  — t        | «      j                  d|id¬«      ƒ d{  –—† S 7 Œ­w)z;Read the single spend log row identified by ``request_id``.r½   N)r›   Úinclude)r®   rž   )r�   r½   s     r8   Ú_find_spend_log_rowrÀ   è   s8   è ø€ ä" =Ó1×=Ñ=Ø˜ZÐ(Øð >ó ÷ ð ð ús   ‚"+¤)¥+c              ƒ   óT   K  — t        | «      j                  |¬«      ƒ d{  –—† S 7 Œ­w)z,Count the spend log rows matching ``where``.©r›   N)r®   Úcount)r�   r›   s     r8   Ú_count_spend_logsrÄ   ð   s%   è ø€ ä" =Ó1×7Ñ7¸eÐ7ÓD×DÐDÐDús   ‚(¡&¢(Úsession_idsc              ƒ   ó”   K  — t        | «      j                  dgdd|iiddi¬«      ƒ d{  –—† }t        t        t           |«      S 7 Œ­w)z;Count spend log rows per session for the given session ids.rz   ÚinT)Úbyr›   rÃ   N)r®   Úgroup_byr   r   r|   )r�   rÅ   r»   s      r8   Ú_count_logs_per_sessionrÊ   õ   s\   è ø€ ô *¨-Ó8×AÑAØˆ>Ø˜d KÐ0Ð1Ø˜TÐ"ð Bó ÷ €Dô
 ”Ô)Ñ*¨DÓ1Ð1ðús   ‚(AªA«ArC   c              ƒ   óX   K  — t        | «      j                  d|i¬«      ƒ d{  –—† S 7 Œ­w)z2Read a single team row as a Prisma model instance.rC   rÂ   N)r°   rž   )r�   rC   s     r8   Ú_find_team_rowrÌ     s*   è ø€ ä˜]Ó+×7Ñ7¸yÈ'Ð>RÐ7ÓS×SÐSÐSúr•   Úteam_idsc              ƒ   ó\   K  — t        | «      j                  dd|ii¬«      ƒ d{  –—† S 7 Œ­w)z)Read team rows as Prisma model instances.rC   rÇ   rÂ   N)r°   r¢   )r�   rÍ   s     r8   Ú_find_team_rowsrÏ     s/   è ø€ ä˜]Ó+×5Ñ5¸YÈÈxÐHXÐ<YÐ5ÓZ×ZÐZÐZús   ‚#,¥*¦,z/spend/keysúBudget & Spend Tracking)ÚtagsÚdependenciesÚinclude_in_schemaÚuser_api_key_dictc              ƒ   óN  K  — ddl m} 	 |€t        d«      ‚t        | ¬«      r|j	                  dd¬«      ƒ d{  –—† S | j
                  }|sg S |j	                  dd|¬	«      ƒ d{  –—† S 7 Œ07 Œ# t        $ r+}t        t        j                  d
t        |«      i¬«      ‚d}~ww xY w­w)aø  
    View keys created, ordered by spend.

    - Admin callers (PROXY_ADMIN / PROXY_ADMIN_VIEW_ONLY) see every key in
      the database.
    - All other callers (INTERNAL_USER / INTERNAL_USER_VIEW_ONLY, etc.) are
      scoped to keys they own (``user_id == caller``). A caller with no
      ``user_id`` has no scope and receives an empty list rather than the
      full table.

    Example Request:
    ```
    curl -X GET "http://0.0.0.0:8000/spend/keys" -H "Authorization: Bearer sk-1234"
    ```
    r   r­   Nú�Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keys©rÔ   ÚkeyÚfind_all©Ú
table_nameÚ
query_type©rÛ   rÜ   Úuser_idÚerror©Ústatus_codeÚdetail)
Úlitellm.proxy.proxy_serverr�   Ú	ExceptionÚ_is_admin_view_safeÚget_datarÞ   r   r   ÚHTTP_400_BAD_REQUESTr>   )rÔ   r�   Úcaller_user_idÚes       r8   Úspend_key_fnrê     sÅ   è ø€ õ4 9ð
ØÐ Üð Tóð ô Ð1BÕCØ&×/Ñ/¸5ÈZÐ/ÓX×XÐXà 1× 9Ñ 9ˆÙØˆIØ"×+Ñ+ØØ!Ø"ð ,ó 
÷ 
ð 	
ð Yøð

ùô ò 
ÜÜ×3Ñ3ØœS ›VÐ$ô
ð 	
ûð
üs`   ‚B%Š/A. ¹A*ºA. ½B%¾A. ÁB%ÁA. Á%A,Á&A. Á)B%Á*A. Á,A. Á.	B"Á7&BÂB"Â"B%c                 óÔ   — t        | t        «      r| n| gD ]P  }|r)t        |d«      r|j                  j	                  dd«       Œ.t        |t
        «      sŒ?|j	                  dd«       ŒR y)z1Strip password field from a list of user objects.Ú__dict__ÚpasswordN)Ú
isinstanceÚlistÚhasattrrì   ÚpopÚdict)ÚusersrB   s     r8   Ú_strip_password_from_usersrô   @  sV   € ä# E¬4Ô0‘°u°gò 'ˆÙ”G˜D *Ô-Ø�M‰M×Ñ˜j¨$Õ/Ü˜œdÕ#Ø�H‰H�Z Õ&ñ	'r:   z/spend/userszGet User Table row for user_id)ÚdefaultÚdescriptionrÞ   c              ƒ   óÖ  K  — ddl m} 	 |€t        d«      ‚t        |¬«      s6|j                  }|sg S | �"| |k7  rt        t        j                  ddi¬«      ‚|} | � |j                  d	d
| ¬«      ƒ d{  –—† }|g}n|j                  d	d¬«      ƒ d{  –—† }|}t        |«       |S 7 Œ27 Œ# t
        $ r ‚ t        $ r+}t        t        j                  dt        |«      i¬«      ‚d}~ww xY w­w)aL  
    View users created, ordered by spend.

    - Admin callers (PROXY_ADMIN / PROXY_ADMIN_VIEW_ONLY) see every user, or
      a specific user when ``user_id`` is supplied.
    - All other callers may only read their own row. If they supply a
      ``user_id`` query parameter that does not match their authenticated
      ``user_id`` the request is rejected with HTTP 403; supplying their
      own id (or none at all) returns just their row. A caller with no
      ``user_id`` on their key has no scope and receives an empty list
      rather than the full table.

    Example Request:
    ```
    curl -X GET "http://0.0.0.0:8000/spend/users" -H "Authorization: Bearer sk-1234"
    ```

    View User Table row for user_id
    ```
    curl -X GET "http://0.0.0.0:8000/spend/users?user_id=1234" -H "Authorization: Bearer sk-1234"
    ```
    r   r­   NrÖ   r×   rß   z.Not authorized to view spend for another user.rà   rB   rž   rÝ   rÙ   rÚ   )rã   r�   rä   rå   rÞ   r   r   ÚHTTP_403_FORBIDDENræ   rô   rç   r>   )rÞ   rÔ   r�   rè   Ú	user_infoÚresultré   s          r8   Úspend_user_fnrû   I  s  è ø€ õJ 9ð!
ØÐ Üð Tóð ô #Ð5FÕGØ$5×$=Ñ$=ˆNÙ!Ø�	ØÐ" w°.Ò'@Ü#Ü &× 9Ñ 9Ø#Ð%UÐVôð ð %ˆGàÐØ+×4Ñ4ÀÐS`ÐjqÐ4Ór×rˆIØ�[‰Fà+×4Ñ4ÀÐS]Ð4Ó^×^ˆIØˆFä" 6Ô*Øˆð søð _ùô ò ØÜò 
ÜÜ×3Ñ3ØœS ›VÐ$ô
ð 	
ûð
üsV   ‚C)Š(B) ²C)³?B) Á2B%Á3B) ÂB'ÂB) Â$C)Â%B) Â'B) Â)C&Â;&C!Ã!C&Ã&C)z/spend/tagséÈ   rŠ   )rÑ   rÒ   Ú	responsesz*Time from which to start viewing key spendz!Time till which to view key spendÚ
start_dateÚend_datec              ƒ   óº  K  — ddl m} 	 |€t        d«      ‚	 t        | ||¬«      ƒ d{  –—† }|S 7 Œ# t        $ r�}t	        |t
        «      rBt        t        |dd|› d�«      d	t        |d
d«      t        |dt        j                  «      ¬«      ‚t	        |t        «      r|‚t        dt        |«      z   d	t        |d
d«      t        j                  ¬«      ‚d}~ww xY w­w)ai  
    LiteLLM Enterprise - View Spend Per Request Tag

    Example Request:
    ```
    curl -X GET "http://0.0.0.0:8000/spend/tags" -H "Authorization: Bearer sk-1234"
    ```

    Spend with Start Date and End Date
    ```
    curl -X GET "http://0.0.0.0:8000/spend/tags?start_date=2022-01-01&end_date=2022-02-01" -H "Authorization: Bearer sk-1234"
    ```
    r   r­   NrÖ   )rþ   rÿ   r�   râ   ú/spend/tags Error(ú)Úinternal_errorÚparamÚNonerá   ©ÚmessageÚtyper  Úcodeú/spend/tags Error)rã   r�   rä   Úget_spend_by_tagsrî   r   ÚProxyExceptionÚgetattrr   ÚHTTP_500_INTERNAL_SERVER_ERRORr>   )rþ   rÿ   r�   Úresponseré   s        r8   Úview_spend_tagsr  ”  sð   è ø€ õD 9ð!
ØÐ Üð Tóð ð
	ô !2¸ZÐRZÐjwÔ x×xˆàˆð yùô ò 
Ü�aœÔ'Ü Ü  8Ð/AÀ!ÀÀAÐ-FÓGØ%Ü˜a ¨&Ó1Ü˜Q ¬v×/TÑ/TÓUô	ð ô ˜œ>Ô*ØˆGÜØ'¬#¨a«&Ñ0Ø!Ü˜!˜W fÓ-Ü×6Ñ6ô	
ð 	
ûð
üs1   ‚CŠ2 ©0ª2 ¯C°2 ²	C»BCÃCÃCc              ƒ   ó¬   K  — ddl m} |€t        dddi¬«      ‚| j                  }|€t        dddi¬«      ‚d}t	        |||||«      ƒ d {  –—† }|S 7 Œ­w)	Nr   r­   éô  rß   úNo db connectedrà   úNo user_id foundaz  
    SELECT
        date_trunc('day', "startTime") AS date,
        COUNT(*) AS api_requests,
        SUM(total_tokens) AS total_tokens
    FROM "LiteLLM_SpendLogs"
    WHERE "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
      AND "startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
    AND "user" = $3
    GROUP BY date_trunc('day', "startTime")
    ©rã   r�   r   rÞ   r˜   ©rÔ   rþ   rÿ   r�   rÞ   rŽ   Údb_responses          r8   Ú!get_global_activity_internal_userr  Ü  sx   è ø€ õ 9àÐÜ¨°WÐ>OÐ4PÔQÐQà&×.Ñ.€GØ€Ü¨°WÐ>PÐ4QÔRÐRð
€Iô ?QØ�y *¨h¸ó?÷ 9€Kð Ðð	9úó   ‚A	AÁAÁAz/global/activity)rÑ   rÒ   rý   rÓ   z&Time from which to start viewing spendzTime till which to view spendc              ƒ   ó¦  K  — | �|€t        t        j                  ddi¬«      ‚t        j                  | d«      j                  t        j                  ¬«      }t        j                  |d«      j                  t        j                  ¬«      }ddlm	} 	 |€t        d	«      ‚|j                  t        j                  k(  s|j                  t        j                  k(  rt        |||«      ƒ d{  –—† }nd
}t!        ||||«      ƒ d{  –—† }|€g S d}d}	g }
|D ]i  }t        j"                  |d   «      }|j%                  d«      |d<   |
j'                  |«       ||j)                  dd«      z  }|	|j)                  dd«      z  }	Œk t+        |
d„ ¬«      }
|
||	dœ}|S 7 Œ«7 Œ”# t        $ r+}t        t        j                  dt-        |«      i¬«      ‚d}~ww xY w­w)aç  
    Get number of API Requests, total tokens through proxy

    {
        "daily_data": [
                const chartdata = [
                {
                date: 'Jan 22',
                api_requests: 10,
                total_tokens: 2000
                },
                {
                date: 'Jan 23',
                api_requests: 10,
                total_tokens: 12
                },
        ],
        "sum_api_requests": 20,
        "sum_total_tokens": 2012
    }
    Nrß   ú&Please provide start_date and end_daterà   ú%Y-%m-%d©Útzinfor   r­   rÖ   a®  
            SELECT
                date_trunc('day', "startTime") AS date,
                COUNT(*) AS api_requests,
                SUM(total_tokens) AS total_tokens
            FROM "LiteLLM_SpendLogs"
            WHERE "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
              AND "startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
            GROUP BY date_trunc('day', "startTime")
            rH   ú%b %drI   rJ   c                 ó   — | d   S ©NrH   r6   ©Úxs    r8   ú<lambda>z%get_global_activity.<locals>.<lambda>X  ó
   € °a¸±i€ r:   ©rØ   ©Ú
daily_dataÚsum_api_requestsÚsum_total_tokens)r   r   rç   r   ÚstrptimeÚreplacer   Úutcrã   r�   rä   Ú	user_roleÚLitellmUserRolesÚINTERNAL_USERÚINTERNAL_USER_VIEW_ONLYr  r˜   ÚfromisoformatÚstrftimeÚappendÚgetÚsortedr>   )rþ   rÿ   rÔ   Ústart_date_objÚend_date_objr�   r  rŽ   r)  r*  r(  ÚrowÚ	_date_objÚdata_to_returnré   s                  r8   Úget_global_activityr<  ú  sø  è ø€ ðT Ð˜XÐ-ÜÜ×3Ñ3ØÐEÐFô
ð 	
ô
 %×-Ñ-¨j¸*ÓE×MÑMÔU]×UaÑUaÐMÓb€NÜ"×+Ñ+¨H°jÓA×IÑIÔQY×Q]ÑQ]ÐIÓ^€Lå8ð7
ØÐ Üð Tóð ð ×'Ñ'Ô+;×+IÑ+IÒIØ ×*Ñ*Ô.>×.VÑ.VÒVä AÐBSÐUcÐeqÓ r×r‰Kð	 ˆIô !3°=À)È^Ð]iÓ j×jˆKàÐØˆIàÐØÐØˆ
Øò 	;ˆCä ×.Ñ.¨s°6©{Ó;ˆIØ#×,Ñ,¨WÓ5ˆC�‰Kà×Ñ˜cÔ"Ø §¡¨¸Ó :Ñ:ÐØ §¡¨¸Ó :Ñ:Ñð	;ô ˜JÑ,?Ô@ˆ
ð %Ø 0Ø 0ñ!
ˆð ÐðM søð kùô8 ò 
ÜÜ×3Ñ3ØœS ›VÐ$ô
ð 	
ûð
üs\   ‚BGÂAF Ã*FÃ+F ÄFÄF ÄGÄB	F ÆGÆF ÆF Æ	GÆ#&G	Ç	GÇGc              ƒ   ó¬   K  — ddl m} |€t        dddi¬«      ‚| j                  }|€t        dddi¬«      ‚d}t	        |||||«      ƒ d {  –—† }|S 7 Œ­w)	Nr   r­   r  rß   r  rà   r  aœ  
    SELECT
        model_group,
        date_trunc('day', "startTime") AS date,
        COUNT(*) AS api_requests,
        SUM(total_tokens) AS total_tokens
    FROM "LiteLLM_SpendLogs"
    WHERE "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
      AND "startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
    AND "user" = $3
    GROUP BY model_group, date_trunc('day', "startTime")
    r  r  s          r8   Ú'get_global_activity_model_internal_userr>  i  sz   è ø€ õ 9àÐÜ¨°WÐ>OÐ4PÔQÐQà&×.Ñ.€GØ€Ü¨°WÐ>PÐ4QÔRÐRð€Iô DVØ�y *¨h¸óD÷ >€Kð Ðð	>úr  z/global/activity/modelc              ƒ   ó¶  K  — | �|€t        t        j                  ddi¬«      ‚t        j                  | d«      j                  t        j                  ¬«      }t        j                  |d«      j                  t        j                  ¬«      }ddlm	} 	 |€t        d	«      ‚|j                  t        j                  k(  s|j                  t        j                  k(  rt        |||«      ƒ d{  –—† }nd
}t!        ||||«      ƒ d{  –—† }|€g S i }|D ]—  }	|	d   }
|
|vr	g dddœ||
<   t        j"                  |	d   «      }|j%                  d«      |	d<   ||
   d   j'                  |	«       ||
   dxx   |	j)                  dd«      z  cc<   ||
   dxx   |	j)                  dd«      z  cc<   Œ™ t+        t-        |j/                  «       d„ d¬«      dd «      }g }|j/                  «       D ]2  \  }}t-        |d   d„ ¬«      }|j'                  |||d   |d   dœ«       Œ4 |S 7 �Œ27 �Œ# t        $ r+}t        t        j0                  dt3        |«      i¬«      ‚d}~ww xY w­w)a€  
    Get number of API Requests, total tokens through proxy - Grouped by MODEL

    [
        {
            "model": "gpt-4",
            "daily_data": [
                    const chartdata = [
                    {
                    date: 'Jan 22',
                    api_requests: 10,
                    total_tokens: 2000
                    },
                    {
                    date: 'Jan 23',
                    api_requests: 10,
                    total_tokens: 12
                    },
            ],
            "sum_api_requests": 20,
            "sum_total_tokens": 2012

        },
        {
            "model": "azure/gpt-4-turbo",
            "daily_data": [
                    const chartdata = [
                    {
                    date: 'Jan 22',
                    api_requests: 10,
                    total_tokens: 2000
                    },
                    {
                    date: 'Jan 23',
                    api_requests: 10,
                    total_tokens: 12
                    },
            ],
            "sum_api_requests": 20,
            "sum_total_tokens": 2012

        },
    ]
    Nrß   r  rà   r  r  r   r­   rÖ   aØ  
            SELECT
                model_group,
                date_trunc('day', "startTime") AS date,
                COUNT(*) AS api_requests,
                SUM(total_tokens) AS total_tokens
            FROM "LiteLLM_SpendLogs"
            WHERE "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
              AND "startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
            GROUP BY model_group, date_trunc('day', "startTime")
            rO   r'  rH   r  r(  r)  rI   r*  rJ   c                 ó   — | d   d   S )Né   r)  r6   r"  s    r8   r$  z+get_global_activity_model.<locals>.<lambda>  s   € ˜a ™dÐ#5Ñ6€ r:   T©rØ   Úreverseé
   c                 ó   — | d   S r!  r6   r"  s    r8   r$  z+get_global_activity_model.<locals>.<lambda>  ó
   € ÈÈ&É	€ r:   r&  )rŠ   r(  r)  r*  )r   r   rç   r   r+  r,  r   r-  rã   r�   rä   r.  r/  r0  r1  r>  r˜   r2  r3  r4  r5  rò   r6  Úitemsr  r>   )rþ   rÿ   rÔ   r7  r8  r�   r  rŽ   Úmodel_ui_datar9  Ú_modelr:  r  rŠ   r£   Ú_sort_daily_dataré   s                    r8   Úget_global_activity_modelrK  ˆ  sª  è ø€ ðB Ð˜XÐ-ÜÜ×3Ñ3ØÐEÐFô
ð 	
ô
 %×-Ñ-¨j¸*ÓE×MÑMÔU]×UaÑUaÐMÓb€NÜ"×+Ñ+¨H°jÓA×IÑIÔQY×Q]ÑQ]ÐIÓ^€Lå8ðI
ØÐ Üð Tóð ð ×'Ñ'Ô+;×+IÑ+IÒIØ ×*Ñ*Ô.>×.VÑ.VÒVä GÐHYÐ[iÐkwÓ x×x‰Kð
 ˆIô !3°=À)È^Ð]iÓ j×jˆKØÐØˆIà ˆàò 	TˆCØ˜Ñ'ˆFØ˜]Ñ*à"$Ø()Ø()ñ)�˜fÑ%ô
 !×.Ñ.¨s°6©{Ó;ˆIØ#×,Ñ,¨WÓ5ˆC�‰Kà˜&Ñ! ,Ñ/×6Ñ6°sÔ;Ø˜&Ñ!Ð"4Ó5¸¿¹ÀÐQRÓ9SÑSÓ5Ø˜&Ñ!Ð"4Ó5¸¿¹ÀÐQRÓ9SÑSÔ5ð	Tô  ÜØ×#Ñ#Ó%Ù6Øôð ˆrð	ó
ˆð ˆØ(×.Ñ.Ó0ò 
	‰KˆE�4Ü% d¨<Ñ&8Ñ>QÔRÐà�O‰Oà"Ø"2Ø(,Ð-?Ñ(@Ø(,Ð-?Ñ(@ñ	õð
	ð ˆðq yùð kúôZ ò 
ÜÜ×=Ñ=ØœS ›VÐ$ô
ð 	
ûð
üs\   ‚BIÂAH" Ã*HÃ+H" ÄHÄH" ÄIÄDH" ÈIÈH" ÈH" È"	IÈ+&IÉIÉIz&/global/activity/exceptions/deploymentzFilter by model group)rö   rO   c              ƒ   óÆ  K  — |�|€t        t        j                  ddi¬«      ‚t        j                  |d«      j                  t        j                  ¬«      }t        j                  |d«      j                  t        j                  ¬«      }ddlm	} 	 |€t        d	«      ‚d
}t        ||||| «      ƒ d{  –—† }|€g S i }|D ]v  }	|	d   }
|
|vrg ddœ||
<   t        j                  |	d   «      }|j                  d«      |	d<   ||
   d   j                  |	«       ||
   dxx   |	j                  dd«      z  cc<   Œx t!        t#        |j%                  «       d„ d¬«      dd «      }g }|j%                  «       D ].  \  }}t#        |d   d„ ¬«      }|j                  |||d   dœ«       Œ0 |S 7 Œó# t        $ r+}t        t        j&                  dt)        |«      i¬«      ‚d}~ww xY w­w)a  
    Get number of 429 errors - Grouped by deployment

    [
        {
            "deployment": "https://azure-us-east-1.openai.azure.com/",
            "daily_data": [
                    const chartdata = [
                    {
                    date: 'Jan 22',
                    num_rate_limit_exceptions: 10
                    },
                    {
                    date: 'Jan 23',
                    num_rate_limit_exceptions: 12
                    },
            ],
            "sum_num_rate_limit_exceptions": 20,

        },
        {
            "deployment": "https://azure-us-east-1.openai.azure.com/",
            "daily_data": [
                    const chartdata = [
                    {
                    date: 'Jan 22',
                    num_rate_limit_exceptions: 10,
                    },
                    {
                    date: 'Jan 23',
                    num_rate_limit_exceptions: 12
                    },
            ],
            "sum_num_rate_limit_exceptions": 20,

        },
    ]
    Nrß   r  rà   r  r  r   r­   rÖ   a(  
        SELECT
            api_base,
            date_trunc('day', "startTime")::date AS date,
            COUNT(*) AS num_rate_limit_exceptions
        FROM
            "LiteLLM_ErrorLogs"
        WHERE
            "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
            AND "startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
            AND model_group = $3
            AND status_code = '429'
        GROUP BY
            api_base,
            date_trunc('day', "startTime")
        ORDER BY
            date;
        rR   ©r(  Úsum_num_rate_limit_exceptionsrH   r  r(  rN  rS   c                 ó   — | d   d   S )NrA  rN  r6   r"  s    r8   r$  z?get_global_activity_exceptions_per_deployment.<locals>.<lambda>™  s   € ˜a ™dÐ#BÑC€ r:   TrB  rD  c                 ó   — | d   S r!  r6   r"  s    r8   r$  z?get_global_activity_exceptions_per_deployment.<locals>.<lambda>   rF  r:   r&  )rR   r(  rN  )r   r   rç   r   r+  r,  r   r-  rã   r�   rä   r˜   r2  r3  r4  r5  rò   r6  rG  r  r>   )rO   rþ   rÿ   r7  r8  r�   rŽ   r  rH  r9  rI  r:  r  rŠ   r£   rJ  ré   s                    r8   Ú-get_global_activity_exceptions_per_deploymentrQ     sA  è ø€ ðz Ð˜XÐ-ÜÜ×3Ñ3ØÐEÐFô
ð 	
ô
 %×-Ñ-¨j¸*ÓE×MÑMÔU]×UaÑUaÐMÓb€NÜ"×+Ñ+¨H°jÓA×IÑIÔQY×Q]ÑQ]ÐIÓ^€Lå8ðH
ØÐ Üð Tóð ðˆ	ô$ OaØ˜9 n°lÀKóO
÷ I
ˆð ÐØˆIà ˆàò 	nˆCØ˜‘_ˆFØ˜]Ñ*à"$Ø56ñ)�˜fÑ%ô !×.Ñ.¨s°6©{Ó;ˆIØ#×,Ñ,¨WÓ5ˆC�‰Kà˜&Ñ! ,Ñ/×6Ñ6°sÔ;Ø˜&Ñ!Ð"AÓBÀcÇgÁgÐNiÐklÓFmÑmÔBð	nô ÜØ×#Ñ#Ó%ÙCØôð ˆrð	ó
ˆð ˆØ(×.Ñ.Ó0ò 		‰KˆE�4Ü% d¨<Ñ&8Ñ>QÔRÐà�O‰Oà %Ø"2Ø59Ð:YÑ5Zñõð		ð ˆðUI
ùôX ò 
ÜÜ×=Ñ=ØœS ›VÐ$ô
ð 	
ûð
üsI   ‚BG!Â!F* Â4F(Â5F* Â<G!Â=C*F* Æ'G!Æ(F* Æ*	GÆ3&GÇGÇG!z/global/activity/exceptionsc              ƒ   óÔ  K  — |�|€t        t        j                  ddi¬«      ‚t        j                  |d«      j                  t        j                  ¬«      }t        j                  |d«      j                  t        j                  ¬«      }ddlm	} 	 |€t        d	«      ‚d
}t        ||||| «      ƒ d{  –—† }|€g S d}g }	|D ]T  }
t        j                  |
d   «      }|j                  d«      |
d<   |	j                  |
«       ||
j                  dd«      z  }ŒV t!        |	d„ ¬«      }	|	|dœ}|S 7 Œz# t        $ r+}t        t        j                  dt#        |«      i¬«      ‚d}~ww xY w­w)až  
    Get number of API Requests, total tokens through proxy

    {
        "daily_data": [
                const chartdata = [
                {
                date: 'Jan 22',
                num_rate_limit_exceptions: 10,
                },
                {
                date: 'Jan 23',
                num_rate_limit_exceptions: 10,
                },
        ],
        "sum_api_exceptions": 20,
    }
    Nrß   r  rà   r  r  r   r­   rÖ   aü  
        SELECT
            date_trunc('day', "startTime")::date AS date,
            COUNT(*) AS num_rate_limit_exceptions
        FROM
            "LiteLLM_ErrorLogs"
        WHERE
            "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
            AND "startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
            AND model_group = $3
            AND status_code = '429'
        GROUP BY
            date_trunc('day', "startTime")
        ORDER BY
            date;
        rH   r  rS   c                 ó   — | d   S r!  r6   r"  s    r8   r$  z0get_global_activity_exceptions.<locals>.<lambda>  r%  r:   r&  rM  )r   r   rç   r   r+  r,  r   r-  rã   r�   rä   r˜   r2  r3  r4  r5  r6  r>   )rO   rþ   rÿ   r7  r8  r�   rŽ   r  rN  r(  r9  r:  r;  ré   s                 r8   Úget_global_activity_exceptionsrT  ³  sŸ  è ø€ ðR Ð˜XÐ-ÜÜ×3Ñ3ØÐEÐFô
ð 	
ô
 %×-Ñ-¨j¸*ÓE×MÑMÔU]×UaÑUaÐMÓb€NÜ"×+Ñ+¨H°jÓA×IÑIÔQY×Q]ÑQ]ÐIÓ^€Lå8ð5
ØÐ Üð Tóð ðˆ	ô  EWØ˜9 n°lÀKóE
÷ ?
ˆð ÐØˆIà()Ð%Øˆ
Øò 	UˆCä ×.Ñ.¨s°6©{Ó;ˆIØ#×,Ñ,¨WÓ5ˆC�‰Kà×Ñ˜cÔ"Ø)¨S¯W©WÐ5PÐRSÓ-TÑTÑ)ð	Uô ˜JÑ,?Ô@ˆ
ð %Ø-Jñ!
ˆð
 Ðð3?
ùô6 ò 
ÜÜ×3Ñ3ØœS ›VÐ$ô
ð 	
ûð
üsI   ‚BE(Â!D1 Â4D/Â5D1 Â<E(Â=A1D1 Ä.E(Ä/D1 Ä1	E%Ä:&E Å E%Å%E(z/global/spend/provider)rÑ   rÒ   rÓ   rý   c              ƒ   ó°  K  — ddl m} | �|€t        t        j                  ddi¬«      ‚t        j                  | d«      j                  t        j                  ¬«      }t        j                  |d«      j                  t        j                  ¬«      }dd	l
m}m} 	 |€t        d
«      ‚|j                  t        j                   k(  s|j                  t        j"                  k(  r7|j$                  }|€t        dddi¬«      ‚d}	t'        ||	|||«      ƒ d{  –—† }
nd}	t'        ||	||«      ƒ d{  –—† }
|
€g S g } |t(        «      }|
D ]–  }|d   }d}|€Œ|j+                  |¬«      }|€Œ"	 t-        j.                  |j0                  j2                  |j0                  j4                  |j0                  j6                  |j0                  ¬«      \  }}}}||xx   |d   z  cc<   Œ˜ |j9                  «       D ]  \  }}|j;                  ||dœ«       Œ |S 7 Œø7 Œá# t        $ r Y ŒÖw xY w# t        $ r+}t        t        j                  dt=        |«      i¬«      ‚d}~ww xY w­w)a-  
    Get breakdown of spend per provider
    [
        {
            "provider": "Azure OpenAI",
            "spend": 20
        },
        {
            "provider": "OpenAI",
            "spend": 10
        },
        {
            "provider": "VertexAI",
            "spend": 30
        }
    ]
    r   )ÚdefaultdictNrß   r  rà   r  r  )Ú
llm_routerr�   rÖ   é�  r  a{  
            SELECT
            model_id,
            SUM(spend) AS spend
            FROM "LiteLLM_SpendLogs"
            WHERE "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
              AND "startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
            AND length(model_id) > 0
            AND "user" = $3
            GROUP BY model_id
            aa  
            SELECT
            model_id,
            SUM(spend) AS spend
            FROM "LiteLLM_SpendLogs"
            WHERE "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
              AND "startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
              AND length(model_id) > 0
            GROUP BY model_id
            rX   ÚUnknown)rX   )rŠ   Úcustom_llm_providerrR   Úlitellm_paramsrY   )ÚproviderrY   )ÚcollectionsrV  r   r   rç   r   r+  r,  r   r-  rã   rW  r�   rä   r.  r/  r0  r1  rÞ   r˜   rL   Úget_deploymentÚlitellmÚget_llm_providerr[  rŠ   rZ  rR   rG  r4  r>   )rþ   rÿ   rÔ   rV  r7  r8  rW  r�   rÞ   rŽ   r  Úui_responseÚprovider_spend_mappingr9  Ú	_model_idÚ	_providerÚ_deploymentÚ_r\  rY   ré   s                        r8   Úget_global_spend_providerrg    s†  è ø€ õJ (àÐ˜XÐ-ÜÜ×3Ñ3ØÐEÐFô
ð 	
ô
 %×-Ñ-¨j¸*ÓE×MÑMÔU]×UaÑUaÐMÓb€NÜ"×+Ñ+¨H°jÓA×IÑIÔQY×Q]ÑQ]ÐIÓ^€LçDðL
ØÐ Üð Tóð ð ×'Ñ'Ô+;×+IÑ+IÒIØ ×*Ñ*Ô.>×.VÑ.VÒVà.×6Ñ6ˆGØˆÜ#°¸WÐFXÐ<YÔZÐZð
ˆIô !3°=À)È^Ð]iÐkrÓ s×s‰Kð	ˆIô !3°=À)È^Ð]iÓ j×jˆKàÐØˆIð  ˆÙ5@ÄÓ5EÐØò 	ˆCØ˜J™ˆIØ!ˆIØÑ%Ø(×7Ñ7ÀÐ7ÓK�ØÑ*ð	Ü-4×-EÑ-EØ"-×"<Ñ"<×"BÑ"BØ0;×0JÑ0J×0^Ñ0^Ø%0×%?Ñ%?×%HÑ%HØ+6×+EÑ+Eô	.Ñ*˜˜9 a¨ð /¨yÓ9¸SÀ¹\ÑIÔ9ð	ð"  6×;Ñ;Ó=ò 	G‰OˆH�eØ×Ñ¨H¸uÑEÕFð	Gð ÐðY tøð kùô4 %ò Ùðûô ò 
ÜÜ×3Ñ3ØœS ›VÐ$ô
ð 	
ûð
üs†   ‚BIÂA8H ÄHÄH Ä,HÄ-H Ä4IÄ5H ÅH Å(A4HÇ/H ÈIÈH ÈH È	HÈH ÈHÈH È	IÈ(&IÉIÉIz/global/spend/reportÚteamz3Group spend by internal team or customer or api_keyz;View spend for a specific api_key. Example api_key='sk-1234zJView spend for a specific internal_user_id. Example internal_user_id='1234z8View spend for a specific team_id. Example team_id='1234zrView spend for a specific customer_id. Example customer_id='1234. Can be used in conjunction with team_id as well.rÉ   )rh  Úcustomerr‰   r‰   Úinternal_user_idÚcustomer_idc              ƒ   ó`  K  — | �|€t        t        j                  ddi¬«      ‚t        j                  | d«      j                  t        j                  ¬«      }t        j                  |d«      j                  t        j                  ¬«      }ddlm	}	m
}
 	 |
€t        d	«      ‚|	d
ur;t        j                  d«       t        dt        j                   j"                  z   «      ‚|�Tt        j                  d|du«       |j%                  d«      rt'        |¬«      }d}t)        |
||||«      ƒ d{  –—† }|€g S |S |�5t        j                  d|«       d}t)        |
||||«      ƒ d{  –—† }|€g S |S |�|�t+        |||||
«      ƒ d{  –—† S |dk(  rt-        ||||
«      ƒ d{  –—† S |dk(  rd}t)        |
|||«      ƒ d{  –—† }|€g S |S |dk(  rd}t)        |
|||«      ƒ d{  –—† }|€g S |S y7 Œ¾7 Œ‰7 Œj7 ŒQ7 Œ67 Œ# t        $ r+}t        t        j                  dt/        |«      i¬«      ‚d}~ww xY w­w)aÞ  
    Get Daily Spend per Team, based on specific startTime and endTime. Per team, view usage by each key, model
    [
        {
            "group-by-day": "2024-05-10",
            "teams": [
                {
                    "team_name": "team-1"
                    "spend": 10,
                    "keys": [
                        "key": "1213",
                        "usage": {
                            "model-1": {
                                    "cost": 12.50,
                                    "input_tokens": 1000,
                                    "output_tokens": 5000,
                                    "requests": 100
                                },
                                "audio-modelname1": {
                                "cost": 25.50,
                                "seconds": 25,
                                "requests": 50
                        },
                        }
                    }
            ]
        ]
    }
    Nrß   r  rà   r  r  r   ©Úpremium_userr�   rÖ   Tz.accessing /spend/report but not a premium userú/spend/report endpoint z$Getting /spend for api_key: [set=%s]úsk-r-   aî  
                WITH SpendByModelApiKey AS (
                    SELECT
                        sl.api_key,
                        sl.model,
                        SUM(sl.spend) AS model_cost,
                        SUM(sl.prompt_tokens) AS model_input_tokens,
                        SUM(sl.completion_tokens) AS model_output_tokens
                    FROM
                        "LiteLLM_SpendLogs" sl
                    WHERE
                        sl."startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
                        AND sl."startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
                        AND sl.api_key = $3
                    GROUP BY
                        sl.api_key,
                        sl.model
                )
                SELECT
                    api_key,
                    SUM(model_cost) AS total_cost,
                    SUM(model_input_tokens) AS total_input_tokens,
                    SUM(model_output_tokens) AS total_output_tokens,
                    jsonb_agg(jsonb_build_object(
                        'model', model,
                        'total_cost', model_cost,
                        'total_input_tokens', model_input_tokens,
                        'total_output_tokens', model_output_tokens
                    )) AS model_details
                FROM
                    SpendByModelApiKey
                GROUP BY
                    api_key
                ORDER BY
                    total_cost DESC;
            z'Getting /spend for internal_user_id: %saë  
                WITH SpendByModelApiKey AS (
                    SELECT
                        sl.api_key,
                        sl.model,
                        SUM(sl.spend) AS model_cost,
                        SUM(sl.prompt_tokens) AS model_input_tokens,
                        SUM(sl.completion_tokens) AS model_output_tokens
                    FROM
                        "LiteLLM_SpendLogs" sl
                    WHERE
                        sl."startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
                        AND sl."startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
                        AND sl.user = $3
                    GROUP BY
                        sl.api_key,
                        sl.model
                )
                SELECT
                    api_key,
                    SUM(model_cost) AS total_cost,
                    SUM(model_input_tokens) AS total_input_tokens,
                    SUM(model_output_tokens) AS total_output_tokens,
                    jsonb_agg(jsonb_build_object(
                        'model', model,
                        'total_cost', model_cost,
                        'total_input_tokens', model_input_tokens,
                        'total_output_tokens', model_output_tokens
                    )) AS model_details
                FROM
                    SpendByModelApiKey
                GROUP BY
                    api_key
                ORDER BY
                    total_cost DESC;
            rh  ri  aS  

            WITH SpendByModelApiKey AS (
                SELECT
                    date_trunc('day', sl."startTime") AS group_by_day,
                    sl.end_user AS customer,
                    sl.model,
                    sl.api_key,
                    SUM(sl.spend) AS model_api_spend,
                    SUM(sl.total_tokens) AS model_api_tokens
                FROM
                    "LiteLLM_SpendLogs" sl
                WHERE
                    sl."startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
                    AND sl."startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
                GROUP BY
                    date_trunc('day', sl."startTime"),
                    customer,
                    sl.model,
                    sl.api_key
            )
            SELECT
                group_by_day,
                jsonb_agg(jsonb_build_object(
                    'customer', customer,
                    'total_spend', total_spend,
                    'metadata', metadata
                )) AS customers
            FROM
                (
                    SELECT
                        group_by_day,
                        customer,
                        SUM(model_api_spend) AS total_spend,
                        jsonb_agg(jsonb_build_object(
                            'model', model,
                            'api_key', api_key,
                            'spend', model_api_spend,
                            'total_tokens', model_api_tokens
                        )) AS metadata
                    FROM
                        SpendByModelApiKey
                    GROUP BY
                        group_by_day,
                        customer
                ) AS aggregated
            GROUP BY
                group_by_day
            ORDER BY
                group_by_day;
                r‰   aÂ  
                WITH SpendByModelApiKey AS (
                    SELECT
                        sl.api_key,
                        sl.model,
                        SUM(sl.spend) AS model_cost,
                        SUM(sl.prompt_tokens) AS model_input_tokens,
                        SUM(sl.completion_tokens) AS model_output_tokens
                    FROM
                        "LiteLLM_SpendLogs" sl
                    WHERE
                        sl."startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
                        AND sl."startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
                    GROUP BY
                        sl.api_key,
                        sl.model
                )
                SELECT
                    api_key,
                    SUM(model_cost) AS total_cost,
                    SUM(model_input_tokens) AS total_input_tokens,
                    SUM(model_output_tokens) AS total_output_tokens,
                    jsonb_agg(jsonb_build_object(
                        'model', model,
                        'total_cost', model_cost,
                        'total_input_tokens', model_input_tokens,
                        'total_output_tokens', model_output_tokens
                    )) AS model_details
                FROM
                    SpendByModelApiKey
                GROUP BY
                    api_key
                ORDER BY
                    total_cost DESC;
            )r   r   rç   r   r+  r,  r   r-  rã   rn  r�   rä   r   ÚdebugÚ
ValueErrorÚCommonProxyErrorsÚnot_premium_userÚvalueÚ
startswithÚ
hash_tokenr˜   r    r   r>   )rþ   rÿ   rÉ   r‰   rj  rC   rk  r7  r8  rn  r�   rŽ   r  ré   s                 r8   Úget_global_spend_reportrx     s¬  è ø€ ðF Ð˜XÐ-ÜÜ×3Ñ3ØÐEÐFô
ð 	
ô
 %×-Ñ-¨j¸*ÓE×MÑMÔU]×UaÑUaÐMÓb€NÜ"×+Ñ+¨H°jÓA×IÑIÔQY×Q]ÑQ]ÐIÓ^€LçFðS
ØÐ Üð Tóð ð ˜tÑ#Ü ×&Ñ&Ð'WÔXÜÐ6Ô9J×9[Ñ9[×9aÑ9aÑaÓbÐbàÐÜ ×&Ñ&Ð'MÈwÐ^bÐObÔcØ×!Ñ! %Ô(Ü$¨7Ô3�ð#ˆIôH !3°=À)È^Ð]iÐkrÓ s×sˆKØÐ"Ø�	àÐØÐ)Ü ×&Ñ&Ð'PÐRbÔcð#ˆIôH !3Ø˜y¨.¸,ÐHXó!÷ ˆKð Ð"Ø�	àÐØÐ  [Ð%<Ü7Ø ¨g°{ÀMó÷ ð ð �vÒÜ*¨>¸<ÈÐR_Ó`×`Ð`à˜Ò#ð2ˆIôh !3°=À)È^Ð]iÓ j×jˆKØÐ"Ø�	àÐØ˜Ò"ð"ˆIôF !3°=À)È^Ð]iÓ j×jˆKØÐ"Ø�	àÐðQ #ðg tøðVøðøð aøðn køðR kùô ò 
ÜÜ×3Ñ3ØœS ›VÐ$ô
ð 	
ûð
üs  ‚BH.ÂBG7 Ä,G+Ä-G7 Ä4H.Ä5G7 Ä6H.Ä7,G7 Å#G-Å$G7 Å+H.Å,G7 Å-H.Å.G7 ÆG/ÆG7 ÆH.Æ	G7 ÆG1Æ G7 Æ#H.Æ$G7 Æ<G3Æ=G7 ÇH.ÇG7 ÇH.ÇG7 ÇG5Ç G7 Ç'H.Ç(G7 Ç)H.Ç+G7 Ç-G7 Ç/G7 Ç1G7 Ç3G7 Ç5G7 Ç7	H+È &H&È&H+È+H.>   rB   r‰   rC   in  Úscope_columnc                 ó:   — | t         vrt        d| ›�«      ‚d| › d�S )u	  Spend grouped by api_key with a per-model breakdown, cut to one scope column.

    ``scope_column`` is interpolated into the SQL, so it must come from
    ``_SPEND_REPORT_SCOPE_COLUMNS`` â€” never from caller input. Scope values are
    always bound as ``$3``.
    z'Unsupported spend report scope column: a"  
        WITH SpendByModelApiKey AS (
            SELECT
                sl.api_key,
                sl.model,
                SUM(sl.spend) AS model_cost,
                SUM(sl.prompt_tokens) AS model_input_tokens,
                SUM(sl.completion_tokens) AS model_output_tokens
            FROM
                "LiteLLM_SpendLogs" sl
            WHERE
                sl."startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
                AND sl."startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
                AND sl.a­   = $3
            GROUP BY
                sl.api_key,
                sl.model
        )
        SELECT
            api_key,
            SUM(model_cost) AS total_cost,
            SUM(model_input_tokens) AS total_input_tokens,
            SUM(model_output_tokens) AS total_output_tokens,
            jsonb_agg(jsonb_build_object(
                'model', model,
                'total_cost', model_cost,
                'total_input_tokens', model_input_tokens,
                'total_output_tokens', model_output_tokens
            )) AS model_details
        FROM
            SpendByModelApiKey
        GROUP BY
            api_key
        ORDER BY
            total_cost DESC;
    )Ú_SPEND_REPORT_SCOPE_COLUMNSrr  ©ry  s    r8   Ú_scoped_spend_report_sqlr}  É  s<   € ð Ô6Ñ6ÜÐBÀ<ÐBRÐSÓTÐTðð %�~ð &ð#ð #r:   aj  
    WITH SpendByModelApiKey AS (
        SELECT
            sl.api_key,
            sl.team_id,
            sl.model,
            SUM(sl.spend) AS model_cost,
            SUM(sl.prompt_tokens) AS model_input_tokens,
            SUM(sl.completion_tokens) AS model_output_tokens
        FROM
            "LiteLLM_SpendLogs" sl
        WHERE
            sl."startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
            AND sl."startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
            AND (
                sl.organization_id = $3
                OR (
                    (sl.organization_id IS NULL OR sl.organization_id = '')
                    AND sl.team_id = ANY($4::text[])
                )
            )
        GROUP BY
            sl.api_key,
            sl.team_id,
            sl.model
    )
    SELECT
        api_key,
        SUM(model_cost) AS total_cost,
        SUM(model_input_tokens) AS total_input_tokens,
        SUM(model_output_tokens) AS total_output_tokens,
        jsonb_agg(jsonb_build_object(
            'team_id', team_id,
            'model', model,
            'total_cost', model_cost,
            'total_input_tokens', model_input_tokens,
            'total_output_tokens', model_output_tokens
        )) AS model_details
    FROM
        SpendByModelApiKey
    GROUP BY
        api_key
    ORDER BY
        total_cost DESC;
c                  óô   — ddl m} m} |€3t        t        j
                  t        j                  j                  ¬«      ‚| dur6t        t        j                  dt        j                  j                  z   ¬«      ‚|S )Nr   rm  rà   Tro  )rã   rn  r�   r   r   r  rs  Údb_not_connected_errorru  rø   rt  rm  s     r8   Ú_spend_report_prereqsr€  '  sm   € ßFàÐÜÜ×=Ñ=Ü$×;Ñ;×AÑAô
ð 	
ð ˜4ÑÜÜ×1Ñ1Ø,Ô/@×/QÑ/Q×/WÑ/WÑWô
ð 	
ð Ðr:   c                 ó"  — | �|€t        t        j                  d¬«      ‚	 t        j                  | d«      j                  t        j                  ¬«      t        j                  |d«      j                  t        j                  ¬«      f}|\  }}||k  rt        t        j                  d¬«      ‚||z
  t        t        ¬«      kD  r#t        t        j                  dt        › d	�¬«      ‚|S # t        $ r t        t        j                  d¬«      ‚w xY w)
Nr  rà   r  r  z4start_date and end_date must be in YYYY-MM-DD formatz(start_date must be on or before end_date©Údaysz!Date range too large; maximum is z days)r   r   rç   r   r+  r,  r   r-  rr  r   Ú_SPEND_REPORT_MAX_RANGE_DAYS)rþ   rÿ   Úparsedr7  r8  s        r8   Ú_parse_spend_report_date_ranger†  7  s  € ØÐ˜XÐ-ÜÜ×3Ñ3Ø;ô
ð 	
ð	
ä×Ñ˜j¨*Ó5×=Ñ=ÄXÇ\Á\Ð=ÓRÜ×Ñ˜h¨
Ó3×;Ñ;Ä8Ç<Á<Ð;ÓPð
ˆð $*Ñ €N�LØ�nÒ$ÜÜ×3Ñ3Ø=ô
ð 	
ð �nÑ$¤yÔ6RÔ'SÒSÜÜ×3Ñ3Ø6Ô7SÐ6TÐTYÐZô
ð 	
ð €Møô! ò 
ÜÜ×3Ñ3ØIô
ð 	
ð
ús   ¡A(C) Ã)%DÚ	requestedÚcaller_valueÚ
scope_namec                 ó¶   — |r2||k7  r+t        | ¬«      st        t        j                  d|› d�¬«      ‚|S |€"t        t        j                  d|› d|› d�¬«      ‚|S )zøReturn the scope value the caller may query spend for.

    Non-admin callers are clamped to their own identity: a ``requested`` value
    that differs from ``caller_value`` is a 403. Proxy admins (and admin
    viewers) may request any scope.
    r×   z#Not authorized to view spend for a z other than your ownrà   zNo z& associated with this API key; pass a z query param)rå   r   r   rø   rç   ©rÔ   r‡  rˆ  r‰  s       r8   Ú_resolve_spend_report_scoperŒ  U  s{   € ñ Ø˜Ò$Ô-@ÐSdÕ-eÜÜ"×5Ñ5Ø<¸Z¸LÐH\Ð]ôð ð ÐØÐÜÜ×3Ñ3Ø˜˜Ð$JÈ:È,ÐVbÐcô
ð 	
ð Ðr:   Úorganization_id.c              ƒ   ó  K  — ddl m} |xs | j                  }|€t        t        j
                  d¬«      ‚ ||| |¬«      ƒ d{  –—†  t        |«      j                  |¬«      ƒ d{  –—† }|t        d„ |D «       «      fS 7 Œ;7 Œ­w)	zäReturn the organization to report on and the team_ids belonging to it.

    Callable by proxy admins (any organization) and org admins of the target
    organization; every other caller is a 403 from ``_verify_org_access``.
    r   )Ú_verify_org_accessNzTNo organization_id associated with this API key; pass an organization_id query paramrà   )r�  rÔ   r�   )r�  c              3   ó4   K  — | ]  }|j                   –— Œ y ­wr5   )rC   )Ú.0rh  s     r8   ú	<genexpr>z2_resolve_org_spend_report_scope.<locals>.<genexpr>ˆ  s   è ø€ Ò<¨d˜TŸ\�\Ñ<ùs   ‚)	Ú9litellm.proxy.management_endpoints.organization_endpointsr�  Úorg_idr   r   rç   r$   Úfind_by_organization_idÚtuple)rÔ   r�  r�   r�  Ú
target_orgÚteamss         r8   Ú_resolve_org_spend_report_scoper™  p  s™   è ø€ õ ]à Ò<Ð$5×$<Ñ$<€JØÐÜÜ×3Ñ3Øiô
ð 	
ñ Ø"Ø+Ø#ô÷ ð ô
 ! Ó/×GÑGÐXbÐGÓc×c€EØ”uÑ<°eÔ<Ó<Ð<Ð<ðøð
 dús$   ‚ABÁB Á"BÁ'BÁ(BÂBz/key/spend/report)rÐ   )rÑ   z3Time from which to start viewing spend (YYYY-MM-DD)z*Time till which to view spend (YYYY-MM-DD)z_View spend for a specific api_key. Proxy admin only; other callers are scoped to their own key.c              ƒ   ó  K  — t        «       }t        ||¬«      \  }}|�|j                  d«      rt        |¬«      n|}t	        | || j
                  d¬«      }t        |t        d¬«      |||«      ƒ d{  –—† }	|	xs dS 7 Œ
­w)	a)  
    Get spend for the calling api_key over a date range, with a per-model breakdown.

    Same row shape as `/global/spend/report?api_key=...`, but callable by any key:
    non-admin callers are always scoped to their own api_key, while proxy admins
    may pass `?api_key=` to view any key.
    ©rþ   rÿ   Nrp  r-   r‰   r‹  r|  r6   )r€  r†  rv  rw  rŒ  r‰   r˜   r}  )
rÔ   rþ   rÿ   r‰   r�   r7  r8  r‡  Úscoped_api_keyr  s
             r8   Úget_key_spend_reportr�  ‹  s˜   è ø€ ô0 *Ó+€MÜ#AÈZÐbjÔ#kÑ €N�LØ-4Ð-@ÀW×EWÑEWÐX]ÔE^”
 Õ)Ðdk€IÜ0Ø+ØØ&×.Ñ.Øô	€Nô @RØÜ ¨iÔ8ØØØó@÷ :€Kð Ò˜"Ðð:ús   ‚A1B Á3A>Á4B z/user/spend/reportzlView spend for a specific internal_user_id. Proxy admin only; other callers are scoped to their own user_id.c              ƒ   óÂ   K  — t        «       }t        ||¬«      \  }}t        | || j                  d¬«      }t	        |t        d¬«      |||«      ƒ d{  –—† }|xs dS 7 Œ
­w)aX  
    Get spend for the calling user over a date range, grouped by api_key with a per-model breakdown.

    Same row shape as `/global/spend/report?internal_user_id=...`, but callable by
    any key with a user: non-admin callers are always scoped to their own user_id,
    while proxy admins may pass `?internal_user_id=` to view any user.
    r›  rj  r‹  rB   r|  Nr6   )r€  r†  rŒ  rÞ   r˜   r}  )	rÔ   rþ   rÿ   rj  r�   r7  r8  Úscoped_user_idr  s	            r8   Úget_user_spend_reportr   ¶  sx   è ø€ ô0 *Ó+€MÜ#AÈZÐbjÔ#kÑ €N�LÜ0Ø+Ø"Ø&×.Ñ.Ø%ô	€Nô @RØÜ ¨fÔ5ØØØó@÷ :€Kð Ò˜"Ðð:úó   ‚AAÁAÁAz/team/spend/reportzbView spend for a specific team_id. Proxy admin only; other callers are scoped to their key's team.c              ƒ   óÂ   K  — t        «       }t        ||¬«      \  }}t        | || j                  d¬«      }t	        |t        d¬«      |||«      ƒ d{  –—† }|xs dS 7 Œ
­w)a  
    Get spend for the calling key's team over a date range, grouped by api_key with a per-model breakdown.

    Callable by any key that belongs to a team: non-admin callers are always
    scoped to their key's team_id, while proxy admins may pass `?team_id=` to
    view any team.
    r›  rC   r‹  r|  Nr6   )r€  r†  rŒ  rC   r˜   r}  )	rÔ   rþ   rÿ   rC   r�   r7  r8  Úscoped_team_idr  s	            r8   Úget_team_spend_reportr¤  à  sx   è ø€ ô0 *Ó+€MÜ#AÈZÐbjÔ#kÑ €N�LÜ0Ø+ØØ&×.Ñ.Øô	€Nô @RØÜ ¨iÔ8ØØØó@÷ :€Kð Ò˜"Ðð:úr¡  z/organization/spend/reportzŠView spend for a specific organization_id. Proxy admins may pass any organization; org admins are scoped to organizations they administer.c              ƒ   ó¼   K  — t        «       }t        ||¬«      \  }}t        | ||¬«      ƒ d{  –—† \  }}t        |t        ||||«      ƒ d{  –—† }	|	xs dS 7 Œ)7 Œ­w)a„  
    Get spend for an organization over a date range, grouped by api_key with a per-model and per-team breakdown.

    Covers spend logged against the organization directly and against any of its
    teams. Callable by proxy admins (any organization) and org admins (their own
    organizations). Defaults to the calling key's organization_id when
    `?organization_id=` is omitted.
    r›  )rÔ   r�  r�   Nr6   )r€  r†  r™  r˜   Ú_ORG_SPEND_REPORT_SQL)
rÔ   rþ   rÿ   r�  r�   r7  r8  r—  rÍ   r  s
             r8   Úget_organization_spend_reportr§  
  s}   è ø€ ô2 *Ó+€MÜ#AÈZÐbjÔ#kÑ €N�LÜ!@Ø+Ø'Ø#ô"÷ Ñ€J�ô
 @RØÜØØØØó@÷ :€Kð Ò˜"Ððøð
:ús!   ‚,A®A¯AÁAÁAÁAz/global/spend/all_tag_namesc               ƒ   ó  K  — 	 ddl m}  | €t        d«      ‚d}t        | |«      ƒ d {  –—† }|€g S g }|D ]"  }|j	                  |j                  d«      «       Œ$ d|iS 7 Œ5# t        $ r�}t        |t        «      rBt        t        |dd|› d	�«      d
t        |dd«      t        |dt        j                  «      ¬«      ‚t        |t        «      r|‚t        dt        |«      z   d
t        |dd«      t        j                  ¬«      ‚d }~ww xY w­w)Nr   r­   rÖ   z‘
        SELECT DISTINCT
            jsonb_array_elements_text(request_tags) AS individual_request_tag
        FROM "LiteLLM_SpendLogs";
        r^   Ú	tag_namesrâ   z/spend/all_tag_names Error(r  r  r  r  rá   r  z/spend/all_tag_names Error)rã   r�   rä   r˜   r4  r5  rî   r   r  r  r   r  r>   )r�   rŽ   r  Ú
_tag_namesr9  ré   s         r8   Úglobal_get_all_tag_namesr«  5  s0  è ø€ ð'
Ý<àÐ Üð Tóð ðˆ	ô BTÐTaÐclÓAm×;mˆØÐØˆIàˆ
Øò 	AˆCØ×Ñ˜cŸg™gÐ&>Ó?Õ@ð	Að ˜ZÐ(Ð(ð <nùô ò 
Ü�aœÔ'Ü Ü  8Ð/JÈ1È#ÈQÐ-OÓPØ%Ü˜a ¨&Ó1Ü˜Q ¬v×/TÑ/TÓUô	ð ô ˜œ>Ô*ØˆGÜØ0´3°q³6Ñ9Ø!Ü˜!˜W fÓ-Ü×6Ñ6ô	
ð 	
ûð
üsC   ‚D	„$A  ¨A©A  °D	±,A  ÁD	ÁA  Á 	DÁ)BDÄDÄD	z/global/spend/tagsz"comman separated tags to filter onrÑ   c              ƒ   ó4  K  — ddl }ddlm} 	 |€t        d«      ‚|�| €t	        dddt
        j                  ¬«      ‚t        | |||¬«      ƒ d{  –—† }|S 7 Œ# t        $ rµ}|j                  «       }t        |«      d	z   |z   }t        |t        «      rBt	        t        |d
d|› d�«      dt        |dd«      t        |dt
        j                  «      ¬«      ‚t        |t        «      r|‚t	        d|z   dt        |dd«      t
        j                  ¬«      ‚d}~ww xY w­w)a}  
    LiteLLM Enterprise - View Spend Per Request Tag. Used by LiteLLM UI

    Example Request:
    ```
    curl -X GET "http://0.0.0.0:4000/spend/tags" -H "Authorization: Bearer sk-1234"
    ```

    Spend with Start Date and End Date
    ```
    curl -X GET "http://0.0.0.0:4000/spend/tags?start_date=2022-01-01&end_date=2022-02-01" -H "Authorization: Bearer sk-1234"
    ```
    r   Nr­   rÖ   r  Úbad_requestr  )rþ   rÿ   Útags_strr�   ú
râ   r  r  r  r  r  rá   r
  )Ú	tracebackrã   r�   rä   r  r   rç   Úui_get_spend_by_tagsÚ
format_excr>   rî   r   r  r  )	rþ   rÿ   rÑ   r°  r�   r  ré   Úerror_traceÚ	error_strs	            r8   Úglobal_view_spend_tagsrµ  i  s?  è ø€ óJ å8ð&
ØÐ Üð Tóð ð Ð˜zÐ1Ü Ø@Ø"ØÜ×0Ñ0ô	ð ô !5Ø!ØØØ'ô	!
÷ 
ˆð ˆð
ùô ò 
Ø&×1Ñ1Ó3ˆÜ˜q›6 D™=¨;Ñ6ˆ	Ü�aœÔ'Ü Ü  8Ð/AÀ)ÀÈAÐ-NÓOØ%Ü˜a ¨&Ó1Ü˜Q ¬v×/TÑ/TÓUô	ð ô ˜œ>Ô*ØˆGÜØ'¨)Ñ3Ø!Ü˜!˜W fÓ-Ü×6Ñ6ô	
ð 	
ûð
üs<   ‚DŽA A ÁAÁA ÁDÁA Á	DÁ B0DÄDÄDc              ƒ   óà  K  — ddl m} |€t        j                  d«       y t	        j
                  | d«      j                  t        j                  ¬«      }t	        j
                  |d«      j                  t        j                  ¬«      }	 d}t        ||||«      ƒ d {  –—† }d}t        ||||«      ƒ d {  –—† }||fS 7 Œ 7 Œ
# t        $ r }t        j                  d|«       Y d }~y d }~ww xY w­w)	Nr   r­   zZDatabase not connected. Connect a database to your proxy for weekly, monthly spend reportsr  r  aÚ  
        SELECT
            t.team_alias,
            SUM(s.spend) AS total_spend
        FROM
            "LiteLLM_SpendLogs" s
        LEFT JOIN
            "LiteLLM_TeamTable" t ON s.team_id = t.team_id
        WHERE
            s."startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
            AND s."startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
        GROUP BY
            t.team_alias
        ORDER BY
            total_spend DESC;
        aŠ  
        SELECT
        jsonb_array_elements_text(request_tags) AS individual_request_tag,
        SUM(spend) AS total_spend
        FROM "LiteLLM_SpendLogs"
        WHERE "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
          AND "startTime" <  (($2::timestamptz + INTERVAL '1 day') AT TIME ZONE 'UTC')
        GROUP BY individual_request_tag
        ORDER BY total_spend DESC;
        z(Exception in _get_daily_spend_reports %s)rã   r�   r   rß   r   r+  r,  r   r-  r˜   rä   )	rþ   rÿ   r�   r7  r8  rŽ   r  Úspend_per_tagré   s	            r8   Ú _get_spend_report_for_time_ranger¸  »  s  è ø€ õ 9àÐÜ×"Ñ"Øhô	
ð ô %×-Ñ-¨j¸*ÓE×MÑMÔU]×UaÑUaÐMÓb€NÜ"×+Ñ+¨H°jÓA×IÑIÔQY×Q]ÑQ]ÐIÓ^€Lð'Rðˆ	ô  ASØ˜9 n°lóA
÷ ;
ˆð
	ˆ	ô EWØ˜9 n°lóE
÷ ?
ˆð ˜Ð&Ð&ð);
øð ?
ùô
 ò RÜ×"Ñ"Ð#MÈq×QÑQûðRüsT   ‚BC.Â
C ÂB>ÂC Â5C Â6C Â=C.Â>C Ã C Ã	C+ÃC&Ã!C.Ã&C+Ã+C.z/spend/calculatezThe calculated costzapplication/jsonÚschemar?   ÚcostÚnumberç        )r  rö   Úexample)r  Ú
properties)rö   ÚcontentÚrequestc              ƒ   ó¾  K  — 	 ddl m} ddlm} ddlm} d}| j                  ��A| j                  €t        dd¬«      ‚d}d}|�˜|j                  �Z| j                  |j                  v rB|j                  | j                     }|j                  D ]  }|j                  d	«      |k(  sŒ|}Œ n2|j                  D ]#  }|j                  d	«      | j                  k(  sŒ"|}Œ% 	 |�h|j                  d
«      }	|	j                  d«      }
|	j                  d«      }|	j                  d«      }|€|�
 |||¬«      } ||
| j                  |¬«      }na || j                  | j                  ¬«      }nB| j                  �)t        j                  di | j                  ¤Ž} ||¬«      }nt        dd¬«      ‚d|iS # t        $ r¥}t        |t        «      rRt!        t#        |dt%        |«      «      t#        |dd«      t#        |dd«      t#        |dt&        j(                  «      ¬«      ‚|› }t!        t#        |d|«      t#        |dd«      t#        |dd«      t#        |dd«      ¬«      ‚d}~ww xY w­w)aÀ  
    Accepts all the params of completion_cost.

    Calculate spend **before** making call:

    Note: If you see a spend of $0.0 you need to set custom_pricing for your model: https://docs.litellm.ai/docs/proxy/custom_pricing

    ```
    curl --location 'http://localhost:4000/spend/calculate'
    --header 'Authorization: Bearer sk-1234'
    --header 'Content-Type: application/json'
    --data '{
        "model": "anthropic.claude-v2",
        "messages": [{"role": "user", "content": "Hey, how'''s it going?"}]
    }'
    ```

    Calculate spend **after** making call:

    ```
    curl --location 'http://localhost:4000/spend/calculate'
    --header 'Authorization: Bearer sk-1234'
    --header 'Content-Type: application/json'
    --data '{
        "completion_response": {
            "id": "chatcmpl-123",
            "object": "chat.completion",
            "created": 1677652288,
            "model": "gpt-3.5-turbo-0125",
            "system_fingerprint": "fp_44709d6fcb",
            "choices": [{
                "index": 0,
                "message": {
                    "role": "assistant",
                    "content": "Hello there, how may I assist you today?"
                },
                "logprobs": null,
                "finish_reason": "stop"
            }]
            "usage": {
                "prompt_tokens": 9,
                "completion_tokens": 12,
                "total_tokens": 21
            }
        }
    }'
    ```
    r   )Úcompletion_cost)ÚCostPerToken©rW  NrX  z>Bad Request - messages must be provided if 'model' is providedrà   Ú
model_namer[  rŠ   Úinput_cost_per_tokenÚoutput_cost_per_token)rÆ  rÇ  )rŠ   ÚmessagesÚcustom_cost_per_token)rŠ   rÈ  )Úcompletion_responsezFBad Request - Either 'model' or 'completion_response' must be providedrº  râ   r  r  r  rá   r  r  r  r6   )r_  rÂ  Úlitellm.cost_calculatorrÃ  rã   rW  rŠ   rÈ  r   Úmodel_group_aliasÚ
model_listr5  rÊ  ÚModelResponserä   rî   r  r  r>   r   rç   )rÀ  rÂ  rÃ  rW  Ú_costÚ_model_in_llm_routerÚcost_per_tokenÚ_model_group_namerŠ   Ú_litellm_paramsÚ_litellm_model_namerÆ  rÇ  Ú_completion_responseré   Ú	error_msgs                   r8   Úcalculate_spendr×  ù  s�  è ø€ ðRP
Ý+Ý8Ý9àˆØ�=‰=Ñ$Ø×ÑÐ'Ü#Ø #Ø[ôð ð $(Ð Ø26ˆNØÐ%Ø×/Ñ/Ð;ÀÇÁÐQ[×QmÑQmÑ@mà/9×/KÑ/KÈGÏMÉMÑ/ZÐ%Ø!+×!6Ñ!6ò 9˜Ø Ÿ9™9 \Ó2Ð6GÓGØ38Ñ0ñ9ð ",×!6Ñ!6ò 9˜Ø Ÿ9™9 \Ó2°g·m±mÓCØ38Ñ0ð9ðð $Ð/Ø)=×)AÑ)AÐBRÓ)S�Ø-<×-@Ñ-@ÀÓ-IÐ#Ø.=×.AÑ.AÐBXÓ.YÐ$Ø/>×/BÑ/BÐCZÓ/[Ð%Ø'Ð3Ð7LÐ7XÙ%1Ø-AØ.Cô&�Nñ
 (Ø-Ø$×-Ñ-Ø*8ô‘ñ (¨g¯m©mÀg×FVÑFVÔW‘Ø×(Ñ(Ð4Ü*1×*?Ñ*?Ñ*^À'×B]ÑB]Ñ*^Ð Ù#Ð8LÔM‰EäØØ_ôð ð ˜ˆÐøÜò 
Ü�aœÔ'Ü Ü  8¬S°«VÓ4Ü˜Q ¨Ó/Ü˜a ¨&Ó1Ü˜Q ¬v×/JÑ/JÓKô	ð ð  ˜Sˆ	ÜÜ˜A˜y¨)Ó4Ü˜˜F FÓ+Ü˜!˜W fÓ-Ü˜˜M¨3Ó/ô	
ð 	
ûð
üs7   ‚I„B F, Â%2F, ÃCF, Æ+IÆ,	IÆ5B IÉIÉIú/spend/logs/v2z/spend/logs/uizGet spend logs based on api keyzGet spend logs based on user_idz4request_id to get spend logs for specific request_idz6Filter spend logs by session_id (partial string match)zFilter spend logs by team_idz:Filter logs with spend greater than or equal to this valuez7Filter logs with spend less than or equal to this valuerA  zPage number for pagination)rõ   rö   Úgeé2   zNumber of items per pageiè  )rõ   rö   rÙ  Úlez.Filter logs by status (e.g., success, failure)zfFilter logs by cache state: 'hit' or 'miss'. Miss includes legacy rows with a null/unknown cache statezFilter logs by modelz5Filter logs by model ID (litellm model deployment id)zFilter logs by model groupzFilter logs by key aliaszFilter logs by end userz.Filter logs by error code (e.g., '404', '500')z3Filter logs by error message (partial string match)r‹   zcSort logs by field: spend, total_tokens, startTime, endTime, request_duration_ms, model, or ttft_msÚdesczSort order: asc or descz;Exclude LiteLLM internal health check requests from resultsrz   Ú	min_spendÚ	max_spendÚpageÚ	page_sizeÚstatus_filterÚcache_hit_filterrX   Ú	key_aliasrt   Ú
error_codeÚerror_messageÚsort_byÚ
sort_orderÚexclude_internal_health_checksc              ƒ   óø  ‡@‡AK  — ddl m} |€t        dddt        j                  ¬«      ‚ddlm} d	 || «      v ŠAh d
£}||vr;t        d|› ddj                  t        |«      «      › �ddt        j                  ¬«      ‚|�3|j                  «       dvr!t        d|› d�ddt        j                  ¬«      ‚t        |t        «      r%|dvr!t        d|› d�ddt        j                  ¬«      ‚	 t        |¬«      }|duxr ‰A }|rd}d}nM|�|	€t        dddt        j                  ¬«      ‚‰ArddgndgŠ@dt        dt        fˆ@ˆAfd„}  | |«      } | |	«      }i }!|�&|�$|j                  «       |j                  «       dœ|!d <   |�||!d!<   t!        |«      }"|"r|!j#                  |"«       |�||!d"<   |�||!d#<   |�||!d$<   |�||!d%<   |�||!d&<   |�||!d'<   g }#|�|#j%                  d(g|d)œ«       |�|#j%                  d*d+gd,|› d,�d-œ«       |�|#j%                  d*d.g|d)œ«       |#r?t'        |#«      d/k(  r	|#d   |!d0<   n(|!j)                  d1g «      |#D �$cg c]  }$d0|$i‘Œ c}$z   |!d1<   |�||!d2<   |€|�i |!d3<   |�||!d3   d4<   |�||!d3   d5<   |�‰As|st+        |||¬6«      ƒ d{  –—†  | xr | xr |du xr t-        |¬«      }%|%rt/        ||¬7«      ƒ d{  –—† nd8}&|%xr	 |& xr |du}'|s»|s¹|�>t1        |||¬9«      ƒ d{  –—† }(|(s t3        t        j4                  d:d;|› �i¬<«      ‚||!d!<   ny|%rw|&r,|€|!j7                  d#d«       d#|j8                  id!d=|&iig|!d><   n7|€|j8                  |!d#<   n%|!j)                  d1g «      d#|j8                  igz   |!d1<   |!j7                  d!d«       |
d/z
  |z  })|}*|xs d?j                  «       }+g },g }-d/}.|�X|�V|,j%                  d@|.› dA�«       |-j%                  |«       |.d/z  }.|,j%                  dB|.› dA�«       |-j%                  |«       |.d/z  }.dCD ]V  \  }/}0|!j)                  |0«      }1|1€Œt        |1t        «      sŒ+|,j%                  |/› dD|.› �«       |-j%                  |1«       |.d/z  }.ŒX |&rOdE|.› dF|.d/z   › dG�}2|-j%                  |j8                  «       |-j%                  |&«       |.dHz  }.|,j%                  |2«       n6|'r4|,j%                  dI|.› �«       |-j%                  |j8                  «       |.d/z  }.|�pt        |t        «      r`|j;                  dJdK«      j;                  dLdM«      j;                  dNdO«      }3|,j%                  dP|.› �«       |-j%                  dL|3› dL�«       |.d/z  }.|�A|dQk(  r|,j%                  dR«       n*|,j%                  dS|.› �«       |-j%                  |«       |.d/z  }.|dTk(  r|,j%                  dU«       n|dVk(  r|,j%                  dW«       |r5|,j%                  dX|.› dY|.d/z   › dZ�«       |-j=                  t>        «       |.dHz  }.|�*|,j%                  d[|.› �«       |-j%                  |«       |.d/z  }.|�*|,j%                  d\|.› �«       |-j%                  |«       |.d/z  }.|�.|,j%                  d]|.› �«       |-j%                  dL|› dL�«       |.d/z  }.|�*|,j%                  d^|.› �«       |-j%                  |«       |.d/z  }.|�.|,j%                  d_|.› �«       |-j%                  dL|› dL�«       |.d/z  }.|+d`k(  rdandb}4dc}5|*ddk(  rde}6df}5n|*dgv rd,|*› d,�}6n|*}6dhdij                  |,«      › dj|.› dk�}7tA        ||7g|-¢tB        d/z   ‘­Ž ƒ d{  –—† }8|8rtE        |8d   dl   «      nd}9|9tB        kD  }:|:rtB        n|9};dmdij                  |,«      › dn|6› do|4› |5› dp|.› dq|.d/z   › dr�}<|-j=                  ||)g«        |jF                  jH                  |<g|-¢­Ž ƒ d{  –—† }=tK        |=«       |;|z   d/z
  |z  }>tM        jN                  dstQ        jR                  |=dtt        ¬u«      «       tU        ||=|;|
||>‰A |:¬v«      ƒ d{  –—† S c c}$w 7 �Œ¦7 �Œv7 �ŒN7 Œú7 Œv7 Œ# tV        $ r&}?tM        jX                  dw|?«       t[        |?«      ‚d}?~?ww xY w­w)xa§  
    View spend logs with pagination support.
    Available at both `/spend/logs/v2` (public API) and `/spend/logs/ui` (internal UI).

    Returns paginated response with data, total, page, page_size, and total_pages.

    Example:
    ```
    curl -X GET "http://0.0.0.0:8000/spend/logs/v2?start_date=2025-11-25%2000:00:00&end_date=2025-11-26%2023:59:59&page=1&page_size=50" -H "Authorization: Bearer sk-1234"
    ```
    r   r­   Nú Prisma Client is not initializedr  r  r  )Úget_request_routerØ  >   rŠ   rY   ÚendTimeÚttft_msr‹   rJ   Úrequest_duration_mszInvalid sort_by: z. Must be one of: z, r­  ræ  >   ÚascrÜ  zInvalid sort_order: z. Must be one of: asc, descrç  >   ÚhitÚmisszInvalid cache_hit_filter: z. Must be one of: hit, missrâ  r×   z$Start date and end date are requiredú%Y-%m-%d %H:%M:%Sr  Údate_strr3   c                 ó
  •— | j                  «       } ‰D ]8  }	 t        j                  | |«      j                  t        j
                  ¬«      c S  ‰rdnd}t        t        j                  d| › d|› �¬«      ‚# t        $ r Y Œmw xY w)Nr  z%'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'z'YYYY-MM-DD HH:MM:SS'zInvalid date format: z. Expected: rà   )
Ústripr   r+  r,  r   r-  rr  r   r   rç   )ró  ÚfmtÚexpectedÚformatsÚis_v2s      €€r8   Ú
parse_datez&ui_view_spend_logs.<locals>.parse_date@	  s‘   ø€ Ø#Ÿ>™>Ó+�Ø"ò !�Cð!Ü'×0Ñ0°¸3Ó?×GÑGÌxÏ|É|ÐGÓ\Ò\ð!ñ
 NSÑ"IÐXo�Ü#Ü &× ;Ñ ;Ø2°8°*¸LÈÈ
ÐSôð øô &ò !Ù ð!ús   ˜3A6Á6	BÂB©ÚgteÚlter‹   rC   r‰   rB   r½   rŠ   rX   rO   Úuser_api_key_alias)ÚpathÚstring_containsÚerror_informationrä  ú")rÿ  Úequalsrå  rA  ÚmetadataÚANDrt   rY   rü  rý  ©r�   rÔ   r½   ©r�   rÔ   r6   ©r�   rÔ   rC   rß   z.Not authorized to view team spend for team_id=rà   rÇ   ÚORrÜ  z"startTime" >= ($z!::timestamptz AT TIME ZONE 'UTC')z"startTime" <= ($))rC   rC   )z"user"rB   )r‰   r‰   )r½   r½   )rŠ   rŠ   )rX   rX   )rO   rO   )rt   rt   z = $z("user" = $z OR team_id = ANY($z
::text[]))é   z
"user" = $ú\z\\ú%z\%rf  z\_zsession_id LIKE $Úsuccessz&(status = 'success' OR status IS NULL)z
status = $rð  zLOWER(cache_hit) = 'true'rñ  z1(cache_hit IS NULL OR LOWER(cache_hit) != 'true')zapi_key NOT IN ($z, $r  z
spend >= $z
spend <= $z&metadata->>'user_api_key_alias' LIKE $z0metadata->'error_information'->>'error_code' = $z6metadata->'error_information'->>'error_message' LIKE $rï  ÚASCÚDESCÚ rí  z¢CASE WHEN "completionStartTime" IS NULL OR "completionStartTime" = "endTime" THEN NULL ELSE (EXTRACT(EPOCH FROM ("completionStartTime" - "startTime")) * 1000) ENDz NULLS LAST)r‹   rì  z—
            SELECT COUNT(*) AS total_count
            FROM (
                SELECT 1
                FROM "LiteLLM_SpendLogs"
                WHERE z AND z
                LIMIT $z*
            ) AS bounded_matches
        rg   a¬  
            SELECT
                request_id, call_type, api_key, spend, total_tokens,
                prompt_tokens, completion_tokens, "startTime", "endTime",
                "completionStartTime", model, model_id, model_group,
                custom_llm_provider, api_base, "user", metadata,
                cache_hit, cache_key, request_tags, team_id,
                organization_id, end_user, requester_ip_address,
                session_id, status, mcp_namespaced_tool_name, agent_id,
                COALESCE(request_duration_ms, (EXTRACT(EPOCH FROM ("endTime" - "startTime")) * 1000)::INTEGER) AS request_duration_ms
            FROM "LiteLLM_SpendLogs"
            WHERE z
            ORDER BY ú z
            LIMIT $z	 OFFSET $z	
        zdata= %sé   )Úindentrõ   )Úenrich_session_countsÚtotal_is_cappedzError in ui_view_spend_logs: %s).rã   r�   r  r   ÚHTTP_401_UNAUTHORIZEDÚlitellm.proxy.auth.auth_utilsrë  Újoinr6  rç   Úlowerrî   r>   rå   r   Ú	isoformatÚ_build_status_filter_conditionÚupdater4  r¸   r5  Ú _assert_user_can_view_request_idÚ_can_user_view_spend_logÚ/_get_permitted_team_ids_for_spend_logs_or_emptyÚ_can_team_member_view_logr   rø   rñ   rÞ   r,  Úextendr/   r˜   r,   rL   r‘   r’   Ú_hydrate_spend_log_metadatar   rq  ÚjsonÚdumpsÚ_build_ui_spend_logs_responserä   Ú	exceptionr!   )BrÀ  r‰   rÞ   r½   rz   rC   rÝ  rÞ  rþ   rÿ   rß  rà  rÔ   rá  râ  rŠ   rX   rO   rã  rt   rä  rå  ræ  rç  rè  r�   rë  Úvalid_sort_fieldsÚis_admin_viewÚis_request_id_lookupr7  r8  rú  Úwhere_conditionsÚstatus_conditionÚmetadata_filtersÚfilter_condÚuser_scope_appliesÚpermitted_team_idsÚ#explicit_user_requires_caller_scopeÚcan_view_teamÚskipÚorder_columnÚorder_directionÚsql_conditionsÚ
sql_paramsÚpÚsql_colÚwc_keyÚvalÚ	or_clauseÚlike_escaped_session_idÚ_sql_dirÚ_nulls_clauseÚ_order_exprÚcount_queryÚ
count_rowsÚ	raw_totalr  Útotal_recordsrŽ   r£   Útotal_pagesré   rø  rù  sB                                                                   @@r8   Úui_view_spend_logsrE  •  sQ  ùè ø€ õL 9àÐÜØ6Ø!ØÜ×-Ñ-ô	
ð 	
õ @à#Ñ'8¸Ó'AÐA€Eò Ðð Ð'Ñ'ÜØ'¨ yÐ0BÀ4Ç9Á9ÌVÐTeÓMfÓCgÐBhÐiØØÜ×,Ñ,ô	
ð 	
ð Ð *×"2Ñ"2Ó"4¸OÑ"KÜØ*¨:¨,Ð6QÐRØØÜ×,Ñ,ô	
ð 	
ô Ð"¤CÔ(Ð-=À_Ñ-TÜØ0Ð1AÐ0BÐB]Ð^ØØ$Ü×,Ñ,ô	
ð 	
ð\+Ü2ÐEVÔWˆØ&0¸Ð&<Ò&JÀUÀÐáð /3ˆNØ,0‰LàÐ! XÐ%5Ü$ØBØ&Ø Ü×4Ñ4ô	ð ñ CHÐ1°:Ñ>ÐNaÐMbˆGð¤Sð ¬Xö ñ (¨
Ó3ˆNÙ% hÓ/ˆLð 35ÐØÐ%¨,Ð*Bà%×/Ñ/Ó1Ø#×-Ñ-Ó/ñ-Ð˜[Ñ)ð
 ÐØ*1Ð˜YÑ'ä"@ÀÓ"OÐÙØ×#Ñ#Ð$4Ô5àÐØ*1Ð˜YÑ'àÐØ'.Ð˜VÑ$àÐ!Ø-7Ð˜\Ñ*àÐØ(-Ð˜WÑ%àÐØ+3Ð˜ZÑ(àÐ"Ø.9Ð˜]Ñ+ð #%ÐØÐ Ø×#Ñ#à1Ð2Ø'0ñôð Ð!Ø×#Ñ#à0°,Ð?Ø ! * ¨QÐ/ñôð Ð$Ø×#Ñ#à0°/ÐBØ'4ñôñ ÜÐ#Ó$¨Ò)Ø/?ÀÑ/BÐ  Ò,à*:×*>Ñ*>¸uÀbÓ*IØAQöMØ2=�Z Ò-òMñ +Ð  Ñ'ð ÐØ+3Ð˜ZÑ(àÐ  IÐ$9Ø(*Ð˜WÑ%ØÐ$Ø3<Ð  Ñ)¨%Ñ0ØÐ$Ø3<Ð  Ñ)¨%Ñ0ð Ð!©%¹Ü2Ø+Ø"3Ø%ô÷ ð ð %Ð$ò NØ!Ð!òNà˜4�òNô )Ð;LÔMð	 	ñ "ô	 BØ+Ø"3ô÷ ð ð
 ð 	ð ÒQÐ'9Ð#9ÒQ¸gÈTÐ>Qð 	,ñ $©MØÐ"Ü-FØ"/Ø&7Ø#ô.÷ (�ñ
 %Ü'Ü$*×$=Ñ$=Ø 'Ð+YÐZaÐYbÐ)cÐdôð ð /6Ð  Ò+Ù#Ù%Ø�Ø(×,Ñ,¨V°TÔ:àÐ!2×!:Ñ!:Ð;Ø" TÐ+=Ð$>Ð?ð.Ð$ TÒ*ð
 �Ø3D×3LÑ3LÐ(¨Ò0à2B×2FÑ2FÀuÈbÓ2QØ#Ð%6×%>Ñ%>Ð?ðUñ 3Ð(¨Ñ/ð !×$Ñ$ Y°Ô5à˜a‘x 9Ñ,ˆð &ˆØ",Ò"6°×!=Ñ!=Ó!?ˆð
 ,.ˆØ*,ˆ
Øˆð
 Ð%¨,Ð*BØ×!Ñ!Ð$7¸°sÐ:[Ð"\Ô]Ø×Ñ˜nÔ-Ø�‰FˆAØ×!Ñ!Ð$7¸°sÐ:[Ð"\Ô]Ø×Ñ˜lÔ+Ø�‰FˆAð	 
ò 	‰OˆG�Vð #×&Ñ& vÓ.ˆCØ‰¤:¨c´3Õ#7Ø×%Ñ%¨¨	°°a°SÐ&9Ô:Ø×!Ñ! #Ô&Ø�Q‘‘ð	ñ" Ø!,¨Q¨CÐ/BÀ1ÀqÁ5À'ÈÐTˆIØ×ÑÐ/×7Ñ7Ô8Ø×ÑÐ0Ô1Ø�‰FˆAØ×!Ñ! )Õ,Ù0Ø×!Ñ! J¨q¨cÐ"2Ô3Ø×ÑÐ/×7Ñ7Ô8Ø�‰FˆAàÐ!¤j°¼SÔ&AØ-7×-?Ñ-?ÀÀfÓ-M×-UÑ-UÐVYÐ[`Ó-a×-iÑ-iÐjmÐotÓ-uÐ#Ø×!Ñ!Ð$5°a°SÐ"9Ô:Ø×Ñ Ð"9Ð!:¸!Ð<Ô=Ø�‰FˆAð Ð$Ø 	Ò)Ø×%Ñ%Ð&NÕOà×%Ñ%¨
°1°#Ð&6Ô7Ø×!Ñ! -Ô0Ø�Q‘�à˜uÒ$Ø×!Ñ!Ð"=Õ>Ø Ò'Ø×!Ñ!Ð"UÔVá)Ø×!Ñ!Ð$5°a°S¸¸AÀ¹E¸7À!Ð"DÔEØ×ÑÔ=Ô>Ø�‰FˆAð Ð Ø×!Ñ! J¨q¨cÐ"2Ô3Ø×Ñ˜iÔ(Ø�‰FˆAØÐ Ø×!Ñ! J¨q¨cÐ"2Ô3Ø×Ñ˜iÔ(Ø�‰FˆAð Ð Ø×!Ñ!Ð$JÈ1È#Ð"NÔOØ×Ñ  ) ¨AÐ.Ô/Ø�‰FˆAØÐ!Ø×!Ñ!Ð$TÐUVÐTWÐ"XÔYØ×Ñ˜jÔ)Ø�‰FˆAØÐ$Ø×!Ñ!Ð$ZÐ[\ÐZ]Ð"^Ô_Ø×Ñ  - °Ð2Ô3Ø�‰FˆAð $3°eÒ#;™%ÀˆØˆØ˜9Ò$ð^ð ð
 *‰MØÐ5Ñ5Ø˜l˜^¨1Ð-‰Kà&ˆKð"ð
 —|‘| NÓ3Ð4ð 5Ø�sð 	ðˆô HZØ˜;ðH
Ø)3ðH
Ü5TÐWXÑ5XòH
÷ B
ˆ
ñ AKœ3˜z¨!™}¨]Ñ;Ô<ÐPQˆ	Ø!*Ô-LÑ!LˆÙBQÕ>ÐW`ˆð ð —<‘< Ó/Ð0ð 1Ø!�] ! H :¨m¨_ð =Ø�3�i  A¡˜wð '	ðˆ	ð 	×Ñ˜9 dÐ+Ô,à6˜M×,Ñ,×6Ñ6°yÐNÀ:ÒN×Nˆä# DÔ)ð ,¨iÑ7¸!Ñ;À	ÑIˆä×"Ñ" :¬t¯z©z¸$ÀqÔRUÔ/VÔWä2ØØØØØØØ&+ )Ø+ô	
÷ 	
ð 		
ùòWMð$ùðùð(ùð@B
øð0 Oøð	
ùô ò +Ü×&Ñ&Ð'HÈ!ÔLÜ'¨Ó*Ð*ûð+üs´   „C#a:Ã(Ea É`4ÉAa Ê`9Ê2a Ë`<Ë*a Ë1`?Ë2D>a Ð1a ÑLa ÝaÝBa ßaßA!a à/aà0a à3a:à4a à<a à?a áa áa áa á	a7á!a2á2a7á7a:c                   ó\   — e Zd ZU eez  ez  dz  ed<   eez  ez  dz  ed<   eez  dz  ed<   y)ÚRequestResponsePayloadNrÈ  r  Úproxy_server_request)r;   r<   r=   r>   rï   rò   rE   r6   r:   r8   rG  rG  ‰
  s9   … Ø�D‰j˜4Ñ $Ñ&Ó&Ø�D‰j˜4Ñ $Ñ&Ó&Ø ™* tÑ+Ô+r:   rG  >   ú[]ú{}r  ÚnullÚ_EMPTY_SPEND_LOG_VALUESru  c                 óž   — | €yt        | t        «      r| j                  «       t        vS t        | t        t
        f«      rt        | «      dkD  S y)NFr   T)rî   r>   rõ  rL  rï   rò   r¸   )ru  s    r8   Ú_spend_log_field_has_contentrN  ’
  sE   € Ø€}ØÜ�%œÔØ�{‰{‹}Ô$;Ð;Ð;Ü�%œ$¤˜Ô&Ü�5‹z˜A‰~ÐØr:   r»   c                 óÞ   — | D ]N  }t        |t        «      sŒ|j                  d«      }t        |t        «      sŒ6	 t	        j
                  |«      |d<   ŒP y# t        t        f$ r i |d<   Y Œhw xY w)a  Re-hydrate the JSONB ``metadata`` column returned by ``query_raw`` as a string.

    The Prisma serialiser bypasses the model-layer JSON hydration we get on the ORM
    path, while the UI reads ``metadata.status`` / ``metadata.error_information`` /
    ``metadata.internal_call_origin`` as object fields. Property access on a string
    is silently undefined, so failure rows looked like successes (#29674). Every
    ``query_raw`` reader of this column goes through here so a new one cannot
    reintroduce that.
    r  N)rî   rò   r5  r>   r#  Úloadsrr  Ú	TypeError)r»   r9  Úmds      r8   r"  r"  œ
  sm   € ð ò %ˆÜ˜#œtÔ$ØØ�W‰W�ZÓ ˆÜ�bœ#Õð%Ü"&§*¡*¨R£.��J’ñ%øô ¤	Ð*ò %Ø"$��J“ð%ús   ºAÁA,Á+A,r  c                 óü   — t        | t        «      r	 t        j                  | «      } t        | t        «      sy | j                  d«      }t        |t        «      r|r|S d S # t        j                  t
        f$ r Y y w xY w)NÚcold_storage_object_key)rî   r>   r#  rP  ÚJSONDecodeErrorrQ  rò   r5  )r  Ú
object_keys     r8   Ú&_cold_storage_object_key_from_metadatarW  ±
  st   € ô �(œCÔ ð	Ü—z‘z (Ó+ˆHô �h¤Ô%ØØ Ÿ™Ð%>Ó?€JÜ# J´Ô4¹ˆ:ÐMÈÐMøô ×$Ñ$¤iÐ0ò 	Ùð	ús   ’A ÁA;Á:A;r9  Úcold_storage_handlerr*   c              ƒ   ó  K  — | j                  d«      }| j                  d«      }| j                  d«      }t        |||«      }t        |«      st        |«      st        |«      r|S t        | j                  d«      «      }|€|S 	 |j	                  |¬«      ƒ d{  –—† }|€|S t        |j                  d«      |j                  d«      |j                  d«      ¬
«      S 7 ŒC# t
        $ r t        j                  d|d¬	«       |cY S w xY w­w)a¢  
    Decide where the prompt/response come from for a single spend-log row.

    PG holds the content when ``store_prompts_in_spend_logs`` is on; otherwise it
    holds ``"{}"`` placeholders and the real payload lives in cold storage keyed
    by ``metadata.cold_storage_object_key``. The choice is made on actual row
    content, not config flags, so historical and mixed-storage rows both resolve
    correctly.
    rÈ  r  rH  r  N)rV  zJFailed to fetch cold storage payload for key %s; falling back to DB valuesT©Úexc_info)rÈ  r  rH  )r5  rG  rN  rW  Ú:get_proxy_server_request_from_cold_storage_with_object_keyrä   r   rº   )r9  rX  rÈ  r  rH  Ú
pg_payloadrV  Úpayloads           r8   Ú!_resolve_request_response_payloadr_  ¿
  s  è ø€ ð —g‘g˜jÓ)€HØ—g‘g˜jÓ)€HØ"%§'¡'Ð*@Ó"AÐä.¨x¸ÐCWÓX€Jä$ XÔ.Ü'¨Ô1Ü'Ð(<Ô=àÐä>¸s¿w¹wÀzÓ?RÓS€JØÐØÐð
Ø3×nÑnØ!ð  oó  
÷ 
ˆð €ØÐä!Ø—‘˜ZÓ(Ø—‘˜ZÓ(Ø$Ÿ[™[Ð)?Ó@ôð ð
ùô ò Ü×$Ñ$ØXØØõ	
ð
 Òðüs<   ‚BD	ÂC  ÂCÂC  Â?D	ÃC  Ã #DÄD	ÄDÄD	z/spend/logs/ui/{request_id}c              ƒ   óÒ  K  — ddl m} t        |¬«      s5|€t        t        j
                  ddi¬«      ‚t        ||| ¬«      ƒ d{  –—†  t        j                  j                  «       }d}d}|�4t        j                  |d	«      j                  t        j                  ¬
«      }|�4t        j                  |d	«      j                  t        j                  ¬
«      }|D ]$  }|j                  | ||¬«      ƒ d{  –—† }	|	€Œ"|	c S  |�Zddlm}
 d}t%        ||| «      ƒ d{  –—† }|r;t'        |«      dkD  r-t)        |d    |
«       ¬«      ƒ d{  –—† }|j+                  «       S y7 �Œ7 Œl7 ŒG7 Œ­w)zâ
    View request / response for a specific request_id

    - goes through all callbacks, checks if any of them have a @property -> has_request_response_payload
    - if so, it will return the request and response payload
    r   r­   r×   Nrß   zmCannot authorize spend log access without a database connection. Connect a database or use a proxy admin key.rà   r  rò  r  )r½   Ústart_time_utcÚend_time_utcr)   zª
            SELECT messages, response, proxy_server_request, metadata
            FROM "LiteLLM_SpendLogs"
            WHERE request_id = $1
            LIMIT 1
        )rX  )rã   r�   rå   r   r   rø   r  r_  Úlogging_callback_managerÚ6get_active_additional_logging_utils_from_custom_loggerr   r+  r,  r   r-  Úget_request_response_payloadÚ1litellm.proxy.spend_tracking.cold_storage_handlerr*   r˜   r¸   r_  Ú_asdict)r½   rþ   rÿ   rÔ   r�   Úcustom_loggersr7  r8  Úcustom_loggerr^  r*   rŽ   Ú	db_resultÚresolveds                 r8   Ú'ui_view_request_response_for_request_idrl  ñ
  sš  è ø€ õ0 9äÐ1BÕCØÐ ÜÜ"×5Ñ5àðSðôð ô /Ø'Ø/Ø!ô
÷ 	
ð 	
ô $×<Ñ<×sÑsÓu€NØ&*€NØ$(€LØÐÜ!×*Ñ*¨:Ð7JÓK×SÑSÔ[c×[gÑ[gÐSÓhˆØÐÜ×(Ñ(¨Ð3FÓG×OÑOÔW_×WcÑWcÐOÓdˆà'ò ˆØ%×BÑBØ!Ø)Ø%ð Có 
÷ 
ˆð
 ÑØŠNðð Ð õ	
ðˆ	ô I[Ø˜9 jóI
÷ C
ˆ	ñ œ˜Y›¨!Ò+Ü>¸yÈ¹|ÑbtÓbvÔw×wˆHØ×#Ñ#Ó%Ð%àð[	
ùð
øð.C
øð xúsO   ‚AE'ÁEÁB.E'Ã4E!Ã5E'Ã<E'ÄE#Ä,E'ÅE%Å	E'Å!E'Å#E'Å%E'z/spend/logszjrequest_id to get spend logs for specific request_id. If none passed then pass spend logs for all requestsTz�When start_date and end_date are provided, summarize=true returns aggregated data by date (legacy behavior), summarize=false returns filtered individual logsÚfastapi_responseÚ	summarizec              ƒ   óÒ
  K  — ddl m} |j                  t        j                  k(  s|j                  t        j
                  k(  r|j                  }	 t        j                  d«       |€t        d«      ‚|��´t        |t        «      �r£|�� t        |t        «      �r�t        j                  |d«      j                  t        j                   ¬«      }	t        j                  |d«      j                  t        j                   ¬«      }
|	j#                  «       }|
j#                  «       }d||d	œi}|�<t        |t        «      r,|j%                  d
«      r|j'                  |¬«      |d<   n||d<   |�t        |t        «      r||d<   |�t        |t        «      r||d<   |s t)        ||ddit*        | ¬«      ƒ d{  –—† }|S t-        |«      j.                  j1                  g d¢|ddi¬«      ƒ d{  –—† }t        |t2        «      �r,t5        |«      dkD  �rt        |d   t6        «      �r	t9        t:        t<           |«      }i }|D �]T  }t        j                  t        |d   «      d«      }|j?                  «       }||vri i dœ||<   |d   }|d   }|d   }||   jA                  dd«      |jA                  di «      jA                  dd«      z   ||   d<   ||   jA                  |d«      |jA                  di «      jA                  dd«      z   ||   |<   ||   d   jA                  |d«      |jA                  di «      jA                  dd«      z   ||   d   |<   ||   d   jA                  |d«      |jA                  di «      jA                  dd«      z   ||   d   |<   �ŒW g }d}tC        |jE                  «       «      D ]  \  }}|jG                  i |¥d|i¥«       |}Œ  |
j?                  «       }|�D||k  r?|tI        d¬«      z   }||k  r+|jG                  |di i dœ«       |tI        d¬«      z  }||k  rŒ+|S |S i }|�;t        |t        «      r+|j%                  d
«      r|j'                  |¬«      }n|}||d<   |�t        |t        «      r||d<   |�t        |t        «      r||d<   t)        ||ddit*        | ¬«      ƒ d{  –—† }|S 7 �Œ7 �ŒÔ7 Œ# t        $ r�}t        |tJ        «      rBtM        tO        |dd|› d �«      d!tO        |d"d#«      tO        |d$tP        jR                  «      ¬%«      ‚t        |tL        «      r|‚tM        d&t        |«      z   d!tO        |d"d#«      tP        jR                  ¬%«      ‚d}~ww xY w­w)'aÏ  
    [DEPRECATED] This endpoint is not paginated and can cause performance issues.
    Please use `/spend/logs/v2` instead for paginated access to spend logs.

    Row results are capped at 10,000 most recent entries per response.

    View all spend logs, if request_id is provided, only logs for that request_id will be returned

    When start_date and end_date are provided:
    - summarize=true (default): Returns aggregated spend data grouped by date (maintains backward compatibility)
    - summarize=false: Returns filtered individual log entries within the date range

    Example Request for all logs
    ```
    curl -X GET "http://0.0.0.0:8000/spend/logs" -H "Authorization: Bearer sk-1234"
    ```

    Example Request for specific request_id
    ```
    curl -X GET "http://0.0.0.0:8000/spend/logs?request_id=chatcmpl-6dcb2540-d3d7-4e49-bb27-291f863f112e" -H "Authorization: Bearer sk-1234"
    ```

    Example Request for specific api_key
    ```
    curl -X GET "http://0.0.0.0:8000/spend/logs?api_key=sk-test-example-key-123" -H "Authorization: Bearer sk-1234"
    ```

    Example Request for specific user_id
    ```
    curl -X GET "http://0.0.0.0:8000/spend/logs?user_id=ishaan@berri.ai" -H "Authorization: Bearer sk-1234"
    ```

    Example Request for date range with individual logs (unsummarized)
    ```
    curl -X GET "http://0.0.0.0:8000/spend/logs?start_date=2024-01-01&end_date=2024-01-02&summarize=false" -H "Authorization: Bearer sk-1234"
    ```
    r   r­   zinside view_spend_logsNrÖ   r  r  r‹   rû  rp  r-   r‰   r½   rB   rÜ  )r›   r³   r´   rµ   )r‰   rB   rŠ   r‹   rY   T)rÈ   r›   Úsumz%Y-%m-%dT%H:%M:%S.%fZ)ró   r&   rŠ   rŒ   ró   r&   rA  r‚  )r‹   rY   ró   r&   râ   z/spend/logs Error(r  r  r  r  rá   r  z/spend/logs Error)*rã   r�   r.  r/  r0  r1  rÞ   r   rq  rä   rî   r>   r   r+  r,  r   r-  r  rv  rw  r¼   r,   r#   r¬   rÉ   rï   r¸   rò   r   r   rˆ   rH   r5  r6  rG  r4  r   r   r  r  r   r  )rm  r‰   rÞ   r½   rþ   rÿ   rn  rÔ   r�   r7  r8  Ústart_date_isoÚend_date_isoÚfilter_queryr£   r  Ú
spend_rowsrú   ÚrecordÚ	dt_objectrH   rŠ   Úreturn_listÚ
final_dateÚkÚvÚend_date_dateÚcurrent_dateÚscoped_filterÚhashed_tokenré   s                                  r8   Úview_spend_logsr  F  sÚ  è ø€ õ\ 9ð 	×#Ñ#Ô'7×'EÑ'EÒEØ×&Ñ&Ô*:×*RÑ*RÒRà#×+Ñ+ˆðN
Ü×"Ñ"Ð#;Ô<ØÐ Üð Tóð ð Ñ"Ü˜:¤sÕ+ØÑ$Ü˜8¤SÕ)ô %-×$5Ñ$5°jÀ*Ó$M×$UÑ$UÔ]e×]iÑ]iÐ$UÓ$jˆNÜ"*×"3Ñ"3°H¸jÓ"I×"QÑ"QÔYa×YeÑYeÐ"QÓ"fˆLð %3×$<Ñ$<Ó$>ˆNØ".×"8Ñ"8Ó":ˆLð Ø)Ø'ñð#ˆLð Ð"¤z°'¼3Ô'?Ø×%Ñ% eÔ,Ø.;×.FÑ.FÈWÐ.FÓ.U�L Ò+à.5�L Ñ+ØÐ%¬*°ZÄÔ*EØ-7�˜\Ñ*ØÐ"¤z°'¼3Ô'?Ø'.�˜VÑ$ñ ä-Ø!Ø&Ø&¨Ð/Ü8Ø"2ô÷ �ð �ô %8¸Ó$F×$LÑ$L×$UÑ$UÚ<Ø"à˜Tðð %Vó %÷ ˆHô ˜(¤DÕ)¬c°(«m¸aÓ.?ÄJÈxÐXYÉ{Ô\`ÕDaÜ$(¬Ô2BÑ)CÀXÓ$N�
Ø&(�Ø(ó �FÜ (× 1Ñ 1´#°f¸[Ñ6IÓ2JÐLcÓ d�IØ$Ÿ>™>Ó+�DØ 6Ñ)Ø13¸rÑ'B˜˜t™Ø$ YÑ/�GØ$ V™n�GØ" 7™O�EØ,2°4©L×,<Ñ,<¸WÀaÓ,HÈ6Ï:É:ÐV\Ð^`ÓKa×KeÑKeÐfmÐopÓKqÑ,q�F˜4‘L Ñ)Ø,2°4©L×,<Ñ,<¸WÀaÓ,HÈ6Ï:É:ÐV\Ð^`ÓKa×KeÑKeÐfmÐopÓKqÑ,q�F˜4‘L Ñ)Ø5;¸D±\À'Ñ5J×5NÑ5NÈwÐXYÓ5ZÐ]c×]gÑ]gÐhnÐprÓ]s×]wÑ]wØ ó^ñ 6�F˜4‘L Ñ)¨'Ñ2ð 5;¸4±LÀÑ4J×4NÑ4NÈuÐVWÓ4XÐ[a×[eÑ[eÐflÐnpÓ[q×[uÑ[uØ ó\ñ 5�F˜4‘L Ñ*¨5Ó1ðð  &(�Ø!�
Ü" 6§<¡<£>Ó2ò #‘D�A�qØ×&Ñ&Ð'<¨!Ð'<¨[¸!Ñ'<Ô=Ø!"‘Jð#ð (4×'8Ñ'8Ó':�ØÐ)¨j¸=Ò.HØ#-´	¸qÔ0AÑ#A�LØ&¨-Ò7à#×*Ñ*à-9Ø)*Ø)+Ø*,ñ	ôð %¬	°qÔ(9Ñ9˜ð '¨-Ó7ð #Ð"àˆOð 46ˆMØÐ"¤z°'¼3Ô'?Ø×%Ñ% eÔ,Ø#0×#;Ñ#;À'Ð#;Ó#J‘Là#*�LØ+7�˜iÑ(ØÐ%¬*°ZÄÔ*EØ.8�˜lÑ+ØÐ"¤z°'¼3Ô'?Ø(/�˜fÑ%ä)ØØ#Ø" FÐ+Ü4Ø.ô÷ ˆDð ˆKðgùðùðBùô ò 
Ü�aœÔ'Ü Ü  8Ð/AÀ!ÀÀAÐ-FÓGØ%Ü˜a ¨&Ó1Ü˜Q ¬v×/TÑ/TÓUô	ð ô ˜œ>Ô*ØˆGÜØ'¬#¨a«&Ñ0Ø!Ü˜!˜W fÓ-Ü×6Ñ6ô	
ð 	
ûð
üsŽ   ‚AU'ÁE R> Æ0R6Æ1R> Æ6U'Æ7.R> Ç%R9Ç&H>R> Ð%R> Ð&U'Ð'R> Ð(U'Ð)BR> Ò/R<Ò0R> Ò5U'Ò6R> Ò9R> Ò<R> Ò>	U$ÓBUÕU$Õ$U'z/global/spend/reset)rÑ   rÒ   c               ƒ   óþ   K  — ddl m}  | €t        dddt        j                  ¬«      ‚t        | «      j                  dd	ii ¬
«      ƒ d{  –—†  t        | «      j                  dd	ii ¬
«      ƒ d{  –—†  dddœS 7 Œ/7 Œ­w)aC  
    ADMIN ONLY / MASTER KEY Only Endpoint

    Globally reset spend for All API Keys and Teams, maintain LiteLLM_SpendLogs

    1. LiteLLM_SpendLogs will maintain the logs on spend, no data gets deleted from there
    2. LiteLLM_VerificationTokens spend will be set = 0
    3. LiteLLM_TeamTable spend will be set = 0

    r   r­   Nrê  r  r  r  rY   r¼  )r£   r›   z3Spend for all API Keys and Teams reset successfullyr  ©r  r   )rã   r�   r  r   r  r²   r¦   r°   r­   s    r8   Úglobal_spend_resetr‚  -  s”   è ø€ õ  9àÐÜØ6Ø!ØÜ×-Ñ-ô	
ð 	
ô $ MÓ
2×
>Ñ
>ÀWÈcÀNÐZ\Ð
>Ó
]×]Ð]Ü
�mÓ
$×
0Ñ
0°wÀ°nÈBÐ
0Ó
O×OÐOð IØñð ð ^øØOús$   ‚AA=Á	A9Á
%A=Á/A;Á0
A=Á;A=z/global/spend/refreshc               ƒ   óP  ‡	K  — ddl mŠ	 ‰	€t        dddt        j                  ¬«      ‚dt
        fˆ	fd	„}  | «       ƒ d{  –—† }|r¨d
}	 ddlm} ddl m} ddl	m
} t        j                  d«      }|€t        |j                  j                  «      ‚ |||ddi¬«      }|j                   j#                  «       ƒ d{  –—†  t%        ||«      ƒ d{  –—†  t'        j(                  d«       dddœS y7 Œ¯7 Œ57 Œ## t        $ r%}t'        j*                  d|«       dddœcY d}~S d}~ww xY w­w)zc
    ADMIN ONLY / MASTER KEY Only Endpoint

    Globally refresh spend MonthlyGlobalSpend view
    r   r­   Nrê  r  r  r  r3   c               “   ór   •K  — d} 	 t        ‰| «      ƒ d{  –—† }|d   d   dk(  S 7 Œ# t        $ r Y yw xY w­w)zM
        Return True if materialized view exists

        Else False
        zy
        SELECT relname, relkind
        FROM pg_class
        WHERE relname = 'MonthlyGlobalSpend';            
        Nr   rl   ÚmF)r”   rä   )rŽ   Úrespr�   s     €r8   Ú!is_materialized_global_spend_viewz?global_spend_refresh.<locals>.is_materialized_global_spend_viewg  sP   øè ø€ ðˆ	ð
	Ü7AÀ-ÐQZÓ7[×1[ˆDà˜‘7˜9Ñ%¨Ñ,Ð,ð 2\ùô ò 	Ùð	üs(   ƒ7‡( –&—( ¥7¦( ¨	4±7³4´7zE
        REFRESH MATERIALIZED VIEW "MonthlyGlobalSpend";    
        )rs  )Úproxy_logging_objr'   ÚDATABASE_URLÚtimeoutip  )Údatabase_urlrˆ  Úhttp_clientz!MonthlyGlobalSpend view refreshedr  r�  z(Failed to refresh materialized view - %sz#Failed to refresh materialized viewÚfailure)rã   r�   r  r   r  ÚboolÚlitellm.proxy._typesrs  rˆ  Úlitellm.proxy.utilsr(   ÚosÚgetenvrä   r  ru  r‘   Úconnectr”   r   Úinfor&  )
r‡  Úview_existsrŽ   rs  rˆ  r(   Údb_urlÚ
new_clientré   r�   s
            @r8   Úglobal_spend_refreshr˜  P  s7  øè ø€ õ 9àÐÜØ6Ø!ØÜ×-Ñ-ô	
ð 	
ð´Tõ ñ$  AÓB×B€Káðˆ	ð	Ý>ÝDÝ8äŸI™I nÓ5ˆFØˆ~ÜÐ 1× HÑ H× NÑ NÓOÐOÙ ,Ø#Ø"3à˜tðô!ˆJð —-‘-×'Ñ'Ó)×)Ð)Ü˜Z¨Ó3×3Ð3Ü ×%Ñ%Ð&IÔJà>Ø#ñð ð/ ð Cøð, *øØ3ùô ò 	Ü ×*Ñ*Ð+UÐWXÔYà@Ø#ñõ ûð	üse   ƒ<D&¿C/Á D&Á	A2C5 Â;C1Â<C5 ÃC3ÃC5 Ã-D&Ã1C5 Ã3C5 Ã5	D#Ã>DÄD#ÄD&ÄD#Ä#D&c              ƒ   óL  K  — ddl m} |€t        dddt        j                  ¬«      ‚	 |j
                  }|€t        d«      ‚| �d}t        ||| |«      ƒ d {  –—† }|S d	}t        |||«      ƒ d {  –—† }|S 7 Œ7 Œ# t        $ r}t        j                  d
|«       |‚d }~ww xY w­w)Nr   r­   rê  r  r  r  z)/global/spend/logs Error: User ID is Nonez§
                SELECT * FROM "MonthlyGlobalSpendPerUserPerKey"
                WHERE "api_key" = $1 AND "user" = $2
                ORDER BY "date";
                zSSELECT * FROM "MonthlyGlobalSpendPerUserPerKey"  WHERE "user" = $1 ORDER BY "date";ú/global/spend/logs Error: %s)rã   r�   r  r   r  rÞ   rr  r”   rä   r   rß   )r‰   rÔ   r�   rÞ   rŽ   r  ré   s          r8   Úglobal_spend_for_internal_userr›  Ÿ  sË   è ø€ õ 9àÐÜØ6Ø!ØÜ×6Ñ6ô	
ð 	
ðØ*×2Ñ2ˆØˆ?ÜÐHÓIÐIØÐðˆIô >HÈÐW`ÐbiÐkrÓ=s×7sˆHàˆOàmˆ	ä# M°9¸gÓF×Fˆàˆð 8tøð Gùô ò Ü×"Ñ"Ð#AÀ1ÔEØˆûðüsX   ‚&B$©.A; ÁA7ÁA; ÁB$ÁA; Á0A9Á1A; Á6B$Á7A; Á9A; Á;	B!ÂBÂB!Â!B$z/global/spend/logszMAPI Key to get global spend (spend per day for last 30d). Admin-only endpointc              ƒ   ól  K  — ddl }ddlm}m} ddlm} 	 |€t        dddt        j                  ¬«      ‚|j                  t        j                  k(  s|j                  t        j                  k(  rt        | |¬	«      ƒ d{  –—† }|S  |«       }|r || ¬
«      ƒ d{  –—† }|S | €d}t        ||«      ƒ d{  –—† }|S d}t        ||| «      ƒ d{  –—† }|S 7 ŒU7 Œ;7 Œ#7 Œ# t        $ rË}	|j!                  «       }
t#        |	«      dz   |
z   }t%        j&                  d|«       t)        |	t*        «      rBt        t-        |	dd|› d�«      dt-        |	dd«      t-        |	dt        j                  «      ¬«      ‚t)        |	t        «      r|	‚t        d|z   dt-        |	dd«      t        j                  ¬«      ‚d}	~	ww xY w­w)zî
    [BETA] This is a beta endpoint. It will change.

    Use this to get global spend (spend per day for last 30d). Admin-only endpoint

    More efficient implementation of /spend/logs, by creating a view over the spend logs table.
    r   N)Úget_daily_spend_from_prometheusÚis_prometheus_connectedr­   rê  r  r  r  )r‰   rÔ   )r‰   z3SELECT * FROM "MonthlyGlobalSpend" ORDER BY "date";z 
                    SELECT * FROM "MonthlyGlobalSpendPerKey"
                    WHERE "api_key" = $1
                    ORDER BY "date";
                    r¯  rš  râ   z/global/spend/logs Error(r  r  rá   z/global/spend/logs Error)r°  Ú6litellm.integrations.prometheus_helpers.prometheus_apir�  rž  rã   r�   r  r   r  r.  r/  r0  r1  r›  r”   rä   r²  r>   r   rß   rî   r   r  )r‰   rÔ   r°  r�  rž  r�   r  Úprometheus_api_enabledrŽ   ré   r³  r´  s               r8   Úglobal_spend_logsr¡  Å  sÅ  è ø€ ó( ÷õ 9ð;
ØÐ Ü Ø:Ø%ØÜ×:Ñ:ô	ð ð ×'Ñ'Ô+;×+IÑ+IÒIØ ×*Ñ*Ô.>×.VÑ.VÒVä;ÀGÐ_pÔq×qˆHàˆOá(?Ó(AÐá!Ù<ÀWÔM×MˆHØˆOàˆØU�	ä!+¨M¸9Ó!E×E�à�ð�	ô ",¨M¸9ÀgÓ!N×N�à�ð3 røð Nøð Føð Oùô ò 
Ø&×1Ñ1Ó3ˆÜ˜q›6 D™=¨;Ñ6ˆ	Ü×"Ñ"Ð#AÀ9ÔMÜ�aœÔ'Ü Ü  8Ð/HÈÈÐSTÐ-UÓVØ%Ü˜a ¨&Ó1Ü˜Q ¬v×/TÑ/TÓUô	ð ô ˜œ>Ô*ØˆGÜØ.°Ñ:Ø!Ü˜!˜W fÓ-Ü×6Ñ6ô	
ð 	
ûð
üs–   ‚F4–A)C Á?CÂ C ÂF4ÂC ÂCÂC Â!F4Â"C Â5CÂ6C Â;F4Â<C ÃCÃC ÃF4ÃC ÃC ÃC ÃC Ã	F1Ã&CF,Æ,F1Æ1F4z/global/spendc               ƒ   óˆ  K  — ddl } ddlm} 	 d}|€t        dddi¬«      ‚d	}t	        ||«      ƒ d{  –—† }|�3t        |t        «      r#t        |«      dkD  r|d   j                  d
d«      }|t        j                  dœS 7 ŒL# t        $ rµ}| j                  «       }t        |«      dz   |z   }t        |t        «      rBt        t        |dd|› d�«      dt        |dd«      t        |dt         j"                  «      ¬«      ‚t        |t        «      r|‚t        d|z   dt        |dd«      t         j"                  ¬«      ‚d}~ww xY w­w)ze
    [BETA] This is a beta endpoint. It will change.

    View total spend across all proxy keys
    r   Nr­   r¼  r  rß   r  rà   z;SELECT SUM(spend) as total_spend FROM "MonthlyGlobalSpend";rb   )rY   Ú
max_budgetr¯  râ   z/global/spend Error(r  r  r  r  rá   r  z/global/spend Error)r°  rã   r�   r   r˜   rî   rï   r¸   r5  r_  r£  rä   r²  r>   r  r  r   r  )r°  r�   rb   rŽ   r  ré   r³  r´  s           r8   Úglobal_spendr¤    sJ  è ø€ ó å8ð
ØˆàÐ Ü¨C¸ÐBSÐ8TÔUÐUØ\ˆ	ÜASÐTaÐclÓAm×;mˆØÐÜ˜(¤DÔ)¬c°(«m¸aÒ.?Ø& q™kŸo™o¨m¸SÓA�à$´G×4FÑ4FÑGÐGð <nùô ò 
Ø&×1Ñ1Ó3ˆÜ˜q›6 D™=¨;Ñ6ˆ	Ü�aœÔ'Ü Ü  8Ð/CÀIÀ;ÈaÐ-PÓQØ%Ü˜a ¨&Ó1Ü˜Q ¬v×/TÑ/TÓUô	ð ô ˜œ>Ô*ØˆGÜØ)¨IÑ5Ø!Ü˜!˜W fÓ-Ü×6Ñ6ô	
ð 	
ûð
üs:   ‚EŽ$B ²A?³AB Á>EÁ?B Â	D?Â
B0D:Ä:D?Ä?ErD  Úlimitc              ƒ   óª   K  — ddl m} |€t        dddi¬«      ‚| j                  }|€t        dddi¬«      ‚d}t	        ||||«      ƒ d {  –—† }|S 7 Œ­w)	Nr   r­   r  rß   r  rà   r  aÃ  
            WITH top_api_keys AS (
            SELECT 
                api_key,
                SUM(spend) as total_spend
            FROM 
                "LiteLLM_SpendLogs"
            WHERE 
                "user" = $1
            GROUP BY 
                api_key
            ORDER BY 
                total_spend DESC
            LIMIT $2  -- Adjust this number to get more or fewer top keys
        )
        SELECT 
            t.api_key,
            t.total_spend,
            v.key_alias,
            v.key_name
        FROM 
            top_api_keys t
        LEFT JOIN 
            "LiteLLM_VerificationToken" v ON t.api_key = v.token
        ORDER BY 
            t.total_spend DESC;
    
    ©rã   r�   r   rÞ   r”   ©rÔ   r¥  r�   rÞ   rŽ   r  s         r8   Úglobal_spend_key_internal_userr©  O  sp   è ø€ Ý8àÐÜ¨°WÐ>OÐ4PÔQÐQà&×.Ñ.€GØ€Ü¨°WÐ>PÐ4QÔRÐRð€Iô: =GÀ}ÐV_ÐahÐjoÓ<p×6p€Hà€Oð 7qúó   ‚AAÁ
AÁAz/global/spend/keysz0Number of keys to get. Will return Top 'n' keys.c           	   ƒ   óÐ  K  — ddl m} |j                  t        j                  k(  s|j                  t        j
                  k(  rt        |¬«      ƒ d{  –—† }|S |€t        dddi¬«      ‚d	}| €t        ||«      ƒ d{  –—† }|S 	 t        | «      } | d
k  rt        d«      ‚d}t        ||| «      ƒ d{  –—† }|S 7 Œf7 Œ=7 Œ
# t        $ r}t        ddd| › d|› �i¬«      |‚d}~ww xY w­w)ú‰
    [BETA] This is a beta endpoint. It will change.

    Use this to get the top 'n' keys with the highest spend, ordered by spend.
    r   r­   r×   Nr  rß   r  rà   z#SELECT * FROM "Last30dKeysBySpend";rA  zLimit must be greater than 0z-SELECT * FROM "Last30dKeysBySpend" LIMIT $1 ;i¦  zInvalid limit: z	, error: )rã   r�   r.  r/  r0  r1  r©  r   r”   rL   rr  )r¥  rÔ   r�   r  rŽ   ré   s         r8   Úglobal_spend_keysr­  {  s
  è ø€ õ$ 9ð 	×#Ñ#Ô'7×'EÑ'EÒEØ×&Ñ&Ô*:×*RÑ*RÒRä7ÐJ[Ô\×\ˆàˆØÐÜ¨°WÐ>OÐ4PÔQÐQØ9€Ià€}Ü# M°9Ó=×=ˆØˆðmÜ�E“
ˆØ�1Š9ÜÐ;Ó<Ð<ØGˆ	Ü# M°9¸eÓD×Dˆð €Oð' ]øð >øð EùÜò mÜ¨°WÀÐPUÈwÐV_Ð`aÐ_bÐ>cÐ4dÔeÐklÐlûðmüsZ   ‚AC&ÁB9Á*C&Á=B;Á>C&Â-B? Â2B=Â3B? Â7C&Â;C&Â=B? Â?	C#ÃCÃC#Ã#C&z/global/spend/teamsc               ƒ   óŽ  K  — ddl m}  | €t        dddi¬«      ‚d}t        | |«      ƒ d{  –—† }i }t	        «       }i }|D ]s  }|d	   }|€Œ|d
   }|€d}|j                  |«       ||v r|d   }	t        |	d«      }	||   }
|	|
|<   n|d   }	t        |	d«      }	||	i||<   ||v r||xx   |	z  cc<   Œo|	||<   Œu g }t        t        |j                  «       d„ d¬«      «      }|D ]-  }t        |«      dk\  r n|€d}|j                  |||   dœ«       Œ/ g }|D ]  }||   }|j                  d|i|¥«       Œ |t        |«      |dœS 7 �Œ­w)z{
    [BETA] This is a beta endpoint. It will change.

    Use this to get daily spend, grouped by `team_id` and `date`
    r   r­   Nr  rß   r  rà   aÔ  
        SELECT
            t.team_alias as team_alias,
            DATE(s."startTime") AS spend_date,
            SUM(s.spend) AS total_spend
        FROM
            "LiteLLM_SpendLogs" s
        LEFT JOIN
            "LiteLLM_TeamTable" t ON s.team_id = t.team_id
        WHERE
            s."startTime" >= CURRENT_DATE - INTERVAL '30 days'
        GROUP BY
            t.team_alias,
            DATE(s."startTime")
        ORDER BY
            spend_date;
        rq   ra   Ú
Unassignedrb   r
  c                 ó   — | d   S ©NrA  r6   )Úitems    r8   r$  z'global_spend_per_team.<locals>.<lambda>ì  s   € ÐVZÐ[\ÑV]€ r:   TrB  rD  )rC   rb   rH   )Údaily_spendr˜  Útotal_spend_per_team)rã   r�   r   r”   ÚsetÚaddÚroundrò   r6  rG  r¸   r4  rï   )r�   rŽ   r  Úspend_by_dateÚteam_aliasesr´  r9  Úrow_datera   rY   Úcurrent_date_entriesÚtotal_spend_per_team_uirC   Úresponse_datarØ   ru  s                   r8   Úglobal_spend_per_teamr¾  ª  sÛ  è ø€ õ 9àÐÜ¨°WÐ>OÐ4PÔQÐQð€Iô" ;EÀ]ÐT]Ó:^×4^€Hð €MÜ›%€LØÐØò 5ˆØ�|Ñ$ˆØÐØØ˜Ñ&ˆ
ØÐØ%ˆJØ×Ñ˜Ô$Ø�}Ñ$ð ˜Ñ&ˆEÜ˜% “OˆEØ#0°Ñ#:Ð Ø/4Ð  Ò,à˜Ñ&ˆEÜ˜% “OˆEØ'1°5Ð&9ˆM˜(Ñ#àÐ-Ñ-Ø  Ó,°Ñ5Ô,à/4Ð  Ò,ð/5ð2 &(Ðä¤Ð';×'AÑ'AÓ'CÑI]ÐgkÔ lÓmÐØ'ò kˆäÐ&Ó'¨2Ò-ÙØˆ?Ø"ˆGØ×&Ñ&°7ÐK_Ð`gÑKhÑ'iÕjðkð €MØò 5ˆØ˜cÑ"ˆØ×Ñ˜f cÐ3¨UÐ3Õ4ð5ð
 %Ü�lÓ#Ø 7ñð ðc 5_ûs   ‚)E«E¬DEz/global/all_end_usersc               ƒ   ó²   K  — ddl m}  | €t        dddi¬«      ‚d}t        | |«      ƒ d{  –—† }|€g S g }|D ]  }|j	                  |d	   «       Œ d
|iS 7 Œ)­w)zn
    [BETA] This is a beta endpoint. It will change.

    Use this to just get all the unique `end_users`
    r   r­   Nr  rß   r  rà   z;
    SELECT DISTINCT end_user FROM "LiteLLM_SpendLogs"
    rt   Ú	end_users)rã   r�   r   r˜   r4  )r�   rŽ   r  Ú
_end_usersr9  s        r8   Úglobal_view_all_end_usersrÂ    sƒ   è ø€ õ 9àÐÜ¨°WÐ>OÐ4PÔQÐQð€Iô >PÐP]Ð_hÓ=i×7i€KØÐØˆ	à€JØò +ˆØ×Ñ˜#˜j™/Õ*ð+ð ˜Ð$Ð$ð 8jús   ‚)A«A¬*Az/global/spend/end_usersr£   c              ƒ   óF  K  — ddl m} |€t        dddi¬«      ‚	 d}d}d}| �$| j                  }| j                  }| j
                  }|xs! t        j                  «       t        d¬	«      z
  }|xs t        j                  «       }d
}t        |||||«      ƒ d{  –—† }|S 7 Œ­w)r¬  r   r­   Nr  rß   r  rà   é   r‚  ag  
SELECT end_user, COUNT(*) AS total_count, SUM(spend) AS total_spend
FROM "LiteLLM_SpendLogs"
WHERE "startTime" >= ($1::timestamptz AT TIME ZONE 'UTC')
  AND "startTime" <  ($2::timestamptz AT TIME ZONE 'UTC')
  AND (
    CASE
      WHEN $3::TEXT IS NULL THEN TRUE
      ELSE api_key = $3
    END
  )
GROUP BY end_user
ORDER BY total_spend DESC
LIMIT 100
    )
rã   r�   r   r‹   rì  r‰   r   Únowr   r”   )r£   r�   r‹   rì  Úselected_api_keyrŽ   r  s          r8   Úglobal_spend_end_usersrÇ  #  s¸   è ø€ õ 9àÐÜ¨°WÐ>OÐ4PÔQÐQðð €IØ€GØÐØÐØ—N‘Nˆ	Ø—,‘,ˆØŸ<™<ÐàÒ@œXŸ\™\›^¬i¸RÔ.@Ñ@€IØÒ'œŸ™›€Gð€Iô =GØ�y )¨WÐ6Fó=÷ 7€Hð €Oð	7ús   ‚BB!ÂBÂB!c              ƒ   óª   K  — ddl m} |€t        dddi¬«      ‚| j                  }|€t        dddi¬«      ‚d}t	        ||||«      ƒ d {  –—† }|S 7 Œ­w)	Nr   r­   r  rß   r  rà   r  a7  
        SELECT 
            model,
            SUM(spend) as total_spend,
            SUM(total_tokens) as total_tokens
        FROM 
            "LiteLLM_SpendLogs"
        WHERE 
            "user" = $1
        GROUP BY 
            model
        ORDER BY 
            total_spend DESC
        LIMIT $2;
    r§  r¨  s         r8   Ú!global_spend_models_internal_userrÉ  X  sp   è ø€ Ý8àÐÜ¨°WÐ>OÐ4PÔQÐQà&×.Ñ.€GØ€Ü¨°WÐ>PÐ4QÔRÐRð€Iô  =GÀ}ÐV_ÐahÐjoÓ<p×6p€Hà€Oð 7qúrª  z/global/spend/modelsz4Number of models to get. Will return Top 'n' models.c              ƒ   ó&  K  — ddl m} |j                  t        j                  k(  s|j                  t        j
                  k(  rt        || ¬«      ƒ d{  –—† }|S |€t        dddi¬«      ‚d	}t        ||t        | «      «      ƒ d{  –—† }|S 7 Œ97 Œ­w)
z‹
    [BETA] This is a beta endpoint. It will change.

    Use this to get the top 'n' models with the highest spend, ordered by spend.
    r   r­   )rÔ   r¥  Nr  rß   r  rà   z/SELECT * FROM "Last30dModelsBySpend" LIMIT $1 ;)
rã   r�   r.  r/  r0  r1  rÉ  r   r”   rL   )r¥  rÔ   r�   r  rŽ   s        r8   Úglobal_spend_modelsrË  w  s•   è ø€ õ$ 9ð 	×#Ñ#Ô'7×'EÑ'EÒEØ×&Ñ&Ô*:×*RÑ*RÒRä:ÐM^ÐfkÔl×lˆØˆàÐÜ¨°WÐ>OÐ4PÔQÐQàL€Iä5?ÀÈyÔZ]Ð^cÓZdÓ5e×/e€Hà€Oð møð 0fús$   ‚ABÁBÁ2BÂBÂBÂBz/provider/budgets)rÒ   Úresponse_modelc               ƒ   ó  K  — ddl m}  	 | €t        dddi¬«      ‚| j                  }|€t	        d«      ‚| j                  «       }|€t	        d	«      ‚i }|j                  «       D ]c  \  }}|j                  |«      ƒ d{  –—† xs d
}|j                  |«      ƒ d{  –—† }t        |j                  |j                  ||¬«      }|||<   Œe t        |¬«      S 7 ŒW7 Œ<# t        $ r&}	t        j                  d|	«       t!        |	«      ‚d}	~	ww xY w­w)aÆ  
    Provider Budget Routing - Get Budget, Spend Details https://docs.litellm.ai/docs/proxy/provider_budget_routing

    Use this endpoint to check current budget, spend and budget reset time for a provider

    Example Request

    ```bash
    curl -X GET http://localhost:4000/provider/budgets     -H "Content-Type: application/json"     -H "Authorization: Bearer sk-1234"
    ```

    Example Response

    ```json
    {
        "providers": {
            "openai": {
                "budget_limit": 1e-12,
                "time_period": "1d",
                "spend": 0.0,
                "budget_reset_at": null
            },
            "azure": {
                "budget_limit": 100.0,
                "time_period": "1d",
                "spend": 0.0,
                "budget_reset_at": null
            },
            "anthropic": {
                "budget_limit": 100.0,
                "time_period": "10d",
                "spend": 0.0,
                "budget_reset_at": null
            },
            "vertex_ai": {
                "budget_limit": 100.0,
                "time_period": "12d",
                "spend": 0.0,
                "budget_reset_at": null
            }
        }
    }
    ```

    r   rÄ  Nr  rß   zNo llm_router foundrà   z—No provider budget config found. Please set a provider budget config in the router settings. https://docs.litellm.ai/docs/proxy/provider_budget_routingzNo router budget logger foundr¼  )Úbudget_limitÚtime_periodrY   Úbudget_reset_at)Ú	providersz)/provider/budgets: Exception occured - %s)rã   rW  r   Úprovider_budget_configrr  Ú%_get_router_deployment_budget_limiterrG  Ú_get_current_provider_spendÚ%_get_current_provider_budget_reset_atr   r£  Úbudget_durationr   rä   r   r&  r!   )
rW  rÒ  Úrouter_budget_loggerÚprovider_budget_response_dictrd  Ú_budget_infoÚ_provider_spendÚ_provider_budget_ttlÚprovider_budget_response_objectré   s
             r8   Úprovider_budgetsrÝ  œ  s=  è ø€ õj 6ð+ØÐÜ¨C¸ÐBWÐ8XÔYÐYà(2×(IÑ(IÐØ!Ð)Üð jóð ð '1×&VÑ&VÓ&XÐØÐ'ÜÐ<Ó=Ð=àXZÐ%Ø'=×'CÑ'CÓ'Eò 		WÑ#ˆI�|Ø$8×$TÑ$TÐU^Ó$_×_ÒfÐcfˆOØ)=×)cÑ)cÐdmÓ)n×#nÐ Ü.JØ)×4Ñ4Ø(×8Ñ8Ø%Ø 4ô	/Ð+ð 8WÐ)¨)Ò4ð		Wô &Ð0MÔNÐNð `øØ#nùô ò +Ü×&Ñ&Ð'RÐTUÔVÜ'¨Ó*Ð*ûð+üsM   ‚DŠA3C Á=CÁ>C ÂCÂ9C ÃDÃC ÃC Ã	DÃ"!DÄDÄDc              ƒ   ó:   K  — t        | d«      ƒ d {  –—† }|S 7 Œ­w)Nzî
        SELECT
        jsonb_array_elements_text(request_tags) AS individual_request_tag,
        COUNT(*) AS log_count,
        SUM(spend) AS total_spend
        FROM "LiteLLM_SpendLogs"
        GROUP BY individual_request_tag;
        r—   )r�   rþ   rÿ   r  s       r8   r  r  ò  s)   è ø€ Ü<FØð	ó
=÷ 
7€Hð €Oð
7ús   ‚’“r®  c              ƒ   ó¤  K  — d}|�t        |«      dkD  r|j                  d«      }|€t        dddi¬«      ‚d}|�t        |t        «      rd|v rd	}t        ||| |«      ƒ d{  –—† }nd
}t        ||| ||«      ƒ d{  –—† }t        j                  t        «      }t        j                  t        «      }|D ])  }	|	d   }
|	d   }||
xx   |z  cc<   ||
xx   |	d   z  cc<   Œ+ t        |j                  «       d„ d¬«      }g }|D ]C  }|d   }|�t        |t        «      rt        |d«      }|j                  |d   |||d      dœ«       ŒE d|iS 7 Œé7 ŒÑ­w)zœ
    Should cover 2 cases:
    1. When user is getting spend for all_tags. "all_tags" in tags_list
    2. When user is getting spend for specific tags.
    Nr   ú,r  rß   r  rà   zall-tagsa  
        SELECT
            individual_request_tag,
            spend_date,
            log_count,
            total_spend
        FROM "DailyTagSpend"
        WHERE spend_date >= $1::date AND spend_date <= $2::date
        ORDER BY total_spend DESC;
        ap  
        SELECT
            individual_request_tag,
            SUM(log_count) AS log_count,
            SUM(total_spend) AS total_spend
        FROM "DailyTagSpend"
        WHERE spend_date >= $1::date AND spend_date <= $2::date
          AND individual_request_tag = ANY($3::text[])
        GROUP BY individual_request_tag
        ORDER BY total_spend DESC;
        r^   rb   rw   c                 ó   — | d   S r±  r6   r"  s    r8   r$  z&ui_get_spend_by_tags.<locals>.<lambda>L  s
   € È1ÈQÉ4€ r:   TrB  rA  r  )ÚnamerY   rw   r·  )r¸   Úsplitr   rî   rï   r”   r]  rV  r[   rL   r6  rG  r·  r4  )rþ   rÿ   r�   r®  Ú	tags_listr  rŽ   Útotal_spend_per_tagÚtotal_requests_per_tagr9  Útag_nameÚ	tag_spendÚsorted_tagsÚui_tagsÚtagÚcurrent_spends                   r8   r±  r±    s®  è ø€ ð #'€IØÐ¤ H£°Ò 1Ø—N‘N 3Ó'ˆ	àÐÜ¨°WÐ>OÐ4PÔQÐQà37€HØÐœZ¨	´4Ô8¸ZÈ9Ñ=Tð	ˆ	ô $ØØØØó	
÷ 
‰ð
ˆ	ô $ØØØØØó
÷ 
ˆô ;F×:QÑ:QÔRWÓ:XÐÜ=H×=TÑ=TÔUXÓ=YÐØò =ˆØÐ/Ñ0ˆØ˜Ñ&ˆ	à˜HÓ%¨Ñ2Ó%Ø˜xÓ(¨C°Ñ,<Ñ<Ô(ð=ô  Ð 3× 9Ñ 9Ó ;ÁÐY]Ô^€Kà€GØò 

ˆØ˜A™ˆØÐ$¬°MÄ5Ô)IÜ! -°Ó3ˆMØ�‰à˜A™Ø&Ø3°C¸±FÑ;ñõ	
ð	

ð ˜WÐ%Ð%ðm
øð&
ús%   ‚A EÁ"EÁ#EÁ<EÁ=CEÅEz/spend/logs/session/uiz+Get all spend logs for a particular session)rõ   rÙ  rö   éd   )rõ   rÙ  rÛ  rö   c              ƒ   óÀ  K  — ddl m} 	 |€t        t        j                  d¬«      ‚t        |¬«      r	d}d}d	| i}nl	 t        |¬«      rt        ||¬
«      ƒ d{  –—† ng }|r(d}|j                  |f}| d|j                  idd|iigdœ}nd}|j                  f}| |j                  dœ}|dz
  |z  }	t        ||«      ƒ d{  –—† }
d|› d�}t        ||| ||	g|¢­Ž ƒ d{  –—† }t        |«       |
|z   dz
  |z  }||
|||dœS 7 Œ¦# t        $ r g }Y Œ¯w xY w7 ŒS7 Œ7# t        $ r;}t        |t        «      r|‚t        t        j                  t        |«      ¬«      ‚d}~ww xY w­w)zü
    Get paginated spend logs for a particular session.

    Returns:
        {
            "data": List[LiteLLM_SpendLogs],
            "total": int,
            "page": int,
            "page_size": int,
            "total_pages": int,
        }
    r   r­   NzDatabase not connectedrà   r×   r  r6   rz   r  z/ AND ("user" = $4 OR team_id = ANY($5::text[]))rB   rC   rÇ   )rz   r	  z AND "user" = $4)rz   rB   rA  a4  
            SELECT
                request_id, call_type, api_key, spend, total_tokens,
                prompt_tokens, completion_tokens, "startTime", "endTime",
                "completionStartTime", model, model_id, model_group,
                custom_llm_provider, api_base, "user", metadata,
                cache_hit, cache_key, request_tags, team_id,
                organization_id, end_user, requester_ip_address,
                session_id, status, mcp_namespaced_tool_name, agent_id
            FROM "LiteLLM_SpendLogs"
            WHERE session_id = $1zN
            ORDER BY "startTime" DESC
            LIMIT $2 OFFSET $3
        )r£   r†   rß  rà  rD  )rã   r�   r   r   r  rå   r  Ú&_get_permitted_team_ids_for_spend_logsrä   rÞ   rÄ   r”   r"  rî   r>   )rz   rß  rà  rÔ   r�   Ú	scope_sqlÚscope_paramsr*  r/  r2  rC  rŽ   rú   rD  ré   s                  r8   Úui_view_session_spend_logsrò  ^  só  è ø€ õL 9ðPØÐ ÜÜ"×AÑAØ/ôð ô
 Ð1BÕCØˆIØˆLØ ,¨jÐ9Ñð
(ô 0ÐBSÕTô	 AØ&3Ø*;ô÷ ð ð
 ð #ñ "ØM�	Ø 1× 9Ñ 9Ð;MÐN�à",àÐ!2×!:Ñ!:Ð;Ø" TÐ+=Ð$>Ð?ðñ$Ñ ð /�	Ø 1× 9Ñ 9Ð;�Ø2<ÐFW×F_ÑF_Ñ#`Ð ð ˜a‘x 9Ñ,ˆô &7°}ÐFVÓ%W×Wˆð
 "ð #, ð -	ðˆ	ô ?IØ˜9 j°)¸Tð?
ØDPò?
÷ 9
ˆô 	$ FÔ+à+¨iÑ7¸!Ñ;À	ÑIˆð Ø"ØØ"Ø&ñ
ð 	
ðiùô ò (Ø%'Ò"ð(úð*  Xøð"9
ùô ò Ü�aœÔ'ØˆGäÜ"×AÑAÜ˜1“vôð ûð	üs|   ‚EŠ2D ½D ÁD ÁD Á AD Â?DÃ D ÃDÃ!D Ã?EÄ D ÄDÄD ÄDÄD ÄD Ä	EÄ 6EÅEÅEr(   rC  rD  r  r  c              ƒ   óÎ  K  — i }|rµt        |D �	ch c]_  }	t        |	t        «      r|	j                  d«      r<nt	        |	dd«      r.t        |	t        «      r|	j                  d«      nt	        |	dd«      ’Œa c}	«      }
|
r?t        | |
«      ƒ d{  –—† }|D �ci c]   }|j                  d«      sŒ|d   |d   d   “Œ" }}i }|�r-
�r*ddlm} 	 t        |D �	ch c]_  }	t        |	t        «      r|	j                  d«      r<nt	        |	dd«      r.t        |	t        «      r|	j                  d«      nt	        |	dd«      ’Œa c}	«      }t        | d|
|«      ƒ d{  –—† }|D �	ci c]Ž  }	|	j                  d«      r{|	d   t        |	j                  d«      xs d	«      t        |	j                  d
«      xs d«      t        |	j                  d«      xs d	«      t        |	j                  d«      xs d«      dœ“Œ� }}	|r®g }|D ]¤  }	t        |	t        «      rt        |	«      n|	j                  «       }|j                  d«      }|r|j                  |d«      nd|d<   |r|j                  |«      nd}|r%|d   |d<   |d
   r|d
   |d
<   |d   |d<   |d   |d<   |j                  |«       Œ¦ |}n|}||||||dœS c c}	w 7 �Œ"c c}w c c}	w 7 �Œkc c}	w # |$ r t        j                  dd¬«       Y Œów xY w­w)a‚  
    Build the paginated response for the UI spend-logs endpoint.

    When ``enrich_session_counts`` is ``True`` (the default for the v1/UI
    endpoint), each row is enriched with ``session_total_count`` so the
    frontend knows which sessions are expandable (multi-call sessions).
    For every row that carries a ``session_id``, a single ``GROUP BY`` query
    fetches the total number of logs in each referenced session.  Rows without
    a ``session_id`` default to ``1``.

    When ``enrich_session_counts`` is ``False`` (v2 endpoint), rows are
    serialised without the extra query.

    Args:
        prisma_client: The connected Prisma client instance.
        data: A list of Prisma model instances (must support ``.model_dump()``
              and have a ``session_id`` attribute).
        total_records: Total number of matching records (for pagination).
        page: Current page number.
        page_size: Number of items per page.
        total_pages: Total number of pages.
        enrich_session_counts: Whether to add ``session_total_count`` to each
            row.  Defaults to ``True``.
        total_is_capped: Whether ``total_records`` was clamped to the
            pagination count cap (there are more matching rows than the cap).

    Returns:
        A dict with ``data`` (enriched rows), ``total``, ``page``,
        ``page_size``, ``total_pages``, and ``total_is_capped``.
    rz   Nr}   r   )ÚPrismaErrorr‰   a$  
                SELECT session_id,
                       COALESCE(SUM(spend), 0)::double precision AS session_total_spend,
                       COUNT(*) FILTER (
                           WHERE call_type IN ('call_mcp_tool', 'list_mcp_tools')
                       )::int AS mcp_tool_call_count,
                       COALESCE(SUM(spend) FILTER (
                           WHERE call_type IN ('call_mcp_tool', 'list_mcp_tools')
                       ), 0)::double precision AS mcp_tool_call_spend,
                       COUNT(*) FILTER (WHERE LOWER(cache_hit) = 'true')::int AS session_cache_hit_count
                FROM "LiteLLM_SpendLogs"
                WHERE session_id = ANY($1::text[])
                  AND api_key = ANY($2::text[])
                GROUP BY session_id
                r€   r¼  r�   r‚   rƒ   )r€   r�   r‚   rƒ   z;Failed to enrich session spend aggregates for spend logs UITrZ  rA  Úsession_total_count)r£   r†   rß  rà  rD  r  )rï   rî   rò   r5  r  rÊ   Úprisma.errorsrô  r”   r[   rL   r   rq  r9   r4  )r�   r£   rC  rß  rà  rD  r  r  Ú	count_mapr9  rÅ   ÚcountsÚrÚsession_spend_maprô  Úauthorized_api_keysr»   ÚenrichedÚrow_dictÚsidÚsession_statsr½  s                         r8   r%  r%  Ù  s=  è ø€ ðP !#€IÙÜ37ð  öàÜ-7¸¼TÔ-B�C—G‘G˜LÕ)ÌÐPSÐUaÐcgÔHhô +5°S¼$Ô*?�—‘˜Ô&ÄWÈSÐR^Ð`dÓEeÑeòó4
ˆñ ô
 #:¸-ÈÓ"U×UˆFØMSÖkÈÐWX×W\ÑW\Ð]iÕWj˜˜<™¨!¨H©+°lÑ*CÑCÐkˆIÐkà;=ÐÚ¢Ý-ð-	ô @Dð  $öàÜ.8¸¼dÔ.C˜Ÿ™ 	Õ*ÌÐQTÐV_ÐaeÔIfô ,6°c¼4Ô+@�S—W‘W˜YÔ'ÄgÈcÐS\Ð^bÓFcÑcòó@Ðô =GØðð Ø#ó%=÷ 7ˆDð6  ö	!ð Ø—7‘7˜<Ô(ð �LÑ!Ü+0°·±Ð9NÓ1OÒ1VÐSVÓ+WÜ+.¨s¯w©wÐ7LÓ/MÒ/RÐQRÓ+SÜ+0°·±Ð9NÓ1OÒ1VÐSVÓ+WÜ/2°3·7±7Ð;TÓ3UÒ3ZÐYZÓ/[ñ	$ñ ð	!Ðð 	!ñ  Ø&(ˆØò 	&ˆCÜ$.¨s´DÔ$9”t˜C”y¸s¿~¹~Ó?OˆHØ—,‘,˜|Ó,ˆCÙGJ¨i¯m©m¸CÀÔ.CÐPQˆHÐ*Ñ+Ù:=Ð-×1Ñ1°#Ô6À4ˆMÙØ2?Ð@UÑ2V�Ð.Ñ/Ø Ð!6Ò7Ø6CÐDYÑ6Z�HÐ2Ñ3Ø6CÐDYÑ6Z�HÐ2Ñ3Ø6CÐD]Ñ6^�Ð2Ñ3Ø�O‰O˜HÕ%ð	&ð '‰ð
 ˆð ØØØØ"Ø*ñð ùòmð VûÚkùòð7ûò(	!øð ò 	Ü ×&Ñ&ØMØ÷ð	üsŒ   ‚K%�A$J)Á4K%ÂJ.ÂK%ÂJ1Â,J1Â:K%Ã	K ÃA$J6Ä8K ÅJ;ÅK ÅBJ>Ç,K Ç.CK%Ê1K%Ê6K Ê>K ËK"ËK%Ë!K"Ë"K%c                 ó8   — | €i S | dk(  rddddiiddigiS dd| iiS )a  
    Helper function to build the status filter condition for database queries.

    Args:
        status_filter (Optional[str]): The status to filter by. Can be "success" or "failure".

    Returns:
        Mapping[str, object]: A mapping containing the status filter condition.
    Nr  r	  r   r  r6   )rá  s    r8   r  r  d  sF   € ð ÐØˆ	à˜	Ò!Ø˜ 8¨YÐ"7Ð8¸8ÀTÐ:JÐKÐLÐLà˜8 ]Ð3Ð4Ð4r:   c                 ó†   — 	 t        | dd«      }|€y|t        j                  t        j                  fv S # t        $ r Y yw xY w)zr
    Safely determine if the current user has admin view permissions.
    Defaults to False on any exception.
    r.  NF)r  r/  ÚPROXY_ADMINÚPROXY_ADMIN_VIEW_ONLYrä   )rÔ   r.  s     r8   rå   rå   w  sW   € ð
	Ü"Ð#4°kÀ4ÓHˆ	ØÐØØÜ×(Ñ(Ü×2Ñ2ð
ð 
ð 	
øô ò Ùðús   ‚4 ’!4 ´	A ¿A c              ƒ   óô   K  — ddl m}m} |€yt        | |«      ƒ d{  –—† }|€yt        j                  |j                  «       «      } |||¬«      ry |||t        j                  j                  ¬«      S 7 ŒX­w)zÐ
    Check if the requesting user can view spend logs for the given team.
    Returns True if the team exists and the user is either a team admin or
    a team member with the ``/spend/logs`` permission.
    r   ©Ú_is_user_team_adminÚ_team_member_has_permissionNF©rÔ   Úteam_objT©rÔ   r	  Ú
permission)
Ú/litellm.proxy.management_endpoints.common_utilsr  r  rÌ   ÚLiteLLM_TeamTableÚmodel_validater9   ÚKeyManagementRoutesÚ
SPEND_LOGSru  )r�   rÔ   rC   r  r  Úteam_rowr	  s          r8   r   r   ˆ  s|   è ø€ ÷ð
 €ØÜ*¨=¸'ÓB×B€HØÐØÜ'×6Ñ6°x×7JÑ7JÓ7LÓM€HÙÐ->ÈÕRØÙ&Ø+ØÜ&×1Ñ1×7Ñ7ôð ð Cús   ‚A8�A6žAA8c                 ó‚   — | j                   }| j                  }|t        j                  t        j                  fv xr |duS )zE
    Check if the requesting user can view their own spend logs.
    N)r.  rÞ   r/  r0  r1  )rÔ   r.  rÞ   s      r8   r  r  ¦  sM   € ð )×2Ñ2€IØ&×.Ñ.€Gàä×*Ñ*Ü×4Ñ4ð
ð	
ò 	 ð
 ˜4Ððr:   c              ƒ   ó*  K  — t        | |«      ƒ d{  –—† }|€y|j                  �|j                  |j                  k(  ry|j                  r#t	        | ||j                  ¬«      ƒ d{  –—† }|ryt        t        j                  dd|› �i¬«      ‚7 Œ|7 Œ)­w)zö
    Verify the requesting non-admin user is allowed to view this spend-log row.
    Allowed when the log belongs to the user directly, or to one of their
    permitted teams (admin or ``/spend/logs`` permission).
    Raises HTTP 403 if not.
    Nr  rß   z0Not authorized to view spend log for request_id=rà   )rÀ   rB   rÞ   rC   r   r   r   rø   )r�   rÔ   r½   r9  Úcan_views        r8   r  r  ¶  s›   è ø€ ô +¨=¸*ÓE×E€CØ
€{Øà
‡x�xÐ §¡Ð,=×,EÑ,EÒ EØà
‡{‚{Ü 9Ø'Ø/Ø—K‘Kô!
÷ 
ˆñ
 Øä
Ü×-Ñ-ØÐKÈJÈ<ÐXÐYôð ð! Føð
ús"   ‚B’B“ABÁ'BÁ((BÂBc              ƒ   óÆ  K  — ddl m} ddlm}m} ddlm}m}  ||j                  | |d|¬«      ƒ d{  –—† }|�|j                  sg S t        | |j                  «      ƒ d{  –—† }g }	|D ]n  }
t        j                  |
j                  «       «      } |||¬«      s$ |||t        j                  j                   ¬	«      sŒT|	j#                  |j$                  «       Œp |	S 7 Œ©7 Œ}­w)
z–
    Return team IDs where the user is either a team admin or has the
    ``/spend/logs`` permission, allowing them to view team-wide spend logs.
    r   )Úget_user_objectr  )rˆ  Úuser_api_key_cacheF)rÞ   r�   r  Úuser_id_upsertrˆ  Nr  r
  )Úlitellm.proxy.auth.auth_checksr  r  r  r  rã   rˆ  r  rÞ   r˜  rÏ   r  r  r9   r  r  ru  r4  rC   )r�   rÔ   r  r  r  rˆ  r  Úuser_objÚ	team_rowsÚ	permittedr  r	  s               r8   rï  rï  ×  sà   è ø€ õ ?÷÷ Qá+Ø!×)Ñ)Ø#Ø-ØØ+ô÷ €Hð Ð˜xŸ~š~Øˆ	ä,¨]¸H¿N¹NÓK×K€Ià"$€IØò /ˆÜ$×3Ñ3°H×4GÑ4GÓ4IÓJˆÙÐ1BÈXÕVÑZuØ/ØÜ*×5Ñ5×;Ñ;ö[
ð
 ×Ñ˜X×-Ñ-Õ.ð/ð Ðð+øð Lús(   ‚1C!³C´-C!Á!CÁ"AC!Â> C!ÃC!c              ƒ   ój   K  — 	 t        t        | |¬«      ƒ d{  –—† «      S 7 Œ# t        $ r Y yw xY w­w)zJResolve permitted teams once, falling back to the caller's own-user scope.r  Nr6   )r–  rï  rä   r  s     r8   r  r  ÿ  sC   è ø€ ð
ÜÜ8Ø+Ø"3ô÷ ó
ð 	
ðùô
 ò Ùðüs(   ‚3„$ ™"š$ ¡3¢$ ¤	0­3¯0°3)r3   N)NNN)rD  r5   )NN)TF)°r]  r#  r‘  Úcollections.abcr   r   r   r   r   Útypingr   r	   r
   r   r   r   r   r   r   r   Úfastapir   r   r   r   r   r   Útyping_extensionsr   r_  Úlitellm._loggingr   Úlitellm.constantsr   r�  r   r   Ú$litellm.proxy.auth.user_api_key_authr   Ú1litellm.proxy.spend_tracking.spend_tracking_utilsr   r    r�  r!   Ú%litellm.repositories.prisma_protocolsr"   Ú'litellm.repositories.table_repositoriesr#   Ú$litellm.repositories.team_repositoryr$   Ú2litellm.repositories.verification_token_repositoryr%   Úprismar&   Úprisma_modelsrã   r(   rf  r*   r+   rE   r,   rw  r/   r0   r2   rA   rG   rN   rQ   rU   rW   r]   r`   rd   rf   rj   rn   rp   rs   rv   ry   r|   r   r…   rˆ   r>   r?   r”   r˜   rš   r©   r®   r°   r²   rL   r¼   rÀ   rÄ   rÊ   rÌ   rÏ   r5  ÚUserAPIKeyAuthrê   rô   ÚQueryrû   rï   ÚLiteLLM_SpendLogsr  r  r<  r>  rK  rQ  rT  rg  rx  Ú	frozensetr{  r„  r}  r¦  r€  r–  r†  rŒ  r™  r�  r   r¤  r§  r«  rµ  r¸  ÚpostÚSpendCalculateRequestr×  rò   r[   rŽ  rE  rG  rL  rN  r"  rW  r_  rl  r  r‚  r˜  r›  r¡  r¤  r©  r­  r¾  rÂ  ÚGlobalEndUsersSpendrÇ  rÉ  rË  rÝ  r  r±  rò  r%  r  rå   r   r  r  rï  r  r6   r:   r8   ú<module>r3     sL  ðä Û Û 	ß -ß 2Ñ 2÷÷ ÷ ó ß P× PÝ &ã Ý 1Ý JÜ "ß UÝ B÷
õ :Ý >Ý GÝ ?õñ Ý.å7ÞTà€Lá“€ˆÓ à).Ð  Ó .ð 1ÙÐAÔBð*Ð  ó ñ
 	�Ó€ô6˜ô 6ô˜Hô ô
�9ô ô˜	ô ô#˜yô #ô#�Yô #ô
�yô ô
 �)ô  ô�Iô ô
�9ô ô
˜ô ô�)ô ô
�Yô ô˜ô ô�)ô ô˜	ô ô˜Yô ô#�yô #ô
+�yô +ô˜¨%õ ô'�yô 'ð> Lð >¸Sð >Èð >ÐT\Ð]bÑTcó >ð
=¨Lð =ÀSð =ÐQWð =Ð\dÐejÑ\kÐnrÑ\ró =ô
g�ô gôg˜hô gð4 \ð 4°lÐCdÑ6eó 4ð/˜|ð /°
ó /ð<¨\ð <Ð>Uó <ðØðà�3˜�;Ñðð �3˜�8Ñðð ð	ð
 ðð Ð Ñ!óð$¨\ð Àsð ÐOdÐgkÑOkó ðE¨<ð EÀÈÈVÈÑ@Tð EÐY\ó Eð
	2Øð	2Ø.6°s¸T±zÑ.Bð	2àÐÑó	2ðT¨ð T¸sð TÐGYÐ\`ÑG`ó Tð
[¨ð [ÀÈ#Áð [ÐS[Ð\nÑSoó [ð
 ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó ñ )0Ð0AÓ(Bñ,
Ø%ò,
óð,
ô^'ð ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó ð (˜'Ÿ-™-ØØ4ôñ )0Ð0AÓ(BñB
Ø�4‰ZðB
ð
 &òB
óðB
ðJ ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-àˆg�tÐ-Ñ.Ð/ðð	 ó ð +˜WŸ]™]ØØ@ôð )˜7Ÿ=™=ØØ7ôñ=
Ø�d‘
ð=
ð
 �D‰jò=
óð=
ð@Ø%ðØ3;ðØGOóð< ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-àˆg�tÐ-Ñ.Ð/ðð ð ó ð +˜WŸ]™]ØØ<ôð )˜7Ÿ=™=ØØ3ôñ )0Ð0AÓ(Bñc
Ø�d‘
ðc
ð
 �D‰jðc
ð &òc
óðc
ðLØ%ðØ3;ðØGOóð> ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-àˆg�tÐ-Ñ.Ð/ðð ð ó ð +˜WŸ]™]ØØ<ôð )˜7Ÿ=™=ØØ3ôñ )0Ð0AÓ(BñL
Ø�d‘
ðL
ð
 �D‰jðL
ð &òL
óðL
ð^ ‡�Ø,Ø
#Ð	$ÙÐ+Ó,Ð-àˆg�tÐ-Ñ.Ð/ðð ð ó ð %�w—}‘}Ø+ôð +˜WŸ]™]ØØ<ôð )˜7Ÿ=™=ØØ3ôñG
ØðG
ð �d‘
ð	G
ð �D‰jòG
óðG
ðT ‡�Ø!Ø
#Ð	$ÙÐ+Ó,Ð-àˆg�tÐ-Ñ.Ð/ðð ð ó ð %�w—}‘}Ø+ôð +˜WŸ]™]ØØ<ôð )˜7Ÿ=™=ØØ3ôñ`
Øð`
ð �d‘
ð	`
ð �D‰jò`
óð`
ðF ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-Øàˆg�tÐ-Ñ.Ð/ðð ó ð +˜WŸ]™]ØØ<ôð )˜7Ÿ=™=ØØ3ôñ )0Ð0AÓ(Bñu
Ø�d‘
ðu
ð
 �D‰jðu
ð &òu
óðu
ðp ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-àˆg�tÐ-Ñ.Ð/ðð	 ó ð +˜WŸ]™]ØØ<ôð )˜7Ÿ=™=ØØ3ôð ?L¸g¿m¹mØØIô?ð (˜'Ÿ-™-ØØQôð $1 7§=¡=ØØ`ô$ð (˜'Ÿ-™-ØØNôð ,˜gŸm™mØð Iôñ3Y
Ø�d‘
ðY
ð
 �D‰jðY
ð Ð3Ñ4°tÑ;ðY
ð �4‰ZðY
ð" ˜D‘jð#Y
ð* �4‰Zð+Y
ð2 �t‘ò3Y
óðY
ñx (Ò(FÓGÐ à"Ð ð,¨3ð ,°3ó ,ð^,Ð ð^˜|ó ð ¨s°T©zð ÀSÈ4ÁZð ÐTYÐZbÐdlÐZlÑTmó ð<Ø%ðà�T‰zðð ˜‘*ðð ð	ð
 	óð6=Ø%ð=à˜4‘Zð=ð  ð=ð ˆ3��c˜3�h‘ÐÑ ó	=ð6 ‡�ØØ	%ð ó ð 	Øosð 	ò$Ø  ±Ð9JÓ1KÐ!KÑLð$àØˆd‰
�M�G—M‘MÐ.cÔdÐdñð$ð
 ˜˜d™
 M G§M¡MÐ>jÔ$kÐkÑlð$ð Øˆd‰
Øˆ�‰Øyô	
ð	ñð$ð ˆg�c˜6�kÑ"Ñ#ò$ó	ð$ðN ‡�ØØ	%ð ó ð 	Øosð 	ò#Ø  ±Ð9JÓ1KÐ!KÑLð#àØˆd‰
�M�G—M‘MÐ.cÔdÐdñð#ð
 ˜˜d™
 M G§M¡MÐ>jÔ$kÐkÑlð#ð  Øˆd‰
Øˆ�‰ð Gô	
ð	ñð#ð ˆg�c˜6�kÑ"Ñ#ò#ó	ð#ðL ‡�ØØ	%ð ó ð 	Øosð 	ò#Ø  ±Ð9JÓ1KÐ!KÑLð#àØˆd‰
�M�G—M‘MÐ.cÔdÐdñð#ð
 ˜˜d™
 M G§M¡MÐ>jÔ$kÐkÑlð#ð Øˆd‰
Øˆ�‰Ø|ô	
ð	ñð#ð ˆg�c˜6�kÑ"Ñ#ò#ó	ð#ðL ‡�Ø Ø	%ð ó ð 	Øosð 	ò$Ø  ±Ð9JÓ1KÐ!KÑLð$àØˆd‰
�M�G—M‘MÐ.cÔdÐdñð$ð
 ˜˜d™
 M G§M¡MÐ>jÔ$kÐkÑlð$ð Øˆd‰
Øˆ�‰ð eô	
ð	ñð$ð ˆg�c˜6�kÑ"Ñ#ò$ó	ð$ðN ‡�Ø!Ø
#Ð	$ÙÐ+Ó,Ð-Øàˆg�tÐ-Ñ.Ð/ðð ó ñ(
óð(
ðV ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-àˆg�tÐ-Ñ.Ð/ðð	 ó ð +˜WŸ]™]ØØ@ôð )˜7Ÿ=™=ØØ7ôð %�w—}‘}ØØ8ôñG
Ø�d‘
ðG
ð
 �D‰jðG
ð �‰*òG
óðG
ðT;RØð;Ràó;Rð| ‡‚ØØ
#Ð	$ÙÐ+Ó,Ð-àØ0à"ØØ (à"Ø(0Ø/DØ+.ñ%ð'ñ	ð%ðñ
ðð	 ó ð0A
Ð#8ò A
ó1ð0A
ðH ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-àˆg�t˜C ˜H‘~Ð&ðð	 ó ð ‡�ØØ
#Ð	$ÙÐ+Ó,Ð-Øàˆg�tÐ-Ñ.Ð/ðð ó ð (˜'Ÿ-™-ØØ5ôð (˜'Ÿ-™-ØØ5ôð +˜WŸ]™]ØØJôð +˜WŸ]™]ØØLôð (˜'Ÿ-™-ØØ2ôð ,˜gŸm™mØØPôð ,˜gŸm™mØØMôð +˜WŸ]™]ØØ@ôð )˜7Ÿ=™=ØØ7ôð �—‘ aÐ5QÐVWÔXØ"�W—]‘]¨2Ð;UÐZ[Ð`dÔeÙ(/Ð0AÓ(BØ - §¡ØÐ"Rô!ð $1 7§=¡=ØØ|ô$ð &˜Ÿ™¨dÐ@VÔWØ(˜7Ÿ=™=ØØKôð ,˜gŸm™m°DÐFbÔcØ)˜GŸM™M°$ÐD^Ô_Ø(˜7Ÿ=™=°ÐC\Ô]Ø*˜WŸ]™]°4ÐEuÔvØ - §¡ØÐ"Wô!ð !�7—=‘=ØØyôð +˜WŸ]™]ØØ-ôð ,9¨7¯=©=ØØQô,ñI`+Øð`+à�4‰Zð`+ð �4‰Zð`+ð �d‘
ð`+ð �d‘
ð`+ð$ �4‰Zð%`+ð, �t‰|ð-`+ð4 �t‰|ð5`+ð< �d‘
ð=`+ðD �D‰jðE`+ðL ðM`+ðN ðO`+ðP &ðQ`+ðR ˜‘:ðS`+ðX ˜D‘jðY`+ð` �‰:ða`+ðb �D‰jðc`+ðj �t‘ðk`+ðl �T‰zðm`+ðn �D‰jðo`+ðp �d‘
ðq`+ðr ˜‘:ðs`+ðx ðy`+ð@ �d‘
ðA`+ðH %)òI`+óóð"`+ôF,˜Zô ,ñ "+Ò+CÓ!DÐ ˜Ó Dð¨¨d©
°TÑ(9¸DÑ(@ð ÀTó ð% h¨w°s¸F°{Ñ/CÑ&Dð %Èó %ð*NØ�D‰j˜4ÑðNàˆ4�ZôNñ/Ø	��c�Ñ	ñ/á.ð/ð ô/ðd ‡�Ù!Ø
#Ð	$ÙÐ+Ó,Ð-Øð	 ó ð +˜WŸ]™]ØØ@ôð )˜7Ÿ=™=ØØ7ôñ )0Ð0AÓ(BñLØðLà�d‘
ðLð �D‰jðLð &óLóðLð^ ‡�ÙØ
#Ð	$ÙÐ+Ó,Ð-àˆg�tÐ-Ñ.Ð/ðð	 ó ð (˜'Ÿ-™-ØØ5ôð (˜'Ÿ-™-ØØ5ôð +˜WŸ]™]Øñ Aôð +˜WŸ]™]ØØ@ôð )˜7Ÿ=™=ØØ7ôð $�g—m‘mÙñ tôñ )0Ð0AÓ(Bò5\
Øð\
à�4‰Zð\
ð �4‰Zð\
ð �d‘
ð\
ð �d‘
ð\
ð$ �D‰jñ%\
ð, ð-\
ð4 &ó5\
óð\
ð~ ‡‚ÙØ
#Ð	$ÙÐ+Ó,Ð-ñ ó ò
óð
ð< ‡‚ÙØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó òFóðFðT Ù(/Ð0AÓ(Bñ#Ø�4‰Zð#à%ô#ðL ‡�ÙØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó ð (˜'Ÿ-™-ØÙcôñ )0Ð0AÓ(BñQ
Ø�4‰ZðQ
ð
 &óQ
óðQ
ðh ‡�ÙØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó ò'
óð'
òT)¸Nñ )ÐSVô )ðX ‡�ÙØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó ð �—‘ØÙFôñ )0Ð0AÓ(Bò&Øð&ð
 &ó&óð&ðR ‡�ÙØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó òPóðPðf ‡�ÙØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó ò%óð%ð4 ‡‚ÙØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó ó,Ð':¸TÑ'Aó ,óð,ò^¸~ñ ÐVYô ð> ‡�ÙØ
#Ð	$ÙÐ+Ó,Ð-Øð	 ó ð �—‘ÙÙJôñ )0Ð0AÓ(BòØðð
 &óóðð> ‡�ÙÙÐ+Ó,Ð-Ø)ñ ó ð
N+Ð 6ó N+óð
N+òb¨<ô ð& *.Øò	Y&ØðY&àðY&ð   $Ñ&ñY&ð �D‰jô	Y&ðx ‡�ÙØ
#Ð	$ÙÐ+Ó,Ð-Øàˆg�tÐ-Ñ.Ð/ðð ó ð $�g—m‘mÙAôð �—‘ØØØ0õð
 #�W—]‘]ØØÙØ.õ	ñ )0Ð0AÓ(BñoØðoð ð	oð ðoð &óoóðoðr #'Ø!òHÙ!ñHà
ñHð ðHð ð	Hð
 ñHð ñHð  ñHð ðHð 
ôHðV5°#¸±*ð 5ÀÈÈfÈÑAUô 5ð&¨>ð ¸dô ð"Øðà%ðð �4‰Zðð 
ô	ð<°ð À4ô ð Øðà%ðð ðð 
ô	ðB%Øð%à%ð%ð 
ˆ#�Yô%ðPØðà%ðð ˆ3�ˆ8�_õr:   