o
    jԩ                     @   sd  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
mZ d dlmZ d dlmZmZ d dlZd dlZdedefddZd4d	d
Ze  d dlZd dlm Z d dlZd dlmZ d dlmZmZmZm Z  d dl!m"Z" d dl#m$Z$ d dl%m&Z' ddl(m)Z) ddl*m+Z+ ddl,m-Z- ddl.m/Z/m0Z0m1Z1 ddl2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z: e;dZ<e)  e- Z=e>e?ddZ@e?ddZAe?ddZBe=CdpdDdd ZEe=d! ZFe=Cd"pdZGe=d# ZHe=Cd$pd%ZIe=d& ZJe=d' ZKe=d( ZLe=d) ZMe=d* ZNeG d+d, d,ZOG d-d. d.ZPd/d0 ZQd1d2 ZReSd3kr0e TeR  dS dS )5    N)	dataclass)deque)AnyOptionaltextreturnc                    s\   | sdS t dd | D }|dkrdS g d}|   t  fdd|D }|dkr,dS dS )	zn
    Detect if text is Hindi/Hinglish or English.
    Returns: 'hi' for Hindi/Hinglish, 'en' for English.
    enc                 s   s,    | ]}d |  krdkrn ndV  qdS )u   ऀu   ॿ   N ).0charr
   r
   T/var/www/html/livekitdocker/backend/agent_runtime/src/mcube_integration/ws_bridge.py	<genexpr>   s   * z"detect_language.<locals>.<genexpr>r   hi)!namastekaisehoaapmainhaikyakarrahar   nahipleasethankyoujibhaiyaardostachatheekr   sahigalatbataosamajhr   kripyakarein	dhanyawadshukriyahaannaboloc                 3   s     | ]}|   v rd V  qdS )r	   N)splitr   word
text_lowerr
   r   r   (   s    r	   )sumlower)r   hindi_charshinglish_wordshinglish_countr
   r1   r   detect_language   s   r8   c                  C   sL   d} | t jv r	dS G dd d}t| }|jdg|d |t j| < dS )a  
    LiveKit Agents currently imports `livekit.agents.tokenize.blingfire`, which loads a native
    extension (`lk_blingfire`). On some Windows setups (WDAC / App Control) that extension is blocked
    and the entire `livekit.agents` import fails.

    The MCube WS bridge doesn't depend on blingfire, so we provide a minimal stub module to keep
    `livekit.agents` importable.
    z!livekit.agents.tokenize.blingfireNc                	   @   sl   e Zd Zdddddedededd	fd
dZd	ddeded	B dee fddZd	dded	B fddZ	d	S )z:_install_livekit_blingfire_stub.<locals>.SentenceTokenizer   
   F)min_sentence_lenstream_context_lenretain_formatr;   r<   r=   r   Nc                S   s   t || _t|| _d S N)int_min_sentence_lenbool_retain_format)selfr;   r<   r=   r
   r
   r   __init__@   s   
zC_install_livekit_blingfire_stub.<locals>.SentenceTokenizer.__init__languager   rF   c                   s,   dd t d|p	dD } fdd|D S )Nc                 S   s   g | ]
}|  r|  qS r
   )stripr   pr
   r
   r   
<listcomp>L   s    zW_install_livekit_blingfire_stub.<locals>.SentenceTokenizer.tokenize.<locals>.<listcomp>z(?<=[.!?])\s+ c                    s   g | ]}t | jkr|qS r
   )lenr@   rH   rC   r
   r   rJ   M   s    )rer.   )rC   r   rF   partsr
   rM   r   tokenizeJ   s   zC_install_livekit_blingfire_stub.<locals>.SentenceTokenizer.tokenizec                S   s   t d)Nz2Streaming tokenizer not supported in fallback stub)NotImplementedErrorrC   rF   r
   r
   r   streamO   s   zA_install_livekit_blingfire_stub.<locals>.SentenceTokenizer.stream)
__name__
__module____qualname__r?   rA   rD   strlistrP   rS   r
   r
   r
   r   SentenceTokenizer?   s    
$
rY   )__all__rY   )sysmodulestypes
ModuleType__dict__update)module_namerY   stubr
   r
   r   _install_livekit_blingfire_stub1   s   


rc   )SpeechEventType)cartesiadeepgram
elevenlabsnoise_cancellation)rtc)StreamAdapter)VADr	   )load_agent_runtime_dotenv)&get_runtime_overrides_from_cluster_bot)get_default_mcube_call_config)MCUBE_AUDIO_SPECfrom_base64_strpcm16_to_mulaw)AI_UTTERANCES_QUEUERABBITMQ_URLcontrol_queue_namedeclare_durable_queueconnectget_channelpublish_jsontts_queue_namezmcube.ws_bridgeMCUBE_WS_BRIDGE_PORT9001MCUBE_WS_BRIDGE_HOSTz0.0.0.0	REDIS_URLzredis://localhost:6379/0system_promptrK   \n
	llm_modelllm_provider	tts_modeltts_providerrg   tts_voice_idtts_encodingstt_language_codestt_model_idstt_providerc                   @   s$   e Zd ZU eed< ejd ed< dS )PendingPlaynameNfuture)rT   rU   rV   rW   __annotations__asyncioFuturer
   r
   r
   r   r      s   
 r   c                   @   s,  e Zd ZdedejdejfddZdd Z	dd	 Z
d
d ZdefddZd7ddZd7ddZdeddfddZdefddZdefddZdd Zdefdd Zdd!d"ded#edB defd$d%Zd&d' Zd(edee fd)d*Zdd+d,ee ddfd-d.Zd7d/d0Zd(eddfd1d2Zd3d4 Zd5d6 ZdS )8McubeCallSessioncall_id	websocketredis_clientc             
   C   s8  || _ || _|| _|| _d | _d | _d | _d| _d| _i | _	t
 | _d| _d | _t| _t| _t| _tdp8d | _d| _t| _t| _t| _d | _ t!| _"t#| _$t%| _&t'| _(zt)dt*dt+t,tdd| _-W n t.yv   d| _-Y nw zt,td	d
| _/W n t.y   d| _/Y nw zt,tdd| _0W n t.y   d| _0Y nw zt)dt+t,tdd| _1W n t.y   d| _1Y nw d | _2d | _3d | _4d | _5d | _6d | _7d | _8d | _9t
: | _;d | _<d | _=d | _>d | _?d | _@d| _Ad| _Bd| _Cd | _DtE | _Fd| _G| jGd | _Ht
I | _Jd| _Kd| _Ld| _Md| _Nd S )NFfirst_messagerK        tts_chunk_ms200   tts_gainz0.35gffffff?playback_pace_factorz1.0g      ?r   checkpoint_every10r:   i@     Td   )Or   wsrabbit_channelr   	stream_idactive_sequence_idcancelled_sequence_idbot_playingresponse_pendingpending_playsr   Queuetts_segments_tts_done_received_tts_final_chunk_seqSYSTEM_PROMPTr~   	LLM_MODELr   LLM_PROVIDERr   
_MCUBE_DEFgetrG   r   _first_message_sentSTT_PROVIDERr   STT_LANGUAGE_CODEr   STT_MODEL_IDr   detected_languageTTS_PROVIDERr   	TTS_MODELr   TTS_VOICE_IDr   TTS_ENCODINGr   maxminr?   floatr   	Exceptionr   r   r   business_idbot_idagent_iduser_idagent_email
agent_namestt
stt_streamEvent_stt_ready_event	_stt_task_ws_reader_task_playback_task_tts_consumer_task_control_consumer_task_stt_reconnect_count_stt_max_reconnect_attempts_stt_reconnecting_resample_state	bytearray_pcm16_16k_buffer_frame_16k_samples_frame_16k_bytesLock_sequence_locknoise_cancellation_enablednoise_gate_thresholdnoise_gate_enabledbackground_audio_enabled)rC   r   r   r   r   r
   r
   r   rD      s   
&


 



zMcubeCallSession.__init__c                    sd   t j|  dd| _t j|  dd| _t j|  dd| _t j|  dd| _	| 
 I d H  d S )Nzmcube.stt_events)r   zmcube.playback_loopzmcube.tts_consumerzmcube.control_consumer)r   create_task_consume_stt_eventsr   _playback_loopr   _consume_tts_queuer   _consume_control_queuer   _ws_reader_looprM   r
   r
   r   start   s   zMcubeCallSession.startc                    s  z| j 2 zj3 d H W }zt|}W n ty"   td| j Y qw z8|d dkr6 | |I d H  n$ dkrD | 	|I d H  n dkrR | 
|I d H  ndkrXW  n#	 	 W q tyo   td| j|d Y qw 6 W |  I d H  d S W |  I d H  d S |  I d H  w )Nz$ws non-json frame ignored call_id=%seventr   mediaplayedStreamstopz,ws event handling failed call_id=%s event=%s)r   jsonloadsr   logwarningr   r   	_on_start	_on_media_on_played_stream	exception_cleanup)rC   rawmsgr
   r
   r   r   
  s:   


"z McubeCallSession._ws_reader_loopc                    s  z| j r| jtd| j dI d H  W n	 ty   Y nw t| j D ]}|j	
 s3|j	  q'| j  z| jd urD| j  W n	 tyN   Y nw zt| dd d ur`| j I d H  W n	 tyj   Y nw | j| j| j| jfD ]}|r|
 s|  qud S )N	terminater   streamId_http_session)r   r   sendr   dumpsr   rX   r   valuesr   donecancelclearr   	end_inputgetattrr   closer   r   r   r   )rC   pptr
   r
   r   r   '  s@    




zMcubeCallSession._cleanupr   c                    s   |d d | _ |d d d}t|d d dtj}|tjks(|tjkr1td| j|| t	d| j| j  | 
 I d H  |  I d H  | jr`| jsbd| _| jd	| j| jd
I d H  d S d S d S )Nr   r   mediaFormatencoding
sampleRatezNMCube audio format mismatch call_id=%s encoding=%s sr=%s (expected mulaw@8kHz)z#mcube start call_id=%s stream_id=%sTrK   bot_say_textrF   )r   r   r?   ro   sample_rater  r   r   r   info_load_call_config	_init_sttr   r   _publish_utterancer   )rC   r   r  r  r
   r
   r   r   F  s$   zMcubeCallSession._on_startr   Nc              	      s  i }z)| j d| j I dH }|r+t|ttfr"|jddd}nt|}t	|}W n t
y<   td| j Y nw dd | D }|d	}|d
}|dur|durz%ttt|t|I dH }| D ]\}}	|	srqk||v rwqk|	||< qkW n t
y   td| j Y nw |sdS |d| j| _t| jtr| jdd| _|dp| jpd | _|d| j| _|d| jpd| _|d| jp| j| _|d| jp| j| _|d| jp| j| _|d| jp| j| _|d| jp| j| _|d| jp| j| _|d| jp| j| _dddd fdddd fddd d fd!d!d"d ffD ](\}
}}||
durWzt| ||||
 W q0 t
yV   Y q0w q0d#}|D ]\}}||durrt| ||| q]dS )$z
        Load per-call config from Redis (written by the /api/mcube/outbound-call endpoint),
        then backfill any missing MCube fields from cluster `{bid}_bots` + `business_id_bots`.
        zmcube_call_config:Nutf-8replace)errorsz+failed to load mcube call config call_id=%sc                 S   s6   h | ]\}}|d urt |trt| dkr|qS )NrK   )
isinstancerW   rG   )r   kvr
   r
   r   	<setcomp>n  s   6 z5McubeCallSession._load_call_config.<locals>.<setcomp>r   r   z&cluster bot backfill failed call_id=%sr~   r   r   r   rK   r   r   r   r   r   r   r   r   r   r   c                 S   s   t dtdtt| S )Nr   r   )r   r   r?   r   xr
   r
   r   <lambda>  s    z4McubeCallSession._load_call_config.<locals>.<lambda>r   c                 S      t | S r>   r   r  r
   r
   r   r        r   c                 S   r  r>   r  r  r
   r
   r   r    r  r   c                 S   s   t dtt| S )Nr   )r   r?   r   r  r
   r
   r   r    s    ))r   r   )r   r   )r   r   )r   r   )r   r   )emailr   )r   r   ) r   r   r   r  bytesr   decoderW   r   r   r   r   r   itemsr   	to_threadrm   r?   r~   r  r   rG   r   r   r   r   r   r   r   r   r   setattr)rC   cfgr   raw_strcfg_keysbidbotdb_ovdkdvckattrcasterid_mapjson_keyr
   r
   r   r  ]  s|   



	z"McubeCallSession._load_call_configc                    s  d| _ t | _| j  tdptdpd}tdpd}tdp&d}t | _	t
d| j| j| j| j | jdkrd|sFt
d	 ntj| jpLd
| jpPd|| j	d| _| j | _| j  dS | jdkr|sqt
d n tj| jpwd| jp{ddd|| j	d| _| j | _| j  dS | jpd }d|v r|dd  pd}tj|| j|| j	d}z|| _| j | _W n ty   tjddd}t||d| _| j | _Y nw | j  dS )zD
        Initialize STT stream for the configured provider.
        NELEVENLABS_API_KEYELEVEN_API_KEYrK   CARTESIA_API_KEYDEEPGRAM_API_KEYzDmcube stt init provider=%s model_id=%s lang=%s noise_cancellation=%srf   z8DEEPGRAM_API_KEY not set; falling back to elevenlabs STTznova-2r   )modelrF   api_keyhttp_sessionre   z8CARTESIA_API_KEY not set; falling back to elevenlabs STTzink-whisper	pcm_s16le>  )r.  rF   r  r  r/  r0  scribe_v2_realtime/)model_idlanguage_coder/  r0  T)r  	force_cpu)r   vad)r   r   r   r   r   osgetenvaiohttpClientSessionr   r   r  r   r   r   r   r   rf   STTr   rS   r   setre   rG   r.   rg   rQ   	SileroVADloadrj   )rC   elevenlabs_keycartesia_keydeepgram_keyel_modelbase_sttr9  r
   r
   r   r    sv   






zMcubeCallSession._init_sttrF   c                    s   t d| j| z
| jr| j  W n	 ty   Y nw zt| dddur.| j I dH  W n	 ty8   Y nw d| _	t
 | _| j  || _|  I dH  dS )zG
        Reinitialize STT with a new language after detection.
        z+mcube reinit_stt call_id=%s new_language=%sr   N)r   r  r   r   r   r   r   r   r   r   r   r   r   r   r   r  rR   r
   r
   r   _reinit_stt_with_language  s*   

z*McubeCallSession._reinit_stt_with_languagec              	      sp  | j sd S | j sd S |dpi }|ddkrd S |dp#d}zt|}t|d}W n tyD   t	d| j
t| Y d S w t|ddd	d
| j\}| _| jrvtd|}|rvtdd |D t| }|| jk rvdt| }| j| t| j| jkrt| jd | j }	| jd | j= tj|	d
d| jd}
| jd usJ | j|
 t| j| jksd S d S )Nr   trackinboundpayloadrK   r   z1invalid media payload ignored call_id=%s bytes=%sr	   i@  r2  hc                 s   s    | ]}t |V  qd S r>   )abs)r   sr
   r
   r   r   =      z-McubeCallSession._on_media.<locals>.<genexpr>    )r  num_channelssamples_per_channel)r   r   is_setr   rp   audioopulaw2linr   r   r   r   rL   ratecvr   r   arrayr3   r   r   extendr   r  ri   
AudioFramer   r   
push_frame)rC   r   r   b64mulaw_bytespcm16_8k	pcm16_16ksamplesrmsframe_bytesframer
   r
   r   r     sV   



zMcubeCallSession._on_mediac                    sT   | d}|s
d S | j |}|r&|j s(|jd  | j|d  d S d S d S )Nr   )r   r   r   r   
set_resultpop)rC   r   r   r   r
   r
   r   r   P  s   
z"McubeCallSession._on_played_streamc           	         s  | j | jk rUz| j I d H  | jd usJ | j2 zt3 d H W }|jtjkrh| jrg|j	r2|j	d nd }|r9|j
nd   h d}t fdd|D } rg|sgt dkrgtd| j  |  I d H  q|jtjkr|j	rv|j	d nd }|r|r|j
nd nd}|r| |I d H  q6 W n tjtjtfy/ } z|  j d7  _ | j | jkrtd	| j | jt| W Y d }~d S td| j d  d
}td| j | j| j|t| t|I d H  z&| jr| jj s| j! I d H  t" | _| # I d H  td| j| j  W n t$y$ } ztd| jt| W Y d }~nd }~ww W Y d }~n"d }~w t$yL } ztd| jt| W Y d }~d S d }~ww | j | jk sd S d S )Nr   rK   >
   mm-hmmuh-huhokmhmyesokayyeahmmhmmrightuhhuhc                 3   s    | ]}| v V  qd S r>   r
   r/   partialr
   r   r   j  rN  z7McubeCallSession._consume_stt_events.<locals>.<genexpr>r   z(barge-in triggered call_id=%s partial=%rr	   z=STT reconnection failed after %d attempts call_id=%s error=%s   zJSTT connection reset attempt=%d/%d call_id=%s reconnecting in %ds error=%sz1STT reconnection successful call_id=%s attempt=%dz/STT reinitialization failed call_id=%s error=%sz.STT event processing error call_id=%s error=%s)%r   r   r   waitr   typerd   INTERIM_TRANSCRIPTr   alternativesr   rG   r4   anyrL   r   r  r   _barge_in_clearFINAL_TRANSCRIPT_handle_final_transcriptr<  ClientConnectionResetErrorClientConnectionErrorConnectionResetErrorerrorrW   r   r   r   sleepr   closedr   r=  r  r   )	rC   evaltbackchannel_wordsis_backchannelr   ebackoff_delay
init_errorr
   rn  r   r   [  sr   

z$McubeCallSession._consume_stt_eventsr   c                    s   | j s| jr	d S | jd u r2|r2t|| _td| j| j|d d  | j| jkr2| | jI d H  | j	|| jp:| jdI d H  d S )Nz6mcube language_detected call_id=%s language=%s text=%r2   rE   )
r   r   r   r8   r   r  r   r   rG  r	  )rC   r   r
   r
   r   rx    s   
 z)McubeCallSession._handle_final_transcriptr   r  r  c                   sd  | j 4 I d H 8 z| jd| j I d H }| jd| j dI d H  W n ty5   tt }Y nw W d   I d H  n1 I d H sFw   Y  t|| _d| _	d| _
d| _d | _| jt||| j| j| j| j| j| j| j| j|| j| jd}|r||d< dD ]}t| |d }|d ur|||< qt| jt|dI d H  td	| j||| j| j| j| j|	 d S )
Nz
mcube:seq:i  FT)r   sequence_id
transcriptr~   r   r   r   r   r   r   r   r   r   r   r  )r   r   r   r   r   r   )channel
queue_namerJ  zvpublished utterance call_id=%s seq=%s text=%r tts_provider=%s tts_model=%s tts_voice_id=%s tts_encoding=%s language=%s)r   r   incrr   expirer   r?   timer   r   r   r   r   r~   r   r   r   r   r   r   r   r   r   r   rx   r   rr   r   r  )rC   r   r  rF   seqrJ  r  r  r
   r
   r   r	    sj    (
z#McubeCallSession._publish_utterancec           
         s.  | j s| j stdI d H  | j rt| j}| jj|ddI d H }| 4 I d H }|2 z3 d H W }|jdd4 I d H  |j	
d}zt|}W n ty]   Y W d   I d H  q-w t|dd}| jd ur{|| jkr{	 W d   I d H  q-|d	d
kr| jd u s|| jkr	 W d   I d H  q-t|d }t|d }	|dkrtd| j|t|	 | j|||	fI d H  n(|d	dkr| jd u s|| jkr	 W d   I d H  q-d| _t|dd| _W d   I d H  n1 I d H sw   Y  q-6 W d   I d H  d S 1 I d H sw   Y  d S )Ng{Gz?TdurableFrequeuer
  r  r5  rr  tts_audio_chunk	chunk_seqaudio_pcm_b64r   z0tts_audio_chunk_first call_id=%s seq=%s bytes=%stts_donefinal_chunk_seq)r   r   r}  ry   r   r   declare_queueiteratorprocessbodyr  r   r   r   r?   r   r   r   rp   r   r  rL   r   putr   r   )
rC   r  queueq_itermessagedatarJ  r  r  pcm16_8k_bytesr
   r
   r   r     sZ   
(0z#McubeCallSession._consume_tts_queuerJ  c                 C   s   | dp| dp| dp| d}|rt|tsdS | }|s%dS | drHz|ddd d	dd
 }W |S  tyG   Y dS w |S )z
        Extract transfer target from tool/control payload.

        We accept several keys so different producers (ai_worker variants) stay compatible.
        transfer_tophone_numbertransfer_numbersip_uriNzsip::r	   @r   )r   r  rW   rG   r4   
startswithr.   r   )rC   rJ  r  r
   r
   r   _extract_transfer_to  s(   
z%McubeCallSession._extract_transfer_tocancelled_seqr  c                C   s   |du r| j }|| _d| _d| _d| _ d| _d| _t| j D ]\}}|j	
 s.|j	  q | j  z	 | j  q6 tjyF   Y dS w )z
        Immediately stop any bot playback and cancel pending playedStream futures.
        This is used for MCube `terminate/transfer` and should be more aggressive
        than barge-in clear.
        NF)r   r   r   r   r   r   rX   r   r  r   r   r   r   r   
get_nowaitr   
QueueEmpty)rC   r  _r   r
   r
   r   _force_stop_playback2  s(   



z%McubeCallSession._force_stop_playbackc                    s  t | j}| jj|ddI dH }| 4 I dH \}|2 zL3 dH W }|jdd4 I dH 1 zt|j	d}W n t
yJ   Y W d  I dH  qw | |I dH  W d  I dH  n1 I dH scw   Y  q6 W d  I dH  dS 1 I dH s{w   Y  dS )ze
        Consume per-call control queue and execute MCube call actions (terminate/transfer).
        Tr  NFr  r
  )rt   r   r   r  r  r  r   r   r  r  r   _handle_control_message)rC   r  r  r  r  rJ  r
   r
   r   r   P  s"   
(.z'McubeCallSession._consume_control_queuec              	      s   | d}| d}t|ttfrt| rt|nd }|d ur.| jd ur.|| jkr.d S |dkrM| jrE| jt	
d| jdI d H  | j|d d S |dkru| |}|rm| jrm| jt	
d| j|d	d
I d H  | j|d d S d S )Nrr  r  mcube_terminater   r   r  mcube_transfertransferT)r   r   
transferToshowOriginalCallerId)r   r  r?   rW   isdigitr   r   r   r   r   r   r  r  )rC   rJ  msg_typer  r  r  r
   r
   r   r  a  s8   

&

 



z(McubeCallSession._handle_control_messagec              
      s  | j }	 | j I d H \}}}| jd ur|| jkrq| jd u s%|| jkr&q| js*q| j d| }d| _zdd l}t	| j
}||d|}W n	 tyP   Y nw t|}| jtdtjtjt|d|ddI d H  |dkr|dks|| dkr| jtd	| j|d
I d H  zt|d tj }	t	| j}
ttd|	d |
 I d H  W n ty   tdI d H  Y nw | jr| jd ur|| jkr| j rd| _d| _ d | _d | _d| _d | _q)NT_seg_r   r   	playAudioascii)contentTyper  rJ  r   )r   r   
checkpoint)r   r   r   g        g\(\?g?F)!r   r   r   r   r   r   r   r   rS  r   r   mulr   rq   r   r   r   r   ro   r  r  base64	b64encoder  rL   r   r   r}  r   r   r   emptyr   )rC   r   r  r  r  r   rS  gainmulawchunk_duration_spacer
   r
   r   r     sx   



"

zMcubeCallSession._playback_loopc                    s   | j sd S | jsd S td| j| j | j| _d| _d| _d | _t| j	
 D ]\}}|j s6|j  | j	|d  q(z| jtd| j dI d H  W n	 tyY   Y nw z	 | j  q\ tjyl   Y d S w )Nz barge-in clear call_id=%s seq=%sF
clearAudior   )r   r   r   r  r   r   r   r   rX   r   r  r   r   r   rc  r   r   r   r   r   r   r  r   r  )rC   r   r   r
   r
   r   rv    s4   

$
z McubeCallSession._barge_in_clearr   N)rT   rU   rV   rW   
websocketsWebSocketServerProtocolredis_asyncRedisrD   r   r   r   dictr   r  r  rG  r   r   r   rx  r	  r   r   r  r?   r  r   r  r   rv  r
   r
   r
   r   r      s6    
l

MT5A":-
&Or   c                   s   t | ddpd}t | dd }|s|d urt |ddpd}td|t | dd |r2|ddd nd |r?|ddng }|rG|d nd}|sW| jdd	d
I d H  d S t|| ||d}| I d H  d S )NpathrK   requestz4ws accepted path=%s remote=%s call_hint_from_path=%sremote_addressr4  r5  i  zmissing call_id)codereason)r   r   r   r   )r   r   r  rG   r.   r   r   r   )r   r   r   r  reqrO   r   sessr
   r
   r   _ws_handler  s.   
r  c               	      s   t jt jd t I d H } t| I d H  tjtddt	dt
t t fdd}t }tjtjfD ]}z||| W q7 tyJ   Y q7w  fdd}| I d H  d S )	N)levelF)decode_responsesz"mcube ws bridge listening on %s:%sc                     s      s d d S d S )NT)r   rb  )r  )r   r
   r   _signal_handler!  s   zmain.<locals>._signal_handlerc                	      sf   t j fddttdddd4 I d H  I d H  W d   I d H  d S 1 I d H s,w   Y  d S )Nc                    s   t |  dS )N)r   r   )r  )r   )r  r   r
   r   r  /  s    z&main.<locals>.runner.<locals>.<lambda>i   r9   <   )max_sizeping_intervalping_timeout)r  serveWS_HOSTWS_PORTr
   r  r   r   r
   r   runner-  s   .zmain.<locals>.runner)loggingbasicConfigINFOrv   rw   r  from_urlr}   r   r  r  r  r   r   get_running_loopsignalSIGINTSIGTERMadd_signal_handlerrQ   )
connectionr  loopsigr  r
   r  r   r     s"   r   __main__r  )Ur   rV  rS  r  r   r  r:  r  r[   r  dataclassesr   collectionsr   typingr   r   r]   rN   rW   r8   rc   r<  redis.asyncior  r  livekit.agents.stt.sttrd   livekit.pluginsre   rf   rg   rh   livekitri   !livekit.agents.stt.stream_adapterrj   livekit.plugins.silero.vadrk   r@  env_loadrl   cluster_bot_runtimerm   mcube_defaultsrn   mcube_codecro   rp   rq   mqrr   rs   rt   ru   rv   rw   rx   ry   	getLoggerr   r   r?   r;  r  r  r}   r   r  r   r   r   r   r   r   r   r   r   r   r   r   r  r   rT   runr
   r
   r
   r   <module>   sz    
&(
      o 
%