
    h                       d dl Z d dlZd dlmZmZmZ d dlmZ d dlmZm	Z	m
Z
mZmZmZ d dlZd dlmZmZmZmZ d dlZd dlmZ d dl d dlmZmZ d d	lmZ d d
lmZ d dlmZ erd dlm Z  ne	Z  e       Z!e!jE                  ddg ee      gd      d        Z#e!jE                  ddg ee      gd       ejH                  dd      fdee%   fd       Z&e!jE                  ddg ee      gddee'   ii       ejH                  dd       ejH                  dd      fdee%   dee%   fd       Z(d e)dedefd!Z*e!jE                  d"dg ee      gddee'   iid#       ejH                  dd$       ejH                  dd%       ee      fdee%   dee%   d e)fd&       Z+d e)dedefd'Z,e!jE                  d(dg ee      gddee'   iid#       ejH                  dd$       ejH                  dd%       ee      fdee%   dee%   d e)fd)       Z-e!jE                  d*dg ee      gddee'   iid#       ejH                  d+,       ejH                  dd$       ejH                  dd%      fd-e%dee%   dee%   fd.       Z.e!jE                  d/dg ee      gddee'   iid#       ejH                  d+,       ejH                  dd$       ejH                  dd%      fd-e%dee%   dee%   fd0       Z/e!jE                  d1dg ee      gdddee'   ii2       ejH                  dd$       ejH                  dd%       ee      fdee%   dee%   d e)fd3       Z0e!jE                  d4dg ee      gddee'   ii       ejH                  dd$       ejH                  dd%       ejH                  d5d6       ejH                  dd7       ejH                  dd8       ejH                  dd9       ejH                  dd:      fdee%   dee%   d;eed<      d=ee%   d>ee%   d?ee%   d@ee%   fdA       Z1e!jE                  dBdg ee      gdddee'   ii2      dC        Z2e!jE                  dDdg ee      gddee'   ii       ejH                  dd       ejH                  dd       ejH                  ddE      fdee%   dee%   dFee%   fdG       Z3de%de%fdHZ4e!jk                  dIdg ee      gddJdKdLdMdNii      dOe6fdP       Z7e!jE                  dQdg ee      gdddee'   ii2       ejH                  ddR       ejH                  ddS       ejH                  ddT       ejH                  ddU       ejH                  ddV       ejH                  ddW       ejH                  dd       ejH                  dd       ejH                  dXdYdXZ       ejH                  d[d\dXd]^       ee       ejH                  dd_       ejH                  dd`      fd=ee%   dee%   daee%   d?ee%   dbee8   dcee8   dee%   dee%   dde9dee9d e)dfee%   dee%   fdg       Z: edhi      e!jE                  djdg ee      gd       ejH                  dd       ejH                  dd      fdae%dee%   dee%   fdk              Z;e!jE                  dldg ee      gddee'   ii       ejH                  ddR       ejH                  ddS       ejH                  ddm       ejH                  dd       ejH                  dd       ejH                  dndo       ee      fd=ee%   dee%   daee%   dee%   dee%   dpe<d e)fdq       Z=e!jk                  drdg ee      gs      dt        Z>e!jk                  dudg ee      gd      dv        Z?d ee      fd=ee%   d e)fdwZ@e!jE                  dxdg ee      gd       ejH                  ddy       ee      fd=ee%   d e)fdz       ZAe!jE                  d{dg ee      gd      d|        ZB	 dd e)d~e9fdZCe!jE                  ddg ee      gd       ejH                  dd       ee      fd~e9d e)fd       ZDe!jE                  ddg ee      gd      d        ZEe!jE                  ddg ee      gd      d        ZFe!jk                  ddg ee      gd      ddeeG   fd       ZH	 dd e)d~e9fdZIe!jE                  ddg ee      gd       ejH                  d}d       ee      fd~e9d e)fd       ZJe!jE                  de      defd       ZK	 dde fdZL	 	 dde%de%dee    dee%   fdZMe!jE                  ddg ee      gdddee'   ii2       ejH                  d,       ee      fde%d e)fd       ZNdfee%   de
e%e	f   fdZOy)    N)datetime	timedeltatimezone)	lru_cache)TYPE_CHECKINGAnyDictListLiteralOptional)	APIRouterDependsHTTPExceptionstatus)verbose_proxy_logger)*)ProviderBudgetResponseProviderBudgetResponseObject)user_api_key_auth)get_spend_by_team_and_customer)handle_exception_on_proxyPrismaClientz/spend/keyszBudget & Spend TrackingF)tagsdependenciesinclude_in_schemac                     K   ddl m}  	 | t        d      | j                  dd       d{   }|S 7 # t        $ r+}t	        t
        j                  dt        |      i	      d}~ww xY ww)
z
    View all keys created, ordered by spend

    Example Request:
    ```
    curl -X GET "http://0.0.0.0:8000/spend/keys" -H "Authorization: Bearer sk-1234"
    ```
    r   prisma_clientNDatabase not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keyskeyfind_all
table_name
query_typeerrorstatus_codedetaillitellm.proxy.proxy_serverr   	Exceptionget_datar   r   HTTP_400_BAD_REQUESTstr)r   key_infoes      s/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/proxy/spend_tracking/spend_management_endpoints.pyspend_key_fnr3      s     " 9
  T  '//5Z/XX Y  
33SV$
 	

s0   A-#6 46 A-6 	A*&A%%A**A-z/spend/userszGet User Table row for user_id)defaultdescriptionuser_idc                 $  K   ddl m} 	 |t        d      | |j                  dd|        d{   }|gS |j                  dd	       d{   }|S 7 $7 # t        $ r+}t	        t
        j                  d
t        |      i      d}~ww xY ww)aD  
    View all users created, ordered by spend

    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    userfind_unique)r$   r%   r6   r"   r#   r&   r'   r*   )r6   r   	user_infor1   s       r2   spend_user_fnr;   @   s     6 9
  T  +44!mW 5  I ;+44!j 5  I 
  
33SV$
 	

sT   B&A AA BA AA BA A 	B"&BBBz/spend/tags   model)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} ddlm} 	 |t        d      	  || ||       d{   }|S # t        $ r' t        dt        j
                  j                  z         w xY w7 9# t        $ r}t        |t              rKt        t        |dd	t        |       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   )get_spend_by_tagszTrying to use Spend by Tagsr   Nr    )r?   r@   r   r)   /spend/tags Error()internal_errorparamNoner(   messagetyperF   code/spend/tags Error)enterprise.utilsrB   ImportErrorr,   CommonProxyErrors!missing_enterprise_package_dockervaluer+   r   
isinstancer   ProxyExceptiongetattrr/   r   HTTP_500_INTERNAL_SERVER_ERROR)r?   r@   rB   r   responser1   s         r2   view_spend_tagsrW   v   s6    D
6 9#
  T 
	 +!HM
 
 5  
)AAGGH
 	

,

  
a' 8/A#a&-KL%a&1Qv/T/TU	  >*G'#a&0!!Wf-66	
 	

sL   D4 DA) A'A) D0A$$D'A) )	D2B!DDDuser_api_key_dictc                    K   ddl m} |t        dddi      | j                  }|t        dddi      d}|j                  j                  ||||       d {   }|S 7 w)	Nr   r     r&   No db connectedr'   No user_id founda0  
    SELECT
        date_trunc('day', "startTime") AS date,
        COUNT(*) AS api_requests,
        SUM(total_tokens) AS total_tokens
    FROM "LiteLLM_SpendLogs"
    WHERE "startTime" BETWEEN $1::date AND $2::date + interval '1 day'
    AND "user" = $3
    GROUP BY date_trunc('day', "startTime")
    r+   r   r   r6   db	query_rawrX   r?   r@   r   r6   	sql_querydb_responses          r2   !get_global_activity_internal_userrc      s      9W>O4PQQ''GW>P4QRR	I &((22:x K 	   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                 L  K   | |t        t        j                  ddi      t        j                  | d      }t        j                  |d      }ddlm} 	 |t        d      |j                  t        j                  k(  s|j                  t        j                  k(  rt        |||       d{   }n'd	}|j                  j                  |||       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-%dr   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" BETWEEN $1::date AND $2::date + interval '1 day'
            GROUP BY date_trunc('day', "startTime")
            date%b %dapi_requeststotal_tokensc                     | d   S Nrh    xs    r2   <lambda>z%get_global_activity.<locals>.<lambda>D      ai    r!   
daily_datasum_api_requestssum_total_tokens)r   r   r.   r   strptimer+   r   r,   	user_roleLitellmUserRolesINTERNAL_USERINTERNAL_USER_VIEW_ONLYrc   r^   r_   fromisoformatstrftimeappendgetsortedr/   )r?   r@   rX   start_date_objend_date_objr   rb   ra   rw   rx   rv   row	_date_objdata_to_returnr1   s                  r2   get_global_activityr      s    T X-33EF
 	

 &&z:>N$$Xz:L89
  T 
 ''+;+I+II **.>.V.VV A!><! KI !. 0 0 : :><! K I
C ..s6{;I#,,W5CKc" :: ::  J,?@
 % 0 0
 S<  
33SV$
 	

s\   AF$AE- .E)/'E- E+E- F$B	E- (F$)E- +E- -	F!6&FF!!F$c                    K   ddl m} |t        dddi      | j                  }|t        dddi      d}|j                  j                  ||||       d {   }|S 7 w)	Nr   r   rZ   r&   r[   r'   r\   aR  
    SELECT
        model_group,
        date_trunc('day', "startTime") AS date,
        COUNT(*) AS api_requests,
        SUM(total_tokens) AS total_tokens
    FROM "LiteLLM_SpendLogs"
    WHERE "startTime" BETWEEN $1::date AND $2::date + interval '1 day'
    AND "user" = $3
    GROUP BY model_group, date_trunc('day', "startTime")
    r]   r`   s          r2   'get_global_activity_model_internal_userr   U  s      9W>O4PQQ''GW>P4QRR
I &((22:x K 	rd   z/global/activity/modelc                 \  K   | |t        t        j                  ddi      t        j                  | d      }t        j                  |d      }ddlm} 	 |t        d      |j                  t        j                  k(  s|j                  t        j                  k(  rt        |||       d{   }n'd	}|j                  j                  |||       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 A7 # 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 - 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&   rf   r'   rg   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" BETWEEN $1::date AND $2::date + interval '1 day'
            GROUP BY model_group, date_trunc('day', "startTime")
            model_groupru   rh   ri   rv   rw   rj   rx   rk   c                     | d   d   S )N   rw   rn   ro   s    r2   rq   z+get_global_activity_model.<locals>.<lambda>  s    ad#56rs   Tr!   reverse
   c                     | d   S rm   rn   ro   s    r2   rq   z+get_global_activity_model.<locals>.<lambda>      &	rs   rt   )r=   rv   rw   rx   )r   r   r.   r   ry   r+   r   r,   rz   r{   r|   r}   r   r^   r_   r~   r   r   r   dictr   itemsrU   r/   )r?   r@   rX   r   r   r   rb   ra   model_ui_datar   _modelr   rV   r=   data_sort_daily_datar1   s                    r2   get_global_activity_modelr   s  s    B X-33EF
 	

 &&z:>N$$Xz:L8M
  T 
 ''+;+I+II **.>.V.VV G!><! K	I !. 0 0 : :><! K I  	 C'F]*"$()())f%
 !..s6{;I#,,W5CK&!,/66s;&!"45QR9SS5&!"45QR9SS5   ##%6 r	
 (..0KE4%d<&8>QROO""2(,-?(@(,-?(@	 1 {b  
==SV$
 	

s\   AH,AG5 .G//'G5 G2G5 H,DG5 .H,/G5 2G5 5	H)>&H$$H))H,z&/global/activity/exceptions/deploymentzFilter by model group)r5   r   c                 l  K   ||t        t        j                  ddi      t        j                  |d      }t        j                  |d      }ddlm} 	 |t        d      d	}|j                  j                  ||||        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&   rf   r'   rg   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::date
            AND "startTime" < ($2::date + INTERVAL '1 day')
            AND model_group = $3
            AND status_code = '429'
        GROUP BY
            api_base,
            date_trunc('day', "startTime")
        ORDER BY
            date;
        api_baserv   sum_num_rate_limit_exceptionsrh   ri   rv   r   num_rate_limit_exceptionsc                     | d   d   S )Nr   r   rn   ro   s    r2   rq   z?get_global_activity_exceptions_per_deployment.<locals>.<lambda>  s    ad#BCrs   Tr   r   c                     | d   S rm   rn   ro   s    r2   rq   z?get_global_activity_exceptions_per_deployment.<locals>.<lambda>  r   rs   rt   )r   rv   r   )r   r   r.   r   ry   r+   r   r,   r^   r_   r~   r   r   r   r   r   r   rU   r/   )r   r?   r@   r   r   r   ra   rb   r   r   r   r   rV   r=   r   r   r1   s                    r2   -get_global_activity_exceptions_per_deploymentr     s    z X-33EF
 	

 &&z:>N$$Xz:L8N
  T 	$ *,,66~|[
 
 I  	 C_F]*"$56)f% !..s6{;I#,,W5CK&!,/66s;&!"ABcgg+QG B   ##%C r	
 (..0KE4%d<&8>QROO %"25976 1 a
d  
==SV$
 	

sI   AF40E= E;E= F4C*E= :F4;E= =	F1&F,,F11F4z/global/activity/exceptionsc                 z  K   ||t        t        j                  ddi      t        j                  |d      }t        j                  |d      }ddlm} 	 |t        d      d	}|j                  j                  ||||        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&   rf   r'   rg   r   r   r    a  
        SELECT
            date_trunc('day', "startTime")::date AS date,
            COUNT(*) AS num_rate_limit_exceptions
        FROM
            "LiteLLM_ErrorLogs"
        WHERE
            "startTime" >= $1::date
            AND "startTime" < ($2::date + INTERVAL '1 day')
            AND model_group = $3
            AND status_code = '429'
        GROUP BY
            date_trunc('day', "startTime")
        ORDER BY
            date;
        rh   ri   r   c                     | d   S rm   rn   ro   s    r2   rq   z0get_global_activity_exceptions.<locals>.<lambda>  rr   rs   rt   r   )r   r   r.   r   ry   r+   r   r,   r^   r_   r~   r   r   r   r   r/   )r   r?   r@   r   r   r   ra   rb   r   rv   r   r   r   r1   s                 r2   get_global_activity_exceptionsr     su    R X-33EF
 	

 &&z:>N$$Xz:L85
  T 	  *,,66~|[
 
 I()%
C ..s6{;I#,,W5CKc")SWW5PRS-TT)  J,?@
 %-J

 3
6  
33SV$
 	

sI   AD;0D DD D;A1D D;D 	D8&D33D88D;z/global/spend/provider)r   r   r   r>   c                 v  K   ddl m} | |t        t        j                  ddi      t        j                  | d      }t        j                  |d      }ddlm}m	} 	 |t        d	      |j                  t        j                  k(  s|j                  t        j                  k(  rF|j                  }|t        d
ddi      d}	|j                   j#                  |	|||       d{   }
n'd}	|j                   j#                  |	||       d{   }
|
g S g } |t$              }|
D ]  }|d   }d}||j'                  |      }|"	 t)        j*                  |j,                  j.                  |j,                  j0                  |j,                  j2                  |j,                        \  }}}}||xx   |d   z  cc<    |j5                         D ]  \  }}|j7                  ||d        |S 7 7 # t        $ r Y w xY w# t        $ r+}t        t        j                  dt9        |      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&   rf   r'   rg   )
llm_routerr   r      r\   a  
            SELECT
            model_id,
            SUM(spend) AS spend
            FROM "LiteLLM_SpendLogs"
            WHERE "startTime" BETWEEN $1::date AND $2::date 
            AND length(model_id) > 0
            AND "user" = $3
            GROUP BY model_id
            z
            SELECT
            model_id,
            SUM(spend) AS spend
            FROM "LiteLLM_SpendLogs"
            WHERE "startTime" BETWEEN $1::date AND $2::date AND length(model_id) > 0
            GROUP BY model_id
            model_idUnknown)r   )r=   custom_llm_providerr   litellm_paramsspend)providerr   )collectionsr   r   r   r.   r   ry   r+   r   r   r,   rz   r{   r|   r}   r6   r^   r_   intget_deploymentlitellmget_llm_providerr   r=   r   r   r   r   r/   )r?   r@   rX   r   r   r   r   r   r6   ra   rb   ui_responseprovider_spend_mappingr   	_model_id	_provider_deployment_r   r   r1   s                        r2   get_global_spend_providerr     sp    J (X-33EF
 	

 &&z:>N$$Xz:LDN
  T 
 ''+;+I+II **.>.V.VV'//G# #W6H,I 	I !. 0 0 : :><! KI !. 0 0 : :><! K I .9#.>CJI!I%(777K*	-4-E-E"-"<"<"B"B0;0J0J0^0^%0%?%?%H%H+6+E+E	.*9a /y9S\I9 "  6;;=OHeHuEF  > ]8 %   
33SV$
 	

s   AH9BH &G.''H G1H H9H 4H 
A4G3>/H -H9.H 1H 3	G?<H >G??H 	H6&H11H66H9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.group_by)r   customerapi_keyr   internal_user_idteam_idcustomer_idc                   K   | |t        t        j                  ddi      t        j                  | d      }t        j                  |d      }ddlm}	m}
 	 |
t        d      |	d	ur;t        j                  d
       t        dt        j                  j                  z         |at        j                  d|       |j                  d      rt!        |      }d}|
j"                  j%                  ||||       d{   }|g S |S |Dt        j                  d|       d}|
j"                  j%                  ||||       d{   }|g S |S ||t'        |||||
       d{   S |dk(  r-d}|
j"                  j%                  |||       d{   }|g S |S |dk(  r-d}|
j"                  j%                  |||       d{   }|g S |S |dk(  r-d}|
j"                  j%                  |||       d{   }|g S |S y7 7 7 7 v7 F7 # 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&   rf   r'   rg   r   )premium_userr   r    Tz.accessing /spend/report but not a premium userz/spend/report endpoint zGetting /spend for api_key: %ssk-tokenad  
                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" BETWEEN $1::date AND $2::date 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: %saa  
                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" BETWEEN $1::date AND $2::date 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;
            r   a  

            WITH SpendByModelApiKey AS (
                SELECT
                    date_trunc('day', sl."startTime") AS group_by_day,
                    COALESCE(tt.team_alias, 'Unassigned Team') AS team_name,
                    sl.model,
                    sl.api_key,
                    SUM(sl.spend) AS model_api_spend,
                    SUM(sl.total_tokens) AS model_api_tokens
                FROM 
                    "LiteLLM_SpendLogs" sl
                LEFT JOIN 
                    "LiteLLM_TeamTable" tt 
                ON 
                    sl.team_id = tt.team_id
                WHERE
                    sl."startTime" BETWEEN $1::date AND $2::date
                GROUP BY
                    date_trunc('day', sl."startTime"),
                    tt.team_alias,
                    sl.model,
                    sl.api_key
            )
                SELECT
                    group_by_day,
                    jsonb_agg(jsonb_build_object(
                        'team_name', team_name,
                        'total_spend', total_spend,
                        'metadata', metadata
                    )) AS teams
                FROM (
                    SELECT
                        group_by_day,
                        team_name,
                        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,
                        team_name
                ) AS aggregated
                GROUP BY
                    group_by_day
                ORDER BY
                    group_by_day;
                r   a  

            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" BETWEEN $1::date AND $2::date
                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   aP  
                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" BETWEEN $1::date AND $2::date
                    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   ry   r+   r   r   r,   r   debug
ValueErrorrO   not_premium_userrQ   
startswith
hash_tokenr^   r_   r   r/   )r?   r@   r   r   r   r   r   r   r   r   r   ra   rb   r1   s                 r2   get_global_spend_reportr     s    F X-33EF
 	

 &&z:>N$$Xz:LFT
  T  t# &&'WX),=,N,N,T,TT   &&'GQ!!%($73!ID !. 0 0 : :><! K "	) &&9;K!ID !. 0 0 : :><9I! K "	 [%<7g{M   v4Il !. 0 0 : :><! K "	#1If !. 0 0 : :><! K "	"!ID !. 0 0 : :><! K "	S #iZxxT  
33SV$
 	

s  AIB$H =H >H IH I;H HH IH IH $H%H (I)'H HH IH I'H H	H 
IH I'H 4H5H <I=H >I H H H H 	H H 	I&H<<IIz/global/spend/all_tag_namesc                  F  K   	 ddl m}  | t        d      d}| j                  j	                  |       d {   }|g S g }|D ]"  }|j                  |j                  d             $ d|iS 7 5# t        $ r}t        |t              rKt        t        |ddt        |       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";
        individual_request_tag	tag_namesr)   z/spend/all_tag_names Error(rD   rE   rF   rG   r(   rH   z/spend/all_tag_names Error)r+   r   r,   r^   r_   r   r   rR   r   rS   rT   r/   r   rU   )r   ra   rb   
_tag_namesr   r1   s         r2   global_get_all_tag_namesr     s4    '
<  T 	 *,,66yAAI
Ccgg&>?@  Z(( B  
a' 8/J3q6(RS-TU%a&1Qv/T/TU	  >*G03q69!!Wf-66	
 	

sD   D!3A/ A-A/ D! ,A/ ,D!-A/ /	D8B!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    rf   bad_requestrH   )r?   r@   tags_strr   
r)   rC   rD   rE   rF   rG   r(   rL   )	tracebackr+   r   r,   rS   r   r.   ui_get_spend_by_tags
format_excr/   rR   r   rT   rU   )	r?   r@   r   r   r   rV   r1   error_trace	error_strs	            r2   global_view_spend_tagsr   0  s?    J 8&
  T  z1 @"00	  .!'	
 
 
  
**,FTMK/	a' 8/A)A-NO%a&1Qv/T/TU	  >*G')3!!Wf-66	
 	

s<   DA A AA DA 	D B0DDDc                 z  K   ddl m} |t        j                  d       y 	 d}|j                  j                  || |       d {   }d}|j                  j                  || |       d {   }||fS 7 /7 
# t        $ r7}t        j                  dj                  t        |                   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 reportsa  
        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"::DATE >= $1::date AND s."startTime"::DATE <= $2::date
        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"::DATE >= $1::date AND "startTime"::DATE <= $2::date
        GROUP BY individual_request_tag
        ORDER BY total_spend DESC;
        z(Exception in _get_daily_spend_reports {})	r+   r   r   r&   r^   r_   r,   formatr/   )r?   r@   r   ra   rV   spend_per_tagr1   s          r2    _get_spend_report_for_time_ranger     s      9""h	
 %
	 '))33Iz8TT	 ,..88z8
 
 &&# U

  
""6==c!fE	
 	

sR   B;"A8 A4&A8 +A6,A8 3B;4A8 6A8 8	B8-B3.B;3B88B;z/spend/calculatecostzThe calculated cost        float)r5   examplerJ   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!        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r   Nr   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)   rJ   rG   rF   r(   rH   rI   rZ   rn   )r   r   litellm.cost_calculatorr   r+   r   r=   r   r   model_group_alias
model_listr   r   ModelResponser,   rR   rS   rT   r/   r   r.   )r   r   r   r   _cost_model_in_llm_routercost_per_token_model_group_namer=   _litellm_params_litellm_model_namer   r   _completion_responser1   	error_msgs                   r2   calculate_spendr     s}    ~V
+89==$'# #[  $( 59N%00<)E)EE )3(D(DW]](S%!+!6!6 99\26GG380 "7 ",!6!6 99\2gmmC380 "7 $/"6":":;K"L&5&9&9'&B#'6':':;Q'R$(7(;(;<S(T%(4,8%1-A.C&N
 (-$--*8 (gmmgFVFVW((4#*#8#8#W7;V;V#W #8LME_   
a' 8SV4Q/a&1Qv/J/JK	  1vh	Ay)4FF+!Wf-M3/	
 	

s7   I&B F, %2F, CF, +I&,	I#5B)II##I&z/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_idz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 valuer   zPage number for pagination)r4   r5   ge2   zNumber of items per paged   )r4   r5   r   lez.Filter logs by status (e.g., success, failure)zFilter logs by model
request_id	min_spend	max_spendpage	page_sizestatus_filterc                 :  K   ddl m} |t        dddt        j                        ||t        dd	dt        j
                        	 t        j                  |d
      j                  t        j                        }t        j                  |d
      j                  t        j                        }|j                         }|j                         }d||di}|||d<   t        |      }|r|j                  |       | | |d<   |||d<   |||d<   |||d<   ||i |d<   |||d   d<   |||d   d<   |dz
  |	z  }|j                  j                  j!                  |       d{   }|j                  j                  j#                  |ddi||	       d{   }||	z   dz
  |	z  }t%        j&                  dt(        j+                  |dt,                     ||||	|dS 7 z7 I# t.        $ r(}t%        j0                  d|        t3        |      d}~ww xY ww)a  
    View spend logs for UI with pagination support

    Returns:
        {
            "data": List[LiteLLM_SpendLogs],  # Paginated spend logs
            "total": int,                      # Total number of records
            "page": int,                       # Current page number
            "page_size": int,                  # Number of items per page
            "total_pages": int                 # Total number of pages
        }
    r   r   N Prisma Client is not initializedrE   rG   rH   z$Start date and end date are requiredr   %Y-%m-%d %H:%M:%Stzinfo	startTimegtelter   r   r8   r  r=   r   r  r  r   )wheredesc)r  orderskiptakezdata= %s   )indentr4   )r   totalr  r  total_pageszError in ui_view_spend_logs: )r+   r   rS   r   HTTP_401_UNAUTHORIZEDr.   r   ry   replacer   utc	isoformat_build_status_filter_conditionupdater^   litellm_spendlogscount	find_manyr   r   jsondumpsr/   r,   	exceptionr   )r   r6   r  r   r  r  r?   r@   r  r  rX   r  r=   r   r   r   start_date_isoend_date_isowhere_conditionsstatus_conditionr  total_recordsr   r  r1   s                            r2   ui_view_spend_logsr*  N  s    H 96!--	
 	
 X-:,,	
 	
K+!**:7JKSS<< T 
  ((3FGOO<< P 

 (113#--/ E,
 *1Y'9-H##$45*1Y''.V$!-7\*(-W% I$9(*W%$3< )%0$3< )%0qI% ,..@@FF" G 
 

 #%%77AA"V  B 
 
 %y014B"":tzz$qRUz/VW ""&
 	
'


*  +&&)Fqc'JK'**+sP   AH
DG' (G#)2G' G%AG' "H#G' %G' '	H0#HHH   )maxsizez/spend/logs/ui/{request_id}c                 ~  K   t         j                  j                         }d}d}|4t        j                  |d      j                  t        j                        }|4t        j                  |d      j                  t        j                        }|D ]$  }|j                  | ||       d{   }|"|c S  y7 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
    Nr	  r
  )r  start_time_utcend_time_utc)	r   logging_callback_manager6get_active_additional_logging_utils_from_custom_loggerr   ry   r  r   r  get_request_response_payload)r  r?   r@   custom_loggersr   r   custom_loggerpayloads           r2   'ui_view_request_response_for_request_idr6    s     2 	((__a  *.N'+L!**:7JKSS<< T 
 ((3FGOO<< P 
 (%BB!)% C 
 

 N ( 
s   B+B=-B;.B=5B=z/spend/logszjrequest_id to get spend logs for specific request_id. If none passed then pass spend logs for all requestsTzWhen start_date and end_date are provided, summarize=true returns aggregated data by date (legacy behavior), summarize=false returns filtered individual logs	summarizec                 
  K   ddl m} |j                  t        j                  k(  s|j                  t        j
                  k(  r|j                  }	 t        j                  d       |t        d      g }|0t        |t              r|t        |t              rt        j                  |d      }	t        j                  |d      }
d|	|
di}| t        | t              r| |d	<   n/|t        |t              r||d
<   n|t        |t              r||d<   |s3|j                  j                  j!                  |ddi       d{   }|S |j                  j                  j#                  g d|ddi       d{   }t        |t$              rt'        |      dkD  rt        |d   t(              ri }|D ]T  }t        j                  t        |d         d      }|j+                         }||vri i d||<   |d	   } |d   }|d   }||   j-                  dd      |j-                  di       j-                  dd      z   ||   d<   ||   j-                  | d      |j-                  di       j-                  dd      z   ||   | <   ||   d   j-                  |d      |j-                  di       j-                  dd      z   ||   d   |<   ||   d   j-                  |d      |j-                  di       j-                  dd      z   ||   d   |<   W g }d}t/        |j1                               D ]  \  }}|j3                  i |d|i       |}  |
j+                         }|D||k  r?|t5        d      z   }||k  r+|j3                  |di i d       |t5        d      z  }||k  r+|S |S | jt        | t              rZ| j7                  d      r|j9                  |       }n| }|j;                  ddd	|d       d{   }t        |t$              r|S |gS |"|j;                  dd d
|d       d{   }|gS |4|j;                  ddd|d       d{   }t        |t$              r|S |gS |j;                  dd!       d{   }|S 7 F7 7 7 b7 @7 # t        $ r}t        |t<              rKt?        tA        |d"d#t        |       d$      d%tA        |d&d'      tA        |d(tB        jD                        )      t        |t>              r|t?        d*t        |      z   d%tA        |d&d'      tB        jD                  )      d}~ww xY ww)+a  
    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-Fn8Ej39NkBQmUagFEoUWPQ" -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    rg   r  r  r   r  r8   r  r  r  )r   r8   r=   r  r   T)byr  sumz%Y-%m-%dT%H:%M:%S.%fZ)usersmodelsr=   _sumr<  r=  r   days)r  r   r<  r=  r   r   r"   )r!   rQ   )r$   r%   key_valr9   r#   r)   z/spend/logs Error(rD   rE   rF   rG   r(   rH   z/spend/logs Error)#r+   r   rz   r{   r|   r}   r6   r   r   r,   rR   r/   r   ry   r^   r  r!  r   listlenr   rh   r   r   r   r   r   r   r   r-   r   rS   rT   r   rU   )r   r6   r  r?   r@   r7  rX   r   
spend_logsr   r   filter_queryr   rV   resultrecord	dt_objectrh   r=   return_list
final_datekvend_date_datecurrent_datehashed_token	spend_logr1   s                               r2   view_spend_logsrQ  $  s    P 9 	##'7'E'EE&&*:*R*RR#++^
""#;<  T  
":s+$8S) &..z:FN#,,XzBL )'L "z'3'?*1Y''Jz3,G-7\*$GS)A'.V$ *--??II&#V J    +--??HH<"T I  H 8T*MA%x{D1!&F ( 1 1#f[6I2JLc dI$>>+D6)13r'Bt$Y/G$VnG"7OE,24L,<,<Wa,H6::Lc'1o-&F4L) -34L,<,<Wa,H6::Lc'1o-&F4L) 6<D\'5J5N5N6

62.227A>6?F4L)'2 5;4L4J4N4Nq5

62.227A>5?F4L*51# '( !!
"6<<>2DAq&&'<!'<[!'<=!"J 3 !- 1 1 3)j=.H#-	q0A#AL&-7#**-9)*)+*,	 %	q(99 '-7 #"O Z%=!!%(,77g7F&+44"% )LA 5  I
 )T*  !{"#+44"( ,zB 5  I
 ; +44"% &9 5  I
 )T*  !{",55"z  6   J S@  
a' 8/A#a&-KL%a&1Qv/T/TU	  >*G'#a&0!!Wf-66	
 	

s   AU
C4R R
R 
U
/R :R;H'R #R $U
%R &U
'AR 9R:R U
R U
R /R0R 6U
7R RR )U
*R ,U
-R RR 	U

R R R R 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                        | j
                  j                  j                  dd	ii 
       d{    | j
                  j                  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  rE   rG   rH   r   r   )r   r  z3Spend for all API Keys and Teams reset successfullysuccessrI   r   )	r+   r   rS   r   r  r^   litellm_verificationtokenupdate_manylitellm_teamtabler   s    r2   global_spend_resetrX    s       96!--	
 	
 


4
4
@
@s^2 A    


,
,
8
8wnTV
8
WWW I  Xs$   ABB0BB
BBz/global/spend/refreshc                    	K   ddl m	 	t        dddt        j                        dt
        f	fd	}  |         d{   }|rd
}	 ddlm} ddl m} ddl	m
} t        j                  d      }|t        |j                  j                         |||ddi      }|j                   j#                          d{    |j                   j%                  |       d{    t'        j(                  d       dddS y7 7 D7 ## t        $ r<}t'        j*                  dj-                  t/        |                   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  rE   rG   rH   returnc                     K   d} 	 j                   j                  |        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   relkindmF)r^   r_   r,   )ra   respr   s     r2   !is_materialized_global_spend_viewz?global_spend_refresh.<locals>.is_materialized_global_spend_viewQ  sX     	
	&))33I>>D79%,, ?  		s1   A7 57 A7 	A AAAzE
        REFRESH MATERIALIZED VIEW "MonthlyGlobalSpend";    
        )rO   )proxy_logging_objr   DATABASE_URLtimeoutip  )database_urlr`  http_clientz!MonthlyGlobalSpend view refreshedrS  rT  z(Failed to refresh materialized view - {}z#Failed to refresh materialized viewfailure)r+   r   rS   r   r  boollitellm.proxy._typesrO   r`  litellm.proxy.utilsr   osgetenvr,   db_not_connected_errorrQ   r^   connectr_   r   infor$  r   r/   )
r_  view_existsra   rO   r`  r   db_url
new_clientr1   r   s
            @r2   global_spend_refreshrq  :  sN     96!--	
 	
T $ :;;K		>D8YY~.F~ 1 H H N NOO%#"3tJ --'')))--)))444 %%&IJ># /  <, *4  	 **:AA#a&I A# 		se   <EC> E	A2D ;D <"D DD <E D D 	E	1E>E	?EE		Ec                   K   ddl m} |t        dddt        j                        	 |j
                  }|t        d      | )d}|j                  j                  || |       d {   }|S d	}|j                  j                  ||       d {   }|S 7 .7 # t        $ r(}t        j                  d
t        |              |d }~ww xY ww)Nr   r   r  rE   rG   rH   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: )r+   r   rS   r   rU   r6   r   r^   r_   r,   r   r&   r/   )r   rX   r   r6   ra   rV   r1   s          r2   global_spend_for_internal_userrt    s      96!66	
 	
#++?HIII +--77	7GTTHOm	&))33IwGG U H  ""%?Ax#HIsX   &C=B &B'B ,C-!B BB CB B 	C
"#CC

Cz/global/spend/logszMAPI Key to get global spend (spend per day for last 30d). Admin-only endpointc                   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}|j                  j                  |       d{   }|S d}|j                  j                  ||        d{   }|S 7 t7 Z7 27 # 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  rE   rG   rH   )r   rX   )r   z3SELECT * FROM "MonthlyGlobalSpend" ORDER BY "date";queryz
                    SELECT * FROM "MonthlyGlobalSpendPerKey"
                    WHERE "api_key" = $1
                    ORDER BY "date";
                    r   rs  r)   z/global/spend/logs Error(rD   rF   r(   z/global/spend/logs Error)r   6litellm.integrations.prometheus_helpers.prometheus_apirv  rw  r+   r   rS   r   rU   rz   r{   r|   r}   rt  r^   r_   r,   r   r/   r   r&   rR   r   rT   )r   rX   r   rv  rw  r   rV   prometheus_api_enabledra   r1   r   r   s               r2   global_spend_logsr|    s    (  9<
  :%::	  ''+;+I+II **.>.V.VV;3D H O!8!:!<WMMHOU	!.!1!1!;!;)!;!LL	 "/!1!1!;!;Iw!OO7 N M P  
**,FTMK/	""%?	{#KLa' 8/HST-UV%a&1Qv/T/TU	  >*G.:!!Wf-66	
 	

s   GA)C< ?C4 C< GC< C6C< !G"#C< C8C< G!C< -C:.C< 3G4C< 6C< 8C< :C< <	GCGGGz/global/spendc                    K   ddl } ddlm} 	 d}|t        dddi      d	}|j                  j                  |
       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   rZ   r&   r[   r'   z;SELECT SUM(spend) as total_spend FROM "MonthlyGlobalSpend";rx  total_spend)r   
max_budgetr   r)   z/global/spend Error(rD   rE   rF   rG   r(   rH   z/global/spend Error)r   r+   r   r   r^   r_   rR   rB  rC  r   r   r  r,   r   r/   rS   rT   r   rU   )r   r   r~  ra   rV   r1   r   r   s           r2   global_spendr  	  sU     8
 CBS8TUUU	&))33)3DD(D)c(ma.?&qkoomSA$G4F4FGG E  
**,FTMK/	a' 8/CI;a-PQ%a&1Qv/T/TU	  >*G)I5!!Wf-66	
 	

s<   E4B BAB EB 	EB0E

EEr   limitc                    K   ddl m} |t        dddi      | j                  }|t        dddi      d}|j                  j                  |||       d {   }|S 7 w)	Nr   r   rZ   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]   rX   r  r   r6   ra   rV   s         r2   global_spend_key_internal_userr  <	  sx      9W>O4PQQ''GW>P4QRRI: #%%//	7EJJHO K   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	}| %|j                  j                  |       d{   }|S 	 t        |       } | d
k  rt        d      d}|j                  j                  ||        d{   }|S 7 7 L7 
# 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   )rX   NrZ   r&   r[   r'   z#SELECT * FROM "Last30dKeysBySpend";r   zLimit must be greater than 0z-SELECT * FROM "Last30dKeysBySpend" LIMIT $1 ;i  zInvalid limit: z	, error: )r+   r   rz   r{   r|   r}   r  r   r^   r_   r   r   )r  rX   r   rV   ra   r1   s         r2   global_spend_keysr  j	  s"    $ 9 	##'7'E'EE&&*:*R*RR7/
 
 W>O4PQQ9I}&))33I>>	E
19;<<G	&))33IuEE O/
 ? F WwiPQs.S$T
	sZ   ADC9DCD<C CC DDC 	D&C<<DDz/global/spend/teamsc                    K   ddl m}  | t        dddi      d}| j                  j	                  |	       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   NrZ   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;
        rx  
spend_date
team_alias
Unassignedr~     c                     | d   S Nr   rn   )items    r2   rq   z'global_spend_per_team.<locals>.<lambda>	  s    d1grs   Tr   r   )r   r~  rh   )daily_spendteamstotal_spend_per_team)r+   r   r   r^   r_   setaddroundr   r   r   rC  r   rB  )r   ra   rV   spend_by_dateteam_aliasesr  r   row_dater  r   current_date_entriestotal_spend_per_team_uir   response_datar!   rQ   s                   r2   global_spend_per_teamr  	  s     9W>O4PQQI" #%%//i/@@H M5L|$&
%J$}$ &E%OE#0#: /4 ,&E%OE'15&9M(#-- ,5,/4 ,/ 2 !#))+1EtT (&'2-?"G&&0DW0MN	
 ( Mc"fc3U34 
 %l# 7 k As   9EEDEz/global/all_end_usersc                     K   ddl m}  | t        dddi      d}| j                  j	                  |	       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   NrZ   r&   r[   r'   z;
    SELECT DISTINCT end_user FROM "LiteLLM_SpendLogs"
    rx  end_user	end_users)r+   r   r   r^   r_   r   )r   ra   rb   
_end_usersr   s        r2   global_view_all_end_usersr  	  s      9W>O4PQQI &((222CCK	J#j/*  $$ Ds   9A'A%*A'z/global/spend/end_usersr   c                 d  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
}|j                  j                  ||||       d{   }|S 7 w)r  r   r   NrZ   r&   r[   r'      r?  a8  
SELECT end_user, COUNT(*) AS total_count, SUM(spend) AS total_spend
FROM "LiteLLM_SpendLogs"
WHERE "startTime" >= $1::timestamp
  AND "startTime" < $2::timestamp
  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  endTimer   r   nowr   r^   r_   )r   r   r  r  selected_api_keyra   rV   s          r2   global_spend_end_usersr  
  s      9W>O4PQQ IGNN	,,<<@X\\^iR.@@I'GI #%%//9g'7 H O	s   B%B0'B.(B0c                    K   ddl m} |t        dddi      | j                  }|t        dddi      d}|j                  j                  |||       d {   }|S 7 w)	Nr   r   rZ   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         r2   !global_spend_models_internal_userr  N
  sx      9W>O4PQQ''GW>P4QRRI  #%%//	7EJJHO Kr  z/global/spend/modelsz4Number of models to get. Will return Top 'n' models.c                 D  K   ddl m} |j                  t        j                  k(  s|j                  t        j
                  k(  rt        ||        d{   }|S |t        dddi      d	}|j                  j                  |t        |              d{   }|S 7 H7 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   )rX   r  NrZ   r&   r[   r'   z/SELECT * FROM "Last30dModelsBySpend" LIMIT $1 ;)r+   r   rz   r{   r|   r}   r  r   r^   r_   r   )r  rX   r   rV   ra   s        r2   global_spend_modelsr  o
  s     $ 9 	##'7'E'EE&&*:*R*RR:/u
 
 W>O4PQQEI"%%//	3u:FFHO
 Gs%   AB BAB BB B z/provider/budgets)response_modelrZ  c                  d  K   ddl m}  	 | t        dddi      | j                  }|t	        d      i }|j                         D ]  \  }}| j                  t	        d	      | j                  j                  |       d{   xs d
}| j                  j                  |       d{   }t        |j                  |j                  ||      }|||<    t        |      S 7 a7 <# t        $ r=}t        j                  dj!                  t#        |                   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   NrZ   r&   zNo llm_router foundr'   zNo 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_periodr   budget_reset_at)	providersz)/provider/budgets: Exception occured - {})r+   r   r   provider_budget_configr   r   router_budget_logger_get_current_provider_spend%_get_current_provider_budget_reset_atr   r  budget_durationr   r,   r   r$  r   r/   r   )	r   r  provider_budget_response_dictr   _budget_info_provider_spend_provider_budget_ttlprovider_budget_response_objectr1   s	            r2   provider_budgetsr  
  sh    b 6%+2G(H  ",!B!B!) j  RT%'='C'C'E#I|..6 !@AA 55QQ   	  *4)H)H)n)n* $  /K)44(88% 4	/+ 8W))4% (F& &0MNN
$  +&&7>>s1vF	
 (**	+sM   D0A7C' C#&C' (C%)9C' "D0#C' %C' '	D-08D((D--D0r   c                 X   K   | j                   j                  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@   rV   s       r2   rB   rB   
  s4      #%%//		 	H O	s   *(*r   c                   K   d}|t        |      dkD  r|j                  d      }|t        dddi      d}|t        |t              r,d|v r(d	}|j
                  j                  || |       d{   }n(d
}|j
                  j                  || ||       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   ,rZ   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   r~  	log_countc                     | d   S r  rn   ro   s    r2   rq   z&ui_get_spend_by_tags.<locals>.<lambda>J  s    AaDrs   Tr   r   r  )namer   r  r   )rC  splitr   rR   rB  r^   r_   r   r   r   r   r   r   r  r   )r?   r@   r   r   	tags_listrV   ra   total_spend_per_tagtotal_requests_per_tagr   tag_name	tag_spendsorted_tagsui_tagstagcurrent_spends                   r2   r   r     s     &*IH 1NN3'	W>O4PQQHZ	48Z9=T		 '))33
 

	 '))33	
 
 4?3J3J53Q6A6M6Mc6R/0&	H%2%x(C,<<(  ,224.RVWKGA$M5)I!-3MA&3CF;	
	  W%%i
$
s%   A/E.1E*2(E.E,CE.,E.z/spend/logs/session/uiz+Get all spend logs for a particular session
session_idc                 R  K   ddl m} 	 |t        t        j                  d      d| i}|j
                  j                  j                  |ddi	       d{   }|S 7 # t        $ r;}t        |t              r|t        t        j                  t        |            d}~ww xY ww)
z5
    Get all spend logs for a particular session
    r   r   NzDatabase not connectedr'   r  r  ascr9  )r+   r   r   r   rU   r^   r  r!  r,   rR   r/   )r  rX   r   r'  rF  r1   s         r2   ui_view_session_spend_logsr  \  s     $ 9 "AA/  )*5$''99CC";*> D 
 
 
  a'G"AA1v 	s;   B'AA  AA  B'A   	B$)6BB$$B'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:
        Dict[str, Any]: A dictionary containing the status filter condition.
    NrS  ORr   equalsrn   )r  s    r2   r  r    sF     		!8Y"788T:JKLL8]344rs   )r   )N)NN)Pr   ri  r   r   r   	functoolsr   typingr   r   r	   r
   r   r   fastapir   r   r   r   r   litellm._loggingr   rg  r   r   $litellm.proxy.auth.user_api_key_authr   1litellm.proxy.spend_tracking.spend_tracking_utilsr   rh  r   r+   r   routerr   r3   Queryr/   r;   LiteLLM_SpendLogsrW   UserAPIKeyAuthrc   r   r   r   r   r   r   r   r   r   r   postSpendCalculateRequestr   r   r   r*  r6  rf  rQ  rX  rq  rt  r|  r  r  r  r  r  GlobalEndUsersSpendr  r  r  r  rB   r   r  r  rn   rs   r2   <module>r     sa    	 2 2  D D  = =  1 " U B :7L	 
#	$+,-	  

: 
#	$+,-	   +W]]4-
c]-
-
` 
#	$+,-gt-./	   !.@! ,gmm7F
F

 smF
F
R%3;GO: 
#	$+,-gt-./    !.<! ,gmm3 )00A(Be
e

 sme
 &e
e
P%3;GO< 
#	$+,-gt-./    !.<! ,gmm3 )00A(BP
P

 smP
 &P
P
f ,
#	$+,-gt-./    %w}}+ !.<! ,gmm3M
M
 	M
 smM
M
` !
#	$+,-gt-./    %w}}+ !.<! ,gmm3`
`
 	`
 sm`
`
F 
#	$+,-gt-./   !.<! ,gmm3 )00A(Bw
w

 smw
 &w
w
t 
#	$+,-gt-./	   !.<! ,gmm3 BOIB +W]]Q '4gmm`' +W]]N "/ I"3Z
Z

 smZ
 w<=>Z
 c]Z
" sm#Z
* c]+Z
2 #3Z
Z
z
 !
#	$+,-gt-./  (
(
V 
#	$+,-gt-./	   !.@! ,gmm7 ('--8G
G

 smG
 3-G
G
T1
1
1
h 
#	$+,-4
	  G
#8 G
G
T 
#	$+,-gt-./   +W]]5 +W]]5 !.J! +W]]2 "/P" "/M" !.@! ,gmm7 ; #W]] :qS )00A(B#07=="R$ )7=="8WX+c]X+
 c]X+ X+ c]X+" #X+* +X+2 3X+: sm;X+B CX+H IX+N &OX+P C=QX+V C=WX+X+v 3!
#	$+,-	   !.@! ,gmm7((( sm( (V 
#	$+,-gt-./	   +W]]5 +W]]5 !. A! !.@! ,gmm7 $gmm t )00A(B3f
c]f

 c]f
 f
 f
" sm#f
* +f
2 &3f
f
R 
#	$+,-  

@ 
#	$+,-	  HHX "(/0A(B#c]#%#L 
#	$+,-	   +W]]c )00A(BR
c]R

 &R
R
j 
#	$+,-	  '
'
V 57+%+.1+\ 
#	$+,-	   F )00A(B))
 &))X 
#	$+,-	  TTn 
#	$+,-	  %%4 
#	$+,-	  ,x0C'D ,,` 57%.1B 
#	$+,-	   J )00A(B
 &B 0FGW+ 6 W+ HW+v <@( -1"	W&W&W& L)W& sm	W&t 
#	$+,-gt-./   $gmmA )00A(B	   &	  F5(3- 5DcN 5rs   