
    (HJj                     8   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 d dlmZmZmZmZ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!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z) ddl*m+Z+ ddl,m-Z- ddl.m/Z/m0Z0 dZ1dZ2dZ3dZ4dZ5d Z6dZ7dZ8dZ9dZ:dZ;dZ<d Z=d Z> ej~                   ej                               ZAej                  dRdej                  deeej                        fd       ZEe
 G d d             ZFd ZGddddddddd dddd ej                  dej                  d!eId"eeej                  gej                  f      d#eeeej                  ej                  gej                  f         d$eeI   d%ee   d&eId'eeI   d(eId)eId*eeeIeIgdf      d+eej                     d,eeej                  ej                  f   ddf   fd-ZJd.ddddd/ddd d0	d ej                  dej                  d1ej                  d2eId!eId"eeej                  gej                  f      d#eeeej                  ej                  gej                  f         d%ee   d&eId'eeI   d(eId)eId,eeej                  ej                  eKf   ddf   fd3ZL	 	 dSdej                  d4eee-f   d eeMej                  eeI   f   d!eId1eej                     d,eeFddf   fd5ZN	 dTdej                  d4eee-f   d eeMeeI   f   d6eKd,eMf
d7ZOdRd8ZPdRd9ZQe
 G d: d;             ZRd< ZSd= ZTd> ZUd? ZVd@ ZW G dA dB      ZX G dC dD      ZY G dE dF      ZZ G dG dH      Z[e
 G dI dJ             Z\	 	 	 	 dUdKeeeI      dLeeee         d!eeIeeI   f   d6eKdMeKd,e\fdNZ]dO Z^e_dPk(  r e`dQ        e^        yy)V    N)deque)	dataclass)partial)AnyCallable	GeneratorListOptionalSequenceTupleUnion)tree_reduce)PreTrainedTokenizer   cache)	ArraysCacheBatchKVCacheBatchRotatingKVCache	CacheListKVCacheQuantizedKVCacheRotatingKVCacheTokenBufferload_prompt_cache)make_sampler)TokenizerWrapper)#does_model_support_input_embeddingsloadhellod           g      ?z(mlx-community/Llama-3.2-3B-Instruct-4biti  c                 &    | j                         dvS )N)falsef)lower)strings    Y/Users/ahmed/devFolder/claude-voice/.venv/lib/python3.12/site-packages/mlx_lm/generate.pystr2boolr)   ;   s    <<>//    c                     t        j                  d      } | j                  dt        dt         dd       | j                  dd	d
       | j                  dt        d       | j                  dt        ddd       | j                  ddd       | j                  ddt
        d       | j                  ddd       | j                  ddt        t        d       | j                  d t        t        d!       | j                  d"t        t        d#       | j                  d$t        t        d%       | j                  d&t        t        d'       | j                  d(t        t        d)       | j                  d*t        d+d,       | j                  d-t        t        d.       | j                  d/t        t        d0       | j                  d1d	d2       | j                  d3d	d4       | j                  d5d6d7       | j                  d8t         d9d:       | j                  d;t        d<d       | j                  d=t        dd>       | j                  d?d@d	dA       | j                  dBt        dCd       | j                  dDt        dEdF       | j                  dGdHt        t"        I       | j                  dJt        dKd       | j                  dLt        dMdN       | S )Oz&Set up and return the argument parser.zLLM inference script)descriptionz--modelz[The path to the local model directory or Hugging Face repo. If no model is specified, then z	 is used.N)typehelpdefaultz--trust-remote-code
store_truez)Enable trusting remote code for tokenizer)actionr.   z--adapter-pathz9Optional path for the trained adapter weights and config.)r-   r.   z--extra-eos-token +z:Add tokens in the list of eos tokens that stop generation.)r-   r/   nargsr.   z--system-promptz.System prompt to be used for the chat template)r/   r.   z--promptz-pz;Message to be processed by the model ('-' reads from stdin)z--prefill-responsez1Prefill response to be used for the chat templatez--max-tokensz-mz$Maximum number of tokens to generate)r-   r/   r.   z--tempzSampling temperaturez--top-pzSampling top-pz--min-pzSampling min-pz--top-kzSampling top-kz--xtc-probabilityz5Probability of XTC sampling to happen each next tokenz--xtc-thresholdr"   zDThresold the probs of each next token candidate to be sampled by XTCz--min-tokens-to-keepz*Minimum tokens to keep for min-p sampling.z--seedz	PRNG seedz--ignore-chat-templatez9Use the raw prompt without the tokenizer's chat template.z--use-default-chat-templatezUse the default chat templatez--chat-template-configzAdditional config for `apply_chat_template`. Should be a dictionary of string keys to values represented as a JSON decodable string.)r.   r/   z	--verboseTzTLog verbose output when 'True' or 'T' or only print the response when 'False' or 'F'z--max-kv-sizez$Set the maximum key-value cache sizez--prompt-cache-filez;A file containing saved KV caches to avoid recomputing themz--quantize-activationsz-qazSQuantize activations using the same quantization config as the corresponding layer.z	--kv-bitszFNumber of bits for KV cache quantization. Defaults to no quantization.z--kv-group-sizez%Group size for KV cache quantization.@   z--quantized-kv-startzLWhen --kv-bits is set, start quantizing the KV cache from this step onwards.)r.   r-   r/   z--draft-modelz,A model to be used for speculative decoding.z--num-draft-tokensz:Number of tokens to draft when using speculative decoding.   )argparseArgumentParseradd_argumentstrDEFAULT_MODELDEFAULT_PROMPTintDEFAULT_MAX_TOKENSfloatDEFAULT_TEMPDEFAULT_TOP_PDEFAULT_MIN_PDEFAULT_TOP_KDEFAULT_XTC_PROBABILITYDEFAULT_MIN_TOKENS_TO_KEEPDEFAULT_SEEDr)   DEFAULT_QUANTIZED_KV_START)parsers    r(   setup_arg_parserrI   ?   s   $$1GHF
..;_IG    8  
 H  
 I   =  
 J	   @  
 "3   ul9O   };K   };K   ]9I   'D	   S	   *9	   	    H  
 %,  
  I	   c	   3	   J	    b	   U	   4	   "*   ;	   I	   Mr*   modelstreamsc              #   N  K   t         j                  j                         s	 d yt        d | d      }t        j                         d   }|d|z  kD  r|dz  }|dz  }t        d| d| d	       t        j                  |      }	 d ||D ]  }t        j                  |        nt        j                          t        j                  |       y# w xY w# ||D ]  }t        j                  |        nt        j                          t        j                  |       w xY ww)
a  
    A context manager to temporarily change the wired limit.

    Note, the wired limit should not be changed during an async eval.  If an
    async eval could be running pass in the streams to synchronize with prior
    to exiting the context manager.
    Nc                 X    t        |t        j                        r| |j                  z   S | S N)
isinstancemxarraynbytes)accxs     r(   <lambda>zwired_limit.<locals>.<lambda>   s!    Z288-D3>M#Mr*   r    max_recommended_working_set_sizeg?i   z0[WARNING] Generating with a model that requires z6 MB which is close to the maximum recommended size of z MB. This can be slow. See the documentation for possible work-arounds: https://github.com/ml-explore/mlx-lm/tree/main#large-models)rP   metalis_availabler   device_infoprintset_wired_limitsynchronize)rJ   rK   model_bytesmax_rec_sizemodel_mb
max_rec_mb	old_limitss           r(   wired_limitrc      s!     88  "	!MuVW
 ~~'(JK|++"e+H%.JB8* MEEOL QNN &&|4		*" ANN1% !  y)1 & " ANN1% !  y)s6   D%C AD%C 
A	D%CD%A
D""D%c                       e Zd ZU dZeed<   eed<   ej                  ed<   e	ed<   eed<   e
ed<   eed<   e
ed	<   e
ed
<   dZee   ed<   y)GenerationResponsea  
    The output of :func:`stream_generate`.

    Args:
        text (str): The next segment of decoded text. This can be an empty string.
        token (int): The next token.
        from_draft (bool): Whether the token was generated by the draft model.
        logprobs (mx.array): A vector of log probabilities.
        prompt_tokens (int): The number of tokens in the prompt.
        prompt_tps (float): The prompt processing tokens-per-second.
        generation_tokens (int): The number of generated tokens.
        generation_tps (float): The tokens-per-second for generation.
        peak_memory (float): The peak memory used so far in GB.
        finish_reason (str): The reason the response is being sent: "length", "stop" or `None`
    texttokenlogprobs
from_draftprompt_tokens
prompt_tpsgeneration_tokensgeneration_tpspeak_memoryNfinish_reason)__name__
__module____qualname____doc__r:   __annotations__r=   rP   rQ   boolr?   ro   r
   r2   r*   r(   re   re     sO      IJhh#'M8C='r*   re   c                     |y t        |       D ]8  \  }}t        |d      s|j                  |k\  s#|j                  ||      | |<   : y )Nto_quantized)
group_sizebits)	enumeratehasattroffsetrw   )prompt_cachequantized_kv_startkv_group_sizekv_bitsecs         r(   maybe_quantize_kv_cacher   +  sI    ,'11n%!((6H*HnnGnTLO (r*         r5   )
max_tokenssamplerlogits_processorsmax_kv_sizer}   prefill_step_sizer   r   r~   prompt_progress_callbackinput_embeddingspromptr   r   r   r   r}   r   r   r   r~   r   r   returnc             #     K   |_t              st        d      t        |       dkD  rTt        |       t        |      k7  r=t        dt        |       dt        |        d      t        |       dk(  rt        d      dt        j                  |      |xs d	 }t        j                  t        |
|	|
      xs d dt        j                  dt        t        j                     ffdddt        j                  dt        t        j                     ffd}t        j                  t              5  |t        |      n
t        |       }d} |||       ||z
  dkD  r||z
  dz
  }t        ||      } | d| d   ||d| d   nd               t        j                  D cg c]  }|j                   c}       ||z  } |||       | |d } |||d n|}t        j                           ||z
  dkD  r || |      \  }}ddd       t        j"                         d}	 ||k7  r! ||      \  }}t        j"                  ||       |dk(  rt        j                  |        ||       ||k(  ry|j%                         |f |dz  dk(  rt        j                           }}|dz  }c c}w # 1 sw Y   xY ww)a  
    A generator producing token ids based on the given prompt from the model.

    Args:
        prompt (mx.array): The input prompt.
        model (nn.Module): The model to use for generation.
        max_tokens (int): The maximum number of tokens. Use``-1`` for an infinite
          generator. Default: ``256``.
        sampler (Callable[mx.array, mx.array], optional): A sampler for sampling a
          token from a vector of log probabilities. Default: ``None``.
        logits_processors (List[Callable[[mx.array, mx.array], mx.array]], optional):
          A list of functions that take tokens and logits and return the processed
          logits. Default: ``None``.
        max_kv_size (int, optional): Maximum size of the key-value cache. Old
          entries (except the first 4 tokens) will be overwritten.
        prompt_cache (List[Any], optional): A pre-computed prompt cache. Note, if
          provided, the cache will be updated in place.
        prefill_step_size (int): Step size for processing the prompt.
        kv_bits (int, optional): Number of bits to use for KV cache quantization.
          None implies no cache quantization. Default: ``None``.
        kv_group_size (int): Group size for KV cache quantization. Default: ``64``.
        quantized_kv_start (int): Step to begin using a quantized KV cache.
           when ``kv_bits`` is non-None. Default: ``0``.
        prompt_progress_callback (Callable[[int, int], None]): A call-back which takes the
           prompt tokens processed so far and the total number of prompt tokens.
        input_embeddings (mx.array, optional): Input embeddings to use instead of or in
          conjunction with prompt tokens. Default: ``None``.

    Yields:
        Tuple[mx.array, mx.array]: One token and a vector of log probabilities.
    Nz(Model does not support input embeddings.r   z8When providing input_embeddings, their sequence length (z0) must match the sequence length of the prompt (z), or the prompt must be empty.z=Either input_embeddings or prompt (or both) must be provided.)r   c                       y rN   r2   )_s    r(   rU   zgenerate_step.<locals>.<lambda>y  s    tr*   r~   r   r   c                 0    t        j                  | d      S NaxisrP   argmaxrT   s    r(   rU   zgenerate_step.<locals>.<lambda>      BIIab$9r*   input_tokensr   c                 2    | | |      S  |       S )N)r   r   r   r2   )r   r   rJ   r}   s     r(   _model_callz"generate_step.<locals>._model_call  s-    'LCS  \::r*   c                    t        j                  t              5   | d    ||d    nd       }|d d dd d f   }r9t        |       dkD  r+t        j                  | g      n| D ]  } ||      }  	       |t        j
                  |d      z
  } 
|      }||j                  d      fcd d d        S # 1 sw Y   y xY w)Nr   r   r   r   T)keepdims)rP   streamgeneration_streamlenconcat	logsumexpsqueeze)r   r   logits	processorrh   sampledr   r   r}   quantize_cache_fnr   tokenss         r(   _stepzgenerate_step.<locals>._step  s     YY() )$/.>.J$T*PTF Ar1H%F S%6%: ) IIv|45% 
 "3I&vv6F "3 l+Vd CCHh'GH,,Q/// *))s   BB==Cr   r   r   rN   )r   
ValueErrorr   r   make_prompt_cache	functoolsr   r   rP   rQ   r
   r   r   minevalstateclear_cache
async_evalitem)r   rJ   r   r   r   r   r}   r   r   r   r~   r   r   r   total_prompt_tokensprompt_processed_tokens	remainingn_to_processr   yrh   nnext_ynext_logprobsr   r   r   s    ` `` `                 @@@r(   generate_stepr   3  s    ^ #259GHH[1_V4D0E!EJ3O_K`Ja bAADV N(( 
 
V	K
 	
 F ..#

  8LO!))-#	 :9G;"(( ;hrxx>P ;0BHH 08J 0 08 
$	%%5%AC !s6{ 	 #$ !8:MN!$;;a?,/FF!KI0)<L#M\248 (3 %]l3D9 l+GGl3lQWWl34#|3#$%<>QRLM*F $/ !/% 
 NN+ "$;;a?. BRS8; 
&> MM!X	A

?$)!H!FMMM&-06GGAJ$%8:MN
?ffh  s7a<NNm8	Q  4% 
&	%s8   D;KA5K9K
?KKB*KKKK      )	num_draft_tokensr   r   r   r}   r   r   r   r~   draft_modelr   c       	      #      !K   | j                  t        j                        }d |+t        j                  |      t        j                        n0|dt        |j                         |t        |j                        d t        j                        sBD ch c](  }|j                         rt        |      j                  * }}t        d| d      xs d t        j                  t        ||
|	      !fdd !fd	!fd	}fd
}fd}t        j                  t               5   ||      } |||      }ddd       d}d}d}	 	 t#        ||z
  |      } ||      } " d j$                  |j$                  z
  |z
  dz     t        j&                  ||g      } |||dz         \  }}t        j(                  ||       |j+                         }|j+                         }d}||k  r2||   ||   ||   }}}||k7  rn|dz  }|dz  }||df ||k(  rn||k  r2||k  r|dz  }||   ||   df ||k(  rnt        j,                  ||   gt        j                        }|}||k(  r<t        j&                  t        j,                  |dd t        j                        |g      }  dt/        ||z
  d          |||       {	  |||       yc c}w # 1 sw Y   xY w#  |||       w xY ww)au  
    A generator producing token ids based on the given prompt from the model.

    Args:
        prompt (mx.array): The input prompt.
        model (nn.Module): The model to use for generation.
        draft_model (nn.Module): The draft model for speculative decoding.
        num_draft_tokens (int, optional): The number of draft tokens for
          speculative decoding. Default: ``2``.
        max_tokens (int): The maximum number of tokens. Use``-1`` for an infinite
          generator. Default: ``256``.
        sampler (Callable[[mx.array], mx.array], optional): A sampler for sampling a
          token from a vector of log probabilities. Default: ``None``.
        logits_processors (List[Callable[[mx.array, mx.array], mx.array]], optional):
          A list of functions that take tokens and logits and return the processed
          logits. Default: ``None``.
        prompt_cache (List[Any], optional): A pre-computed prompt cache. Note, if
          provided, the cache will be updated in place. The cache must be trimmable.
        prefill_step_size (int): Step size for processing the prompt.
        kv_bits (int, optional): Number of bits to use for KV cache quantization.
          None implies no cache quantization. Default: ``None``.
        kv_group_size (int): Group size for KV cache quantization. Default: ``64``.
        quantized_kv_start (int): Step to begin using a quantized KV cache.
           when ``kv_bits`` is non-None. Default: ``0``.

    Yields:
        Tuple[mx.array, mx.array, bool]: One token, a vector of log probabilities,
          and a bool indicating if the token was generated by the draft model
    Nz<Speculative decoding requires a trimmable prompt cache (got z).c                 0    t        j                  | d      S r   r   r   s    r(   rU   z+speculative_generate_step.<locals>.<lambda>  r   r*   r   c                 v    rD ]  } || |      } |t        j                  |dd      z
  } |      }||fS )Nr   Tr   r   )rP   r   )r   r   r   rh   r   r   r   s        r(   _process_and_samplez6speculative_generate_step.<locals>._process_and_sample   sI    .	"662 / BLLb4HHH({r*   r   c           
      6   t        j                  t              5   | |d    |      }|d d | d d d f   } |       
rg g }}|dkD  r	|d |dz
    }t        |      D ]U  }t        j                  |g      n| 	|d d |d d f         \  }}|j                  |       |j                  |       W t        j                  |d      t        j                  |d      fcd d d        S  	d |j                  d            cd d d        S # 1 sw Y   y xY w)Nr   r   r   r   )rP   r   r   rangeconcatenateappendr   )rJ   r   r   	n_predictr   out_yout_logprobsirh   r   r   prev_tokensr   s            r(   r   z(speculative_generate_step.<locals>._step)  s   YY()1T7%0FA	z{A-.Fe$ &("|q=,i!m,-Ay)A '2 Q'78  
 #6k6!QPQ'?"SKAxLLO ''1 * ~~e!4bnn q7 ' *). +41BC/ *))s   C	D.DDc                 >   |j                   dkD  rt        |j                   dz
        } | |d | d    |        |       t        j                  |D cg c]  }|j                   c}       ||d  }t        j
                          |j                   dkD  r|S c c}w )Nr   r   )sizer   rP   r   r   r   )rJ   r   r   r   r   r   r   s        r(   _prefillz+speculative_generate_step.<locals>._prefillC  s    ffqj0!&&1*=L!M\"4(6e$GGe,eQWWe,-,- ANN ffqj  -s   Bc                     t        j                  | |z
         t        j                  t        | |z
  dz
  d             y )Nr   r   )r   trim_prompt_cachemax)	num_draft
num_acceptdraft_cachemodel_caches     r(   _rewind_cachez0speculative_generate_step.<locals>._rewind_cacheM  s9    Y-CDSZ1G!1KQ-OPr*   c                 
   |dk(  r$t        j                  g t         j                        S g }t        |      D ]5  } |       \  } }t        j                  |        |j                  |        7 t        j                  |      S Nr   )rP   rQ   uint32r   r   r   r   )r   r   ysr   r   r   r   s       r(   _draft_generatez2speculative_generate_step.<locals>._draft_generateQ  sm    >88B		**y!Ak15DAqMM!IIaL " ~~b!!r*   r   TFr   )r   )astyperP   r   r   r   r   layerscan_trim_prompt_cacheis_trimmabler-   rp   r   r   r   r   r   r   r   r   r   r   tolistrQ   r   )"r   rJ   r   r   r   r   r   r}   r   r   r   r~   r   r   typesr   r   r   draft_yntoksr   r   draft_tokensr   rh   tndtnlpnr   r   r   r   r   r   s"     `  `` `                   @@@@@@r(   speculative_generate_stepr     sA    Z 	bii AK --e4--k:"#6S%67"3u||#4#67&&{3+6O;aann>Na!!;ONugUWX
 	
 :9G!))-#	D D4Q" 
$	%;Q7UK+ 
& EI	A+$J.0@AI*7I>L&)*UK,<,<qvv,E	,QTU,UV<01A$UKIMJFHGGFL)'..0L]]_FAi-%ay,q/8A;C9Q
#tm#J& i- z!
Qi!e33
"&)bii0AG
 I~..XXl23/;WE &)*BSQ-B,BC)Q'Q 2 " 	i#y PR 
&	%f 	i#sQ   BL$K,:K,A0LK1L%CK> 9B(K> "L1K;6L>L		L	tokenizerc              +   H  K   t        |t              st        |      }t        |t        j                        sdt        |t              r?|j
                  du xs |j                  |j
                         }|j                  ||      }t        j                  |      }|j                  }||d<   |)|j                  dd       t        || fi |}d |D        }n2|j                  dd       |j                  dd       t        || |fi |}t        | t        g      5  t        j                         }	t!        |      D ]  \  }
\  }}}|
dk(  r:t        j                         |	z
  }|j"                  |z  }t        j                         }	||j$                  v r n{|j'                  |       |
d	z   |k(  r n`t)        |j*                  ||||j"                  |
d	z   |
d	z   t        j                         |	z
  z  t        j,                         d
z  d
        |j/                          t)        |j*                  |j"                  
d	z   |
d	z   t        j                         |	z
  z  t        j,                         d
z  ||j$                  v rdnd
       ddd       y# 1 sw Y   yxY ww)a  
    A generator producing text based on the given prompt from the model.

    Args:
        model (nn.Module): The model to use for generation.
        tokenizer (PreTrainedTokenizer): The tokenizer.
        prompt (Union[str, mx.array, List[int]]): The input prompt string or
          integer tokens.
        max_tokens (int): The maximum number of tokens to generate.
          Default: ``256``.
        draft_model (Optional[nn.Module]): An optional draft model. If provided
          then speculative decoding is used. The draft model must use the same
          tokenizer as the main model. Default: ``None``.
        kwargs: The remaining options get passed to :func:`generate_step`.
          See :func:`generate_step` for more details.

    Yields:
        GenerationResponse: An instance containing the generated text segment and
            associated metadata. See :class:`GenerationResponse` for details.
    Nadd_special_tokensr   r   c              3   ,   K   | ]  \  }}||d f  yw)FNr2   ).0rg   rh   s      r(   	<genexpr>z"stream_generate.<locals>.<genexpr>  s      
<KUHe$Os   r   r   r   r       eA)
rf   rg   rh   ri   rj   rk   rl   rm   rn   ro   stoplength)rO   r   rP   rQ   r:   	bos_token
startswithencodedetokenizerpopr   r   rc   r   timeperf_counterrz   r   eos_token_ids	add_tokenre   last_segmentget_peak_memoryfinalize)rJ   r   r   r   r   kwargsr   r   token_generatorticr   rg   rh   ri   prompt_timerk   s                   r(   stream_generater	    s    8 i!12$Y/	fbhh'fc"!*!4!4!< "FDUDU##E A %%fAS%TF&!''K%F<

%t,'@@
<K
 	

=$'

-t43E;
*0
 
U./	0!09/0J,A,xAv"//1C7#[[;6
'')	///!!%(A*$$ --!%$kk%"#a% !A$*;*;*=*CD..036"  1K2 	 ))! ++!!eEd&7&7&9C&?@**,s2$)Y-D-D$D&(
 	
9 
1	0	0s   DJ"E2J	J"JJ"verbosec                    |rt        d       d}t        | ||fi |D ]+  }|rt        |j                  dd       ||j                  z  }- |rt                t        d       t        |      dk(  rt        d       yt        dj                   d	|j
                  d
d       t        d|j                   d	|j                  d
d       t        d|j                  d
d       |S )a  
    Generate a complete response from the model.

    Args:
       model (nn.Module): The language model.
       tokenizer (PreTrainedTokenizer): The tokenizer.
       prompt (Union[str, List[int]]): The input prompt string or integer tokens.
       verbose (bool): If ``True``, print tokens and timing information.
           Default: ``False``.
       kwargs: The remaining options get passed to :func:`stream_generate`.
          See :func:`stream_generate` for more details.
    z
========== T)endflushr   z!No text generated for this promptNzPrompt: 	 tokens, .3f tokens-per-seczGeneration: zPeak memory:  GB)	rZ   r	  rf   r   rj   rk   rl   rm   rn   )rJ   r   r   r
  r  rf   responses          r(   generater    s    & hD#E9fGG(--Rt4 H
 ht9>56x--.i""3'8	
 	8556i&&s+?<	
 	h2237s;<Kr*   c           
          |t        d | D              }t        j                  | D cg c]  }dg|t        |      z
  z  |z    c}      S c c}w )Nc              3   2   K   | ]  }t        |        y wrN   r   r   ps     r(   r   z$_left_pad_prompts.<locals>.<genexpr>$       1AQ   r   r   rP   rQ   r   prompts
max_lengthr  s      r(   _left_pad_promptsr   "  sN    111
88gFgaSJQ/014gFGGF   Ac                     |t        d | D              }t        j                  | D cg c]  }|dg|t        |      z
  z  z    c}      S c c}w )Nc              3   2   K   | ]  }t        |        y wrN   r  r  s     r(   r   z%_right_pad_prompts.<locals>.<genexpr>*  r  r  r   r  r  s      r(   _right_pad_promptsr$  (  sN    111
88gFgQ!
SV 344gFGGFr!  c                   t    e Zd ZU dZdZeed<   dZeed<   dZ	eed<   dZ
eed<   dZeed<   dZeed<   dZeed	<   y
)
BatchStatsa%  
    An data object to hold generation stats.

    Args:
        prompt_tokens (int): The number of prompt tokens processed.
        prompt_tps (float): The prompt processing tokens-per-second.
        prompt_time (float): The time in seconds spent in prompt processing.
        generation_tokens (int): The number of generated tokens.
        generation_tps (float): The tokens-per-second for generation.
        generation_time (float): The time in seconds spent in generation .
        peak_memory (float): The peak memory used so far in GB.
    r   rj   rk   r  rl   rm   generation_timern   N)rp   rq   rr   rs   rj   r=   rt   rk   r?   r  rl   rm   r'  rn   r2   r*   r(   r&  r&  .  sP     M3JKsNEOUKr*   r&  c                 &   fdt        | d      r&| j                         }|D cg c]
  } |       c}S |$| j                  D cg c]  }t        |       c}S | j                  D cg c]  }t	               c}S c c}w c c}w c c}w )z[
    Convert a list of regular caches into their corresponding
    batch-aware caches.
    c                    t        |       t        u rt              S t        | t              rt        j                        | _        | S t        | t              r0| j                  dkD  rt        d      t        | j                        S t        | t              rt        fd| j                  D         S t        t        |        d      )Nr   z2RotatingKVCache with keep tokens is not supported.c              3   .   K   | ]  } |        y wrN   r2   )r   sub_cto_batch_caches     r(   r   z6_make_cache.<locals>.to_batch_cache.<locals>.<genexpr>W  s     K(~e4(s   z does not yet support batching)r-   r   r   rO   r   rP   rQ   left_paddingr   keepr   r   max_sizer   caches)r   r-  r,  s    r(   r,  z#_make_cache.<locals>.to_batch_cacheL  s    7g--;'XXl3ANH?+vvz !UVV'

LAA9%K!((KLLQy(FGHHr*   
make_cache)r{   r1  r   r   r   )rJ   r-  r   r   r   r   r,  s    `    @r(   _make_cacher2  F  s    I ul#  "+015aq!511"INIUA$[,?  5:LLALq\*LAA 2 Bs   BB	/Bc           
          g }| s|S t        t        | d               D ]h  }t        | d   |   d      r8|j                  | d   |   j	                  | D cg c]  }||   	 c}             Mt        t        | d   |          d       |S c c}w )Nr   mergez+ does not yet support batching with history)r   r   r{   r   r4  r   r-   )r0  batch_cacher   r   s       r(   _merge_cachesr6  f  s    K3vay>"6!9Q<)vay|112HA1Q42HIJq	!%&&QR 	 #  3Is   Bc                 `    | s|S |s| S t        | |      D ]  \  }}|j                  |        | S rN   )zipextend)cache_acache_bcacbs       r(   _extend_cacher>  v  s7    gw'B
		" (Nr*   c                 `   i }t        |       D ]1  \  }}|}	 |D ]  }|j                  |i       } t        |      |f|d<   3 t	               }|j                         D ]!  \  }}|dk(  r||d<   |j                  |       # |r|j                         }	|	j                         D ]\  \  }}|dv r|j                  |       |	d   }
||
vr|
|ur|
d   }
||
vr|
|ur||
v r|
|   n||d<   d|vsJd|d   v sR|d   d   |d<   ^ |r|S # t        $ r |j                  |i       }|f|f|d<   Y w xY w)u}   Build an Aho-Corasick trie from the provided sequences

    See https://en.wikipedia.org/wiki/Aho–Corasick_algorithm .
    	__match____fail__)rA  r@  )rz   
setdefaulttuple	TypeErrorr   itemsr   popleft)	sequencestrieidxseqnodetokqueuekeychildparentfails              r(   _build_trierR    sz   
 Di(S	.sB/ !&sS 1D ) GEjjl
U+ jU	 #
  ,,.JC//LL*%DT/d$&6J' T/d$&6-0D[S	dE*%'K5;L,L%*:%6{%Ck" )  K/  	.??3+D"%D	.s   )D#D-,D-c                 D    || vr| |ur| d   } || vr| |ur|| v r| |   } | S )z"One step in the Aho-Corasick trie.rA  r2   )rK  rH  rT   s      r(   
_step_trierT    s?    
4-D,J 4-D,DyAwKr*   c                   8    e Zd ZdZi dfdZd Zd Zed        Zy)SequenceStateMachinea  A state machine that uses one Aho-Corasick trie per state to efficiently
    track state across a generated sequence.

    The transitions are provided as state -> [(sequence, new_state)].

    Example:

        sm = SequenceStateMachine(
            transitions={
                "normal": [
                    (think_start_tokens, "reasoning"),
                    (tool_start_tokens, "tool"),
                    (eos, None),
                ],
                "reasoning": [
                    (think_end_tokens, "normal"),
                    (eos, None),
                ],
                "tool": [
                    (tool_end_tokens, None),
                    (eos, None)
                ],
            },
            initial="normal"
        )
    normalc                     || _         i | _        |j                         D ]*  \  }}t        | \  }}t	        |      |f| j                  |<   , | j                  st	        g       g f| j                  |<   y y rN   )_initial_statesrE  r8  rR  )selftransitionsinitialsrcedgesrG  dsts          r(   __init__zSequenceStateMachine.__init__  sq    %++-JC %[NIs!,Y!7 =DLL . ||%0_b$9DLL! r*   c                 |    t         j                  t              }| j                  |_        | j                  |_        |S rN   )object__new__rV  rY  rZ  )r[  memonews      r(   __deepcopy__z!SequenceStateMachine.__deepcopy__  s,    nn12}}ll
r*   c                 h    | j                   | j                  | j                      d   | j                  fS r   )rY  rZ  r[  s    r(   
make_statezSequenceStateMachine.make_state  s)    t||DMM:1=t||LLr*   c                     | \  }}}t        |||   d   |      }d }|j                  d      }||d   }||   d   |d      }|||   d   nd }|||f||fS )Nr   r@  r   )rT  get)r   rT   rb   r   statesrJ  matchs          r(   rn  zSequenceStateMachine.match  s    1fq&)A,*k"(Cq	!U1X&A !q	!4A1f~sA%%r*   N)	rp   rq   rr   rs   ra  rg  rj  staticmethodrn  r2   r*   r(   rV  rV    s2    6 $&x :M & &r*   rV  c                   z   e Zd ZdZe G d d             Z	 	 	 	 	 	 	 ddej                  dee	   deee
      deeee	         d	e	d
eeeej                  gej                  f         deeej                  gej                  f      deeeeej                  ej                  gej                  f            deee      deee	      fdZd Zde	dee
   fdZd Zd Zdee	   fdZdee	   fdZdeee	      fdZdeee	      fdZe	 ddej                  deej                  gej                  f   d	e	fd       Zy)PromptProcessingBatchz
    A batch processor for prompt tokens with support for incremental processing.

    This class handles batched prompt processing, managing KV caches and preparing
    tokens for generation. It supports extending, filtering, and splitting batches.
    c                   6    e Zd ZU eed<   eed<   eed<   eed<   y)PromptProcessingBatch.Responseuidprogressend_of_segmentend_of_promptN)rp   rq   rr   r=   rt   rC  ru   r2   r*   r(   Responsers    s    r*   rx  NrJ   uidsr0  r   r   samplersfallback_samplerr   state_machinesr   c                 f   || _         || _        t        |      | _        ||n|D cg c]  }g  c}| _        || _        ||ng | _        |xs d | _        ||ng | _        |	|	nt               gt        |      z  | _        |
|
| _        y t        gt        | j                        z  | _        y c c}w )Nc                 0    t        j                  | d      S r   r   r   s    r(   rU   z0PromptProcessingBatch.__init__.<locals>.<lambda>  s    ryyQS?Tr*   )rJ   ry  r6  r}   r   r   rz  r{  r   rV  r   r|  r>   r   )r[  rJ   ry  r0  r   r   rz  r{  r   r|  r   r   s               r(   ra  zPromptProcessingBatch.__init__  s     
	)&1 & 2fT8JTT8J!2$,$8b 0 U5T!2!>B 	
 ) &()CI5 	 %  	 %%DII6 	 9Ks   	B.c                 ,    t        | j                        S rN   r   ry  ri  s    r(   __len__zPromptProcessingBatch.__len__       499~r*   rI  r   c                 ^    | j                   D cg c]  }|j                  |       c}S c c}w rN   r}   extractr[  rI  r   s      r(   extract_cachez#PromptProcessingBatch.extract_cache#  *    (,(9(9:(91		#(9:::   *c                    t        | j                        sd gt        | j                        z  | _        t        | j                        sd gt        | j                        z  | _        t        |j                        r|j                  nd gt        |j                        z  }t        |j                        r|j                  nd gt        |j                        z  }| j                  j                  |j                         t        | j                  |j                        | _        | j                  j                  |j                         | j                  j                  |       | j                  j                  |       | j                  j                  |j                         | j                  j                  |j                         y rN   )anyrz  r   ry  r   r9  r>  r}   r   r   r|  )r[  batchrz  r   s       r(   r9  zPromptProcessingBatch.extend&  sB   4==!!FS^3DM4))*&*Vc$))n%<D"%(%85>>tfs5::>V 5**+ ###ejj/) 	 			$)$*;*;U=O=OP5<<(X&%%&78u//0""5#7#78r*   c                 6   | j                   j                  | j                         }| j                  |_        t        | j                        |_        t        j                  | j                        |_        t        | j                        |_        | j                  |_	        t        | j                        |_
        | j                  |_        t        | j                        |_        t        | j                        |_        t        | j                        |_        |S rN   )	__class__rd  rJ   listry  copydeepcopyr}   r   r   rz  r{  r   r|  r   )r[  	new_batchs     r(   _copyzPromptProcessingBatch._copy:  s    NN**4>>:	**	dii	!%t/@/@!A	,	&*&<&<	#!$--0	%)%:%:	"&*4+A+A&B	##'(;(;#<	 #DOO4	r*   indicesc           	          t        |      }t        t        t        t        | j                                    t        |      z
        }| j                         }| j                  |       |j                  |       |S rN   )sortedsetr   r   ry  r  filter)r[  r  indices_leftr  s       r(   splitzPromptProcessingBatch.splitH  s[    /c%DII"783w<GHJJL	L!!r*   r.  c                    |D cg c]  }| j                   |    c}| _         |s| j                  j                          n"| j                  D ]  }|j                  |        |D cg c]  }| j                  |    c}| _        t        | j                        r#|D cg c]  }| j                  |    c}| _        nd gt        |      z  | _        t        | j                        r#|D cg c]  }| j                  |    c}| _        ng gt        |      z  | _        |D cg c]  }| j                  |    c}| _	        |D cg c]  }| j                  |    c}| _
        y c c}w c c}w c c}w c c}w c c}w c c}w rN   )ry  r}   clearr  r   r  rz  r   r   r   r|  r[  r.  rI  r   s       r(   r  zPromptProcessingBatch.filterQ  sL   /34tTYYs^t4	##%&& '3784Ct{{3'48t}};?@4CT]]3/4@DM!FSY.DMt%%&MQ%RTcd&<&<S&AT%RD"&(TCI%5D";?@4C4??3/4@CGH4Ct22374H! 5 9@ &S AHs#   E!&E&E+)E0 E5E:c                 T   t        | j                        t        |      k7  rt        d      |syt        | j                  |      D ]
  \  }}||z  } |D cg c]  }t        |       }}t        |      }|D cg c]  }||z
  	 }}t        |      }	|	dkD  r2t        ||      }| j                  D ]  }
|
j                  ||        nt        j                  |      }|j                  d   dkD  rt        | j                  |j                  d         }| j                  |ddd|f   | j                         t        j                  | j                  D 
cg c]  }
|
j                    c}
       t        j"                          |dd|df   }|j                  d   dkD  r|	dkD  rm| j                  D ]  }
|
j%                           t        j                  | j                  D 
cg c]  }
|
j                    c}
       t        j"                          yyc c}w c c}w c c}
w c c}
w )z
        Process prompt tokens through the model.

        Args:
            tokens: List of token sequences to process.
        z3The batch length doesn't match the number of inputsNr   )r  )lengthsright_paddingr   r   )r   ry  r   r8  r   r   r$  r}   preparerP   rQ   shaper   r   rJ   r   r   r   r  )r[  r   stitir  r  r  lpaddingmax_paddingr   r   s               r(   r   zPromptProcessingBatch.promptd  s    tyy>S[(RSS 4;;/GC2IC 0 $**6a3q66*\
+237a:>73'l ?':FF&&		'	A ' XXf%F ll1o!t55v||AGLJJva,./t7H7HJIGGd&7&78&7QWW&789NNA|},-F ll1o! ?&&

 'GGd&7&78&7QWW&789NN	 / +3  9 9s   H:HH &H%c                    t        d |D              r"| j                  |D cg c]  }|dd 	 c}       t        j                  |D cg c]  }|d   	 c}      }t	        | j
                  | j                  || j                  | j                  | j                  | j                  | j                  | j                  | j                  
      }g | _        g | _        g | _        g | _	        g | _        g | _        |S c c}w c c}w )z
        Transition from prompt processing to generation.

        Args:
            tokens: Final tokens for each sequence to start generation.

        Returns:
            A GenerationBatch ready for token generation.
        c              3   8   K   | ]  }t        |      d kD    yw)r   Nr  )r   ts     r(   r   z1PromptProcessingBatch.generate.<locals>.<genexpr>  s     *6as1vz6s   Nr   )r  r   rP   rQ   GenerationBatchrJ   ry  r}   r   rz  r{  r   r|  r   )r[  r   r  
last_token
generations        r(   r  zPromptProcessingBatch.generate  s     *6**KK0A3B01XXf5fquf56
$JJIIKKMM!!""OO

 	!#/ 15s   C5C:c                 &     | |||g g g g g g g 
      S )N)
rJ   r{  r   ry  r0  r   rz  r   r   r|  r2   )clsrJ   r{  r   s       r(   emptyzPromptProcessingBatch.empty  s/     -/ 
 	
r*   )Nr   NNNNN)r   )rp   rq   rr   rs   r   rx  nnModuler	   r=   r   r
   r   rP   rQ   rV  ra  r  r  r9  r  r  r  r   r  classmethodr  r2   r*   r(   rq  rq    s       -1!%CGEI ?C*.#
yy#
 3i#
 T#Y	#

 d3i)#
 #
 4"((RXX)= >?@#
 #8RXXJ,@#AB#
 $h"((3RXX=>?@
#
 !&:!;<#
 T#Y'#
J; ;c ;9(T#Y I49 I&.T$s)_ .`"tDI "H 
 "&	
yy
 #BHH:rxx#78
 	
 
r*   rq  c                   X   e Zd ZdZe G d d             Zdej                  dee	   de
j                  dee   deee	      d	eeee
j                  ge
j                  f         d
ee
j                  ge
j                  f   deeeee
j                  e
j                  ge
j                  f            dee   dee	   fdZd Zd Zdeee	   ee
j                     f   fdZde	dee   fdZdee	   fdZdee   fdZedej                  d
ee
j                  ge
j                  f   fd       Zy)r  z
    A batched token generator that manages multiple sequences in parallel.

    This class handles the generation phase after prompt processing, managing
    KV caches, sampling, and stop sequence detection for multiple sequences.
    c                       e Zd ZU eed<   eed<   ej                  ed<   ee   ed<   ee   ed<   ee	e      ed<   ee	e
      ed<   ee	e      ed<   y	)
GenerationBatch.Responsert  rg   rh   ro   current_statematch_sequencer}   
all_tokensN)rp   rq   rr   r=   rt   rP   rQ   r
   r:   r	   r   r2   r*   r(   rx  r    sW    
((}$}$ c++tCy))T#Y''r*   rx  rJ   ry  inputsr}   r   rz  r{  r   r|  r   c                    || _         || _        || _        || _        || _        || _        || _        |	| _        |
| _        | j                  r6t        | j                        t        | j                        k7  rt        d      | j                  r6t        | j                        t        | j                        k7  rt        d      d | _        g | _        || _        g | _        |D cg c]  }t        |       c}| _        dgt        | j                        z  | _        |	D cg c]  }|j%                          c}| _        | j                  r| j)                          y y c c}w c c}w )Nz(Insufficient number of samplers providedz1Insufficient number of logits_processors providedr   )rJ   ry  r}   r   rz  r{  r   r|  r   r   r   _current_tokens_current_logprobs_next_tokens_next_logprobsr   _token_context_num_tokensrj  _matcher_statesr   )r[  rJ   ry  r  r}   r   rz  r{  r   r|  r   r  ms                r(   ra  zGenerationBatch.__init__  s-    
	(  0!2,$==S/3tyy>AGHH!!c$*@*@&AS^&SPQQ#!#" 7=>v!{1~v>3TYY/8FG1G99JJL 	 ?Gs   $E E"c                 ,    t        | j                        S rN   r  ri  s    r(   r  zGenerationBatch.__len__
  r  r*   c                 (   | j                   j                  |j                          t        | j                  |j                        | _        | j                  j                  |j                         | j
                  j                  |j
                         | j                  j                  |j                         | j                  j                  |j                         | j                  j                  |j                         | j                  #|j                  | _	        |j                  | _
        na|j                  Ut        j                  | j                  |j                  g      | _	        | j                  j                  |j                         | j                  #|j                  | _        |j                  | _        na|j                  Ut        j                  | j                  |j                  g      | _        | j                  j                  |j                         | j                  j                  |j                         | j                   j                  |j                          | j"                  j                  |j"                         y)z0Extend this batch with another generation batch.N)ry  r9  r>  r}   r   rz  r   r   r|  r  r  rP   r   r  r  r  r  r  )r[  r  s     r(   r9  zGenerationBatch.extend  s   		$)$*;*;U=O=OP5<<(U^^,%%e&=&=>u//0""5#7#78'#(#8#8D %*%<%<D""".#%>>%%u'<'<=$D  ""))%*A*AB$ % 2 2D"'"6"6D+ "0A0A5CUCU/V WD&&u';';<""5#7#78 1 12##E$9$9:r*   r   c           
      ,   | j                   | _        | j                  | _        | j                  }| j	                  |dddf   | j
                        }|dddddf   }g }t        | j                        rt        | j                        D cg c]  \  }}|j                  |||dz           }}}g }t        t        | j                              D ];  }|||dz    }| j                  |   D ]  }	 |	||   |      } |j                  |       = t        j                   |d      }|t        j"                  |dd      z
  }
t        | j$                        ryg }t        t        | j                              D ]>  }| j$                  |   xs | j&                  } ||
||dz          }|j                  |       @ t        j                   |d      }n| j'                  |
      }|| _         t)        |
      | _        t        j*                  | j                   | j                  |       t        j,                  || j                         |j/                         }t1        | j2                  |      D ]  \  }}|j                  |        || j                  fS c c}}w )	zx
        Perform a single generation step.

        Returns:
            Tuple of token list and logprobs list.
        Nr   r   r   r   r   Tr   )r  r  r  r  rJ   r}   r  r   rz   r  update_and_fetchr   r   ry  r   rP   r   r   rz  r{  r  r   r   r   r8  r   )r[  r  r   token_contextr   tcprocessed_logitsr   sample_logitsr   rh   all_samplessample_samplerr   r  r  s                   r(   r   zGenerationBatch._step(  s^     $00!%!4!4%% F1d7O43D3DE2q! t%%& 't':':;;EAr ##F1q1u$56;    "3tyy>* &q1q5 1!%!7!7!:I$-mA.>$NM "; ''6	 +
 ^^$41=F BLLb4HH t}}K3tyy>*!%q!1!JT5J5J(!a!e)<=""7+ + nn[q9G++H5G $"8n
d'')<)<mL
 	../4;;/GCJJrN 0t----Os   !JrI  c                 ^    | j                   D cg c]  }|j                  |       c}S c c}w rN   r  r  s      r(   r  zGenerationBatch.extract_cached  r  r  r.  c                    |D cg c]  }| j                   |    c}| _         |s| j                  j                          n"| j                  D ]  }|j                  |        |D cg c]  }| j                  |    c}| _        t        | j                        r"|D cg c]  }| j                  |    c}| _        t        | j                        r"|D cg c]  }| j                  |    c}| _        |D cg c]  }| j                  |    c}| _        |D cg c]  }| j                  |    c}| _	        |r| j                  |   nd| _
        |D cg c]  }| j                  |    c}| _        |D cg c]  }| j                  |    c}| _        |D cg c]  }| j                  |    c}| _        |D cg c]  }| j                  |    c}| _        yc c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w )z4Filter the batch to keep only the specified indices.N)ry  r}   r  r  r   r  rz  r   r   r|  r  r  r  r  r  r  s       r(   r  zGenerationBatch.filterg  s   /34tTYYs^t4	##%&& '3784Ct{{3'48t}};?@4CT]]3/4@DMt%%&MQ%RTcd&<&<S&AT%RD";?@4C4??3/4@CGH4Ct22374H7;D--d3CGH4Ct22374HCGH4Ct22374H=ABTcD,,S1TBEIJTc 4 4S 9TJ% 5 9@%R@H IHBJs;   G&GG!G&6G+G0G54G:G?8Hc                 N   | j                   sg S | j                         \  }}g }g }t        t        | j                               D ]+  }d}d}| j                  |xx   dz  cc<   | j                  |   | j
                  |   k\  rd}| j                  |   j                  | j                  |   ||         \  | j                  |<   }}||d}|X|j                  | j                  | j                   |   ||   ||   |||| j                  |      | j                  |                |j                  |       |j                  | j                  | j                   |   ||   ||   d||dd             . t        |      t        | j                         k  r| j                  |       |S )z
        Generate the next batch of tokens.

        Returns:
            List of Response objects for each sequence in the batch.
        Nr   r   r   )rt  rg   rh   ro   r  r  r}   r  )rt  rg   rh   ro   r  r  r}   r  )ry  r   r   r   r  r   r|  rn  r  r   rx  r  r   r  )	r[  r   rh   r.  	responsesr   ro   r  r  s	            r(   nextzGenerationBatch.next}  s    yyI::<	s499~&A M!NQ1$"dooa&88 ( ##A&,,T-A-A!-DfQiP CD  #^] )m.C &(  MM IIaL$Qi!)!&3&3'5%)%7%7%:#';;q> " 	 A  MM IIaL$Qi!)!&*'5&3%)#' " 	; 'T t9s499~%KKr*   c                 l     | ||g t        j                  g t         j                        g g g g g g 
      S )N)dtype)
rJ   r{  ry  r  r}   r   rz  r   r   r|  )rP   rQ   r   )r  rJ   r{  s      r(   r  zGenerationBatch.empty  s>     -88Bbii0 
 	
r*   N)rp   rq   rr   rs   r   rx  r  r  r	   r=   rP   rQ   r   r
   r   rV  ra  r  r9  r   r   r  r  r  r  r  r2   r*   r(   r  r    s    ( ( ((yy( 3i( 	(
 3i( T#Y( 4"((RXX)= >?@( #BHH:rxx#78( $h"((3RXX=>?@
( 12( I(T;6:.uT#YRXX67 :.x; ;c ;K49 K,;d8n ;z 
yy
 #BHH:rxx#78
 
r*   r  c                      e Zd ZdZdddddddddd	dej
                  d	ed
eeee         dee	e
j                  ge
j                  f      deee	e
j                  e
j                  ge
j                  f         dedededee   fdZed        Zd Zd Zej&                  d(d       Z	 	 	 	 	 	 d)deee      d	eee      deeee         deeee         deee	e
j                  ge
j                  f         deeee	e
j                  e
j                  ge
j                  f            deee      fdZ	 	 	 	 	 	 d)deeee         d	eee      deeee         deeee         deee	e
j                  ge
j                  f         deeee	e
j                  e
j                  ge
j                  f            deee      fdZd Zd Zd  Zd*d!Zed"        Zd#efd$Zd% Zd& Z d' Z!y)+BatchGeneratoraW  
    A batch generator implements continuous batching.

    This class provides automatic management of prompt processing and generation
    batches, handling the transition between the two.

    It also allows for segmented prompt processing which guarantees that the
    generator will stop at these boundaries when processing an input.
       N       r   )	r   stop_tokensr   r   completion_batch_sizeprefill_batch_sizer   r   r   rJ   r   r  r   r   r  r  r   r   c       	            || _         || _        |xs d | _        |xs g | _        d| _        || _        || _        t        ||      | _        |	| _	        |
xs t        | _        t        |rd|D cg c]  }|d f c}ini d      | _        d| _        t        j!                  | j                   | j                  |      | _        t$        j!                  | j                   | j                        | _        t)               | _        g | _        d| _        d| _        d| _        d| _        t6        j8                  j;                         r0t7        j<                  t7        j>                         d         | _         y d | _         y c c}w )Nc                 0    t        j                  | d      S r   r   r   s    r(   rU   z)BatchGenerator.__init__.<locals>.<lambda>  s    RYYqr-Br*   r   rW  )r]  )r   rV   )!rJ   r   r   r   	uid_countr   r  r   r  r   r   _streamrV  _default_state_machine
_uid_countrq  r  _prompt_batchr  _generation_batchr   _unprocessed_sequences_currently_processing_prompt_tokens_counter_prompt_time_counter_gen_tokens_counter_steps_counterrP   rW   rX   r[   rY   _old_wired_limit)r[  rJ   r   r  r   r   r  r  r   r   r   rJ  s               r(   ra  zBatchGenerator.__init__  s^     
$C#B!2!8b!2"4%()>@R%S"&2!2&:@KX{;{d{;<QS'
# 288JJLL/ 9 

 "1!6!6tzz4<<!P&+g#%'"&'#$%!#$ 88  "$&$6$6 !CD%D! %)D!/ <s   .E9
c                     | j                   S rN   )r  ri  s    r(   r   zBatchGenerator.stream  s    ||r*   c                     | j                   Ft        j                  | j                         t        j                  | j                          d | _         y y rN   )r  rP   r\   r  r[   ri  s    r(   closezBatchGenerator.close  s?      ,NN4<<(t445$(D! -r*   c                 $    | j                          y rN   )r  ri  s    r(   __del__zBatchGenerator.__del__  s    

r*   c              #     K   |xs
 t               }d| _        d| _        d| _        t	        j
                         }	 | t	        j
                         }||z
  }|| j                  z
  }|xj                  | j                  z  c_        |xj                  | j                  z  c_        |j                  |j                  z  |_        |xj                  | j                  z  c_	        |xj                  |z  c_
        |j                  |j                  z  |_        t        |j                  t        j                         dz        |_        y # t	        j
                         }||z
  }|| j                  z
  }|xj                  | j                  z  c_        |xj                  | j                  z  c_        |j                  |j                  z  |_        |xj                  | j                  z  c_	        |xj                  |z  c_
        |j                  |j                  z  |_        t        |j                  t        j                         dz        |_        w xY ww)Nr   r   )r&  r  r  r  r   r   rj   r  rk   rl   r'  rm   r   rn   rP   r  )r[  statsr  toc
total_timegen_times         r(   r  zBatchGenerator.stats  s    %&'#$%!#$ !	SK##%CsJ!D$=$==H4#>#>>!:!::$22U5F5FFE##t'?'??#!!X-!#(#:#:U=R=R#RE  #E$5$5r7I7I7Kc7Q RE ##%CsJ!D$=$==H4#>#>>!:!::$22U5F5FFE##t'?'??#!!X-!#(#:#:U=R=R#RE  #E$5$5r7I7I7Kc7Q REs   8IE DIDIIr  r0  r  rz  r|  c           	      X    | j                  |D cg c]  }|g c}||||||      S c c}w rN   )insert_segments)	r[  r  r   r0  r  rz  r   r|  r  s	            r(   insertzBatchGenerator.insert1  s@     ##!"'QaS'"
 	
"s   
'segmentsc                    g }|xs | j                   gt        |      z  }|xs |D 	cg c]  }	g  c}	}|xs d gt        |      z  }|xs | j                  gt        |      z  }|xs | j                  gt        |      z  }|xs d gt        |      z  }t	        t        |            D ]  }
||
   	| j                         ||
<    t        |||||||      D ]  \  }}}}}}}t        |      }t        |d         dk7  r"|j                  |d   dd         |d   d d |d<   | j                  j                  | j                  |||||||f       |j                  | j                         | xj                  dz  c_
         |S c c}	w )Nr   r   )r   r   r   r  r   _make_new_cacher8  r  r   r  r  )r[  r  r   r0  r  rz  r   r|  ry  r   r   rJ  r  r   atrb   lpsms                     r(   r  zBatchGenerator.insert_segmentsG  s    DDOO#4s8}#D
9#91B#9
5vH5- 
##$s8}4 	 ( 
(()CM9 	 1D6CM1s8}%Aay  002q	 & ),)
$CAr1b" s)C3r7|q 

3r723<(b'#2,B''..#q!RB; KK(OOq O#)
& C $:s   	Fc                    | j                   t        j                  | j                        S t        j                  | j                        D cg c]*  }t	        |t
              rt        | j                         n|, c}S c c}w )N)r/  )r   r   r   rJ   rO   r   r   )r[  cis     r(   r  zBatchGenerator._make_new_cachey  s|    #**4::66 --djj9
 : b'*  )9)9: :
 	
 
s   /A?c                 J   t        |      }i }t        | j                  j                        D ]  \  }}||v sd|f||<    t        | j                  j                        D ]  \  }}||v sd|f||<    t        | j
                        D ]  \  }}|d   |v sd|f||d   <    |S )Nr   r   r   )r  rz   r  ry  r  r  )r[  ry  resultsr   uid_irJ  s         r(   
_find_uidszBatchGenerator._find_uids  s    4y!$"8"8"="=>HAu}"#Q ? "$"4"4"9"9:HAu}"#Q ;   ; ;<FAs1v~#$a&A = r*   c                 |   i }| j                  |      j                         D ]  \  }\  }}|dk(  r| j                  |   dd ||<   $|dk(  r8| j                  j	                  |      | j                  j
                  |   f||<   a| j                  j	                  |      | j                  j
                  |   f||<    |S )Nr   r6      r   )r  rE  r  r  r  r   r  )r[  ry  r  rt  stagerI  s         r(   r  zBatchGenerator.extract_cache  s    !%!6!<!<!>C%z#::3?!D!&&44S9&&--c2  **88=**11#6  "? r*   c           	         i }|r| j                  |      }t        t        t        | j                                    t        t        t        | j
                                    t        t        t        | j                                    f| j                  |      j                         D ]  \  }}|   j                  |        t        d         t        | j                        k  r,t        fdt        | j                        D              | _        t        d         t        | j
                        k  r\| j
                  j                  t        d                t        | j                        D cg c]  \  }}|d   v s| c}}| _        t        d         t        | j                        k  r'| j                  j                  t        d                |S c c}}w )Nr   c              3   8   K   | ]  \  }}|d    v s|  yw)r   Nr2   )r   r   rT   r.  s      r(   r   z(BatchGenerator.remove.<locals>.<genexpr>  s%      0DdaTRSWDs   r   r   )r  r  r   r   r  r  r  r  valuesremover   rz   r  r  r  )	r[  ry  return_prompt_cachesr0  r  rI  r   rT   r.  s	           @r(   r  zBatchGenerator.remove  s   ''-F c$55678c$,,-./c$00123

 //$/668JE3Ks# 9 tAw<#d99::*/ 0'(C(CD0 +D' tAw<#d0011%%fT!Wo6'(B(BC*CdaqDQRG|C*D& tAw<#d4455""))&a/:*s   9G#	G#c                     t        d | j                  D              }|t        d | j                  j                  D              z  }|t        d | j                  j                  D              z  }|S )Nc              3   H   K   | ]  }|d    D ]  }|j                      yw)r6   NrR   )r   r  r   s      r(   r   z5BatchGenerator.prompt_cache_nbytes.<locals>.<genexpr>  s#     P&A1Q4aAHH4H&As    "c              3   4   K   | ]  }|j                     y wrN   r  r   r   s     r(   r   z5BatchGenerator.prompt_cache_nbytes.<locals>.<genexpr>  s     G'F!QXX'F   c              3   4   K   | ]  }|j                     y wrN   r  r  s     r(   r   z5BatchGenerator.prompt_cache_nbytes.<locals>.<genexpr>  s     K'J!QXX'Jr  )sumr  r  r}   r  )r[  totals     r(   prompt_cache_nbytesz"BatchGenerator.prompt_cache_nbytes  s_    Pd&A&APPGt'9'9'F'FGGGKt'='='J'JKKKr*   r   c                 X   g }g }g }g }g }g }g }t        |      D ]  }	| j                  j                         }
|j                  |
d          |j                  |
d          |j                  |
d          |j                  |
d          |j                  |
d          |j                  |
d          |j                  |
d          | j                  j                  |
d   dt        d	 |
d   D              g        t        | j                  |||| j                  || j                  |||

      S )Nr   r6      r     r      r   c              3   2   K   | ]  }t        |        y wrN   r  )r   rb   s     r(   r   z-BatchGenerator._make_batch.<locals>.<genexpr>  s     $A[SV[r  )
rJ   ry  r0  r   r   rz  r{  r   r|  r   )
r   r  rF  r   r  r  rq  rJ   r   r   )r[  r   ry  r0  r   rz  r   r   r|  r   sequences              r(   _make_batchzBatchGenerator._make_batch  s*   
qA22::<HKK$MM(1+&MM(1+&OOHQK($$Xa[1hqk*!!(1+.&&--!a$AXa[$A!AB  %**"44!\\/)!
 	
r*   c           	      \   g }g }t        | j                        dkD  rs| j                  j                         }| xj                  t        |      z  c_        | xj                  dz  c_        | j                  dz  dk(  rt        j                          t        | j                        | j                  k\  r||fS t        | j                  t        | j                        z
  | j                  t        | j                        z
  t        | j                              }|dkD  r*| j                  j                  | j                  |             g }g }t        | j                        D ]L  \  }}|d   }t        |      dk(  r#t        |d         dk(  r|j!                  |       <|j!                  |       N |r|D cg c]  }| j                  |   d   d    }	}|D cg c]  }| j                  |   d   fdz   }
}|D cg c]  }| j                  |    c}| _        | j                  j#                  |      j%                  |	      }t        |
      D ]9  \  }}|j!                  t&        j)                  |j*                  |   |dd             ; | j                  j                  |       g }t        | j                        D ]  \  }}t&        j)                  | j                  j*                  |   ddd      }|d   }t        t        |d         | j,                        }|j!                  |d   d |        |d   |d  |d<   t        |d         dk(  r|j/                  d       d|_        |dxx   t        |d         z  cc<   |d   |d   f|_        |j!                  |        | xj4                  t7        d |D              z  c_        t9        j:                         }| j                  j=                  |       t9        j:                         }| xj>                  ||z
  z  c_        ||fS c c}w c c}w c c}w )	Nr   r   r   r   TFr   c              3   2   K   | ]  }t        |        y wrN   r  r  s     r(   r   z'BatchGenerator._next.<locals>.<genexpr>/  s     *C7a3q67r  ) r   r  r  r  r  rP   r   r  r   r  r  r  r9  r  rz   r  r   r  r  rq  rx  ry  r   r   rv  ru  r  r  r   r   r   r  )r[  generation_responsesprompt_responsesr   r.  r  r   rJ  r  last_inputsru  	gen_batchr  r  r  r  r  s                    r(   _nextzBatchGenerator._next  s   ! t%%&*#'#9#9#>#>#@ $$,@(AA$1$""S(A-  t%%&$*D*DD#%999 ##c$*<*<&==&&T-C-C)DD++,

 q5%%d&6&6q&9:  : :;FAs1vH8}!c(1+&6!&;QA < HMN1455a8;A>KNINOA33A6q9;a?HOQU)VQUA$*D*DQ*GQU)VD&**007@@MI!(+1 '')22!q)	 , "")))4  : :;FAs,55""''*AueH 1vHC$d&<&<=ANN8A;r?+"1+ab/HQK8A;1$Q*.'Fc'"+&&F!$QQ 0H##H- <  	##s*C7*C'CC#!!!'*!!!S3Y.!!555O OO)Vs   3PP$8P)c                     t        j                  | j                        5  | j                         cddd       S # 1 sw Y   yxY w)z
        Get the next batch of responses.

        Returns:
            Tuple of prompt processing responses and generation responses.
        NrP   r   r  r%  ri  s    r(   r  zBatchGenerator.next7  s)     YYt||$::< %$$s	   :Ac                     t        j                  | j                        5  	 | j                         \  }}|s|r|cddd       S # 1 sw Y   yxY w)z
        Return only generated tokens ignoring batch generation responses.

        Returns:
            List of GenerationBatch.Response objects
        Nr'  )r[  r"  r!  s      r(   next_generatedzBatchGenerator.next_generatedA  sA     YYt||$9=6 "6+0@+ %$$s   AArN   )NNNNNNF)"rp   rq   rr   rs   r  r  r=   r
   r   r   rP   rQ   r	   ra  propertyr   r  r  
contextlibcontextmanagerr  r   rV  r  r  r  r  r  r  r  r  r%  r  r)  r2   r*   r(   r  r    s!    9=<@ %'"#!%%)4)yy4) 	4)
 hx}564) (BHH:rxx#7894) $288RXX.89:
4)  #4)  4) 4) c]4)l  ) S S. +/,004CG ?C
d3i
 T#Y'
 d3i)	

 T$s)_-
 4"((RXX)= >?@
 $h"((3RXX=>?@

 !&:!;<
2 +/,004CG ?C0tDI'0 T#Y'0 d3i)	0
 T$s)_-0 4"((RXX)= >?@0 $h"((3RXX=>?@
0 !&:!;<0d
"6   
S  
DL6\ ,r*   r  c                   H    e Zd ZU dZee   ed<   eed<   eeee	         ed<   y)BatchResponsez
    A data object to hold a batch generation response.

    Args:
        texts: (List[str]): The generated text for each prompt.
        stats (BatchStats): Statistics about the generation.
    textsr  r0  N)
rp   rq   rr   rs   r	   r:   rt   r&  r
   r   r2   r*   r(   r/  r/  P  s,     9T$s)_%%r*   r/  r  prompt_cachesr  c           	      |   t        | fd|j                  D cg c]  }|g c}i|}	t        |      }
d}|rt        d|
 dd       t	        |t
              r|gt        |      z  }|	j                  |||      }|D ci c]  }|g  }}i }|	j                         5 }|	j                         x}r|D ]|  }|j                  6|r|j                  ||j                  <   |r|d	z  }t        d
| d|
 dd       |j                  dk7  sU||j                     j                  |j                         ~ |	j                         x}rddd       |	j                          |rt        d
| d|
        |D cg c]  }|j                  ||          }}|r|D cg c]  }||   	 c}nd}|rht        dj                    d|j"                  dd       t        d|j$                   d|j&                  dd       t        d|j(                  dd       t+        ||      S c c}w c c}w # 1 sw Y   xY wc c}w c c}w )a|  
    Generate responses for the given batch of prompts.

    Args:
       model (nn.Module): The language model.
       tokenizer (PreTrainedTokenizer): The tokenizer.
       prompts (List[List[int]]): The input prompts.
       prompt_caches (List[List[Any]], optional): Pre-computed prompt-caches
          for each input prompt. Note, unlike ``generate_step``, the caches
          won't be updated in-place.
       verbose (bool): If ``True``, print tokens and timing information.
          Default: ``False``.
       max_tokens (Union[int, List[int]): Maximum number of output tokens. This
          can be per prompt if a list is provided.
       return_prompt_caches (bool): Return the prompt caches in the batch
          responses. Default: ``False``.
       kwargs: The remaining options get passed to :obj:`BatchGenerator`.
          See :obj:`BatchGenerator` for more details.
    r  r   z'[batch_generate] Finished processing 0/z ...)r  )r0  Nr   z%[batch_generate] Finished processing /r   z[batch_generate] Prompt: r  r  r  z[batch_generate] Generation: z[batch_generate] Peak memory: r  )r  r   r   rZ   rO   r=   r  r  r)  ro   r}   rt  r   rg   r  decoderj   rk   rl   rm   rn   r/  )rJ   r   r  r1  r   r
  r  r  r  gennum_samplesfinry  rt  r  r  r  rr0  r0  s                       r(   batch_generater:  _  sk   < "+"9"9:"9QaS"9: C
 g,K
C7}DItT*c" \CL0
::gz-:@D"&'$3sBw$G'M	--//i/??.+/0~~aee,qCC5+VZ[ $ ??f,AEEN))!''2  --//i/ 
 IIK5cU!K=IJ 8<<tYgcl+tE<5ID1DSmC D1tF'(;(;'<IeFVFVWZE[[jk	
 	+E,C,C+DI##C(9	
 	.u/@/@.ESIJv..Y ; (	& =1s*   
H?
H#A)H(<H(3H4H9(H1c                     t               } | j                         }|j                  )t        j                  j                  |j                         |j
                  d u}|rt        |j
                  d      \  }}t        |d   t              rZ|j                  '|j                  |d   j                  k7  rt        d      |j                  |d   j                  k7  rt        d      |si nt        j                  d         }|j                   rdnd |d<   |j"                  }|r%|d   }n|d   k7  rt        d	| d
|d    d      |xs t$        }t'        ||j(                  |d|j*                  i      \  }}|j,                  D ]  }	|j/                  |	        i }
|j0                  t        j                  |j0                        }
|j2                  j5                  dd      j5                  dd      }|dk(  rt6        j8                  j;                         n|}|j<                  s|j>                  r|j@                  d|j@                  dg}ng }|jC                  d|d       |jD                  d u}|r|jC                  d|jD                  d        |jF                  |fd|| d|
}|r2d|d   d<   |jG                  |d||       }||jI                  d      d  }|jK                  |d      }n|jK                  |      }|jL                  <t'        |jL                        \  }}|jN                  |jN                  k7  rt        d      d }tQ        |jR                  |jT                  |jV                  |jX                  |jZ                  |j\                  |j^                  |jK                  d      ta        |jb                        z         }te        ||||jf                  |jh                  ||jj                  |rnd |j                  |j                  |jl                  ||jn                        }|jh                  stq        |       y y ) NT)return_metadatar   zF--kv-bits does not match the kv cache loaded from --prompt-cache-file.zL--kv-group-size does not match the kv cache loaded from --prompt-cache-file.tokenizer_configtrust_remote_coderJ   zProviding a different model (z-) than that used to create the prompt cache (z) is an error.quantize_activations)adapter_pathr=  model_configz\n
z\t	-system)rolecontentuser	assistantF)tokenizecontinue_final_messageadd_generation_promptz<query>r   rG  r   z5Draft model tokenizer does not match model tokenizer.)top_kxtc_probabilityxtc_thresholdxtc_special_tokens)
r   r
  r   r   r}   r   r   r~   r   r   )9rI   
parse_argsseedrP   randomprompt_cache_filer   rO   r   r   ry   r   r   rx   jsonloadsr>  rJ   r;   r   r@  r?  extra_eos_tokenadd_eos_tokenchat_template_configr   replacesysstdinreadignore_chat_templatehas_chat_templatesystem_promptr   prefill_responseapply_chat_templateindexr   r   
vocab_sizer   temptop_pmin_pmin_tokens_to_keeprM  rN  rO  r  r   r  r   r
  r   r~   r   rZ   )rH   argsusing_cacher}   metadatar=  
model_pathrJ   r   	eos_tokentemplate_kwargsr   messageshas_prefilltest_promptr   draft_tokenizerr   r  s                      r(   mainrs    sA   FDyy
		tyy! ((4K!2"" "
h l1o'78||'DLLLO<P<P,P \  !!\!_%?%?? b  4::h7I.J#K  594J4JDPT()J!'*J8G,,/
| <44<W4E3F G 
 ,}J&&),d.G.GH	E9 ))		* * O  ,**T%>%>?[[  -55eTBF!'3SYY^^FF$$)D)D)!)d6H6HIJHHF;<++47OO[T=R=RST...
#.&1/	

 
 &/HRL##77'2*5o	 8 K K--i8:;F!!&U!C!!&)#'+D,<,<'=$_%%)=)==TUU		



jj,,(($++D1D9P9P4QQ	G ??$$%0\d((22..H <<h r*   __main__zCalling `python -m mlx_lm.generate...` directly is deprecated. Use `mlx_lm.generate...` or `python -m mlx_lm generate ...` instead.rN   )r   Nr*  )Nr  FF)ar7   r,  r  r   rU  r[  r   collectionsr   dataclassesr   r   typingr   r   r   r	   r
   r   r   r   mlx.corecorerP   mlx.nnr  	mlx.utilsr   transformersr   modelsr   models.cacher   r   r   r   r   r   r   r   r   sample_utilsr   tokenizer_utilsr   utilsr   r   r<   r>   r@   rA   rB   rC   rD   DEFAULT_XTC_THRESHOLDrE   rF   r;   rG   r)   rI   new_thread_local_streamdefault_devicer   r-  r  Streamrc   re   r   rQ   r=   r   ru   r   r:   r	  r  r   r$  r&  r2  r6  r>  rR  rT  rV  rq  r  r  r/  r:  rs  rp   rZ   r2   r*   r(   <module>r     s        
   ! 	 	 	   ! , 
 
 
 ' - <    :! 0_F /B../@r/@/@/BC  $*ryy $*8DO+D $* $*N ( ( (:U 8<RV!%"&!!EI+/cHHc99c 	c
 hz288345c  Xrxx.BBHH.L%M NOc #c 3-c c c]c c c 'xc
D0@'ABc rxx(c uRXXrxx'($45cV 8<RV"& !u$HHu$99u$ u$
 u$ u$ hz288345u$  Xrxx.BBHH.L%M NOu$ 3-u$ u$ c]u$ u$ u$ uRXXrxx-.d:;u$x '+`
99`
(*::;`
 #rxxc*+`
 	`

 "))$`
 !4-.`
N 	+99+(*::;+ #tCy.!+ 	+ 	+\HH   .B@ #L:& :&z^
 ^
B~
 ~
B, ,D & & &$ 04(+!&L/ $s)_L/ DcO,	L/
 c49n%L/ L/ L/ L/^zz z		P 	F r*   