
    TiU                        d Z ddlmZ ddlZddlZddlZddlmZmZ ddl	m
Z
mZ  ej                  e      Ze G d d             Z G d d	      Zy)
a>  FR client for the Face Recognition server.

Sends a single JPEG frame to the FR WebSocket server and returns the list of
detections.  The server runs SCRFD + ViT + ByteTrack; per-connection tracking
state resets when the connection closes, which is fine for the demo pattern of
one ``IDENTIFY_PERSON`` call per scene.
    )annotationsN)	dataclassfield)AnyOptionalc                  >    e Zd ZU dZ ed       Zded<   dZded<   y	)
FRConfigzConfiguration for the FR client.

    Attributes:
        endpoint: WebSocket URL for the FR server.
        timeout_s: Connection + response timeout in seconds.
    c                 .    t        j                  dd      S )NFR_ENDPOINTzws://kluster.klass.dev:42067/)osgetenv     F/home/nelsen/Projects/kognitive/orchestrator/src/services/fr_client.py<lambda>zFRConfig.<lambda>   s    		:!
 r   )default_factorystrendpoint
   int	timeout_sN)__name__
__module____qualname____doc__r   r   __annotations__r   r   r   r   r	   r	      s+     
Hc 
 Isr   r	   c                  "    e Zd ZdZdddZddZy)FRClientu  Async WebSocket client for the Face Recognition server.

    Usage::

        client = FRClient()
        detections = await client.identify(jpeg_bytes)
        # [{"identity": "alice", "confidence": 0.92, "bbox": [x1, y1, x2, y2]}, ...]

    The FR server expects:
    - **In:**  Raw binary JPEG/PNG bytes (one frame per message, any resolution)
    - **Out:** ``{"timestamp": ..., "detections": [{"identity": str|null,
               "confidence": float, "bbox": [x1, y1, x2, y2]}]}``

    A new WebSocket connection is opened per call.  This is adequate for the
    demo frequency of 1–2 calls per scene and avoids long-lived connection
    management complexity.
    Nc                *    |xs
 t               | _        y N)r	   config)selfr!   s     r   __init__zFRClient.__init__8   s    *
r   c                T  K   |st         j                  d       g S 	 ddl}	 |j                  | j                  j                  | j                  j                  | j                  j                        4 d{   }|j                  |       d{    ddl
}|j                  |j                         | j                  j                         d{   }ddd      d{    t        j                        }|j                  dg       }t         j!                  dt#        |      t#        |             |S # t        $ r t         j	                  d       g cY S w xY w7 7 7 7 # 1 d{  7  sw Y   xY w# t$        $ r"}t         j	                  d	|       g cY d}~S d}~ww xY ww)
a  Send a JPEG frame to the FR server and return detections.

        Args:
            jpeg_bytes: Raw JPEG bytes of the frame to analyse.

        Returns:
            List of detection dicts, each with keys:
            - ``identity``: str name or ``None`` if unrecognised
            - ``confidence``: float in [0, 1]
            - ``bbox``: ``[x1, y1, x2, y2]`` pixel coordinates

            Returns an empty list on any error (connection failure, timeout,
            malformed response).
        u6   FRClient.identify called with empty bytes — skippingr   Nu^   websockets is not installed — cannot call FR server. Install it with: pip install websockets)open_timeoutclose_timeout)timeout
detectionsz0FR identified %d detection(s) from %d-byte framezFR identify request failed: %s)loggerwarning
websocketsImportErrorerrorconnectr!   r   r   sendasynciowait_forrecvjsonloadsgetinfolen	Exception)	r"   
jpeg_bytesr+   wsr0   rawdatar(   excs	            r   identifyzFRClient.identify;   s     NNSTI		!))$$![[22"kk33 *  W W ggj))) #,,RWWY@U@U,VVW W ::c?D/3xxb/IJKKBJJ
 ;  	LL: I	W *
 WW W W W.  	LL93?I	s   F(D7 AE: 6E7E: :E%EA E%E!E%E:  E#!AE: 6F(7 EF(EF(E: E%!E%#E: %E7+E.,E73E: :	F%F F%F( F%%F(r    )r!   zOptional[FRConfig]returnNone)r9   bytesr?   zlist[dict[str, Any]])r   r   r   r   r#   r>   r   r   r   r   r   %   s    $+6r   r   )r   
__future__r   r3   loggingr   dataclassesr   r   typingr   r   	getLoggerr   r)   r	   r   r   r   r   <module>rG      sU    #   	 (  			8	$    L Lr   