
    hg'                     d    d Z ddlZddlmZmZ ddlmZmZmZ ddlZddl	Z
ddlmZ  G d d      Zy)z<Output modules for writing CBF data to various destinations.    N)datetimetimezone)AnyOptionalUnion)Consolec            
       D   e Zd ZdZddededee   fdZddej                  ded	dfd
Z	dej                  d	e
eej                  f   fdZded	efdZdedej                  ded	dfdZdedej                  ded	e
eef   fdZde
eef   d	ee
eef      fdZded	efdZy)CloudZeroStreamerzTStream CBF data to CloudZero AnyCost API with proper batching and timezone handling.Napi_keyconnection_iduser_timezonec                 P   || _         || _        d| _        t               | _        |  |r	 t        j                  |      | _        yt        j                  | _        y# t
        j                  $ r7 | j                  j                  d| d       t        j                  | _        Y yw xY w)z/Initialize CloudZero streamer with credentials.zhttps://api.cloudzero.comz#[yellow]Warning: Unknown timezone 'z', using UTC[/yellow]N)r   r   base_urlr   consolezoneinfoZoneInfor   ZoneInfoNotFoundErrorprintr   utc)selfr   r   r   s       h/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/integrations/cloudzero/cz_stream_api.py__init__zCloudZeroStreamer.__init__!   s    *3y 	2%-%6%6}%E"
 "*D	 11 2""%HWl#mn%-\\"2s   A AB%$B%data	operationreturnc                 f   |j                         r| j                  j                  d       y| j                  |      }|s| j                  j                  d       y| j                  j                  dt	        |       d| d       |j                         D ]  \  }}| j                  |||        y)z8Send CBF data in daily batches to CloudZero AnyCost API.z-[yellow]No data to send to CloudZero[/yellow]Nz/[yellow]No valid daily batches to send[/yellow]z[blue]Sending z! daily batch(es) with operation 'z'[/blue])is_emptyr   r   _group_by_datelenitems_send_daily_batch)r   r   r   daily_batches
batch_date
batch_datas         r   send_batchedzCloudZeroStreamer.send_batched3   s    ==?LLNO ++D1LLPQ^C,>+??`aj`kkstu&3&9&9&;"J
"":z9E '<    c           	      &   i }d|j                   vr| j                  j                  d       i S d}|j                  d      D ]V  }	 |j	                  d      }|s| j                  |      }|j                  d      }||vrg ||<   ||   j                  |       X |j                         D 	ci c]  \  }}	|	s	|t        j                  |	        c}	}S # t        $ r,}| j                  j                  d| d| d	       Y d}~d}~ww xY wc c}	}w )
z;Group data by date, converting to UTC and validating dates.time/usage_startzE[red]Error: Missing 'time/usage_start' column for date grouping[/red]NTnamed%Y-%m-%dz.[yellow]Warning: Could not process timestamp '': 	[/yellow])columnsr   r   	iter_rowsget_parse_and_convert_timestampstrftimeappend	Exceptionr    pl	DataFrame)
r   r   r"   timestamp_strrowdtr#   edate_keyrecordss
             r   r   z CloudZeroStreamer._group_by_dateE   s   9; T\\1LLfgI'+>>>-C #(: ;$ 66}E[[4
]202M*-j)005 .* JWI\I\I^j4EHgbi",,w//jj  ""%STaSbbefgehhq#rs
 ks*   C?C.
D9D	D
"DD
r7   c                    	 |j                  d      r&t        j                  |j                  dd            }nhd|v s|j                  d      rt        j                  |      }n=t        j                  |      }|j                  |j                  | j
                        }|j                  t        j                        S # t        $ r}t        d| d|       d}~ww xY w)	z*Parse timestamp string and convert to UTC.Z+00:00+)z-00:00z-01:00z-02:00z-03:00z-04:00z-05:00z-06:00z-07:00z-08:00z-09:00z-10:00z-11:00z-12:00z+01:00z+02:00z+03:00z+04:00z+05:00z+06:00z+07:00z+08:00z+09:00z+10:00z+11:00z+12:00N)tzinfozCould not parse timestamp 'r,   )
endswithr   fromisoformatreplacerA   r   
astimezoner   r   
ValueError)r   r7   r9   r:   s       r   r1   z.CloudZeroStreamer._parse_and_convert_timestampf   s    	R%%c*++M,A,A#x,PQ%)?)? Au *v ++M: ++M:99$4+=+=>B ==.. 	R:=/QCPQQ	Rs   B=C   	C	CCr#   r$   c           
      8   |j                         ryd| j                   dd}| j                   d| j                   d}| j	                  |||      }	 t        j                  d      5 }| j                  j                  d	| d
t        |       d       |j                  |||      }|j                          | j                  j                  d| d
t        |       d       ddd       y# 1 sw Y   yxY w# t
        j                  $ r(}	| j                  j                  d| d|	 d        d}	~	wt
        j                  $ rS}	| j                  j                  d| d|	j                  j                   d|	j                  j                    d        d}	~	ww xY w)z+Send a single daily batch to CloudZero API.NzBearer zapplication/json)AuthorizationzContent-Typez /v2/connections/billing/anycost/z/billing_dropsg      >@)timeoutz[blue]Sending batch for z (z records)[/blue])headersjsonu'   [green]✓ Successfully sent batch for z records)[/green]u)   [red]✗ Network error sending batch for z: z[/red]u&   [red]✗ HTTP error sending batch for  )r   r   r   r   _prepare_batch_payloadhttpxClientr   r   r   postraise_for_statusRequestErrorHTTPStatusErrorresponsestatus_codetext)
r   r#   r$   r   rJ   urlpayloadclientrT   r:   s
             r   r!   z#CloudZeroStreamer._send_daily_batch   s      't||n5.
 ?@R@R?SSab --j*iP	d+ v""%=j\CPZOK\\l#mn!;;sG';J))+""%LZLXZ[^_i[jZkk|#}~   !! 	LL!J:,VXYZX[[abc$$ 	LL!G
|SUVWV`V`VlVlUmmnopoyoyo~o~n  @F   G  H	sD   C: *A;C.%C: .C73C: 7C: :F#D00FAFFc                 B   	 t        j                  |d      }|j                  d      }g }|j                  d      D ]'  }| j                  |      }|s|j                  |       ) |||d}	|	S # t        $ r& t        j                         j                  d      }Y tw xY w)z@Prepare batch payload according to CloudZero AnyCost API format.r+   z%Y-%mTr)   )monthr   r   )r   strptimer2   rF   nowr/   _convert_cbf_to_api_formatr3   )
r   r#   r$   r   date_obj	month_strdata_recordsr8   recordrX   s
             r   rM   z(CloudZeroStreamer._prepare_batch_payload   s    	9((Z@H ))'2I ''d'3C44S9F##F+ 4 " 
 #  	9 //8I	9s   'A/ /,BBr8   c                    	 i }|j                         D ]h  \  }}|	t        |t        t        f      rEt        |t              r&|dj	                  d      j	                  d      ||<   Ut        |      ||<   d|||<   j d|v r| j                  |d         |d<   |S # t        $ r)}| j                  j                  d| d       Y d}~yd}~ww xY w)z\Convert CBF row to CloudZero API format - keeping CBF field names as CloudZero expects them.Nz.10f0.r(   z9[yellow]Warning: Could not convert record to API format: r-   )
r    
isinstanceintfloatrstripstr_ensure_utc_timestampr4   r   r   )r   r8   
api_recordkeyvaluer:   s         r   r^   z,CloudZeroStreamer._convert_cbf_to_api_format   s    	J "iik
U$!%#u6%eU316t.D.DS.I.P.PQT.UJsO.1%jJsO*/
3 * "Z/151K1KJWiLj1k
-. 	LL!Z[\Z]]fgh	s   B A>B 	C%C		Cc                 l   |s1t        j                  t        j                        j	                         S 	 | j                  |      }|j	                         j                  dd      S # t        $ rD t        j                  t        j                        j	                         j                  dd      cY S w xY w)z*Ensure timestamp is in UTC format for API.r?   r>   )r   r]   r   r   	isoformatr1   rD   r4   )r   r7   r9   s      r   rk   z'CloudZeroStreamer._ensure_utc_timestamp   s    <<-7799	Q22=AB<<>))(C88 	Q<<-779AA(CPP	Qs   0A& &A
B32B3)N)replace_hourly)__name__
__module____qualname____doc__rj   r   r   r5   r6   r%   dictr   r   r1   r!   r   rM   r^   rk    r&   r   r
   r
      s    ^. .C .QT .$F F# FUY F$k2<< kDbll9J4K kBR# R( R4C R\\ VY ^b @ ",, [^ cghkmphpcq 2d38n $sTWx.AY <
Q3 
Q3 
Qr&   r
   )ru   r   r   r   typingr   r   r   rN   polarsr5   rich.consoler   r
   rw   r&   r   <module>r{      s.   & C  ' ' '    CQ CQr&   