
    qi!                     v    d Z ddlZddlmZ ddlmZmZmZmZm	Z	m
Z
mZmZmZ ddlmZ ddlmZ  G d de      Zy)	zBThis module defines a controller for managing user idle detection.    N)Optional)	BotStartedSpeakingFrameBotStoppedSpeakingFrameFrameFunctionCallCancelFrameFunctionCallResultFrameFunctionCallsStartedFrameUserIdleTimeoutUpdateFrameUserStartedSpeakingFrameUserStoppedSpeakingFrame)BaseTaskManager)
BaseObjectc                   x     e Zd ZdZdddef fdZedefd       Zdefd	Z	 fd
Z
defdZd Zd Zd Z xZS )UserIdleControllera  Controller for managing user idle detection.

    This class monitors user activity and triggers an event when the user has been
    idle (not speaking) for a configured timeout period after the bot finishes
    speaking. The timer starts when BotStoppedSpeakingFrame is received and is
    cancelled when someone starts speaking again (UserStartedSpeakingFrame or
    BotStartedSpeakingFrame).

    The timer is suppressed while a user turn is in progress to avoid false
    triggers during interruptions (where BotStoppedSpeakingFrame arrives while
    the user is still speaking).

    Event handlers available:

    - on_user_turn_idle: Emitted when the user has been idle for the timeout period.

    Example::

        @controller.event_handler("on_user_turn_idle")
        async def on_user_turn_idle(controller):
            # Handle user idle - send reminder, prompt, etc.
            ...
    r   )user_idle_timeoutr   c                    t         |           || _        d| _        d| _        d| _        d| _        | j                  dd       y)zInitialize the user idle controller.

        Args:
            user_idle_timeout: Timeout in seconds before considering the user idle.
                0 disables idle detection.
        NFr   on_user_turn_idleT)sync)super__init___user_idle_timeout_task_manager_user_turn_in_progress_function_calls_in_progress_idle_timer_task_register_event_handler)selfr   	__class__s     T/opt/pipecat/venv/lib/python3.12/site-packages/pipecat/turns/user_idle_controller.pyr   zUserIdleController.__init__4   sL     	"38<,1#01(8<$$%8t$D    returnc                 N    | j                   st        |  d      | j                   S )z$Returns the configured task manager.z, user idle controller was not properly setup)r   RuntimeErrorr   s    r   task_managerzUserIdleController.task_managerK   s,     !!$'STUU!!!r    r%   c                    K   || _         yw)zInitialize the controller with the given task manager.

        Args:
            task_manager: The task manager to be associated with this instance.
        N)r   )r   r%   s     r   setupzUserIdleController.setupR   s      *s   	c                 r   K   t         |           d{    | j                          d{    y7 7 w)zCleanup the controller.N)r   cleanup_cancel_idle_timer)r   r   s    r   r)   zUserIdleController.cleanupZ   s2     go%%''' 	 's   737577framec                 0  K   t        |t              r9|j                  | _        | j                  dk  r| j	                          d{    yt        |t
              r6| j                  s)| j                  dk(  r| j                          d{    yyyt        |t              r| j	                          d{    yt        |t              r d| _        | j	                          d{    yt        |t              rd| _        yt        |t              rA| xj                  t        |j                        z  c_        | j	                          d{    yt        |t        t         f      rt#        d| j                  dz
        | _        yy7 D7 7 7 7 Ew)z}Process an incoming frame to track user activity state.

        Args:
            frame: The frame to be processed.
        r   NTF   )
isinstancer
   timeoutr   r*   r   r   r   _start_idle_timerr   r   r   r	   lenfunction_callsr   r   max)r   r+   s     r   process_framez UserIdleController.process_frame_   s\     e78&+mmD#&&!+--///e45 ..43S3SWX3X,,... 4Y.67))+++78*.D'))+++78*/D'89,,E4H4H0II,))+++ 79PQR/21d6V6VYZ6Z/[D, S= 0& /+ ,
 ,s\   AFF
AF
F*F5F6/F%F&A(FF<FFFFFc                    K   | j                   dk  ry| j                          d{    | j                  j                  | j	                         |  d      | _        y7 7w)z"Start (or restart) the idle timer.r   Nz::idle_timer)r   r*   r%   create_task_idle_timer_expiredr   r$   s    r   r0   z$UserIdleController._start_idle_timer   s]     ""a'%%''' $ 1 1 = =$$&fL!!
 	(s   $A A8A c                    K   | j                   r5| j                  j                  | j                          d{    d| _         yy7 w)z!Cancel the idle timer if running.N)r   r%   cancel_taskr$   s    r   r*   z%UserIdleController._cancel_idle_timer   s?       ##//0E0EFFF$(D! !Fs   5AAAc                    K   t        j                  | j                         d{    d| _        | j	                  d       d{    y7 %7 w)z8Sleep for the timeout duration then fire the idle event.Nr   )asynciosleepr   r   _call_event_handlerr$   s    r   r7   z&UserIdleController._idle_timer_expired   sD     mmD33444 $&&':;;; 	5;s!   #AAAAAA)__name__
__module____qualname____doc__floatr   propertyr   r%   r'   r)   r   r4   r0   r*   r7   __classcell__)r   s   @r   r   r      sh    6 $%E !E. "o " "* *(
(\ (\T
)<r    r   )rA   r;   typingr   pipecat.frames.framesr   r   r   r   r   r	   r
   r   r   "pipecat.utils.asyncio.task_managerr   pipecat.utils.base_objectr   r    r    r   <module>rJ      s6    I  
 
 
 ? 0B< B<r    