@@ -25,6 +25,11 @@ def __init__(self, tts_service, transport=None):
2525 self .audio_chunks = [] # 100ms audio chunks for fast interruption
2626 self .user_has_input = False # Ensure audio only starts after user input
2727
28+ # SMART DELAY STATE - 500ms grace period before audio starts
29+ self .delay_task : Optional [asyncio .Task ] = None
30+ self .is_in_delay_period = False
31+ self .delay_duration_ms = 500 # Wait 500ms before starting audio
32+
2833 # FUNCTION CALL SET STATE - Track function call set audio
2934 self .is_function_call_set_active = False # Track if we're in a function call set
3035 self .function_call_set_audio_playing = False # Track if function call set audio is playing
@@ -69,8 +74,8 @@ def set_user_input(self):
6974 self .user_has_input = True
7075 logger .info ("User input detected - audio enabled" )
7176
72- async def start_audio (self ):
73- """Start seamless chunked audio playback (only if user has provided input) ."""
77+ async def start_audio_with_delay (self ):
78+ """Start audio with 500ms grace period for fast responses ."""
7479
7580 # Check prerequisites
7681 if not self .user_has_input :
@@ -79,6 +84,42 @@ async def start_audio(self):
7984 if not self .audio_chunks :
8085 return
8186
87+ if self .is_playing or self .is_in_delay_period :
88+ return
89+
90+ # Start delay period
91+ self .is_in_delay_period = True
92+ logger .info (f"Starting { self .delay_duration_ms } ms grace period before audio" )
93+
94+ # Cancel any existing delay task
95+ if self .delay_task and not self .delay_task .done ():
96+ self .delay_task .cancel ()
97+
98+ # Start delay task
99+ self .delay_task = asyncio .create_task (self ._delay_then_start_audio ())
100+
101+ async def start_audio (self ):
102+ """Legacy method - now uses smart delay."""
103+ await self .start_audio_with_delay ()
104+
105+ async def _delay_then_start_audio (self ):
106+ """Wait for delay period, then start audio if not cancelled."""
107+ try :
108+ # Wait for the grace period
109+ await asyncio .sleep (self .delay_duration_ms / 1000 )
110+
111+ # If we reach here, no response came within grace period
112+ if self .is_in_delay_period and self .user_has_input :
113+ logger .info (f"Grace period ended - starting audio" )
114+ await self ._start_audio_immediately ()
115+
116+ except asyncio .CancelledError :
117+ logger .info ("Grace period cancelled - fast response received" )
118+ finally :
119+ self .is_in_delay_period = False
120+
121+ async def _start_audio_immediately (self ):
122+ """Start audio immediately without delay."""
82123 if self .is_playing :
83124 return
84125
@@ -92,14 +133,23 @@ async def start_audio(self):
92133
93134 # Start seamless audio streaming
94135 self .loop_task = asyncio .create_task (self ._stream_seamless_audio ())
95- # logger.info("Started audio playback")
136+ logger .info ("Started audio playback" )
96137
97138 async def stop_and_disable_audio (self ):
98139 """Stop audio immediately and disable until next user input."""
99140 # Set stop flags
100141 self .is_playing = False
101142 self .user_has_input = False # Require new user input for next audio
102143 self .loop_count = 0
144+ self .is_in_delay_period = False
145+
146+ # Cancel delay task if active
147+ if self .delay_task and not self .delay_task .done ():
148+ self .delay_task .cancel ()
149+ try :
150+ await self .delay_task
151+ except asyncio .CancelledError :
152+ pass
103153
104154 # Cancel audio task
105155 if self .loop_task and not self .loop_task .done ():
0 commit comments