o
    ưig'                     @   s^   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 dZdS )z<Output modules for writing CBF data to various destinations.    N)datetimetimezone)AnyOptionalUnion)Consolec                
   @   s   e Zd ZdZddededee fddZdd	ejd
eddfddZ	d	ejde
eejf fddZdedefddZdedejd
eddfddZdedejd
ede
eef fddZde
eef dee
eef  fddZdedefddZdS ) CloudZeroStreamerzTStream CBF data to CloudZero AnyCost API with proper batching and timezone handling.Napi_keyconnection_iduser_timezonec                 C   st   || _ || _d| _t | _|  |r4z	t|| _W dS  tjy3   | j	d| d t
j| _Y dS w t
j| _dS )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zoneinfoZZoneInfor   ZZoneInfoNotFoundErrorprintr   utc)selfr	   r
   r    r   c/home/app/Keep/.python/lib/python3.10/site-packages/litellm/integrations/cloudzero/cz_stream_api.py__init__!   s   zCloudZeroStreamer.__init__replace_hourlydata	operationreturnc                 C   sx   |  r| jd dS | |}|s| jd dS | jdt| d| d | D ]\}}| ||| q.dS )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_datar   r   r   send_batched3   s   
zCloudZeroStreamer.send_batchedc                 C   s   i }d|j vr| jd i S d}|jddD ]E}z$|d}|s#W q| |}|d}||vr5g ||< || | W q ty\ } z| jd| d| d	 W Y d}~qd}~ww d
d |	 D S )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]c                 S   s    i | ]\}}|r|t |qS r   )pl	DataFrame).0Zdate_keyrecordsr   r   r   
<dictcomp>d   s     z4CloudZeroStreamer._group_by_date.<locals>.<dictcomp>)
columnsr   r   	iter_rowsget_parse_and_convert_timestampstrftimeappend	Exceptionr   )r   r   r   timestamp_strrowdtr   er   r   r   r   E   s*   



z CloudZeroStreamer._group_by_dater4   c              
   C   s   z6| drt|dd}n d|v s| drt|}nt|}|jdu r0|j| jd}|tjW S  t	yL } z
t	d| d| d}~w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replacer;   r   
astimezoner   r   
ValueError)r   r4   r6   r7   r   r   r   r0   f   s   


z.CloudZeroStreamer._parse_and_convert_timestampr   r    c           
      C   sD  |  rdS d| j dd}| j d| j d}| |||}zEtjdd4}| jd	| d
t	| d |j
|||d}|  | jd| d
t	| d W d   W dS 1 s^w   Y  W dS  tjy }	 z| jd| d|	 d  d}	~	w tjy }	 z| jd| d|	jj d|	jj d  d}	~	w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httpxZClientr   r   r   postraise_for_statusRequestErrorZHTTPStatusErrorresponsestatus_codetext)
r   r   r    r   rC   urlpayloadclientrK   r7   r   r   r   r      s.   
 &(z#CloudZeroStreamer._send_daily_batchc           
      C   sz   zt |d}|d}W n ty   t  d}Y nw g }|jddD ]}| |}|r4|| q&|||d}	|	S )z@Prepare batch payload according to CloudZero AnyCost API format.r%   z%Y-%mTr#   )monthr   r   )r   strptimer1   r@   nowr.   _convert_cbf_to_api_formatr2   )
r   r   r    r   Zdate_obj	month_strZdata_recordsr5   recordrO   r   r   r   rF      s"   

z(CloudZeroStreamer._prepare_batch_payloadr5   c              
   C   s   zCi }|  D ],\}}|dur3t|ttfr/t|tr(|ddd||< qt|||< q|||< qd|v rA| |d |d< |W S  ty` } z| j	d| d W Y d}~dS d}~w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_timestampr3   r   r   )r   r5   Z
api_recordkeyvaluer7   r   r   r   rT      s$   
z,CloudZeroStreamer._convert_cbf_to_api_formatc                 C   s\   |s
t tj S z| |}| ddW S  ty-   t tj dd Y S w )z*Ensure timestamp is in UTC format for API.r9   r8   )r   rS   r   r   	isoformatr0   r>   r3   )r   r4   r6   r   r   r   r^      s   
z'CloudZeroStreamer._ensure_utc_timestamp)N)r   )__name__
__module____qualname____doc__r]   r   r   r(   r)   r!   dictr   r   r0   r   r   rF   rT   r^   r   r   r   r   r      s    !$ &r   )re   r   r   r   typingr   r   r   rG   Zpolarsr(   Zrich.consoler   r   r   r   r   r   <module>   s   