o
    y	i#                     @   sb   d dl Z d dlZd dlZd dlmZmZmZ d dlmZ d dl	m
Z
 d dlmZ G dd dZdS )    N)OptionalListCallable)datetime)Config)Logc                   @   s   e Zd ZdZdd Zdededdfdd	Zd
edefddZ	dededdfddZ
dededdfddZdededdfddZdededdfddZdededdfddZdeddfddZd"ddZd#dededdfddZdefd d!ZdS )$VoiceActivityDetectorz
    Voice Activity Detection service for handling long user speech.
    
    Detects when user starts and stops speaking using volume-based analysis.
    Waits for natural silence before transcribing complete user input.
    c              	   C   s   t j| _t j| _t j| _t j| _t j	| _
d| _d | _d | _d | _g | _d| _d | _d | _td| j d| j d| j d d S )NFu    🎤 VAD initialized - Enabled: z, Silence threshold: z, Silence duration: s)r   ZVAD_ENABLEDenabledZVAD_SILENCE_THRESHOLDsilence_thresholdZVAD_SILENCE_DURATIONsilence_durationZVAD_MAX_SPEECH_DURATIONmax_speech_durationZVAD_MIN_SPEECH_DURATIONmin_speech_durationis_speakingspeech_start_timelast_speech_timesilence_start_timeaudio_bufferprocessing_lockon_speech_starton_speech_endr   infoself r   services/vad_service.py__init__   s   (zVoiceActivityDetector.__init__
audio_data
session_idreturnNc              
   C   s  | j sdS | jrtd|  dS zzd| _t|}| |}t 	 }| j
| t| j
dkrNtdt| j
 d|  | | W W d| _dS || jkrd| js]| || n| || n| jrn| || n| || | jr| jr|| j | jkrtd| j d	|  | | W n ty } ztd
| d|  W Y d}~nd}~ww W d| _dS W d| _dS d| _w )z
        Add audio chunk and analyze for voice activity.
        
        Args:
            audio_data: Base64 encoded audio data
            session_id: Session identifier for logging
        Nu7   🎤 VAD processing locked, skipping chunk for session Ti  u   🎤 VAD buffer too large (z- chunks) - forcing transcription for session Fu"   🎤 Max speech duration reached (z's) - forcing transcription for session u,   ❌ Error in VAD audio analysis for session z: )r
   r   r   debugbase64Z	b64decode_calculate_volumer   ZnowZ	timestampr   appendlenZwarning_force_transcriptionr   r   _start_speech_continue_speech_handle_silence_continue_silencer   r   r   	Exceptionerror)r   r   r   audio_bytesvolumecurrent_timeer   r   r   add_audio_chunk)   sL   





"
z%VoiceActivityDetector.add_audio_chunkr,   c              
   C   s~   z#ddl }||d}t|dkr!||d}|d }t|dW S W dS  ty> } ztd|  W Y d}~dS d}~ww )z
        Calculate audio volume (RMS) from audio bytes.
        
        Args:
            audio_bytes: Raw audio data
            
        Returns:
            Volume level (0.0 to 1.0)
        r   N   g    @g      ?g        u!   ⚠️ Error calculating volume: )audioopZulaw2linr$   rmsminr*   r   r    )r   r,   r2   Zpcm_datar3   r-   r/   r   r   r   r"   e   s   
z'VoiceActivityDetector._calculate_volumer.   c                 C   s@   d| _ || _|| _d| _td|  | jr| | dS dS )zHandle speech start detection.TNu    🎤 Speech started for session )r   r   r   r   r   r    r   r   r.   r   r   r   r   r&      s   z#VoiceActivityDetector._start_speechc                 C   s   || _ d| _dS )zHandle continuing speech.N)r   r   r5   r   r   r   r'      s   
z&VoiceActivityDetector._continue_speechc                 C   s8   | j du r|| _ || j  }|| jkr| || dS dS )zHandle silence during speech.N)r   r   _end_speech)r   r.   r   r   r   r   r   r(      s   


z%VoiceActivityDetector._handle_silencec                 C   s   dS )zHandle continuing silence.Nr   r5   r   r   r   r)      s   z'VoiceActivityDetector._continue_silencec              	   C   s   | j r| jsdS || j }|| jkrAtd| d|ddt| j  | jr;| jr;| j }| 	  | || dS | 	  dS t
d|dd|  | 	  dS )zHandle speech end detection.Nu   🎤 Speech ended for session z - Duration: z.1fzs, Buffer size: u   🎤 Speech too short (zs) - ignoring for session )r   r   r   r   r   r$   r   r   copy_reset_stater    )r   r.   r   Zspeech_durationbuffer_copyr   r   r   r6      s   

$
z!VoiceActivityDetector._end_speechc                 C   sV   t d| dt| j  | jr%| jr%| j }|   | || dS |   dS )z/Force transcription due to max speech duration.u'   🎤 Forcing transcription for session z - Buffer size: N)r   r   r$   r   r   r7   r8   )r   r   r9   r   r   r   r%      s   
z*VoiceActivityDetector._force_transcriptionc                 C   s,   d| _ d| _d| _d| _| j  d| _dS )zReset VAD state.FN)r   r   r   r   r   clearr   r   r   r   r   r8      s   

z"VoiceActivityDetector._reset_stater   r   c                 C   s   || _ || _dS )z
        Set callback functions for speech events.
        
        Args:
            on_speech_start: Called when speech starts (session_id)
            on_speech_end: Called when speech ends (session_id, audio_buffer)
        N)r   r   )r   r   r   r   r   r   set_callbacks   s   
z#VoiceActivityDetector.set_callbacksc              	   C   s*   | j | j| j| j| jt| j| j| jdS )z$Get current VAD state for debugging.)r
   r   r   r   r   Zbuffer_sizer   r   )	r
   r   r   r   r   r$   r   r   r   r   r   r   r   	get_state   s   zVoiceActivityDetector.get_state)r   N)NN)__name__
__module____qualname____doc__r   strr0   bytesfloatr"   r&   r'   r(   r)   r6   r%   r8   r   r;   dictr<   r   r   r   r   r   
   s    <

	r   )ZasyncioZnumpyZnpr!   typingr   r   r   r   Zconfigr   Zservices.log_utilsr   r   r   r   r   r   <module>   s    