
    7|hT              	          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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mZmZmZ ddlmZmZ ddlmZ ddlmZmZ ddlm Z m!Z!m"Z"m#Z#m$Z$m%Z% erddl&Z'ddl(m)c m*c m+Z,  ejZ                  e.      Z/d	Z0d
Z1dZ2d&dZ3 G d d      Z4 e4       Z5 e4       Z6 G d de7e	      Z8 G d de!      Z9 G d de!      Z: G d d      Z;dee7   de<deee7   eejz                     f   fdZ>ddde7fdZ?ded   dee7ddf   fdZ@eeAe4f   ZBe7ZC G d  d!      ZDeDZEe7ZF G d" d#e9e:eeEeFf         ZGee7eef   ZHeAZI G d$ d%e9e:eeHeIf         ZJeGZKeJZLeDZMy)'z*A common module for NVIDIA Riva Runnables.    N)Enum)TYPE_CHECKINGAnyAsyncGeneratorAsyncIteratorDict	GeneratorIteratorListOptionalTupleUnioncast)
AnyMessageBaseMessage)PromptValue)RunnableConfigRunnableSerializable)
AnyHttpUrl	BaseModelFieldparse_obj_asroot_validator	validator      ?i  )
.!?   ¡   ¿returnc                  ^    	 ddl } | j                  S # t        $ r}t        d      |d}~ww xY w)z5Import the riva client and raise an error on failure.r   NziCould not import the NVIDIA Riva client library. Please install it with `pip install nvidia-riva-client`.)riva.clientImportErrorclient)rivaerrs     h/var/www/html/test/engine/venv/lib/python3.12/site-packages/langchain_community/utilities/nvidia_riva.py_import_riva_clientr*   1   s@     ;;  G
 	s    	,',c                       e Zd ZdZy)	SentinelTzAn empty Sentinel type.N)__name__
__module____qualname____doc__     r)   r,   r,   >   s    !r2   r,   c                   T    e Zd ZdZdZdZdZdZdZdZ	e
ded	d fd
       Zedd       Zy)RivaAudioEncodinga  An enum of the possible choices for Riva audio encoding.

    The list of types exposed by the Riva GRPC Protobuf files can be found
    with the following commands:
    ```python
    import riva.client
    print(riva.client.AudioEncoding.keys())  # noqa: T201
    ```
    ALAWENCODING_UNSPECIFIEDFLAC
LINEAR_PCMMULAWOGGOPUSformat_coder"   c                     	 | j                   | j                  | j                  d|   S # t        $ r}t	        d|       |d}~ww xY w)zReturn the audio encoding specified by the format code in the wave file.

        ref: https://mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
        )         z>The following wave file format code is not supported by Riva: N)r8   r5   r9   KeyErrorNotImplementedError)clsr;   r(   s      r)   from_wave_format_codez'RivaAudioEncoding.from_wave_format_codeX   sV    	~~#((syyA+NN 	%**58 	s   &) 	AAAc                 B    t               }t        |j                  |       S )z-Returns the Riva API object for the encoding.)r*   getattrAudioEncodingselfriva_clients     r)   riva_pb2zRivaAudioEncoding.riva_pb2f   s     *+{00$77r2   N)r"   zriva.client.AudioEncoding)r-   r.   r/   r0   r5   r6   r7   r8   r9   r:   classmethodintrC   propertyrJ   r1   r2   r)   r4   r4   F   s]     D1DJEG 8K   8 8r2   r4   c                       e Zd ZU dZ e ed      dddg      Zeeef   e	d<    edd	      Z
ee   e	d
<   edd       Z eddd      ededefd              Zy)RivaAuthMixinzBConfiguration for the authentication to a Riva service connection.zhttp://localhost:50051z1The full URL where the Riva service can be found.z"https://user@pass:riva.example.com)descriptionexamplesurlNz@A full path to the file where Riva's public ssl key can be read.rP   ssl_certr"   c                     t               }t        t        | j                        }|j                  dk(  }t        | j                        j                  d      d   }|j                  | j                  ||      S )z!Return a riva client auth object.https/   )rT   use_ssluri)	r*   r   r   rR   schemestrsplitAuthrT   )rH   rI   rR   rY   url_no_schemes        r)   authzRivaAuthMixin.authz   sj     *+:txx(**'DHH++C03]]G   
 	
r2   T)preallow_reusevalc                 ~    t        |t              rt        t        t	        t        |            S t        t        |      S )z:Do some initial conversations for the URL before checking.)
isinstancer\   r   r   r   )rB   rc   s     r)   _validate_urlzRivaAuthMixin._validate_url   s/     c3
LS$ABBJ$$r2   )r"   zriva.client.Auth)r-   r.   r/   r0   r   r   rR   r   r\   __annotations__rT   r   rM   r`   r   rK   r   rf   r1   r2   r)   rO   rO   m   s    L"'+,G*,PQ#Cz3	 
 $VHhsm 
 
 
 u$D1% %
 %  2%r2   rO   c                       e Zd ZU dZ eej                  d      Zeed<    edd      Z	e
ed<    edd	      Zeed
<   y)RivaCommonConfigMixinz%A collection of common Riva settings.z!The encoding on the audio stream.)defaultrP   encodingi@  z*The sample rate frequency of audio stream.sample_rate_hertzzen-USzaThe [BCP-47 language code](https://www.rfc-editor.org/rfc/bcp/bcp47.txt) for the target language.language_codeN)r-   r.   r/   r0   r   r4   r8   rk   rg   rl   rL   rm   r\   r1   r2   r)   ri   ri      sX    /"'!,,7#H  #"Ns  #M3 r2   ri   c                       e Zd ZU dZej
                  ed<   ej
                  ed<   ddZddZ	ddZ
defd	Zdd
ZddZy)_Eventz3A combined event that is threadsafe and async safe._event_aeventr"   Nc                 h    t        j                         | _        t        j                         | _        y)zInitialize the event.N)	threadingEventrp   asynciorq   rH   s    r)   __init__z_Event.__init__   s    oo'}}r2   c                 l    | j                   j                          | j                  j                          yzSet the event.N)rp   setrq   rv   s    r)   rz   z
_Event.set   s     r2   c                 l    | j                   j                          | j                  j                          yry   )rp   clearrq   rv   s    r)   r|   z_Event.clear   s"    r2   c                 6    | j                   j                         S )zIndicate if the event is set.)rp   is_setrv   s    r)   r~   z_Event.is_set   s    {{!!##r2   c                 8    | j                   j                          y)zWait for the event to be set.N)rp   waitrv   s    r)   r   z_Event.wait   s    r2   c                 T   K   | j                   j                          d{    y7 w)z#Async wait for the event to be set.N)rq   r   rv   s    r)   
async_waitz_Event.async_wait   s     ll!!!s   (&(r"   N)r-   r.   r/   r0   rs   rt   rg   ru   rw   rz   r|   boolr~   r   r   r1   r2   r)   ro   ro      s>    =OO]]'


$ $"r2   ro   output_directorysample_ratec                    | r{t        j                  ddd|       5 }|j                  }ddd       t        j                  d      }|j                  d       |j                  d       |j                  |       ||fS y	# 1 sw Y   WxY w)
zECreate a new wave file and return the wave write object and filename.bxz.wavF)modesuffixdeletedirNwbr=   rX   )NN)tempfileNamedTemporaryFilenamewaveopensetnchannelssetsampwidthsetframerate)r   r   fwav_file_namewav_files        r)   _mk_wave_filer      s     ((fU8H
 	#FFM	# 99]D1a a k*x((	# 	#s   A??Brc   TTSInputTypec                     t        | t              r| j                         S t        | t              rt	        | j
                        S t	        |       S )zAttempt to coerce the input value to a string.

    This is particularly useful for converting LangChain message to strings.
    )re   r   	to_stringr   r\   content)rc   s    r)   _coerce_stringr      s<    
 #{#}}#{#3;;s8Or2   inputsc              #   4  K   d}| D ]  }t        |      }t        D ]-  }||v s|j                  |d      \  }}||z   |z    d}||v r&/ ||z  }t        |      t        kD  s\t        dt        |      t              D ]  }|||dz      d} |r| yyw)z9Filter the input chunks are return strings ready for TTS. r=   r      N)r   _SENTENCE_TERMINATORSr]   len_MAX_TEXT_LENGTHrange)r   bufferchunk
terminatorlast_sentenceidxs         r)   _process_chunksr      s     F u% 0 	J%',{{:q'A$u},z99 %	 	% v;))QF-=> ,S37++,F!&  s    B%B	B#5Bc                      e Zd ZU dZej
                  ed<   ej                  ed<   ej                  ed<   e	ed<   e	ed<   e	ed<   e
ej                     ed<   dd	ed
dfdZd
eeddf   fdZd
ee   fdZed
efd       Zed
efd       Zed
efd       Zed
efd       Zddede
e   d
dfdZddede
e   d
dfdZdde
e   d
dfdZdde
e   d
dfdZded   d
dfdZy)AudioStreamz%A message containing streaming audio.	_put_lock_queueoutputhangupuser_talking
user_quiet_workermaxsizer"   Nc                    t        j                         | _        t        j                  |      | _        t        j                         | _        t               | _        t               | _	        t               | _
        d| _        y)zInitialize the queue.)r   N)rs   Lockr   queueQueuer   r   ro   r   r   r   r   )rH   r   s     r)   rw   zAudioStream.__init__  sP    ")kk'2kkmh ("Hr2   c              #      K   	 	 | j                   j                  dt              }|t
        k(  ry| | j                   j                          J# t        j                  $ r Y `w xY ww)zReturn an error.TN)r   get_QUEUE_GET_TIMEOUTr   EmptyHANGUP	task_donerH   next_vals     r)   __iter__zAudioStream.__iter__  sc     ;;??41CD
 6! NKK!!#  ;; s'   A' A )A'A$!A'#A$$A'c                $  K   	 	 t        j                         j                  d| j                  j                  dt
               d{   }|t        k(  ry| | j                  j                          q7 .# t        j                  $ r Y w xY ww)z4Iterate through all items in the queue until HANGUP.TN)
ru   get_event_looprun_in_executorr   r   r   r   r   r   r   r   s     r)   	__aiter__zAudioStream.__aiter__&  s     !(!7!7!9!I!I$++//41C"  6! NKK!!#  ;; s;   BAA7 A5A7 *B5A7 7B
BBBc                 6    | j                   j                         S )z(Indicate if the audio stream has hungup.)r   r~   rv   s    r)   hungupzAudioStream.hungup9  s     {{!!##r2   c                 6    | j                   j                         S )z-Indicate in the input stream buffer is empty.)r   emptyrv   s    r)   r   zAudioStream.empty>  s     {{  ""r2   c                     | j                   xr | j                  }| j                  duxr7 | j                  j                          xr | j                  j                         }|xr |S )z;Indicate if the audio stream has hungup and been processed.N)r   r   r   is_aliver   )rH   
input_doneoutput_dones      r)   completezAudioStream.completeC  sa     [[/TZZ
LL$ $LL))++$!!# 	
 )k)r2   c                 P    | j                   r| j                   j                         S y)z&Indicate if the ASR stream is running.F)r   r   rv   s    r)   runningzAudioStream.runningN  s!     <<<<((**r2   itemtimeoutc                     | j                   5  | j                  rt        d      |t        u r| j                  j                          | j                  j                  ||       ddd       y# 1 sw Y   yxY w)zPut a new item into the queue.z?The audio stream has already been hungup. Cannot put more data.r   N)r   r   RuntimeErrorr   r   rz   r   put)rH   r   r   s      r)   r   zAudioStream.putU  s`    ^^ 	3{{"U  v~!KKOOD'O2	3 	3 	3s   AA--A6c                    K   t        j                         }t        j                  |j                  d| j                  |      |       d{    y7 w)z$Async put a new item into the queue.N)ru   r   wait_forr   r   )rH   r   r   loops       r)   aputzAudioStream.aput`  s=     %%'t33D$((DI7SSSs   A	AAAc                 0    | j                  t        |       y)zSend the hangup signal.N)r   r   rH   r   s     r)   closezAudioStream.closee  s    !r2   c                 L   K   | j                  t        |       d{    y7 w)zAsync send the hangup signal.N)r   r   r   s     r)   aclosezAudioStream.aclosei  s     ii(((s   $"$	responseszrasr.StreamingRecognizeResponsec                 "     j                   rt        d      t        j                  dd      d	 fd}t        j                  |       _        d j
                  _         j
                  j                          j                          y)
zIDrain the responses from the provided iterator and put them into a queue.z,An ASR instance has already been registered.rX   r   r   Nc                  2   j                          D ]   } | j                  s| j                  D ]  }|j                  s|j                  rwj                  j                          j                  j                          t        t        |j                  d   j                        }j                  j                  |       j                  j                         rj                  j                          j                  j                            y)zConsume the ASR Generator.r   N)r   resultsalternativesis_finalr   r|   r   rz   r   r\   
transcriptr   r   r~   )responseresultr   has_startedr   rH   s      r)   workerz$AudioStream.register.<locals>.workert  s    % 0''&.. 0F!.. ))//1++-%)#v/B/B1/E/P/P%Q

3!..557))--/--/0	0r2   )targetTr   )	r   r   rs   BarrierThreadr   daemonstartr   )rH   r   r   r   s   `` @r)   registerzAudioStream.registerm  si    <<MNN''15	0* !''v6"r2   )r   N) r-   r.   r/   r0   rs   r   rg   r   r   ro   r   r   rL   rw   r	   bytesr   r   StreamInputTyper   rM   r   r   r   r   r   r   r   r   r   r
   r   r1   r2   r)   r   r      sv   /~~KKKKNi&&'' D $)E4$56 $"$!? $& $ $ $ #t # # *$ * *   	3 	3(3- 	34 	3T T# TRV T
"Xc] "d ")HSM )T )(+L"M RV r2   r   c            	       
   e Zd ZU dZdZeed<   dZeed<    edd      Z	e
ed	<    ed
d      Zeed<    ed
d      Zeed<    ed
      edeeef   deeef   fd              Zedd       ZddZ	 ddedee   dedefdZy)RivaASRzNA runnable that performs Automatic Speech Recognition (ASR) using NVIDIA Riva.nvidia_riva_asrr   zA Runnable for converting audio bytes to a string.This is useful for feeding an audio stream into a chain andpreprocessing that audio to create an LLM prompt.rP   r=   z7The number of audio channels in the input audio stream.rS   audio_channel_countTz\Controls whether or not Riva should attempt to filter profanity out of the transcribed text.profanity_filterz]Controls whether Riva should attempt to correct senetence puncuation in the transcribed text.enable_automatic_punctuationra   valuesr"   c                     t               }|S z4Validate the Python environment and input arguments.r*   rB   r   _s      r)   _validate_environmentzRivaASR._validate_environment        !r2   c                     t               }|j                  d|j                  | j                  | j                  | j
                  d| j                  | j                  | j                              S )z)Create and return the riva config object.Tr=   )rk   rl   r   max_alternativesr   r   rm   )interim_resultsconfig)	r*   StreamingRecognitionConfigRecognitionConfigrk   rl   r   r   r   rm   rG   s     r)   r  zRivaASR.config  sq     *+55 00"&"8"8$($<$<!"!%!6!6-1-N-N"00 1  6 
 	
r2   c                     t               }	 |j                  | j                        S # t        $ r}t	        d      |d}~ww xY w);Connect to the riva service and return the a client object.z5Error raised while connecting to the Riva ASR server.N)r*   
ASRServicer`   	Exception
ValueErrorrH   rI   r(   s      r)   _get_servicezRivaASR._get_service  sG    )+	))$))44 	G	   ' 	A<ANinputr  kwargsc                    |j                   s>| j                         }|j                  || j                        }|j	                  |       g }|j
                  s|j                  j                  5  |j                  j                  j                  d      }ddd       r|j                  j                         sT	 ||j                  j                         gz  }|j                  j                          |j                  j                         sTt        j                  dt!        |             dj#                  |      j%                         S |j
                  sy# 1 sw Y   xY w# t        j                  $ r Y w xY w)z3Transcribe the audio bytes into a string with Riva.)audio_chunksstreaming_configg?NzRiva ASR returning: %s r   )r   r  streaming_response_generatorr  r   r   r   	not_emptyr   r   
get_nowaitr   r   r   _LOGGERdebugreprjoinstrip)rH   r  r  r  servicer   full_responsereadys           r)   invokezRivaASR.invoke  s;    }}'')G<<"!% = I NN9% $&..'' 9..33C89 ,,,,.!%%,,*A*A*C)DD LL**,  ,,,,. 6]8KLxx.4466 .. 9 9 !;; ! !s   /&E:E% E"%E;:E;)r"   z&riva.client.StreamingRecognitionConfig)r"   zriva.client.ASRServicer   )r-   r.   r/   r0   r   r\   rg   rP   r   r   rL   r   r   r   r   rK   r   r   r  rM   r  r  ASRInputTyper   r   ASROutputTyper$  r1   r2   r)   r   r     s   
 Y!D#!	<    %	P   #5d  */<* $  4S> d38n   
 
 
  ,0   (  	 
 
 r2   r   c                   |   e Zd ZU dZdZeed<   dZeed<    edd      Z	eed	<    ed
d      Z
ee   ed<    ed      edeeef   deeef   fd              Z ed      ededefd              ZddZ	 ddedee   dedefdZ	 ddee   dee   dee   dee   fdZ	 ddee   dee   dee   deed
f   fdZy
)RivaTTSz?A runnable that performs Text-to-Speech (TTS) with NVIDIA Riva.nvidia_riva_ttsr   z_A tool for converting text to speech.This is useful for converting LLM output into audio bytes.rP   zEnglish-US.Female-1zThe voice model in Riva to use for speech. Pre-trained models are documented in [the Riva documentation](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/tts/tts-overview.html).rS   
voice_nameNzThe directory where all audio files should be saved. A null value indicates that wave files should not be saved. This is useful for debugging purposes.r   Tr   r   r"   c                     t               }|S r   r   r  s      r)   r  zRivaTTS._validate_environment   r  r2   vc                     |rAt        j                  |      }|j                  dd       t        |j	                               S |S )NT)parentsexist_ok)pathlibPathmkdirr\   absolute)rB   r,  dirpaths      r)   _output_directory_validatorz#RivaTTS._output_directory_validator'  s=     ll1oGMM$M6w'')**r2   c                     t               }	 |j                  | j                        S # t        $ r}t	        d      |d}~ww xY w)r  z5Error raised while connecting to the Riva TTS server.N)r*   SpeechSynthesisServicer`   r  r  r  s      r)   r  zRivaTTS._get_service0  sG    )+	55dii@@ 	G	r  r  r  r  c                 V    dj                  | j                  t        |g                  S )zDPerform TTS by taking a string and outputting the entire audio file.r2   )r  	transformiter)rH   r  r  r  s       r)   r$  zRivaTTS.invoke:  s"     xxtUG}566r2   c              +     K   | j                         }t        | j                  | j                        \  }}t	        |      D ]  }t
        j                  d|       |j                  || j                  | j                  | j                  j                  | j                        }|D ]3  }	t        t        |	j                        }
|r|j                  |
       |
 5  |r'|j!                          t
        j                  d|       yyw)zHPerform TTS by taking a stream of characters and streaming output bytes.zRiva TTS chunk: %s)textr*  rm   rk   sample_rate_hzzRiva TTS wrote file: %sN)r  r   r   rl   r   r  r  synthesize_onliner*  rm   rk   rJ   r   r   audiowriteframesrawr   )rH   r  r  r  r!  r   r   r   r   respr?  s              r)   r9  zRivaTTS.transformC  s      ##% #0!!4#9#9#
x
 %U+ 	EMM.6  11??"00//#55 2 I " UDJJ/++E2		( NNMM3]C s   DDc                P   	
K   t        j                         t        j                         t        j                         dfd}dt        t
           ffd
d
 fd	d	fd}j                   |             }j                   |             }	 	 t        j                  j                         d       d{   }j                          |t        u rn| L| d{    | d{    y7 8# t         j                  j                  $ r Y w xY w7 47 ,w)	zGIntercept async transforms and route them to the synchronous transform.r"   Nc                  x   K   2 3 d{   } j                  |        7 6 j                  t               yw)z#Produce input into the input queue.N)
put_nowait_TRANSFORM_END)rc   r  input_queues    r)   	_producerz%RivaTTS.atransform.<locals>._produceru  s:     " , ,c&&s+,U"">2s   :#!#:#:c               3      K   	 	 j                  d      } | t        k(  ry|  "# t        j                  $ r Y 8w xY ww)zIterate over the input_queue.r   r   N)r   r   r   rE  )rc   rF  s    r)   _input_iteratorz+RivaTTS.atransform.<locals>._input_iterator{  sM     %//#/6C .(	  {{ s    A ' A =A =A c                      j                                D ]  } j                  |         j                  t               y)z!Consume the input with transform.N)r9  rD  rE  )rc   rI  	out_queuerH   s    r)   	_consumerz%RivaTTS.atransform.<locals>._consumer  s:    ~~o&78 *$$S)*  0r2   c                  F   K   j                  d        d{    y7 w)z"Coroutine that wraps the consumer.N)r   )rL  r   s   r)   _consumer_coroz*RivaTTS.atransform.<locals>._consumer_coro  s     &&tY777s   !!r   r   )ru   get_running_loopr   r   r
   r   create_taskr   r   
exceptionsTimeoutErrorr   rE  )rH   r  r  r  rG  rN  producerconsumerrc   rL  rI  rF  r   rK  s   ``       @@@@@r)   
atransformzRivaTTS.atransformj  s      '')#(;;=#*==?		3		,!7 			1	8 ##IK0##N$45#,,Y]]_cBB !n$I   C%%22  	sZ   BD&'C? C=C? 	$D&-D".	D&7D$8D&=C? ?DD&DD&$D&)r"   z"riva.client.SpeechSynthesisServicer   )r-   r.   r/   r0   r   r\   rg   rP   r   r*  r   r   r   rK   r   r   r  r   r5  r  r   r   TTSOutputTyper$  r
   r9  r   r   rU  r1   r2   r)   r(  r(     s   
 J!D#!	E   aJ  ',5'hsm  4S> d38n   
 !"C C   # ,077 (7 	7
 
7 ,0%D%%D (%D 3-	%D
 
-	 %DT ,05\*5 (5 3-	5
 
t+	,5r2   r(  )r"   zriva.client)Nr0   ru   loggingr0  r   r   rs   r   enumr   typingr   r   r   r   r   r	   r
   r   r   r   r   r   langchain_core.messagesr   r   langchain_core.prompt_valuesr   langchain_core.runnablesr   r   pydanticr   r   r   r   r   r   r$   r'   riva.client.proto.riva_asr_pb2r&   protoriva_asr_pb2rasr	getLoggerr-   r  r   r   r   r*   r,   r   rE  r\   r4   rO   ri   ro   float
Wave_writer   r   r   r   r   StreamOutputTyper   r%  r&  r   r   rV  r(  NVIDIARivaASRNVIDIARivaTTSNVIDIARivaStreamr1   r2   r)   <module>ri     s   0            < 4 I  11
'

H
%  9 
" " 
$8T $8N%I %BI (" "Dsm27
8C=(4??334"	 	3 	H^4 3d?9S 6 y() L L` c}45cP S*k12_}45_F  r2   