
    <ic                     n   d 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 ddlZddlmZ ddlmZ ddlmZ dd	lmZmZmZmZ  e	         ej0                           ej2                  ej4                  d
        ej2                  dddd       dZ G d d      Zd Zd Zedk(  r e        yy)zn
Rivet Voice Assistant - Real-time phone AI using Pipecat
Simpler implementation using available Pipecat APIs
    N)Optional)load_dotenv)logger)AnthropicLLMService)ElevenLabsTTSService)DeepgramSTTService)	TextFrameTranscriptionFrameEndFrameAudioRawFrameINFO)levelzlogs/{time:YYYY-MM-DD}.logz1 dayz7 daysDEBUG)rotation	retentionr   u  You are Rivet, the COO system for RateRight — a construction hiring marketplace in Australia. You're talking on the phone with Michael, the founder.

Be direct, no waffle. Keep responses SHORT (1-2 sentences). You're his right hand — you know the business, you push back when needed, you're honest.

RateRight: $50 flat fee per hire. Workers pay nothing. Connects contractors with construction workers.

You're not a customer service bot. You're Rivet — Michael's AI COO. Talk like it.c                   J    e Zd ZdZd Zdedee   fdZd Z	defdZ
d	efd
Zy)TwilioMediaStreamHandlerzCHandle Twilio Media Stream protocol and connect to Pipecat servicesc                 r   t        t        j                  d      dd      | _        t	        t        j                  d      d      | _        t        t        j                  d      t        j                  d	d
      d      | _        dt        dg| _	        d | _
        d | _        t        j                  d       y )NDEEPGRAM_API_KEYznova-2-conversationalaizen-AU)api_keymodellanguageANTHROPIC_API_KEYzclaude-opus-4-5-20251101)r   r   ELEVENLABS_API_KEYELEVENLABS_VOICE_IDIKne3meq5aSn9XLyUdCDeleven_turbo_v2_5)r   voice_idr   system)rolecontentz$TwilioMediaStreamHandler initialized)r   osgetenvdeepgramr   llmr   ttsSYSTEM_PROMPTconversation_history
stream_sidcall_sidr   info)selfs    @/home/ccuser/rateright-growth/voice-assistant/voice_assistant.py__init__z!TwilioMediaStreamHandler.__init__1   s    *II01+
 'II12,

 (II23YY46LM%
 -8%
! :;    audio_payloadreturnc                    K   	 t        j                  |      }y# t        $ r"}t        j                  d|        Y d}~yd}~ww xY ww)a  
        Process incoming audio from Twilio:
        1. Decode base64 audio
        2. Send to Deepgram for STT
        3. Send transcription to Claude
        4. Get response from Claude
        5. Send to ElevenLabs for TTS
        6. Return audio bytes
        NzError processing audio: )base64	b64decode	Exceptionr   error)r,   r0   audio_byteses       r-   handle_audioz%TwilioMediaStreamHandler.handle_audioM   sF     	 **=9K
  	LL3A378	s)   A A	AA A AAc                 F  K   t        j                  d|        	 |2 3 d{   }t        j                  |      }|j	                  d      }|dk(  rf|d   d   | _        |d   d   | _        t        j                  d| j                   d| j
                          d	}| j                  ||       d{    |d
k(  r?|d
   d   }| j                  |       d{   }|s| j                  ||       d{    |dk(  st        j                  d| j
                           y7 7 v7 Q7 66 y# t        j                  j                  $ r% t        j                  d| j
                          Y yt        $ r$}	t        j                  d|	 d       Y d}	~	yd}	~	ww xY ww)z/Handle Twilio Media Stream websocket connectionzNew WebSocket connection: Neventstart	streamSidcallSidzStream started - Call: z
, Stream: z)Hello! This is Rivet. How can I help you?mediapayloadstopzStream stopped: zWebSocket closed: zError in websocket handler: Texc_info)r   r+   jsonloadsgetr)   r*   send_text_responser9   
send_audio
websockets
exceptionsConnectionClosedr5   r6   )
r,   	websocketpathmessagedatar;   greetingr@   response_audior8   s
             r-   handle_websocketz)TwilioMediaStreamHandler.handle_websocketd   s     	078	L!*  gzz'*)G#&*7mK&@DO$(M)$<DMKK"9$--
SWSbSbRc de  KH11)XFFFg%"7mI6G+/+<+<W+E%EN%"ooiHHHf_KK"24??2C DE1 G
 &F I) "+4 $$55 	@KK,T__,=>? 	LLL7s;dKK	Ls   F!D1 D/D&D/BD1 2D)3&D1 D+D1 !D1 6D-7
D1 #D1 %F!&D/)D1 +D1 -D1 /D1 0F!1?F0F!2F:FF!FF!textc                   K   	 t        j                  d|        g }| j                  j                  |      2 3 d{   }t	        |d      s|j                  |j                         27 -6 |r-dj                  |      }| j                  ||       d{  7   yy# t        $ r"}t        j                  d|        Y d}~yd}~ww xY ww)z)Convert text to speech and send to callerzRivet: Naudior/   zError sending response: )r   r+   r&   run_ttshasattrappendrU   joinrH   r5   r6   )r,   rL   rS   audio_chunkschunk
audio_datar8   s          r-   rG   z+TwilioMediaStreamHandler.send_text_response   s     	9KK'$() L#xx//5 5 5e5'* ''455  XXl3
ooi<<< 
  	9LL3A3788	9sa   C5B A-A+A-B B +A--)B BB C	C	'C?CC		Cr\   c                    K   t        j                  |      j                  d      }d| j                  d|id}|j	                  t        j                  |             d{    y7 w)z%Send audio to Twilio via Media Streamzutf-8r?   r@   )r;   r=   r?   N)r3   	b64encodedecoder)   sendrD   dumps)r,   rL   r\   encoded_audiorN   s        r-   rH   z#TwilioMediaStreamHandler.send_audio   s]      ((4;;GD =
 nnTZZ0111s   AA( A&!A(N)__name__
__module____qualname____doc__r.   strr   bytesr9   rR   rG   rH    r/   r-   r   r   .   s@    M<8  .#LJ9 9(2e 2r/   r   c            	        K   t        j                  dd      } t        t        j                  dd            }t        j                  d       t        j                  d|  d|        t        j                  dt        j                  d	|  d|       j                  d
d       d       t               }t        j                  |j                  | |      4 d{    t        j                  d       t        j                  d       t        j                          d{    ddd      d{    y7 [7 7 	# 1 d{  7  sw Y   yxY ww)z/Start WebSocket server for Twilio Media StreamsHOSTz0.0.0.0PORT8765z=== Rivet Voice Assistant ===zStarting WebSocket server on :zWebhook URL for Twilio: ws://
PUBLIC_URLzhttp:// z/media-streamNu"   ✅ Voice Assistant server runningzWaiting for incoming calls...)r"   r#   intr   r+   replacer   rI   serverR   asyncioFuture)hostporthandlers      r-   start_serverry      s     99VY'Dryy()D
KK/0
KK/vQtf=>
KK/		,4&PQRVQWHX0Y0a0abkmo0p/qq~  A&(G 8 8$E  8934nn   	   s[   CED5EAD;D7 D;$E/D90E7D;9E;EEE	Ec                     g d} | D cg c]  }t        j                  |      r| }}|r-t        j                  d|        t	        j
                  d       	 t        j                  t                      yc c}w # t        $ r t        j                  d       Y yt        $ r9}t        j                  d| d       t	        j
                  d       Y d}~yd}~ww xY w)	zMain entry point)r   r   r   TWILIO_ACCOUNT_SIDTWILIO_AUTH_TOKENz(Missing required environment variables:    zServer stopped by userzFatal error: TrB   N)r"   r#   r   r6   sysexitrt   runry   KeyboardInterruptr+   r5   )required_keyskmissingr8   s       r-   mainr      s    M (<Qryy|q<G<?yIJLN# =  .,- }QC(48s(   A8A8A= =CC%/CC__main__) rf   rt   r3   rD   r"   r~   typingr   dotenvr   logurur   rI   pipecat.services.anthropicr   pipecat.services.elevenlabsr   pipecat.services.deepgramr   pipecat.frames.framesr	   r
   r   r   removeaddstderrr'   r   ry   r   rc   ri   r/   r-   <module>r      s   
    	 
     ; < 8    


3::V $ 


''XU\ ]W}2 }2@$4 zF r/   