
    -cJj=$                     n    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 d dlmZ defdZ G d de      Zy	)
    )Path)ListOptional)FeatureExtractorConfigKeywordSpotterConfigOnlineModelConfigOnlineTransducerModelConfigOnlineStreamProviderConfig)KeywordSpotterfc                 J    t        |       j                         s
J |  d       y )Nz does not exist)r   is_file)r   s    e/Users/ahmed/devFolder/claude-voice/.venv/lib/python3.12/site-packages/sherpa_onnx/keyword_spotter.py_assert_file_existsr      s"    7??3?33    c                       e Zd ZdZ	 	 	 	 	 	 	 	 	 ddededededededed	ed
edededededefdZdefdZ	dde
e   fdZdefdZdee   fdZdedefdZdedefdZdedee   fdZdedee   fdZy) r   uB	  A class for keyword spotting.

    It uses streaming transducer models with keyword lists.

    Example using pre-defined keywords::

        import numpy as np
        import sherpa_onnx
        import soundfile as sf

        kws = sherpa_onnx.KeywordSpotter(
            tokens="./sherpa-onnx-kws-zipformer-wenetspeech-3.3M-2024-01-01-mobile/tokens.txt",
            encoder="./sherpa-onnx-kws-zipformer-wenetspeech-3.3M-2024-01-01-mobile/encoder-epoch-12-avg-2-chunk-16-left-64.int8.onnx",
            decoder="./sherpa-onnx-kws-zipformer-wenetspeech-3.3M-2024-01-01-mobile/decoder-epoch-12-avg-2-chunk-16-left-64.onnx",
            joiner="./sherpa-onnx-kws-zipformer-wenetspeech-3.3M-2024-01-01-mobile/joiner-epoch-12-avg-2-chunk-16-left-64.int8.onnx",
            keywords_file="./sherpa-onnx-kws-zipformer-wenetspeech-3.3M-2024-01-01-mobile/test_wavs/test_keywords.txt",
            num_threads=2,
            provider="cpu",
        )

        audio, sample_rate = sf.read("test.wav", dtype="float32")

        tail_paddings = np.zeros(int(0.66 * sample_rate), dtype=np.float32)

        stream = kws.create_stream()
        stream.accept_waveform(sample_rate, audio)
        stream.accept_waveform(sample_rate, tail_paddings)
        stream.input_finished()

        while kws.is_ready(stream):
            kws.decode_stream(stream)
            r = kws.get_result(stream)
            if r != "":
                # Remember to call reset right after detecting a keyword
                kws.reset_stream(stream)
                print(f"Detected: {r}")

    Example with inline keywords::

        # Add extra keywords at stream creation time
        stream = kws.create_stream("y ǎn y uán @演员/zh ī m íng @知名")
        stream.accept_waveform(sample_rate, audio)
        stream.accept_waveform(sample_rate, tail_paddings)
        stream.input_finished()

        while kws.is_ready(stream):
            kws.decode_stream(stream)
            r = kws.get_result(stream)
            if r != "":
                kws.reset_stream(stream)
                print(f"Detected: {r}")

    Please refer to the following files for more usages:

    - `<https://github.com/k2-fsa/sherpa-onnx/blob/master/python-api-examples/keyword-spotter.py>`_
    - `<https://github.com/k2-fsa/sherpa-onnx/blob/master/python-api-examples/keyword-spotter-from-microphone.py>`_
    tokensencoderdecoderjoinerkeywords_filenum_threadssample_ratefeature_dimmax_active_pathskeywords_scorekeywords_thresholdnum_trailing_blanksproviderdevicec           	      &   t        |       t        |       t        |       t        |       |dkD  sJ |       t        |||      }t        ||      }t        ||||      }t	        ||      }t        |||	||
||      }t        |      | _        y)a1  
        Please refer to
        `<https://k2-fsa.github.io/sherpa/onnx/kws/pretrained_models/index.html>`_
        to download pre-trained models for different languages, e.g., Chinese,
        English, etc.

        Args:
          tokens:
            Path to ``tokens.txt``. Each line in ``tokens.txt`` contains two
            columns::

                symbol integer_id

          encoder:
            Path to ``encoder.onnx``.
          decoder:
            Path to ``decoder.onnx``.
          joiner:
            Path to ``joiner.onnx``.
          keywords_file:
            The file containing keywords, one word/phrase per line, and for each
            phrase the bpe/cjkchar/pinyin are separated by a space.
          num_threads:
            Number of threads for neural network computation.
          sample_rate:
            Sample rate of the training data used to train the model.
          feature_dim:
            Dimension of the feature used to train the model.
          max_active_paths:
            Use only when decoding_method is modified_beam_search. It specifies
            the maximum number of active paths during beam search.
          keywords_score:
            The boosting score of each token for keywords. The larger the easier to
            survive beam search.
          keywords_threshold:
            The trigger threshold (i.e. probability) of the keyword. The larger the
            harder to trigger.
          num_trailing_blanks:
            The number of trailing blanks a keyword should be followed. Setting
            to a larger value (e.g. 8) when your keywords has overlapping tokens
            between each other.
          provider:
            onnxruntime execution providers. Valid values are: cpu, cuda, coreml.
          device:
            onnxruntime cuda device index.
        r   )r   r   r   )r    r!   )
transducerr   r   provider_config)sampling_rater   )feat_configmodel_configr   r   r   r   r   N)r   r	   r   r   r   r   _KeywordSpotterkeyword_spotter)selfr   r   r   r   r   r   r   r   r   r   r   r   r    r!   transducer_configr$   r'   r&   keywords_spotter_configs                       r   __init__zKeywordSpotter.__init__Q   s    ~ 	F#G$G$F#Q++7
 )

 )(#+	
 -%#

 #7#%- 3)1'#
  //FGr   sc                 :    | j                   j                  |       y)zReset the stream after a keyword is detected.

        You should call this right after a keyword is detected and before
        feeding more audio to the stream.

        Args:
          s:
            The stream to be reset.
        N)r)   resetr*   r.   s     r   reset_streamzKeywordSpotter.reset_stream   s     	""1%r   Nkeywordsc                 p    || j                   j                         S | j                   j                  |      S )ar  Create a new stream for keyword spotting.

        Args:
          keywords:
            Optional extra keywords to add for this stream. The format is the
            same as the keywords file content. Use ``None`` to use only the
            keywords from the keywords file provided to the constructor.
        Returns:
          A new ``OnlineStream`` object.
        )r)   create_stream)r*   r3   s     r   r5   zKeywordSpotter.create_stream   s6     ''5577''55h??r   c                 :    | j                   j                  |       y)zlDecode one step for the given stream.

        Args:
          s:
            The stream to decode.
        N)r)   decode_streamr1   s     r   r7   zKeywordSpotter.decode_stream   s     	**1-r   ssc                 :    | j                   j                  |       y)z{Decode on multiple streams at the same time.

        Args:
          ss:
            A list of streams to decode.
        N)r)   decode_streams)r*   r8   s     r   r:   zKeywordSpotter.decode_streams   s     	++B/r   returnc                 8    | j                   j                  |      S )zCheck whether the stream has enough frames for decoding.

        Args:
          s:
            The stream to check.
        Returns:
          ``True`` if the stream has enough frames for decoding.
          ``False`` otherwise.
        )r)   is_readyr1   s     r   r=   zKeywordSpotter.is_ready   s     ##,,Q//r   c                 h    | j                   j                  |      j                  j                         S )a  Get the keyword spotting result as a string.

        Args:
          s:
            The stream to get the result from.
        Returns:
          A string containing the detected keyword. Returns an empty string if
          no keyword is detected.
        )r)   
get_resultkeywordstripr1   s     r   r?   zKeywordSpotter.get_result   s*     ##..q199??AAr   c                 L    | j                   j                  |      j                  S )zGet the token list of the keyword result.

        Args:
          s:
            The stream to get the tokens from.
        Returns:
          A list of strings, each being a token.
        )r)   r?   r   r1   s     r   r   zKeywordSpotter.tokens   s!     ##..q1888r   c                 L    | j                   j                  |      j                  S )zGet the timestamp list of the keyword result.

        Args:
          s:
            The stream to get the timestamps from.
        Returns:
          A list of floats, each being the timestamp (in seconds) of the
          corresponding token.
        )r)   r?   
timestampsr1   s     r   rD   zKeywordSpotter.timestamps
  s!     ##..q1<<<r   )	   i>  P      g      ?g      ?   cpur   )N)__name__
__module____qualname____doc__strintfloatr-   r
   r2   r   r5   r7   r   r:   boolr=   r?   r   rD    r   r   r   r      se   8B " ! #$(#$fHfH fH 	fH
 fH fH fH fH fH fH fH "fH !fH fH fHP
&l 
&@hsm @ .| .0l!3 0
0, 
04 
0
BL 
BS 
B	9 	9c 	9
=L 
=T%[ 
=r   r   N)pathlibr   typingr   r   sherpa_onnx.lib._sherpa_onnxr   r   r   r	   r
   r   r   r(   rN   r   objectrR   r   r   <module>rW      s7     !  K43 4~=V ~=r   