
    h~P                        d dl Z d dlZd dlZd dlmZ d dlmZ d dlmZ d dlmZmZm	Z	m
Z
mZ d dlmZ d dlZd dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZmZ d dlmZmZ d dlmZmZm Z m!Z!m"Z" d dl#m$Z$ de%de
e%   de&fdZ'	 	 	 	 	 	 	 d7de
e(   de
ee%      de
ee%      de
e   de
ee"      de
e   de
e(   de
e    defdZ)dede%fdZ*de%de(de(de
e%   fdZ+defd Z,de(d!e
e!   de%fd"Z-d#edefd$Z.d%ed&ed'e%d(e%d)ef
d*Z/	 d8d!e
e!   de
e(   de%fd+Z0	 d8d,e(d-e
e1   de(fd.Z2de(d/e(de%fd0Z3de
ee"      de
ee"      fd1Z4d2e
e!   de%fd3Z5de&fd4Z6de(de	d5   fd6Z7y)9    N)datetime)timezone)AnyListLiteralOptionalcast)	BaseModel)verbose_proxy_logger)REDACTED_BY_LITELM_STRING) get_litellm_metadata_from_kwargs)
safe_dumps)SpendLogsMetadataSpendLogsPayload)PrismaClient
hash_token)#StandardLoggingGuardrailInformationStandardLoggingMCPToolCallStandardLoggingModelInformationStandardLoggingPayload!StandardLoggingVectorStoreRequest)!get_end_user_id_for_cost_trackingapi_key_master_keyreturnc                     |yt        j                  | |      }|ryt        j                  | t        |            }|ryy)NFT)secretscompare_digestr   )r   r   is_master_keys      m/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/proxy/spend_tracking/spend_tracking_utils.py_is_master_keyr!      sG     **7K@M **7J{4KLM    metadataapplied_guardrailsbatch_modelsmcp_tool_call_metadatavector_store_request_metadataguardrail_informationusage_objectmodel_map_informationc           
         | Bt        di dd dd dd dd dd dd dd dd d	d d
d dddd dd dd dd dd dd dd dd S t        j                  dt        t	        | j                                     z          t        di t         j                  j                         D ci c]  }|| v r|| |    c}}	||	d
<   ||	d<   ||	d<   t        |      |	d<   ||	d<   ||	d<   ||	d<   |	S c c}w )Nuser_api_keyuser_api_key_aliasuser_api_key_team_iduser_api_key_org_iduser_api_key_user_iduser_api_key_team_aliasspend_logs_metadatarequester_ip_addressadditional_usage_valuesr$   statussuccesserror_informationproxy_server_requestr%   r&   r'   r*   r)   r(   z;getting payload for SpendLogs, available keys in metadata:  )r   r   debugstrlistkeys__annotations__0_get_vector_store_request_for_spend_logs_payload)
r#   r$   r%   r&   r'   r(   r)   r*   keyclean_metadatas
             r    _get_spend_logs_metadatarB   -   s      

#
 "&
 !%	

 "&
 %)
 !%
 "&
 %)
  $
 %
 #
 "&
 
 $(
  +/!
" #'#
$ %
& #''
 	
* E
d8==?#
$	% '  )88==?
h #
N ,>N'(%1N>"/EN+,89VW 23 /DN*+%1N>".CN*+
s   $C(response_objc                 *   	 t        j                  | d      }t        j                  |j	                               j                         }|S # t        $ r= t        j                  t        |       j	                               j                         cY S w xY w)z
    Generate a stable hash from a response object.

    Args:
        response_obj: The response object to hash (can be dict, list, etc.)

    Returns:
        A hex string representation of the MD5 hash
    T)	sort_keys)jsondumpshashlibmd5encode	hexdigest	Exceptionr;   )rC   json_strunique_hashs      r    generate_hash_from_responserO   h   sw    
C ::ld; kk(//"34>>@ C{{3|,3356@@BBCs   A	A ABB	call_typekwargsc                     | dk(  s| dk(  rt        |      }|S t        t        t           |j	                  d            xs& t        t        t           |j	                  d            }|S )Naretrieve_batchacreate_fileidlitellm_call_id)rO   r	   r   r;   get)rP   rC   rQ   rU   s       r    get_spend_logs_idrX      sh     %%n)D7E
 I (3-!1!1$!78 
DSM6::&78=
 Ir"   c                    ddl m}m} | i } | t        |t              st        |t
              si }| j                  di       }t        |       }| j                  d|      }| j                  d      }	| j                  dd      }
t        t
        |      j                  dd       xs i }t        |t        j                        rt        |      }t        |t
              r|}n#t        |t              r|j                         }ni }t        |	xs d	||       }t        t        t           | j                  d
d             }t        |      }|j                  dd      }d}d}d}|6|j                  dd      }|j                  dd      }|j                  dd      }|Nt        |t               r>|j#                  d      rt%        |      }t'        ||      r|j                  d      du rd}|5|xs |d   j                  d      xs d}|xs |d   j                  d      }nd}t        |j                  dg       t(              r%t+        j,                  |j                  dg             nd}|)|j                  d      t+        j,                  |d         }t'        ||      r|j                  d      du rd}|j                  di       j                  dd      }|j                  dd      }t/        |||d   j                  dd       nd |"|j                  di       j                  d d       nd ||d   j                  d!d       nd ||d   j                  d"d       nd ||d   j                  d#d       nd ||d$   nd ||j                  d%d       nd &      }g d'}i }|j1                         D ]=  \  }}||vst        |t              r|j                         }|j3                  ||i       ? ||d(<   t        j4                   t        j4                  j6                  dLi | }nd)}|
du rdd l}| d*|j9                          }d }|j                  d!i       }||j                  d+d       }	 t;        dLi d,t!        |      d|	xs dd-t!        |      dt!        |
      d.t=        |      d/t=        |      d0t=        |      d1| j                  d1d      xs dd2|j                  d3d      xs dd4|j                  d5d      xs ddt?        |      d6|d7| j                  d8d      d|j                  d|      d|j                  d|      d|j                  d|      d|d9|xs dd:|j                  d:d      d|d;|d<|d=|j                  d=d       d>| j                  d>d      d?tA        ||@      dAtC        |      dBtE        ||C      dDtG        | |E      dFtI        |G      } tK        jL                  dHt+        j,                  | dIt         J             | S # tN        $ r4}!tK        jP                  dKjS                  t!        |!                   |!d }!~!ww xY w)MNr   )general_settings
master_keylitellm_paramscompletion_start_timerP   	cache_hitFusageacompletionstandard_logging_objectr,    prompt_tokenscompletion_tokenstotal_tokenszsk-)r   r   $disable_adding_master_key_hash_to_dbTlitellm_proxy_master_keyr#   user_api_key_hashuser_api_key_end_user_idtagsz[]request_tags
model_inforU   model_groupr$   hidden_paramsr%   r&   r'   r)   r*   r(   )r$   r%   r&   r'   r)   r*   r(   )rd   rc   re   r4   z	Cache OFF
_cache_hitnamespaced_tool_name
request_idr   	startTimeendTimecompletionStartTimemodeluserr0   team_idr.   	cache_keyspendresponse_costend_userapi_basemodel_idmcp_namespaced_tool_namer3   custom_llm_providermessagesstandard_logging_payloadr#   responser8   )r#   r\   
session_id)rQ   r   r5   )r#   z+SpendTable: created payload - payload: %s

   )indentdefaultz$Error creating spendlogs object - {}r9   )*litellm.proxy.proxy_serverrZ   r[   
isinstancer
   dictrW   r   r	   litellmUsage
model_dumprX   r   r   r   r;   
startswithr   r!   r<   rF   rG   rB   itemsupdatecacheget_cache_keytimer   _ensure_datetime_utcr   $_get_messages_for_spend_logs_payload$_get_response_for_spend_logs_payload0_get_proxy_server_request_for_spend_logs_payload_get_session_id_for_spend_log_get_status_for_spend_logr   r:   rL   	exceptionformat)"rQ   rC   
start_timeend_timerZ   r[   r\   r#   r]   rP   r^   r_   response_obj_dictrU   r   end_user_idr   standard_logging_prompt_tokens"standard_logging_completion_tokensstandard_logging_total_tokensrk   	_model_id_model_grouprA   special_usage_fieldsr4   kvrx   r   r~   r&   payloades"                                     r    get_logging_payloadr      sE    H~|Y/
<QU8VZZ 0"5N/7H"JJ'>I

;'I

;.I|$(($7=2E%'U,%(	L)	,(335	957H&	QB#'(&**5NPT*U  4NCKll>2.G*+"./&)*!+)A)E)EQ*
& .F-I-I.
* )A(D(D^UV(W%z'37e$ )G7
C $$%KLPTT0G 	!,  '
3778KL 	
 " 
%=j%I%M%M&&
  hll62.5 	

8<<+,  	!,$((8Dzz":>"JKwJ?  !GHDP,\2.224<I<<r2L . (3 %Z0445I4P (3 %(("=AA.RVW (3 %Z0445MtT (3 %Z044/  (3 %Z044^TJ (3 %%<= (3 %(()@$GK'NR R 1((!Y'LLN#**Aq62	 
 1HN,-}} MM//9&9		Dt:diik]+#+//0H"M)#9#=#="D$
 6$4 )%
2w)%
o2)%
 L)%
 )n	)%

 +:6)%
 )2)%
 !55J K)%
 **Wb)/R)%
 4b9?R)%
 LL!7<B)%
  /)%
  )%
 **_a0)%
 >3PQ)%
  ))O5ST)%
  $ii#%G!)%
& &')%
( !&B))%
* $''
B7+)%
, %-)%
. /)%
0 &>1)%
2 "0!3!34JD!Q3)%
4 !'

+@" E5)%
6 :)AH7)%
< ::RS=)%
> "R!."?)%
D 5)AE)%
L -!M)%
V 	"";JJwq#6	

  &&299#a&A	
 	s   'F8X   	Y)/YYr   c                     ddl }|+|j                  d      t        |j                  d            S | j                  d      t        | j                  d            S t        |j                               S )zy
    Get the session id for the spend log.

    This ensures each spend log is associated with a unique session id.

    r   Ntrace_idlitellm_trace_id)uuidrW   r;   uuid4)rQ   r   r   s      r    r   r   b  sq      	!,$((4@+//
;<< zz$%16::0122 tzz|r"   	timestampc                 D    | j                  t        j                        } | S )z#Helper to ensure datetime is in UTC)
astimezoner   utc)r   s    r    r   r   |  s    $$X\\2Ir"   
start_dateend_daterw   customer_idprisma_clientc                 l   K   d}|j                   j                  || |||       d {   }|g S |S 7 
w)Na  
    WITH SpendByModelApiKey AS (
        SELECT
            date_trunc('day', sl."startTime") AS group_by_day,
            COALESCE(tt.team_alias, 'Unassigned Team') AS team_name,
            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
        LEFT JOIN 
            "LiteLLM_TeamTable" tt 
        ON 
            sl.team_id = tt.team_id
        WHERE
            sl."startTime" BETWEEN $1::date AND $2::date
            AND sl.team_id = $3
            AND sl.end_user = $4
        GROUP BY
            date_trunc('day', sl."startTime"),
            tt.team_alias,
            sl.end_user,
            sl.model,
            sl.api_key
    )
        SELECT
            group_by_day,
            jsonb_agg(jsonb_build_object(
                'team_name', team_name,
                'customer', customer,
                'total_spend', total_spend,
                'metadata', metadata
            )) AS teams_customers
        FROM (
            SELECT
                group_by_day,
                team_name,
                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,
                team_name,
                customer
        ) AS aggregated
        GROUP BY
            group_by_day
        ORDER BY
            group_by_day;
    )db	query_raw)r   r   rw   r   r   	sql_querydb_responses          r    get_spend_by_team_and_customerr     sN     :Ix &((22:x+ K 	s   %424c                      y)N{}r9   r   s     r    r   r     s     r"   request_bodyvisitedc                     d
t               t        |       }|v ri S j                  |       dt        dt        ffd| j	                         D ci c]  \  }}| |       c}}S c c}}w )z
    Recursively sanitize request body to prevent logging large base64 strings or other large values.
    Truncates strings longer than 1000 characters and handles nested dictionaries.
    i  valuer   c                    t        | t              rt        |       S t        | t              r| D cg c]
  } |       c}S t        | t              r't        |       kD  r| d   dt        |       z
   dS | S | S c c}w )Nz... (truncated z chars))r   r   -_sanitize_request_body_for_spend_logs_payloadr<   r;   len)r   itemMAX_STRING_LENGTH_sanitize_valuer   s     r    r   zF_sanitize_request_body_for_spend_logs_payload.<locals>._sanitize_value  s    eT"@PPt$6;<dOD)<<s#5z-- 2!234OCJQbDbCccjkkL =s   A=)setrU   addr   r   )r   r   obj_idr   r   r   r   s    `   @@r    r   r     s|     % F	KK	s 	s 	 /;.@.@.BCdaAq!!CCCs   A2r\   c                     t               rgt        t        t           |j	                  di             }|>|j	                  di       xs i }t        |      }t        j                  |t              }|S y)zS
    Only store if _should_store_prompts_and_responses_in_spend_logs() is True
    r8   body)r   r   )	1_should_store_prompts_and_responses_in_spend_logsr	   r   r   rW   r   rF   rG   r;   )r#   r\   _proxy_server_request_request_body_request_body_json_strs        r    r   r     so     9: $TNN../ErJ!
 !,155fbAGRMI-XM%)ZZs%K"))r"   c                     t               r| S | y| D ]^  }|j                  di       xs i }|j                  dg       xs g }|D ]+  }|j                  dg       xs g D ]  }d|v st        |d<    - ` | S )z~
    If user does not want to store prompts and responses, then remove the content from the vector store request metadata
    Nvector_store_search_responsedatacontenttext)r   rW   r   )r'   vector_store_requestr   response_dataresponse_itemcontent_items         r    r?   r?   	  s     9:,, %, = $$%CRHNB 	% 588DJ*M - 1 1)R @ FB F\)+DL( !G + !> )(r"   r   c                 h    | yt               r%t        j                  | j                  di             S y)Nr   r   )r   rF   rG   rW   )r   s    r    r   r   !  s/     8:zz'++j"566r"   c                  X    ddl m}  ddlm} | j	                  d      du xs
  |d      du S )Nr   )rZ   )get_secret_boolstore_prompts_in_spend_logsTSTORE_PROMPTS_IN_SPEND_LOGS)r   rZ   litellm.secret_managers.mainr   rW   )rZ   r   s     r    r   r   +  s7    ;< 	:;tC 	B89TAr"   )r6   failurec                 4    | j                  dd      }|dk(  ryy)zk
    Get the status for the spend log.

    It's only a failure if metadata.get("status") is "failure"
    r5   Nr   r6   )rW   )r#   _statuss     r    r   r   5  s"     &\\(D9G)r"   )NNNNNNN)N)8rH   rF   r   r   dtr   typingr   r   r   r   r	   pydanticr
   r   litellm._loggingr   litellm.constantsr   'litellm.litellm_core_utils.core_helpersr   *litellm.litellm_core_utils.safe_json_dumpsr   litellm.proxy._typesr   r   litellm.proxy.utilsr   r   litellm.types.utilsr   r   r   r   r   litellm.utilsr   r;   boolr!   r   rB   rO   rX   r   r   r   r   r   r   r   r   r?   r   r   r   r9   r"   r    <module>r      s       #  5 5   1 7 T A D 8  <C hsm  & /3(,CG 	KO#'GK8tn8 c+8 49%8 %%?@	8
 $,./$8 $$GH8 4.8 $$CD8 8vCc Cc C.

"&
04
c]
SSl&'=> 	4H  III I 	I
  I\  $&'=>tn 	 "DDc]D 
DB 	&)#+D1R,S#T)d456)0,-4 !"r"   