
    ^j                        d dl mZ d dlZd dlZd dlZd dlmZ d dlmZm	Z	 d dl
Zd dlmZ d dlmZ  ee      Zg dZ G d d	e	      Z G d
 d      Zy)    )annotationsN)Iterable)AnyProtocol)
Detections)_get_loggerx_miny_minx_maxy_maxclass_id
confidence
tracker_idc                      e Zd ZddZy)WriterProtocolc                     y N )selfrows     o/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/supervision/detection/tools/csv_sink.pywriterowzWriterProtocol.writerow   s        N)r   zIterable[Any]returnr   )__name__
__module____qualname__r   r   r   r   r   r      s    6r   r   c                      e Zd ZdZdddZddZ	 	 	 	 	 	 	 	 ddZddZddZe	dd       Z
e		 d	 	 	 	 	 dd	       Z	 d	 	 	 	 	 dd
Ze		 d	 	 	 	 	 dd       Zy)CSVSinkaP  
    A utility class for saving detection data to a CSV file. This class is designed to
    efficiently serialize detection objects into a CSV format, allowing for the
    inclusion of bounding box coordinates and additional attributes like `confidence`,
    `class_id`, and `tracker_id`.

    !!! tip

        CSVSink allows passing custom data alongside detection fields, providing
        flexibility for logging various types of information.
        When a list or tuple value in custom_data (or detections.data) has the
        same length as the detection count, each element is written to the
        corresponding detection row; any other value is broadcast to all rows.

    Args:
        file_name: The name of the CSV file where the detections will be stored.
            Defaults to 'output.csv'.

    Example:
        ```pycon
        >>> import supervision as sv
        >>> import numpy as np
        >>> import tempfile
        >>> import os
        >>> # Create synthetic detections
        >>> detections = sv.Detections(
        ...     xyxy=np.array([[10, 20, 30, 40], [50, 60, 70, 80]]),
        ...     confidence=np.array([0.9, 0.8]),
        ...     class_id=np.array([0, 1])
        ... )
        >>> # Use temporary file
        >>> temp_file = tempfile.NamedTemporaryFile(
        ...     mode='w', suffix='.csv', delete=False
        ... )
        >>> temp_file.close()
        >>> csv_sink = sv.CSVSink(temp_file.name)
        >>> with csv_sink as sink:
        ...     sink.append(detections, custom_data={'frame': 0})
        >>> os.unlink(temp_file.name)  # Clean up

        ```
    c                J    || _         d| _        d| _        d| _        g | _        y)zr
        Initialize the CSVSink instance.

        Args:
            file_name: The name of the CSV file.
        NF)	file_namefilewriterheader_writtenfield_names)r   r"   s     r   __init__zCSVSink.__init__K   s)     #-1	-1#&(r   c                &    | j                          | S r   )openr   s    r   	__enter__zCSVSink.__enter__X   s    		r   c                $    | j                          y r   )close)r   exc_typeexc_valexc_tbs       r   __exit__zCSVSink.__exit__\   s     	

r   c                D   t         j                  j                  | j                        }|r4t         j                  j	                  |      st        j
                  |       t        | j                  dd      | _        t        j                  | j                        | _	        y)z0
        Open the CSV file for writing.
        w )newlineN)
ospathdirnamer"   existsmakedirsr)   r#   csvr$   )r   parent_directorys     r   r)   zCSVSink.opend   sc     77??4>>:BGGNN3C$DKK()b9	jj+r   c                R    | j                   r| j                   j                          yy)z%
        Close the CSV file.
        N)r#   r-   r*   s    r   r-   zCSVSink.closeo   s     99IIOO r   c                    t        | t        j                        r| j                  dk(  r| S | |   S t        | t        t
        f      rt        |       |k(  r| |   S | S )a{  
        Return the i-th element when the value stores per-detection data.

        Dispatch rules:
            - np.ndarray with ndim == 0: return as-is for broadcasting
            - np.ndarray with ndim >= 1: return value[i]
            - list or tuple with len equal to n: return value[i]
            - any other type: return as-is for broadcasting

        Args:
            value: Custom-data field value.
            i: Zero-based detection index.
            n: Total number of detections.

        Returns:
            Element at position i if value is a per-detection sequence,
            otherwise value unchanged.
        r   )
isinstancenpndarrayndimlisttuplelen)valueins      r   _slice_valuezCSVSink._slice_valuev   sQ    ( eRZZ(!JJ!O59q9edE]+E
a8Or   Nc                   g }t        | j                        }t        |      D ]F  }| j                  |   d   | j                  |   d   | j                  |   d   | j                  |   d   | j                  dnt	        | j                  |         | j
                  dnt	        | j
                  |         | j                  dnt	        | j                  |         d}t        | d      r<| j                  j                         D ]  \  }}t        j                  |||      ||<   ! |r2|j                         D ]  \  }}t        j                  |||      ||<   ! |j                  |       I |S )aK  
        Convert detections and optional custom data into per-detection rows.

        Builds one dictionary per detection containing bounding box coordinates,
        detection attributes, and any values from ``detections.data`` or
        ``custom_data``. List and tuple values in ``custom_data`` with length
        equal to ``len(detections.xyxy)`` are sliced one element per row; all
        other values are broadcast to every row.

        Args:
            detections: Detection data to serialize into row dictionaries.
            custom_data: Optional extra fields to include in each row.

        Returns:
            A list of dictionaries, one per detection, containing ``xyxy``
            coordinates, ``class_id``, ``confidence``, ``tracker_id``, and any
            values from ``detections.data`` or ``custom_data``.
        r            r4   r	   data)rE   xyxyranger   strr   r   hasattrrN   itemsr    rI   append)
detectionscustom_dataparsed_rowsrH   rG   r   keyrF   s           r   parse_detection_datazCSVSink.parse_detection_data   sz   , 
 q 	$A#+A.#+A.#+A.#+A.&&. ,,Q/0((0 !..q12((0 !..q12C  z6*",//"7"7"9 AJC&33E1a@CHA "-"3"3"5 AJC&33E1a@CHA s#3	$4 r   c           
        | j                   st        d| j                   d      t        j	                  ||      }| j
                  s)|| _        | j                   j                  |       d| _        || j                  k7  r!t        j                  d| j                  |       t        j                  ||      }|D ]E  }| j                   j                  | j                  D cg c]  }|j                  |d       c}       G yc c}w )a  
        Append detection data to the CSV file.

        Args:
            detections: The detection data.
            custom_data: Custom data to include. Scalars, dictionaries, and
                other non-sequence values are broadcast to every detection in
                this batch. NumPy arrays, lists, and tuples with length equal
                to ``len(detections)`` are sliced per detection; other lists
                and tuples are broadcast unchanged.
        z Cannot append to CSV: The file 'z' is not open.Tz<Field names do not match the header. Expected: %s, given: %sr4   N)r$   	Exceptionr"   r    parse_field_namesr%   r&   r   loggerwarningrY   get)r   rU   rV   r&   rW   r   
field_names          r   rT   zCSVSink.append   s     {{24>>2B.Q  //
KH""*DKK  -"&D$***NNN   22:{K 	CKK  ;?;K;KLZR(L	Ls   D
c           
         |rt        |j                               n	t               }t        |t        t        | di       j                               z        }t        |z   S )NrN   )setkeyssortedgetattrBASE_HEADER)rU   rV   custom_keysdynamic_headers       r   r\   zCSVSink.parse_field_names   sS     2=c+**,-#%#gj&"=BBDEE
 ^++r   )z
output.csv)r"   rQ   r   None)r   r    )r.   ztype | Noner/   zException | Noner0   z
Any | Noner   ri   )r   ri   )rF   r   rG   intrH   rj   r   r   r   )rU   r   rV   dict[str, Any] | Noner   zlist[dict[str, Any]])rU   r   rV   rk   r   ri   )rU   r   rV   rk   r   z	list[str])r   r   r   __doc__r'   r+   r1   r)   r-   staticmethodrI   rY   rT   r\   r   r   r   r    r       s    )V) " 	
 
	,  2 EI11-B1	1 1h LP#$#3H#	#J EI,,-B,	, ,r   r    )
__future__r   r;   ior6   collections.abcr   typingr   r   numpyr@   supervision.detection.corer   supervision.utils.loggerr   r   r]   rf   r   r    r   r   r   <module>ru      sI    " 
 	 	 $    1 0	X	7X 7R, R,r   